diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index 441e0d2afc..7c3ff0808c 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -4225,6 +4225,8 @@ The following video options are currently all specific to ``--vo=opengl`` and DRM/EGL x11egl X11/EGL + mali-fbdev + Direct fbdev/EGL support on some ARM/MALI devices. ``--opengl-es=`` Select whether to use GLES: diff --git a/video/out/opengl/context.c b/video/out/opengl/context.c index a8058fb18c..a22227562a 100644 --- a/video/out/opengl/context.c +++ b/video/out/opengl/context.c @@ -45,6 +45,7 @@ extern const struct mpgl_driver mpgl_driver_angle; extern const struct mpgl_driver mpgl_driver_angle_es2; extern const struct mpgl_driver mpgl_driver_dxinterop; extern const struct mpgl_driver mpgl_driver_rpi; +extern const struct mpgl_driver mpgl_driver_mali; static const struct mpgl_driver *const backends[] = { #if HAVE_RPI @@ -78,6 +79,9 @@ static const struct mpgl_driver *const backends[] = { #if HAVE_EGL_DRM &mpgl_driver_drm_egl, #endif +#if HAVE_MALI_FBDEV + &mpgl_driver_mali, +#endif }; // 0-terminated list of desktop GL versions a backend should try to diff --git a/video/out/opengl/context_mali_fbdev.c b/video/out/opengl/context_mali_fbdev.c new file mode 100644 index 0000000000..e76d220939 --- /dev/null +++ b/video/out/opengl/context_mali_fbdev.c @@ -0,0 +1,167 @@ +/* + * This file is part of mpv. + * + * mpv is free software; you can redistribute it 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. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with mpv. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "common/common.h" +#include "context.h" +#include "egl_helpers.h" + +static bool get_fbdev_size(int *w, int *h) +{ + int fd = open("/dev/fb0", O_RDWR | O_CLOEXEC); + if (fd < 0) + return false; + + struct fb_var_screeninfo info = {0}; + bool ok = !ioctl(fd, FBIOGET_VSCREENINFO, &info); + if (ok) { + *w = info.xres; + *h = info.yres; + } + + close(fd); + + return ok; +} + +static void *get_proc_address(const GLubyte *name) +{ + void *p = eglGetProcAddress(name); + // EGL 1.4 (supported by the MALI drivers) does not necessarily return + // function pointers for core functions. + if (!p) + p = dlsym(RTLD_DEFAULT, name); + return p; +} + +struct priv { + struct mp_log *log; + struct GL *gl; + EGLDisplay egl_display; + EGLConfig egl_config; + EGLContext egl_context; + EGLSurface egl_surface; + struct fbdev_window egl_window; + int w, h; +}; + +static void mali_uninit(struct MPGLContext *ctx) +{ + struct priv *p = ctx->priv; + + if (p->egl_surface) { + eglMakeCurrent(p->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, + EGL_NO_CONTEXT); + eglDestroySurface(p->egl_display, p->egl_surface); + } + if (p->egl_context) + eglDestroyContext(p->egl_display, p->egl_context); + eglReleaseThread(); +} + +static int mali_init(struct MPGLContext *ctx, int flags) +{ + struct priv *p = ctx->priv; + p->log = ctx->vo->log; + + if (!get_fbdev_size(&p->w, &p->h)) { + MP_FATAL(p, "Could not get fbdev size.\n"); + goto fail; + } + + p->egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (!eglInitialize(p->egl_display, NULL, NULL)) { + MP_FATAL(p, "EGL failed to initialize.\n"); + goto fail; + } + + EGLConfig config; + if (!mpegl_create_context(p->egl_display, p->log, flags, &p->egl_context, + &config)) + goto fail; + + p->egl_window = (struct fbdev_window){ + .width = p->w, + .height = p->h, + }; + + p->egl_surface = eglCreateWindowSurface(p->egl_display, config, + (EGLNativeWindowType)&p->egl_window, NULL); + + if (p->egl_surface == EGL_NO_SURFACE) { + MP_FATAL(p, "Could not create EGL surface!\n"); + goto fail; + } + + if (!eglMakeCurrent(p->egl_display, p->egl_surface, p->egl_surface, + p->egl_context)) + { + MP_FATAL(p, "Failed to set context!\n"); + goto fail; + } + + ctx->gl = talloc_zero(ctx, GL); + + const char *exts = eglQueryString(p->egl_display, EGL_EXTENSIONS); + mpgl_load_functions(ctx->gl, get_proc_address, exts, p->log); + + return 0; + +fail: + mali_uninit(ctx); + return -1; +} + +static int mali_reconfig(struct MPGLContext *ctx) +{ + struct priv *p = ctx->priv; + ctx->vo->dwidth = p->w; + ctx->vo->dheight = p->h; + return 0; +} + +static void mali_swap_buffers(MPGLContext *ctx) +{ + struct priv *p = ctx->priv; + eglSwapBuffers(p->egl_display, p->egl_surface); +} + +static int mali_control(MPGLContext *ctx, int *events, int request, void *arg) +{ + return VO_NOTIMPL; +} + +const struct mpgl_driver mpgl_driver_mali = { + .name = "mali-fbdev", + .priv_size = sizeof(struct priv), + .init = mali_init, + .reconfig = mali_reconfig, + .swap_buffers = mali_swap_buffers, + .control = mali_control, + .uninit = mali_uninit, +}; diff --git a/wscript b/wscript index 033c8f5fa2..5b07a3bda6 100644 --- a/wscript +++ b/wscript @@ -822,11 +822,22 @@ video_output_features = [ 'deps': ['any-gl'], 'deps_any': [ 'libmpv-shared', 'libmpv-static' ], 'func': check_true, - } , { + }, { + 'name': '--mali-fbdev', + 'desc': 'MALI via Linux fbdev', + 'deps': ['standard-gl', 'libdl'], + 'func': compose_checks( + check_cc(lib="EGL"), + check_cc(lib="GLESv2"), + check_statement('EGL/fbdev_window.h', 'struct fbdev_window test'), + check_statement('linux/fb.h', 'struct fb_var_screeninfo test'), + ), + }, { 'name': '--gl', 'desc': 'OpenGL video outputs', 'deps_any': [ 'gl-cocoa', 'gl-x11', 'egl-x11', 'egl-drm', - 'gl-win32', 'gl-wayland', 'rpi', 'plain-gl' ], + 'gl-win32', 'gl-wayland', 'rpi', 'mali-fbdev', + 'plain-gl' ], 'func': check_true, 'req': True, 'fmsg': "Unable to find OpenGL header files for video output. " + @@ -835,7 +846,7 @@ video_output_features = [ }, { 'name': 'egl-helpers', 'desc': 'EGL helper functions', - 'deps_any': [ 'egl-x11' ], + 'deps_any': [ 'egl-x11', 'mali-fbdev' ], 'func': check_true } ] diff --git a/wscript_build.py b/wscript_build.py index 08cb2d1cea..c9960252fa 100644 --- a/wscript_build.py +++ b/wscript_build.py @@ -334,6 +334,7 @@ def build(ctx): ( "video/out/opengl/context_cocoa.c", "gl-cocoa" ), ( "video/out/opengl/context_drm_egl.c", "egl-drm" ), ( "video/out/opengl/context_dxinterop.c","gl-dxinterop" ), + ( "video/out/opengl/context_mali_fbdev.c","mali-fbdev" ), ( "video/out/opengl/context_rpi.c", "rpi" ), ( "video/out/opengl/context_wayland.c", "gl-wayland" ), ( "video/out/opengl/context_w32.c", "gl-win32" ),