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