diff --git a/video/out/opengl/angle.c b/video/out/opengl/angle.c new file mode 100644 index 0000000000..7aac2bd29d --- /dev/null +++ b/video/out/opengl/angle.c @@ -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 . + * + * 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 +#include +#include + +#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, +}; diff --git a/video/out/opengl/common.c b/video/out/opengl/common.c index 3d24f9818f..660b4b2717 100644 --- a/video/out/opengl/common.c +++ b/video/out/opengl/common.c @@ -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 diff --git a/wscript b/wscript index 858dcc901c..0f113002ba 100644 --- a/wscript +++ b/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', diff --git a/wscript_build.py b/wscript_build.py index 76b3929c95..6829554c17 100644 --- a/wscript_build.py +++ b/wscript_build.py @@ -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" ),