glwin32.c 9.39 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
/* 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);

Adrien Maglo's avatar
Adrien Maglo committed
89
    /* Initialize the necessary function pointers */
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
    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);

Adrien Maglo's avatar
Adrien Maglo committed
137
    /* Initialize the necessary function pointers */
138 139 140 141 142 143 144 145 146 147 148 149
    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
    const vlc_fourcc_t *subpicture_chromas;
213 214
    sys->vgl = vout_display_opengl_New(&fmt, &subpicture_chromas, &sys->gl,
                                       &vd->cfg->viewpoint);
215
    if (!sys->vgl)
216 217 218 219
        goto error;

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

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

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

    return VLC_SUCCESS;
235 236 237 238

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

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

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

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

    CommonClean(vd);

    free(sys);
263 264
}

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

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

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

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

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

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

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

    CommonDisplay(vd);
293 294
}

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

    CommonManage(vd);
300

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

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

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

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