1 /*
2 * GStreamer
3 * Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.com>
4 * Copyright (C) 2012 Matthew Waters <ystreet00@gmail.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22 #define GLIB_DISABLE_DEPRECATION_WARNINGS
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 /* FIXME: Sharing contexts requires the Display to be the same.
29 * May need to box it
30 */
31
32 #include <gst/gst.h>
33
34 #include "../gstgl_fwd.h"
35 #include <gst/gl/gstglcontext.h>
36
37 #include <gst/gl/gl.h>
38 #include "gstglcontext_glx.h"
39 #include "../utils/opengl_versions.h"
40 #include "../gstglcontext_private.h"
41
42 #define GST_CAT_DEFAULT gst_gl_context_debug
43
44 static guintptr gst_gl_context_glx_get_gl_context (GstGLContext * context);
45 static void gst_gl_context_glx_swap_buffers (GstGLContext * context);
46 static gboolean gst_gl_context_glx_activate (GstGLContext * context,
47 gboolean activate);
48 static gboolean gst_gl_context_glx_create_context (GstGLContext *
49 context, GstGLAPI gl_api, GstGLContext * other_context, GError ** error);
50 static void gst_gl_context_glx_destroy_context (GstGLContext * context);
51 static gboolean gst_gl_context_glx_choose_format (GstGLContext *
52 context, GError ** error);
53 static GstGLAPI gst_gl_context_glx_get_gl_api (GstGLContext * context);
54 static GstGLPlatform gst_gl_context_glx_get_gl_platform (GstGLContext *
55 context);
56 static void gst_gl_context_glx_get_gl_platform_version (GstGLContext * context,
57 gint * major, gint * minor);
58 static GstStructure *gst_gl_context_glx_get_config (GstGLContext * context);
59 static gboolean gst_gl_context_glx_request_config (GstGLContext * context,
60 GstStructure * config);
61
62 struct _GstGLContextGLXPrivate
63 {
64 int glx_major;
65 int glx_minor;
66
67 GstGLAPI context_api;
68
69 GLXFBConfig *fbconfigs;
70 GLXContext (*glXCreateContextAttribsARB) (Display *, GLXFBConfig,
71 GLXContext, Bool, const int *);
72
73 GstStructure *requested_config;
74 };
75
76 #define gst_gl_context_glx_parent_class parent_class
77 G_DEFINE_TYPE_WITH_PRIVATE (GstGLContextGLX, gst_gl_context_glx,
78 GST_TYPE_GL_CONTEXT);
79
80 static void
gst_gl_context_glx_class_init(GstGLContextGLXClass * klass)81 gst_gl_context_glx_class_init (GstGLContextGLXClass * klass)
82 {
83 GstGLContextClass *context_class = (GstGLContextClass *) klass;
84
85 context_class->get_gl_context =
86 GST_DEBUG_FUNCPTR (gst_gl_context_glx_get_gl_context);
87 context_class->activate = GST_DEBUG_FUNCPTR (gst_gl_context_glx_activate);
88 context_class->create_context =
89 GST_DEBUG_FUNCPTR (gst_gl_context_glx_create_context);
90 context_class->destroy_context =
91 GST_DEBUG_FUNCPTR (gst_gl_context_glx_destroy_context);
92 context_class->choose_format =
93 GST_DEBUG_FUNCPTR (gst_gl_context_glx_choose_format);
94 context_class->swap_buffers =
95 GST_DEBUG_FUNCPTR (gst_gl_context_glx_swap_buffers);
96
97 context_class->get_gl_api = GST_DEBUG_FUNCPTR (gst_gl_context_glx_get_gl_api);
98 context_class->get_gl_platform =
99 GST_DEBUG_FUNCPTR (gst_gl_context_glx_get_gl_platform);
100 context_class->get_proc_address =
101 GST_DEBUG_FUNCPTR (gst_gl_context_glx_get_proc_address);
102 context_class->get_current_context =
103 GST_DEBUG_FUNCPTR (gst_gl_context_glx_get_current_context);
104 context_class->get_gl_platform_version =
105 GST_DEBUG_FUNCPTR (gst_gl_context_glx_get_gl_platform_version);
106 context_class->get_config = GST_DEBUG_FUNCPTR (gst_gl_context_glx_get_config);
107 context_class->request_config =
108 GST_DEBUG_FUNCPTR (gst_gl_context_glx_request_config);
109 }
110
111 static void
gst_gl_context_glx_init(GstGLContextGLX * context)112 gst_gl_context_glx_init (GstGLContextGLX * context)
113 {
114 context->priv = gst_gl_context_glx_get_instance_private (context);
115 }
116
117 GstGLContextGLX *
gst_gl_context_glx_new(GstGLDisplay * display)118 gst_gl_context_glx_new (GstGLDisplay * display)
119 {
120 GstGLContextGLX *context;
121
122 if ((gst_gl_display_get_handle_type (display) & GST_GL_DISPLAY_TYPE_X11) == 0)
123 /* we require an x11 display handle to create GLX contexts */
124 return NULL;
125
126 context = g_object_new (GST_TYPE_GL_CONTEXT_GLX, NULL);
127 gst_object_ref_sink (context);
128
129 return context;
130 }
131
132 static GstGLConfigSurfaceType
glx_drawable_type_to_gst(int drawable_type)133 glx_drawable_type_to_gst (int drawable_type)
134 {
135 GstGLConfigSurfaceType ret = GST_GL_CONFIG_SURFACE_TYPE_NONE;
136
137 if (drawable_type & GLX_WINDOW_BIT)
138 ret |= GST_GL_CONFIG_SURFACE_TYPE_WINDOW;
139 if (drawable_type & GLX_PIXMAP_BIT)
140 ret |= GST_GL_CONFIG_SURFACE_TYPE_PIXMAP;
141 if (drawable_type & GLX_PBUFFER_BIT)
142 ret |= GST_GL_CONFIG_SURFACE_TYPE_PBUFFER;
143
144 return ret;
145 }
146
147 static GstGLConfigCaveat
glx_caveat_to_gst(int caveat)148 glx_caveat_to_gst (int caveat)
149 {
150 switch (caveat) {
151 case GLX_NONE:
152 return GST_GL_CONFIG_CAVEAT_NONE;
153 case GLX_SLOW_CONFIG:
154 return GST_GL_CONFIG_CAVEAT_SLOW;
155 case GLX_NON_CONFORMANT_CONFIG:
156 return GST_GL_CONFIG_CAVEAT_NON_CONFORMANT;
157 default:
158 GST_WARNING ("unknown GLX caveat value %u (0x%x)", caveat, caveat);
159 return GST_GL_CONFIG_CAVEAT_NON_CONFORMANT;
160 }
161 }
162
163 static GstStructure *
fb_config_to_structure(GstGLContext * context,Display * dpy,GLXFBConfig fbconfig)164 fb_config_to_structure (GstGLContext * context,
165 Display * dpy, GLXFBConfig fbconfig)
166 {
167 GstStructure *ret;
168 int val, render_type;
169
170 ret = gst_structure_new (GST_GL_CONFIG_STRUCTURE_NAME,
171 GST_GL_CONFIG_STRUCTURE_SET_ARGS (PLATFORM, GstGLPlatform,
172 GST_GL_PLATFORM_GLX), "platform-sub-type", G_TYPE_STRING, "fbconfig",
173 NULL);
174
175 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_FBCONFIG_ID, &val))
176 goto failure;
177 gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (CONFIG_ID, int,
178 val), NULL);
179
180 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_VISUAL_ID, &val))
181 goto failure;
182 gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (NATIVE_VISUAL_ID,
183 guint, val), NULL);
184
185 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_CONFIG_CAVEAT, &val))
186 goto failure;
187 gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (CAVEAT,
188 GstGLConfigCaveat, glx_caveat_to_gst (val)), NULL);
189
190 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_DRAWABLE_TYPE, &val))
191 goto failure;
192 gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (SURFACE_TYPE,
193 GstGLConfigSurfaceType, glx_drawable_type_to_gst (val)), NULL);
194
195 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_X_RENDERABLE, &val))
196 goto failure;
197 gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (NATIVE_RENDERABLE,
198 gboolean, val), NULL);
199
200 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_LEVEL, &val))
201 goto failure;
202 gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (LEVEL, int, val),
203 NULL);
204
205 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_RENDER_TYPE,
206 &render_type))
207 goto failure;
208
209 if (render_type & GLX_RGBA_BIT) {
210 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_RED_SIZE, &val))
211 goto failure;
212 gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (RED_SIZE, int,
213 val), NULL);
214
215 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_GREEN_SIZE, &val))
216 goto failure;
217 gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (GREEN_SIZE, int,
218 val), NULL);
219
220 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_BLUE_SIZE, &val))
221 goto failure;
222 gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (BLUE_SIZE, int,
223 val), NULL);
224
225 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_ALPHA_SIZE, &val))
226 goto failure;
227 gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (ALPHA_SIZE, int,
228 val), NULL);
229 }
230
231 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_DEPTH_SIZE, &val))
232 goto failure;
233 gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (DEPTH_SIZE, int,
234 val), NULL);
235
236 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_STENCIL_SIZE, &val))
237 goto failure;
238 gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (STENCIL_SIZE, int,
239 val), NULL);
240
241 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_MAX_PBUFFER_WIDTH,
242 &val))
243 goto failure;
244 gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (MAX_PBUFFER_WIDTH,
245 int, val), NULL);
246
247 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_MAX_PBUFFER_HEIGHT,
248 &val))
249 goto failure;
250 gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (MAX_PBUFFER_HEIGHT,
251 int, val), NULL);
252
253 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_MAX_PBUFFER_PIXELS,
254 &val))
255 goto failure;
256 gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (MAX_PBUFFER_PIXELS,
257 int, val), NULL);
258
259 return ret;
260
261 failure:
262 gst_structure_free (ret);
263 return NULL;
264 }
265
266 static void
gst_gl_context_glx_dump_fb_config(GstGLContextGLX * glx,Display * dpy,GLXFBConfig fbconfig)267 gst_gl_context_glx_dump_fb_config (GstGLContextGLX * glx,
268 Display * dpy, GLXFBConfig fbconfig)
269 {
270
271 #define SIMPLE_STRING_ASSIGN(res_str,value,to_check,str) \
272 if (res_str == NULL && value == to_check) \
273 res_str = str
274
275 int fb_id, render_type;
276 {
277 int visual_id;
278 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_FBCONFIG_ID,
279 &fb_id))
280 return;
281 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_VISUAL_ID,
282 &visual_id))
283 return;
284 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_RENDER_TYPE,
285 &render_type))
286 return;
287
288 GST_DEBUG_OBJECT (glx, "dumping GLXFBConfig %p with id 0x%x and "
289 "visual id 0x%x", fbconfig, fb_id, visual_id);
290 }
291
292 {
293 #define MAX_RENDER_TYPE 8
294 #define MAX_DRAWABLE_TYPE 8
295 int x_renderable, visual_type, drawable_type, caveat, i = 0;
296 const char *render_values[MAX_RENDER_TYPE] = { NULL, };
297 const char *drawable_values[MAX_DRAWABLE_TYPE] = { NULL, };
298 const char *caveat_str = NULL;
299 const char *visual_type_str = NULL;
300 char *render_type_str = NULL;
301 char *drawable_type_str = NULL;
302 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_X_RENDERABLE,
303 &x_renderable))
304 return;
305 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_CONFIG_CAVEAT,
306 &caveat))
307 return;
308 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_X_VISUAL_TYPE,
309 &visual_type))
310 return;
311 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_DRAWABLE_TYPE,
312 &drawable_type))
313 return;
314
315 SIMPLE_STRING_ASSIGN (visual_type_str, visual_type, GLX_TRUE_COLOR,
316 "TrueColor");
317 SIMPLE_STRING_ASSIGN (visual_type_str, visual_type, GLX_DIRECT_COLOR,
318 "DirectColor");
319 SIMPLE_STRING_ASSIGN (visual_type_str, visual_type, GLX_PSEUDO_COLOR,
320 "PseudoColor");
321 SIMPLE_STRING_ASSIGN (visual_type_str, visual_type, GLX_STATIC_COLOR,
322 "StaticColor");
323 SIMPLE_STRING_ASSIGN (visual_type_str, visual_type, GLX_GRAY_SCALE,
324 "GrayScale");
325 SIMPLE_STRING_ASSIGN (visual_type_str, visual_type, GLX_STATIC_GRAY,
326 "StaticGray");
327 SIMPLE_STRING_ASSIGN (visual_type_str, visual_type, GLX_NONE, "None");
328
329 SIMPLE_STRING_ASSIGN (caveat_str, caveat, GLX_NONE, "None");
330 SIMPLE_STRING_ASSIGN (caveat_str, caveat, GLX_SLOW_CONFIG, "SlowConfig");
331 SIMPLE_STRING_ASSIGN (caveat_str, caveat, GLX_NON_CONFORMANT_CONFIG,
332 "NonConformantConfig");
333
334 i = 0;
335 if (render_type & GLX_RGBA_BIT)
336 render_values[i++] = "RGBA";
337 if (render_type & GLX_COLOR_INDEX_BIT)
338 render_values[i++] = "Color Index";
339
340 /* bad things have happened if this fails: we haven't allocated enough
341 * space to hold all the values */
342 g_assert (i < MAX_RENDER_TYPE);
343
344 i = 0;
345 if (drawable_type & GLX_WINDOW_BIT)
346 drawable_values[i++] = "Window";
347 if (drawable_type & GLX_PIXMAP_BIT)
348 drawable_values[i++] = "Pixmap";
349 if (drawable_type & GLX_PBUFFER_BIT)
350 drawable_values[i++] = "PBuffer";
351
352 /* bad things have happened if this fails: we haven't allocated enough
353 * space to hold all the values */
354 g_assert (i < MAX_DRAWABLE_TYPE);
355
356 render_type_str = g_strjoinv ("|", (char **) render_values);
357 drawable_type_str = g_strjoinv ("|", (char **) drawable_values);
358 GST_DEBUG_OBJECT (glx, "Is XRenderable?: %s, visual type: (0x%x) %s, "
359 "render type: (0x%x) %s, drawable type: (0x%x) %s, caveat: (0x%x) %s",
360 x_renderable ? "YES" : "NO", visual_type, visual_type_str, render_type,
361 render_type_str, drawable_type, drawable_type_str, caveat, caveat_str);
362 g_free (render_type_str);
363 g_free (drawable_type_str);
364 #undef MAX_RENDER_TYPE
365 #undef MAX_DRAWABLE_TYPE
366 }
367
368 {
369 int buffer_size, level, double_buffered, stereo, aux_buffers;
370 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_BUFFER_SIZE,
371 &buffer_size))
372 return;
373 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_LEVEL, &level))
374 return;
375 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_DOUBLEBUFFER,
376 &double_buffered))
377 return;
378 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_STEREO, &stereo))
379 return;
380 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_AUX_BUFFERS,
381 &aux_buffers))
382 return;
383 GST_DEBUG_OBJECT (glx, "Level: %i, buffer size: %i, double buffered: %i, "
384 "stereo: %i, aux buffers: %i", level, buffer_size, double_buffered,
385 stereo, aux_buffers);
386 }
387
388 if (render_type & GLX_RGBA_BIT) {
389 int r, g, b, a;
390 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_RED_SIZE, &r))
391 return;
392 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_GREEN_SIZE, &g))
393 return;
394 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_BLUE_SIZE, &b))
395 return;
396 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_ALPHA_SIZE, &a))
397 return;
398 GST_DEBUG_OBJECT (glx, "[R, G, B, A] = [%i, %i, %i, %i]", r, g, b, a);
399 }
400
401 {
402 int d, s;
403 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_DEPTH_SIZE, &d))
404 return;
405 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_STENCIL_SIZE, &s))
406 return;
407
408 GST_DEBUG_OBJECT (glx, "[D, S] = [%i, %i]", d, s);
409 }
410
411 {
412 int r, g, b, a;
413 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_ACCUM_RED_SIZE, &r))
414 return;
415 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_ACCUM_GREEN_SIZE,
416 &g))
417 return;
418 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_ACCUM_BLUE_SIZE,
419 &b))
420 return;
421 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_ACCUM_ALPHA_SIZE,
422 &a))
423 return;
424 GST_DEBUG_OBJECT (glx, "Accumulation [R, G, B, A] = [%i, %i, %i, %i]", r, g,
425 b, a);
426 }
427
428 {
429 int transparent_type;
430 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_TRANSPARENT_TYPE,
431 &transparent_type))
432 return;
433
434 if (transparent_type == GLX_NONE) {
435 GST_DEBUG_OBJECT (glx, "Is opaque");
436 } else if (transparent_type == GLX_TRANSPARENT_INDEX) {
437 int transparent_index;
438 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_TRANSPARENT_INDEX,
439 &transparent_index))
440 return;
441 GST_DEBUG_OBJECT (glx, "Is transparent for index value 0x%x",
442 transparent_index);
443 } else if (transparent_type == GLX_TRANSPARENT_RGB) {
444 int r, g, b, a;
445 if (Success != glXGetFBConfigAttrib (dpy, fbconfig,
446 GLX_TRANSPARENT_RED_VALUE, &r))
447 return;
448 if (Success != glXGetFBConfigAttrib (dpy, fbconfig,
449 GLX_TRANSPARENT_GREEN_VALUE, &g))
450 return;
451 if (Success != glXGetFBConfigAttrib (dpy, fbconfig,
452 GLX_TRANSPARENT_BLUE_VALUE, &b))
453 return;
454 if (Success != glXGetFBConfigAttrib (dpy, fbconfig,
455 GLX_TRANSPARENT_ALPHA_VALUE, &a))
456 return;
457 GST_DEBUG_OBJECT (glx, "Is transparent for value [R, G, B, A] = "
458 "[0x%x, 0x%x, 0x%x, 0x%x]", r, g, b, a);
459 } else {
460 GST_DEBUG_OBJECT (glx, "Unknown transparent type 0x%x", transparent_type);
461 }
462 }
463
464 {
465 int w, h, pixels;
466 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_MAX_PBUFFER_WIDTH,
467 &w))
468 return;
469 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_MAX_PBUFFER_HEIGHT,
470 &h))
471 return;
472 if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_MAX_PBUFFER_PIXELS,
473 &pixels))
474 return;
475 GST_DEBUG_OBJECT (glx,
476 "PBuffer maximum dimensions are [%i, %i]. Max pixels are %i", w,
477 h, pixels);
478 }
479 #undef SIMPLE_STRING_ASSIGN
480 }
481
482 static void
gst_gl_context_glx_dump_all_fb_configs(GstGLContextGLX * glx,Display * dpy,int screen)483 gst_gl_context_glx_dump_all_fb_configs (GstGLContextGLX * glx,
484 Display * dpy, int screen)
485 {
486 int i, n;
487 GLXFBConfig *configs;
488
489 configs = glXGetFBConfigs (dpy, screen, &n);
490
491 for (i = 0; i < n; i++) {
492 gst_gl_context_glx_dump_fb_config (glx, dpy, configs[i]);
493 }
494
495 XFree (configs);
496 }
497
498 static int *
fb_config_attributes_from_structure(GstStructure * config)499 fb_config_attributes_from_structure (GstStructure * config)
500 {
501 guint i = 0, n;
502 int *ret;
503
504 if (!config) {
505 gint attribs[] = {
506 GLX_RENDER_TYPE, GLX_RGBA_BIT,
507 GLX_RED_SIZE, 1,
508 GLX_GREEN_SIZE, 1,
509 GLX_BLUE_SIZE, 1,
510 GLX_DEPTH_SIZE, 16,
511 GLX_DOUBLEBUFFER, True,
512 None
513 };
514
515 return g_memdup2 (attribs, sizeof (attribs));
516 }
517
518 n = gst_structure_n_fields (config) * 2 + 1;
519 ret = g_new0 (gint, n);
520
521 #define TRANSFORM_VALUE(GL_CONF_NAME,GLX_ATTR_NAME) \
522 G_STMT_START { \
523 if (gst_structure_has_field_typed (config, \
524 GST_GL_CONFIG_ATTRIB_NAME(GL_CONF_NAME), \
525 GST_GL_CONFIG_ATTRIB_GTYPE(GL_CONF_NAME))) { \
526 int val; \
527 if (gst_structure_get (config, \
528 GST_GL_CONFIG_ATTRIB_NAME(GL_CONF_NAME), \
529 GST_GL_CONFIG_ATTRIB_GTYPE(GL_CONF_NAME), &val, NULL)) { \
530 ret[i++] = GLX_ATTR_NAME; \
531 ret[i++] = (int) val; \
532 } \
533 } \
534 } G_STMT_END
535
536 TRANSFORM_VALUE (CONFIG_ID, GLX_FBCONFIG_ID);
537 TRANSFORM_VALUE (RED_SIZE, GLX_RED_SIZE);
538 TRANSFORM_VALUE (GREEN_SIZE, GLX_GREEN_SIZE);
539 TRANSFORM_VALUE (BLUE_SIZE, GLX_BLUE_SIZE);
540 TRANSFORM_VALUE (ALPHA_SIZE, GLX_ALPHA_SIZE);
541 TRANSFORM_VALUE (DEPTH_SIZE, GLX_DEPTH_SIZE);
542 TRANSFORM_VALUE (STENCIL_SIZE, GLX_STENCIL_SIZE);
543 /* TODO: more values */
544
545 #undef TRANSFORM_VALUE
546
547 ret[i++] = None;
548 g_assert (i <= n);
549 return ret;
550 }
551
552 static GLXContext
_create_context_with_flags(GstGLContextGLX * context_glx,Display * dpy,GLXFBConfig fbconfig,GLXContext share_context,gint major,gint minor,gint contextFlags,gint profileMask)553 _create_context_with_flags (GstGLContextGLX * context_glx, Display * dpy,
554 GLXFBConfig fbconfig, GLXContext share_context, gint major, gint minor,
555 gint contextFlags, gint profileMask)
556 {
557 GLXContext ret;
558 #define N_ATTRIBS 20
559 gint attribs[N_ATTRIBS];
560 int x_error = 0;
561 gint n = 0;
562
563 if (major) {
564 attribs[n++] = GLX_CONTEXT_MAJOR_VERSION_ARB;
565 attribs[n++] = major;
566 }
567 if (minor) {
568 attribs[n++] = GLX_CONTEXT_MINOR_VERSION_ARB;
569 attribs[n++] = minor;
570 }
571 if (contextFlags) {
572 attribs[n++] = GLX_CONTEXT_FLAGS_ARB;
573 attribs[n++] = contextFlags;
574 }
575 #ifdef GLX_ARB_create_context_profile
576 if (profileMask) {
577 attribs[n++] = GLX_CONTEXT_PROFILE_MASK_ARB;
578 attribs[n++] = profileMask;
579 }
580 #endif
581 attribs[n++] = None;
582
583 g_assert (n < N_ATTRIBS);
584 #undef N_ATTRIBS
585
586 gst_gl_window_x11_trap_x_errors ();
587 ret = context_glx->priv->glXCreateContextAttribsARB (dpy, fbconfig,
588 share_context, True, attribs);
589 x_error = gst_gl_window_x11_untrap_x_errors ();
590
591 if (x_error)
592 ret = 0;
593
594 return ret;
595 }
596
597 static gboolean
gst_gl_context_glx_create_context(GstGLContext * context,GstGLAPI gl_api,GstGLContext * other_context,GError ** error)598 gst_gl_context_glx_create_context (GstGLContext * context,
599 GstGLAPI gl_api, GstGLContext * other_context, GError ** error)
600 {
601 GstGLContextGLX *context_glx;
602 GstGLWindow *window;
603 GstGLWindowX11 *window_x11;
604 GstGLDisplay *display = NULL;
605 gboolean create_context;
606 const char *glx_exts;
607 Display *device;
608 guintptr external_gl_context = 0;
609
610 context_glx = GST_GL_CONTEXT_GLX (context);
611 window = gst_gl_context_get_window (context);
612
613 if (!GST_IS_GL_WINDOW_X11 (window)) {
614 g_set_error (error, GST_GL_CONTEXT_ERROR,
615 GST_GL_CONTEXT_ERROR_WRONG_CONFIG,
616 "Cannot create an GLX context from a non-X11 window");
617 goto failure;
618 }
619
620 window_x11 = GST_GL_WINDOW_X11 (window);
621 display = gst_gl_context_get_display (context);
622
623 if (other_context) {
624 if (gst_gl_context_get_gl_platform (other_context) != GST_GL_PLATFORM_GLX) {
625 g_set_error (error, GST_GL_CONTEXT_ERROR,
626 GST_GL_CONTEXT_ERROR_WRONG_CONFIG,
627 "Cannot share context with non-GLX context");
628 goto failure;
629 }
630
631 external_gl_context = gst_gl_context_get_gl_context (other_context);
632 }
633
634 device = (Display *) gst_gl_display_get_handle (display);
635 if (!device) {
636 g_set_error (error, GST_GL_CONTEXT_ERROR,
637 GST_GL_CONTEXT_ERROR_RESOURCE_UNAVAILABLE, "Invalid Display handle");
638 goto failure;
639 }
640
641 glx_exts = glXQueryExtensionsString (device, DefaultScreen (device));
642
643 create_context = gst_gl_check_extension ("GLX_ARB_create_context", glx_exts);
644 context_glx->priv->glXCreateContextAttribsARB =
645 (gpointer) glXGetProcAddressARB ((const GLubyte *)
646 "glXCreateContextAttribsARB");
647
648 if (!context_glx->glx_context && gl_api & GST_GL_API_OPENGL3 && create_context
649 && context_glx->priv->glXCreateContextAttribsARB) {
650 gint i;
651
652 for (i = 0; i < G_N_ELEMENTS (opengl_versions); i++) {
653 gint profileMask = 0;
654 gint contextFlags = 0;
655
656 if ((opengl_versions[i].major > 3
657 || (opengl_versions[i].major == 3
658 && opengl_versions[i].minor >= 2))) {
659 profileMask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
660 contextFlags |= GLX_CONTEXT_DEBUG_BIT_ARB;
661 } else {
662 break;
663 }
664
665 GST_DEBUG_OBJECT (context, "trying to create a GL %d.%d context",
666 opengl_versions[i].major, opengl_versions[i].minor);
667
668 context_glx->glx_context = _create_context_with_flags (context_glx,
669 device, context_glx->priv->fbconfigs[0],
670 (GLXContext) external_gl_context, opengl_versions[i].major,
671 opengl_versions[i].minor, contextFlags, profileMask);
672
673 if (context_glx->glx_context) {
674 context_glx->priv->context_api = GST_GL_API_OPENGL3;
675 break;
676 }
677 }
678 }
679 if (!context_glx->glx_context && gl_api & GST_GL_API_OPENGL) {
680 context_glx->glx_context =
681 glXCreateContext (device, window_x11->visual_info,
682 (GLXContext) external_gl_context, TRUE);
683 context_glx->priv->context_api = GST_GL_API_OPENGL;
684 }
685
686 if (!context_glx->glx_context) {
687 g_set_error (error, GST_GL_CONTEXT_ERROR,
688 GST_GL_CONTEXT_ERROR_CREATE_CONTEXT, "Failed to create opengl context");
689 goto failure;
690 }
691
692 GST_LOG ("gl context id: %ld", (gulong) context_glx->glx_context);
693
694 gst_object_unref (window);
695 gst_object_unref (display);
696
697 return TRUE;
698
699 failure:
700 if (window)
701 gst_object_unref (window);
702 if (display)
703 gst_object_unref (display);
704
705 return FALSE;
706 }
707
708 static void
gst_gl_context_glx_destroy_context(GstGLContext * context)709 gst_gl_context_glx_destroy_context (GstGLContext * context)
710 {
711 GstGLWindow *window;
712 GstGLContextGLX *context_glx;
713 Display *device;
714
715 context_glx = GST_GL_CONTEXT_GLX (context);
716 window = gst_gl_context_get_window (context);
717 device = (Display *) gst_gl_display_get_handle (window->display);
718
719 if (context_glx->priv->fbconfigs)
720 XFree (context_glx->priv->fbconfigs);
721 context_glx->priv->fbconfigs = NULL;
722
723 glXDestroyContext (device, context_glx->glx_context);
724
725 context_glx->glx_context = 0;
726
727 if (context_glx->priv->requested_config)
728 gst_structure_free (context_glx->priv->requested_config);
729 context_glx->priv->requested_config = NULL;
730
731 gst_object_unref (window);
732 }
733
734 static gboolean
gst_gl_context_glx_choose_format(GstGLContext * context,GError ** error)735 gst_gl_context_glx_choose_format (GstGLContext * context, GError ** error)
736 {
737 GstGLContextGLX *context_glx;
738 GstGLWindow *window;
739 GstGLWindowX11 *window_x11;
740 gint error_base;
741 gint event_base;
742 Display *device;
743
744 context_glx = GST_GL_CONTEXT_GLX (context);
745 window = gst_gl_context_get_window (context);
746
747 if (!GST_IS_GL_WINDOW_X11 (window)) {
748 g_set_error (error, GST_GL_CONTEXT_ERROR,
749 GST_GL_CONTEXT_ERROR_WRONG_CONFIG,
750 "Cannot create an GLX context from a non-X11 window");
751 goto failure;
752 }
753 window_x11 = GST_GL_WINDOW_X11 (window);
754
755 device = (Display *) gst_gl_display_get_handle (window->display);
756 if (!device) {
757 g_set_error (error, GST_GL_CONTEXT_ERROR,
758 GST_GL_CONTEXT_ERROR_RESOURCE_UNAVAILABLE, "Invalid Display handle");
759 goto failure;
760 }
761
762 if (!glXQueryExtension (device, &error_base, &event_base)) {
763 g_set_error (error, GST_GL_CONTEXT_ERROR,
764 GST_GL_CONTEXT_ERROR_RESOURCE_UNAVAILABLE, "No GLX extension");
765 goto failure;
766 }
767
768 if (!glXQueryVersion (device, &context_glx->priv->glx_major,
769 &context_glx->priv->glx_minor)) {
770 g_set_error (error, GST_GL_CONTEXT_ERROR,
771 GST_GL_CONTEXT_ERROR_CREATE_CONTEXT,
772 "Failed to query GLX version (glXQueryVersion failed)");
773 goto failure;
774 }
775
776 GST_INFO ("GLX Version: %d.%d", context_glx->priv->glx_major,
777 context_glx->priv->glx_minor);
778
779 /* legacy case */
780 if (context_glx->priv->glx_major < 1 || (context_glx->priv->glx_major == 1
781 && context_glx->priv->glx_minor < 3)) {
782 gint attribs[] = {
783 GLX_RGBA,
784 GLX_RED_SIZE, 1,
785 GLX_GREEN_SIZE, 1,
786 GLX_BLUE_SIZE, 1,
787 GLX_DEPTH_SIZE, 16,
788 GLX_DOUBLEBUFFER,
789 None
790 };
791
792 window_x11->visual_info = glXChooseVisual (device,
793 window_x11->screen_num, attribs);
794
795 if (!window_x11->visual_info) {
796 g_set_error (error, GST_GL_CONTEXT_ERROR,
797 GST_GL_CONTEXT_ERROR_WRONG_CONFIG,
798 "Bad attributes in glXChooseVisual");
799 goto failure;
800 }
801 } else {
802 int fbcount;
803 int *attribs;
804
805 attribs =
806 fb_config_attributes_from_structure (context_glx->
807 priv->requested_config);
808
809 gst_gl_context_glx_dump_all_fb_configs (context_glx, device,
810 DefaultScreen (device));
811
812 context_glx->priv->fbconfigs = glXChooseFBConfig (device,
813 DefaultScreen (device), attribs, &fbcount);
814
815 g_free (attribs);
816
817 if (!context_glx->priv->fbconfigs) {
818 g_set_error (error, GST_GL_CONTEXT_ERROR,
819 GST_GL_CONTEXT_ERROR_WRONG_CONFIG,
820 "Could not find any FBConfig's to use (check attributes?)");
821 goto failure;
822 }
823
824 GST_DEBUG_OBJECT (context_glx, "Chosen GLXFBConfig:");
825 gst_gl_context_glx_dump_fb_config (context_glx, device,
826 context_glx->priv->fbconfigs[0]);
827
828 window_x11->visual_info = glXGetVisualFromFBConfig (device,
829 context_glx->priv->fbconfigs[0]);
830
831 if (!window_x11->visual_info) {
832 g_set_error (error, GST_GL_CONTEXT_ERROR,
833 GST_GL_CONTEXT_ERROR_WRONG_CONFIG, "Bad attributes in FBConfig");
834 goto failure;
835 }
836 }
837
838 gst_gl_window_x11_create_window ((GstGLWindowX11 *) window);
839
840 gst_object_unref (window);
841
842 return TRUE;
843
844 failure:
845 if (window)
846 gst_object_unref (window);
847
848 return FALSE;
849 }
850
851 static void
gst_gl_context_glx_swap_buffers(GstGLContext * context)852 gst_gl_context_glx_swap_buffers (GstGLContext * context)
853 {
854 GstGLWindow *window = gst_gl_context_get_window (context);
855 Display *device = (Display *) gst_gl_display_get_handle (window->display);
856 Window window_handle = (Window) gst_gl_window_get_window_handle (window);
857
858 glXSwapBuffers (device, window_handle);
859
860 gst_object_unref (window);
861 }
862
863 static guintptr
gst_gl_context_glx_get_gl_context(GstGLContext * context)864 gst_gl_context_glx_get_gl_context (GstGLContext * context)
865 {
866 return (guintptr) GST_GL_CONTEXT_GLX (context)->glx_context;
867 }
868
869 static gboolean
gst_gl_context_glx_activate(GstGLContext * context,gboolean activate)870 gst_gl_context_glx_activate (GstGLContext * context, gboolean activate)
871 {
872 GstGLWindow *window = gst_gl_context_get_window (context);
873 Display *device = (Display *) gst_gl_display_get_handle (window->display);
874 Window window_handle = (Window) gst_gl_window_get_window_handle (window);
875 gboolean result;
876
877 if (activate) {
878 result = glXMakeCurrent (device, window_handle,
879 GST_GL_CONTEXT_GLX (context)->glx_context);
880 } else {
881 result = glXMakeCurrent (device, None, NULL);
882 }
883
884 gst_object_unref (window);
885
886 return result;
887 }
888
889 GstGLAPI
gst_gl_context_glx_get_gl_api(GstGLContext * context)890 gst_gl_context_glx_get_gl_api (GstGLContext * context)
891 {
892 GstGLContextGLX *context_glx;
893
894 context_glx = GST_GL_CONTEXT_GLX (context);
895
896 return context_glx->priv->context_api;
897 }
898
899 static GstGLPlatform
gst_gl_context_glx_get_gl_platform(GstGLContext * context)900 gst_gl_context_glx_get_gl_platform (GstGLContext * context)
901 {
902 return GST_GL_PLATFORM_GLX;
903 }
904
905 gpointer
gst_gl_context_glx_get_proc_address(GstGLAPI gl_api,const gchar * name)906 gst_gl_context_glx_get_proc_address (GstGLAPI gl_api, const gchar * name)
907 {
908 gpointer result;
909
910 if (!(result = gst_gl_context_default_get_proc_address (gl_api, name))) {
911 result = glXGetProcAddressARB ((const GLubyte *) name);
912 }
913
914 return result;
915 }
916
917 guintptr
gst_gl_context_glx_get_current_context(void)918 gst_gl_context_glx_get_current_context (void)
919 {
920 return (guintptr) glXGetCurrentContext ();
921 }
922
923 static void
gst_gl_context_glx_get_gl_platform_version(GstGLContext * context,gint * major,gint * minor)924 gst_gl_context_glx_get_gl_platform_version (GstGLContext * context,
925 gint * major, gint * minor)
926 {
927 GstGLContextGLX *context_glx = GST_GL_CONTEXT_GLX (context);
928
929 *major = context_glx->priv->glx_major;
930 *minor = context_glx->priv->glx_minor;
931 }
932
933 static GstStructure *
gst_gl_context_glx_get_config(GstGLContext * context)934 gst_gl_context_glx_get_config (GstGLContext * context)
935 {
936 GstGLContextGLX *glx = GST_GL_CONTEXT_GLX (context);
937 GstGLWindow *window;
938 GstGLWindowX11 *window_x11;
939 Display *device;
940 GstStructure *ret;
941
942 window = gst_gl_context_get_window (context);
943 device = (Display *) gst_gl_display_get_handle (window->display);
944 window_x11 = GST_GL_WINDOW_X11 (window);
945
946 g_return_val_if_fail (glx->priv->fbconfigs || window_x11->visual_info, NULL);
947
948 if (glx->priv->fbconfigs) {
949 ret = fb_config_to_structure (context, device, glx->priv->fbconfigs[0]);
950 } else {
951 /*TODO: XVisualInfo for really old GLX/X11 versions, */
952 ret = NULL;
953 }
954 gst_object_unref (window);
955 return ret;
956 }
957
958 static gboolean
gst_gl_context_glx_request_config(GstGLContext * context,GstStructure * config)959 gst_gl_context_glx_request_config (GstGLContext * context,
960 GstStructure * config)
961 {
962 GstGLContextGLX *glx = GST_GL_CONTEXT_GLX (context);
963
964 if (glx->priv->requested_config)
965 gst_structure_free (glx->priv->requested_config);
966 glx->priv->requested_config = config;
967
968 return TRUE;
969 }
970
971 gboolean
gst_gl_context_glx_fill_info(GstGLContext * context,GError ** error)972 gst_gl_context_glx_fill_info (GstGLContext * context, GError ** error)
973 {
974 GLXContext glx_context = (GLXContext) gst_gl_context_get_gl_context (context);
975 GstStructure *config;
976 Display *device;
977 GLXFBConfig *fbconfigs;
978 int fbconfig_id, n_fbconfigs;
979 int glx_major, glx_minor;
980 int attrs[3];
981
982 if (!glx_context) {
983 g_set_error (error, GST_GL_CONTEXT_ERROR,
984 GST_GL_CONTEXT_ERROR_RESOURCE_UNAVAILABLE, "No GLX context");
985 return FALSE;
986 }
987
988 device = (Display *) gst_gl_display_get_handle (context->display);
989
990 if (!glXQueryVersion (device, &glx_major, &glx_minor)) {
991 GST_WARNING_OBJECT (context, "could not retrieve GLX version");
992 g_set_error (error, GST_GL_CONTEXT_ERROR,
993 GST_GL_CONTEXT_ERROR_RESOURCE_UNAVAILABLE,
994 "could not retrieve GLX version");
995 return FALSE;
996 }
997
998 if (!GST_GL_CHECK_GL_VERSION (glx_major, glx_minor, 1, 4)) {
999 GST_FIXME_OBJECT (context, "No support for retrieving the "
1000 "GstGLContextConfig from GLX < 1.4, have %u.%u", glx_major, glx_minor);
1001 return TRUE;
1002 }
1003
1004 if (Success != glXQueryContext (device, glx_context, GLX_FBCONFIG_ID,
1005 &fbconfig_id)) {
1006 GST_WARNING_OBJECT (context,
1007 "could not retrieve fbconfig id from glx context");
1008 g_set_error (error, GST_GL_CONTEXT_ERROR,
1009 GST_GL_CONTEXT_ERROR_WRONG_CONFIG,
1010 "could not retrieve fbconfig id from glx context");
1011 goto failure;
1012 }
1013
1014 attrs[0] = GLX_FBCONFIG_ID;
1015 attrs[1] = fbconfig_id;
1016 attrs[2] = None;
1017
1018 fbconfigs = glXChooseFBConfig (device, DefaultScreen (device), attrs,
1019 &n_fbconfigs);
1020 if (!fbconfigs || n_fbconfigs <= 0) {
1021 GST_WARNING_OBJECT (context,
1022 "could not retrieve fbconfig from its ID 0x%x. "
1023 "Wrong Display or Screen?", fbconfig_id);
1024 g_set_error (error, GST_GL_CONTEXT_ERROR,
1025 GST_GL_CONTEXT_ERROR_WRONG_CONFIG,
1026 "could not retrieve fbconfig from its ID 0x%x. "
1027 "Wrong Display or Screen?", fbconfig_id);
1028 goto failure;
1029 }
1030
1031 config = fb_config_to_structure (context, device, fbconfigs[0]);
1032 if (!config) {
1033 GST_WARNING_OBJECT (context, "could not transform fbconfig id 0x%x into "
1034 "GstStructure.", fbconfig_id);
1035 g_set_error (error, GST_GL_CONTEXT_ERROR,
1036 GST_GL_CONTEXT_ERROR_WRONG_CONFIG,
1037 "could not transform fbconfig id 0x%x into GstStructure.", fbconfig_id);
1038 goto failure;
1039 }
1040
1041 GST_INFO_OBJECT (context, "found config %" GST_PTR_FORMAT, config);
1042
1043 g_object_set_data_full (G_OBJECT (context),
1044 GST_GL_CONTEXT_WRAPPED_GL_CONFIG_NAME, config,
1045 (GDestroyNotify) gst_structure_free);
1046
1047 return TRUE;
1048
1049 failure:
1050 return FALSE;
1051 }
1052