132001f49Smrg/* 232001f49Smrg * Copyright (C) 2008 Brian Paul All Rights Reserved. 332001f49Smrg * 432001f49Smrg * Permission is hereby granted, free of charge, to any person obtaining a 532001f49Smrg * copy of this software and associated documentation files (the "Software"), 632001f49Smrg * to deal in the Software without restriction, including without limitation 732001f49Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 832001f49Smrg * and/or sell copies of the Software, and to permit persons to whom the 932001f49Smrg * Software is furnished to do so, subject to the following conditions: 1032001f49Smrg * 1132001f49Smrg * The above copyright notice and this permission notice shall be included 1232001f49Smrg * in all copies or substantial portions of the Software. 1332001f49Smrg * 1432001f49Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 1532001f49Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1632001f49Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1732001f49Smrg * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 1832001f49Smrg * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 1932001f49Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 2032001f49Smrg */ 2132001f49Smrg 2232001f49Smrg/* 2332001f49Smrg * Test drawing to two windows. 2432001f49Smrg * Brian Paul 2532001f49Smrg * August 2008 2632001f49Smrg */ 2732001f49Smrg 2832001f49Smrg 2932001f49Smrg#include <assert.h> 3032001f49Smrg#include <math.h> 3132001f49Smrg#include <stdlib.h> 3232001f49Smrg#include <stdio.h> 3332001f49Smrg#include <string.h> 3432001f49Smrg#include <X11/Xlib.h> 3532001f49Smrg#include <X11/Xutil.h> 3632001f49Smrg#include <X11/keysym.h> 3732001f49Smrg#include <GLES/gl.h> 3832001f49Smrg#include <GLES/glext.h> 3932001f49Smrg#include <EGL/egl.h> 4032001f49Smrg 4132001f49Smrg 4232001f49Smrgstatic int WinWidth[2] = {150, 300}, WinHeight[2] = {150, 300}; 4332001f49Smrg 4432001f49Smrg 4532001f49Smrgstatic GLfloat view_rotx = 0.0, view_roty = 0.0, view_rotz = 0.0; 4632001f49Smrg 4732001f49Smrg 4832001f49Smrg/* new window size or exposure */ 4932001f49Smrgstatic void 5032001f49Smrgreshape(int width, int height) 5132001f49Smrg{ 5232001f49Smrg GLfloat ar = (GLfloat) width / (GLfloat) height; 5332001f49Smrg 5432001f49Smrg glViewport(0, 0, (GLint) width, (GLint) height); 5532001f49Smrg 5632001f49Smrg glMatrixMode(GL_PROJECTION); 5732001f49Smrg glLoadIdentity(); 5832001f49Smrg#ifdef GL_VERSION_ES_CM_1_0 5932001f49Smrg glFrustumf(-ar, ar, -1, 1, 5.0, 60.0); 6032001f49Smrg#else 6132001f49Smrg glFrustum(-ar, ar, -1, 1, 5.0, 60.0); 6232001f49Smrg#endif 6332001f49Smrg 6432001f49Smrg glMatrixMode(GL_MODELVIEW); 6532001f49Smrg glLoadIdentity(); 6632001f49Smrg glTranslatef(0.0, 0.0, -10.0); 6732001f49Smrg} 6832001f49Smrg 6932001f49Smrg 7032001f49Smrgstatic void 7132001f49Smrgdraw(int win) 7232001f49Smrg{ 7332001f49Smrg static const GLfloat verts[3][2] = { 7432001f49Smrg { -1, -1 }, 7532001f49Smrg { 1, -1 }, 7632001f49Smrg { 0, 1 } 7732001f49Smrg }; 7832001f49Smrg static const GLfloat colors[3][4] = { 7932001f49Smrg { 1, 0, 0, 1 }, 8032001f49Smrg { 0, 1, 0, 1 }, 8132001f49Smrg { 0, 0, 1, 1 } 8232001f49Smrg }; 8332001f49Smrg 8432001f49Smrg assert(win == 0 || win == 1); 8532001f49Smrg 8632001f49Smrg reshape(WinWidth[win], WinHeight[win]); 8732001f49Smrg 8832001f49Smrg glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 8932001f49Smrg 9032001f49Smrg glPushMatrix(); 9132001f49Smrg glRotatef(view_rotx, 1, 0, 0); 9232001f49Smrg glRotatef(view_roty, 0, 1, 0); 9332001f49Smrg glRotatef(view_rotz, 0, 0, 1); 9432001f49Smrg 9532001f49Smrg /* draw triangle */ 9632001f49Smrg { 9732001f49Smrg glVertexPointer(2, GL_FLOAT, 0, verts); 9832001f49Smrg glColorPointer(4, GL_FLOAT, 0, colors); 9932001f49Smrg 10032001f49Smrg glEnableClientState(GL_VERTEX_ARRAY); 10132001f49Smrg glEnableClientState(GL_COLOR_ARRAY); 10232001f49Smrg 10332001f49Smrg glDrawArrays(GL_TRIANGLES, 0, 3); 10432001f49Smrg 10532001f49Smrg glDisableClientState(GL_VERTEX_ARRAY); 10632001f49Smrg glDisableClientState(GL_COLOR_ARRAY); 10732001f49Smrg } 10832001f49Smrg 10932001f49Smrg glPopMatrix(); 11032001f49Smrg} 11132001f49Smrg 11232001f49Smrg 11332001f49Smrgstatic void 11432001f49Smrginit(void) 11532001f49Smrg{ 11632001f49Smrg glClearColor(0.4, 0.4, 0.4, 0.0); 11732001f49Smrg} 11832001f49Smrg 11932001f49Smrg 12032001f49Smrg/* 12132001f49Smrg * Create an RGB, double-buffered X window. 12232001f49Smrg * Return the window and context handles. 12332001f49Smrg */ 12432001f49Smrgstatic void 12532001f49Smrgmake_x_window(Display *x_dpy, EGLDisplay egl_dpy, 12632001f49Smrg const char *name, 12732001f49Smrg int x, int y, int width, int height, 12832001f49Smrg Window *winRet, 12932001f49Smrg EGLContext *ctxRet, 13032001f49Smrg EGLSurface *surfRet) 13132001f49Smrg{ 13232001f49Smrg static const EGLint attribs[] = { 13332001f49Smrg EGL_RED_SIZE, 1, 13432001f49Smrg EGL_GREEN_SIZE, 1, 13532001f49Smrg EGL_BLUE_SIZE, 1, 13632001f49Smrg EGL_DEPTH_SIZE, 1, 13732001f49Smrg EGL_NONE 13832001f49Smrg }; 13932001f49Smrg 14032001f49Smrg int scrnum; 14132001f49Smrg XSetWindowAttributes attr; 14232001f49Smrg unsigned long mask; 14332001f49Smrg Window root; 14432001f49Smrg Window win; 14532001f49Smrg XVisualInfo *visInfo, visTemplate; 14632001f49Smrg int num_visuals; 14732001f49Smrg EGLContext ctx; 14832001f49Smrg EGLConfig config; 14932001f49Smrg EGLint num_configs; 15032001f49Smrg EGLint vid; 15132001f49Smrg 15232001f49Smrg scrnum = DefaultScreen( x_dpy ); 15332001f49Smrg root = RootWindow( x_dpy, scrnum ); 15432001f49Smrg 15532001f49Smrg if (!eglChooseConfig( egl_dpy, attribs, &config, 1, &num_configs)) { 15632001f49Smrg printf("Error: couldn't get an EGL visual config\n"); 15732001f49Smrg exit(1); 15832001f49Smrg } 15932001f49Smrg 16032001f49Smrg assert(config); 16132001f49Smrg assert(num_configs > 0); 16232001f49Smrg 16332001f49Smrg if (!eglGetConfigAttrib(egl_dpy, config, EGL_NATIVE_VISUAL_ID, &vid)) { 16432001f49Smrg printf("Error: eglGetConfigAttrib() failed\n"); 16532001f49Smrg exit(1); 16632001f49Smrg } 16732001f49Smrg 16832001f49Smrg /* The X window visual must match the EGL config */ 16932001f49Smrg visTemplate.visualid = vid; 17032001f49Smrg visInfo = XGetVisualInfo(x_dpy, VisualIDMask, &visTemplate, &num_visuals); 17132001f49Smrg if (!visInfo) { 17232001f49Smrg printf("Error: couldn't get X visual\n"); 17332001f49Smrg exit(1); 17432001f49Smrg } 17532001f49Smrg 17632001f49Smrg /* window attributes */ 17732001f49Smrg attr.background_pixel = 0; 17832001f49Smrg attr.border_pixel = 0; 17932001f49Smrg attr.colormap = XCreateColormap( x_dpy, root, visInfo->visual, AllocNone); 18032001f49Smrg attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask; 18132001f49Smrg mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; 18232001f49Smrg 18332001f49Smrg win = XCreateWindow( x_dpy, root, x, y, width, height, 18432001f49Smrg 0, visInfo->depth, InputOutput, 18532001f49Smrg visInfo->visual, mask, &attr ); 18632001f49Smrg 18732001f49Smrg /* set hints and properties */ 18832001f49Smrg { 18932001f49Smrg XSizeHints sizehints; 19032001f49Smrg sizehints.x = x; 19132001f49Smrg sizehints.y = y; 19232001f49Smrg sizehints.width = width; 19332001f49Smrg sizehints.height = height; 19432001f49Smrg sizehints.flags = USSize | USPosition; 19532001f49Smrg XSetNormalHints(x_dpy, win, &sizehints); 19632001f49Smrg XSetStandardProperties(x_dpy, win, name, name, 19732001f49Smrg None, (char **)NULL, 0, &sizehints); 19832001f49Smrg } 19932001f49Smrg 20032001f49Smrg#if USE_FULL_GL 20132001f49Smrg eglBindAPI(EGL_OPENGL_API); 20232001f49Smrg#else 20332001f49Smrg eglBindAPI(EGL_OPENGL_ES_API); 20432001f49Smrg#endif 20532001f49Smrg 20632001f49Smrg if (ctxRet) { 20732001f49Smrg ctx = eglCreateContext(egl_dpy, config, EGL_NO_CONTEXT, NULL ); 20832001f49Smrg if (!ctx) { 20932001f49Smrg printf("Error: eglCreateContext failed\n"); 21032001f49Smrg exit(1); 21132001f49Smrg } 21232001f49Smrg *ctxRet = ctx; 21332001f49Smrg } 21432001f49Smrg 21532001f49Smrg *surfRet = eglCreateWindowSurface(egl_dpy, config, win, NULL); 21632001f49Smrg 21732001f49Smrg if (!*surfRet) { 21832001f49Smrg printf("Error: eglCreateWindowSurface failed\n"); 21932001f49Smrg exit(1); 22032001f49Smrg } 22132001f49Smrg 22232001f49Smrg XFree(visInfo); 22332001f49Smrg 22432001f49Smrg *winRet = win; 22532001f49Smrg} 22632001f49Smrg 22732001f49Smrg 22832001f49Smrgstatic void 22932001f49Smrgevent_loop(Display *dpy, Window win1, Window win2, 23032001f49Smrg EGLDisplay egl_dpy, EGLSurface egl_surf1, EGLSurface egl_surf2, 23132001f49Smrg EGLContext egl_ctx) 23232001f49Smrg{ 23332001f49Smrg while (1) { 23432001f49Smrg int redraw = 0; 23532001f49Smrg int win; 23632001f49Smrg XEvent event; 23732001f49Smrg 23832001f49Smrg XNextEvent(dpy, &event); 23932001f49Smrg 24032001f49Smrg switch (event.type) { 24132001f49Smrg case Expose: 24232001f49Smrg redraw = 1; 24332001f49Smrg break; 24432001f49Smrg case ConfigureNotify: 24532001f49Smrg if (event.xconfigure.window == win1) 24632001f49Smrg win = 0; 24732001f49Smrg else 24832001f49Smrg win = 1; 24932001f49Smrg WinWidth[win] = event.xconfigure.width; 25032001f49Smrg WinHeight[win] = event.xconfigure.height; 25132001f49Smrg break; 25232001f49Smrg case KeyPress: 25332001f49Smrg { 25432001f49Smrg char buffer[10]; 25532001f49Smrg int r, code; 25632001f49Smrg code = XLookupKeysym(&event.xkey, 0); 25732001f49Smrg if (code == XK_Left) { 25832001f49Smrg view_roty += 5.0; 25932001f49Smrg } 26032001f49Smrg else if (code == XK_Right) { 26132001f49Smrg view_roty -= 5.0; 26232001f49Smrg } 26332001f49Smrg else if (code == XK_Up) { 26432001f49Smrg view_rotx += 5.0; 26532001f49Smrg } 26632001f49Smrg else if (code == XK_Down) { 26732001f49Smrg view_rotx -= 5.0; 26832001f49Smrg } 26932001f49Smrg else { 27032001f49Smrg r = XLookupString(&event.xkey, buffer, sizeof(buffer), 27132001f49Smrg NULL, NULL); 27232001f49Smrg if (buffer[0] == 27) { 27332001f49Smrg /* escape */ 27432001f49Smrg return; 27532001f49Smrg } 27632001f49Smrg } 27732001f49Smrg } 27832001f49Smrg redraw = 1; 27932001f49Smrg break; 28032001f49Smrg default: 28132001f49Smrg ; /*no-op*/ 28232001f49Smrg } 28332001f49Smrg 28432001f49Smrg if (redraw) { 28532001f49Smrg /* win 1 */ 28632001f49Smrg if (!eglMakeCurrent(egl_dpy, egl_surf1, egl_surf1, egl_ctx)) { 28732001f49Smrg printf("Error: eglMakeCurrent(1) failed\n"); 28832001f49Smrg return; 28932001f49Smrg } 29032001f49Smrg draw(0); 29132001f49Smrg eglSwapBuffers(egl_dpy, egl_surf1); 29232001f49Smrg 29332001f49Smrg /* win 2 */ 29432001f49Smrg if (!eglMakeCurrent(egl_dpy, egl_surf2, egl_surf2, egl_ctx)) { 29532001f49Smrg printf("Error: eglMakeCurrent(2) failed\n"); 29632001f49Smrg return; 29732001f49Smrg } 29832001f49Smrg draw(1); 29932001f49Smrg eglSwapBuffers(egl_dpy, egl_surf2); 30032001f49Smrg } 30132001f49Smrg } 30232001f49Smrg} 30332001f49Smrg 30432001f49Smrg 30532001f49Smrgstatic void 30632001f49Smrgusage(void) 30732001f49Smrg{ 30832001f49Smrg printf("Usage:\n"); 30932001f49Smrg printf(" -display <displayname> set the display to run on\n"); 31032001f49Smrg printf(" -info display OpenGL renderer info\n"); 31132001f49Smrg} 31232001f49Smrg 31332001f49Smrg 31432001f49Smrgint 31532001f49Smrgmain(int argc, char *argv[]) 31632001f49Smrg{ 31732001f49Smrg Display *x_dpy; 31832001f49Smrg Window win1, win2; 31932001f49Smrg EGLSurface egl_surf1, egl_surf2; 32032001f49Smrg EGLContext egl_ctx; 32132001f49Smrg EGLDisplay egl_dpy; 32232001f49Smrg char *dpyName = NULL; 32332001f49Smrg GLboolean printInfo = GL_FALSE; 32432001f49Smrg EGLint egl_major, egl_minor; 32532001f49Smrg int i; 32632001f49Smrg const char *s; 32732001f49Smrg 32832001f49Smrg static struct { 32932001f49Smrg char *name; 33032001f49Smrg GLenum value; 33132001f49Smrg enum {GetString, GetInteger} type; 33232001f49Smrg } info_items[] = { 33332001f49Smrg {"GL_RENDERER", GL_RENDERER, GetString}, 33432001f49Smrg {"GL_VERSION", GL_VERSION, GetString}, 33532001f49Smrg {"GL_VENDOR", GL_VENDOR, GetString}, 33632001f49Smrg {"GL_EXTENSIONS", GL_EXTENSIONS, GetString}, 33732001f49Smrg {"GL_MAX_PALETTE_MATRICES_OES", GL_MAX_PALETTE_MATRICES_OES, GetInteger}, 33832001f49Smrg {"GL_MAX_VERTEX_UNITS_OES", GL_MAX_VERTEX_UNITS_OES, GetInteger}, 33932001f49Smrg }; 34032001f49Smrg 34132001f49Smrg for (i = 1; i < argc; i++) { 34232001f49Smrg if (strcmp(argv[i], "-display") == 0) { 34332001f49Smrg dpyName = argv[i+1]; 34432001f49Smrg i++; 34532001f49Smrg } 34632001f49Smrg else if (strcmp(argv[i], "-info") == 0) { 34732001f49Smrg printInfo = GL_TRUE; 34832001f49Smrg } 34932001f49Smrg else { 35032001f49Smrg usage(); 35132001f49Smrg return -1; 35232001f49Smrg } 35332001f49Smrg } 35432001f49Smrg 35532001f49Smrg x_dpy = XOpenDisplay(dpyName); 35632001f49Smrg if (!x_dpy) { 35732001f49Smrg printf("Error: couldn't open display %s\n", 35832001f49Smrg dpyName ? dpyName : getenv("DISPLAY")); 35932001f49Smrg return -1; 36032001f49Smrg } 36132001f49Smrg 36232001f49Smrg egl_dpy = eglGetDisplay(x_dpy); 36332001f49Smrg if (!egl_dpy) { 36432001f49Smrg printf("Error: eglGetDisplay() failed\n"); 36532001f49Smrg return -1; 36632001f49Smrg } 36732001f49Smrg 36832001f49Smrg if (!eglInitialize(egl_dpy, &egl_major, &egl_minor)) { 36932001f49Smrg printf("Error: eglInitialize() failed\n"); 37032001f49Smrg return -1; 37132001f49Smrg } 37232001f49Smrg 37332001f49Smrg s = eglQueryString(egl_dpy, EGL_VERSION); 37432001f49Smrg printf("EGL_VERSION = %s\n", s); 37532001f49Smrg 37632001f49Smrg s = eglQueryString(egl_dpy, EGL_VENDOR); 37732001f49Smrg printf("EGL_VENDOR = %s\n", s); 37832001f49Smrg 37932001f49Smrg s = eglQueryString(egl_dpy, EGL_EXTENSIONS); 38032001f49Smrg printf("EGL_EXTENSIONS = %s\n", s); 38132001f49Smrg 38232001f49Smrg s = eglQueryString(egl_dpy, EGL_CLIENT_APIS); 38332001f49Smrg printf("EGL_CLIENT_APIS = %s\n", s); 38432001f49Smrg 38532001f49Smrg make_x_window(x_dpy, egl_dpy, 38632001f49Smrg "xegl_two_win #1", 0, 0, WinWidth[0], WinHeight[0], 38732001f49Smrg &win1, &egl_ctx, &egl_surf1); 38832001f49Smrg 38932001f49Smrg make_x_window(x_dpy, egl_dpy, 39032001f49Smrg "xegl_two_win #2", WinWidth[0] + 50, 0, 39132001f49Smrg WinWidth[1], WinHeight[1], 39232001f49Smrg &win2, NULL, &egl_surf2); 39332001f49Smrg 39432001f49Smrg XMapWindow(x_dpy, win1); 39532001f49Smrg 39632001f49Smrg XMapWindow(x_dpy, win2); 39732001f49Smrg 39832001f49Smrg if (!eglMakeCurrent(egl_dpy, egl_surf1, egl_surf1, egl_ctx)) { 39932001f49Smrg printf("Error: eglMakeCurrent() failed\n"); 40032001f49Smrg return -1; 40132001f49Smrg } 40232001f49Smrg 40332001f49Smrg if (printInfo) { 40432001f49Smrg for (i = 0; i < sizeof(info_items)/sizeof(info_items[0]); i++) { 40532001f49Smrg switch (info_items[i].type) { 40632001f49Smrg case GetString: 40732001f49Smrg printf("%s = %s\n", info_items[i].name, (char *)glGetString(info_items[i].value)); 40832001f49Smrg break; 40932001f49Smrg case GetInteger: { 41032001f49Smrg GLint rv = -1; 41132001f49Smrg glGetIntegerv(info_items[i].value, &rv); 41232001f49Smrg printf("%s = %d\n", info_items[i].name, rv); 41332001f49Smrg break; 41432001f49Smrg } 41532001f49Smrg } 41632001f49Smrg } 41732001f49Smrg }; 41832001f49Smrg 41932001f49Smrg init(); 42032001f49Smrg 42132001f49Smrg event_loop(x_dpy, win1, win2, egl_dpy, egl_surf1, egl_surf2, egl_ctx); 42232001f49Smrg 42332001f49Smrg eglDestroyContext(egl_dpy, egl_ctx); 42432001f49Smrg eglDestroySurface(egl_dpy, egl_surf1); 42532001f49Smrg eglDestroySurface(egl_dpy, egl_surf2); 42632001f49Smrg eglTerminate(egl_dpy); 42732001f49Smrg 42832001f49Smrg XDestroyWindow(x_dpy, win1); 42932001f49Smrg XDestroyWindow(x_dpy, win2); 43032001f49Smrg XCloseDisplay(x_dpy); 43132001f49Smrg 43232001f49Smrg return 0; 43332001f49Smrg} 434