1/* 2 * Copyright (C) 2008 Brian Paul All Rights Reserved. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included 12 * in all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 */ 21 22/* 23 * Test drawing to two windows. 24 * Brian Paul 25 * August 2008 26 */ 27 28 29#include <assert.h> 30#include <math.h> 31#include <stdlib.h> 32#include <stdio.h> 33#include <string.h> 34#include <X11/Xlib.h> 35#include <X11/Xutil.h> 36#include <X11/keysym.h> 37#include <GLES/gl.h> 38#include <GLES/glext.h> 39#include <EGL/egl.h> 40 41 42static int WinWidth[2] = {150, 300}, WinHeight[2] = {150, 300}; 43 44 45static GLfloat view_rotx = 0.0, view_roty = 0.0, view_rotz = 0.0; 46 47 48/* new window size or exposure */ 49static void 50reshape(int width, int height) 51{ 52 GLfloat ar = (GLfloat) width / (GLfloat) height; 53 54 glViewport(0, 0, (GLint) width, (GLint) height); 55 56 glMatrixMode(GL_PROJECTION); 57 glLoadIdentity(); 58#ifdef GL_VERSION_ES_CM_1_0 59 glFrustumf(-ar, ar, -1, 1, 5.0, 60.0); 60#else 61 glFrustum(-ar, ar, -1, 1, 5.0, 60.0); 62#endif 63 64 glMatrixMode(GL_MODELVIEW); 65 glLoadIdentity(); 66 glTranslatef(0.0, 0.0, -10.0); 67} 68 69 70static void 71draw(int win) 72{ 73 static const GLfloat verts[3][2] = { 74 { -1, -1 }, 75 { 1, -1 }, 76 { 0, 1 } 77 }; 78 static const GLfloat colors[3][4] = { 79 { 1, 0, 0, 1 }, 80 { 0, 1, 0, 1 }, 81 { 0, 0, 1, 1 } 82 }; 83 84 assert(win == 0 || win == 1); 85 86 reshape(WinWidth[win], WinHeight[win]); 87 88 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 89 90 glPushMatrix(); 91 glRotatef(view_rotx, 1, 0, 0); 92 glRotatef(view_roty, 0, 1, 0); 93 glRotatef(view_rotz, 0, 0, 1); 94 95 /* draw triangle */ 96 { 97 glVertexPointer(2, GL_FLOAT, 0, verts); 98 glColorPointer(4, GL_FLOAT, 0, colors); 99 100 glEnableClientState(GL_VERTEX_ARRAY); 101 glEnableClientState(GL_COLOR_ARRAY); 102 103 glDrawArrays(GL_TRIANGLES, 0, 3); 104 105 glDisableClientState(GL_VERTEX_ARRAY); 106 glDisableClientState(GL_COLOR_ARRAY); 107 } 108 109 glPopMatrix(); 110} 111 112 113static void 114init(void) 115{ 116 glClearColor(0.4, 0.4, 0.4, 0.0); 117} 118 119 120/* 121 * Create an RGB, double-buffered X window. 122 * Return the window and context handles. 123 */ 124static void 125make_x_window(Display *x_dpy, EGLDisplay egl_dpy, 126 const char *name, 127 int x, int y, int width, int height, 128 Window *winRet, 129 EGLContext *ctxRet, 130 EGLSurface *surfRet) 131{ 132 static const EGLint attribs[] = { 133 EGL_RED_SIZE, 1, 134 EGL_GREEN_SIZE, 1, 135 EGL_BLUE_SIZE, 1, 136 EGL_DEPTH_SIZE, 1, 137 EGL_NONE 138 }; 139 140 int scrnum; 141 XSetWindowAttributes attr; 142 unsigned long mask; 143 Window root; 144 Window win; 145 XVisualInfo *visInfo, visTemplate; 146 int num_visuals; 147 EGLContext ctx; 148 EGLConfig config; 149 EGLint num_configs; 150 EGLint vid; 151 152 scrnum = DefaultScreen( x_dpy ); 153 root = RootWindow( x_dpy, scrnum ); 154 155 if (!eglChooseConfig( egl_dpy, attribs, &config, 1, &num_configs)) { 156 printf("Error: couldn't get an EGL visual config\n"); 157 exit(1); 158 } 159 160 assert(config); 161 assert(num_configs > 0); 162 163 if (!eglGetConfigAttrib(egl_dpy, config, EGL_NATIVE_VISUAL_ID, &vid)) { 164 printf("Error: eglGetConfigAttrib() failed\n"); 165 exit(1); 166 } 167 168 /* The X window visual must match the EGL config */ 169 visTemplate.visualid = vid; 170 visInfo = XGetVisualInfo(x_dpy, VisualIDMask, &visTemplate, &num_visuals); 171 if (!visInfo) { 172 printf("Error: couldn't get X visual\n"); 173 exit(1); 174 } 175 176 /* window attributes */ 177 attr.background_pixel = 0; 178 attr.border_pixel = 0; 179 attr.colormap = XCreateColormap( x_dpy, root, visInfo->visual, AllocNone); 180 attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask; 181 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; 182 183 win = XCreateWindow( x_dpy, root, x, y, width, height, 184 0, visInfo->depth, InputOutput, 185 visInfo->visual, mask, &attr ); 186 187 /* set hints and properties */ 188 { 189 XSizeHints sizehints; 190 sizehints.x = x; 191 sizehints.y = y; 192 sizehints.width = width; 193 sizehints.height = height; 194 sizehints.flags = USSize | USPosition; 195 XSetNormalHints(x_dpy, win, &sizehints); 196 XSetStandardProperties(x_dpy, win, name, name, 197 None, (char **)NULL, 0, &sizehints); 198 } 199 200#if USE_FULL_GL 201 eglBindAPI(EGL_OPENGL_API); 202#else 203 eglBindAPI(EGL_OPENGL_ES_API); 204#endif 205 206 if (ctxRet) { 207 ctx = eglCreateContext(egl_dpy, config, EGL_NO_CONTEXT, NULL ); 208 if (!ctx) { 209 printf("Error: eglCreateContext failed\n"); 210 exit(1); 211 } 212 *ctxRet = ctx; 213 } 214 215 *surfRet = eglCreateWindowSurface(egl_dpy, config, win, NULL); 216 217 if (!*surfRet) { 218 printf("Error: eglCreateWindowSurface failed\n"); 219 exit(1); 220 } 221 222 XFree(visInfo); 223 224 *winRet = win; 225} 226 227 228static void 229event_loop(Display *dpy, Window win1, Window win2, 230 EGLDisplay egl_dpy, EGLSurface egl_surf1, EGLSurface egl_surf2, 231 EGLContext egl_ctx) 232{ 233 while (1) { 234 int redraw = 0; 235 int win; 236 XEvent event; 237 238 XNextEvent(dpy, &event); 239 240 switch (event.type) { 241 case Expose: 242 redraw = 1; 243 break; 244 case ConfigureNotify: 245 if (event.xconfigure.window == win1) 246 win = 0; 247 else 248 win = 1; 249 WinWidth[win] = event.xconfigure.width; 250 WinHeight[win] = event.xconfigure.height; 251 break; 252 case KeyPress: 253 { 254 char buffer[10]; 255 int r, code; 256 code = XLookupKeysym(&event.xkey, 0); 257 if (code == XK_Left) { 258 view_roty += 5.0; 259 } 260 else if (code == XK_Right) { 261 view_roty -= 5.0; 262 } 263 else if (code == XK_Up) { 264 view_rotx += 5.0; 265 } 266 else if (code == XK_Down) { 267 view_rotx -= 5.0; 268 } 269 else { 270 r = XLookupString(&event.xkey, buffer, sizeof(buffer), 271 NULL, NULL); 272 if (buffer[0] == 27) { 273 /* escape */ 274 return; 275 } 276 } 277 } 278 redraw = 1; 279 break; 280 default: 281 ; /*no-op*/ 282 } 283 284 if (redraw) { 285 /* win 1 */ 286 if (!eglMakeCurrent(egl_dpy, egl_surf1, egl_surf1, egl_ctx)) { 287 printf("Error: eglMakeCurrent(1) failed\n"); 288 return; 289 } 290 draw(0); 291 eglSwapBuffers(egl_dpy, egl_surf1); 292 293 /* win 2 */ 294 if (!eglMakeCurrent(egl_dpy, egl_surf2, egl_surf2, egl_ctx)) { 295 printf("Error: eglMakeCurrent(2) failed\n"); 296 return; 297 } 298 draw(1); 299 eglSwapBuffers(egl_dpy, egl_surf2); 300 } 301 } 302} 303 304 305static void 306usage(void) 307{ 308 printf("Usage:\n"); 309 printf(" -display <displayname> set the display to run on\n"); 310 printf(" -info display OpenGL renderer info\n"); 311} 312 313 314int 315main(int argc, char *argv[]) 316{ 317 Display *x_dpy; 318 Window win1, win2; 319 EGLSurface egl_surf1, egl_surf2; 320 EGLContext egl_ctx; 321 EGLDisplay egl_dpy; 322 char *dpyName = NULL; 323 GLboolean printInfo = GL_FALSE; 324 EGLint egl_major, egl_minor; 325 int i; 326 const char *s; 327 328 static struct { 329 char *name; 330 GLenum value; 331 enum {GetString, GetInteger} type; 332 } info_items[] = { 333 {"GL_RENDERER", GL_RENDERER, GetString}, 334 {"GL_VERSION", GL_VERSION, GetString}, 335 {"GL_VENDOR", GL_VENDOR, GetString}, 336 {"GL_EXTENSIONS", GL_EXTENSIONS, GetString}, 337 {"GL_MAX_PALETTE_MATRICES_OES", GL_MAX_PALETTE_MATRICES_OES, GetInteger}, 338 {"GL_MAX_VERTEX_UNITS_OES", GL_MAX_VERTEX_UNITS_OES, GetInteger}, 339 }; 340 341 for (i = 1; i < argc; i++) { 342 if (strcmp(argv[i], "-display") == 0) { 343 dpyName = argv[i+1]; 344 i++; 345 } 346 else if (strcmp(argv[i], "-info") == 0) { 347 printInfo = GL_TRUE; 348 } 349 else { 350 usage(); 351 return -1; 352 } 353 } 354 355 x_dpy = XOpenDisplay(dpyName); 356 if (!x_dpy) { 357 printf("Error: couldn't open display %s\n", 358 dpyName ? dpyName : getenv("DISPLAY")); 359 return -1; 360 } 361 362 egl_dpy = eglGetDisplay(x_dpy); 363 if (!egl_dpy) { 364 printf("Error: eglGetDisplay() failed\n"); 365 return -1; 366 } 367 368 if (!eglInitialize(egl_dpy, &egl_major, &egl_minor)) { 369 printf("Error: eglInitialize() failed\n"); 370 return -1; 371 } 372 373 s = eglQueryString(egl_dpy, EGL_VERSION); 374 printf("EGL_VERSION = %s\n", s); 375 376 s = eglQueryString(egl_dpy, EGL_VENDOR); 377 printf("EGL_VENDOR = %s\n", s); 378 379 s = eglQueryString(egl_dpy, EGL_EXTENSIONS); 380 printf("EGL_EXTENSIONS = %s\n", s); 381 382 s = eglQueryString(egl_dpy, EGL_CLIENT_APIS); 383 printf("EGL_CLIENT_APIS = %s\n", s); 384 385 make_x_window(x_dpy, egl_dpy, 386 "xegl_two_win #1", 0, 0, WinWidth[0], WinHeight[0], 387 &win1, &egl_ctx, &egl_surf1); 388 389 make_x_window(x_dpy, egl_dpy, 390 "xegl_two_win #2", WinWidth[0] + 50, 0, 391 WinWidth[1], WinHeight[1], 392 &win2, NULL, &egl_surf2); 393 394 XMapWindow(x_dpy, win1); 395 396 XMapWindow(x_dpy, win2); 397 398 if (!eglMakeCurrent(egl_dpy, egl_surf1, egl_surf1, egl_ctx)) { 399 printf("Error: eglMakeCurrent() failed\n"); 400 return -1; 401 } 402 403 if (printInfo) { 404 for (i = 0; i < sizeof(info_items)/sizeof(info_items[0]); i++) { 405 switch (info_items[i].type) { 406 case GetString: 407 printf("%s = %s\n", info_items[i].name, (char *)glGetString(info_items[i].value)); 408 break; 409 case GetInteger: { 410 GLint rv = -1; 411 glGetIntegerv(info_items[i].value, &rv); 412 printf("%s = %d\n", info_items[i].name, rv); 413 break; 414 } 415 } 416 } 417 }; 418 419 init(); 420 421 event_loop(x_dpy, win1, win2, egl_dpy, egl_surf1, egl_surf2, egl_ctx); 422 423 eglDestroyContext(egl_dpy, egl_ctx); 424 eglDestroySurface(egl_dpy, egl_surf1); 425 eglDestroySurface(egl_dpy, egl_surf2); 426 eglTerminate(egl_dpy); 427 428 XDestroyWindow(x_dpy, win1); 429 XDestroyWindow(x_dpy, win2); 430 XCloseDisplay(x_dpy); 431 432 return 0; 433} 434