SDL: Merge pull request #6317 from tycho/wip/angle-egl

From 5a7c20b945da35dcb0fc8baf659f12a409ac9804 Mon Sep 17 00:00:00 2001
From: Steven Noonan <[EMAIL REDACTED]>
Date: Thu, 25 Aug 2022 19:35:41 -0700
Subject: [PATCH 1/9] hints: replace SDL_HINT_VIDEO_X11_FORCE_EGL with
 platform-agnostic SDL_HINT_VIDEO_FORCE_EGL

This adds support for forcing the use of EGL on Windows and MacOS. The
SDL_HINT_VIDEO_X11_FORCE_EGL hint is retained for backwards
compatibility but is now deprecated.
---
 include/SDL_hints.h                  | 15 ++++++++++++++
 src/video/SDL_egl.c                  |  2 +-
 src/video/cocoa/SDL_cocoavideo.m     | 27 ++++++++++++++++----------
 src/video/windows/SDL_windowsvideo.c | 29 +++++++++++++++++-----------
 src/video/x11/SDL_x11opengl.c        |  4 +++-
 src/video/x11/SDL_x11opengles.c      |  1 +
 src/video/x11/SDL_x11video.c         |  3 ++-
 src/video/x11/SDL_x11window.c        |  1 +
 8 files changed, 58 insertions(+), 24 deletions(-)

diff --git a/include/SDL_hints.h b/include/SDL_hints.h
index ce2225440fb3..2175cf11f360 100644
--- a/include/SDL_hints.h
+++ b/include/SDL_hints.h
@@ -1802,6 +1802,18 @@ extern "C" {
 */
 #define SDL_HINT_VIDEO_WIN_D3DCOMPILER              "SDL_VIDEO_WIN_D3DCOMPILER"
 
+/**
+ * \brief A variable controlling whether the OpenGL context should be created
+ * with EGL by default
+ *
+ * This variable can be set to the following values:
+ * "0" - Use platform-specific GL context creation API (GLX, WGL, CGL, etc)
+ * "1" - Use EGL
+ *
+ * By default SDL will use the platform-specific GL context API when both are present.
+ */
+#define SDL_HINT_VIDEO_FORCE_EGL "SDL_VIDEO_FORCE_EGL"
+
 /**
  * \brief A variable controlling whether X11 should use GLX or EGL by default
  *
@@ -1810,6 +1822,9 @@ extern "C" {
  * "1" - Use EGL
  *
  * By default SDL will use GLX when both are present.
+ *
+ * \deprecated Use the platform-agnostic SDL_HINT_VIDEO_FORCE_EGL hint instead.
+ *
  */
 #define SDL_HINT_VIDEO_X11_FORCE_EGL "SDL_VIDEO_X11_FORCE_EGL"
 
diff --git a/src/video/SDL_egl.c b/src/video/SDL_egl.c
index 28d02b132c62..a0e78b2bace5 100644
--- a/src/video/SDL_egl.c
+++ b/src/video/SDL_egl.c
@@ -506,7 +506,7 @@ SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_displa
          * Khronos doc: "EGL_BAD_DISPLAY is generated if display is not an EGL display connection, unless display is EGL_NO_DISPLAY and name is EGL_EXTENSIONS."
          * Therefore SDL_EGL_GetVersion() shouldn't work with uninitialized display.
          * - it actually doesn't work on Android that has 1.5 egl client
-         * - it works on desktop X11 (using SDL_VIDEO_X11_FORCE_EGL=1) */
+         * - it works on desktop X11 (using SDL_VIDEO_FORCE_EGL=1) */
         SDL_EGL_GetVersion(_this);
 
         if (_this->egl_data->egl_version_major == 1 && _this->egl_data->egl_version_minor == 5) {
diff --git a/src/video/cocoa/SDL_cocoavideo.m b/src/video/cocoa/SDL_cocoavideo.m
index 6c3d44efae17..d95718433919 100644
--- a/src/video/cocoa/SDL_cocoavideo.m
+++ b/src/video/cocoa/SDL_cocoavideo.m
@@ -139,16 +139,23 @@ @implementation SDL_VideoData
     device->GL_GetSwapInterval = Cocoa_GL_GetSwapInterval;
     device->GL_SwapWindow = Cocoa_GL_SwapWindow;
     device->GL_DeleteContext = Cocoa_GL_DeleteContext;
-#elif SDL_VIDEO_OPENGL_EGL
-    device->GL_LoadLibrary = Cocoa_GLES_LoadLibrary;
-    device->GL_GetProcAddress = Cocoa_GLES_GetProcAddress;
-    device->GL_UnloadLibrary = Cocoa_GLES_UnloadLibrary;
-    device->GL_CreateContext = Cocoa_GLES_CreateContext;
-    device->GL_MakeCurrent = Cocoa_GLES_MakeCurrent;
-    device->GL_SetSwapInterval = Cocoa_GLES_SetSwapInterval;
-    device->GL_GetSwapInterval = Cocoa_GLES_GetSwapInterval;
-    device->GL_SwapWindow = Cocoa_GLES_SwapWindow;
-    device->GL_DeleteContext = Cocoa_GLES_DeleteContext;
+#endif
+#if SDL_VIDEO_OPENGL_EGL
+#if SDL_VIDEO_OPENGL_CGL
+    if (SDL_GetHintBoolean(SDL_HINT_VIDEO_FORCE_EGL, SDL_FALSE)) {
+#endif
+        device->GL_LoadLibrary = Cocoa_GLES_LoadLibrary;
+        device->GL_GetProcAddress = Cocoa_GLES_GetProcAddress;
+        device->GL_UnloadLibrary = Cocoa_GLES_UnloadLibrary;
+        device->GL_CreateContext = Cocoa_GLES_CreateContext;
+        device->GL_MakeCurrent = Cocoa_GLES_MakeCurrent;
+        device->GL_SetSwapInterval = Cocoa_GLES_SetSwapInterval;
+        device->GL_GetSwapInterval = Cocoa_GLES_GetSwapInterval;
+        device->GL_SwapWindow = Cocoa_GLES_SwapWindow;
+        device->GL_DeleteContext = Cocoa_GLES_DeleteContext;
+#if SDL_VIDEO_OPENGL_CGL
+    }
+#endif
 #endif
 
 #if SDL_VIDEO_VULKAN
diff --git a/src/video/windows/SDL_windowsvideo.c b/src/video/windows/SDL_windowsvideo.c
index 0dc107bdf240..bdf887bdb902 100644
--- a/src/video/windows/SDL_windowsvideo.c
+++ b/src/video/windows/SDL_windowsvideo.c
@@ -226,17 +226,24 @@ WIN_CreateDevice(void)
     device->GL_GetSwapInterval = WIN_GL_GetSwapInterval;
     device->GL_SwapWindow = WIN_GL_SwapWindow;
     device->GL_DeleteContext = WIN_GL_DeleteContext;
-#elif SDL_VIDEO_OPENGL_EGL
-    /* Use EGL based functions */
-    device->GL_LoadLibrary = WIN_GLES_LoadLibrary;
-    device->GL_GetProcAddress = WIN_GLES_GetProcAddress;
-    device->GL_UnloadLibrary = WIN_GLES_UnloadLibrary;
-    device->GL_CreateContext = WIN_GLES_CreateContext;
-    device->GL_MakeCurrent = WIN_GLES_MakeCurrent;
-    device->GL_SetSwapInterval = WIN_GLES_SetSwapInterval;
-    device->GL_GetSwapInterval = WIN_GLES_GetSwapInterval;
-    device->GL_SwapWindow = WIN_GLES_SwapWindow;
-    device->GL_DeleteContext = WIN_GLES_DeleteContext;
+#endif
+#if SDL_VIDEO_OPENGL_EGL
+#if SDL_VIDEO_OPENGL_WGL
+    if (SDL_GetHintBoolean(SDL_HINT_VIDEO_FORCE_EGL, SDL_FALSE)) {
+#endif
+        /* Use EGL based functions */
+        device->GL_LoadLibrary = WIN_GLES_LoadLibrary;
+        device->GL_GetProcAddress = WIN_GLES_GetProcAddress;
+        device->GL_UnloadLibrary = WIN_GLES_UnloadLibrary;
+        device->GL_CreateContext = WIN_GLES_CreateContext;
+        device->GL_MakeCurrent = WIN_GLES_MakeCurrent;
+        device->GL_SetSwapInterval = WIN_GLES_SetSwapInterval;
+        device->GL_GetSwapInterval = WIN_GLES_GetSwapInterval;
+        device->GL_SwapWindow = WIN_GLES_SwapWindow;
+        device->GL_DeleteContext = WIN_GLES_DeleteContext;
+#if SDL_VIDEO_OPENGL_WGL
+    }
+#endif
 #endif
 #if SDL_VIDEO_VULKAN
     device->Vulkan_LoadLibrary = WIN_Vulkan_LoadLibrary;
diff --git a/src/video/x11/SDL_x11opengl.c b/src/video/x11/SDL_x11opengl.c
index 60b2203cdf68..8c728ea97083 100644
--- a/src/video/x11/SDL_x11opengl.c
+++ b/src/video/x11/SDL_x11opengl.c
@@ -253,6 +253,7 @@ X11_GL_LoadLibrary(_THIS, const char *path)
      * GLX_EXT_create_context_es2_profile extension, switch over to X11_GLES functions  
      */
     if (((_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) ||
+         SDL_GetHintBoolean(SDL_HINT_VIDEO_FORCE_EGL, SDL_FALSE) ||
          SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_FORCE_EGL, SDL_FALSE)) &&
         X11_GL_UseEGL(_this) ) {
 #if SDL_VIDEO_OPENGL_EGL
@@ -691,7 +692,8 @@ SDL_bool
 X11_GL_UseEGL(_THIS)
 {
     SDL_assert(_this->gl_data != NULL);
-    if (SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_FORCE_EGL, SDL_FALSE))
+    if (SDL_GetHintBoolean(SDL_HINT_VIDEO_FORCE_EGL, SDL_FALSE) ||
+        SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_FORCE_EGL, SDL_FALSE))
     {
         /* use of EGL has been requested, even for desktop GL */
         return SDL_TRUE;
diff --git a/src/video/x11/SDL_x11opengles.c b/src/video/x11/SDL_x11opengles.c
index e1ec4e4d2a26..7641a6cc6466 100644
--- a/src/video/x11/SDL_x11opengles.c
+++ b/src/video/x11/SDL_x11opengles.c
@@ -36,6 +36,7 @@ X11_GLES_LoadLibrary(_THIS, const char *path)
 
     /* If the profile requested is not GL ES, switch over to X11_GL functions  */
     if ((_this->gl_config.profile_mask != SDL_GL_CONTEXT_PROFILE_ES) &&
+        !SDL_GetHintBoolean(SDL_HINT_VIDEO_FORCE_EGL, SDL_FALSE) &&
         !SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_FORCE_EGL, SDL_FALSE)) {
         #if SDL_VIDEO_OPENGL_GLX
         X11_GLES_UnloadLibrary(_this);
diff --git a/src/video/x11/SDL_x11video.c b/src/video/x11/SDL_x11video.c
index 2e5e190bd0cb..569e995f3d3a 100644
--- a/src/video/x11/SDL_x11video.c
+++ b/src/video/x11/SDL_x11video.c
@@ -282,7 +282,8 @@ X11_CreateDevice(void)
 #endif
 #if SDL_VIDEO_OPENGL_EGL
 #if SDL_VIDEO_OPENGL_GLX
-    if (SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_FORCE_EGL, SDL_FALSE)) {
+    if (SDL_GetHintBoolean(SDL_HINT_VIDEO_FORCE_EGL, SDL_FALSE) ||
+        SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_FORCE_EGL, SDL_FALSE)) {
 #endif
         device->GL_LoadLibrary = X11_GLES_LoadLibrary;
         device->GL_GetProcAddress = X11_GLES_GetProcAddress;
diff --git a/src/video/x11/SDL_x11window.c b/src/video/x11/SDL_x11window.c
index 9b007e79d782..8e08be753f17 100644
--- a/src/video/x11/SDL_x11window.c
+++ b/src/video/x11/SDL_x11window.c
@@ -429,6 +429,7 @@ X11_CreateWindow(_THIS, SDL_Window * window)
 
 #if SDL_VIDEO_OPENGL_EGL
         if (((_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) ||
+             SDL_GetHintBoolean(SDL_HINT_VIDEO_FORCE_EGL, SDL_FALSE) ||
              SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_FORCE_EGL, SDL_FALSE))
 #if SDL_VIDEO_OPENGL_GLX            
             && ( !_this->gl_data || X11_GL_UseEGL(_this) )

From aed980526c1c9e794cc4b839072dace087ad3b95 Mon Sep 17 00:00:00 2001
From: Steven Noonan <steven@valvesoftware.com>
Date: Thu, 25 Aug 2022 20:22:52 -0700
Subject: [PATCH 2/9] SDL_video: defer destroying window until GL/EGL/Vulkan
 unloaded

---
 src/video/SDL_video.c | 32 ++++++++++++++++----------------
 1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c
index 7994c1943241..0bb5f0e9c2b4 100644
--- a/src/video/SDL_video.c
+++ b/src/video/SDL_video.c
@@ -1904,16 +1904,6 @@ SDL_RecreateWindow(SDL_Window * window, Uint32 flags)
         window->surface_valid = SDL_FALSE;
     }
 
-    if (_this->checked_texture_framebuffer) { /* never checked? No framebuffer to destroy. Don't risk calling the wrong implementation. */
-        if (_this->DestroyWindowFramebuffer) {
-            _this->DestroyWindowFramebuffer(_this, window);
-        }
-    }
-
-    if (_this->DestroyWindow && !(flags & SDL_WINDOW_FOREIGN)) {
-        _this->DestroyWindow(_this, window);
-    }
-
     if ((window->flags & SDL_WINDOW_OPENGL) != (flags & SDL_WINDOW_OPENGL)) {
         if (flags & SDL_WINDOW_OPENGL) {
             need_gl_load = SDL_TRUE;
@@ -1956,6 +1946,16 @@ SDL_RecreateWindow(SDL_Window * window, Uint32 flags)
         SDL_Vulkan_UnloadLibrary();
     }
 
+    if (_this->checked_texture_framebuffer) { /* never checked? No framebuffer to destroy. Don't risk calling the wrong implementation. */
+        if (_this->DestroyWindowFramebuffer) {
+            _this->DestroyWindowFramebuffer(_this, window);
+        }
+    }
+
+    if (_this->DestroyWindow && !(flags & SDL_WINDOW_FOREIGN)) {
+        _this->DestroyWindow(_this, window);
+    }
+
     if (need_gl_load) {
         if (SDL_GL_LoadLibrary(NULL) < 0) {
             return -1;
@@ -3297,6 +3297,12 @@ SDL_DestroyWindow(SDL_Window * window)
         window->surface = NULL;
         window->surface_valid = SDL_FALSE;
     }
+    if (window->flags & SDL_WINDOW_OPENGL) {
+        SDL_GL_UnloadLibrary();
+    }
+    if (window->flags & SDL_WINDOW_VULKAN) {
+        SDL_Vulkan_UnloadLibrary();
+    }
     if (_this->checked_texture_framebuffer) { /* never checked? No framebuffer to destroy. Don't risk calling the wrong implementation. */
         if (_this->DestroyWindowFramebuffer) {
             _this->DestroyWindowFramebuffer(_this, window);
@@ -3305,12 +3311,6 @@ SDL_DestroyWindow(SDL_Window * window)
     if (_this->DestroyWindow) {
         _this->DestroyWindow(_this, window);
     }
-    if (window->flags & SDL_WINDOW_OPENGL) {
-        SDL_GL_UnloadLibrary();
-    }
-    if (window->flags & SDL_WINDOW_VULKAN) {
-        SDL_Vulkan_UnloadLibrary();
-    }
 
     display = SDL_GetDisplayForWindow(window);
     if (display->fullscreen_window == window) {

From c608cf6222937ec339b2002a26f72a7abb773ebc Mon Sep 17 00:00:00 2001
From: Steven Noonan <steven@valvesoftware.com>
Date: Thu, 25 Aug 2022 20:29:41 -0700
Subject: [PATCH 3/9] egl: implement SDL_GL_EGL_PLATFORM attribute

This implements a new SDL_GL_EGL_PLATFORM attribute to set the
"platform" argument for SDL_EGL_LoadLibrary on Windows, macOS, and
Linux. I've limited it to those three operating systems because that's
what I've been able to test against.
---
 include/SDL_video.h                     |  3 ++-
 src/video/SDL_sysvideo.h                |  1 +
 src/video/SDL_video.c                   | 11 +++++++++++
 src/video/cocoa/SDL_cocoaopengles.m     |  4 ++--
 src/video/windows/SDL_windowsopengles.c |  4 ++--
 src/video/x11/SDL_x11opengles.c         |  2 +-
 6 files changed, 19 insertions(+), 6 deletions(-)

diff --git a/include/SDL_video.h b/include/SDL_video.h
index 79d572fcc8a2..8e9ed8da2b1c 100644
--- a/include/SDL_video.h
+++ b/include/SDL_video.h
@@ -249,7 +249,8 @@ typedef enum
     SDL_GL_CONTEXT_RELEASE_BEHAVIOR,
     SDL_GL_CONTEXT_RESET_NOTIFICATION,
     SDL_GL_CONTEXT_NO_ERROR,
-    SDL_GL_FLOATBUFFERS
+    SDL_GL_FLOATBUFFERS,
+    SDL_GL_EGL_PLATFORM
 } SDL_GLattr;
 
 typedef enum
diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h
index 4bc1f111fd8a..20340da60a16 100644
--- a/src/video/SDL_sysvideo.h
+++ b/src/video/SDL_sysvideo.h
@@ -391,6 +391,7 @@ struct SDL_VideoDevice
         int framebuffer_srgb_capable;
         int no_error;
         int retained_backing;
+        int egl_platform;
         int driver_loaded;
         char driver_path[256];
         void *dll_handle;
diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c
index 0bb5f0e9c2b4..6f5d468550e3 100644
--- a/src/video/SDL_video.c
+++ b/src/video/SDL_video.c
@@ -3673,6 +3673,8 @@ SDL_GL_ResetAttributes()
     _this->gl_config.reset_notification = SDL_GL_CONTEXT_RESET_NO_NOTIFICATION;
 
     _this->gl_config.share_with_current_context = 0;
+
+    _this->gl_config.egl_platform = 0;
 }
 
 int
@@ -3789,6 +3791,9 @@ SDL_GL_SetAttribute(SDL_GLattr attr, int value)
     case SDL_GL_CONTEXT_NO_ERROR:
         _this->gl_config.no_error = value;
         break;
+    case SDL_GL_EGL_PLATFORM:
+        _this->gl_config.egl_platform = value;
+        break;
     default:
         retval = SDL_SetError("Unknown OpenGL attribute");
         break;
@@ -3998,6 +4003,12 @@ SDL_GL_GetAttribute(SDL_GLattr attr, int *value)
             *value = _this->gl_config.no_error;
             return 0;
         }
+    case SDL_GL_EGL_PLATFORM:
+        {
+            *value = _this->gl_config.egl_platform;
+            return 0;
+        }
+        break;
     default:
         return SDL_SetError("Unknown OpenGL attribute");
     }
diff --git a/src/video/cocoa/SDL_cocoaopengles.m b/src/video/cocoa/SDL_cocoaopengles.m
index bdf2e9a084bb..04561b281f16 100644
--- a/src/video/cocoa/SDL_cocoaopengles.m
+++ b/src/video/cocoa/SDL_cocoaopengles.m
@@ -51,7 +51,7 @@
     }
     
     if (_this->egl_data == NULL) {
-        return SDL_EGL_LoadLibrary(_this, NULL, EGL_DEFAULT_DISPLAY, 0);
+        return SDL_EGL_LoadLibrary(_this, NULL, EGL_DEFAULT_DISPLAY, _this->gl_config.egl_platform);
     }
 
     return 0;
@@ -127,7 +127,7 @@
         #if 0  /* When hint SDL_HINT_OPENGL_ES_DRIVER is set to "1" (e.g. for ANGLE support), _this->gl_config.driver_loaded can be 1, while the below lines function. */
         SDL_assert(!_this->gl_config.driver_loaded);
         #endif
-        if (SDL_EGL_LoadLibrary(_this, NULL, EGL_DEFAULT_DISPLAY, 0) < 0) {
+        if (SDL_EGL_LoadLibrary(_this, NULL, EGL_DEFAULT_DISPLAY, _this->gl_config.egl_platform) < 0) {
             SDL_EGL_UnloadLibrary(_this);
             return -1;
         }
diff --git a/src/video/windows/SDL_windowsopengles.c b/src/video/windows/SDL_windowsopengles.c
index 1e2a4f62079b..49cebd62dd2f 100644
--- a/src/video/windows/SDL_windowsopengles.c
+++ b/src/video/windows/SDL_windowsopengles.c
@@ -52,7 +52,7 @@ WIN_GLES_LoadLibrary(_THIS, const char *path) {
     }
     
     if (_this->egl_data == NULL) {
-        return SDL_EGL_LoadLibrary(_this, NULL, EGL_DEFAULT_DISPLAY, 0);
+        return SDL_EGL_LoadLibrary(_this, NULL, EGL_DEFAULT_DISPLAY, _this->gl_config.egl_platform);
     }
 
     return 0;
@@ -113,7 +113,7 @@ WIN_GLES_SetupWindow(_THIS, SDL_Window * window)
         #if 0  /* When hint SDL_HINT_OPENGL_ES_DRIVER is set to "1" (e.g. for ANGLE support), _this->gl_config.driver_loaded can be 1, while the below lines function. */
         SDL_assert(!_this->gl_config.driver_loaded);
         #endif
-        if (SDL_EGL_LoadLibrary(_this, NULL, EGL_DEFAULT_DISPLAY, 0) < 0) {
+        if (SDL_EGL_LoadLibrary(_this, NULL, EGL_DEFAULT_DISPLAY, _this->gl_config.egl_platform) < 0) {
             SDL_EGL_UnloadLibrary(_this);
             return -1;
         }
diff --git a/src/video/x11/SDL_x11opengles.c b/src/video/x11/SDL_x11opengles.c
index 7641a6cc6466..43d7a7d892c4 100644
--- a/src/video/x11/SDL_x11opengles.c
+++ b/src/video/x11/SDL_x11opengles.c
@@ -55,7 +55,7 @@ X11_GLES_LoadLibrary(_THIS, const char *path)
         #endif
     }
     
-    return SDL_EGL_LoadLibrary(_this, path, (NativeDisplayType) data->display, 0);
+    return SDL_EGL_LoadLibrary(_this, path, (NativeDisplayType) data->display, _this->gl_config.egl_platform);
 }
 
 XVisualInfo *

From fb1a5812096af54742410e5381648e0cd4f6976e Mon Sep 17 00:00:00 2001
From: Steven Noonan <steven@valvesoftware.com>
Date: Thu, 25 Aug 2022 21:29:30 -0700
Subject: [PATCH 4/9] egl: add hint to disable eglGetDisplay fallback when
 eglGetPlatformDisplay fails

This fallback is undesirable when using ANGLE, because it will end up
using some default configuration (e.g. on Windows it defaults to the
D3D11 backend).
---
 include/SDL_hints.h | 12 ++++++++++++
 src/video/SDL_egl.c |  4 +++-
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/include/SDL_hints.h b/include/SDL_hints.h
index 2175cf11f360..2f4441502fc6 100644
--- a/include/SDL_hints.h
+++ b/include/SDL_hints.h
@@ -1643,6 +1643,18 @@ extern "C" {
  */
 #define SDL_HINT_VIDEO_EGL_ALLOW_TRANSPARENCY "SDL_VIDEO_EGL_ALLOW_TRANSPARENCY"
 
+/**
+ * \brief If eglGetPlatformDisplay fails, fall back to calling eglGetDisplay.
+ *
+ * This variable can be set to one of the following values:
+ *   "0"        - Do not fall back to eglGetDisplay
+ *   "1"        - Fall back to eglGetDisplay if eglGetPlatformDisplay fails.
+ *
+ * By default, SDL will fall back to eglGetDisplay if eglGetPlatformDisplay
+ * fails.
+ */
+#define SDL_HINT_VIDEO_EGL_ALLOW_GETDISPLAY_FALLBACK "SDL_VIDEO_EGL_GETDISPLAY_FALLBACK"
+
 /**
  * \brief A variable controlling whether the graphics context is externally managed.
  *
diff --git a/src/video/SDL_egl.c b/src/video/SDL_egl.c
index a0e78b2bace5..f1a9bc14f718 100644
--- a/src/video/SDL_egl.c
+++ b/src/video/SDL_egl.c
@@ -526,7 +526,9 @@ SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_displa
     }
 #endif
     /* Try the implementation-specific eglGetDisplay even if eglGetPlatformDisplay fails */
-    if ((_this->egl_data->egl_display == EGL_NO_DISPLAY) && (_this->egl_data->eglGetDisplay != NULL)) {
+    if ((_this->egl_data->egl_display == EGL_NO_DISPLAY) &&
+        (_this->egl_data->eglGetDisplay != NULL) &&
+        SDL_GetHintBoolean(SDL_HINT_VIDEO_EGL_ALLOW_GETDISPLAY_FALLBACK, SDL_TRUE)) {
         _this->egl_data->egl_display = _this->egl_data->eglGetDisplay(native_display);
     }
     if (_this->egl_data->egl_display == EGL_NO_DISPLAY) {

From eacf6dc15e85dec1dca181a4ef981819af0a040e Mon Sep 17 00:00:00 2001
From: Steven Noonan <steven@valvesoftware.com>
Date: Thu, 25 Aug 2022 22:53:25 -0700
Subject: [PATCH 5/9] egl: fix function prototype for eglGetPlatformDisplay

The EGL 1.5 specification says that eglGetPlatformDisplay (unlike
eglGetPlatformDisplayExt) takes an EGLAttrib* rather than EGLint* for
the attribute list.
---
 src/video/SDL_egl_c.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/video/SDL_egl_c.h b/src/video/SDL_egl_c.h
index 76d26f93b069..c983012e15eb 100644
--- a/src/video/SDL_egl_c.h
+++ b/src/video/SDL_egl_c.h
@@ -46,7 +46,7 @@ typedef struct SDL_EGL_VideoData
     EGLDisplay(EGLAPIENTRY *eglGetDisplay) (NativeDisplayType display);
     EGLDisplay(EGLAPIENTRY *eglGetPlatformDisplay) (EGLenum platform,
                                 void *native_display,
-                                const EGLint *attrib_list);
+                                const EGLAttrib *attrib_list);
     EGLDisplay(EGLAPIENTRY *eglGetPlatformDisplayEXT) (EGLenum platform,
                                 void *native_display,
                                 const EGLint *attrib_list);

From 0644042eb8781781a56ff2430740ef654c3b67f1 Mon Sep 17 00:00:00 2001
From: Steven Noonan <steven@valvesoftware.com>
Date: Thu, 25 Aug 2022 19:44:35 -0700
Subject: [PATCH 6/9] egl: implement public functions to obtain internal EGL
 handles

These functions allow applications to call EGL functions against the SDL
EGL context. For example, applications can use an EGL API loader via
SDL_EGL_GetCurrentDisplay and SDL_EGL_GetProcAddress, and can call
functions such as eglQuerySurface against the internal EGLSurface and
EGLDisplay.
---
 include/SDL_video.h                           | 48 +++++++++++
 src/video/SDL_egl.c                           |  4 +-
 src/video/SDL_egl_c.h                         |  2 +-
 src/video/SDL_sysvideo.h                      |  1 +
 src/video/SDL_video.c                         | 86 +++++++++++++++++++
 src/video/android/SDL_androidvideo.c          |  2 +-
 src/video/cocoa/SDL_cocoaopengles.h           |  3 +-
 src/video/cocoa/SDL_cocoaopengles.m           |  9 ++
 src/video/cocoa/SDL_cocoavideo.m              |  2 +
 src/video/emscripten/SDL_emscriptenopengles.h |  2 +-
 src/video/kmsdrm/SDL_kmsdrmopengles.h         |  2 +-
 src/video/offscreen/SDL_offscreenopengles.h   |  2 +-
 src/video/raspberry/SDL_rpiopengles.h         |  2 +-
 src/video/vita/SDL_vitavideo.c                |  2 +-
 src/video/vivante/SDL_vivanteopengles.h       |  2 +-
 src/video/wayland/SDL_waylandopengles.c       | 10 ++-
 src/video/wayland/SDL_waylandopengles.h       |  3 +-
 src/video/wayland/SDL_waylandvideo.c          |  1 +
 src/video/windows/SDL_windowsopengl.c         |  1 +
 src/video/windows/SDL_windowsopengles.c       | 10 +++
 src/video/windows/SDL_windowsopengles.h       |  3 +-
 src/video/windows/SDL_windowsvideo.c          |  2 +
 src/video/winrt/SDL_winrtopengles.h           |  2 +-
 src/video/x11/SDL_x11opengles.c               |  7 ++
 src/video/x11/SDL_x11opengles.h               |  3 +-
 src/video/x11/SDL_x11video.c                  |  2 +
 26 files changed, 197 insertions(+), 16 deletions(-)

diff --git a/include/SDL_video.h b/include/SDL_video.h
index 8e9ed8da2b1c..cfbed9c89213 100644
--- a/include/SDL_video.h
+++ b/include/SDL_video.h
@@ -217,6 +217,13 @@ typedef enum
  */
 typedef void *SDL_GLContext;
 
+/**
+ *  \brief Opaque EGL types.
+ */
+typedef void *SDL_EGLDisplay;
+typedef void *SDL_EGLConfig;
+typedef void *SDL_EGLSurface;
+
 /**
  *  \brief OpenGL configuration attributes
  */
@@ -1903,6 +1910,21 @@ extern DECLSPEC int SDLCALL SDL_GL_LoadLibrary(const char *path);
  */
 extern DECLSPEC void *SDLCALL SDL_GL_GetProcAddress(const char *proc);
 
+/**
+ * Get an EGL library function by name.
+ *
+ * If an EGL library is loaded, this function allows applications to get entry
+ * points for EGL functions. This is useful to provide to an EGL API and
+ * extension loader.
+ *
+ * \param proc the name of an EGL function
+ * \returns a pointer to the named EGL function. The returned pointer should be
+ *          cast to the appropriate function signature.
+ *
+ * \sa SDL_GL_GetCurrentEGLDisplay
+ */
+extern DECLSPEC void *SDLCALL SDL_EGL_GetProcAddress(const char *proc);
+
 /**
  * Unload the OpenGL library previously loaded by SDL_GL_LoadLibrary().
  *
@@ -2041,6 +2063,32 @@ extern DECLSPEC SDL_Window* SDLCALL SDL_GL_GetCurrentWindow(void);
  */
 extern DECLSPEC SDL_GLContext SDLCALL SDL_GL_GetCurrentContext(void);
 
+/**
+ * Get the currently active EGL display.
+ *
+ * \returns the currently active EGL display or NULL on failure; call
+ *          SDL_GetError() for more information.
+ *
+ */
+extern DECLSPEC SDL_EGLDisplay SDLCALL SDL_EGL_GetCurrentEGLDisplay(void);
+
+/**
+ * Get the currently active EGL config.
+ *
+ * \returns the currently active EGL config or NULL on failure; call
+ *          SDL_GetError() for more information.
+ *
+ */
+extern DECLSPEC SDL_EGLConfig SDLCALL SDL_EGL_GetCurrentEGLConfig(void);
+
+/**
+ * Get the EGL surface associated with the window.
+ *
+ * \returns the EGLSurface pointer associated with the window, or NULL on
+ *          failure.
+ */
+extern DECLSPEC SDL_EGLSurface SDLCALL SDL_EGL_GetWindowEGLSurface(SDL_Window * window);
+
 /**
  * Get the size of a window's underlying drawable in pixels.
  *
diff --git a/src/video/SDL_egl.c b/src/video/SDL_egl.c
index f1a9bc14f718..072b99ba9b2a 100644
--- a/src/video/SDL_egl.c
+++ b/src/video/SDL_egl.c
@@ -242,7 +242,7 @@ SDL_bool SDL_EGL_HasExtension(_THIS, SDL_EGL_ExtensionType type, const char *ext
 }
 
 void *
-SDL_EGL_GetProcAddress(_THIS, const char *proc)
+SDL_EGL_GetProcAddressInternal(_THIS, const char *proc)
 {
     const Uint32 eglver = (((Uint32) _this->egl_data->egl_version_major) << 16) | ((Uint32) _this->egl_data->egl_version_minor);
     const SDL_bool is_egl_15_or_later = eglver >= ((((Uint32) 1) << 16) | 5);
@@ -517,7 +517,7 @@ SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_displa
             _this->egl_data->egl_display = _this->egl_data->eglGetPlatformDisplay(platform, (void *)(uintptr_t)native_display, NULL);
         } else {
             if (SDL_EGL_HasExtension(_this, SDL_EGL_CLIENT_EXTENSION, "EGL_EXT_platform_base")) {
-                _this->egl_data->eglGetPlatformDisplayEXT = SDL_EGL_GetProcAddress(_this, "eglGetPlatformDisplayEXT");
+                _this->egl_data->eglGetPlatformDisplayEXT = SDL_EGL_GetProcAddressInternal(_this, "eglGetPlatformDisplayEXT");
                 if (_this->egl_data->eglGetPlatformDisplayEXT) {
                     _this->egl_data->egl_display = _this->egl_data->eglGetPlatformDisplayEXT(platform, (void *)(uintptr_t)native_display, NULL);
                 }
diff --git a/src/video/SDL_egl_c.h b/src/video/SDL_egl_c.h
index c983012e15eb..3cf3cbb57b00 100644
--- a/src/video/SDL_egl_c.h
+++ b/src/video/SDL_egl_c.h
@@ -132,7 +132,7 @@ extern int SDL_EGL_GetAttribute(_THIS, SDL_GLattr attrib, int *value);
  */
 extern int SDL_EGL_LoadLibraryOnly(_THIS, const char *path);
 extern int SDL_EGL_LoadLibrary(_THIS, const char *path, NativeDisplayType native_display, EGLenum platform);
-extern void *SDL_EGL_GetProcAddress(_THIS, const char *proc);
+extern void *SDL_EGL_GetProcAddressInternal(_THIS, const char *proc);
 extern void SDL_EGL_UnloadLibrary(_THIS);
 extern void SDL_EGL_SetRequiredVisualId(_THIS, int visual_id);
 extern int SDL_EGL_ChooseConfig(_THIS);
diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h
index 20340da60a16..63d3eea84d23 100644
--- a/src/video/SDL_sysvideo.h
+++ b/src/video/SDL_sysvideo.h
@@ -275,6 +275,7 @@ struct SDL_VideoDevice
       SDL_GLContext(*GL_CreateContext) (_THIS, SDL_Window * window);
     int (*GL_MakeCurrent) (_THIS, SDL_Window * window, SDL_GLContext context);
     void (*GL_GetDrawableSize) (_THIS, SDL_Window * window, int *w, int *h);
+    SDL_EGLSurface (*GL_GetEGLSurface) (_THIS, SDL_Window * window);
     int (*GL_SetSwapInterval) (_THIS, int interval);
     int (*GL_GetSwapInterval) (_THIS);
     int (*GL_SwapWindow) (_THIS, SDL_Window * window);
diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c
index 6f5d468550e3..36276e969829 100644
--- a/src/video/SDL_video.c
+++ b/src/video/SDL_video.c
@@ -25,6 +25,7 @@
 #include "SDL.h"
 #include "SDL_video.h"
 #include "SDL_sysvideo.h"
+#include "SDL_egl_c.h"
 #include "SDL_blit.h"
 #include "SDL_pixels_c.h"
 #include "SDL_rect_c.h"
@@ -3480,6 +3481,31 @@ SDL_GL_GetProcAddress(const char *proc)
     return func;
 }
 
+void *
+SDL_EGL_GetProcAddress(const char *proc)
+{
+#if SDL_VIDEO_OPENGL_EGL
+    void *func;
+
+    if (!_this) {
+        SDL_UninitializedVideo();
+        return NULL;
+    }
+    func = NULL;
+
+    if (_this->egl_data) {
+        func = SDL_EGL_GetProcAddressInternal(_this, proc);
+    } else {
+        SDL_SetError("No EGL library has been loaded");
+    }
+
+    return func;
+#else
+    SDL_SetError("SDL was not built with EGL support");
+    return NULL;
+#endif
+}
+
 void
 SDL_GL_UnloadLibrary(void)
 {
@@ -4152,6 +4178,66 @@ SDL_GL_GetCurrentContext(void)
     return (SDL_GLContext)SDL_TLSGet(_this->current_glctx_tls);
 }
 
+SDL_EGLDisplay
+SDL_EGL_GetCurrentEGLDisplay(void)
+{
+#if SDL_VIDEO_OPENGL_EGL
+    if (!_this) {
+        SDL_UninitializedVideo();
+        return EGL_NO_DISPLAY;
+    }
+    if (!_this->egl_data) {
+        SDL_SetError("There is no current EGL display");
+        return EGL_NO_DISPLAY;
+    }
+    return _this->egl_data->egl_display;
+#else
+    SDL_SetError("SDL was not built with EGL support");
+    return NULL;
+#endif
+}
+
+SDL_EGLConfig
+SDL_EGL_GetCurrentEGLConfig(void)
+{
+#if SDL_VIDEO_OPENGL_EGL
+    if (!_this) {
+        SDL_UninitializedVideo();
+        return NULL;
+    }
+    if (!_this->egl_data) {
+        SDL_SetError("There is no current EGL display");
+        return NULL;
+    }
+    return _this->egl_data->egl_config;
+#else
+    SDL_SetError("SDL was not built with EGL support");
+    return NULL;
+#endif
+}
+
+SDL_EGLConfig
+SDL_EGL_GetWindowEGLSurface(SDL_Window * window)
+{
+#if SDL_VIDEO_OPENGL_EGL
+    if (!_this) {
+        SDL_UninitializedVideo();
+        return NULL;
+    }
+    if (!_this->egl_data) {
+        SDL_SetError("There is no current EGL display");
+        return NULL;
+    }
+    if (_this->GL_GetEGLSurface) {
+        return _this->GL_GetEGLSurface(_this, window);
+    }
+    return NULL;
+#else
+    SDL_SetError("SDL was not built with EGL support");
+    return NULL;
+#endif
+}
+
 void SDL_GL_GetDrawableSize(SDL_Window * window, int *w, int *h)
 {
     CHECK_WINDOW_MAGIC(window,);
diff --git a/src/video/android/SDL_androidvideo.c b/src/video/android/SDL_androidvideo.c
index 3ed828fde1bc..d405e7004d7f 100644
--- a/src/video/android/SDL_androidvideo.c
+++ b/src/video/android/SDL_androidvideo.c
@@ -50,7 +50,7 @@ static void Android_VideoQuit(_THIS);
 int Android_GetDisplayDPI(_THIS, SDL_VideoDisplay *display, float *ddpi, float *hdpi, float *vdpi);
 
 #include "../SDL_egl_c.h"
-#define Android_GLES_GetProcAddress SDL_EGL_GetProcAddress
+#define Android_GLES_GetProcAddress SDL_EGL_GetProcAddressInternal
 #define Android_GLES_UnloadLibrary SDL_EGL_UnloadLibrary
 #define Android_GLES_SetSwapInterval SDL_EGL_SetSwapInterval
 #define Android_GLES_GetSwapInterval SDL_EGL_GetSwapInterval
diff --git a/src/video/cocoa/SDL_cocoaopengles.h b/src/video/cocoa/SDL_cocoaopengles.h
index bfabb6d57f9d..05800e3e426e 100644
--- a/src/video/cocoa/SDL_cocoaopengles.h
+++ b/src/video/cocoa/SDL_cocoaopengles.h
@@ -30,7 +30,7 @@
 
 /* OpenGLES functions */
 #define Cocoa_GLES_GetAttribute SDL_EGL_GetAttribute
-#define Cocoa_GLES_GetProcAddress SDL_EGL_GetProcAddress
+#define Cocoa_GLES_GetProcAddress SDL_EGL_GetProcAddressInternal
 #define Cocoa_GLES_UnloadLibrary SDL_EGL_UnloadLibrary
 #define Cocoa_GLES_GetSwapInterval SDL_EGL_GetSwapInterval
 #define Cocoa_GLES_SetSwapInterval SDL_EGL_SetSwapInterval
@@ -41,6 +41,7 @@ extern int Cocoa_GLES_SwapWindow(_THIS, SD

(Patch may be truncated, please check the link at the top of this post.)