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:
James Ross-Gowan 2015-11-14 00:04:30 +11:00
parent a3195381d1
commit e76ec2c963
4 changed files with 228 additions and 0 deletions

215
video/out/opengl/angle.c Normal file
View File

@ -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,
};

View File

@ -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

View File

@ -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',

View File

@ -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" ),