mirror of https://github.com/mpv-player/mpv
213 lines
6.2 KiB
C
213 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->vo_init = vo_w32_init;
|
|
ctx->vo_uninit = vo_w32_uninit;
|
|
ctx->vo_control = vo_w32_control;
|
|
}
|