• 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 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 
26 #include <gst/gst.h>
27 #include <gmodule.h>
28 
29 #include <gst/gl/gl.h>
30 #include <gst/gl/gstglfuncs.h>
31 
32 #include "gstglcontext_wgl.h"
33 #include <GL/wglext.h>
34 
35 #include "../utils/opengl_versions.h"
36 #include "../gstglcontext_private.h"
37 
38 struct _GstGLContextWGLPrivate
39 {
40   PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
41   PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB;
42 
43   GstGLAPI context_api;
44   const gchar *wgl_exts;
45 };
46 
47 #define GST_CAT_DEFAULT gst_gl_context_debug
48 
49 #define gst_gl_context_wgl_parent_class parent_class
50 G_DEFINE_TYPE_WITH_PRIVATE (GstGLContextWGL, gst_gl_context_wgl,
51     GST_TYPE_GL_CONTEXT);
52 
53 static guintptr gst_gl_context_wgl_get_gl_context (GstGLContext * context);
54 static void gst_gl_context_wgl_swap_buffers (GstGLContext * context);
55 static gboolean gst_gl_context_wgl_choose_format (GstGLContext * context,
56     GError ** error);
57 static gboolean gst_gl_context_wgl_activate (GstGLContext * context,
58     gboolean activate);
59 static gboolean gst_gl_context_wgl_create_context (GstGLContext * context,
60     GstGLAPI gl_api, GstGLContext * other_context, GError ** error);
61 static void gst_gl_context_wgl_destroy_context (GstGLContext * context);
62 GstGLAPI gst_gl_context_wgl_get_gl_api (GstGLContext * context);
63 static GstGLPlatform gst_gl_context_wgl_get_gl_platform (GstGLContext *
64     context);
65 static gboolean gst_gl_context_wgl_check_feature (GstGLContext * context,
66     const gchar * feature);
67 GstStructure *gst_gl_context_wgl_get_config (GstGLContext * context);
68 
69 static void
gst_gl_context_wgl_class_init(GstGLContextWGLClass * klass)70 gst_gl_context_wgl_class_init (GstGLContextWGLClass * klass)
71 {
72   GstGLContextClass *context_class = (GstGLContextClass *) klass;
73 
74   context_class->get_gl_context =
75       GST_DEBUG_FUNCPTR (gst_gl_context_wgl_get_gl_context);
76   context_class->choose_format =
77       GST_DEBUG_FUNCPTR (gst_gl_context_wgl_choose_format);
78   context_class->activate = GST_DEBUG_FUNCPTR (gst_gl_context_wgl_activate);
79   context_class->create_context =
80       GST_DEBUG_FUNCPTR (gst_gl_context_wgl_create_context);
81   context_class->destroy_context =
82       GST_DEBUG_FUNCPTR (gst_gl_context_wgl_destroy_context);
83   context_class->swap_buffers =
84       GST_DEBUG_FUNCPTR (gst_gl_context_wgl_swap_buffers);
85 
86   context_class->get_proc_address =
87       GST_DEBUG_FUNCPTR (gst_gl_context_wgl_get_proc_address);
88   context_class->get_gl_api = GST_DEBUG_FUNCPTR (gst_gl_context_wgl_get_gl_api);
89   context_class->get_gl_platform =
90       GST_DEBUG_FUNCPTR (gst_gl_context_wgl_get_gl_platform);
91   context_class->check_feature =
92       GST_DEBUG_FUNCPTR (gst_gl_context_wgl_check_feature);
93   context_class->get_config = GST_DEBUG_FUNCPTR (gst_gl_context_wgl_get_config);
94 }
95 
96 static void
gst_gl_context_wgl_init(GstGLContextWGL * context_wgl)97 gst_gl_context_wgl_init (GstGLContextWGL * context_wgl)
98 {
99   context_wgl->priv = gst_gl_context_wgl_get_instance_private (context_wgl);
100 
101   context_wgl->priv->context_api = GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
102 }
103 
104 /* Must be called in the gl thread */
105 GstGLContextWGL *
gst_gl_context_wgl_new(GstGLDisplay * display)106 gst_gl_context_wgl_new (GstGLDisplay * display)
107 {
108   GstGLContextWGL *context;
109 
110   if ((gst_gl_display_get_handle_type (display) & GST_GL_DISPLAY_TYPE_WIN32) ==
111       0)
112     /* we require an win32 display handle to create WGL contexts */
113     return NULL;
114 
115   context = g_object_new (GST_TYPE_GL_CONTEXT_WGL, NULL);
116   gst_object_ref_sink (context);
117 
118   return context;
119 }
120 
121 static HGLRC
_create_context_with_flags(GstGLContextWGL * context_wgl,HDC dpy,HGLRC share_context,gint major,gint minor,gint contextFlags,gint profileMask)122 _create_context_with_flags (GstGLContextWGL * context_wgl, HDC dpy,
123     HGLRC share_context, gint major, gint minor, gint contextFlags,
124     gint profileMask)
125 {
126   HGLRC ret;
127 #define N_ATTRIBS 20
128   gint attribs[N_ATTRIBS];
129   gint n = 0;
130 
131   if (major) {
132     attribs[n++] = WGL_CONTEXT_MAJOR_VERSION_ARB;
133     attribs[n++] = major;
134   }
135   if (minor) {
136     attribs[n++] = WGL_CONTEXT_MINOR_VERSION_ARB;
137     attribs[n++] = minor;
138   }
139   if (contextFlags) {
140     attribs[n++] = WGL_CONTEXT_FLAGS_ARB;
141     attribs[n++] = contextFlags;
142   }
143   if (profileMask) {
144     attribs[n++] = WGL_CONTEXT_PROFILE_MASK_ARB;
145     attribs[n++] = profileMask;
146   }
147   attribs[n++] = 0;
148 
149   g_assert (n < N_ATTRIBS);
150 #undef N_ATTRIBS
151 
152   ret =
153       context_wgl->priv->wglCreateContextAttribsARB (dpy, share_context,
154       attribs);
155 
156   return ret;
157 }
158 
159 static gboolean
gst_gl_context_wgl_create_context(GstGLContext * context,GstGLAPI gl_api,GstGLContext * other_context,GError ** error)160 gst_gl_context_wgl_create_context (GstGLContext * context,
161     GstGLAPI gl_api, GstGLContext * other_context, GError ** error)
162 {
163   GstGLWindow *window;
164   GstGLContextWGL *context_wgl;
165   HGLRC external_gl_context = NULL;
166   HGLRC trampoline;
167   HDC device;
168 
169   context_wgl = GST_GL_CONTEXT_WGL (context);
170   window = gst_gl_context_get_window (context);
171   device = (HDC) gst_gl_window_get_display (window);
172 
173   if (other_context) {
174     if (gst_gl_context_get_gl_platform (other_context) != GST_GL_PLATFORM_WGL) {
175       g_set_error (error, GST_GL_CONTEXT_ERROR,
176           GST_GL_CONTEXT_ERROR_WRONG_CONFIG,
177           "Cannot share context with a non-WGL context");
178       goto failure;
179     }
180     external_gl_context = (HGLRC) gst_gl_context_get_gl_context (other_context);
181   }
182 
183   trampoline = wglCreateContext (device);
184   if (trampoline)
185     GST_DEBUG ("gl context created: %" G_GUINTPTR_FORMAT,
186         (guintptr) trampoline);
187   else {
188     g_set_error (error, GST_GL_CONTEXT_ERROR,
189         GST_GL_CONTEXT_ERROR_CREATE_CONTEXT, "failed to create glcontext:0x%x",
190         (unsigned int) GetLastError ());
191     goto failure;
192   }
193   g_assert (trampoline);
194 
195   /* get extension functions */
196   wglMakeCurrent (device, trampoline);
197 
198   context_wgl->priv->wglCreateContextAttribsARB =
199       (PFNWGLCREATECONTEXTATTRIBSARBPROC)
200       wglGetProcAddress ("wglCreateContextAttribsARB");
201   context_wgl->priv->wglGetExtensionsStringARB =
202       (PFNWGLGETEXTENSIONSSTRINGARBPROC)
203       wglGetProcAddress ("wglGetExtensionsStringARB");
204 
205   wglMakeCurrent (device, 0);
206   wglDeleteContext (trampoline);
207   trampoline = NULL;
208 
209   if (context_wgl->priv->wglGetExtensionsStringARB) {
210     context_wgl->priv->wgl_exts =
211         context_wgl->priv->wglGetExtensionsStringARB (device);
212 
213     GST_DEBUG_OBJECT (context, "Available WGL extensions %s",
214         GST_STR_NULL (context_wgl->priv->wgl_exts));
215   }
216 
217   if (context_wgl->priv->wglCreateContextAttribsARB != NULL
218       && gl_api & GST_GL_API_OPENGL3) {
219     gint i;
220 
221     for (i = 0; i < G_N_ELEMENTS (opengl_versions); i++) {
222       gint profileMask = 0;
223       gint contextFlags = 0;
224 
225       if ((opengl_versions[i].major > 3
226               || (opengl_versions[i].major == 3
227                   && opengl_versions[i].minor >= 2))) {
228         profileMask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
229         contextFlags |= WGL_CONTEXT_DEBUG_BIT_ARB;
230       } else {
231         break;
232       }
233 
234       GST_DEBUG_OBJECT (context, "trying to create a GL %d.%d context",
235           opengl_versions[i].major, opengl_versions[i].minor);
236 
237       context_wgl->wgl_context = _create_context_with_flags (context_wgl,
238           device, external_gl_context, opengl_versions[i].major,
239           opengl_versions[i].minor, contextFlags, profileMask);
240 
241       if (context_wgl->wgl_context) {
242         context_wgl->priv->context_api = GST_GL_API_OPENGL3;
243         break;
244       }
245     }
246   }
247 
248   if (!context_wgl->wgl_context) {
249 
250     if (context_wgl->priv->wglCreateContextAttribsARB && external_gl_context) {
251       context_wgl->wgl_context =
252           context_wgl->priv->wglCreateContextAttribsARB (device,
253           external_gl_context, 0);
254     }
255 
256 
257     if (!context_wgl->wgl_context) {
258 
259       context_wgl->wgl_context = wglCreateContext (device);
260 
261       if (!context_wgl->wgl_context) {
262         g_set_error (error, GST_GL_CONTEXT_ERROR,
263             GST_GL_CONTEXT_ERROR_CREATE_CONTEXT,
264             "Failed to create WGL context 0x%x",
265             (unsigned int) GetLastError ());
266         goto failure;
267       }
268 
269       if (external_gl_context) {
270         if (!wglShareLists (external_gl_context, context_wgl->wgl_context)) {
271           g_set_error (error, GST_GL_CONTEXT_ERROR,
272               GST_GL_CONTEXT_ERROR_CREATE_CONTEXT,
273               "failed to share contexts through wglShareLists 0x%x",
274               (unsigned int) GetLastError ());
275           goto failure;
276         }
277       }
278     }
279 
280     context_wgl->priv->context_api = GST_GL_API_OPENGL;
281   }
282 
283   GST_LOG ("gl context id: %" G_GUINTPTR_FORMAT,
284       (guintptr) context_wgl->wgl_context);
285 
286   gst_object_unref (window);
287 
288   return TRUE;
289 
290 failure:
291   gst_object_unref (window);
292 
293   return FALSE;
294 }
295 
296 static void
gst_gl_context_wgl_destroy_context(GstGLContext * context)297 gst_gl_context_wgl_destroy_context (GstGLContext * context)
298 {
299   GstGLContextWGL *context_wgl;
300 
301   context_wgl = GST_GL_CONTEXT_WGL (context);
302 
303   if (context_wgl->wgl_context)
304     wglDeleteContext (context_wgl->wgl_context);
305   context_wgl->wgl_context = NULL;
306 }
307 
308 static GstGLConfigSurfaceType
pfd_flags_to_surface_type(int flags)309 pfd_flags_to_surface_type (int flags)
310 {
311   GstGLConfigSurfaceType ret = GST_GL_CONFIG_SURFACE_TYPE_NONE;
312 
313   if (flags & PFD_DRAW_TO_WINDOW)
314     ret |= GST_GL_CONFIG_SURFACE_TYPE_WINDOW;
315   if (flags & PFD_DRAW_TO_BITMAP)
316     ret |= GST_GL_CONFIG_SURFACE_TYPE_PIXMAP;
317 
318   return ret;
319 }
320 
321 static GstStructure *
pixel_format_to_structure(HDC hdc,int pixfmt)322 pixel_format_to_structure (HDC hdc, int pixfmt)
323 {
324   GstStructure *ret;
325   PIXELFORMATDESCRIPTOR pfd;
326 
327   if (pixfmt == 0)
328     return NULL;
329 
330   if (DescribePixelFormat (hdc, pixfmt, sizeof (pfd), &pfd) == 0)
331     return NULL;
332 
333   ret = gst_structure_new (GST_GL_CONFIG_STRUCTURE_NAME,
334       GST_GL_CONFIG_STRUCTURE_SET_ARGS (PLATFORM, GstGLPlatform,
335           GST_GL_PLATFORM_WGL), GST_GL_CONFIG_STRUCTURE_SET_ARGS (RED_SIZE, int,
336           pfd.cRedBits), GST_GL_CONFIG_STRUCTURE_SET_ARGS (BLUE_SIZE, int,
337           pfd.cBlueBits), GST_GL_CONFIG_STRUCTURE_SET_ARGS (GREEN_SIZE, int,
338           pfd.cGreenBits), GST_GL_CONFIG_STRUCTURE_SET_ARGS (ALPHA_SIZE, int,
339           pfd.cAlphaBits), GST_GL_CONFIG_STRUCTURE_SET_ARGS (DEPTH_SIZE, int,
340           pfd.cDepthBits), GST_GL_CONFIG_STRUCTURE_SET_ARGS (STENCIL_SIZE, int,
341           pfd.cStencilBits), GST_GL_CONFIG_STRUCTURE_SET_ARGS (NATIVE_VISUAL_ID,
342           guint, pixfmt), GST_GL_CONFIG_STRUCTURE_SET_ARGS (SURFACE_TYPE,
343           GstGLConfigSurfaceType, pfd_flags_to_surface_type (pfd.dwFlags)),
344       NULL);
345 
346   return ret;
347 }
348 
349 static gboolean
gst_gl_context_wgl_choose_format(GstGLContext * context,GError ** error)350 gst_gl_context_wgl_choose_format (GstGLContext * context, GError ** error)
351 {
352   GstGLWindow *window;
353   PIXELFORMATDESCRIPTOR pfd;
354   gint pixelformat = 0;
355   gboolean res = FALSE;
356   HDC device;
357   GstStructure *config;
358 
359   window = gst_gl_context_get_window (context);
360   gst_gl_window_win32_create_window (GST_GL_WINDOW_WIN32 (window), error);
361   device = (HDC) gst_gl_window_get_display (window);
362   gst_object_unref (window);
363 
364   pfd.nSize = sizeof (PIXELFORMATDESCRIPTOR);
365   pfd.nVersion = 1;
366   pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
367   pfd.iPixelType = PFD_TYPE_RGBA;
368   pfd.cColorBits = 24;
369   pfd.cRedBits = 8;
370   pfd.cRedShift = 0;
371   pfd.cGreenBits = 8;
372   pfd.cGreenShift = 0;
373   pfd.cBlueBits = 8;
374   pfd.cBlueShift = 0;
375   pfd.cAlphaBits = 0;
376   pfd.cAlphaShift = 0;
377   pfd.cAccumBits = 0;
378   pfd.cAccumRedBits = 0;
379   pfd.cAccumGreenBits = 0;
380   pfd.cAccumBlueBits = 0;
381   pfd.cAccumAlphaBits = 0;
382   pfd.cDepthBits = 24;
383   pfd.cStencilBits = 8;
384   pfd.cAuxBuffers = 0;
385   pfd.iLayerType = PFD_MAIN_PLANE;
386   pfd.bReserved = 0;
387   pfd.dwLayerMask = 0;
388   pfd.dwVisibleMask = 0;
389   pfd.dwDamageMask = 0;
390 
391   pfd.cColorBits = (BYTE) GetDeviceCaps (device, BITSPIXEL);
392 
393   pixelformat = ChoosePixelFormat (device, &pfd);
394 
395   if (!pixelformat) {
396     g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED,
397         "Failed to choose a pixel format");
398     return FALSE;
399   }
400 
401   config = pixel_format_to_structure (device, pixelformat);
402   GST_INFO_OBJECT (context, "chosen config %" GST_PTR_FORMAT, config);
403   gst_structure_free (config);
404 
405   res = SetPixelFormat (device, pixelformat, &pfd);
406 
407   return res;
408 }
409 
410 static void
gst_gl_context_wgl_swap_buffers(GstGLContext * context)411 gst_gl_context_wgl_swap_buffers (GstGLContext * context)
412 {
413   GstGLWindow *window = gst_gl_context_get_window (context);
414   HDC device = (HDC) gst_gl_window_get_display (window);
415 
416   SwapBuffers (device);
417 
418   gst_object_unref (window);
419 }
420 
421 static guintptr
gst_gl_context_wgl_get_gl_context(GstGLContext * context)422 gst_gl_context_wgl_get_gl_context (GstGLContext * context)
423 {
424   return (guintptr) GST_GL_CONTEXT_WGL (context)->wgl_context;
425 }
426 
427 static gboolean
gst_gl_context_wgl_activate(GstGLContext * context,gboolean activate)428 gst_gl_context_wgl_activate (GstGLContext * context, gboolean activate)
429 {
430   GstGLWindow *window;
431   GstGLContextWGL *context_wgl;
432   HDC device;
433   gboolean result;
434 
435   window = gst_gl_context_get_window (context);
436   context_wgl = GST_GL_CONTEXT_WGL (context);
437   device = (HDC) gst_gl_window_get_display (window);
438 
439   if (activate) {
440     result = wglMakeCurrent (device, context_wgl->wgl_context);
441   } else {
442     result = wglMakeCurrent (NULL, NULL);
443   }
444 
445   gst_object_unref (window);
446 
447   return result;
448 }
449 
450 GstGLAPI
gst_gl_context_wgl_get_gl_api(GstGLContext * context)451 gst_gl_context_wgl_get_gl_api (GstGLContext * context)
452 {
453   GstGLContextWGL *context_wgl = GST_GL_CONTEXT_WGL (context);
454 
455   return context_wgl->priv->context_api;
456 }
457 
458 static GstGLPlatform
gst_gl_context_wgl_get_gl_platform(GstGLContext * context)459 gst_gl_context_wgl_get_gl_platform (GstGLContext * context)
460 {
461   return GST_GL_PLATFORM_WGL;
462 }
463 
464 static gboolean
gst_gl_context_wgl_check_feature(GstGLContext * context,const gchar * feature)465 gst_gl_context_wgl_check_feature (GstGLContext * context, const gchar * feature)
466 {
467   GstGLContextWGL *context_wgl = GST_GL_CONTEXT_WGL (context);
468 
469   return gst_gl_check_extension (feature, context_wgl->priv->wgl_exts);
470 }
471 
472 static GOnce module_opengl_dll_gonce = G_ONCE_INIT;
473 static GModule *module_opengl_dll;
474 
475 static gpointer
load_opengl_dll_module(gpointer user_data)476 load_opengl_dll_module (gpointer user_data)
477 {
478 #ifdef GST_GL_LIBGL_MODULE_NAME
479   module_opengl_dll =
480       g_module_open (GST_GL_LIBGL_MODULE_NAME, G_MODULE_BIND_LAZY);
481 #else
482   if (g_strcmp0 (G_MODULE_SUFFIX, "dll") == 0)
483     module_opengl_dll = g_module_open ("opengl32.dll", G_MODULE_BIND_LAZY);
484 
485   /* This automatically handles the suffix and even .la files */
486   if (!module_opengl_dll)
487     module_opengl_dll = g_module_open ("opengl32", G_MODULE_BIND_LAZY);
488 #endif
489 
490   return NULL;
491 }
492 
493 gpointer
gst_gl_context_wgl_get_proc_address(GstGLAPI gl_api,const gchar * name)494 gst_gl_context_wgl_get_proc_address (GstGLAPI gl_api, const gchar * name)
495 {
496   gpointer result = NULL;
497 
498   if (gl_api & (GST_GL_API_OPENGL | GST_GL_API_OPENGL3)) {
499     g_once (&module_opengl_dll_gonce, load_opengl_dll_module, NULL);
500     if (module_opengl_dll)
501       g_module_symbol (module_opengl_dll, name, &result);
502 
503     if (!result) {
504       result = wglGetProcAddress ((LPCSTR) name);
505     }
506   }
507   if (!result)
508     result = gst_gl_context_default_get_proc_address (gl_api, name);
509 
510   return result;
511 }
512 
513 guintptr
gst_gl_context_wgl_get_current_context(void)514 gst_gl_context_wgl_get_current_context (void)
515 {
516   return (guintptr) wglGetCurrentContext ();
517 }
518 
519 GstStructure *
gst_gl_context_wgl_get_config(GstGLContext * context)520 gst_gl_context_wgl_get_config (GstGLContext * context)
521 {
522   GstGLWindow *window;
523   int pixfmt;
524   HDC hdc;
525 
526   window = gst_gl_context_get_window (context);
527   hdc = (HDC) gst_gl_window_get_display (window);
528 
529   pixfmt = GetPixelFormat (hdc);
530 
531   return pixel_format_to_structure (hdc, pixfmt);
532 }
533