Merge branch '7.8'
[mesa.git] / progs / egl / opengles1 / pbuffer.c
1 /*
2 * Copyright (C) 2008 Tunsgten Graphics,Inc. All Rights Reserved.
3 */
4
5 /*
6 * Test EGL Pbuffers
7 * Brian Paul
8 * August 2008
9 */
10
11
12 #include <assert.h>
13 #include <math.h>
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <X11/Xlib.h>
18 #include <X11/Xutil.h>
19 #include <X11/keysym.h>
20 #include <GLES/gl.h>
21 #include <GLES/glext.h>
22 #include <EGL/egl.h>
23
24
25
26 static int WinWidth = 300, WinHeight = 300;
27
28 static GLfloat view_rotx = 0.0, view_roty = 0.0, view_rotz = 0.0;
29
30
31 static void
32 Normal(GLfloat *n, GLfloat nx, GLfloat ny, GLfloat nz)
33 {
34 n[0] = nx;
35 n[1] = ny;
36 n[2] = nz;
37 }
38
39 static void
40 Vertex(GLfloat *v, GLfloat vx, GLfloat vy, GLfloat vz)
41 {
42 v[0] = vx;
43 v[1] = vy;
44 v[2] = vz;
45 }
46
47 static void
48 Texcoord(GLfloat *v, GLfloat s, GLfloat t)
49 {
50 v[0] = s;
51 v[1] = t;
52 }
53
54
55 /* Borrowed from glut, adapted */
56 static void
57 draw_torus(GLfloat r, GLfloat R, GLint nsides, GLint rings)
58 {
59 int i, j;
60 GLfloat theta, phi, theta1;
61 GLfloat cosTheta, sinTheta;
62 GLfloat cosTheta1, sinTheta1;
63 GLfloat ringDelta, sideDelta;
64 GLfloat varray[100][3], narray[100][3], tarray[100][2];
65 int vcount;
66
67 glVertexPointer(3, GL_FLOAT, 0, varray);
68 glNormalPointer(GL_FLOAT, 0, narray);
69 glTexCoordPointer(2, GL_FLOAT, 0, tarray);
70 glEnableClientState(GL_VERTEX_ARRAY);
71 glEnableClientState(GL_NORMAL_ARRAY);
72 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
73
74 ringDelta = 2.0 * M_PI / rings;
75 sideDelta = 2.0 * M_PI / nsides;
76
77 theta = 0.0;
78 cosTheta = 1.0;
79 sinTheta = 0.0;
80 for (i = rings - 1; i >= 0; i--) {
81 theta1 = theta + ringDelta;
82 cosTheta1 = cos(theta1);
83 sinTheta1 = sin(theta1);
84
85 vcount = 0; /* glBegin(GL_QUAD_STRIP); */
86
87 phi = 0.0;
88 for (j = nsides; j >= 0; j--) {
89 GLfloat s0, s1, t;
90 GLfloat cosPhi, sinPhi, dist;
91
92 phi += sideDelta;
93 cosPhi = cos(phi);
94 sinPhi = sin(phi);
95 dist = R + r * cosPhi;
96
97 s0 = 20.0 * theta / (2.0 * M_PI);
98 s1 = 20.0 * theta1 / (2.0 * M_PI);
99 t = 8.0 * phi / (2.0 * M_PI);
100
101 Normal(narray[vcount], cosTheta1 * cosPhi, -sinTheta1 * cosPhi, sinPhi);
102 Texcoord(tarray[vcount], s1, t);
103 Vertex(varray[vcount], cosTheta1 * dist, -sinTheta1 * dist, r * sinPhi);
104 vcount++;
105
106 Normal(narray[vcount], cosTheta * cosPhi, -sinTheta * cosPhi, sinPhi);
107 Texcoord(tarray[vcount], s0, t);
108 Vertex(varray[vcount], cosTheta * dist, -sinTheta * dist, r * sinPhi);
109 vcount++;
110 }
111
112 /*glEnd();*/
113 assert(vcount <= 100);
114 glDrawArrays(GL_TRIANGLE_STRIP, 0, vcount);
115
116 theta = theta1;
117 cosTheta = cosTheta1;
118 sinTheta = sinTheta1;
119 }
120
121 glDisableClientState(GL_VERTEX_ARRAY);
122 glDisableClientState(GL_NORMAL_ARRAY);
123 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
124 }
125
126
127 static void
128 draw(void)
129 {
130 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
131
132 glPushMatrix();
133 glRotatef(view_rotx, 1, 0, 0);
134 glRotatef(view_roty, 0, 1, 0);
135 glRotatef(view_rotz, 0, 0, 1);
136 glScalef(0.5, 0.5, 0.5);
137
138 draw_torus(1.0, 3.0, 30, 60);
139
140 glPopMatrix();
141
142 glFinish();
143 }
144
145
146 /**
147 * Draw to both the window and pbuffer and compare results.
148 */
149 static void
150 draw_both(EGLDisplay egl_dpy, EGLSurface egl_surf, EGLSurface egl_pbuf,
151 EGLContext egl_ctx)
152 {
153 unsigned *wbuf, *pbuf;
154 int x = 100, y = 110;
155 int i, dif;
156
157 wbuf = (unsigned *) malloc(WinWidth * WinHeight * 4);
158 pbuf = (unsigned *) malloc(WinWidth * WinHeight * 4);
159
160 glPixelStorei(GL_PACK_ALIGNMENT, 1);
161
162 /* first draw to window */
163 if (!eglMakeCurrent(egl_dpy, egl_surf, egl_surf, egl_ctx)) {
164 printf("Error: eglMakeCurrent(window) failed\n");
165 return;
166 }
167 draw();
168 glReadPixels(0, 0, WinWidth, WinHeight, GL_RGBA, GL_UNSIGNED_BYTE, wbuf);
169 printf("Window[%d,%d] = 0x%08x\n", x, y, wbuf[y*WinWidth+x]);
170
171 /* then draw to pbuffer */
172 if (!eglMakeCurrent(egl_dpy, egl_pbuf, egl_pbuf, egl_ctx)) {
173 printf("Error: eglMakeCurrent(pbuffer) failed\n");
174 return;
175 }
176 draw();
177 glReadPixels(0, 0, WinWidth, WinHeight, GL_RGBA, GL_UNSIGNED_BYTE, pbuf);
178 printf("Pbuffer[%d,%d] = 0x%08x\n", x, y, pbuf[y*WinWidth+x]);
179
180 eglSwapBuffers(egl_dpy, egl_surf);
181
182 /* compare renderings */
183 for (dif = i = 0; i < WinWidth * WinHeight; i++) {
184 if (wbuf[i] != pbuf[i]) {
185 dif = 1;
186 break;
187 }
188 }
189
190 if (dif)
191 printf("Difference at %d: 0x%08x vs. 0x%08x\n", i, wbuf[i], pbuf[i]);
192 else
193 printf("Window rendering matches Pbuffer rendering!\n");
194
195 free(wbuf);
196 free(pbuf);
197 }
198
199
200 /* new window size or exposure */
201 static void
202 reshape(int width, int height)
203 {
204 GLfloat ar = (GLfloat) width / (GLfloat) height;
205
206 WinWidth = width;
207 WinHeight = height;
208
209 glViewport(0, 0, (GLint) width, (GLint) height);
210
211 glMatrixMode(GL_PROJECTION);
212 glLoadIdentity();
213
214 #ifdef GL_VERSION_ES_CM_1_0
215 glFrustumf(-ar, ar, -1, 1, 5.0, 60.0);
216 #else
217 glFrustum(-ar, ar, -1, 1, 5.0, 60.0);
218 #endif
219
220 glMatrixMode(GL_MODELVIEW);
221 glLoadIdentity();
222 glTranslatef(0.0, 0.0, -15.0);
223 }
224
225
226 static void
227 make_texture(void)
228 {
229 #define SZ 64
230 GLenum Filter = GL_LINEAR;
231 GLubyte image[SZ][SZ][4];
232 GLuint i, j;
233
234 for (i = 0; i < SZ; i++) {
235 for (j = 0; j < SZ; j++) {
236 GLfloat d = (i - SZ/2) * (i - SZ/2) + (j - SZ/2) * (j - SZ/2);
237 d = sqrt(d);
238 if (d < SZ/3) {
239 image[i][j][0] = 255;
240 image[i][j][1] = 255;
241 image[i][j][2] = 255;
242 image[i][j][3] = 255;
243 }
244 else {
245 image[i][j][0] = 127;
246 image[i][j][1] = 127;
247 image[i][j][2] = 127;
248 image[i][j][3] = 255;
249 }
250 }
251 }
252
253 glActiveTexture(GL_TEXTURE0); /* unit 0 */
254 glBindTexture(GL_TEXTURE_2D, 42);
255 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SZ, SZ, 0,
256 GL_RGBA, GL_UNSIGNED_BYTE, image);
257 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, Filter);
258 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, Filter);
259 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
260 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
261 #undef SZ
262 }
263
264
265
266 static void
267 init(void)
268 {
269 static const GLfloat red[4] = {1, 0, 0, 0};
270 static const GLfloat white[4] = {1.0, 1.0, 1.0, 1.0};
271 static const GLfloat diffuse[4] = {0.7, 0.7, 0.7, 1.0};
272 static const GLfloat specular[4] = {0.001, 0.001, 0.001, 1.0};
273 static const GLfloat pos[4] = {20, 20, 50, 1};
274
275 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, red);
276 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, white);
277 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 9.0);
278
279 glEnable(GL_LIGHTING);
280 glEnable(GL_LIGHT0);
281 glLightfv(GL_LIGHT0, GL_POSITION, pos);
282 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
283 glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
284
285 glClearColor(0.4, 0.4, 0.4, 0.0);
286 glEnable(GL_DEPTH_TEST);
287
288 make_texture();
289 glEnable(GL_TEXTURE_2D);
290 }
291
292
293 /*
294 * Create an RGB, double-buffered X window.
295 * Return the window and context handles.
296 */
297 static void
298 make_x_window(Display *x_dpy, EGLDisplay egl_dpy,
299 const char *name,
300 int x, int y, int width, int height,
301 Window *winRet,
302 EGLContext *ctxRet,
303 EGLSurface *surfRet)
304 {
305 static const EGLint attribs[] = {
306 EGL_RED_SIZE, 1,
307 EGL_GREEN_SIZE, 1,
308 EGL_BLUE_SIZE, 1,
309 EGL_DEPTH_SIZE, 1,
310 EGL_NONE
311 };
312
313 int scrnum;
314 XSetWindowAttributes attr;
315 unsigned long mask;
316 Window root;
317 Window win;
318 XVisualInfo *visInfo, visTemplate;
319 int num_visuals;
320 EGLContext ctx;
321 EGLConfig config;
322 EGLint num_configs;
323 EGLint vid;
324
325 scrnum = DefaultScreen( x_dpy );
326 root = RootWindow( x_dpy, scrnum );
327
328 if (!eglChooseConfig( egl_dpy, attribs, &config, 1, &num_configs)) {
329 printf("Error: couldn't get an EGL visual config\n");
330 exit(1);
331 }
332
333 assert(config);
334 assert(num_configs > 0);
335
336 if (!eglGetConfigAttrib(egl_dpy, config, EGL_NATIVE_VISUAL_ID, &vid)) {
337 printf("Error: eglGetConfigAttrib() failed\n");
338 exit(1);
339 }
340
341 /* The X window visual must match the EGL config */
342 visTemplate.visualid = vid;
343 visInfo = XGetVisualInfo(x_dpy, VisualIDMask, &visTemplate, &num_visuals);
344 if (!visInfo) {
345 printf("Error: couldn't get X visual\n");
346 exit(1);
347 }
348
349 /* window attributes */
350 attr.background_pixel = 0;
351 attr.border_pixel = 0;
352 attr.colormap = XCreateColormap( x_dpy, root, visInfo->visual, AllocNone);
353 attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
354 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
355
356 win = XCreateWindow( x_dpy, root, 0, 0, width, height,
357 0, visInfo->depth, InputOutput,
358 visInfo->visual, mask, &attr );
359
360 /* set hints and properties */
361 {
362 XSizeHints sizehints;
363 sizehints.x = x;
364 sizehints.y = y;
365 sizehints.width = width;
366 sizehints.height = height;
367 sizehints.flags = USSize | USPosition;
368 XSetNormalHints(x_dpy, win, &sizehints);
369 XSetStandardProperties(x_dpy, win, name, name,
370 None, (char **)NULL, 0, &sizehints);
371 }
372
373 eglBindAPI(EGL_OPENGL_ES_API);
374
375 ctx = eglCreateContext(egl_dpy, config, EGL_NO_CONTEXT, NULL );
376 if (!ctx) {
377 printf("Error: eglCreateContext failed\n");
378 exit(1);
379 }
380
381 *surfRet = eglCreateWindowSurface(egl_dpy, config, win, NULL);
382
383 if (!*surfRet) {
384 printf("Error: eglCreateWindowSurface failed\n");
385 exit(1);
386 }
387
388 XFree(visInfo);
389
390 *winRet = win;
391 *ctxRet = ctx;
392 }
393
394
395 static EGLSurface
396 make_pbuffer(Display *x_dpy, EGLDisplay egl_dpy, int width, int height)
397 {
398 static const EGLint config_attribs[] = {
399 EGL_RED_SIZE, 1,
400 EGL_GREEN_SIZE, 1,
401 EGL_BLUE_SIZE, 1,
402 EGL_DEPTH_SIZE, 1,
403 EGL_NONE
404 };
405 EGLConfig config;
406 EGLSurface pbuf;
407 EGLint num_configs;
408 EGLint pbuf_attribs[5];
409
410 pbuf_attribs[0] = EGL_WIDTH;
411 pbuf_attribs[1] = width;
412 pbuf_attribs[2] = EGL_HEIGHT;
413 pbuf_attribs[3] = height;
414 pbuf_attribs[4] = EGL_NONE;
415
416 if (!eglChooseConfig( egl_dpy, config_attribs, &config, 1, &num_configs)) {
417 printf("Error: couldn't get an EGL config for pbuffer\n");
418 exit(1);
419 }
420
421 pbuf = eglCreatePbufferSurface(egl_dpy, config, pbuf_attribs);
422
423 return pbuf;
424 }
425
426
427 static void
428 event_loop(Display *dpy, Window win,
429 EGLDisplay egl_dpy, EGLSurface egl_surf, EGLSurface egl_pbuf,
430 EGLContext egl_ctx)
431 {
432 int anim = 0;
433
434 while (1) {
435 int redraw = 0;
436
437 if (!anim || XPending(dpy)) {
438 XEvent event;
439 XNextEvent(dpy, &event);
440
441 switch (event.type) {
442 case Expose:
443 redraw = 1;
444 break;
445 case ConfigureNotify:
446 if (event.xconfigure.window == win)
447 reshape(event.xconfigure.width, event.xconfigure.height);
448 break;
449 case KeyPress:
450 {
451 char buffer[10];
452 int r, code;
453 code = XLookupKeysym(&event.xkey, 0);
454 if (code == XK_Left) {
455 view_roty += 5.0;
456 }
457 else if (code == XK_Right) {
458 view_roty -= 5.0;
459 }
460 else if (code == XK_Up) {
461 view_rotx += 5.0;
462 }
463 else if (code == XK_Down) {
464 view_rotx -= 5.0;
465 }
466 else {
467 r = XLookupString(&event.xkey, buffer, sizeof(buffer),
468 NULL, NULL);
469 if (buffer[0] == ' ') {
470 anim = !anim;
471 }
472 else if (buffer[0] == 27) {
473 /* escape */
474 return;
475 }
476 }
477 }
478 redraw = 1;
479 break;
480 default:
481 ; /*no-op*/
482 }
483 }
484
485 if (anim) {
486 view_rotx += 1.0;
487 view_roty += 2.0;
488 redraw = 1;
489 }
490
491 if (redraw) {
492 draw_both(egl_dpy, egl_surf, egl_pbuf, egl_ctx);
493 }
494 }
495 }
496
497
498 static void
499 usage(void)
500 {
501 printf("Usage:\n");
502 printf(" -display <displayname> set the display to run on\n");
503 printf(" -info display OpenGL renderer info\n");
504 }
505
506
507 int
508 main(int argc, char *argv[])
509 {
510 Display *x_dpy;
511 Window win;
512 EGLSurface egl_surf, egl_pbuf;
513 EGLContext egl_ctx;
514 EGLDisplay egl_dpy;
515 char *dpyName = NULL;
516 GLboolean printInfo = GL_FALSE;
517 EGLint egl_major, egl_minor;
518 int i;
519 const char *s;
520
521 for (i = 1; i < argc; i++) {
522 if (strcmp(argv[i], "-display") == 0) {
523 dpyName = argv[i+1];
524 i++;
525 }
526 else if (strcmp(argv[i], "-info") == 0) {
527 printInfo = GL_TRUE;
528 }
529 else {
530 usage();
531 return -1;
532 }
533 }
534
535 x_dpy = XOpenDisplay(dpyName);
536 if (!x_dpy) {
537 printf("Error: couldn't open display %s\n",
538 dpyName ? dpyName : getenv("DISPLAY"));
539 return -1;
540 }
541
542 egl_dpy = eglGetDisplay(x_dpy);
543 if (!egl_dpy) {
544 printf("Error: eglGetDisplay() failed\n");
545 return -1;
546 }
547
548 if (!eglInitialize(egl_dpy, &egl_major, &egl_minor)) {
549 printf("Error: eglInitialize() failed\n");
550 return -1;
551 }
552
553 s = eglQueryString(egl_dpy, EGL_VERSION);
554 printf("EGL_VERSION = %s\n", s);
555
556 s = eglQueryString(egl_dpy, EGL_VENDOR);
557 printf("EGL_VENDOR = %s\n", s);
558
559 s = eglQueryString(egl_dpy, EGL_EXTENSIONS);
560 printf("EGL_EXTENSIONS = %s\n", s);
561
562 s = eglQueryString(egl_dpy, EGL_CLIENT_APIS);
563 printf("EGL_CLIENT_APIS = %s\n", s);
564
565 make_x_window(x_dpy, egl_dpy,
566 "pbuffer", 0, 0, WinWidth, WinHeight,
567 &win, &egl_ctx, &egl_surf);
568
569 egl_pbuf = make_pbuffer(x_dpy, egl_dpy, WinWidth, WinHeight);
570 if (!egl_pbuf) {
571 printf("Error: eglCreatePBufferSurface() failed\n");
572 return -1;
573 }
574
575 XMapWindow(x_dpy, win);
576 if (!eglMakeCurrent(egl_dpy, egl_surf, egl_surf, egl_ctx)) {
577 printf("Error: eglMakeCurrent() failed\n");
578 return -1;
579 }
580
581 if (printInfo) {
582 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
583 printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
584 printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
585 printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
586 }
587
588 init();
589
590 /* Set initial projection/viewing transformation.
591 * We can't be sure we'll get a ConfigureNotify event when the window
592 * first appears.
593 */
594 reshape(WinWidth, WinHeight);
595
596 event_loop(x_dpy, win, egl_dpy, egl_surf, egl_pbuf, egl_ctx);
597
598 eglDestroyContext(egl_dpy, egl_ctx);
599 eglDestroySurface(egl_dpy, egl_surf);
600 eglTerminate(egl_dpy);
601
602
603 XDestroyWindow(x_dpy, win);
604 XCloseDisplay(x_dpy);
605
606 return 0;
607 }