diff options
Diffstat (limited to 'video/out/opengl/egl_helpers.c')
-rw-r--r-- | video/out/opengl/egl_helpers.c | 173 |
1 files changed, 103 insertions, 70 deletions
diff --git a/video/out/opengl/egl_helpers.c b/video/out/opengl/egl_helpers.c index ad026ba253..18d9027762 100644 --- a/video/out/opengl/egl_helpers.c +++ b/video/out/opengl/egl_helpers.c @@ -41,10 +41,18 @@ #define EGL_CONTEXT_OPENGL_PROFILE_MASK 0x30FD #define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT 0x00000001 #define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE 0x31B1 -#define EGL_OPENGL_ES3_BIT 0x00000040 typedef intptr_t EGLAttrib; #endif +// Not every EGL provider (like RPI) has these. +#ifndef EGL_CONTEXT_FLAGS_KHR +#define EGL_CONTEXT_FLAGS_KHR EGL_NONE +#endif + +#ifndef EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR +#define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0 +#endif + struct mp_egl_config_attr { int attrib; const char *name; @@ -78,9 +86,22 @@ static void dump_egl_config(struct mp_log *log, int msgl, EGLDisplay display, } } -// es_version: 0 (core), 2 or 3 +static void *mpegl_get_proc_address(void *ctx, const char *name) +{ + void *p = eglGetProcAddress(name); +#if defined(__GLIBC__) && HAVE_LIBDL + // Some crappy ARM/Linux things do not provide EGL 1.5, so above call does + // not necessarily return function pointers for core functions. Try to get + // them from a loaded GLES lib. As POSIX leaves RTLD_DEFAULT "reserved", + // use it only with glibc. + if (!p) + p = dlsym(RTLD_DEFAULT, name); +#endif + return p; +} + static bool create_context(struct ra_ctx *ctx, EGLDisplay display, - int es_version, struct mpegl_cb cb, + bool es, struct mpegl_cb cb, EGLContext *out_context, EGLConfig *out_config) { int msgl = ctx->opts.probing ? MSGL_V : MSGL_FATAL; @@ -89,23 +110,14 @@ static bool create_context(struct ra_ctx *ctx, EGLDisplay display, EGLint rend; const char *name; - switch (es_version) { - case 0: + if (!es) { api = EGL_OPENGL_API; rend = EGL_OPENGL_BIT; name = "Desktop OpenGL"; - break; - case 2: + } else { api = EGL_OPENGL_ES_API; rend = EGL_OPENGL_ES2_BIT; - name = "GLES 2.x"; - break; - case 3: - api = EGL_OPENGL_ES_API; - rend = EGL_OPENGL_ES3_BIT; - name = "GLES 3.x"; - break; - default: abort(); + name = "GLES 2.x +"; } MP_VERBOSE(ctx, "Trying to create %s context.\n", name); @@ -120,7 +132,7 @@ static bool create_context(struct ra_ctx *ctx, EGLDisplay display, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, - EGL_ALPHA_SIZE, ctx->opts.want_alpha ? 1 : 0, + EGL_ALPHA_SIZE, ctx->opts.want_alpha ? 8 : 0, EGL_RENDERABLE_TYPE, rend, EGL_NONE }; @@ -157,29 +169,19 @@ static bool create_context(struct ra_ctx *ctx, EGLDisplay display, MP_DBG(ctx, "Chosen EGLConfig:\n"); dump_egl_config(ctx->log, MSGL_DEBUG, display, config); + int ctx_flags = ctx->opts.debug ? EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR : 0; EGLContext *egl_ctx = NULL; - if (es_version) { - if (!ra_gl_ctx_test_version(ctx, MPGL_VER(es_version, 0), true)) - return false; - - EGLint attrs[] = { - EGL_CONTEXT_CLIENT_VERSION, es_version, - EGL_NONE - }; - - egl_ctx = eglCreateContext(display, config, EGL_NO_CONTEXT, attrs); - } else { - for (int n = 0; mpgl_preferred_gl_versions[n]; n++) { - int ver = mpgl_preferred_gl_versions[n]; - if (!ra_gl_ctx_test_version(ctx, ver, false)) - continue; + if (!es) { + for (int n = 0; mpgl_min_required_gl_versions[n]; n++) { + int ver = mpgl_min_required_gl_versions[n]; EGLint attrs[] = { EGL_CONTEXT_MAJOR_VERSION, MPGL_VER_GET_MAJOR(ver), EGL_CONTEXT_MINOR_VERSION, MPGL_VER_GET_MINOR(ver), EGL_CONTEXT_OPENGL_PROFILE_MASK, ver >= 320 ? EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT : 0, + EGL_CONTEXT_FLAGS_KHR, ctx_flags, EGL_NONE }; @@ -187,17 +189,23 @@ static bool create_context(struct ra_ctx *ctx, EGLDisplay display, if (egl_ctx) break; } + } + if (!egl_ctx) { + // Fallback for EGL 1.4 without EGL_KHR_create_context or GLES + EGLint attrs[] = { + EGL_CONTEXT_FLAGS_KHR, ctx_flags, + es ? EGL_CONTEXT_CLIENT_VERSION : EGL_NONE, 2, + EGL_NONE + }; - if (!egl_ctx && ra_gl_ctx_test_version(ctx, 140, false)) { - // Fallback for EGL 1.4 without EGL_KHR_create_context. - EGLint attrs[] = { EGL_NONE }; - - egl_ctx = eglCreateContext(display, config, EGL_NO_CONTEXT, attrs); - } + egl_ctx = eglCreateContext(display, config, EGL_NO_CONTEXT, attrs); + if (!egl_ctx) + egl_ctx = eglCreateContext(display, config, EGL_NO_CONTEXT, &attrs[2]); } if (!egl_ctx) { - MP_MSG(ctx, msgl, "Could not create EGL context for %s!\n", name); + MP_MSG(ctx, msgl, "Could not create EGL context for %s (error=%d)!\n", + name, eglGetError()); return false; } @@ -233,11 +241,15 @@ bool mpegl_create_context_cb(struct ra_ctx *ctx, EGLDisplay display, MP_VERBOSE(ctx, "EGL_VERSION=%s\nEGL_VENDOR=%s\nEGL_CLIENT_APIS=%s\n", STR_OR_ERR(version), STR_OR_ERR(vendor), STR_OR_ERR(apis)); - int es[] = {0, 3, 2}; // preference order - for (int i = 0; i < MP_ARRAY_SIZE(es); i++) { - if (create_context(ctx, display, es[i], cb, out_context, out_config)) - return true; - } + enum gles_mode mode = ra_gl_ctx_get_glesmode(ctx); + + if ((mode == GLES_NO || mode == GLES_AUTO) && + create_context(ctx, display, false, cb, out_context, out_config)) + return true; + + if ((mode == GLES_YES || mode == GLES_AUTO) && + create_context(ctx, display, true, cb, out_context, out_config)) + return true; int msgl = ctx->opts.probing ? MSGL_V : MSGL_ERR; MP_MSG(ctx, msgl, "Could not create a GL context.\n"); @@ -252,20 +264,6 @@ static int GLAPIENTRY swap_interval(int interval) return !eglSwapInterval(display, interval); } -static void *mpegl_get_proc_address(void *ctx, const char *name) -{ - void *p = eglGetProcAddress(name); -#if defined(__GLIBC__) && HAVE_LIBDL - // Some crappy ARM/Linux things do not provide EGL 1.5, so above call does - // not necessarily return function pointers for core functions. Try to get - // them from a loaded GLES lib. As POSIX leaves RTLD_DEFAULT "reserved", - // use it only with glibc. - if (!p) - p = dlsym(RTLD_DEFAULT, name); -#endif - return p; -} - // Load gl version and function pointers into *gl. // Expects a current EGL context set. void mpegl_load_functions(struct GL *gl, struct mp_log *log) @@ -280,6 +278,20 @@ void mpegl_load_functions(struct GL *gl, struct mp_log *log) gl->SwapInterval = swap_interval; } +static bool is_egl15(void) +{ + // 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; + return ver && sscanf(ver, "%d.%d", &ma, &mi) == 2 && (ma > 1 || mi >= 5); +} + // 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 @@ -310,20 +322,11 @@ EGLDisplay mpegl_get_display(EGLenum platform, const char *platform_ext_name, // 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)) + if (!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)) { + if (is_egl15()) { // 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). @@ -335,8 +338,7 @@ EGLDisplay mpegl_get_display(EGLenum platform, const char *platform_ext_name, return GetPlatformDisplay(platform, native_display, NULL); } - // (It should be impossible to be missing, but uh.) - if (!gl_check_extension(exts, "EGL_EXT_client_extensions")) + if (!gl_check_extension(exts, "EGL_EXT_platform_base")) return EGL_NO_DISPLAY; EGLDisplay (EGLAPIENTRYP GetPlatformDisplayEXT)(EGLenum, void*, const EGLint*) @@ -348,3 +350,34 @@ EGLDisplay mpegl_get_display(EGLenum platform, const char *platform_ext_name, return EGL_NO_DISPLAY; } + +// The same mess but with eglCreatePlatformWindowSurface(EXT) +// again no support for an attribute list because the type differs +// Returns EGL_NO_SURFACE on failure. +EGLSurface mpegl_create_window_surface(EGLDisplay dpy, EGLConfig config, + void *native_window) +{ + // Use the EGL 1.5 function if possible + if (is_egl15()) { + EGLSurface (EGLAPIENTRYP CreatePlatformWindowSurface) + (EGLDisplay, EGLConfig, void *, const EGLAttrib *) = + (void *)eglGetProcAddress("eglCreatePlatformWindowSurface"); + // (It should be impossible to be NULL, but uh.) + if (CreatePlatformWindowSurface) + return CreatePlatformWindowSurface(dpy, config, native_window, NULL); + } + + // Check the extension that provides the *EXT function + const char *exts = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); + if (!gl_check_extension(exts, "EGL_EXT_platform_base")) + return EGL_NO_SURFACE; + + EGLSurface (EGLAPIENTRYP CreatePlatformWindowSurfaceEXT) + (EGLDisplay, EGLConfig, void *, const EGLint *) = + (void *)eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT"); + // (It should be impossible to be NULL, but uh.) + if (CreatePlatformWindowSurfaceEXT) + return CreatePlatformWindowSurfaceEXT(dpy, config, native_window, NULL); + + return EGL_NO_SURFACE; +} |