• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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