]> git.cworth.org Git - apitrace-tests/blob - apps/egl/gles2/tri_glsl.c
Make tri_glsl test robust against attribute location changes.
[apitrace-tests] / apps / egl / gles2 / tri_glsl.c
1 /**************************************************************************
2  *
3  * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
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/gl.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
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
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
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
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
132 reshape(int width, int height)
133 {
134    glViewport(0, 0, (GLint) width, (GLint) height);
135 }
136
137
138 static void
139 create_shaders(void)
140 {
141    static const char *fragShaderText =
142       "varying vec4 v_color;\n"
143       "void main() {\n"
144       "   gl_FragColor = v_color;\n"
145       "}\n";
146    static const char *vertShaderText =
147       "uniform mat4 modelviewProjection;\n"
148       "attribute vec4 pos;\n"
149       "attribute vec4 color;\n"
150       "varying vec4 v_color;\n"
151       "void main() {\n"
152       "   gl_Position = modelviewProjection * pos;\n"
153       "   v_color = color;\n"
154       "}\n";
155
156    GLuint fragShader, vertShader, program;
157    GLint stat;
158
159    fragShader = glCreateShader(GL_FRAGMENT_SHADER);
160    glShaderSource(fragShader, 1, (const char **) &fragShaderText, NULL);
161    glCompileShader(fragShader);
162    glGetShaderiv(fragShader, GL_COMPILE_STATUS, &stat);
163    if (!stat) {
164       fprintf(stderr, "error: fragment shader did not compile!\n");
165       exit(1);
166    }
167
168    vertShader = glCreateShader(GL_VERTEX_SHADER);
169    glShaderSource(vertShader, 1, (const char **) &vertShaderText, NULL);
170    glCompileShader(vertShader);
171    glGetShaderiv(vertShader, GL_COMPILE_STATUS, &stat);
172    if (!stat) {
173       fprintf(stderr, "error: vertex shader did not compile!\n");
174       exit(1);
175    }
176
177    program = glCreateProgram();
178    glAttachShader(program, fragShader);
179    glAttachShader(program, vertShader);
180    glBindAttribLocation(program, attr_pos, "pos");
181    glBindAttribLocation(program, attr_color, "color");
182    glLinkProgram(program);
183
184    glGetProgramiv(program, GL_LINK_STATUS, &stat);
185    if (!stat) {
186       char log[1000];
187       GLsizei len;
188       glGetProgramInfoLog(program, 1000, &len, log);
189       fprintf(stderr, "error: linking:\n%s\n", log);
190       exit(1);
191    }
192
193    glUseProgram(program);
194
195    attr_pos = glGetAttribLocation(program, "pos");
196    attr_color = glGetAttribLocation(program, "color");
197
198    u_matrix = glGetUniformLocation(program, "modelviewProjection");
199 }
200
201
202 static void
203 init(void)
204 {
205    typedef void (*proc)();
206
207 #if 1 /* test code */
208    proc p = eglGetProcAddress("glMapBufferOES");
209    assert(p);
210 #endif
211
212    glClearColor(0.4, 0.4, 0.4, 0.0);
213
214    create_shaders();
215 }
216
217
218 /*
219  * Create an RGB, double-buffered X window.
220  * Return the window and context handles.
221  */
222 static void
223 make_x_window(Display *x_dpy, EGLDisplay egl_dpy,
224               const char *name,
225               int x, int y, int width, int height,
226               Window *winRet,
227               EGLContext *ctxRet,
228               EGLSurface *surfRet)
229 {
230    static const EGLint attribs[] = {
231       EGL_RED_SIZE, 1,
232       EGL_GREEN_SIZE, 1,
233       EGL_BLUE_SIZE, 1,
234       EGL_DEPTH_SIZE, 1,
235       EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
236       EGL_NONE
237    };
238 #if USE_FULL_GL
239    static const EGLint ctx_attribs[] = {
240        EGL_NONE
241    };
242 #else
243    static const EGLint ctx_attribs[] = {
244       EGL_CONTEXT_CLIENT_VERSION, 2,
245       EGL_NONE
246    };
247 #endif
248
249    int scrnum;
250    XSetWindowAttributes attr;
251    unsigned long mask;
252    Window root;
253    Window win;
254    XVisualInfo *visInfo, visTemplate;
255    int num_visuals;
256    EGLContext ctx;
257    EGLConfig config;
258    EGLint num_configs;
259    EGLint vid;
260
261    scrnum = DefaultScreen( x_dpy );
262    root = RootWindow( x_dpy, scrnum );
263
264    if (!eglChooseConfig( egl_dpy, attribs, &config, 1, &num_configs)) {
265       fprintf(stderr, "error: couldn't get an EGL visual config\n");
266       exit(1);
267    }
268
269    assert(config);
270    assert(num_configs > 0);
271
272    if (!eglGetConfigAttrib(egl_dpy, config, EGL_NATIVE_VISUAL_ID, &vid)) {
273       fprintf(stderr, "error: eglGetConfigAttrib() failed\n");
274       exit(1);
275    }
276
277    /* The X window visual must match the EGL config */
278    visTemplate.visualid = vid;
279    visInfo = XGetVisualInfo(x_dpy, VisualIDMask, &visTemplate, &num_visuals);
280    if (!visInfo) {
281       fprintf(stderr, "error: couldn't get X visual\n");
282       exit(1);
283    }
284
285    /* window attributes */
286    attr.background_pixel = 0;
287    attr.border_pixel = 0;
288    attr.colormap = XCreateColormap( x_dpy, root, visInfo->visual, AllocNone);
289    attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
290    mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
291
292    win = XCreateWindow( x_dpy, root, 0, 0, width, height,
293                         0, visInfo->depth, InputOutput,
294                         visInfo->visual, mask, &attr );
295
296    /* set hints and properties */
297    {
298       XSizeHints sizehints;
299       sizehints.x = x;
300       sizehints.y = y;
301       sizehints.width  = width;
302       sizehints.height = height;
303       sizehints.flags = USSize | USPosition;
304       XSetNormalHints(x_dpy, win, &sizehints);
305       XSetStandardProperties(x_dpy, win, name, name,
306                               None, (char **)NULL, 0, &sizehints);
307    }
308
309 #if USE_FULL_GL /* XXX fix this when eglBindAPI() works */
310    eglBindAPI(EGL_OPENGL_API);
311 #else
312    eglBindAPI(EGL_OPENGL_ES_API);
313 #endif
314
315    ctx = eglCreateContext(egl_dpy, config, EGL_NO_CONTEXT, ctx_attribs );
316    if (!ctx) {
317       fprintf(stderr, "error: eglCreateContext failed\n");
318       exit(1);
319    }
320
321 #if !USE_FULL_GL
322    /* test eglQueryContext() */
323    {
324       EGLint val;
325       eglQueryContext(egl_dpy, ctx, EGL_CONTEXT_CLIENT_VERSION, &val);
326       assert(val == 2);
327    }
328 #endif
329
330    *surfRet = eglCreateWindowSurface(egl_dpy, config, win, NULL);
331    if (!*surfRet) {
332       fprintf(stderr, "error: eglCreateWindowSurface failed\n");
333       exit(1);
334    }
335
336    /* sanity checks */
337    {
338       EGLint val;
339       eglQuerySurface(egl_dpy, *surfRet, EGL_WIDTH, &val);
340       assert(val == width);
341       eglQuerySurface(egl_dpy, *surfRet, EGL_HEIGHT, &val);
342       assert(val == height);
343       assert(eglGetConfigAttrib(egl_dpy, config, EGL_SURFACE_TYPE, &val));
344       assert(val & EGL_WINDOW_BIT);
345    }
346
347    XFree(visInfo);
348
349    *winRet = win;
350    *ctxRet = ctx;
351 }
352
353
354 static void
355 event_loop(Display *dpy, Window win,
356            EGLDisplay egl_dpy, EGLSurface egl_surf)
357 {
358    while (1) {
359       int redraw = 0;
360       XEvent event;
361
362       XNextEvent(dpy, &event);
363
364       switch (event.type) {
365       case Expose:
366          redraw = 1;
367          break;
368       case ConfigureNotify:
369          reshape(event.xconfigure.width, event.xconfigure.height);
370          break;
371       case KeyPress:
372          {
373             char buffer[10];
374             int r, code;
375             code = XLookupKeysym(&event.xkey, 0);
376             if (code == XK_Left) {
377                view_roty += 5.0;
378             }
379             else if (code == XK_Right) {
380                view_roty -= 5.0;
381             }
382             else if (code == XK_Up) {
383                view_rotx += 5.0;
384             }
385             else if (code == XK_Down) {
386                view_rotx -= 5.0;
387             }
388             else {
389                r = XLookupString(&event.xkey, buffer, sizeof(buffer),
390                                  NULL, NULL);
391                if (buffer[0] == 27) {
392                   /* escape */
393                   return;
394                }
395             }
396          }
397          redraw = 1;
398          break;
399       default:
400          ; /*no-op*/
401       }
402
403       if (redraw) {
404          draw();
405          eglSwapBuffers(egl_dpy, egl_surf);
406          exit(0);
407       }
408    }
409 }
410
411
412 static void
413 usage(void)
414 {
415    printf("Usage:\n");
416    printf("  -display <displayname>  set the display to run on\n");
417    printf("  -info                   display OpenGL renderer info\n");
418 }
419
420
421 int
422 main(int argc, char *argv[])
423 {
424    const int winWidth = 300, winHeight = 300;
425    Display *x_dpy;
426    Window win;
427    EGLSurface egl_surf;
428    EGLContext egl_ctx;
429    EGLDisplay egl_dpy;
430    char *dpyName = NULL;
431    GLboolean printInfo = GL_FALSE;
432    EGLint egl_major, egl_minor;
433    int i;
434    const char *s;
435
436    for (i = 1; i < argc; i++) {
437       if (strcmp(argv[i], "-display") == 0) {
438          dpyName = argv[i+1];
439          i++;
440       }
441       else if (strcmp(argv[i], "-info") == 0) {
442          printInfo = GL_TRUE;
443       }
444       else {
445          usage();
446          return -1;
447       }
448    }
449
450    x_dpy = XOpenDisplay(dpyName);
451    if (!x_dpy) {
452       fprintf(stderr, "error: couldn't open display %s\n",
453              dpyName ? dpyName : getenv("DISPLAY"));
454       return -1;
455    }
456
457    egl_dpy = eglGetDisplay(x_dpy);
458    if (!egl_dpy) {
459       fprintf(stderr, "error: eglGetDisplay() failed\n");
460       return -1;
461    }
462
463    if (!eglInitialize(egl_dpy, &egl_major, &egl_minor)) {
464       fprintf(stderr, "error: eglInitialize() failed\n");
465       return -1;
466    }
467
468    s = eglQueryString(egl_dpy, EGL_VERSION);
469    printf("EGL_VERSION = %s\n", s);
470
471    s = eglQueryString(egl_dpy, EGL_VENDOR);
472    printf("EGL_VENDOR = %s\n", s);
473
474    s = eglQueryString(egl_dpy, EGL_EXTENSIONS);
475    printf("EGL_EXTENSIONS = %s\n", s);
476
477    s = eglQueryString(egl_dpy, EGL_CLIENT_APIS);
478    printf("EGL_CLIENT_APIS = %s\n", s);
479
480    make_x_window(x_dpy, egl_dpy,
481                  "OpenGL ES 2.x tri", 0, 0, winWidth, winHeight,
482                  &win, &egl_ctx, &egl_surf);
483
484    XMapWindow(x_dpy, win);
485    if (!eglMakeCurrent(egl_dpy, egl_surf, egl_surf, egl_ctx)) {
486       fprintf(stderr, "error: eglMakeCurrent() failed\n");
487       return -1;
488    }
489
490    if (printInfo) {
491       printf("GL_RENDERER   = %s\n", (char *) glGetString(GL_RENDERER));
492       printf("GL_VERSION    = %s\n", (char *) glGetString(GL_VERSION));
493       printf("GL_VENDOR     = %s\n", (char *) glGetString(GL_VENDOR));
494       printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
495    }
496
497    init();
498
499    /* Set initial projection/viewing transformation.
500     * We can't be sure we'll get a ConfigureNotify event when the window
501     * first appears.
502     */
503    reshape(winWidth, winHeight);
504
505    event_loop(x_dpy, win, egl_dpy, egl_surf);
506
507    eglDestroyContext(egl_dpy, egl_ctx);
508    eglDestroySurface(egl_dpy, egl_surf);
509    eglTerminate(egl_dpy);
510
511
512    XDestroyWindow(x_dpy, win);
513    XCloseDisplay(x_dpy);
514
515    return 0;
516 }