1 /**
2 * compile with: gcc -o contextRetargetDrawable02 contextRetargetDrawable02.c -lX11 -lGL
3 */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <unistd.h>
9 #include <errno.h>
10 #include <X11/X.h>
11 #include <X11/Xlib.h>
12 #include <X11/Xutil.h>
13 #include <GL/glx.h>
14 #include <GL/gl.h>
15
16 typedef int bool;
17 #define true 1
18 #define false 0
19
20 static PFNGLXSWAPINTERVALSGIPROC _glXSwapIntervalSGI = NULL;
21
22 static void testRetarget(bool reverse);
23
24 static const char * msg = "contextRetargetDrawable01";
25
26 static const useconds_t demodelay = 2 * 1000 * 1000;
27
main(int nargs,char ** vargs)28 int main(int nargs, char **vargs) {
29 _glXSwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC) glXGetProcAddressARB("glXSwapIntervalSGI");
30 if(NULL == _glXSwapIntervalSGI) {
31 fprintf(stderr, "No glXSwapIntervalSGI avail, bail out\n");
32 return 1;
33 }
34 testRetarget(false);
35 return 0;
36 }
37
38 static void createGLWin(Display *dpy, int width, int height, Window *rWin, GLXContext *rCtx);
39 static void useGL(Display *dpy, Window win, GLXContext ctx, int width, int height, float c, int swapInterval);
40
testRetarget(bool reverse)41 static void testRetarget(bool reverse) {
42 int major, minor;
43 Display *disp1;
44 Window win1;
45 GLXContext ctx1;
46
47 Display *disp2;
48 Window win2;
49 GLXContext ctx2;
50
51 fprintf(stderr, "%s: Create #1\n", msg);
52 disp1 = XOpenDisplay(NULL);
53 createGLWin(disp1, 200, 200, &win1, &ctx1);
54
55 fprintf(stderr, "%s: Create #2\n", msg);
56 disp2 = disp1;
57 // disp2 = XOpenDisplay(NULL);
58 createGLWin(disp2, 300, 300, &win2, &ctx2);
59
60 fprintf(stderr, "%s: Use #1.1\n", msg);
61 useGL(disp1, win1, ctx1, 200, 200, 0.0f, 1); // OK
62
63 fprintf(stderr, "%s: Use #1.2\n", msg);
64 useGL(disp2, win2, ctx2, 300, 300, 1.0f, 1); // OK
65
66 usleep( demodelay );
67
68 fprintf(stderr, "%s: Retarget Drawable\n", msg);
69 {
70 GLXContext _ctx = ctx2;
71 ctx2 = ctx1;
72 ctx1 = _ctx;
73 }
74
75 /**
76 if(reverse) {
77 fprintf(stderr, "%s: Use #2.2\n", msg);
78 useGL(disp2, win2, ctx2, 300, 300, 1.0f, 0); // no setSwapInterval - OK
79
80 fprintf(stderr, "%s: Use #2.1\n", msg);
81 useGL(disp1, win1, ctx1, 200, 200, 0.0f, 0); // no setSwapInterval - OK
82 } else {
83 fprintf(stderr, "%s: Use #2.1\n", msg);
84 useGL(disp1, win1, ctx1, 200, 200, 0.0f, 0); // no setSwapInterval - OK
85
86 fprintf(stderr, "%s: Use #2.2\n", msg);
87 useGL(disp2, win2, ctx2, 300, 300, 1.0f, 0); // no setSwapInterval - OK
88 }
89 usleep( demodelay ); */
90
91 if(reverse) {
92 fprintf(stderr, "%s: Use #3.2\n", msg);
93 useGL(disp2, win2, ctx2, 300, 300, 0.9f, 1); // setSwapInterval - crash on Mesa 8.0.4 DRI2
94
95 fprintf(stderr, "%s: Use #3.1\n", msg);
96 useGL(disp1, win1, ctx1, 200, 200, 0.1f, 1); // setSwapInterval - crash on Mesa 8.0.4 DRI2
97 } else {
98 fprintf(stderr, "%s: Use #3.1\n", msg);
99 useGL(disp1, win1, ctx1, 200, 200, 0.1f, 1); // setSwapInterval - crash on Mesa 8.0.4 DRI2
100
101 fprintf(stderr, "%s: Use #3.2\n", msg);
102 useGL(disp2, win2, ctx2, 300, 300, 0.9f, 1); // setSwapInterval - crash on Mesa 8.0.4 DRI2
103 }
104 fprintf(stderr, "%s: Success - no bug\n", msg);
105 usleep( demodelay );
106
107 fprintf(stderr, "%s: Destroy #1.0\n", msg);
108 glXMakeContextCurrent(disp1, 0, 0, 0);
109 glXDestroyContext(disp1, ctx1);
110 if( disp1 != disp2 ) {
111 XCloseDisplay(disp1);
112 }
113 fprintf(stderr, "%s: Destroy #1.X\n", msg);
114
115 fprintf(stderr, "%s: Destroy #2.0\n", msg);
116 glXMakeContextCurrent(disp2, 0, 0, 0);
117 glXDestroyContext(disp2, ctx2);
118 XCloseDisplay(disp2);
119 fprintf(stderr, "%s: Destroy #2.X\n", msg);
120
121 fprintf(stderr, "%s: Exit - OK\n", msg);
122 }
123
useGL(Display * dpy,Window win,GLXContext ctx,int width,int height,float c,int swapInterval)124 static void useGL(Display *dpy, Window win, GLXContext ctx, int width, int height, float c, int swapInterval)
125 {
126 glXMakeContextCurrent(dpy, win, win, ctx);
127 glViewport(0, 0, width, height);
128 if(0 < swapInterval) {
129 fprintf(stderr, "%s: glXSwapIntervalSGI(1)\n", msg);
130 _glXSwapIntervalSGI(1); // offending op after retargeting drawable
131 }
132 fprintf(stderr, "GL_VENDOR: %s\n", glGetString(GL_VENDOR));
133 fprintf(stderr, "GL_VERSION: %s\n", glGetString(GL_VERSION));
134 fprintf(stderr, "GL_RENDERER: %s\n", glGetString(GL_RENDERER));
135 glClearColor(c, c, c, 0.0f);
136 glClearDepth(1.0f);
137 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
138 glXSwapBuffers(dpy, win);
139 glXMakeContextCurrent(dpy, 0, 0, 0);
140 }
141
142 static volatile bool ctxErrorOccurred = false;
ctxErrorHandler(Display * dpy,XErrorEvent * e)143 static int ctxErrorHandler( Display *dpy, XErrorEvent *e )
144 {
145 const char * errnoStr = strerror(errno);
146 char errCodeStr[80];
147 char reqCodeStr[80];
148
149 snprintf(errCodeStr, sizeof(errCodeStr), "%d", e->request_code);
150 XGetErrorDatabaseText(dpy, "XRequest", errCodeStr, "Unknown", reqCodeStr, sizeof(reqCodeStr));
151 XGetErrorText(dpy, e->error_code, errCodeStr, sizeof(errCodeStr));
152
153 fprintf(stderr, "X11 Error: %d - %s, dpy %p, id %x, # %d: %d:%d %s\n",
154 e->error_code, errCodeStr, e->display, (int)e->resourceid, (int)e->serial,
155 (int)e->request_code, (int)e->minor_code, reqCodeStr);
156 fflush(stderr);
157
158 ctxErrorOccurred = true;
159 return 0;
160 }
161
162 /* attributes for a double buffered visual in RGBA format with at least
163 * 8 bits per color and a 16 bit depth buffer */
164 static int visual_attribs[] = {
165 GLX_X_RENDERABLE , True,
166 GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT,
167 GLX_RENDER_TYPE , GLX_RGBA_BIT,
168 GLX_RED_SIZE , 8,
169 GLX_GREEN_SIZE , 8,
170 GLX_BLUE_SIZE , 8,
171 GLX_DEPTH_SIZE , 16,
172 GLX_DOUBLEBUFFER , True,
173 GLX_STEREO , False,
174 GLX_TRANSPARENT_TYPE, GLX_NONE,
175 //GLX_SAMPLE_BUFFERS , 1,
176 //GLX_SAMPLES , 4,
177 None };
178
179 static int context_attribs[] = {
180 GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
181 GLX_CONTEXT_MINOR_VERSION_ARB, 0,
182 GLX_RENDER_TYPE , GLX_RGBA_TYPE,
183 GLX_CONTEXT_FLAGS_ARB , 0,
184 // GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
185 // GLX_CONTEXT_PROFILE_MASK_ARB , GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
186 None };
187
188 static bool isExtensionSupported(const char *extList, const char *extension);
189
createGLWin(Display * dpy,int width,int height,Window * rWin,GLXContext * rCtx)190 static void createGLWin(Display *dpy, int width, int height, Window *rWin, GLXContext *rCtx)
191 {
192 int glx_major, glx_minor;
193
194 // FBConfigs were added in GLX version 1.3.
195 if ( !glXQueryVersion( dpy, &glx_major, &glx_minor ) ||
196 ( ( glx_major == 1 ) && ( glx_minor < 3 ) ) || ( glx_major < 1 ) )
197 {
198 printf( "Invalid GLX version" );
199 exit(1);
200 }
201
202 int fbcount;
203 GLXFBConfig *fbc = glXChooseFBConfig( dpy, DefaultScreen( dpy ),
204 visual_attribs, &fbcount );
205 if ( !fbc || 0 == fbcount )
206 {
207 printf( "Failed to retrieve a framebuffer config\n" );
208 exit(1);
209 }
210 printf( "Found %d matching FB configs.\n", fbcount );
211
212 GLXFBConfig bestFbc = fbc[ 0 ];
213 int bestFbcID = 0;
214 if( 0 != glXGetFBConfigAttrib( dpy, bestFbc, GLX_FBCONFIG_ID, &bestFbcID ) ) {
215 printf( "Invalid FBConfigID\n" );
216 exit(1);
217 }
218 printf( "Chosen FBConfigID = 0x%x\n", bestFbcID);
219
220 XVisualInfo *vi = glXGetVisualFromFBConfig( dpy, bestFbc );
221 printf( "Chosen visual ID = 0x%x\n", (int) vi->visualid );
222
223 XSetWindowAttributes swa;
224 Colormap cmap;
225 swa.colormap = cmap = XCreateColormap( dpy,
226 RootWindow( dpy, vi->screen ),
227 vi->visual, AllocNone );
228 swa.background_pixmap = None ;
229 swa.border_pixel = 0;
230 swa.event_mask = StructureNotifyMask;
231
232 printf( "Creating window\n" );
233 Window win = XCreateWindow( dpy, RootWindow( dpy, vi->screen ),
234 0, 0, width, height, 0, vi->depth, InputOutput,
235 vi->visual,
236 CWBorderPixel|CWColormap|CWEventMask, &swa );
237 if ( !win )
238 {
239 printf( "Failed to create window.\n" );
240 exit(1);
241 }
242
243 // Done with the visual info data
244 XFree( vi );
245
246 XStoreName( dpy, win, "GL Window" );
247
248 XMapWindow( dpy, win );
249
250 *rWin = win;
251
252 GLXContext ctx0 = glXCreateNewContext( dpy, bestFbc, GLX_RGBA_TYPE, 0, True );
253 if( !ctx0 ) {
254 printf( "Failed to create intermediate old OpenGL context\n" );
255 exit(1);
256 }
257 glXMakeContextCurrent(dpy, win, win, ctx0);
258
259
260 // Get the default screen's GLX extension list
261 const char *glxExts01 = glXQueryExtensionsString( dpy,
262 DefaultScreen( dpy ) );
263 const char *glxExts02 = glXGetClientString( dpy, GLX_EXTENSIONS);
264 const char *glxExts03 = glXQueryServerString( dpy, DefaultScreen( dpy ), GLX_EXTENSIONS);
265
266 // NOTE: It is not necessary to create or make current to a context before
267 // calling glXGetProcAddressARB
268 PFNGLXCREATECONTEXTATTRIBSARBPROC _glXCreateContextAttribsARB = 0;
269 _glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)
270 glXGetProcAddressARB( (const GLubyte *) "glXCreateContextAttribsARB" );
271
272 // Check for the GLX_ARB_create_context extension string and the function.
273 // If either is not present, use GLX 1.3 context creation method.
274 bool isGLX_ARB_create_contextAvail = isExtensionSupported( glxExts01, "GLX_ARB_create_context" ) ||
275 isExtensionSupported( glxExts02, "GLX_ARB_create_context" ) ||
276 isExtensionSupported( glxExts03, "GLX_ARB_create_context" );
277
278 glXMakeContextCurrent(dpy, 0, 0, 0);
279
280 GLXContext ctx = 0;
281
282 // Install an X error handler so the application won't exit if GL 3.0
283 // context allocation fails.
284 //
285 // Note this error handler is global. All display connections in all threads
286 // of a process use the same error handler, so be sure to guard against other
287 // threads issuing X commands while this code is running.
288 int (*oldHandler)(Display*, XErrorEvent*) =
289 XSetErrorHandler(&ctxErrorHandler);
290
291 if ( !isGLX_ARB_create_contextAvail || !_glXCreateContextAttribsARB )
292 {
293 printf( "glXCreateContextAttribsARB() not found (ext %d, func %p)"
294 " ... using old-style GLX context\n", isGLX_ARB_create_contextAvail, _glXCreateContextAttribsARB );
295 printf( "extensions 01: %s\n", glxExts01);
296 printf( "extensions 02: %s\n", glxExts02);
297 printf( "extensions 03: %s\n", glxExts03);
298 ctx = ctx0;
299 }
300
301 // If it does, try to get a GL 3.0 context!
302 else
303 {
304 printf( "Creating context\n" );
305 XSync( dpy, False );
306 ctxErrorOccurred = false;
307 ctx = _glXCreateContextAttribsARB( dpy, bestFbc, 0, True, context_attribs );
308 XSync( dpy, False );
309
310 if ( !ctxErrorOccurred && ctx ) {
311 printf( "Created GL 3.0 context\n" );
312 glXDestroyContext(dpy, ctx0); // get rid of old ctx
313 } else
314 {
315 // Couldn't create GL 3.0 context. Fall back to old-style 2.x context.
316 // When a context version below 3.0 is requested, implementations will
317 // return the newest context version compatible with OpenGL versions less
318 // than version 3.0.
319 // GLX_CONTEXT_MAJOR_VERSION_ARB = 1
320 context_attribs[1] = 1;
321 // GLX_CONTEXT_MINOR_VERSION_ARB = 0
322 context_attribs[3] = 0;
323
324 printf( "Failed to create GL 3.0 context (err %d, ctx %p)"
325 " ... using old-style GLX context\n", ctxErrorOccurred, (void*)ctx );
326 ctx = ctx0;
327
328 ctxErrorOccurred = false;
329 }
330 }
331
332 // Sync to ensure any errors generated are processed.
333 XSync( dpy, False );
334
335 // Restore the original error handler
336 XSetErrorHandler( oldHandler );
337
338 if ( ctxErrorOccurred || !ctx )
339 {
340 printf( "Failed to create an OpenGL context\n" );
341 exit(1);
342 }
343
344 XFree( fbc );
345
346 *rCtx = ctx;
347 }
348
349 // Helper to check for extension string presence. Adapted from:
350 // http://www.opengl.org/resources/features/OGLextensions/
isExtensionSupported(const char * extList,const char * extension)351 static bool isExtensionSupported(const char *extList, const char *extension)
352 {
353
354 const char *start;
355 const char *where, *terminator;
356
357 /* Extension names should not have spaces. */
358 where = strchr(extension, ' ');
359 if ( where || *extension == '\0' )
360 return false;
361
362 /* It takes a bit of care to be fool-proof about parsing the
363 OpenGL extensions string. Don't be fooled by sub-strings,
364 etc. */
365 for ( start = extList; ; ) {
366 where = strstr( start, extension );
367
368 if ( !where )
369 break;
370
371 terminator = where + strlen( extension );
372
373 if ( where == start || *(where - 1) == ' ' )
374 if ( *terminator == ' ' || *terminator == '\0' )
375 return true;
376
377 start = terminator;
378 }
379
380 return false;
381 }
382
383