UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
glx_common.c
Go to the documentation of this file.
1
5/*
6 * Copyright (c) 2012-2016 CESNET, z. s. p. o.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, is permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * 3. Neither the name of CESNET nor the names of its contributors may be
21 * used to endorse or promote products derived from this software without
22 * specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
26 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
28 * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
34 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
35 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38#ifdef HAVE_CONFIG_H
39#include "config.h"
40#include "config_unix.h"
41#endif
42#include "debug.h"
43
44#include <GL/glew.h>
45#include <X11/Xlib.h>
46#include <X11/Xutil.h>
47#include <GL/glx.h>
48#include "x11_common.h"
49#include "glx_common.h"
50
51#ifdef HAVE_GPUPERFAPI
52#include "GPUPerfAPI.h"
53#endif
54
55#define GLX_MAGIC 0x665f43ffu
56
57#define VERSION_GET_MAJOR(version) (version >> 8u)
58#define VERSION_GET_MINOR(version) (version & 0xFF)
59#define VERSION_IS_UNSPECIFIED(version) (!version)
60
61/*
62 * GLX context creation overtaken from:
63 * http://www.opengl.org/wiki/Tutorial:_OpenGL_3.0_Context_Creation_%28GLX%29
64 */
65
67{
68 GLXContext ctx;
69 Window win;
70 Colormap cmap;
71 uint32_t magic;
72};
73
74static int isExtensionSupported(const char *extList, const char *extension);
75static int ctxErrorHandler( Display *dpy, XErrorEvent *ev );
76
77#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
78#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
79typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
80
81void glx_validate(void *arg)
82{
83 debug_msg("Validating GLX context %p.\n", arg);
84 struct state_glx *context = (struct state_glx *) arg;
85
86 assert(context->magic == GLX_MAGIC);
87 debug_msg("GLX context %p validated.\n", context);
88}
89
90void glx_free(void *arg)
91{
92 struct state_glx *context = (struct state_glx *) arg;
93 Display *display = NULL;
94
95 assert(context->magic == GLX_MAGIC);
96
97 x11_lock();
98
99#ifdef HAVE_GPUPERFAPI
100 GPA_CloseContext();
101#endif
102
104 if(!display) {
105 error_msg("Unable to get shared display for GLX!\n");
106 x11_unlock();
107 }
108
109
110 glXMakeCurrent( display, context->win, context->ctx );
111
112 glXDestroyContext( display, context->ctx );
113 debug_msg("GLX context destroyed\n");
114#ifdef HAVE_GPUPERFAPI
115 GPA_Destroy();
116#endif
117
118 XDestroyWindow( display, context->win );
119 XFreeColormap( display, context->cmap );
120
122 free(context);
123
124 x11_unlock();
125}
126
127// Helper to check for extension string presence. Adapted from:
128// http://www.opengl.org/resources/features/OGLextensions/
129static int isExtensionSupported(const char *extList, const char *extension)
130{
131 const char *start;
132 const char *where, *terminator;
133
134 /* Extension names should not have spaces. */
135 where = strchr(extension, ' ');
136 if ( where || *extension == '\0' )
137 return FALSE;
138
139 /* It takes a bit of care to be fool-proof about parsing the
140 OpenGL extensions string. Don't be fooled by sub-strings,
141 etc. */
142 for ( start = extList; ; ) {
143 where = strstr( start, extension );
144
145 if ( !where )
146 break;
147
148 terminator = where + strlen( extension );
149
150 if ( where == start || *(where - 1) == ' ' )
151 if ( *terminator == ' ' || *terminator == '\0' )
152 return TRUE;
153
154 start = terminator;
155 }
156
157 return FALSE;
158}
159
161static int ctxErrorHandler( Display *dpy, XErrorEvent *ev )
162{
163 UNUSED(dpy);
164 UNUSED(ev);
166 return 0;
167}
168
170{
171 Display *display;
172 struct state_glx *context;
173
174 context = (struct state_glx *) malloc(sizeof(struct state_glx));
175 context->magic = GLX_MAGIC;
176 x11_lock();
177
179
180 if(!display) {
181 free(context);
182 x11_unlock();
183 return NULL;
184 }
185
186#ifdef HAVE_GPUPERFAPI
187 GPA_Status gpa_status;
188
189 gpa_status = GPA_Initialize();
190 assert(gpa_status == GPA_STATUS_OK);
191#endif
192
193
194
195 // Get a matching FB config
196 static int visual_attribs[] =
197 {
198 GLX_X_RENDERABLE , True,
199 GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT,
200 GLX_RENDER_TYPE , GLX_RGBA_BIT,
201 GLX_X_VISUAL_TYPE , GLX_TRUE_COLOR,
202 GLX_RED_SIZE , 8,
203 GLX_GREEN_SIZE , 8,
204 GLX_BLUE_SIZE , 8,
205 GLX_ALPHA_SIZE , 8,
206 GLX_DEPTH_SIZE , 24,
207 GLX_STENCIL_SIZE , 8,
208 GLX_DOUBLEBUFFER , True,
209 //GLX_SAMPLE_BUFFERS , 1,
210 //GLX_SAMPLES , 4,
211 None
212 };
213
214 int glx_major, glx_minor;
215
216 int fbcount;
217 int best_fbc = -1, worst_fbc = -1, best_num_samp = -1, worst_num_samp = 999;
218 GLXFBConfig *fbc;
219 GLXFBConfig bestFbc;
220 XVisualInfo *vi;
221 const char *glxExts;
222 glXCreateContextAttribsARBProc glXCreateContextAttribsARB;
223 int (*oldHandler)(Display*, XErrorEvent*);
224
225 // FBConfigs were added in GLX version 1.3.
226 if ( !glXQueryVersion( display, &glx_major, &glx_minor ) ||
227 ( ( glx_major == 1 ) && ( glx_minor < 3 ) ) || ( glx_major < 1 ) )
228 {
229 verbose_msg( "Invalid GLX version" );
230 goto error;
231 }
232
233 debug_msg( "Getting matching framebuffer configs\n" );
234 fbc = glXChooseFBConfig( display, DefaultScreen( display ),
235 visual_attribs, &fbcount );
236 if ( !fbc )
237 {
238 debug_msg( "Failed to retrieve a framebuffer config\n" );
239 goto error;
240 }
241 debug_msg( "Found %d matching FB configs.\n", fbcount );
242
243 // Pick the FB config/visual with the most samples per pixel
244 debug_msg( "Getting XVisualInfos\n" );
245
246 for ( int i = 0; i < fbcount; i++ )
247 {
248 XVisualInfo *vi = glXGetVisualFromFBConfig( display, fbc[i] );
249 if ( vi )
250 {
251 int samp_buf, samples;
252 glXGetFBConfigAttrib( display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf );
253 glXGetFBConfigAttrib( display, fbc[i], GLX_SAMPLES , &samples );
254
255 debug_msg( " Matching fbconfig %d, visual ID 0x%2x: SAMPLE_BUFFERS = %d,"
256 " SAMPLES = %d\n",
257 i, (unsigned int) vi -> visualid, samp_buf, samples );
258
259 if ( best_fbc < 0 || (samp_buf && samples > best_num_samp ))
260 best_fbc = i, best_num_samp = samples;
261 if ( worst_fbc < 0 || !samp_buf || samples < worst_num_samp )
262 worst_fbc = i, worst_num_samp = samples;
263 }
264 XFree( vi );
265 }
266
267 bestFbc = fbc[ best_fbc ];
268
269 // Be sure to free the FBConfig list allocated by glXChooseFBConfig()
270 XFree( fbc );
271
272 // Get a visual
273 vi = glXGetVisualFromFBConfig( display, bestFbc );
274 debug_msg( "Chosen visual ID = 0x%x\n", (unsigned int) vi->visualid );
275
276 debug_msg( "Creating colormap\n" );
277 XSetWindowAttributes swa;
278 swa.colormap = context->cmap = XCreateColormap( display,
279 RootWindow( display, vi->screen ),
280 vi->visual, AllocNone );
281 swa.background_pixmap = None ;
282 swa.border_pixel = 0;
283 swa.event_mask = StructureNotifyMask;
284
285 debug_msg( "Creating window\n" );
286 context->win = XCreateWindow( display, RootWindow( display, vi->screen ),
287 0, 0, 1920, 1080, 0, vi->depth, InputOutput,
288 vi->visual,
289 CWBorderPixel|CWColormap|CWEventMask, &swa );
290 XMoveWindow(display, context->win, 0, 0);
291
292 if ( !context->win )
293 {
294 debug_msg( "Failed to create window.\n" );
295 goto error;
296 }
297
298 // Done with the visual info data
299 XFree( vi );
300
301 /* We don't need this for UG */
302 /*XStoreName( display, win, "GL 3.0 Window" );
303
304 debug_msg( "Mapping window\n" );
305 XMapWindow( display, win );*/
306
307 // Get the default screen's GLX extension list
308 glxExts = glXQueryExtensionsString( display,
309 DefaultScreen( display ) );
310
311 // NOTE: It is not necessary to create or make current to a context before
312 // calling glXGetProcAddressARB
313 glXCreateContextAttribsARB = 0;
314 glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)
315 glXGetProcAddressARB( (const GLubyte *) "glXCreateContextAttribsARB" );
316
317 context->ctx = 0;
318
319 // Install an X error handler so the application won't exit if GL 3.0
320 // context allocation fails.
321 //
322 // Note this error handler is global. All display connections in all threads
323 // of a process use the same error handler, so be sure to guard against other
324 // threads issuing X commands while this code is running.
326 oldHandler = XSetErrorHandler(&ctxErrorHandler);
327
328 // Check for the GLX_ARB_create_context extension string and the function.
329 // If either is not present, use GLX 1.3 context creation method.
330 if ( !isExtensionSupported( glxExts, "GLX_ARB_create_context" ) ||
331 !glXCreateContextAttribsARB )
332 {
333 debug_msg( "glXCreateContextAttribsARB() not found"
334 " ... using old-style GLX context\n" );
335 context->ctx = glXCreateNewContext( display, bestFbc, GLX_RGBA_TYPE, 0, True );
336 if(!VERSION_IS_UNSPECIFIED(version)) {
337 goto error;
338 }
339 }
340
341 // If it does, try to get a GL 3.0 context!
342 else
343 {
344 int context_attribs[] =
345 {
348 //GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
349 None
350 };
351
352 if(!VERSION_IS_UNSPECIFIED(version)) {
353 context_attribs[1] = VERSION_GET_MAJOR(version);
354 context_attribs[3] = VERSION_GET_MINOR(version);
355 }
356
357 debug_msg( "Creating context\n" );
358 context->ctx = glXCreateContextAttribsARB( display, bestFbc, 0,
359 True, context_attribs );
360
361 // Sync to ensure any errors generated are processed.
362 XSync( display, False );
363 if ( !ctxErrorOccurred && context->ctx )
364 debug_msg( "Created GL %d.%d context\n", context_attribs[1], context_attribs[3]);
365 else
366 {
367 if(VERSION_IS_UNSPECIFIED(version)) {
368 // Couldn't create GL 3.0 context. Fall back to old-style 2.x context.
369 // When a context version below 3.0 is requested, implementations will
370 // return the newest context version compatible with OpenGL versions less
371 // than version 3.0.
372 // GLX_CONTEXT_MAJOR_VERSION_ARB = 1
373 context_attribs[1] = 1;
374 // GLX_CONTEXT_MINOR_VERSION_ARB = 0
375 context_attribs[3] = 0;
376
378
379 debug_msg( "Failed to create GL 3.0 context"
380 " ... using old-style GLX context\n" );
381 context->ctx = glXCreateContextAttribsARB( display, bestFbc, 0,
382 True, context_attribs );
383 } else {
384 // we explicitly requested context which we cannot obtain - return error then
385 goto error;
386 }
387 }
388 }
389
390 // Sync to ensure any errors generated are processed.
391 XSync( display, False );
392
393 // Restore the original error handler
394 XSetErrorHandler( oldHandler );
395
396 if ( ctxErrorOccurred || !context->ctx )
397 {
398 debug_msg( "Failed to create an OpenGL context\n" );
399 goto error;
400 }
401
402 // Verifying that context is a direct context
403 if ( ! glXIsDirect ( display, context->ctx ) )
404 {
405 debug_msg( "Indirect GLX rendering context obtained\n" );
406 }
407 else
408 {
409 debug_msg( "Direct GLX rendering context obtained\n" );
410 }
411
412 debug_msg( "Making context current\n" );
413 glXMakeCurrent( display, context->win, context->ctx );
414
415 glewInit();
416
417 x11_unlock();
418
419 glx_validate(context);
420
421#ifdef HAVE_GPUPERFAPI
422 gpa_status = GPA_OpenContext( context->ctx );
423 assert(gpa_status == GPA_STATUS_OK);
424#endif
425
426 return (void *) context;
427
428error:
429 free(context);
430 x11_unlock();
431 return NULL;
432}
433
434void glx_make_current(void *arg)
435{
436 if(arg) {
437 struct state_glx *context = (struct state_glx *) arg;
438 Bool res;
439
440 res = glXMakeCurrent( x11_get_display(), context->win, context->ctx );
441 if(res != True) {
442 fprintf(stderr, "Acquiring GLX context failed!\n");
443 }
444 } else {
445 Bool res;
446
447 res = glXMakeCurrent( x11_get_display(), None, NULL);
448 if(res != True) {
449 fprintf(stderr, "Releasing GLX context failed!\n");
450 }
451 }
452}
453
#define UNUSED(x)
#define TRUE
#define FALSE
#define error_msg(...)
Definition debug.h:89
#define verbose_msg(...)
Definition debug.h:90
#define debug_msg(...)
#define debug_msg(...) log_msg(LOG_LEVEL_DEBUG, "[pid/%d +%d %s] ", getpid(), LINE,...
Definition debug.h:92
static int ctxErrorOccurred
Definition glx_common.c:160
static int isExtensionSupported(const char *extList, const char *extension)
Definition glx_common.c:129
#define VERSION_GET_MAJOR(version)
Definition glx_common.c:57
static int ctxErrorHandler(Display *dpy, XErrorEvent *ev)
Definition glx_common.c:161
#define VERSION_GET_MINOR(version)
Definition glx_common.c:58
#define GLX_CONTEXT_MINOR_VERSION_ARB
Definition glx_common.c:78
void glx_validate(void *arg)
Definition glx_common.c:81
void glx_free(void *arg)
Definition glx_common.c:90
#define VERSION_IS_UNSPECIFIED(version)
Definition glx_common.c:59
#define GLX_CONTEXT_MAJOR_VERSION_ARB
Definition glx_common.c:77
GLXContext(* glXCreateContextAttribsARBProc)(Display *, GLXFBConfig, GLXContext, Bool, const int *)
Definition glx_common.c:79
#define GLX_MAGIC
Definition glx_common.c:55
void glx_make_current(void *arg)
Definition glx_common.c:434
void * glx_init(glx_opengl_version_t version)
Definition glx_common.c:169
uint32_t glx_opengl_version_t
Definition glx_common.h:38
static void start()
Definition sdp.c:202
This struct represents initialized video display state.
Colormap cmap
Definition glx_common.c:70
Window win
Definition glx_common.c:69
GLXContext ctx
Definition glx_common.c:68
uint32_t magic
Definition glx_common.c:71
void * x11_acquire_display(void)
Definition x11_common.c:108
void x11_lock(void)
Definition x11_common.c:147
void x11_unlock(void)
Definition x11_common.c:153
void * x11_get_display(void)
Definition x11_common.c:126
void x11_release_display()
Definition x11_common.c:132