From fcccc9dc0b95bc47c9c3460358fb1e3464695a41 Mon Sep 17 00:00:00 2001 From: Kyle Brenneman Date: Sun, 16 Apr 2017 11:12:05 -0600 Subject: [PATCH] Use eglGetPlatformDisplay when it's available. Added a platform parameter to egl_init_context. If the caller provides a platform other than EGL_NONE, then it will try to use eglGetPlatformDisplay or eglGetPlatformDisplayEXT instead of eglGetDisplay. If neither eglGetPlatformDisplay or eglGetPlatformDisplayEXT is supported, then it will still fall back to calling eglGetDisplay. Updated the Wayland, X11, and DRM callers to use the correct platform enum. Those are the callers that don't just pass EGL_DEFAULT_DISPLAY as the native display handle. Calling eglGetDisplay with any value other than EGL_DEFAULT_DISPLAY is inherently unreliable, because it requires the EGL implementation to guess a platform type based on a (void *) pointer. Some implementations might not identify a particular platform, or worse, might guess wrong. Fixes https://github.com/libretro/RetroArch/issues/4790 --- gfx/common/egl_common.c | 119 ++++++++++++++++++++- gfx/common/egl_common.h | 1 + gfx/drivers_context/android_ctx.c | 2 +- gfx/drivers_context/drm_ctx.c | 3 +- gfx/drivers_context/emscriptenegl_ctx.c | 2 +- gfx/drivers_context/mali_fbdev_ctx.c | 2 +- gfx/drivers_context/opendingux_fbdev_ctx.c | 2 +- gfx/drivers_context/qnx_ctx.c | 2 +- gfx/drivers_context/vc_egl_ctx.c | 2 +- gfx/drivers_context/vivante_fbdev_ctx.c | 2 +- gfx/drivers_context/wayland_ctx.c | 1 + gfx/drivers_context/xegl_ctx.c | 4 +- 12 files changed, 131 insertions(+), 11 deletions(-) diff --git a/gfx/common/egl_common.c b/gfx/common/egl_common.c index db76d0c9f1..bdcddf8bad 100644 --- a/gfx/common/egl_common.c +++ b/gfx/common/egl_common.c @@ -208,12 +208,129 @@ void egl_get_video_size(egl_ctx_data_t *egl, unsigned *width, unsigned *height) } } +static bool check_egl_version(int minMajorVersion, int minMinorVersion) +{ + const char *str = eglQueryString(EGL_NO_DISPLAY, EGL_VERSION); + int major, minor; + int count; + + if (str == NULL) + { + return false; + } + + count = sscanf(str, "%d.%d", &major, &minor); + if (count != 2) + { + return false; + } + + if (major < minMajorVersion) + { + return false; + } + else if (major > minMajorVersion) + { + return true; + } + else if (minor >= minMinorVersion) + { + return true; + } + else + { + return false; + } +} + +static bool check_egl_client_extension(const char *name) +{ + const char *str; + size_t nameLen; + + str = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); + if (str == NULL) + { + // The EGL implementation doesn't support client extensions at all. + return false; + } + + nameLen = strlen(name); + while (*str != '\0') + { + // Use strspn and strcspn to find the start position and length of each + // token in the extension string. Using strtok could also work, but + // that would require allocating a copy of the string. + size_t len = strcspn(str, " "); + if (len == nameLen && strncmp(str, name, nameLen) == 0) + { + return true; + } + str += len; + str += strspn(str, " "); + } + + return false; +} + +static EGLDisplay get_egl_display(EGLenum platform, void *native) +{ + if (platform != EGL_NONE) + { + // If the client library supports at least EGL 1.5, then we can call + // eglGetPlatformDisplay. Otherwise, see if eglGetPlatformDisplayEXT + // is available. + if (check_egl_version(1, 5)) + { + typedef EGLDisplay (EGLAPIENTRY * pfn_eglGetPlatformDisplay) + (EGLenum platform, void *native_display, const EGLAttrib *attrib_list); + pfn_eglGetPlatformDisplay ptr_eglGetPlatformDisplay; + + RARCH_LOG("[EGL] Found EGL client version >= 1.5, trying eglGetPlatformDisplay\n"); + ptr_eglGetPlatformDisplay = (pfn_eglGetPlatformDisplay) + eglGetProcAddress("eglGetPlatformDisplay"); + if (ptr_eglGetPlatformDisplay != NULL) + { + EGLDisplay dpy = ptr_eglGetPlatformDisplay(platform, native, NULL); + if (dpy != EGL_NO_DISPLAY) + { + return dpy; + } + } + } + + if (check_egl_client_extension("EGL_EXT_platform_base")) + { + PFNEGLGETPLATFORMDISPLAYEXTPROC ptr_eglGetPlatformDisplayEXT; + + RARCH_LOG("[EGL] Found EGL_EXT_platform_base, trying eglGetPlatformDisplayEXT\n"); + ptr_eglGetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC) + eglGetProcAddress("eglGetPlatformDisplayEXT"); + if (ptr_eglGetPlatformDisplayEXT != NULL) + { + EGLDisplay dpy = ptr_eglGetPlatformDisplayEXT(platform, native, NULL); + if (dpy != EGL_NO_DISPLAY) + { + return dpy; + } + } + } + } + + // Either the caller didn't provide a platform type, or the EGL + // implementation doesn't support eglGetPlatformDisplay. In this case, try + // eglGetDisplay and hope for the best. + RARCH_LOG("[EGL] Falling back to eglGetDisplay\n"); + return eglGetDisplay((EGLNativeDisplayType) native); +} + bool egl_init_context(egl_ctx_data_t *egl, + EGLenum platform, void *display_data, EGLint *major, EGLint *minor, EGLint *n, const EGLint *attrib_ptr) { - EGLDisplay dpy = (NativeDisplayType)eglGetDisplay((EGLNativeDisplayType)display_data); + EGLDisplay dpy = get_egl_display(platform, display_data); if (dpy == EGL_NO_DISPLAY) { RARCH_ERR("[EGL]: Couldn't get EGL display.\n"); diff --git a/gfx/common/egl_common.h b/gfx/common/egl_common.h index 6df02a5f39..5e1dbc8ad1 100644 --- a/gfx/common/egl_common.h +++ b/gfx/common/egl_common.h @@ -89,6 +89,7 @@ void egl_set_swap_interval(egl_ctx_data_t *egl, unsigned interval); void egl_get_video_size(egl_ctx_data_t *egl, unsigned *width, unsigned *height); bool egl_init_context(egl_ctx_data_t *egl, + EGLenum platform, void *display_data, EGLint *major, EGLint *minor, diff --git a/gfx/drivers_context/android_ctx.c b/gfx/drivers_context/android_ctx.c index 13e6e66ca7..b721c8467b 100644 --- a/gfx/drivers_context/android_ctx.c +++ b/gfx/drivers_context/android_ctx.c @@ -143,7 +143,7 @@ static void *android_gfx_ctx_init(video_frame_info_t *video_info, void *video_dr #ifdef HAVE_EGL RARCH_LOG("Android EGL: GLES version = %d.\n", g_es3 ? 3 : 2); - if (!egl_init_context(&and->egl, EGL_DEFAULT_DISPLAY, + if (!egl_init_context(&and->egl, EGL_NONE, EGL_DEFAULT_DISPLAY, &major, &minor, &n, attribs)) { egl_report_error(); diff --git a/gfx/drivers_context/drm_ctx.c b/gfx/drivers_context/drm_ctx.c index ae61ccb819..4f9391e211 100644 --- a/gfx/drivers_context/drm_ctx.c +++ b/gfx/drivers_context/drm_ctx.c @@ -563,7 +563,8 @@ static bool gfx_ctx_drm_egl_set_video_mode(gfx_ctx_drm_data_t *drm) case GFX_CTX_OPENGL_ES_API: case GFX_CTX_OPENVG_API: #ifdef HAVE_EGL - if (!egl_init_context(&drm->egl, (EGLNativeDisplayType)g_gbm_dev, &major, + if (!egl_init_context(&drm->egl, EGL_PLATFORM_GBM_KHR, + (EGLNativeDisplayType)g_gbm_dev, &major, &minor, &n, attrib_ptr)) goto error; diff --git a/gfx/drivers_context/emscriptenegl_ctx.c b/gfx/drivers_context/emscriptenegl_ctx.c index 6d6c50cf86..8212507112 100644 --- a/gfx/drivers_context/emscriptenegl_ctx.c +++ b/gfx/drivers_context/emscriptenegl_ctx.c @@ -135,7 +135,7 @@ static void *gfx_ctx_emscripten_init(video_frame_info_t *video_info, void *video return (void*)"emscripten"; } - if (!egl_init_context(&emscripten->egl, EGL_DEFAULT_DISPLAY, + if (!egl_init_context(&emscripten->egl, EGL_NONE, EGL_DEFAULT_DISPLAY, &major, &minor, &n, attribute_list)) { egl_report_error(); diff --git a/gfx/drivers_context/mali_fbdev_ctx.c b/gfx/drivers_context/mali_fbdev_ctx.c index 5d8b9d3d6c..12b8ce430f 100644 --- a/gfx/drivers_context/mali_fbdev_ctx.c +++ b/gfx/drivers_context/mali_fbdev_ctx.c @@ -116,7 +116,7 @@ static void *gfx_ctx_mali_fbdev_init(video_frame_info_t *video_info, void *video #endif #ifdef HAVE_EGL - if (!egl_init_context(&mali->egl, EGL_DEFAULT_DISPLAY, + if (!egl_init_context(&mali->egl, EGL_NONE, EGL_DEFAULT_DISPLAY, &major, &minor, &n, attribs)) { egl_report_error(); diff --git a/gfx/drivers_context/opendingux_fbdev_ctx.c b/gfx/drivers_context/opendingux_fbdev_ctx.c index 3af8154f97..9cccc1ac51 100644 --- a/gfx/drivers_context/opendingux_fbdev_ctx.c +++ b/gfx/drivers_context/opendingux_fbdev_ctx.c @@ -83,7 +83,7 @@ static void *gfx_ctx_opendingux_init(video_frame_info_t *video_info, void *video #ifdef HAVE_EGL frontend_driver_install_signal_handler(); - if (!egl_init_context(&viv->egl, EGL_DEFAULT_DISPLAY, + if (!egl_init_context(&viv->egl, EGL_NONE, EGL_DEFAULT_DISPLAY, &major, &minor, &n, attribs)) { diff --git a/gfx/drivers_context/qnx_ctx.c b/gfx/drivers_context/qnx_ctx.c index 3ac5c734fb..37c9b654fb 100644 --- a/gfx/drivers_context/qnx_ctx.c +++ b/gfx/drivers_context/qnx_ctx.c @@ -131,7 +131,7 @@ static void *gfx_ctx_qnx_init(video_frame_info_t *video_info, void *video_driver #ifdef HAVE_EGL - if (!egl_init_context(&qnx->egl, EGL_DEFAULT_DISPLAY, &major, &minor, + if (!egl_init_context(&qnx->egl, EGL_NONE, EGL_DEFAULT_DISPLAY, &major, &minor, &n, attribs)) { egl_report_error(); diff --git a/gfx/drivers_context/vc_egl_ctx.c b/gfx/drivers_context/vc_egl_ctx.c index a9fa66f247..26e5eea378 100644 --- a/gfx/drivers_context/vc_egl_ctx.c +++ b/gfx/drivers_context/vc_egl_ctx.c @@ -183,7 +183,7 @@ static void *gfx_ctx_vc_init(video_frame_info_t *video_info, void *video_driver) bcm_host_init(); #ifdef HAVE_EGL - if (!egl_init_context(&vc->egl, EGL_DEFAULT_DISPLAY, + if (!egl_init_context(&vc->egl, EGL_NONE, EGL_DEFAULT_DISPLAY, &major, &minor, &n, attribute_list)) { egl_report_error(); diff --git a/gfx/drivers_context/vivante_fbdev_ctx.c b/gfx/drivers_context/vivante_fbdev_ctx.c index 88a9edb0e7..6d8e0728f5 100644 --- a/gfx/drivers_context/vivante_fbdev_ctx.c +++ b/gfx/drivers_context/vivante_fbdev_ctx.c @@ -90,7 +90,7 @@ static void *gfx_ctx_vivante_init(video_frame_info_t *video_info, void *video_dr system("setterm -cursor off"); #ifdef HAVE_EGL - if (!egl_init_context(&viv->egl, EGL_DEFAULT_DISPLAY, &major, &minor, + if (!egl_init_context(&viv->egl, EGL_NONE, EGL_DEFAULT_DISPLAY, &major, &minor, &n, attribs)) { egl_report_error(); diff --git a/gfx/drivers_context/wayland_ctx.c b/gfx/drivers_context/wayland_ctx.c index 138d2b5537..6b1ac60e5e 100644 --- a/gfx/drivers_context/wayland_ctx.c +++ b/gfx/drivers_context/wayland_ctx.c @@ -900,6 +900,7 @@ static void *gfx_ctx_wl_init(video_frame_info_t *video_info, void *video_driver) case GFX_CTX_OPENVG_API: #ifdef HAVE_EGL if (!egl_init_context(&wl->egl, + EGL_PLATFORM_WAYLAND_KHR, (EGLNativeDisplayType)wl->dpy, &major, &minor, &n, attrib_ptr)) { diff --git a/gfx/drivers_context/xegl_ctx.c b/gfx/drivers_context/xegl_ctx.c index 07977f5f25..08b57c9c70 100644 --- a/gfx/drivers_context/xegl_ctx.c +++ b/gfx/drivers_context/xegl_ctx.c @@ -163,8 +163,8 @@ static void *gfx_ctx_xegl_init(video_frame_info_t *video_info, void *video_drive goto error; #ifdef HAVE_EGL - if (!egl_init_context(&xegl->egl, (EGLNativeDisplayType)g_x11_dpy, - &major, &minor, &n, attrib_ptr)) + if (!egl_init_context(&xegl->egl, EGL_PLATFORM_X11_KHR, + (EGLNativeDisplayType)g_x11_dpy, &major, &minor, &n, attrib_ptr)) { egl_report_error(); goto error;