es2tri.c revision 7ec3b29a
1/************************************************************************** 2 * 3 * Copyright 2008 VMware, Inc. 4 * All Rights Reserved. 5 * 6 **************************************************************************/ 7 8/* 9 * Draw a triangle with X/EGL and OpenGL ES 2.x 10 */ 11 12#define USE_FULL_GL 0 13 14 15 16#include <assert.h> 17#include <math.h> 18#include <stdlib.h> 19#include <stdio.h> 20#include <string.h> 21#include <X11/Xlib.h> 22#include <X11/Xutil.h> 23#include <X11/keysym.h> 24#if USE_FULL_GL 25#include "gl_wrap.h" /* use full OpenGL */ 26#else 27#include <GLES2/gl2.h> /* use OpenGL ES 2.x */ 28#endif 29#include <EGL/egl.h> 30 31 32#define FLOAT_TO_FIXED(X) ((X) * 65535.0) 33 34 35 36static GLfloat view_rotx = 0.0, view_roty = 0.0; 37 38static GLint u_matrix = -1; 39static GLint attr_pos = 0, attr_color = 1; 40 41 42static void 43make_z_rot_matrix(GLfloat angle, GLfloat *m) 44{ 45 float c = cos(angle * M_PI / 180.0); 46 float s = sin(angle * M_PI / 180.0); 47 int i; 48 for (i = 0; i < 16; i++) 49 m[i] = 0.0; 50 m[0] = m[5] = m[10] = m[15] = 1.0; 51 52 m[0] = c; 53 m[1] = s; 54 m[4] = -s; 55 m[5] = c; 56} 57 58static void 59make_scale_matrix(GLfloat xs, GLfloat ys, GLfloat zs, GLfloat *m) 60{ 61 int i; 62 for (i = 0; i < 16; i++) 63 m[i] = 0.0; 64 m[0] = xs; 65 m[5] = ys; 66 m[10] = zs; 67 m[15] = 1.0; 68} 69 70 71static void 72mul_matrix(GLfloat *prod, const GLfloat *a, const GLfloat *b) 73{ 74#define A(row,col) a[(col<<2)+row] 75#define B(row,col) b[(col<<2)+row] 76#define P(row,col) p[(col<<2)+row] 77 GLfloat p[16]; 78 GLint i; 79 for (i = 0; i < 4; i++) { 80 const GLfloat ai0=A(i,0), ai1=A(i,1), ai2=A(i,2), ai3=A(i,3); 81 P(i,0) = ai0 * B(0,0) + ai1 * B(1,0) + ai2 * B(2,0) + ai3 * B(3,0); 82 P(i,1) = ai0 * B(0,1) + ai1 * B(1,1) + ai2 * B(2,1) + ai3 * B(3,1); 83 P(i,2) = ai0 * B(0,2) + ai1 * B(1,2) + ai2 * B(2,2) + ai3 * B(3,2); 84 P(i,3) = ai0 * B(0,3) + ai1 * B(1,3) + ai2 * B(2,3) + ai3 * B(3,3); 85 } 86 memcpy(prod, p, sizeof(p)); 87#undef A 88#undef B 89#undef PROD 90} 91 92 93static void 94draw(void) 95{ 96 static const GLfloat verts[3][2] = { 97 { -1, -1 }, 98 { 1, -1 }, 99 { 0, 1 } 100 }; 101 static const GLfloat colors[3][3] = { 102 { 1, 0, 0 }, 103 { 0, 1, 0 }, 104 { 0, 0, 1 } 105 }; 106 GLfloat mat[16], rot[16], scale[16]; 107 108 /* Set modelview/projection matrix */ 109 make_z_rot_matrix(view_rotx, rot); 110 make_scale_matrix(0.5, 0.5, 0.5, scale); 111 mul_matrix(mat, rot, scale); 112 glUniformMatrix4fv(u_matrix, 1, GL_FALSE, mat); 113 114 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 115 116 { 117 glVertexAttribPointer(attr_pos, 2, GL_FLOAT, GL_FALSE, 0, verts); 118 glVertexAttribPointer(attr_color, 3, GL_FLOAT, GL_FALSE, 0, colors); 119 glEnableVertexAttribArray(attr_pos); 120 glEnableVertexAttribArray(attr_color); 121 122 glDrawArrays(GL_TRIANGLES, 0, 3); 123 124 glDisableVertexAttribArray(attr_pos); 125 glDisableVertexAttribArray(attr_color); 126 } 127} 128 129 130/* new window size or exposure */ 131static void 132reshape(int width, int height) 133{ 134 glViewport(0, 0, (GLint) width, (GLint) height); 135} 136 137 138static void 139create_shaders(void) 140{ 141 static const char *fragShaderText = 142 "precision mediump float;\n" 143 "varying vec4 v_color;\n" 144 "void main() {\n" 145 " gl_FragColor = v_color;\n" 146 "}\n"; 147 static const char *vertShaderText = 148 "uniform mat4 modelviewProjection;\n" 149 "attribute vec4 pos;\n" 150 "attribute vec4 color;\n" 151 "varying vec4 v_color;\n" 152 "void main() {\n" 153 " gl_Position = modelviewProjection * pos;\n" 154 " v_color = color;\n" 155 "}\n"; 156 157 GLuint fragShader, vertShader, program; 158 GLint stat; 159 160 fragShader = glCreateShader(GL_FRAGMENT_SHADER); 161 glShaderSource(fragShader, 1, (const char **) &fragShaderText, NULL); 162 glCompileShader(fragShader); 163 glGetShaderiv(fragShader, GL_COMPILE_STATUS, &stat); 164 if (!stat) { 165 printf("Error: fragment shader did not compile!\n"); 166 exit(1); 167 } 168 169 vertShader = glCreateShader(GL_VERTEX_SHADER); 170 glShaderSource(vertShader, 1, (const char **) &vertShaderText, NULL); 171 glCompileShader(vertShader); 172 glGetShaderiv(vertShader, GL_COMPILE_STATUS, &stat); 173 if (!stat) { 174 printf("Error: vertex shader did not compile!\n"); 175 exit(1); 176 } 177 178 program = glCreateProgram(); 179 glAttachShader(program, fragShader); 180 glAttachShader(program, vertShader); 181 glLinkProgram(program); 182 183 glGetProgramiv(program, GL_LINK_STATUS, &stat); 184 if (!stat) { 185 char log[1000]; 186 GLsizei len; 187 glGetProgramInfoLog(program, 1000, &len, log); 188 printf("Error: linking:\n%s\n", log); 189 exit(1); 190 } 191 192 glUseProgram(program); 193 194 if (1) { 195 /* test setting attrib locations */ 196 glBindAttribLocation(program, attr_pos, "pos"); 197 glBindAttribLocation(program, attr_color, "color"); 198 glLinkProgram(program); /* needed to put attribs into effect */ 199 } 200 else { 201 /* test automatic attrib locations */ 202 attr_pos = glGetAttribLocation(program, "pos"); 203 attr_color = glGetAttribLocation(program, "color"); 204 } 205 206 u_matrix = glGetUniformLocation(program, "modelviewProjection"); 207 printf("Uniform modelviewProjection at %d\n", u_matrix); 208 printf("Attrib pos at %d\n", attr_pos); 209 printf("Attrib color at %d\n", attr_color); 210} 211 212 213static void 214init(void) 215{ 216 typedef void (*proc)(); 217 218#if 1 /* test code */ 219 proc p = eglGetProcAddress("glMapBufferOES"); 220 assert(p); 221#endif 222 223 glClearColor(0.4, 0.4, 0.4, 0.0); 224 225 create_shaders(); 226} 227 228 229/* 230 * Create an RGB, double-buffered X window. 231 * Return the window and context handles. 232 */ 233static void 234make_x_window(Display *x_dpy, EGLDisplay egl_dpy, 235 const char *name, 236 int x, int y, int width, int height, 237 Window *winRet, 238 EGLContext *ctxRet, 239 EGLSurface *surfRet) 240{ 241 static const EGLint attribs[] = { 242 EGL_RED_SIZE, 1, 243 EGL_GREEN_SIZE, 1, 244 EGL_BLUE_SIZE, 1, 245 EGL_DEPTH_SIZE, 1, 246 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 247 EGL_NONE 248 }; 249#if USE_FULL_GL 250 static const EGLint ctx_attribs[] = { 251 EGL_NONE 252 }; 253#else 254 static const EGLint ctx_attribs[] = { 255 EGL_CONTEXT_CLIENT_VERSION, 2, 256 EGL_NONE 257 }; 258#endif 259 260 int scrnum; 261 XSetWindowAttributes attr; 262 unsigned long mask; 263 Window root; 264 Window win; 265 XVisualInfo *visInfo, visTemplate; 266 int num_visuals; 267 EGLContext ctx; 268 EGLConfig config; 269 EGLint num_configs; 270 EGLint vid; 271 272 scrnum = DefaultScreen( x_dpy ); 273 root = RootWindow( x_dpy, scrnum ); 274 275 if (!eglChooseConfig( egl_dpy, attribs, &config, 1, &num_configs)) { 276 printf("Error: couldn't get an EGL visual config\n"); 277 exit(1); 278 } 279 280 assert(config); 281 assert(num_configs > 0); 282 283 if (!eglGetConfigAttrib(egl_dpy, config, EGL_NATIVE_VISUAL_ID, &vid)) { 284 printf("Error: eglGetConfigAttrib() failed\n"); 285 exit(1); 286 } 287 288 /* The X window visual must match the EGL config */ 289 visTemplate.visualid = vid; 290 visInfo = XGetVisualInfo(x_dpy, VisualIDMask, &visTemplate, &num_visuals); 291 if (!visInfo) { 292 printf("Error: couldn't get X visual\n"); 293 exit(1); 294 } 295 296 /* window attributes */ 297 attr.background_pixel = 0; 298 attr.border_pixel = 0; 299 attr.colormap = XCreateColormap( x_dpy, root, visInfo->visual, AllocNone); 300 attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask; 301 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; 302 303 win = XCreateWindow( x_dpy, root, 0, 0, width, height, 304 0, visInfo->depth, InputOutput, 305 visInfo->visual, mask, &attr ); 306 307 /* set hints and properties */ 308 { 309 XSizeHints sizehints; 310 sizehints.x = x; 311 sizehints.y = y; 312 sizehints.width = width; 313 sizehints.height = height; 314 sizehints.flags = USSize | USPosition; 315 XSetNormalHints(x_dpy, win, &sizehints); 316 XSetStandardProperties(x_dpy, win, name, name, 317 None, (char **)NULL, 0, &sizehints); 318 } 319 320#if USE_FULL_GL /* XXX fix this when eglBindAPI() works */ 321 eglBindAPI(EGL_OPENGL_API); 322#else 323 eglBindAPI(EGL_OPENGL_ES_API); 324#endif 325 326 ctx = eglCreateContext(egl_dpy, config, EGL_NO_CONTEXT, ctx_attribs ); 327 if (!ctx) { 328 printf("Error: eglCreateContext failed\n"); 329 exit(1); 330 } 331 332#if !USE_FULL_GL 333 /* test eglQueryContext() */ 334 { 335 EGLint val; 336 eglQueryContext(egl_dpy, ctx, EGL_CONTEXT_CLIENT_VERSION, &val); 337 assert(val == 2); 338 } 339#endif 340 341 *surfRet = eglCreateWindowSurface(egl_dpy, config, win, NULL); 342 if (!*surfRet) { 343 printf("Error: eglCreateWindowSurface failed\n"); 344 exit(1); 345 } 346 347 /* sanity checks */ 348 { 349 EGLint val; 350 eglQuerySurface(egl_dpy, *surfRet, EGL_WIDTH, &val); 351 assert(val == width); 352 eglQuerySurface(egl_dpy, *surfRet, EGL_HEIGHT, &val); 353 assert(val == height); 354 assert(eglGetConfigAttrib(egl_dpy, config, EGL_SURFACE_TYPE, &val)); 355 assert(val & EGL_WINDOW_BIT); 356 } 357 358 XFree(visInfo); 359 360 *winRet = win; 361 *ctxRet = ctx; 362} 363 364 365static void 366event_loop(Display *dpy, Window win, 367 EGLDisplay egl_dpy, EGLSurface egl_surf) 368{ 369 while (1) { 370 int redraw = 0; 371 XEvent event; 372 373 XNextEvent(dpy, &event); 374 375 switch (event.type) { 376 case Expose: 377 redraw = 1; 378 break; 379 case ConfigureNotify: 380 reshape(event.xconfigure.width, event.xconfigure.height); 381 break; 382 case KeyPress: 383 { 384 char buffer[10]; 385 int r, code; 386 code = XLookupKeysym(&event.xkey, 0); 387 if (code == XK_Left) { 388 view_roty += 5.0; 389 } 390 else if (code == XK_Right) { 391 view_roty -= 5.0; 392 } 393 else if (code == XK_Up) { 394 view_rotx += 5.0; 395 } 396 else if (code == XK_Down) { 397 view_rotx -= 5.0; 398 } 399 else { 400 r = XLookupString(&event.xkey, buffer, sizeof(buffer), 401 NULL, NULL); 402 if (buffer[0] == 27) { 403 /* escape */ 404 return; 405 } 406 } 407 } 408 redraw = 1; 409 break; 410 default: 411 ; /*no-op*/ 412 } 413 414 if (redraw) { 415 draw(); 416 eglSwapBuffers(egl_dpy, egl_surf); 417 } 418 } 419} 420 421 422static void 423usage(void) 424{ 425 printf("Usage:\n"); 426 printf(" -display <displayname> set the display to run on\n"); 427 printf(" -info display OpenGL renderer info\n"); 428} 429 430 431int 432main(int argc, char *argv[]) 433{ 434 const int winWidth = 300, winHeight = 300; 435 Display *x_dpy; 436 Window win; 437 EGLSurface egl_surf; 438 EGLContext egl_ctx; 439 EGLDisplay egl_dpy; 440 char *dpyName = NULL; 441 GLboolean printInfo = GL_FALSE; 442 EGLint egl_major, egl_minor; 443 int i; 444 const char *s; 445 446 for (i = 1; i < argc; i++) { 447 if (strcmp(argv[i], "-display") == 0) { 448 dpyName = argv[i+1]; 449 i++; 450 } 451 else if (strcmp(argv[i], "-info") == 0) { 452 printInfo = GL_TRUE; 453 } 454 else { 455 usage(); 456 return -1; 457 } 458 } 459 460 x_dpy = XOpenDisplay(dpyName); 461 if (!x_dpy) { 462 printf("Error: couldn't open display %s\n", 463 dpyName ? dpyName : getenv("DISPLAY")); 464 return -1; 465 } 466 467 egl_dpy = eglGetDisplay(x_dpy); 468 if (!egl_dpy) { 469 printf("Error: eglGetDisplay() failed\n"); 470 return -1; 471 } 472 473 if (!eglInitialize(egl_dpy, &egl_major, &egl_minor)) { 474 printf("Error: eglInitialize() failed\n"); 475 return -1; 476 } 477 478 s = eglQueryString(egl_dpy, EGL_VERSION); 479 printf("EGL_VERSION = %s\n", s); 480 481 s = eglQueryString(egl_dpy, EGL_VENDOR); 482 printf("EGL_VENDOR = %s\n", s); 483 484 s = eglQueryString(egl_dpy, EGL_EXTENSIONS); 485 printf("EGL_EXTENSIONS = %s\n", s); 486 487 s = eglQueryString(egl_dpy, EGL_CLIENT_APIS); 488 printf("EGL_CLIENT_APIS = %s\n", s); 489 490 make_x_window(x_dpy, egl_dpy, 491 "OpenGL ES 2.x tri", 0, 0, winWidth, winHeight, 492 &win, &egl_ctx, &egl_surf); 493 494 XMapWindow(x_dpy, win); 495 if (!eglMakeCurrent(egl_dpy, egl_surf, egl_surf, egl_ctx)) { 496 printf("Error: eglMakeCurrent() failed\n"); 497 return -1; 498 } 499 500 if (printInfo) { 501 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER)); 502 printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION)); 503 printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR)); 504 printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS)); 505 } 506 507 init(); 508 509 /* Set initial projection/viewing transformation. 510 * We can't be sure we'll get a ConfigureNotify event when the window 511 * first appears. 512 */ 513 reshape(winWidth, winHeight); 514 515 event_loop(x_dpy, win, egl_dpy, egl_surf); 516 517 eglDestroyContext(egl_dpy, egl_ctx); 518 eglDestroySurface(egl_dpy, egl_surf); 519 eglTerminate(egl_dpy); 520 521 522 XDestroyWindow(x_dpy, win); 523 XCloseDisplay(x_dpy); 524 525 return 0; 526} 527