summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2019-11-30 20:48:30 +0100
committerwm4 <wm4@nowhere>2019-12-16 00:25:51 +0100
commite1586585b4c54b1f76379728e4f1478b2fd5b3ce (patch)
tree56f9ab11a71592d852c37ecc06b3d17873616064
parent4ae43a1c40b2e6f96ce2c62bc5f16d55f91436f5 (diff)
downloadmpv-e1586585b4c54b1f76379728e4f1478b2fd5b3ce.tar.bz2
mpv-e1586585b4c54b1f76379728e4f1478b2fd5b3ce.tar.xz
vo_gpu: opengl: make it work with EGL 1.4
This tries to deal with the crazy EGL situation. The summary is: - using eglGetDisplay() with multiple windowing platforms doesn't really work, but Mesa had an awful hack for it - this hack can be disabled at build time, and some distros sometimes accidentally or intentionally do so - Mesa will probably eventually disable it by default - we switched to eglGetPlatformDisplay(), but this requires EGL 1.5 - the very regrettable graphics company (also known as Nvidia) ships drivers (for old hardware I think) that are EGL 1.4 only - that means even though we "require" EGL 1.5 and link against it, the runtime EGL may be 1.4 - trying to run mpv there crashes in the dynamic linker - so we have to go through some more awful compatibility hacks This commit tries to do it "properly", but using EGL 1.4 as base. The plaform selection mechanism is a messy extension there, which got elevated to core API in 1.5 (but OF COURSE in incompatible ways). I'm not sure whether the EGL 1.5 code path (by parsing the EGL_VERSION) is really needed, but if you ask me, it feels slightly saner not to rely on an EGL 1.4 kludge forever. But maybe this is just an instance of self-harm, since they will most likely never drop or not provide this API. Also, unlike before, we actually check the extension string for the individual platform extensions, because who knows, some EGL implementations might curse us if we pass unknown platform parameters. (But actually, the more I think about this, the more bullshit it is.) X11 and Wayland were the only ones trying to call eglGetPlatformDisplay, so they're the only ones which are adjusted in this commit. Unfortunately, correct function of this commit is unconfirmed. It's possible that it crashes with the old drivers mentioned above. Why didn't they solve it like this: struct native_display { int platform_type; void *native_display; }; Could have kept eglGetDisplay() without all the obnoxious extension BS.
-rw-r--r--video/out/opengl/context_wayland.c7
-rw-r--r--video/out/opengl/context_x11egl.c7
-rw-r--r--video/out/opengl/egl_helpers.c69
-rw-r--r--video/out/opengl/egl_helpers.h3
4 files changed, 82 insertions, 4 deletions
diff --git a/video/out/opengl/context_wayland.c b/video/out/opengl/context_wayland.c
index 2dd8cdec29..8af5c7b9a6 100644
--- a/video/out/opengl/context_wayland.c
+++ b/video/out/opengl/context_wayland.c
@@ -28,6 +28,8 @@
// Generated from presentation-time.xml
#include "video/out/wayland/presentation-time.h"
+#define EGL_PLATFORM_WAYLAND_EXT 0x31D8
+
struct priv {
GL gl;
EGLDisplay egl_display;
@@ -163,8 +165,9 @@ static bool egl_create_context(struct ra_ctx *ctx)
struct priv *p = ctx->priv = talloc_zero(ctx, struct priv);
struct vo_wayland_state *wl = ctx->vo->wl;
- if (!(p->egl_display = eglGetPlatformDisplay(EGL_PLATFORM_WAYLAND_KHR,
- wl->display, NULL)))
+ if (!(p->egl_display = mpegl_get_display(EGL_PLATFORM_WAYLAND_EXT,
+ "EGL_EXT_platform_wayland",
+ wl->display)))
return false;
if (eglInitialize(p->egl_display, NULL, NULL) != EGL_TRUE)
diff --git a/video/out/opengl/context_x11egl.c b/video/out/opengl/context_x11egl.c
index a829aad85e..812718a647 100644
--- a/video/out/opengl/context_x11egl.c
+++ b/video/out/opengl/context_x11egl.c
@@ -28,6 +28,8 @@
#include "oml_sync.h"
#include "utils.h"
+#define EGL_PLATFORM_X11_EXT 0x31D5
+
struct priv {
GL gl;
EGLDisplay egl_display;
@@ -101,8 +103,9 @@ static bool mpegl_init(struct ra_ctx *ctx)
if (!vo_x11_init(vo))
goto uninit;
- p->egl_display = eglGetPlatformDisplay(EGL_PLATFORM_X11_KHR,
- vo->x11->display, NULL);
+ p->egl_display = mpegl_get_display(EGL_PLATFORM_X11_EXT,
+ "EGL_EXT_platform_x11",
+ vo->x11->display);
if (!eglInitialize(p->egl_display, NULL, NULL)) {
MP_MSG(ctx, msgl, "Could not initialize EGL.\n");
goto uninit;
diff --git a/video/out/opengl/egl_helpers.c b/video/out/opengl/egl_helpers.c
index 29057614b2..94a0e66eca 100644
--- a/video/out/opengl/egl_helpers.c
+++ b/video/out/opengl/egl_helpers.c
@@ -277,3 +277,72 @@ void mpegl_load_functions(struct GL *gl, struct mp_log *log)
if (!gl->SwapInterval)
gl->SwapInterval = swap_interval;
}
+
+// This is similar to eglGetPlatformDisplay(platform, native_display, NULL),
+// except that it 1. may use eglGetPlatformDisplayEXT, 2. checks for the
+// platform client extension platform_ext_name, and 3. does not support passing
+// an attrib list, because the type for that parameter is different in the EXT
+// and standard functions (EGL can't not fuck up, no matter what).
+// platform: e.g. EGL_PLATFORM_X11_KHR
+// platform_ext_name: e.g. "EGL_KHR_platform_x11"
+// native_display: e.g. X11 Display*
+// Returns EGL_NO_DISPLAY on failure.
+// Warning: the EGL version can be different at runtime depending on the chosen
+// platform, so this might return a display corresponding to some older EGL
+// version (often 1.4).
+// Often, there are two extension variants of a platform (KHR and EXT). If you
+// need to check both, call this function twice. (Why do they define them twice?
+// They're crazy.)
+EGLDisplay mpegl_get_display(EGLenum platform, const char *platform_ext_name,
+ void *native_display)
+{
+ // EGL is awful. Designed as ultra-portable library, it fails at dealing
+ // with slightly more complex environment than its short-sighted design
+ // could deal with. So they invented an awful, awful kludge that modifies
+ // EGL standard behavior, the EGL_EXT_client_extensions extension. EGL 1.4
+ // normally is to return NULL when querying EGL_EXTENSIONS on EGL_NO_DISPLAY,
+ // however, with that extension, it'll return the set of "client extensions",
+ // which may include EGL_EXT_platform_base.
+
+ // Prerequisite: check the platform extension.
+ // If this is either EGL 1.5, or 1.4 with EGL_EXT_client_extensions, then
+ // this must return a valid extension string.
+ const char *exts = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
+ if (!exts || !gl_check_extension(exts, platform_ext_name))
+ return EGL_NO_DISPLAY;
+
+ // Before we go through the EGL 1.4 BS, try if we can use native EGL 1.5
+ // It appears that EGL 1.4 is specified to _require_ an initialized display
+ // for EGL_VERSION, while EGL 1.5 is _required_ to return the EGL version.
+ const char *ver = eglQueryString(EGL_NO_DISPLAY, EGL_VERSION);
+ // Of course we have to go through the excruciating pain of parsing a
+ // version string, since EGL provides no other way without a display. In
+ // theory version!=NULL is already proof enough that it's 1.5, but be
+ // extra defensive, since this should have been true for EGL_EXTENSIONS as
+ // well, but then they added an extension that modified standard behavior.
+ int ma = 0, mi = 0;
+ if (ver && sscanf(ver, "%d.%d", &ma, &mi) == 2 && (ma > 1 || mi >= 5)) {
+ // This is EGL 1.5. It must support querying standard functions through
+ // eglGetProcAddress(). Note that on EGL 1.4, even if the function is
+ // unknown, it could return non-NULL anyway (because EGL is crazy).
+ EGLDisplay (EGLAPIENTRYP GetPlatformDisplay)
+ (EGLenum, void *, const EGLAttrib *) =
+ (void *)eglGetProcAddress("eglGetPlatformDisplay");
+ // (It should be impossible to be NULL, but uh.)
+ if (GetPlatformDisplay)
+ return GetPlatformDisplay(platform, native_display, NULL);
+ }
+
+ // (It should be impossible to be missing, but uh.)
+ if (!gl_check_extension(exts, "EGL_EXT_client_extensions"))
+ return EGL_NO_DISPLAY;
+
+ EGLDisplay (EGLAPIENTRYP GetPlatformDisplayEXT)(EGLenum, void*, const EGLint*)
+ = (void *)eglGetProcAddress("eglGetPlatformDisplayEXT");
+
+ // (It should be impossible to be NULL, but uh.)
+ if (GetPlatformDisplayEXT)
+ return GetPlatformDisplayEXT(platform, native_display, NULL);
+
+ return EGL_NO_DISPLAY;
+}
diff --git a/video/out/opengl/egl_helpers.h b/video/out/opengl/egl_helpers.h
index df489daf0c..bbd274e613 100644
--- a/video/out/opengl/egl_helpers.h
+++ b/video/out/opengl/egl_helpers.h
@@ -29,4 +29,7 @@ bool mpegl_create_context_cb(struct ra_ctx *ctx, EGLDisplay display,
struct GL;
void mpegl_load_functions(struct GL *gl, struct mp_log *log);
+EGLDisplay mpegl_get_display(EGLenum platform, const char *platform_ext_name,
+ void *native_display);
+
#endif