1/* 2 * Copyright (C) 2008 Tunsgten Graphics,Inc. All Rights Reserved. 3 */ 4 5/* 6 * Test EGL render to texture. 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 25static int TexWidth = 256, TexHeight = 256; 26 27static int WinWidth = 300, WinHeight = 300; 28 29static GLfloat view_rotx = 0.0, view_roty = 0.0, view_rotz = 0.0; 30 31static GLuint DotTexture, RenderTexture; 32 33 34static void 35Normal(GLfloat *n, GLfloat nx, GLfloat ny, GLfloat nz) 36{ 37 n[0] = nx; 38 n[1] = ny; 39 n[2] = nz; 40} 41 42static void 43Vertex(GLfloat *v, GLfloat vx, GLfloat vy, GLfloat vz) 44{ 45 v[0] = vx; 46 v[1] = vy; 47 v[2] = vz; 48} 49 50static void 51Texcoord(GLfloat *v, GLfloat s, GLfloat t) 52{ 53 v[0] = s; 54 v[1] = t; 55} 56 57 58/* Borrowed from glut, adapted */ 59static void 60draw_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 130static void 131draw_torus_to_texture(void) 132{ 133 glViewport(0, 0, TexWidth, TexHeight); 134 135 glMatrixMode(GL_PROJECTION); 136 glLoadIdentity(); 137 glFrustumf(-1, 1, -1, 1, 5.0, 60.0); 138 139 glMatrixMode(GL_MODELVIEW); 140 glLoadIdentity(); 141 glTranslatef(0.0, 0.0, -15.0); 142 143 glClearColor(0.4, 0.4, 0.4, 0.0); 144 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 145 146 glBindTexture(GL_TEXTURE_2D, DotTexture); 147 148 glEnable(GL_LIGHTING); 149 150 glPushMatrix(); 151 glRotatef(view_roty, 0, 1, 0); 152 glScalef(0.5, 0.5, 0.5); 153 154 draw_torus(1.0, 3.0, 30, 60); 155 156 glPopMatrix(); 157 158 glDisable(GL_LIGHTING); 159 160#if 0 161 glBindTexture(GL_TEXTURE_2D, RenderTexture); 162 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, TexWidth, TexHeight); 163#endif 164 165 glFinish(); 166} 167 168 169static void 170draw_textured_quad(void) 171{ 172 GLfloat ar = (GLfloat) WinWidth / (GLfloat) WinHeight; 173 174 glViewport(0, 0, WinWidth, WinHeight); 175 176 glMatrixMode(GL_PROJECTION); 177 glLoadIdentity(); 178 glFrustumf(-ar, ar, -1, 1, 5.0, 60.0); 179 180 glMatrixMode(GL_MODELVIEW); 181 glLoadIdentity(); 182 glTranslatef(0.0, 0.0, -8.0); 183 184 glClearColor(0.4, 0.4, 1.0, 0.0); 185 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 186 187 glBindTexture(GL_TEXTURE_2D, RenderTexture); 188 189 glPushMatrix(); 190 glRotatef(view_rotx, 1, 0, 0); 191 glRotatef(view_rotz, 0, 0, 1); 192 193 { 194 static const GLfloat texcoord[4][2] = { 195 { 0, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } 196 }; 197 static const GLfloat vertex[4][2] = { 198 { -1, -1 }, { 1, -1 }, { -1, 1 }, { 1, 1 } 199 }; 200 201 glVertexPointer(2, GL_FLOAT, 0, vertex); 202 glTexCoordPointer(2, GL_FLOAT, 0, texcoord); 203 glEnableClientState(GL_VERTEX_ARRAY); 204 glEnableClientState(GL_TEXTURE_COORD_ARRAY); 205 206 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 207 208 glDisableClientState(GL_VERTEX_ARRAY); 209 glDisableClientState(GL_TEXTURE_COORD_ARRAY); 210 } 211 212 glPopMatrix(); 213} 214 215 216 217static void 218draw(EGLDisplay egl_dpy, EGLSurface egl_surf, EGLSurface egl_pbuf, 219 EGLContext egl_ctx) 220{ 221 /*printf("Begin draw\n");*/ 222 223 /* first draw torus to pbuffer /texture */ 224#if 01 225 if (!eglMakeCurrent(egl_dpy, egl_pbuf, egl_pbuf, egl_ctx)) { 226#else 227 if (!eglMakeCurrent(egl_dpy, egl_surf, egl_surf, egl_ctx)) { 228#endif 229 printf("Error: eglMakeCurrent(pbuf) failed\n"); 230 return; 231 } 232 draw_torus_to_texture(); 233 234 /* draw textured quad to window */ 235 if (!eglMakeCurrent(egl_dpy, egl_surf, egl_surf, egl_ctx)) { 236 printf("Error: eglMakeCurrent(pbuffer) failed\n"); 237 return; 238 } 239 240 glBindTexture(GL_TEXTURE_2D, RenderTexture); 241 eglBindTexImage(egl_dpy, egl_pbuf, EGL_BACK_BUFFER); 242 draw_textured_quad(); 243 eglReleaseTexImage(egl_dpy, egl_pbuf, EGL_BACK_BUFFER); 244 245 eglSwapBuffers(egl_dpy, egl_surf); 246 247 /*printf("End draw\n");*/ 248} 249 250 251 252static void 253make_dot_texture(void) 254{ 255#define SZ 64 256 GLenum Filter = GL_LINEAR; 257 GLubyte image[SZ][SZ][4]; 258 GLuint i, j; 259 260 for (i = 0; i < SZ; i++) { 261 for (j = 0; j < SZ; j++) { 262 GLfloat d = (i - SZ/2) * (i - SZ/2) + (j - SZ/2) * (j - SZ/2); 263 d = sqrt(d); 264 if (d < SZ/3) { 265 image[i][j][0] = 255; 266 image[i][j][1] = 255; 267 image[i][j][2] = 255; 268 image[i][j][3] = 255; 269 } 270 else { 271 image[i][j][0] = 127; 272 image[i][j][1] = 127; 273 image[i][j][2] = 127; 274 image[i][j][3] = 255; 275 } 276 } 277 } 278 279 glGenTextures(1, &DotTexture); 280 glBindTexture(GL_TEXTURE_2D, DotTexture); 281 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SZ, SZ, 0, 282 GL_RGBA, GL_UNSIGNED_BYTE, image); 283 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, Filter); 284 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, Filter); 285 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 286 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 287#undef SZ 288} 289 290 291static void 292make_render_texture(void) 293{ 294 GLenum Filter = GL_LINEAR; 295 glGenTextures(1, &RenderTexture); 296 glBindTexture(GL_TEXTURE_2D, RenderTexture); 297 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TexWidth, TexHeight, 0, 298 GL_RGBA, GL_UNSIGNED_BYTE, NULL); 299 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, Filter); 300 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, Filter); 301 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 302 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 303} 304 305 306static void 307init(void) 308{ 309 static const GLfloat red[4] = {1, 0, 0, 0}; 310 static const GLfloat white[4] = {1.0, 1.0, 1.0, 1.0}; 311 static const GLfloat diffuse[4] = {0.7, 0.7, 0.7, 1.0}; 312 static const GLfloat specular[4] = {0.001, 0.001, 0.001, 1.0}; 313 static const GLfloat pos[4] = {20, 20, 50, 1}; 314 315 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, red); 316 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, white); 317 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 9.0); 318 319 glEnable(GL_LIGHT0); 320 glLightfv(GL_LIGHT0, GL_POSITION, pos); 321 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse); 322 glLightfv(GL_LIGHT0, GL_SPECULAR, specular); 323 324 glEnable(GL_DEPTH_TEST); 325 326 make_dot_texture(); 327 make_render_texture(); 328 329 printf("DotTexture=%u RenderTexture=%u\n", DotTexture, RenderTexture); 330 331 glEnable(GL_TEXTURE_2D); 332} 333 334 335/* 336 * Create an RGB, double-buffered X window. 337 * Return the window and context handles. 338 */ 339static void 340make_x_window(Display *x_dpy, EGLDisplay egl_dpy, 341 const char *name, 342 int x, int y, int width, int height, 343 Window *winRet, 344 EGLContext *ctxRet, 345 EGLSurface *surfRet) 346{ 347 static const EGLint attribs[] = { 348 EGL_RED_SIZE, 1, 349 EGL_GREEN_SIZE, 1, 350 EGL_BLUE_SIZE, 1, 351 EGL_DEPTH_SIZE, 1, 352 EGL_NONE 353 }; 354 355 int scrnum; 356 XSetWindowAttributes attr; 357 unsigned long mask; 358 Window root; 359 Window win; 360 XVisualInfo *visInfo, visTemplate; 361 int num_visuals; 362 EGLContext ctx; 363 EGLConfig config; 364 EGLint num_configs; 365 EGLint vid; 366 367 scrnum = DefaultScreen( x_dpy ); 368 root = RootWindow( x_dpy, scrnum ); 369 370 if (!eglChooseConfig( egl_dpy, attribs, &config, 1, &num_configs)) { 371 printf("Error: couldn't get an EGL visual config\n"); 372 exit(1); 373 } 374 375 assert(config); 376 assert(num_configs > 0); 377 378 if (!eglGetConfigAttrib(egl_dpy, config, EGL_NATIVE_VISUAL_ID, &vid)) { 379 printf("Error: eglGetConfigAttrib() failed\n"); 380 exit(1); 381 } 382 383 /* The X window visual must match the EGL config */ 384 visTemplate.visualid = vid; 385 visInfo = XGetVisualInfo(x_dpy, VisualIDMask, &visTemplate, &num_visuals); 386 if (!visInfo) { 387 printf("Error: couldn't get X visual\n"); 388 exit(1); 389 } 390 391 /* window attributes */ 392 attr.background_pixel = 0; 393 attr.border_pixel = 0; 394 attr.colormap = XCreateColormap( x_dpy, root, visInfo->visual, AllocNone); 395 attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask; 396 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; 397 398 win = XCreateWindow( x_dpy, root, 0, 0, width, height, 399 0, visInfo->depth, InputOutput, 400 visInfo->visual, mask, &attr ); 401 402 /* set hints and properties */ 403 { 404 XSizeHints sizehints; 405 sizehints.x = x; 406 sizehints.y = y; 407 sizehints.width = width; 408 sizehints.height = height; 409 sizehints.flags = USSize | USPosition; 410 XSetNormalHints(x_dpy, win, &sizehints); 411 XSetStandardProperties(x_dpy, win, name, name, 412 None, (char **)NULL, 0, &sizehints); 413 } 414 415 eglBindAPI(EGL_OPENGL_ES_API); 416 417 ctx = eglCreateContext(egl_dpy, config, EGL_NO_CONTEXT, NULL ); 418 if (!ctx) { 419 printf("Error: eglCreateContext failed\n"); 420 exit(1); 421 } 422 423 *surfRet = eglCreateWindowSurface(egl_dpy, config, win, NULL); 424 425 if (!*surfRet) { 426 printf("Error: eglCreateWindowSurface failed\n"); 427 exit(1); 428 } 429 430 XFree(visInfo); 431 432 *winRet = win; 433 *ctxRet = ctx; 434} 435 436 437static EGLSurface 438make_pbuffer(Display *x_dpy, EGLDisplay egl_dpy, int width, int height) 439{ 440 static const EGLint config_attribs[] = { 441 EGL_RED_SIZE, 1, 442 EGL_GREEN_SIZE, 1, 443 EGL_BLUE_SIZE, 1, 444 EGL_DEPTH_SIZE, 1, 445 EGL_NONE 446 }; 447 EGLConfig config; 448 EGLSurface pbuf; 449 EGLint num_configs; 450 EGLint pbuf_attribs[15]; 451 int i = 0; 452 453 pbuf_attribs[i++] = EGL_WIDTH; 454 pbuf_attribs[i++] = width; 455 pbuf_attribs[i++] = EGL_HEIGHT; 456 pbuf_attribs[i++] = height; 457 pbuf_attribs[i++] = EGL_TEXTURE_FORMAT; 458 pbuf_attribs[i++] = EGL_TEXTURE_RGBA; 459 pbuf_attribs[i++] = EGL_TEXTURE_TARGET; 460 pbuf_attribs[i++] = EGL_TEXTURE_2D; 461 pbuf_attribs[i++] = EGL_MIPMAP_TEXTURE; 462 pbuf_attribs[i++] = EGL_FALSE; 463 pbuf_attribs[i++] = EGL_NONE; 464 assert(i <= 15); 465 466 if (!eglChooseConfig( egl_dpy, config_attribs, &config, 1, &num_configs)) { 467 printf("Error: couldn't get an EGL config for pbuffer\n"); 468 exit(1); 469 } 470 471 pbuf = eglCreatePbufferSurface(egl_dpy, config, pbuf_attribs); 472 473 return pbuf; 474} 475 476 477static void 478event_loop(Display *dpy, Window win, 479 EGLDisplay egl_dpy, EGLSurface egl_surf, EGLSurface egl_pbuf, 480 EGLContext egl_ctx) 481{ 482 int anim = 0; 483 484 while (1) { 485 int redraw = 0; 486 487 if (!anim || XPending(dpy)) { 488 XEvent event; 489 XNextEvent(dpy, &event); 490 491 switch (event.type) { 492 case Expose: 493 redraw = 1; 494 break; 495 case ConfigureNotify: 496 if (event.xconfigure.window == win) { 497 WinWidth = event.xconfigure.width; 498 WinHeight = event.xconfigure.height; 499 } 500 break; 501 case KeyPress: 502 { 503 char buffer[10]; 504 int r, code; 505 code = XLookupKeysym(&event.xkey, 0); 506 if (code == XK_Left) { 507 view_roty += 5.0; 508 } 509 else if (code == XK_Right) { 510 view_roty -= 5.0; 511 } 512 else if (code == XK_Up) { 513 view_rotx += 5.0; 514 } 515 else if (code == XK_Down) { 516 view_rotx -= 5.0; 517 } 518 else { 519 r = XLookupString(&event.xkey, buffer, sizeof(buffer), 520 NULL, NULL); 521 if (buffer[0] == ' ') { 522 anim = !anim; 523 } 524 else if (buffer[0] == 'z') { 525 view_rotz += 5.0; 526 } 527 else if (buffer[0] == 'Z') { 528 view_rotz -= 5.0; 529 } 530 else if (buffer[0] == 27) { 531 /* escape */ 532 return; 533 } 534 } 535 } 536 redraw = 1; 537 break; 538 default: 539 ; /*no-op*/ 540 } 541 } 542 543 if (anim) { 544 view_rotx += 1.0; 545 view_roty += 2.0; 546 redraw = 1; 547 } 548 549 if (redraw) { 550 draw(egl_dpy, egl_surf, egl_pbuf, egl_ctx); 551 } 552 } 553} 554 555 556static void 557usage(void) 558{ 559 printf("Usage:\n"); 560 printf(" -display <displayname> set the display to run on\n"); 561 printf(" -info display OpenGL renderer info\n"); 562} 563 564 565int 566main(int argc, char *argv[]) 567{ 568 Display *x_dpy; 569 Window win; 570 EGLSurface egl_surf, egl_pbuf; 571 EGLContext egl_ctx; 572 EGLDisplay egl_dpy; 573 char *dpyName = NULL; 574 GLboolean printInfo = GL_FALSE; 575 EGLint egl_major, egl_minor; 576 int i; 577 const char *s; 578 579 for (i = 1; i < argc; i++) { 580 if (strcmp(argv[i], "-display") == 0) { 581 dpyName = argv[i+1]; 582 i++; 583 } 584 else if (strcmp(argv[i], "-info") == 0) { 585 printInfo = GL_TRUE; 586 } 587 else { 588 usage(); 589 return -1; 590 } 591 } 592 593 x_dpy = XOpenDisplay(dpyName); 594 if (!x_dpy) { 595 printf("Error: couldn't open display %s\n", 596 dpyName ? dpyName : getenv("DISPLAY")); 597 return -1; 598 } 599 600 egl_dpy = eglGetDisplay(x_dpy); 601 if (!egl_dpy) { 602 printf("Error: eglGetDisplay() failed\n"); 603 return -1; 604 } 605 606 if (!eglInitialize(egl_dpy, &egl_major, &egl_minor)) { 607 printf("Error: eglInitialize() failed\n"); 608 return -1; 609 } 610 611 s = eglQueryString(egl_dpy, EGL_VERSION); 612 printf("EGL_VERSION = %s\n", s); 613 614 s = eglQueryString(egl_dpy, EGL_VENDOR); 615 printf("EGL_VENDOR = %s\n", s); 616 617 s = eglQueryString(egl_dpy, EGL_EXTENSIONS); 618 printf("EGL_EXTENSIONS = %s\n", s); 619 620 s = eglQueryString(egl_dpy, EGL_CLIENT_APIS); 621 printf("EGL_CLIENT_APIS = %s\n", s); 622 623 make_x_window(x_dpy, egl_dpy, 624 "render_tex", 0, 0, WinWidth, WinHeight, 625 &win, &egl_ctx, &egl_surf); 626 627 egl_pbuf = make_pbuffer(x_dpy, egl_dpy, TexWidth, TexHeight); 628 if (!egl_pbuf) { 629 printf("Error: eglCreatePBufferSurface() failed\n"); 630 return -1; 631 } 632 633 XMapWindow(x_dpy, win); 634 if (!eglMakeCurrent(egl_dpy, egl_surf, egl_surf, egl_ctx)) { 635 printf("Error: eglMakeCurrent() failed\n"); 636 return -1; 637 } 638 639 if (printInfo) { 640 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER)); 641 printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION)); 642 printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR)); 643 printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS)); 644 } 645 646 init(); 647 648 event_loop(x_dpy, win, egl_dpy, egl_surf, egl_pbuf, egl_ctx); 649 650 eglDestroyContext(egl_dpy, egl_ctx); 651 eglDestroySurface(egl_dpy, egl_surf); 652 eglTerminate(egl_dpy); 653 654 655 XDestroyWindow(x_dpy, win); 656 XCloseDisplay(x_dpy); 657 658 return 0; 659} 660