mpv/video/out/gl_w32.c

214 lines
6.2 KiB
C

/*
* MPlayer is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* MPlayer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* You can alternatively redistribute this file 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 (at your option) any later version.
*/
#include <windows.h>
#include "w32_common.h"
#include "gl_common.h"
struct w32_context {
HGLRC context;
};
static void *w32gpa(const GLubyte *procName)
{
HMODULE oglmod;
void *res = wglGetProcAddress(procName);
if (res)
return res;
oglmod = GetModuleHandle("opengl32.dll");
return GetProcAddress(oglmod, procName);
}
static bool create_context_w32_old(struct MPGLContext *ctx)
{
GL *gl = ctx->gl;
struct w32_context *w32_ctx = ctx->priv;
HGLRC *context = &w32_ctx->context;
if (*context) {
gl->Finish(); // supposedly to prevent flickering
return true;
}
HWND win = ctx->vo->w32->window;
HDC windc = GetDC(win);
bool res = false;
HGLRC new_context = wglCreateContext(windc);
if (!new_context) {
MP_FATAL(ctx->vo, "Could not create GL context!\n");
goto out;
}
if (!wglMakeCurrent(windc, new_context)) {
MP_FATAL(ctx->vo, "Could not set GL context!\n");
wglDeleteContext(new_context);
goto out;
}
*context = new_context;
mpgl_load_functions(ctx->gl, w32gpa, NULL, ctx->vo->log);
res = true;
out:
ReleaseDC(win, windc);
return res;
}
static bool create_context_w32_gl3(struct MPGLContext *ctx)
{
struct w32_context *w32_ctx = ctx->priv;
HGLRC *context = &w32_ctx->context;
if (*context) // reuse existing context
return true; // not reusing it breaks gl3!
HWND win = ctx->vo->w32->window;
HDC windc = GetDC(win);
HGLRC new_context = 0;
new_context = wglCreateContext(windc);
if (!new_context) {
MP_FATAL(ctx->vo, "Could not create GL context!\n");
return false;
}
// set context
if (!wglMakeCurrent(windc, new_context)) {
MP_FATAL(ctx->vo, "Could not set GL context!\n");
goto out;
}
const char *(GLAPIENTRY *wglGetExtensionsStringARB)(HDC hdc)
= w32gpa((const GLubyte*)"wglGetExtensionsStringARB");
if (!wglGetExtensionsStringARB)
goto unsupported;
const char *wgl_exts = wglGetExtensionsStringARB(windc);
if (!strstr(wgl_exts, "WGL_ARB_create_context"))
goto unsupported;
HGLRC (GLAPIENTRY *wglCreateContextAttribsARB)(HDC hDC, HGLRC hShareContext,
const int *attribList)
= w32gpa((const GLubyte*)"wglCreateContextAttribsARB");
if (!wglCreateContextAttribsARB)
goto unsupported;
int gl_version = ctx->requested_gl_version;
int attribs[] = {
WGL_CONTEXT_MAJOR_VERSION_ARB, MPGL_VER_GET_MAJOR(gl_version),
WGL_CONTEXT_MINOR_VERSION_ARB, MPGL_VER_GET_MINOR(gl_version),
WGL_CONTEXT_FLAGS_ARB, 0,
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
0
};
*context = wglCreateContextAttribsARB(windc, 0, attribs);
if (! *context) {
// NVidia, instead of ignoring WGL_CONTEXT_FLAGS_ARB, will error out if
// it's present on pre-3.2 contexts.
// Remove it from attribs and retry the context creation.
attribs[6] = attribs[7] = 0;
*context = wglCreateContextAttribsARB(windc, 0, attribs);
}
if (! *context) {
int err = GetLastError();
MP_FATAL(ctx->vo, "Could not create an OpenGL 3.x context: error 0x%x\n", err);
goto out;
}
wglMakeCurrent(NULL, NULL);
wglDeleteContext(new_context);
if (!wglMakeCurrent(windc, *context)) {
MP_FATAL(ctx->vo, "Could not set GL3 context!\n");
wglDeleteContext(*context);
return false;
}
/* update function pointers */
mpgl_load_functions(ctx->gl, w32gpa, NULL, ctx->vo->log);
int pfmt = GetPixelFormat(windc);
PIXELFORMATDESCRIPTOR pfd;
if (DescribePixelFormat(windc, pfmt, sizeof(PIXELFORMATDESCRIPTOR), &pfd)) {
ctx->depth_r = pfd.cRedBits;
ctx->depth_g = pfd.cGreenBits;
ctx->depth_b = pfd.cBlueBits;
}
return true;
unsupported:
MP_ERR(ctx->vo, "The current OpenGL implementation does not support OpenGL 3.x \n");
out:
wglDeleteContext(new_context);
return false;
}
static bool config_window_w32(struct MPGLContext *ctx, uint32_t d_width,
uint32_t d_height, uint32_t flags)
{
if (!vo_w32_config(ctx->vo, d_width, d_height, flags))
return false;
bool success = false;
if (ctx->requested_gl_version >= MPGL_VER(3, 0))
success = create_context_w32_gl3(ctx);
if (!success)
success = create_context_w32_old(ctx);
return success;
}
static void releaseGlContext_w32(MPGLContext *ctx)
{
struct w32_context *w32_ctx = ctx->priv;
HGLRC *context = &w32_ctx->context;
if (*context) {
wglMakeCurrent(0, 0);
wglDeleteContext(*context);
}
*context = 0;
}
static void swapGlBuffers_w32(MPGLContext *ctx)
{
HDC vo_hdc = GetDC(ctx->vo->w32->window);
SwapBuffers(vo_hdc);
ReleaseDC(ctx->vo->w32->window, vo_hdc);
}
void mpgl_set_backend_w32(MPGLContext *ctx)
{
ctx->priv = talloc_zero(ctx, struct w32_context);
ctx->config_window = config_window_w32;
ctx->releaseGlContext = releaseGlContext_w32;
ctx->swapGlBuffers = swapGlBuffers_w32;
ctx->check_events = vo_w32_check_events;
ctx->vo_init = vo_w32_init;
ctx->vo_uninit = vo_w32_uninit;
ctx->vo_control = vo_w32_control;
}