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
28 #include <gst/gl/gl.h>
29 #include <gst/gl/gstglfuncs.h>
30
31 #include "gstglcontext_wgl.h"
32 #include <GL/wglext.h>
33
34 #include "../utils/opengl_versions.h"
35 #include "../gstglcontext_private.h"
36
37 struct _GstGLContextWGLPrivate
38 {
39 PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
40
41 GstGLAPI context_api;
42 };
43
44 #define GST_CAT_DEFAULT gst_gl_context_debug
45
46 #define gst_gl_context_wgl_parent_class parent_class
47 G_DEFINE_TYPE_WITH_PRIVATE (GstGLContextWGL, gst_gl_context_wgl,
48 GST_TYPE_GL_CONTEXT);
49
50 static guintptr gst_gl_context_wgl_get_gl_context (GstGLContext * context);
51 static void gst_gl_context_wgl_swap_buffers (GstGLContext * context);
52 static gboolean gst_gl_context_wgl_choose_format (GstGLContext * context,
53 GError ** error);
54 static gboolean gst_gl_context_wgl_activate (GstGLContext * context,
55 gboolean activate);
56 static gboolean gst_gl_context_wgl_create_context (GstGLContext * context,
57 GstGLAPI gl_api, GstGLContext * other_context, GError ** error);
58 static void gst_gl_context_wgl_destroy_context (GstGLContext * context);
59 GstGLAPI gst_gl_context_wgl_get_gl_api (GstGLContext * context);
60 static GstGLPlatform gst_gl_context_wgl_get_gl_platform (GstGLContext *
61 context);
62
63 static void
gst_gl_context_wgl_class_init(GstGLContextWGLClass * klass)64 gst_gl_context_wgl_class_init (GstGLContextWGLClass * klass)
65 {
66 GstGLContextClass *context_class = (GstGLContextClass *) klass;
67
68 context_class->get_gl_context =
69 GST_DEBUG_FUNCPTR (gst_gl_context_wgl_get_gl_context);
70 context_class->choose_format =
71 GST_DEBUG_FUNCPTR (gst_gl_context_wgl_choose_format);
72 context_class->activate = GST_DEBUG_FUNCPTR (gst_gl_context_wgl_activate);
73 context_class->create_context =
74 GST_DEBUG_FUNCPTR (gst_gl_context_wgl_create_context);
75 context_class->destroy_context =
76 GST_DEBUG_FUNCPTR (gst_gl_context_wgl_destroy_context);
77 context_class->swap_buffers =
78 GST_DEBUG_FUNCPTR (gst_gl_context_wgl_swap_buffers);
79
80 context_class->get_proc_address =
81 GST_DEBUG_FUNCPTR (gst_gl_context_wgl_get_proc_address);
82 context_class->get_gl_api = GST_DEBUG_FUNCPTR (gst_gl_context_wgl_get_gl_api);
83 context_class->get_gl_platform =
84 GST_DEBUG_FUNCPTR (gst_gl_context_wgl_get_gl_platform);
85 }
86
87 static void
gst_gl_context_wgl_init(GstGLContextWGL * context_wgl)88 gst_gl_context_wgl_init (GstGLContextWGL * context_wgl)
89 {
90 context_wgl->priv = gst_gl_context_wgl_get_instance_private (context_wgl);
91
92 context_wgl->priv->context_api = GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
93 }
94
95 /* Must be called in the gl thread */
96 GstGLContextWGL *
gst_gl_context_wgl_new(GstGLDisplay * display)97 gst_gl_context_wgl_new (GstGLDisplay * display)
98 {
99 GstGLContextWGL *context;
100
101 if ((gst_gl_display_get_handle_type (display) & GST_GL_DISPLAY_TYPE_WIN32) ==
102 0)
103 /* we require an win32 display handle to create WGL contexts */
104 return NULL;
105
106 context = g_object_new (GST_TYPE_GL_CONTEXT_WGL, NULL);
107 gst_object_ref_sink (context);
108
109 return context;
110 }
111
112 static HGLRC
_create_context_with_flags(GstGLContextWGL * context_wgl,HDC dpy,HGLRC share_context,gint major,gint minor,gint contextFlags,gint profileMask)113 _create_context_with_flags (GstGLContextWGL * context_wgl, HDC dpy,
114 HGLRC share_context, gint major, gint minor, gint contextFlags,
115 gint profileMask)
116 {
117 HGLRC ret;
118 #define N_ATTRIBS 20
119 gint attribs[N_ATTRIBS];
120 gint n = 0;
121
122 if (major) {
123 attribs[n++] = WGL_CONTEXT_MAJOR_VERSION_ARB;
124 attribs[n++] = major;
125 }
126 if (minor) {
127 attribs[n++] = WGL_CONTEXT_MINOR_VERSION_ARB;
128 attribs[n++] = minor;
129 }
130 if (contextFlags) {
131 attribs[n++] = WGL_CONTEXT_FLAGS_ARB;
132 attribs[n++] = contextFlags;
133 }
134 if (profileMask) {
135 attribs[n++] = WGL_CONTEXT_PROFILE_MASK_ARB;
136 attribs[n++] = profileMask;
137 }
138 attribs[n++] = 0;
139
140 g_assert (n < N_ATTRIBS);
141 #undef N_ATTRIBS
142
143 ret =
144 context_wgl->priv->wglCreateContextAttribsARB (dpy, share_context,
145 attribs);
146
147 return ret;
148 }
149
150 static gboolean
gst_gl_context_wgl_create_context(GstGLContext * context,GstGLAPI gl_api,GstGLContext * other_context,GError ** error)151 gst_gl_context_wgl_create_context (GstGLContext * context,
152 GstGLAPI gl_api, GstGLContext * other_context, GError ** error)
153 {
154 GstGLWindow *window;
155 GstGLContextWGL *context_wgl;
156 HGLRC external_gl_context = NULL;
157 HGLRC trampoline;
158 HDC device;
159
160 context_wgl = GST_GL_CONTEXT_WGL (context);
161 window = gst_gl_context_get_window (context);
162 device = (HDC) gst_gl_window_get_display (window);
163
164 if (other_context) {
165 if (gst_gl_context_get_gl_platform (other_context) != GST_GL_PLATFORM_WGL) {
166 g_set_error (error, GST_GL_CONTEXT_ERROR,
167 GST_GL_CONTEXT_ERROR_WRONG_CONFIG,
168 "Cannot share context with a non-WGL context");
169 goto failure;
170 }
171 external_gl_context = (HGLRC) gst_gl_context_get_gl_context (other_context);
172 }
173
174 trampoline = wglCreateContext (device);
175 if (trampoline)
176 GST_DEBUG ("gl context created: %" G_GUINTPTR_FORMAT,
177 (guintptr) trampoline);
178 else {
179 g_set_error (error, GST_GL_CONTEXT_ERROR,
180 GST_GL_CONTEXT_ERROR_CREATE_CONTEXT, "failed to create glcontext:0x%x",
181 (unsigned int) GetLastError ());
182 goto failure;
183 }
184 g_assert (trampoline);
185
186 /* get extension functions */
187 wglMakeCurrent (device, trampoline);
188
189 context_wgl->priv->wglCreateContextAttribsARB =
190 (PFNWGLCREATECONTEXTATTRIBSARBPROC)
191 wglGetProcAddress ("wglCreateContextAttribsARB");
192
193 wglMakeCurrent (device, 0);
194 wglDeleteContext (trampoline);
195 trampoline = NULL;
196
197 if (context_wgl->priv->wglCreateContextAttribsARB != NULL
198 && gl_api & GST_GL_API_OPENGL3) {
199 gint i;
200
201 for (i = 0; i < G_N_ELEMENTS (opengl_versions); i++) {
202 gint profileMask = 0;
203 gint contextFlags = 0;
204
205 if ((opengl_versions[i].major > 3
206 || (opengl_versions[i].major == 3
207 && opengl_versions[i].minor >= 2))) {
208 profileMask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
209 contextFlags |= WGL_CONTEXT_DEBUG_BIT_ARB;
210 } else {
211 break;
212 }
213
214 GST_DEBUG_OBJECT (context, "trying to create a GL %d.%d context",
215 opengl_versions[i].major, opengl_versions[i].minor);
216
217 context_wgl->wgl_context = _create_context_with_flags (context_wgl,
218 device, external_gl_context, opengl_versions[i].major,
219 opengl_versions[i].minor, contextFlags, profileMask);
220
221 if (context_wgl->wgl_context) {
222 context_wgl->priv->context_api = GST_GL_API_OPENGL3;
223 break;
224 }
225 }
226 }
227
228 if (!context_wgl->wgl_context) {
229
230 if (context_wgl->priv->wglCreateContextAttribsARB && external_gl_context) {
231 context_wgl->wgl_context =
232 context_wgl->priv->wglCreateContextAttribsARB (device,
233 external_gl_context, 0);
234 }
235
236
237 if (!context_wgl->wgl_context) {
238
239 context_wgl->wgl_context = wglCreateContext (device);
240
241 if (!context_wgl->wgl_context) {
242 g_set_error (error, GST_GL_CONTEXT_ERROR,
243 GST_GL_CONTEXT_ERROR_CREATE_CONTEXT,
244 "Failed to create WGL context 0x%x",
245 (unsigned int) GetLastError ());
246 goto failure;
247 }
248
249 if (external_gl_context) {
250 if (!wglShareLists (external_gl_context, context_wgl->wgl_context)) {
251 g_set_error (error, GST_GL_CONTEXT_ERROR,
252 GST_GL_CONTEXT_ERROR_CREATE_CONTEXT,
253 "failed to share contexts through wglShareLists 0x%x",
254 (unsigned int) GetLastError ());
255 goto failure;
256 }
257 }
258 }
259
260 context_wgl->priv->context_api = GST_GL_API_OPENGL;
261 }
262
263 GST_LOG ("gl context id: %" G_GUINTPTR_FORMAT,
264 (guintptr) context_wgl->wgl_context);
265
266 gst_object_unref (window);
267
268 return TRUE;
269
270 failure:
271 gst_object_unref (window);
272
273 return FALSE;
274 }
275
276 static void
gst_gl_context_wgl_destroy_context(GstGLContext * context)277 gst_gl_context_wgl_destroy_context (GstGLContext * context)
278 {
279 GstGLContextWGL *context_wgl;
280
281 context_wgl = GST_GL_CONTEXT_WGL (context);
282
283 if (context_wgl->wgl_context)
284 wglDeleteContext (context_wgl->wgl_context);
285 context_wgl->wgl_context = NULL;
286 }
287
288 static gboolean
gst_gl_context_wgl_choose_format(GstGLContext * context,GError ** error)289 gst_gl_context_wgl_choose_format (GstGLContext * context, GError ** error)
290 {
291 GstGLWindow *window;
292 PIXELFORMATDESCRIPTOR pfd;
293 gint pixelformat = 0;
294 gboolean res = FALSE;
295 HDC device;
296
297 window = gst_gl_context_get_window (context);
298 gst_gl_window_win32_create_window (GST_GL_WINDOW_WIN32 (window), error);
299 device = (HDC) gst_gl_window_get_display (window);
300 gst_object_unref (window);
301
302 pfd.nSize = sizeof (PIXELFORMATDESCRIPTOR);
303 pfd.nVersion = 1;
304 pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
305 pfd.iPixelType = PFD_TYPE_RGBA;
306 pfd.cColorBits = 24;
307 pfd.cRedBits = 8;
308 pfd.cRedShift = 0;
309 pfd.cGreenBits = 8;
310 pfd.cGreenShift = 0;
311 pfd.cBlueBits = 8;
312 pfd.cBlueShift = 0;
313 pfd.cAlphaBits = 0;
314 pfd.cAlphaShift = 0;
315 pfd.cAccumBits = 0;
316 pfd.cAccumRedBits = 0;
317 pfd.cAccumGreenBits = 0;
318 pfd.cAccumBlueBits = 0;
319 pfd.cAccumAlphaBits = 0;
320 pfd.cDepthBits = 24;
321 pfd.cStencilBits = 8;
322 pfd.cAuxBuffers = 0;
323 pfd.iLayerType = PFD_MAIN_PLANE;
324 pfd.bReserved = 0;
325 pfd.dwLayerMask = 0;
326 pfd.dwVisibleMask = 0;
327 pfd.dwDamageMask = 0;
328
329 pfd.cColorBits = (BYTE) GetDeviceCaps (device, BITSPIXEL);
330
331 pixelformat = ChoosePixelFormat (device, &pfd);
332
333 if (!pixelformat) {
334 g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED,
335 "Failed to choose a pixel format");
336 return FALSE;
337 }
338
339 res = SetPixelFormat (device, pixelformat, &pfd);
340
341 return res;
342 }
343
344 static void
gst_gl_context_wgl_swap_buffers(GstGLContext * context)345 gst_gl_context_wgl_swap_buffers (GstGLContext * context)
346 {
347 GstGLWindow *window = gst_gl_context_get_window (context);
348 HDC device = (HDC) gst_gl_window_get_display (window);
349
350 SwapBuffers (device);
351
352 gst_object_unref (window);
353 }
354
355 static guintptr
gst_gl_context_wgl_get_gl_context(GstGLContext * context)356 gst_gl_context_wgl_get_gl_context (GstGLContext * context)
357 {
358 return (guintptr) GST_GL_CONTEXT_WGL (context)->wgl_context;
359 }
360
361 static gboolean
gst_gl_context_wgl_activate(GstGLContext * context,gboolean activate)362 gst_gl_context_wgl_activate (GstGLContext * context, gboolean activate)
363 {
364 GstGLWindow *window;
365 GstGLContextWGL *context_wgl;
366 HDC device;
367 gboolean result;
368
369 window = gst_gl_context_get_window (context);
370 context_wgl = GST_GL_CONTEXT_WGL (context);
371 device = (HDC) gst_gl_window_get_display (window);
372
373 if (activate) {
374 result = wglMakeCurrent (device, context_wgl->wgl_context);
375 } else {
376 result = wglMakeCurrent (NULL, NULL);
377 }
378
379 gst_object_unref (window);
380
381 return result;
382 }
383
384 GstGLAPI
gst_gl_context_wgl_get_gl_api(GstGLContext * context)385 gst_gl_context_wgl_get_gl_api (GstGLContext * context)
386 {
387 GstGLContextWGL *context_wgl = GST_GL_CONTEXT_WGL (context);
388
389 return context_wgl->priv->context_api;
390 }
391
392 static GstGLPlatform
gst_gl_context_wgl_get_gl_platform(GstGLContext * context)393 gst_gl_context_wgl_get_gl_platform (GstGLContext * context)
394 {
395 return GST_GL_PLATFORM_WGL;
396 }
397
398 gpointer
gst_gl_context_wgl_get_proc_address(GstGLAPI gl_api,const gchar * name)399 gst_gl_context_wgl_get_proc_address (GstGLAPI gl_api, const gchar * name)
400 {
401 gpointer result;
402
403 if (!(result = gst_gl_context_default_get_proc_address (gl_api, name))) {
404 result = wglGetProcAddress ((LPCSTR) name);
405 }
406
407 return result;
408 }
409
410 guintptr
gst_gl_context_wgl_get_current_context(void)411 gst_gl_context_wgl_get_current_context (void)
412 {
413 return (guintptr) wglGetCurrentContext ();
414 }
415