glwin32.c 9.38 KB
Newer Older
1 2 3
/*****************************************************************************
 * glwin32.c: Windows OpenGL provider
 *****************************************************************************
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2001-2009 VLC authors and VideoLAN
5 6 7 8
 * $Id$
 *
 * Authors: Gildas Bazin <gbazin@videolan.org>
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
9 10 11
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
12 13 14 15
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
16 17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
18
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
19 20 21
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22
 *****************************************************************************/
23 24 25 26
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

27
#include <vlc_common.h>
28
#include <vlc_plugin.h>
29
#include <vlc_vout_display.h>
30 31 32

#include <windows.h>

33
#define GLEW_STATIC
34
#include "../opengl.h"
35
#include <GL/wglew.h>
36

37
#include "common.h"
38 39 40 41

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
42 43 44
static int  Open (vlc_object_t *);
static void Close(vlc_object_t *);

45 46
#define HW_GPU_AFFINITY_TEXT N_("GPU affinity")

47 48 49 50 51
vlc_module_begin()
    set_category(CAT_VIDEO)
    set_subcategory(SUBCAT_VIDEO_VOUT)
    set_shortname("OpenGL")
    set_description(N_("OpenGL video output"))
52 53 54

    add_integer("gpu-affinity", -1, HW_GPU_AFFINITY_TEXT, HW_GPU_AFFINITY_TEXT, true)

55
    set_capability("vout display", 160)
56
    add_shortcut("glwin32", "opengl")
57 58
    set_callbacks(Open, Close)
vlc_module_end()
59 60

/*****************************************************************************
61
 * Local prototypes.
62
 *****************************************************************************/
63
static picture_pool_t *Pool  (vout_display_t *, unsigned);
64 65
static void           Prepare(vout_display_t *, picture_t *, subpicture_t *);
static void           Display(vout_display_t *, picture_t *, subpicture_t *);
66
static void           Manage (vout_display_t *);
67

68
static void           Swap   (vlc_gl_t *);
Laurent Aimar's avatar
Laurent Aimar committed
69
static void          *OurGetProcAddress(vlc_gl_t *, const char *);
70

71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
/* Create an GPU Affinity DC */
static void CreateGPUAffinityDC(vout_display_t *vd, UINT nVidiaAffinity) {
    PIXELFORMATDESCRIPTOR pfd;
    memset(&pfd, 0, sizeof(pfd));
    pfd.nSize = sizeof(pfd);
    pfd.nVersion = 1;
    pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
    pfd.iPixelType = PFD_TYPE_RGBA;
    pfd.cColorBits = 24;
    pfd.cDepthBits = 16;
    pfd.iLayerType = PFD_MAIN_PLANE;

    /* create a temporary GL context */
    HDC winDC = GetDC(vd->sys->hvideownd);
    SetPixelFormat(winDC, ChoosePixelFormat(winDC, &pfd), &pfd);
    HGLRC hGLRC = wglCreateContext(winDC);
    wglMakeCurrent(winDC, hGLRC);

    /* Initialize the neccessary function pointers */
    PFNWGLENUMGPUSNVPROC fncEnumGpusNV = (PFNWGLENUMGPUSNVPROC)wglGetProcAddress("wglEnumGpusNV");
    PFNWGLCREATEAFFINITYDCNVPROC fncCreateAffinityDCNV = (PFNWGLCREATEAFFINITYDCNVPROC)wglGetProcAddress("wglCreateAffinityDCNV");

    /* delete the temporary GL context */
    wglDeleteContext(hGLRC);

    /* see if we have the extensions */
    if (!fncEnumGpusNV || !fncCreateAffinityDCNV) return;

    /* find the graphics card */
    HGPUNV GpuMask[2];
    GpuMask[0] = NULL;
    GpuMask[1] = NULL;
    HGPUNV hGPU;
    if (!fncEnumGpusNV(nVidiaAffinity, &hGPU)) return;

    /* make the affinity DC */
    GpuMask[0] = hGPU;
    vd->sys->affinityHDC = fncCreateAffinityDCNV(GpuMask);
    if (vd->sys->affinityHDC == NULL) return;
    SetPixelFormat(vd->sys->affinityHDC,
        ChoosePixelFormat(vd->sys->affinityHDC, &pfd), &pfd);

    msg_Dbg( vd, "GPU affinity set to adapter: %d",
                     nVidiaAffinity );
}

/* Destroy an GPU Affinity DC */
static void DestroyGPUAffinityDC(vout_display_t *vd) {
    if (vd->sys->affinityHDC == NULL) return;

    PIXELFORMATDESCRIPTOR pfd;
    memset(&pfd, 0, sizeof(pfd));
    pfd.nSize = sizeof(pfd);
    pfd.nVersion = 1;
    pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
    pfd.iPixelType = PFD_TYPE_RGBA;
    pfd.cColorBits = 24;
    pfd.cDepthBits = 16;
    pfd.iLayerType = PFD_MAIN_PLANE;

    /* create a temporary GL context */
    HDC winDC = GetDC(vd->sys->hvideownd);
    SetPixelFormat(winDC, ChoosePixelFormat(winDC, &pfd), &pfd);
    HGLRC hGLRC = wglCreateContext(winDC);
    wglMakeCurrent(winDC, hGLRC);

    /* Initialize the neccessary function pointers */
    PFNWGLDELETEDCNVPROC fncDeleteDCNV = (PFNWGLDELETEDCNVPROC)wglGetProcAddress("wglDeleteDCNV");

    /* delete the temporary GL context */
    wglDeleteContext(hGLRC);

    /* see if we have the extensions */
    if (!fncDeleteDCNV) return;

    /* delete the affinity DC */
    fncDeleteDCNV(vd->sys->affinityHDC);
}

150 151 152 153
/**
 * It creates an OpenGL vout display.
 */
static int Open(vlc_object_t *object)
154
{
155 156
    vout_display_t *vd = (vout_display_t *)object;
    vout_display_sys_t *sys;
157 158

    /* Allocate structure */
159 160
    vd->sys = sys = calloc(1, sizeof(*sys));
    if (!sys)
161 162
        return VLC_ENOMEM;

163 164
    /* */
    if (CommonInit(vd))
165 166
        goto error;

167
    EventThreadUpdateTitle(sys->event, VOUT_TITLE " (OpenGL output)");
168

169 170 171 172
    /* process selected GPU affinity */
    int nVidiaAffinity = var_InheritInteger(vd, "gpu-affinity");
    if (nVidiaAffinity >= 0) CreateGPUAffinityDC(vd, nVidiaAffinity);

173 174
    /* */
    sys->hGLDC = GetDC(sys->hvideownd);
175 176

    /* Set the pixel format for the DC */
177 178 179
    PIXELFORMATDESCRIPTOR pfd;
    memset(&pfd, 0, sizeof(pfd));
    pfd.nSize = sizeof(pfd);
180 181 182 183 184 185
    pfd.nVersion = 1;
    pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
    pfd.iPixelType = PFD_TYPE_RGBA;
    pfd.cColorBits = 24;
    pfd.cDepthBits = 16;
    pfd.iLayerType = PFD_MAIN_PLANE;
186 187
    SetPixelFormat(sys->hGLDC,
                   ChoosePixelFormat(sys->hGLDC, &pfd), &pfd);
188

189 190 191 192 193 194
    /*
     * Create and enable the render context
     * For GPU affinity, attach the window DC
     * to the GPU affinity DC
     */
    sys->hGLRC = wglCreateContext((sys->affinityHDC != NULL) ? sys->affinityHDC : sys->hGLDC);
195 196
    wglMakeCurrent(sys->hGLDC, sys->hGLRC);

197 198 199 200 201 202 203 204 205
    const char *extensions = (const char*)glGetString(GL_EXTENSIONS);
#ifdef WGL_EXT_swap_control
    if (HasExtension(extensions, "WGL_EXT_swap_control")) {
        PFNWGLSWAPINTERVALEXTPROC SwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
        if (SwapIntervalEXT)
            SwapIntervalEXT(1);
    }
#endif

206 207 208 209
    /* */
    sys->gl.lock = NULL;
    sys->gl.unlock = NULL;
    sys->gl.swap = Swap;
Laurent Aimar's avatar
Laurent Aimar committed
210
    sys->gl.getProcAddress = OurGetProcAddress;
211 212 213
    sys->gl.sys = vd;

    video_format_t fmt = vd->fmt;
214 215
    const vlc_fourcc_t *subpicture_chromas;
    sys->vgl = vout_display_opengl_New(&fmt, &subpicture_chromas, &sys->gl);
216
    if (!sys->vgl)
217 218 219 220
        goto error;

    vout_display_info_t info = vd->info;
    info.has_double_click = true;
221
    info.has_hide_mouse = false;
222
    info.has_event_thread = true;
223
    info.subpicture_chromas = subpicture_chromas;
224 225 226 227 228

   /* Setup vout_display now that everything is fine */
    vd->fmt  = fmt;
    vd->info = info;

229
    vd->pool    = Pool;
230 231
    vd->prepare = Prepare;
    vd->display = Display;
232
    vd->control = CommonControl;
233
    vd->manage  = Manage;
234 235

    return VLC_SUCCESS;
236 237 238 239

error:
    Close(object);
    return VLC_EGENERIC;
240 241
}

242 243 244 245
/**
 * It destroys an OpenGL vout display.
 */
static void Close(vlc_object_t *object)
246
{
247 248 249
    vout_display_t *vd = (vout_display_t *)object;
    vout_display_sys_t *sys = vd->sys;

250 251
    if (sys->vgl)
        vout_display_opengl_Delete(sys->vgl);
252 253 254 255 256 257 258

    if (sys->hGLDC && sys->hGLRC)
        wglMakeCurrent(NULL, NULL);
    if (sys->hGLRC)
        wglDeleteContext(sys->hGLRC);
    if (sys->hGLDC)
        ReleaseDC(sys->hvideownd, sys->hGLDC);
259
    DestroyGPUAffinityDC(vd);
260 261 262 263

    CommonClean(vd);

    free(sys);
264 265
}

266
/* */
267
static picture_pool_t *Pool(vout_display_t *vd, unsigned count)
268
{
269 270
    vout_display_sys_t *sys = vd->sys;

271
    if (!sys->pool)
272
        sys->pool = vout_display_opengl_GetPool(sys->vgl, count);
273
    return sys->pool;
274
}
275

276
static void Prepare(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture)
277 278
{
    vout_display_sys_t *sys = vd->sys;
279

280
    vout_display_opengl_Prepare(sys->vgl, picture, subpicture);
281 282
}

283
static void Display(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture)
284
{
285
    vout_display_sys_t *sys = vd->sys;
286

287
    vout_display_opengl_Display(sys->vgl, &vd->source);
288

289
    picture_Release(picture);
Laurent Aimar's avatar
Laurent Aimar committed
290 291
    if (subpicture)
        subpicture_Delete(subpicture);
292 293

    CommonDisplay(vd);
294 295
}

296 297 298 299 300
static void Manage (vout_display_t *vd)
{
    vout_display_sys_t *sys = vd->sys;

    CommonManage(vd);
301

302 303 304 305 306
    const int width  = sys->rect_dest.right  - sys->rect_dest.left;
    const int height = sys->rect_dest.bottom - sys->rect_dest.top;
    glViewport(0, 0, width, height);
}

307
static void Swap(vlc_gl_t *gl)
308
{
309 310 311
    vout_display_t *vd = gl->sys;

    SwapBuffers(vd->sys->hGLDC);
312
}
313

Laurent Aimar's avatar
Laurent Aimar committed
314
static void *OurGetProcAddress(vlc_gl_t *gl, const char *name)
315
{
316
    VLC_UNUSED(gl);
317 318 319
    return wglGetProcAddress(name);
}