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
59 struct _GstGLContextGLXPrivate
60 {
61 int glx_major;
62 int glx_minor;
63
64 GstGLAPI context_api;
65
66 GLXFBConfig *fbconfigs;
67 GLXContext (*glXCreateContextAttribsARB) (Display *, GLXFBConfig,
68 GLXContext, Bool, const int *);
69 };
70
71 #define gst_gl_context_glx_parent_class parent_class
72 G_DEFINE_TYPE_WITH_PRIVATE (GstGLContextGLX, gst_gl_context_glx,
73 GST_TYPE_GL_CONTEXT);
74
75 static void
gst_gl_context_glx_class_init(GstGLContextGLXClass * klass)76 gst_gl_context_glx_class_init (GstGLContextGLXClass * klass)
77 {
78 GstGLContextClass *context_class = (GstGLContextClass *) klass;
79
80 context_class->get_gl_context =
81 GST_DEBUG_FUNCPTR (gst_gl_context_glx_get_gl_context);
82 context_class->activate = GST_DEBUG_FUNCPTR (gst_gl_context_glx_activate);
83 context_class->create_context =
84 GST_DEBUG_FUNCPTR (gst_gl_context_glx_create_context);
85 context_class->destroy_context =
86 GST_DEBUG_FUNCPTR (gst_gl_context_glx_destroy_context);
87 context_class->choose_format =
88 GST_DEBUG_FUNCPTR (gst_gl_context_glx_choose_format);
89 context_class->swap_buffers =
90 GST_DEBUG_FUNCPTR (gst_gl_context_glx_swap_buffers);
91
92 context_class->get_gl_api = GST_DEBUG_FUNCPTR (gst_gl_context_glx_get_gl_api);
93 context_class->get_gl_platform =
94 GST_DEBUG_FUNCPTR (gst_gl_context_glx_get_gl_platform);
95 context_class->get_proc_address =
96 GST_DEBUG_FUNCPTR (gst_gl_context_glx_get_proc_address);
97 context_class->get_current_context =
98 GST_DEBUG_FUNCPTR (gst_gl_context_glx_get_current_context);
99 context_class->get_gl_platform_version =
100 GST_DEBUG_FUNCPTR (gst_gl_context_glx_get_gl_platform_version);
101 }
102
103 static void
gst_gl_context_glx_init(GstGLContextGLX * context)104 gst_gl_context_glx_init (GstGLContextGLX * context)
105 {
106 context->priv = gst_gl_context_glx_get_instance_private (context);
107 }
108
109 GstGLContextGLX *
gst_gl_context_glx_new(GstGLDisplay * display)110 gst_gl_context_glx_new (GstGLDisplay * display)
111 {
112 GstGLContextGLX *context;
113
114 if ((gst_gl_display_get_handle_type (display) & GST_GL_DISPLAY_TYPE_X11) == 0)
115 /* we require an x11 display handle to create GLX contexts */
116 return NULL;
117
118 context = g_object_new (GST_TYPE_GL_CONTEXT_GLX, NULL);
119 gst_object_ref_sink (context);
120
121 return context;
122 }
123
124 static inline void
_describe_fbconfig(Display * display,GLXFBConfig config)125 _describe_fbconfig (Display * display, GLXFBConfig config)
126 {
127 int val;
128
129 glXGetFBConfigAttrib (display, config, GLX_FBCONFIG_ID, &val);
130 GST_DEBUG ("ID: %d", val);
131 glXGetFBConfigAttrib (display, config, GLX_DOUBLEBUFFER, &val);
132 GST_DEBUG ("double buffering: %d", val);
133 glXGetFBConfigAttrib (display, config, GLX_RED_SIZE, &val);
134 GST_DEBUG ("red: %d", val);
135 glXGetFBConfigAttrib (display, config, GLX_GREEN_SIZE, &val);
136 GST_DEBUG ("green: %d", val);
137 glXGetFBConfigAttrib (display, config, GLX_BLUE_SIZE, &val);
138 GST_DEBUG ("blue: %d", val);
139 glXGetFBConfigAttrib (display, config, GLX_ALPHA_SIZE, &val);
140 GST_DEBUG ("alpha: %d", val);
141 glXGetFBConfigAttrib (display, config, GLX_DEPTH_SIZE, &val);
142 GST_DEBUG ("depth: %d", val);
143 glXGetFBConfigAttrib (display, config, GLX_STENCIL_SIZE, &val);
144 GST_DEBUG ("stencil: %d", val);
145 }
146
147 static GLXContext
_create_context_with_flags(GstGLContextGLX * context_glx,Display * dpy,GLXFBConfig fbconfig,GLXContext share_context,gint major,gint minor,gint contextFlags,gint profileMask)148 _create_context_with_flags (GstGLContextGLX * context_glx, Display * dpy,
149 GLXFBConfig fbconfig, GLXContext share_context, gint major, gint minor,
150 gint contextFlags, gint profileMask)
151 {
152 GLXContext ret;
153 #define N_ATTRIBS 20
154 gint attribs[N_ATTRIBS];
155 int x_error = 0;
156 gint n = 0;
157
158 if (major) {
159 attribs[n++] = GLX_CONTEXT_MAJOR_VERSION_ARB;
160 attribs[n++] = major;
161 }
162 if (minor) {
163 attribs[n++] = GLX_CONTEXT_MINOR_VERSION_ARB;
164 attribs[n++] = minor;
165 }
166 if (contextFlags) {
167 attribs[n++] = GLX_CONTEXT_FLAGS_ARB;
168 attribs[n++] = contextFlags;
169 }
170 #ifdef GLX_ARB_create_context_profile
171 if (profileMask) {
172 attribs[n++] = GLX_CONTEXT_PROFILE_MASK_ARB;
173 attribs[n++] = profileMask;
174 }
175 #endif
176 attribs[n++] = None;
177
178 g_assert (n < N_ATTRIBS);
179 #undef N_ATTRIBS
180
181 gst_gl_window_x11_trap_x_errors ();
182 ret = context_glx->priv->glXCreateContextAttribsARB (dpy, fbconfig,
183 share_context, True, attribs);
184 x_error = gst_gl_window_x11_untrap_x_errors ();
185
186 if (x_error)
187 ret = 0;
188
189 return ret;
190 }
191
192 static gboolean
gst_gl_context_glx_create_context(GstGLContext * context,GstGLAPI gl_api,GstGLContext * other_context,GError ** error)193 gst_gl_context_glx_create_context (GstGLContext * context,
194 GstGLAPI gl_api, GstGLContext * other_context, GError ** error)
195 {
196 GstGLContextGLX *context_glx;
197 GstGLWindow *window;
198 GstGLWindowX11 *window_x11;
199 GstGLDisplay *display = NULL;
200 gboolean create_context;
201 const char *glx_exts;
202 Display *device;
203 guintptr external_gl_context = 0;
204
205 context_glx = GST_GL_CONTEXT_GLX (context);
206 window = gst_gl_context_get_window (context);
207
208 if (!GST_IS_GL_WINDOW_X11 (window)) {
209 g_set_error (error, GST_GL_CONTEXT_ERROR,
210 GST_GL_CONTEXT_ERROR_WRONG_CONFIG,
211 "Cannot create an GLX context from a non-X11 window");
212 goto failure;
213 }
214
215 window_x11 = GST_GL_WINDOW_X11 (window);
216 display = gst_gl_context_get_display (context);
217
218 if (other_context) {
219 if (gst_gl_context_get_gl_platform (other_context) != GST_GL_PLATFORM_GLX) {
220 g_set_error (error, GST_GL_CONTEXT_ERROR,
221 GST_GL_CONTEXT_ERROR_WRONG_CONFIG,
222 "Cannot share context with non-GLX context");
223 goto failure;
224 }
225
226 external_gl_context = gst_gl_context_get_gl_context (other_context);
227 }
228
229 device = (Display *) gst_gl_display_get_handle (display);
230 if (!device) {
231 g_set_error (error, GST_GL_CONTEXT_ERROR,
232 GST_GL_CONTEXT_ERROR_RESOURCE_UNAVAILABLE, "Invalid Display handle");
233 goto failure;
234 }
235
236 glx_exts = glXQueryExtensionsString (device, DefaultScreen (device));
237
238 create_context = gst_gl_check_extension ("GLX_ARB_create_context", glx_exts);
239 context_glx->priv->glXCreateContextAttribsARB =
240 (gpointer) glXGetProcAddressARB ((const GLubyte *)
241 "glXCreateContextAttribsARB");
242
243 if (!context_glx->glx_context && gl_api & GST_GL_API_OPENGL3 && create_context
244 && context_glx->priv->glXCreateContextAttribsARB) {
245 gint i;
246
247 for (i = 0; i < G_N_ELEMENTS (opengl_versions); i++) {
248 gint profileMask = 0;
249 gint contextFlags = 0;
250
251 if ((opengl_versions[i].major > 3
252 || (opengl_versions[i].major == 3
253 && opengl_versions[i].minor >= 2))) {
254 profileMask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
255 contextFlags |= GLX_CONTEXT_DEBUG_BIT_ARB;
256 } else {
257 break;
258 }
259
260 GST_DEBUG_OBJECT (context, "trying to create a GL %d.%d context",
261 opengl_versions[i].major, opengl_versions[i].minor);
262
263 context_glx->glx_context = _create_context_with_flags (context_glx,
264 device, context_glx->priv->fbconfigs[0],
265 (GLXContext) external_gl_context, opengl_versions[i].major,
266 opengl_versions[i].minor, contextFlags, profileMask);
267
268 if (context_glx->glx_context) {
269 context_glx->priv->context_api = GST_GL_API_OPENGL3;
270 break;
271 }
272 }
273 }
274 if (!context_glx->glx_context && gl_api & GST_GL_API_OPENGL) {
275 context_glx->glx_context =
276 glXCreateContext (device, window_x11->visual_info,
277 (GLXContext) external_gl_context, TRUE);
278 context_glx->priv->context_api = GST_GL_API_OPENGL;
279 }
280
281 if (context_glx->priv->fbconfigs)
282 XFree (context_glx->priv->fbconfigs);
283
284 if (!context_glx->glx_context) {
285 g_set_error (error, GST_GL_CONTEXT_ERROR,
286 GST_GL_CONTEXT_ERROR_CREATE_CONTEXT, "Failed to create opengl context");
287 goto failure;
288 }
289
290 GST_LOG ("gl context id: %ld", (gulong) context_glx->glx_context);
291
292 gst_object_unref (window);
293 gst_object_unref (display);
294
295 return TRUE;
296
297 failure:
298 if (window)
299 gst_object_unref (window);
300 if (display)
301 gst_object_unref (display);
302
303 return FALSE;
304 }
305
306 static void
gst_gl_context_glx_destroy_context(GstGLContext * context)307 gst_gl_context_glx_destroy_context (GstGLContext * context)
308 {
309 GstGLWindow *window;
310 GstGLContextGLX *context_glx;
311 Display *device;
312
313 context_glx = GST_GL_CONTEXT_GLX (context);
314 window = gst_gl_context_get_window (context);
315 device = (Display *) gst_gl_display_get_handle (window->display);
316
317 glXDestroyContext (device, context_glx->glx_context);
318
319 context_glx->glx_context = 0;
320
321 gst_object_unref (window);
322 }
323
324 static gboolean
gst_gl_context_glx_choose_format(GstGLContext * context,GError ** error)325 gst_gl_context_glx_choose_format (GstGLContext * context, GError ** error)
326 {
327 GstGLContextGLX *context_glx;
328 GstGLWindow *window;
329 GstGLWindowX11 *window_x11;
330 gint error_base;
331 gint event_base;
332 Display *device;
333
334 context_glx = GST_GL_CONTEXT_GLX (context);
335 window = gst_gl_context_get_window (context);
336
337 if (!GST_IS_GL_WINDOW_X11 (window)) {
338 g_set_error (error, GST_GL_CONTEXT_ERROR,
339 GST_GL_CONTEXT_ERROR_WRONG_CONFIG,
340 "Cannot create an GLX context from a non-X11 window");
341 goto failure;
342 }
343 window_x11 = GST_GL_WINDOW_X11 (window);
344
345 device = (Display *) gst_gl_display_get_handle (window->display);
346 if (!device) {
347 g_set_error (error, GST_GL_CONTEXT_ERROR,
348 GST_GL_CONTEXT_ERROR_RESOURCE_UNAVAILABLE, "Invalid Display handle");
349 goto failure;
350 }
351
352 if (!glXQueryExtension (device, &error_base, &event_base)) {
353 g_set_error (error, GST_GL_CONTEXT_ERROR,
354 GST_GL_CONTEXT_ERROR_RESOURCE_UNAVAILABLE, "No GLX extension");
355 goto failure;
356 }
357
358 if (!glXQueryVersion (device, &context_glx->priv->glx_major,
359 &context_glx->priv->glx_minor)) {
360 g_set_error (error, GST_GL_CONTEXT_ERROR,
361 GST_GL_CONTEXT_ERROR_CREATE_CONTEXT,
362 "Failed to query GLX version (glXQueryVersion failed)");
363 goto failure;
364 }
365
366 GST_INFO ("GLX Version: %d.%d", context_glx->priv->glx_major,
367 context_glx->priv->glx_minor);
368
369 /* legacy case */
370 if (context_glx->priv->glx_major < 1 || (context_glx->priv->glx_major == 1
371 && context_glx->priv->glx_minor < 3)) {
372 gint attribs[] = {
373 GLX_RGBA,
374 GLX_RED_SIZE, 1,
375 GLX_GREEN_SIZE, 1,
376 GLX_BLUE_SIZE, 1,
377 GLX_DEPTH_SIZE, 16,
378 GLX_DOUBLEBUFFER,
379 None
380 };
381
382 window_x11->visual_info = glXChooseVisual (device,
383 window_x11->screen_num, attribs);
384
385 if (!window_x11->visual_info) {
386 g_set_error (error, GST_GL_CONTEXT_ERROR,
387 GST_GL_CONTEXT_ERROR_WRONG_CONFIG,
388 "Bad attributes in glXChooseVisual");
389 goto failure;
390 }
391 } else {
392 gint attribs[] = {
393 GLX_RENDER_TYPE, GLX_RGBA_BIT,
394 GLX_RED_SIZE, 1,
395 GLX_GREEN_SIZE, 1,
396 GLX_BLUE_SIZE, 1,
397 GLX_DEPTH_SIZE, 16,
398 GLX_DOUBLEBUFFER, True,
399 None
400 };
401 int fbcount;
402
403 context_glx->priv->fbconfigs = glXChooseFBConfig (device,
404 DefaultScreen (device), attribs, &fbcount);
405
406 if (!context_glx->priv->fbconfigs) {
407 g_set_error (error, GST_GL_CONTEXT_ERROR,
408 GST_GL_CONTEXT_ERROR_WRONG_CONFIG,
409 "Could not find any FBConfig's to use (check attributes?)");
410 goto failure;
411 }
412
413 _describe_fbconfig (device, context_glx->priv->fbconfigs[0]);
414
415 window_x11->visual_info = glXGetVisualFromFBConfig (device,
416 context_glx->priv->fbconfigs[0]);
417
418 if (!window_x11->visual_info) {
419 g_set_error (error, GST_GL_CONTEXT_ERROR,
420 GST_GL_CONTEXT_ERROR_WRONG_CONFIG, "Bad attributes in FBConfig");
421 goto failure;
422 }
423 }
424
425 gst_gl_window_x11_create_window ((GstGLWindowX11 *) window);
426
427 gst_object_unref (window);
428
429 return TRUE;
430
431 failure:
432 if (window)
433 gst_object_unref (window);
434
435 return FALSE;
436 }
437
438 static void
gst_gl_context_glx_swap_buffers(GstGLContext * context)439 gst_gl_context_glx_swap_buffers (GstGLContext * context)
440 {
441 GstGLWindow *window = gst_gl_context_get_window (context);
442 Display *device = (Display *) gst_gl_display_get_handle (window->display);
443 Window window_handle = (Window) gst_gl_window_get_window_handle (window);
444
445 glXSwapBuffers (device, window_handle);
446
447 gst_object_unref (window);
448 }
449
450 static guintptr
gst_gl_context_glx_get_gl_context(GstGLContext * context)451 gst_gl_context_glx_get_gl_context (GstGLContext * context)
452 {
453 return (guintptr) GST_GL_CONTEXT_GLX (context)->glx_context;
454 }
455
456 static gboolean
gst_gl_context_glx_activate(GstGLContext * context,gboolean activate)457 gst_gl_context_glx_activate (GstGLContext * context, gboolean activate)
458 {
459 GstGLWindow *window = gst_gl_context_get_window (context);
460 Display *device = (Display *) gst_gl_display_get_handle (window->display);
461 Window window_handle = (Window) gst_gl_window_get_window_handle (window);
462 gboolean result;
463
464 if (activate) {
465 result = glXMakeCurrent (device, window_handle,
466 GST_GL_CONTEXT_GLX (context)->glx_context);
467 } else {
468 result = glXMakeCurrent (device, None, NULL);
469 }
470
471 gst_object_unref (window);
472
473 return result;
474 }
475
476 GstGLAPI
gst_gl_context_glx_get_gl_api(GstGLContext * context)477 gst_gl_context_glx_get_gl_api (GstGLContext * context)
478 {
479 GstGLContextGLX *context_glx;
480
481 context_glx = GST_GL_CONTEXT_GLX (context);
482
483 return context_glx->priv->context_api;
484 }
485
486 static GstGLPlatform
gst_gl_context_glx_get_gl_platform(GstGLContext * context)487 gst_gl_context_glx_get_gl_platform (GstGLContext * context)
488 {
489 return GST_GL_PLATFORM_GLX;
490 }
491
492 gpointer
gst_gl_context_glx_get_proc_address(GstGLAPI gl_api,const gchar * name)493 gst_gl_context_glx_get_proc_address (GstGLAPI gl_api, const gchar * name)
494 {
495 gpointer result;
496
497 if (!(result = gst_gl_context_default_get_proc_address (gl_api, name))) {
498 result = glXGetProcAddressARB ((const GLubyte *) name);
499 }
500
501 return result;
502 }
503
504 guintptr
gst_gl_context_glx_get_current_context(void)505 gst_gl_context_glx_get_current_context (void)
506 {
507 return (guintptr) glXGetCurrentContext ();
508 }
509
510 static void
gst_gl_context_glx_get_gl_platform_version(GstGLContext * context,gint * major,gint * minor)511 gst_gl_context_glx_get_gl_platform_version (GstGLContext * context,
512 gint * major, gint * minor)
513 {
514 GstGLContextGLX *context_glx = GST_GL_CONTEXT_GLX (context);
515
516 *major = context_glx->priv->glx_major;
517 *minor = context_glx->priv->glx_minor;
518 }
519