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 26static int WinWidth = 300, WinHeight = 300; 27 28static GLfloat view_rotx = 0.0, view_roty = 0.0, view_rotz = 0.0; 29 30 31static void 32Normal(GLfloat *n, GLfloat nx, GLfloat ny, GLfloat nz) 33{ 34 n[0] = nx; 35 n[1] = ny; 36 n[2] = nz; 37} 38 39static void 40Vertex(GLfloat *v, GLfloat vx, GLfloat vy, GLfloat vz) 41{ 42 v[0] = vx; 43 v[1] = vy; 44 v[2] = vz; 45} 46 47static void 48Texcoord(GLfloat *v, GLfloat s, GLfloat t) 49{ 50 v[0] = s; 51 v[1] = t; 52} 53 54 55/* Borrowed from glut, adapted */ 56static void 57draw_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 127static void 128draw(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 */ 149static void 150draw_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 */ 202static void 203reshape(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 227static void 228make_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 267static void 268init(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 */ 298static void 299make_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 396static EGLSurface 397make_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 428static void 429event_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 499static void 500usage(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 508int 509main(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} 609