mirror of https://github.com/mpv-player/mpv
vo_opengl: add initial ANGLE support
ANGLE is a GLES2 implementation for Windows that uses Direct3D 11 for rendering, enabling vo_opengl to work on systems with poor OpenGL drivers and bypassing some of the problems with native GL, such as VSync in fullscreen mode. Unfortunately, using GLES2 means that most of vo_opengl's advanced features will not work, however ANGLE is under rapid development and GLES3 support is supposed to be coming soon.
This commit is contained in:
parent
a3195381d1
commit
e76ec2c963
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* This file is part of mpv.
|
||||
*
|
||||
* mpv 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.
|
||||
*
|
||||
* mpv 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 mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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 <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
|
||||
#include "common/common.h"
|
||||
#include "video/out/w32_common.h"
|
||||
#include "common.h"
|
||||
|
||||
struct priv {
|
||||
EGLDisplay egl_display;
|
||||
EGLContext egl_context;
|
||||
EGLSurface egl_surface;
|
||||
HMODULE libglesv2;
|
||||
};
|
||||
|
||||
static void angle_uninit(MPGLContext *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
|
||||
if (p->egl_context) {
|
||||
eglMakeCurrent(p->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
|
||||
EGL_NO_CONTEXT);
|
||||
eglDestroyContext(p->egl_display, p->egl_context);
|
||||
}
|
||||
p->egl_context = EGL_NO_CONTEXT;
|
||||
|
||||
if (p->libglesv2)
|
||||
FreeLibrary(p->libglesv2);
|
||||
|
||||
vo_w32_uninit(ctx->vo);
|
||||
}
|
||||
|
||||
static EGLConfig select_fb_config_egl(struct MPGLContext *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
|
||||
EGLint attributes[] = {
|
||||
EGL_RED_SIZE, 8,
|
||||
EGL_GREEN_SIZE, 8,
|
||||
EGL_BLUE_SIZE, 8,
|
||||
EGL_DEPTH_SIZE, 0,
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
EGLint config_count;
|
||||
EGLConfig config;
|
||||
|
||||
eglChooseConfig(p->egl_display, attributes, &config, 1, &config_count);
|
||||
|
||||
if (!config_count) {
|
||||
MP_FATAL(ctx->vo, "Could find EGL configuration!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
static bool create_context_egl(MPGLContext *ctx, EGLConfig config,
|
||||
EGLNativeWindowType window)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
|
||||
EGLint context_attributes[] = {
|
||||
EGL_CONTEXT_CLIENT_VERSION, 2,
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
p->egl_surface = eglCreateWindowSurface(p->egl_display, config, window, NULL);
|
||||
|
||||
if (p->egl_surface == EGL_NO_SURFACE) {
|
||||
MP_FATAL(ctx->vo, "Could not create EGL surface!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
p->egl_context = eglCreateContext(p->egl_display, config,
|
||||
EGL_NO_CONTEXT, context_attributes);
|
||||
|
||||
if (p->egl_context == EGL_NO_CONTEXT) {
|
||||
MP_FATAL(ctx->vo, "Could not create EGL context!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
eglMakeCurrent(p->egl_display, p->egl_surface, p->egl_surface,
|
||||
p->egl_context);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void *get_proc_address(const GLubyte *proc_name)
|
||||
{
|
||||
void *res = eglGetProcAddress(proc_name);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
// ANGLE's eglGetProcAddress only works for extensions
|
||||
return GetProcAddress(GetModuleHandleW(L"libGLESv2.dll"), proc_name);
|
||||
}
|
||||
|
||||
static int angle_init(struct MPGLContext *ctx, int flags)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
struct vo *vo = ctx->vo;
|
||||
|
||||
if (!vo_w32_init(vo))
|
||||
goto fail;
|
||||
|
||||
p->libglesv2 = LoadLibraryW(L"libGLESv2.dll");
|
||||
if (!p->libglesv2) {
|
||||
MP_FATAL(vo, "Couldn't load GLES functions\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
HDC dc = GetDC(vo_w32_hwnd(vo));
|
||||
if (!dc) {
|
||||
MP_FATAL(vo, "Couldn't get DC\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT =
|
||||
(PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT");
|
||||
if (!eglGetPlatformDisplayEXT) {
|
||||
MP_FATAL(vo, "Missing EGL_EXT_platform_base\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
EGLint display_attributes[] = {
|
||||
EGL_PLATFORM_ANGLE_TYPE_ANGLE,
|
||||
EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
|
||||
EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE,
|
||||
EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE,
|
||||
EGL_NONE,
|
||||
};
|
||||
|
||||
p->egl_display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, dc,
|
||||
display_attributes);
|
||||
if (p->egl_display == EGL_NO_DISPLAY) {
|
||||
MP_FATAL(vo, "Couldn't get display\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!eglInitialize(p->egl_display, NULL, NULL)) {
|
||||
MP_FATAL(vo, "Couldn't initialize EGL\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
eglBindAPI(EGL_OPENGL_ES_API);
|
||||
if (eglGetError() != EGL_SUCCESS) {
|
||||
MP_FATAL(vo, "Couldn't bind GLES API\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
EGLConfig config = select_fb_config_egl(ctx);
|
||||
if (!config)
|
||||
goto fail;
|
||||
|
||||
if (!create_context_egl(ctx, config, vo_w32_hwnd(vo)))
|
||||
goto fail;
|
||||
|
||||
mpgl_load_functions(ctx->gl, get_proc_address, NULL, vo->log);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
angle_uninit(ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int angle_reconfig(struct MPGLContext *ctx)
|
||||
{
|
||||
vo_w32_config(ctx->vo);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int angle_control(MPGLContext *ctx, int *events, int request, void *arg)
|
||||
{
|
||||
return vo_w32_control(ctx->vo, events, request, arg);
|
||||
}
|
||||
|
||||
static void angle_swap_buffers(MPGLContext *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
eglSwapBuffers(p->egl_display, p->egl_surface);
|
||||
}
|
||||
|
||||
const struct mpgl_driver mpgl_driver_angle = {
|
||||
.name = "angle",
|
||||
.priv_size = sizeof(struct priv),
|
||||
.init = angle_init,
|
||||
.reconfig = angle_reconfig,
|
||||
.swap_buffers = angle_swap_buffers,
|
||||
.control = angle_control,
|
||||
.uninit = angle_uninit,
|
||||
};
|
|
@ -509,6 +509,7 @@ extern const struct mpgl_driver mpgl_driver_drm_egl;
|
|||
extern const struct mpgl_driver mpgl_driver_cocoa;
|
||||
extern const struct mpgl_driver mpgl_driver_wayland;
|
||||
extern const struct mpgl_driver mpgl_driver_w32;
|
||||
extern const struct mpgl_driver mpgl_driver_angle;
|
||||
extern const struct mpgl_driver mpgl_driver_rpi;
|
||||
|
||||
static const struct mpgl_driver *const backends[] = {
|
||||
|
@ -521,6 +522,9 @@ static const struct mpgl_driver *const backends[] = {
|
|||
#if HAVE_GL_WIN32
|
||||
&mpgl_driver_w32,
|
||||
#endif
|
||||
#if HAVE_EGL_ANGLE
|
||||
&mpgl_driver_angle,
|
||||
#endif
|
||||
#if HAVE_GL_WAYLAND
|
||||
&mpgl_driver_wayland,
|
||||
#endif
|
||||
|
|
8
wscript
8
wscript
|
@ -658,6 +658,14 @@ video_output_features = [
|
|||
'groups': [ 'gl' ],
|
||||
'func': check_statement('windows.h', 'wglCreateContext(0)',
|
||||
lib='opengl32')
|
||||
} , {
|
||||
'name': '--egl-angle',
|
||||
'desc': 'OpenGL Win32 ANGLE Backend',
|
||||
'deps_any': [ 'os-win32', 'os-cygwin' ],
|
||||
'groups': [ 'gl' ],
|
||||
'func': check_statement(['EGL/egl.h'],
|
||||
'eglCreateWindowSurface(0, 0, 0, 0)',
|
||||
lib='EGL')
|
||||
} , {
|
||||
'name': '--vdpau',
|
||||
'desc': 'VDPAU acceleration',
|
||||
|
|
|
@ -334,6 +334,7 @@ def build(ctx):
|
|||
( "video/out/opengl/video.c", "gl" ),
|
||||
( "video/out/opengl/video_shaders.c", "gl" ),
|
||||
( "video/out/opengl/w32.c", "gl-win32" ),
|
||||
( "video/out/opengl/angle.c", "egl-angle" ),
|
||||
( "video/out/opengl/wayland.c", "gl-wayland" ),
|
||||
( "video/out/opengl/x11.c", "gl-x11" ),
|
||||
( "video/out/opengl/x11egl.c", "egl-x11" ),
|
||||
|
|
Loading…
Reference in New Issue