glwin32.c 9.33 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", 220)
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
    /* */
    sys->gl.swap = Swap;
Laurent Aimar's avatar
Laurent Aimar committed
208
    sys->gl.getProcAddress = OurGetProcAddress;
209 210 211
    sys->gl.sys = vd;

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

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

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

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

    return VLC_SUCCESS;
234 235 236 237

error:
    Close(object);
    return VLC_EGENERIC;
238 239
}

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

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

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

    CommonClean(vd);

    free(sys);
262 263
}

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

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

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

278
    vout_display_opengl_Prepare(sys->vgl, picture, subpicture);
279 280
}

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

285
    vout_display_opengl_Display(sys->vgl, &vd->source);
286

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

    CommonDisplay(vd);
292 293
}

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

    CommonManage(vd);
299

300 301 302 303 304
    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);
}

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

    SwapBuffers(vd->sys->hGLDC);
310
}
311

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