direct3d11: only do the SwapChain Present() during Display
[vlc.git] / modules / video_output / win32 / wgl.c
blob3baee6e3500adf7445d4278e3b57d9f96b03ce0c
1 /*****************************************************************************
2 * wgl.c: WGL extension for OpenGL
3 *****************************************************************************
4 * Copyright © 2009-2016 VLC authors and VideoLAN
6 * Authors: Adrien Maglo <magsoft@videolan.org>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
22 #ifdef HAVE_CONFIG_H
23 # include "config.h"
24 #endif
26 #include <vlc_common.h>
27 #include <vlc_plugin.h>
28 #include <vlc_vout_display.h>
29 #include <vlc_opengl.h>
31 #include "../opengl/vout_helper.h"
32 #include <GL/wglew.h>
34 #include "common.h"
36 /*****************************************************************************
37 * Module descriptor
38 *****************************************************************************/
39 static int Open(vlc_object_t *);
40 static void Close(vlc_object_t *);
42 #define HW_GPU_AFFINITY_TEXT N_("GPU affinity")
44 vlc_module_begin()
45 set_shortname("WGL")
46 set_description(N_("WGL extension for OpenGL"))
47 set_category(CAT_VIDEO)
48 set_subcategory(SUBCAT_VIDEO_VOUT)
50 add_integer("gpu-affinity", -1, HW_GPU_AFFINITY_TEXT, HW_GPU_AFFINITY_TEXT, true)
52 set_capability("opengl", 50)
53 set_callbacks(Open, Close)
54 add_shortcut("wgl")
55 vlc_module_end()
57 /*****************************************************************************
58 * Local prototypes.
59 *****************************************************************************/
61 struct vout_display_sys_t
63 vout_display_sys_win32_t sys;
65 HDC hGLDC;
66 HGLRC hGLRC;
67 vlc_gl_t *gl;
68 HDC affinityHDC; // DC for the selected GPU
71 static void Swap(vlc_gl_t *);
72 static void *OurGetProcAddress(vlc_gl_t *, const char *);
73 static int MakeCurrent(vlc_gl_t *gl);
74 static void ReleaseCurrent(vlc_gl_t *gl);
77 /* Create an GPU Affinity DC */
78 static void CreateGPUAffinityDC(vlc_gl_t *gl, UINT nVidiaAffinity) {
79 vout_display_sys_t *sys = gl->sys;
81 PIXELFORMATDESCRIPTOR pfd;
82 memset(&pfd, 0, sizeof(pfd));
83 pfd.nSize = sizeof(pfd);
84 pfd.nVersion = 1;
85 pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
86 pfd.iPixelType = PFD_TYPE_RGBA;
87 pfd.cColorBits = 24;
88 pfd.cDepthBits = 16;
89 pfd.iLayerType = PFD_MAIN_PLANE;
91 /* create a temporary GL context */
92 HDC winDC = GetDC(sys->sys.hvideownd);
93 SetPixelFormat(winDC, ChoosePixelFormat(winDC, &pfd), &pfd);
94 HGLRC hGLRC = wglCreateContext(winDC);
95 wglMakeCurrent(winDC, hGLRC);
97 /* Initialize the necessary function pointers */
98 PFNWGLENUMGPUSNVPROC fncEnumGpusNV = (PFNWGLENUMGPUSNVPROC)wglGetProcAddress("wglEnumGpusNV");
99 PFNWGLCREATEAFFINITYDCNVPROC fncCreateAffinityDCNV = (PFNWGLCREATEAFFINITYDCNVPROC)wglGetProcAddress("wglCreateAffinityDCNV");
101 /* delete the temporary GL context */
102 wglDeleteContext(hGLRC);
104 /* see if we have the extensions */
105 if (!fncEnumGpusNV || !fncCreateAffinityDCNV) return;
107 /* find the graphics card */
108 HGPUNV GpuMask[2];
109 GpuMask[0] = NULL;
110 GpuMask[1] = NULL;
111 HGPUNV hGPU;
112 if (!fncEnumGpusNV(nVidiaAffinity, &hGPU)) return;
114 /* make the affinity DC */
115 GpuMask[0] = hGPU;
116 sys->affinityHDC = fncCreateAffinityDCNV(GpuMask);
117 if (sys->affinityHDC == NULL) return;
118 SetPixelFormat(sys->affinityHDC,
119 ChoosePixelFormat(sys->affinityHDC, &pfd), &pfd);
121 msg_Dbg(gl, "GPU affinity set to adapter: %d", nVidiaAffinity);
124 /* Destroy an GPU Affinity DC */
125 static void DestroyGPUAffinityDC(vlc_gl_t *gl) {
126 vout_display_sys_t *sys = gl->sys;
128 if (sys->affinityHDC == NULL) return;
130 PIXELFORMATDESCRIPTOR pfd;
131 memset(&pfd, 0, sizeof(pfd));
132 pfd.nSize = sizeof(pfd);
133 pfd.nVersion = 1;
134 pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
135 pfd.iPixelType = PFD_TYPE_RGBA;
136 pfd.cColorBits = 24;
137 pfd.cDepthBits = 16;
138 pfd.iLayerType = PFD_MAIN_PLANE;
140 /* create a temporary GL context */
141 HDC winDC = GetDC(sys->sys.hvideownd);
142 SetPixelFormat(winDC, ChoosePixelFormat(winDC, &pfd), &pfd);
143 HGLRC hGLRC = wglCreateContext(winDC);
144 wglMakeCurrent(winDC, hGLRC);
146 /* Initialize the necessary function pointers */
147 PFNWGLDELETEDCNVPROC fncDeleteDCNV = (PFNWGLDELETEDCNVPROC)wglGetProcAddress("wglDeleteDCNV");
149 /* delete the temporary GL context */
150 wglDeleteContext(hGLRC);
152 /* see if we have the extensions */
153 if (!fncDeleteDCNV) return;
155 /* delete the affinity DC */
156 fncDeleteDCNV(sys->affinityHDC);
159 static int Open(vlc_object_t *object)
161 vlc_gl_t *gl = (vlc_gl_t *)object;
162 vout_display_sys_t *sys;
164 /* Allocate structure */
165 gl->sys = sys = calloc(1, sizeof(*sys));
166 if (!sys)
167 return VLC_ENOMEM;
169 /* Process selected GPU affinity */
170 int nVidiaAffinity = var_InheritInteger(gl, "gpu-affinity");
171 if (nVidiaAffinity >= 0) CreateGPUAffinityDC(gl, nVidiaAffinity);
173 vout_window_t *wnd = gl->surface;
174 sys->sys.hvideownd = wnd->handle.hwnd;
175 if (wnd->type != VOUT_WINDOW_TYPE_HWND)
176 goto error;
178 sys->hGLDC = GetDC(wnd->handle.hwnd);
179 if (sys->hGLDC == NULL)
181 msg_Err(gl, "Could not get the device context");
182 goto error;
185 /* Set the pixel format for the DC */
186 PIXELFORMATDESCRIPTOR pfd;
187 memset(&pfd, 0, sizeof(pfd));
188 pfd.nSize = sizeof(pfd);
189 pfd.nVersion = 1;
190 pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
191 pfd.iPixelType = PFD_TYPE_RGBA;
192 pfd.cColorBits = 24;
193 pfd.cDepthBits = 16;
194 pfd.iLayerType = PFD_MAIN_PLANE;
195 SetPixelFormat(sys->hGLDC, ChoosePixelFormat(sys->hGLDC, &pfd), &pfd);
197 /* Create the context. */
198 sys->hGLRC = wglCreateContext((sys->affinityHDC != NULL) ? sys->affinityHDC : sys->hGLDC);
199 if (sys->hGLRC == NULL)
201 msg_Err(gl, "Could not create the OpenGL rendering context");
202 goto error;
205 #ifdef WGL_EXT_swap_control
206 wglMakeCurrent(sys->hGLDC, sys->hGLRC);
207 /* Create an GPU Affinity DC */
208 const char *extensions = (const char*)glGetString(GL_EXTENSIONS);
209 if (HasExtension(extensions, "WGL_EXT_swap_control")) {
210 PFNWGLSWAPINTERVALEXTPROC SwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
211 if (SwapIntervalEXT)
212 SwapIntervalEXT(1);
214 wglMakeCurrent(sys->hGLDC, NULL);
215 #endif
217 gl->makeCurrent = MakeCurrent;
218 gl->releaseCurrent = ReleaseCurrent;
219 gl->resize = NULL;
220 gl->swap = Swap;
221 gl->getProcAddress = OurGetProcAddress;
223 return VLC_SUCCESS;
225 error:
226 Close(object);
227 return VLC_EGENERIC;
230 static void Close(vlc_object_t *object)
232 vlc_gl_t *gl = (vlc_gl_t *)object;
233 vout_display_sys_t *sys = gl->sys;
235 if (sys->hGLRC)
236 wglDeleteContext(sys->hGLRC);
237 if (sys->hGLDC)
238 ReleaseDC(sys->sys.hvideownd, sys->hGLDC);
240 DestroyGPUAffinityDC(gl);
242 free(sys);
245 static void Swap(vlc_gl_t *gl)
247 vout_display_sys_t *sys = gl->sys;
248 SwapBuffers(sys->hGLDC);
251 static void *OurGetProcAddress(vlc_gl_t *gl, const char *name)
253 VLC_UNUSED(gl);
254 return wglGetProcAddress(name);
257 static int MakeCurrent(vlc_gl_t *gl)
259 vout_display_sys_t *sys = gl->sys;
260 bool success = wglMakeCurrent(sys->hGLDC, sys->hGLRC);
261 return success ? VLC_SUCCESS : VLC_EGENERIC;
264 static void ReleaseCurrent(vlc_gl_t *gl)
266 vout_display_sys_t *sys = gl->sys;
267 wglMakeCurrent (sys->hGLDC, NULL);