1 /**************************************************************************
2 *
3 * Copyright 2008 VMware, Inc.
4 * All Rights Reserved.
5 *
6 **************************************************************************/
7
8 /*
9 * Draw a triangle with X/EGL and OpenGL ES 2.x
10 */
11
12 #define USE_FULL_GL 0
13
14
15
16 #include <assert.h>
17 #include <math.h>
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <X11/Xlib.h>
22 #include <X11/Xutil.h>
23 #include <X11/keysym.h>
24 #if USE_FULL_GL
25 #include "gl_wrap.h" /* use full OpenGL */
26 #else
27 #include <GLES2/gl2.h> /* use OpenGL ES 2.x */
28 #endif
29 #include <EGL/egl.h>
30
31
32 #define FLOAT_TO_FIXED(X) ((X) * 65535.0)
33
34
35
36 static GLfloat view_rotx = 0.0, view_roty = 0.0;
37
38 static GLint u_matrix = -1;
39 static GLint attr_pos = 0, attr_color = 1;
40
41
42 static void
make_z_rot_matrix(GLfloat angle,GLfloat * m)43 make_z_rot_matrix(GLfloat angle, GLfloat *m)
44 {
45 float c = cos(angle * M_PI / 180.0);
46 float s = sin(angle * M_PI / 180.0);
47 int i;
48 for (i = 0; i < 16; i++)
49 m[i] = 0.0;
50 m[0] = m[5] = m[10] = m[15] = 1.0;
51
52 m[0] = c;
53 m[1] = s;
54 m[4] = -s;
55 m[5] = c;
56 }
57
58 static void
make_scale_matrix(GLfloat xs,GLfloat ys,GLfloat zs,GLfloat * m)59 make_scale_matrix(GLfloat xs, GLfloat ys, GLfloat zs, GLfloat *m)
60 {
61 int i;
62 for (i = 0; i < 16; i++)
63 m[i] = 0.0;
64 m[0] = xs;
65 m[5] = ys;
66 m[10] = zs;
67 m[15] = 1.0;
68 }
69
70
71 static void
mul_matrix(GLfloat * prod,const GLfloat * a,const GLfloat * b)72 mul_matrix(GLfloat *prod, const GLfloat *a, const GLfloat *b)
73 {
74 #define A(row,col) a[(col<<2)+row]
75 #define B(row,col) b[(col<<2)+row]
76 #define P(row,col) p[(col<<2)+row]
77 GLfloat p[16];
78 GLint i;
79 for (i = 0; i < 4; i++) {
80 const GLfloat ai0=A(i,0), ai1=A(i,1), ai2=A(i,2), ai3=A(i,3);
81 P(i,0) = ai0 * B(0,0) + ai1 * B(1,0) + ai2 * B(2,0) + ai3 * B(3,0);
82 P(i,1) = ai0 * B(0,1) + ai1 * B(1,1) + ai2 * B(2,1) + ai3 * B(3,1);
83 P(i,2) = ai0 * B(0,2) + ai1 * B(1,2) + ai2 * B(2,2) + ai3 * B(3,2);
84 P(i,3) = ai0 * B(0,3) + ai1 * B(1,3) + ai2 * B(2,3) + ai3 * B(3,3);
85 }
86 memcpy(prod, p, sizeof(p));
87 #undef A
88 #undef B
89 #undef PROD
90 }
91
92
93 static void
draw(void)94 draw(void)
95 {
96 static const GLfloat verts[3][2] = {
97 { -1, -1 },
98 { 1, -1 },
99 { 0, 1 }
100 };
101 static const GLfloat colors[3][3] = {
102 { 1, 0, 0 },
103 { 0, 1, 0 },
104 { 0, 0, 1 }
105 };
106 GLfloat mat[16], rot[16], scale[16];
107
108 /* Set modelview/projection matrix */
109 make_z_rot_matrix(view_rotx, rot);
110 make_scale_matrix(0.5, 0.5, 0.5, scale);
111 mul_matrix(mat, rot, scale);
112 glUniformMatrix4fv(u_matrix, 1, GL_FALSE, mat);
113
114 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
115
116 {
117 glVertexAttribPointer(attr_pos, 2, GL_FLOAT, GL_FALSE, 0, verts);
118 glVertexAttribPointer(attr_color, 3, GL_FLOAT, GL_FALSE, 0, colors);
119 glEnableVertexAttribArray(attr_pos);
120 glEnableVertexAttribArray(attr_color);
121
122 glDrawArrays(GL_TRIANGLES, 0, 3);
123
124 glDisableVertexAttribArray(attr_pos);
125 glDisableVertexAttribArray(attr_color);
126 }
127 }
128
129
130 /* new window size or exposure */
131 static void
reshape(int width,int height)132 reshape(int width, int height)
133 {
134 glViewport(0, 0, (GLint) width, (GLint) height);
135 }
136
137
138 static void
create_shaders(void)139 create_shaders(void)
140 {
141 static const char *fragShaderText =
142 "precision mediump float;\n"
143 "varying vec4 v_color;\n"
144 "void main() {\n"
145 " gl_FragColor = v_color;\n"
146 "}\n";
147 static const char *vertShaderText =
148 "uniform mat4 modelviewProjection;\n"
149 "attribute vec4 pos;\n"
150 "attribute vec4 color;\n"
151 "varying vec4 v_color;\n"
152 "void main() {\n"
153 " gl_Position = modelviewProjection * pos;\n"
154 " v_color = color;\n"
155 "}\n";
156
157 GLuint fragShader, vertShader, program;
158 GLint stat;
159
160 fragShader = glCreateShader(GL_FRAGMENT_SHADER);
161 glShaderSource(fragShader, 1, (const char **) &fragShaderText, NULL);
162 glCompileShader(fragShader);
163 glGetShaderiv(fragShader, GL_COMPILE_STATUS, &stat);
164 if (!stat) {
165 printf("Error: fragment shader did not compile!\n");
166 exit(1);
167 }
168
169 vertShader = glCreateShader(GL_VERTEX_SHADER);
170 glShaderSource(vertShader, 1, (const char **) &vertShaderText, NULL);
171 glCompileShader(vertShader);
172 glGetShaderiv(vertShader, GL_COMPILE_STATUS, &stat);
173 if (!stat) {
174 printf("Error: vertex shader did not compile!\n");
175 exit(1);
176 }
177
178 program = glCreateProgram();
179 glAttachShader(program, fragShader);
180 glAttachShader(program, vertShader);
181 glLinkProgram(program);
182
183 glGetProgramiv(program, GL_LINK_STATUS, &stat);
184 if (!stat) {
185 char log[1000];
186 GLsizei len;
187 glGetProgramInfoLog(program, 1000, &len, log);
188 printf("Error: linking:\n%s\n", log);
189 exit(1);
190 }
191
192 glUseProgram(program);
193
194 if (1) {
195 /* test setting attrib locations */
196 glBindAttribLocation(program, attr_pos, "pos");
197 glBindAttribLocation(program, attr_color, "color");
198 glLinkProgram(program); /* needed to put attribs into effect */
199 }
200 else {
201 /* test automatic attrib locations */
202 attr_pos = glGetAttribLocation(program, "pos");
203 attr_color = glGetAttribLocation(program, "color");
204 }
205
206 u_matrix = glGetUniformLocation(program, "modelviewProjection");
207 printf("Uniform modelviewProjection at %d\n", u_matrix);
208 printf("Attrib pos at %d\n", attr_pos);
209 printf("Attrib color at %d\n", attr_color);
210 }
211
212
213 static void
init(void)214 init(void)
215 {
216 typedef void (*proc)();
217
218 #if 1 /* test code */
219 proc p = eglGetProcAddress("glMapBufferOES");
220 assert(p);
221 #endif
222
223 glClearColor(0.4, 0.4, 0.4, 0.0);
224
225 create_shaders();
226 }
227
228
229 /*
230 * Create an RGB, double-buffered X window.
231 * Return the window and context handles.
232 */
233 static void
make_x_window(Display * x_dpy,EGLDisplay egl_dpy,const char * name,int x,int y,int width,int height,Window * winRet,EGLContext * ctxRet,EGLSurface * surfRet)234 make_x_window(Display *x_dpy, EGLDisplay egl_dpy,
235 const char *name,
236 int x, int y, int width, int height,
237 Window *winRet,
238 EGLContext *ctxRet,
239 EGLSurface *surfRet)
240 {
241 static const EGLint attribs[] = {
242 EGL_RED_SIZE, 1,
243 EGL_GREEN_SIZE, 1,
244 EGL_BLUE_SIZE, 1,
245 EGL_DEPTH_SIZE, 1,
246 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
247 EGL_NONE
248 };
249 #if USE_FULL_GL
250 static const EGLint ctx_attribs[] = {
251 EGL_NONE
252 };
253 #else
254 static const EGLint ctx_attribs[] = {
255 EGL_CONTEXT_CLIENT_VERSION, 2,
256 EGL_NONE
257 };
258 #endif
259
260 int scrnum;
261 XSetWindowAttributes attr;
262 unsigned long mask;
263 Window root;
264 Window win;
265 XVisualInfo *visInfo, visTemplate;
266 int num_visuals;
267 EGLContext ctx;
268 EGLConfig config;
269 EGLint num_configs;
270 EGLint vid;
271
272 scrnum = DefaultScreen( x_dpy );
273 root = RootWindow( x_dpy, scrnum );
274
275 if (!eglChooseConfig( egl_dpy, attribs, &config, 1, &num_configs)) {
276 printf("Error: couldn't get an EGL visual config\n");
277 exit(1);
278 }
279
280 assert(config);
281 assert(num_configs > 0);
282
283 if (!eglGetConfigAttrib(egl_dpy, config, EGL_NATIVE_VISUAL_ID, &vid)) {
284 printf("Error: eglGetConfigAttrib() failed\n");
285 exit(1);
286 }
287
288 /* The X window visual must match the EGL config */
289 visTemplate.visualid = vid;
290 visInfo = XGetVisualInfo(x_dpy, VisualIDMask, &visTemplate, &num_visuals);
291 if (!visInfo) {
292 printf("Error: couldn't get X visual\n");
293 exit(1);
294 }
295
296 /* window attributes */
297 attr.background_pixel = 0;
298 attr.border_pixel = 0;
299 attr.colormap = XCreateColormap( x_dpy, root, visInfo->visual, AllocNone);
300 attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
301 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
302
303 win = XCreateWindow( x_dpy, root, 0, 0, width, height,
304 0, visInfo->depth, InputOutput,
305 visInfo->visual, mask, &attr );
306
307 /* set hints and properties */
308 {
309 XSizeHints sizehints;
310 sizehints.x = x;
311 sizehints.y = y;
312 sizehints.width = width;
313 sizehints.height = height;
314 sizehints.flags = USSize | USPosition;
315 XSetNormalHints(x_dpy, win, &sizehints);
316 XSetStandardProperties(x_dpy, win, name, name,
317 None, (char **)NULL, 0, &sizehints);
318 }
319
320 #if USE_FULL_GL /* XXX fix this when eglBindAPI() works */
321 eglBindAPI(EGL_OPENGL_API);
322 #else
323 eglBindAPI(EGL_OPENGL_ES_API);
324 #endif
325
326 ctx = eglCreateContext(egl_dpy, config, EGL_NO_CONTEXT, ctx_attribs );
327 if (!ctx) {
328 printf("Error: eglCreateContext failed\n");
329 exit(1);
330 }
331
332 #if !USE_FULL_GL
333 /* test eglQueryContext() */
334 {
335 EGLint val;
336 eglQueryContext(egl_dpy, ctx, EGL_CONTEXT_CLIENT_VERSION, &val);
337 assert(val == 2);
338 }
339 #endif
340
341 *surfRet = eglCreateWindowSurface(egl_dpy, config, win, NULL);
342 if (!*surfRet) {
343 printf("Error: eglCreateWindowSurface failed\n");
344 exit(1);
345 }
346
347 /* sanity checks */
348 {
349 EGLint val;
350 eglQuerySurface(egl_dpy, *surfRet, EGL_WIDTH, &val);
351 assert(val == width);
352 eglQuerySurface(egl_dpy, *surfRet, EGL_HEIGHT, &val);
353 assert(val == height);
354 assert(eglGetConfigAttrib(egl_dpy, config, EGL_SURFACE_TYPE, &val));
355 assert(val & EGL_WINDOW_BIT);
356 }
357
358 XFree(visInfo);
359
360 *winRet = win;
361 *ctxRet = ctx;
362 }
363
364
365 static void
event_loop(Display * dpy,Window win,EGLDisplay egl_dpy,EGLSurface egl_surf)366 event_loop(Display *dpy, Window win,
367 EGLDisplay egl_dpy, EGLSurface egl_surf)
368 {
369 while (1) {
370 int redraw = 0;
371 XEvent event;
372
373 XNextEvent(dpy, &event);
374
375 switch (event.type) {
376 case Expose:
377 redraw = 1;
378 break;
379 case ConfigureNotify:
380 reshape(event.xconfigure.width, event.xconfigure.height);
381 break;
382 case KeyPress:
383 {
384 char buffer[10];
385 int r, code;
386 code = XLookupKeysym(&event.xkey, 0);
387 if (code == XK_Left) {
388 view_roty += 5.0;
389 }
390 else if (code == XK_Right) {
391 view_roty -= 5.0;
392 }
393 else if (code == XK_Up) {
394 view_rotx += 5.0;
395 }
396 else if (code == XK_Down) {
397 view_rotx -= 5.0;
398 }
399 else {
400 r = XLookupString(&event.xkey, buffer, sizeof(buffer),
401 NULL, NULL);
402 if (buffer[0] == 27) {
403 /* escape */
404 return;
405 }
406 }
407 }
408 redraw = 1;
409 break;
410 default:
411 ; /*no-op*/
412 }
413
414 if (redraw) {
415 draw();
416 eglSwapBuffers(egl_dpy, egl_surf);
417 }
418 }
419 }
420
421
422 static void
usage(void)423 usage(void)
424 {
425 printf("Usage:\n");
426 printf(" -display <displayname> set the display to run on\n");
427 printf(" -info display OpenGL renderer info\n");
428 }
429
430
431 int
main(int argc,char * argv[])432 main(int argc, char *argv[])
433 {
434 const int winWidth = 300, winHeight = 300;
435 Display *x_dpy;
436 Window win;
437 EGLSurface egl_surf;
438 EGLContext egl_ctx;
439 EGLDisplay egl_dpy;
440 char *dpyName = NULL;
441 GLboolean printInfo = GL_FALSE;
442 EGLint egl_major, egl_minor;
443 int i;
444 const char *s;
445
446 for (i = 1; i < argc; i++) {
447 if (strcmp(argv[i], "-display") == 0) {
448 dpyName = argv[i+1];
449 i++;
450 }
451 else if (strcmp(argv[i], "-info") == 0) {
452 printInfo = GL_TRUE;
453 }
454 else {
455 usage();
456 return -1;
457 }
458 }
459
460 x_dpy = XOpenDisplay(dpyName);
461 if (!x_dpy) {
462 printf("Error: couldn't open display %s\n",
463 dpyName ? dpyName : getenv("DISPLAY"));
464 return -1;
465 }
466
467 egl_dpy = eglGetDisplay(x_dpy);
468 if (!egl_dpy) {
469 printf("Error: eglGetDisplay() failed\n");
470 return -1;
471 }
472
473 if (!eglInitialize(egl_dpy, &egl_major, &egl_minor)) {
474 printf("Error: eglInitialize() failed\n");
475 return -1;
476 }
477
478 s = eglQueryString(egl_dpy, EGL_VERSION);
479 printf("EGL_VERSION = %s\n", s);
480
481 s = eglQueryString(egl_dpy, EGL_VENDOR);
482 printf("EGL_VENDOR = %s\n", s);
483
484 s = eglQueryString(egl_dpy, EGL_EXTENSIONS);
485 printf("EGL_EXTENSIONS = %s\n", s);
486
487 s = eglQueryString(egl_dpy, EGL_CLIENT_APIS);
488 printf("EGL_CLIENT_APIS = %s\n", s);
489
490 make_x_window(x_dpy, egl_dpy,
491 "OpenGL ES 2.x tri", 0, 0, winWidth, winHeight,
492 &win, &egl_ctx, &egl_surf);
493
494 XMapWindow(x_dpy, win);
495 if (!eglMakeCurrent(egl_dpy, egl_surf, egl_surf, egl_ctx)) {
496 printf("Error: eglMakeCurrent() failed\n");
497 return -1;
498 }
499
500 if (printInfo) {
501 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
502 printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
503 printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
504 printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
505 }
506
507 init();
508
509 /* Set initial projection/viewing transformation.
510 * We can't be sure we'll get a ConfigureNotify event when the window
511 * first appears.
512 */
513 reshape(winWidth, winHeight);
514
515 event_loop(x_dpy, win, egl_dpy, egl_surf);
516
517 eglDestroyContext(egl_dpy, egl_ctx);
518 eglDestroySurface(egl_dpy, egl_surf);
519 eglTerminate(egl_dpy);
520
521
522 XDestroyWindow(x_dpy, win);
523 XCloseDisplay(x_dpy);
524
525 return 0;
526 }
527