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