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 eglSwapBuffers(egl_dpy, egl_surf);
172
173 /* then draw to pbuffer */
174 if (!eglMakeCurrent(egl_dpy, egl_pbuf, egl_pbuf, egl_ctx)) {
175 printf("Error: eglMakeCurrent(pbuffer) failed\n");
176 return;
177 }
178 draw();
179 glReadPixels(0, 0, WinWidth, WinHeight, GL_RGBA, GL_UNSIGNED_BYTE, pbuf);
180 printf("Pbuffer[%d,%d] = 0x%08x\n", x, y, pbuf[y*WinWidth+x]);
181
182
183 /* compare renderings */
184 for (dif = i = 0; i < WinWidth * WinHeight; i++) {
185 if (wbuf[i] != pbuf[i]) {
186 dif = 1;
187 break;
188 }
189 }
190
191 if (dif)
192 printf("Difference at %d: 0x%08x vs. 0x%08x\n", i, wbuf[i], pbuf[i]);
193 else
194 printf("Window rendering matches Pbuffer rendering!\n");
195
196 free(wbuf);
197 free(pbuf);
198 }
199
200
201 /* new window size or exposure */
202 static void
203 reshape(int width, int height)
204 {
205 GLfloat ar = (GLfloat) width / (GLfloat) height;
206
207 WinWidth = width;
208 WinHeight = height;
209
210 glViewport(0, 0, (GLint) width, (GLint) height);
211
212 glMatrixMode(GL_PROJECTION);
213 glLoadIdentity();
214
215 #ifdef GL_VERSION_ES_CM_1_0
216 glFrustumf(-ar, ar, -1, 1, 5.0, 60.0);
217 #else
218 glFrustum(-ar, ar, -1, 1, 5.0, 60.0);
219 #endif
220
221 glMatrixMode(GL_MODELVIEW);
222 glLoadIdentity();
223 glTranslatef(0.0, 0.0, -15.0);
224 }
225
226
227 static void
228 make_texture(void)
229 {
230 #define SZ 64
231 GLenum Filter = GL_LINEAR;
232 GLubyte image[SZ][SZ][4];
233 GLuint i, j;
234
235 for (i = 0; i < SZ; i++) {
236 for (j = 0; j < SZ; j++) {
237 GLfloat d = (i - SZ/2) * (i - SZ/2) + (j - SZ/2) * (j - SZ/2);
238 d = sqrt(d);
239 if (d < SZ/3) {
240 image[i][j][0] = 255;
241 image[i][j][1] = 255;
242 image[i][j][2] = 255;
243 image[i][j][3] = 255;
244 }
245 else {
246 image[i][j][0] = 127;
247 image[i][j][1] = 127;
248 image[i][j][2] = 127;
249 image[i][j][3] = 255;
250 }
251 }
252 }
253
254 glActiveTexture(GL_TEXTURE0); /* unit 0 */
255 glBindTexture(GL_TEXTURE_2D, 42);
256 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SZ, SZ, 0,
257 GL_RGBA, GL_UNSIGNED_BYTE, image);
258 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, Filter);
259 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, Filter);
260 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
261 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
262 #undef SZ
263 }
264
265
266
267 static void
268 init(void)
269 {
270 static const GLfloat red[4] = {1, 0, 0, 0};
271 static const GLfloat white[4] = {1.0, 1.0, 1.0, 1.0};
272 static const GLfloat diffuse[4] = {0.7, 0.7, 0.7, 1.0};
273 static const GLfloat specular[4] = {0.001, 0.001, 0.001, 1.0};
274 static const GLfloat pos[4] = {20, 20, 50, 1};
275
276 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, red);
277 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, white);
278 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 9.0);
279
280 glEnable(GL_LIGHTING);
281 glEnable(GL_LIGHT0);
282 glLightfv(GL_LIGHT0, GL_POSITION, pos);
283 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
284 glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
285
286 glClearColor(0.4, 0.4, 0.4, 0.0);
287 glEnable(GL_DEPTH_TEST);
288
289 make_texture();
290 glEnable(GL_TEXTURE_2D);
291 }
292
293
294 /*
295 * Create an RGB, double-buffered X window.
296 * Return the window and context handles.
297 */
298 static void
299 make_x_window(Display *x_dpy, EGLDisplay egl_dpy,
300 const char *name,
301 int x, int y, int width, int height,
302 Window *winRet,
303 EGLContext *ctxRet,
304 EGLSurface *surfRet)
305 {
306 static const EGLint attribs[] = {
307 EGL_RED_SIZE, 1,
308 EGL_GREEN_SIZE, 1,
309 EGL_BLUE_SIZE, 1,
310 EGL_DEPTH_SIZE, 1,
311 EGL_NONE
312 };
313
314 int scrnum;
315 XSetWindowAttributes attr;
316 unsigned long mask;
317 Window root;
318 Window win;
319 XVisualInfo *visInfo, visTemplate;
320 int num_visuals;
321 EGLContext ctx;
322 EGLConfig config;
323 EGLint num_configs;
324 EGLint vid;
325
326 scrnum = DefaultScreen( x_dpy );
327 root = RootWindow( x_dpy, scrnum );
328
329 if (!eglChooseConfig( egl_dpy, attribs, &config, 1, &num_configs)) {
330 printf("Error: couldn't get an EGL visual config\n");
331 exit(1);
332 }
333
334 assert(config);
335 assert(num_configs > 0);
336
337 if (!eglGetConfigAttrib(egl_dpy, config, EGL_NATIVE_VISUAL_ID, &vid)) {
338 printf("Error: eglGetConfigAttrib() failed\n");
339 exit(1);
340 }
341
342 /* The X window visual must match the EGL config */
343 visTemplate.visualid = vid;
344 visInfo = XGetVisualInfo(x_dpy, VisualIDMask, &visTemplate, &num_visuals);
345 if (!visInfo) {
346 printf("Error: couldn't get X visual\n");
347 exit(1);
348 }
349
350 /* window attributes */
351 attr.background_pixel = 0;
352 attr.border_pixel = 0;
353 attr.colormap = XCreateColormap( x_dpy, root, visInfo->visual, AllocNone);
354 attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
355 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
356
357 win = XCreateWindow( x_dpy, root, 0, 0, width, height,
358 0, visInfo->depth, InputOutput,
359 visInfo->visual, mask, &attr );
360
361 /* set hints and properties */
362 {
363 XSizeHints sizehints;
364 sizehints.x = x;
365 sizehints.y = y;
366 sizehints.width = width;
367 sizehints.height = height;
368 sizehints.flags = USSize | USPosition;
369 XSetNormalHints(x_dpy, win, &sizehints);
370 XSetStandardProperties(x_dpy, win, name, name,
371 None, (char **)NULL, 0, &sizehints);
372 }
373
374 eglBindAPI(EGL_OPENGL_ES_API);
375
376 ctx = eglCreateContext(egl_dpy, config, EGL_NO_CONTEXT, NULL );
377 if (!ctx) {
378 printf("Error: eglCreateContext failed\n");
379 exit(1);
380 }
381
382 *surfRet = eglCreateWindowSurface(egl_dpy, config, win, NULL);
383
384 if (!*surfRet) {
385 printf("Error: eglCreateWindowSurface failed\n");
386 exit(1);
387 }
388
389 XFree(visInfo);
390
391 *winRet = win;
392 *ctxRet = ctx;
393 }
394
395
396 static EGLSurface
397 make_pbuffer(Display *x_dpy, EGLDisplay egl_dpy, int width, int height)
398 {
399 static const EGLint config_attribs[] = {
400 EGL_RED_SIZE, 1,
401 EGL_GREEN_SIZE, 1,
402 EGL_BLUE_SIZE, 1,
403 EGL_DEPTH_SIZE, 1,
404 EGL_NONE
405 };
406 EGLConfig config;
407 EGLSurface pbuf;
408 EGLint num_configs;
409 EGLint pbuf_attribs[5];
410
411 pbuf_attribs[0] = EGL_WIDTH;
412 pbuf_attribs[1] = width;
413 pbuf_attribs[2] = EGL_HEIGHT;
414 pbuf_attribs[3] = height;
415 pbuf_attribs[4] = EGL_NONE;
416
417 if (!eglChooseConfig( egl_dpy, config_attribs, &config, 1, &num_configs)) {
418 printf("Error: couldn't get an EGL config for pbuffer\n");
419 exit(1);
420 }
421
422 pbuf = eglCreatePbufferSurface(egl_dpy, config, pbuf_attribs);
423
424 return pbuf;
425 }
426
427
428 static void
429 event_loop(Display *dpy, Window win,
430 EGLDisplay egl_dpy, EGLSurface egl_surf, EGLSurface egl_pbuf,
431 EGLContext egl_ctx)
432 {
433 int anim = 0;
434
435 while (1) {
436 int redraw = 0;
437
438 if (!anim || XPending(dpy)) {
439 XEvent event;
440 XNextEvent(dpy, &event);
441
442 switch (event.type) {
443 case Expose:
444 redraw = 1;
445 break;
446 case ConfigureNotify:
447 if (event.xconfigure.window == win)
448 reshape(event.xconfigure.width, event.xconfigure.height);
449 break;
450 case KeyPress:
451 {
452 char buffer[10];
453 int r, code;
454 code = XLookupKeysym(&event.xkey, 0);
455 if (code == XK_Left) {
456 view_roty += 5.0;
457 }
458 else if (code == XK_Right) {
459 view_roty -= 5.0;
460 }
461 else if (code == XK_Up) {
462 view_rotx += 5.0;
463 }
464 else if (code == XK_Down) {
465 view_rotx -= 5.0;
466 }
467 else {
468 r = XLookupString(&event.xkey, buffer, sizeof(buffer),
469 NULL, NULL);
470 if (buffer[0] == ' ') {
471 anim = !anim;
472 }
473 else if (buffer[0] == 27) {
474 /* escape */
475 return;
476 }
477 }
478 }
479 redraw = 1;
480 break;
481 default:
482 ; /*no-op*/
483 }
484 }
485
486 if (anim) {
487 view_rotx += 1.0;
488 view_roty += 2.0;
489 redraw = 1;
490 }
491
492 if (redraw) {
493 draw_both(egl_dpy, egl_surf, egl_pbuf, egl_ctx);
494 }
495 }
496 }
497
498
499 static void
500 usage(void)
501 {
502 printf("Usage:\n");
503 printf(" -display <displayname> set the display to run on\n");
504 printf(" -info display OpenGL renderer info\n");
505 }
506
507
508 int
509 main(int argc, char *argv[])
510 {
511 Display *x_dpy;
512 Window win;
513 EGLSurface egl_surf, egl_pbuf;
514 EGLContext egl_ctx;
515 EGLDisplay egl_dpy;
516 char *dpyName = NULL;
517 GLboolean printInfo = GL_FALSE;
518 EGLint egl_major, egl_minor;
519 int i;
520 const char *s;
521
522 for (i = 1; i < argc; i++) {
523 if (strcmp(argv[i], "-display") == 0) {
524 dpyName = argv[i+1];
525 i++;
526 }
527 else if (strcmp(argv[i], "-info") == 0) {
528 printInfo = GL_TRUE;
529 }
530 else {
531 usage();
532 return -1;
533 }
534 }
535
536 x_dpy = XOpenDisplay(dpyName);
537 if (!x_dpy) {
538 printf("Error: couldn't open display %s\n",
539 dpyName ? dpyName : getenv("DISPLAY"));
540 return -1;
541 }
542
543 egl_dpy = eglGetDisplay(x_dpy);
544 if (!egl_dpy) {
545 printf("Error: eglGetDisplay() failed\n");
546 return -1;
547 }
548
549 if (!eglInitialize(egl_dpy, &egl_major, &egl_minor)) {
550 printf("Error: eglInitialize() failed\n");
551 return -1;
552 }
553
554 s = eglQueryString(egl_dpy, EGL_VERSION);
555 printf("EGL_VERSION = %s\n", s);
556
557 s = eglQueryString(egl_dpy, EGL_VENDOR);
558 printf("EGL_VENDOR = %s\n", s);
559
560 s = eglQueryString(egl_dpy, EGL_EXTENSIONS);
561 printf("EGL_EXTENSIONS = %s\n", s);
562
563 s = eglQueryString(egl_dpy, EGL_CLIENT_APIS);
564 printf("EGL_CLIENT_APIS = %s\n", s);
565
566 make_x_window(x_dpy, egl_dpy,
567 "pbuffer", 0, 0, WinWidth, WinHeight,
568 &win, &egl_ctx, &egl_surf);
569
570 egl_pbuf = make_pbuffer(x_dpy, egl_dpy, WinWidth, WinHeight);
571 if (!egl_pbuf) {
572 printf("Error: eglCreatePBufferSurface() failed\n");
573 return -1;
574 }
575
576 XMapWindow(x_dpy, win);
577 if (!eglMakeCurrent(egl_dpy, egl_surf, egl_surf, egl_ctx)) {
578 printf("Error: eglMakeCurrent() failed\n");
579 return -1;
580 }
581
582 if (printInfo) {
583 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
584 printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
585 printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
586 printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
587 }
588
589 init();
590
591 /* Set initial projection/viewing transformation.
592 * We can't be sure we'll get a ConfigureNotify event when the window
593 * first appears.
594 */
595 reshape(WinWidth, WinHeight);
596
597 event_loop(x_dpy, win, egl_dpy, egl_surf, egl_pbuf, egl_ctx);
598
599 eglDestroyContext(egl_dpy, egl_ctx);
600 eglDestroySurface(egl_dpy, egl_surf);
601 eglTerminate(egl_dpy);
602
603
604 XDestroyWindow(x_dpy, win);
605 XCloseDisplay(x_dpy);
606
607 return 0;
608 }