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
This commit is contained in:
Kyle Brenneman 2017-04-16 11:12:05 -06:00
parent f21bb4d0dc
commit fcccc9dc0b
12 changed files with 131 additions and 11 deletions

View File

@ -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");

View File

@ -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,

View File

@ -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();

View File

@ -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;

View File

@ -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();

View File

@ -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();

View File

@ -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))
{

View File

@ -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();

View File

@ -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();

View File

@ -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();

View File

@ -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))
{

View File

@ -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;