Commits to SDL revision control. Unmonitored, automated account; try @icculus
or https://github.com/libsdl-org/SDL !


The patch
From 675f77718c1161ebc4fd0a72bc7625baf7607cc7 Mon Sep 17 00:00:00 2001
From: SDL Wiki Bot <[EMAIL REDACTED]>
Date: Wed, 23 Nov 2022 19:03:15 +0000
Subject: [PATCH] Sync SDL3 wiki -> header

---
 include/SDL_video.h | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/include/SDL_video.h b/include/SDL_video.h
index fd63fd9bc202..120366c15999 100644
--- a/include/SDL_video.h
+++ b/include/SDL_video.h
@@ -1926,8 +1926,8 @@ extern DECLSPEC void *SDLCALL SDL_GL_GetProcAddress(const char *proc);
  * 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.
+ * \returns a pointer to the named EGL function. The returned pointer should
+ *          be cast to the appropriate function signature.
  *
  * \sa SDL_GL_GetCurrentEGLDisplay
  */
@@ -2076,7 +2076,6 @@ extern DECLSPEC SDL_GLContext SDLCALL SDL_GL_GetCurrentContext(void);
  *
  * \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);
 
@@ -2085,7 +2084,6 @@ extern DECLSPEC SDL_EGLDisplay SDLCALL SDL_EGL_GetCurrentEGLDisplay(void);
  *
  * \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);
 



https://github.com/libsdl-org/SDL/commit/040a17a50f1b500c7a1e07c6bc6e1d6eff5dbe76

The patch
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.)



https://github.com/libsdl-org/SDL/commit/dcd9e219666fae8bf581eac15052d6c0f8f82d7f

The patch
From eebbf3457ccb7ebca9a83cd77e8673a5f822e772 Mon Sep 17 00:00:00 2001
From: Charlie Birks <[EMAIL REDACTED]>
Date: Fri, 25 Feb 2022 17:19:25 +0000
Subject: [PATCH 001/153] emscripten: Use emscripten_webgl_ API directly

---
 src/video/emscripten/SDL_emscriptenopengles.c | 138 +++++++++++-------
 src/video/emscripten/SDL_emscriptenopengles.h |  16 +-
 src/video/emscripten/SDL_emscriptenvideo.c    |  24 ---
 src/video/emscripten/SDL_emscriptenvideo.h    |   7 -
 4 files changed, 96 insertions(+), 89 deletions(-)

diff --git a/src/video/emscripten/SDL_emscriptenopengles.c b/src/video/emscripten/SDL_emscriptenopengles.c
index 10c6285cf325..a3219372c147 100644
--- a/src/video/emscripten/SDL_emscriptenopengles.c
+++ b/src/video/emscripten/SDL_emscriptenopengles.c
@@ -20,83 +20,123 @@
 */
 #include "../../SDL_internal.h"
 
-#if SDL_VIDEO_DRIVER_EMSCRIPTEN && SDL_VIDEO_OPENGL_EGL
+#if SDL_VIDEO_DRIVER_EMSCRIPTEN
 
 #include <emscripten/emscripten.h>
+#include <emscripten/html5_webgl.h>
 #include <GLES2/gl2.h>
 
 #include "SDL_emscriptenvideo.h"
 #include "SDL_emscriptenopengles.h"
 #include "SDL_hints.h"
 
-#define LOAD_FUNC(NAME) _this->egl_data->NAME = NAME;
 
-/* EGL implementation of SDL OpenGL support */
+int
+Emscripten_GLES_LoadLibrary(_THIS, const char *path)
+{
+    return 0;
+}
+
+void
+Emscripten_GLES_UnloadLibrary(_THIS)
+{
+}
+
+void *
+Emscripten_GLES_GetProcAddress(_THIS, const char *proc)
+{
+    return emscripten_webgl_get_proc_address(proc);
+}
 
 int
-Emscripten_GLES_LoadLibrary(_THIS, const char *path) {
-    /*we can't load EGL dynamically*/
-    _this->egl_data = (struct SDL_EGL_VideoData *) SDL_calloc(1, sizeof(SDL_EGL_VideoData));
-    if (!_this->egl_data) {
-        return SDL_OutOfMemory();
+Emscripten_GLES_SetSwapInterval(_THIS, int interval)
+{
+    if (interval < 0) {
+        return SDL_SetError("Late swap tearing currently unsupported");
+    } else if(interval == 0) {
+        emscripten_set_main_loop_timing(EM_TIMING_SETTIMEOUT, 0);
+    } else {
+        emscripten_set_main_loop_timing(EM_TIMING_RAF, interval);
     }
 
-    /* Emscripten forces you to manually cast eglGetProcAddress to the real
-       function type; grep for "__eglMustCastToProperFunctionPointerType" in
-       Emscripten's egl.h for details. */
-    _this->egl_data->eglGetProcAddress = (void *(EGLAPIENTRY *)(const char *)) eglGetProcAddress;
-
-    LOAD_FUNC(eglGetDisplay);
-    LOAD_FUNC(eglInitialize);
-    LOAD_FUNC(eglTerminate);
-    LOAD_FUNC(eglChooseConfig);
-    LOAD_FUNC(eglGetConfigAttrib);
-    LOAD_FUNC(eglCreateContext);
-    LOAD_FUNC(eglDestroyContext);
-    LOAD_FUNC(eglCreateWindowSurface);
-    LOAD_FUNC(eglDestroySurface);
-    LOAD_FUNC(eglMakeCurrent);
-    LOAD_FUNC(eglSwapBuffers);
-    LOAD_FUNC(eglSwapInterval);
-    LOAD_FUNC(eglWaitNative);
-    LOAD_FUNC(eglWaitGL);
-    LOAD_FUNC(eglBindAPI);
-    LOAD_FUNC(eglQueryString);
-    LOAD_FUNC(eglGetError);
-
-    _this->egl_data->egl_display = _this->egl_data->eglGetDisplay(EGL_DEFAULT_DISPLAY);
-    if (!_this->egl_data->egl_display) {
-        return SDL_SetError("Could not get EGL display");
-    }
-    
-    if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) {
-        return SDL_SetError("Could not initialize EGL");
+    return 0;
+}
+
+int
+Emscripten_GLES_GetSwapInterval(_THIS)
+{
+    int mode, value;
+
+    emscripten_get_main_loop_timing(&mode, &value);
+
+    if(mode == EM_TIMING_RAF)
+        return value;
+
+    return 0;
+}
+
+SDL_GLContext
+Emscripten_GLES_CreateContext(_THIS, SDL_Window * window)
+{
+    SDL_WindowData *window_data;
+
+    EmscriptenWebGLContextAttributes attribs;
+    EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context;
+
+    emscripten_webgl_init_context_attributes(&attribs);
+
+    attribs.alpha = _this->gl_config.alpha_size > 0;
+    attribs.depth = _this->gl_config.depth_size > 0;
+    attribs.stencil = _this->gl_config.stencil_size > 0;
+    attribs.antialias = _this->gl_config.multisamplebuffers == 1;
+
+    if(_this->gl_config.major_version == 3)
+        attribs.majorVersion = 2; /* WebGL 2.0 ~= GLES 3.0 */
+
+    window_data = (SDL_WindowData *) window->driverdata;
+    context = emscripten_webgl_create_context(window_data->canvas_id, &attribs);
+
+    if (context < 0) {
+        SDL_SetError("Could not create webgl context");
+        return NULL;
     }
 
-    if (path) {
-        SDL_strlcpy(_this->gl_config.driver_path, path, sizeof(_this->gl_config.driver_path) - 1);
-    } else {
-        *_this->gl_config.driver_path = '\0';
+    if (emscripten_webgl_make_context_current(context) != EMSCRIPTEN_RESULT_SUCCESS) {
+        emscripten_webgl_destroy_context(context);
+        return NULL;
     }
-    
-    return 0;
+
+
+    return (SDL_GLContext)context;
 }
 
-SDL_EGL_CreateContext_impl(Emscripten)
-SDL_EGL_MakeCurrent_impl(Emscripten)
+void
+Emscripten_GLES_DeleteContext(_THIS, SDL_GLContext context)
+{
+    emscripten_webgl_destroy_context((EMSCRIPTEN_WEBGL_CONTEXT_HANDLE)context);
+}
 
 int
 Emscripten_GLES_SwapWindow(_THIS, SDL_Window * window)
 {
-    EGLBoolean ret = SDL_EGL_SwapBuffers(_this, ((SDL_WindowData *) window->driverdata)->egl_surface);
     if (emscripten_has_asyncify() && SDL_GetHintBoolean(SDL_HINT_EMSCRIPTEN_ASYNCIFY, SDL_TRUE)) {
         /* give back control to browser for screen refresh */
         emscripten_sleep(0);
     }
-    return ret;
+    return 0;
+}
+
+int
+Emscripten_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
+{
+    /* ignores window, as it isn't possible to reuse contexts across canvases */
+    if (emscripten_webgl_make_context_current((EMSCRIPTEN_WEBGL_CONTEXT_HANDLE)context) != EMSCRIPTEN_RESULT_SUCCESS) {
+        return SDL_SetError("Unable to make context current");
+    }
+    return 0;
 }
 
-#endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN && SDL_VIDEO_OPENGL_EGL */
+#endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN */
 
 /* vi: set ts=4 sw=4 expandtab: */
 
diff --git a/src/video/emscripten/SDL_emscriptenopengles.h b/src/video/emscripten/SDL_emscriptenopengles.h
index 9d178f6902d9..6d58ac10dfd4 100644
--- a/src/video/emscripten/SDL_emscriptenopengles.h
+++ b/src/video/emscripten/SDL_emscriptenopengles.h
@@ -23,25 +23,23 @@
 #ifndef SDL_emscriptenopengles_h_
 #define SDL_emscriptenopengles_h_
 
-#if SDL_VIDEO_DRIVER_EMSCRIPTEN && SDL_VIDEO_OPENGL_EGL
+#if SDL_VIDEO_DRIVER_EMSCRIPTEN
 
 #include "../SDL_sysvideo.h"
-#include "../SDL_egl_c.h"
 
 /* OpenGLES functions */
-#define Emscripten_GLES_GetAttribute SDL_EGL_GetAttribute
-#define Emscripten_GLES_GetProcAddress SDL_EGL_GetProcAddress
-#define Emscripten_GLES_UnloadLibrary SDL_EGL_UnloadLibrary
-#define Emscripten_GLES_SetSwapInterval SDL_EGL_SetSwapInterval
-#define Emscripten_GLES_GetSwapInterval SDL_EGL_GetSwapInterval
-#define Emscripten_GLES_DeleteContext SDL_EGL_DeleteContext
 
 extern int Emscripten_GLES_LoadLibrary(_THIS, const char *path);
+extern void Emscripten_GLES_UnloadLibrary(_THIS);
+extern void * Emscripten_GLES_GetProcAddress(_THIS, const char *proc);
+extern int Emscripten_GLES_SetSwapInterval(_THIS, int interval);
+extern int Emscripten_GLES_GetSwapInterval(_THIS);
 extern SDL_GLContext Emscripten_GLES_CreateContext(_THIS, SDL_Window * window);
+extern void Emscripten_GLES_DeleteContext(_THIS, SDL_GLContext context);
 extern int Emscripten_GLES_SwapWindow(_THIS, SDL_Window * window);
 extern int Emscripten_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context);
 
-#endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN && SDL_VIDEO_OPENGL_EGL */
+#endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN */
 
 #endif /* SDL_emscriptenopengles_h_ */
 
diff --git a/src/video/emscripten/SDL_emscriptenvideo.c b/src/video/emscripten/SDL_emscriptenvideo.c
index 550031d3fbea..46813a721798 100644
--- a/src/video/emscripten/SDL_emscriptenvideo.c
+++ b/src/video/emscripten/SDL_emscriptenvideo.c
@@ -27,7 +27,6 @@
 #include "SDL_hints.h"
 #include "../SDL_sysvideo.h"
 #include "../SDL_pixels_c.h"
-#include "../SDL_egl_c.h"
 #include "../../events/SDL_events_c.h"
 
 #include "SDL_emscriptenvideo.h"
@@ -110,7 +109,6 @@ Emscripten_CreateDevice(void)
     device->UpdateWindowFramebuffer = Emscripten_UpdateWindowFramebuffer;
     device->DestroyWindowFramebuffer = Emscripten_DestroyWindowFramebuffer;
 
-#if SDL_VIDEO_OPENGL_EGL
     device->GL_LoadLibrary = Emscripten_GLES_LoadLibrary;
     device->GL_GetProcAddress = Emscripten_GLES_GetProcAddress;
     device->GL_UnloadLibrary = Emscripten_GLES_UnloadLibrary;
@@ -120,7 +118,6 @@ Emscripten_CreateDevice(void)
     device->GL_GetSwapInterval = Emscripten_GLES_GetSwapInterval;
     device->GL_SwapWindow = Emscripten_GLES_SwapWindow;
     device->GL_DeleteContext = Emscripten_GLES_DeleteContext;
-#endif
 
     device->free = Emscripten_DeleteDevice;
 
@@ -259,21 +256,6 @@ Emscripten_CreateWindow(_THIS, SDL_Window * window)
         }
     }
 
-#if SDL_VIDEO_OPENGL_EGL
-    if (window->flags & SDL_WINDOW_OPENGL) {
-        if (!_this->egl_data) {
-            if (SDL_GL_LoadLibrary(NULL) < 0) {
-                return -1;
-            }
-        }
-        wdata->egl_surface = SDL_EGL_CreateSurface(_this, 0);
-
-        if (wdata->egl_surface == EGL_NO_SURFACE) {
-            return SDL_SetError("Could not create GLES window surface");
-        }
-    }
-#endif
-
     wdata->window = window;
 
     /* Setup driver data for this window */
@@ -329,12 +311,6 @@ Emscripten_DestroyWindow(_THIS, SDL_Window * window)
         data = (SDL_WindowData *) window->driverdata;
 
         Emscripten_UnregisterEventHandlers(data);
-#if SDL_VIDEO_OPENGL_EGL
-        if (data->egl_surface != EGL_NO_SURFACE) {
-            SDL_EGL_DestroySurface(_this, data->egl_surface);
-            data->egl_surface = EGL_NO_SURFACE;
-        }
-#endif
 
         /* We can't destroy the canvas, so resize it to zero instead */
         emscripten_set_canvas_element_size(data->canvas_id, 0, 0);
diff --git a/src/video/emscripten/SDL_emscriptenvideo.h b/src/video/emscripten/SDL_emscriptenvideo.h
index e87788d3f815..20481235e5b5 100644
--- a/src/video/emscripten/SDL_emscriptenvideo.h
+++ b/src/video/emscripten/SDL_emscriptenvideo.h
@@ -28,15 +28,8 @@
 #include <emscripten/emscripten.h>
 #include <emscripten/html5.h>
 
-#if SDL_VIDEO_OPENGL_EGL
-#include <EGL/egl.h>
-#endif
-
 typedef struct SDL_WindowData
 {
-#if SDL_VIDEO_OPENGL_EGL
-    EGLSurface egl_surface;
-#endif
     SDL_Window *window;
     SDL_Surface *surface;
 

From 539efc1bbaec197cb0d6663824fd29fd71060785 Mon Sep 17 00:00:00 2001
From: Charlie Birks <charlie@daft.games>
Date: Sat, 26 Feb 2022 12:24:32 +0000
Subject: [PATCH 002/153] emscripten: Return an error for webgl context
 limitations

---
 src/video/emscripten/SDL_emscriptenopengles.c | 30 ++++++++++++++++++-
 src/video/emscripten/SDL_emscriptenvideo.h    |  2 ++
 2 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/src/video/emscripten/SDL_emscriptenopengles.c b/src/video/emscripten/SDL_emscriptenopengles.c
index a3219372c147..ccec124ce20f 100644
--- a/src/video/emscripten/SDL_emscriptenopengles.c
+++ b/src/video/emscripten/SDL_emscriptenopengles.c
@@ -94,6 +94,12 @@ Emscripten_GLES_CreateContext(_THIS, SDL_Window * window)
         attribs.majorVersion = 2; /* WebGL 2.0 ~= GLES 3.0 */
 
     window_data = (SDL_WindowData *) window->driverdata;
+
+    if (window_data->gl_context) {
+        SDL_SetError("Cannot create multiple webgl contexts per window");
+        return NULL;
+    }
+
     context = emscripten_webgl_create_context(window_data->canvas_id, &attribs);
 
     if (context < 0) {
@@ -106,6 +112,7 @@ Emscripten_GLES_CreateContext(_THIS, SDL_Window * window)
         return NULL;
     }
 
+    window_data->gl_context = (SDL_GLContext)context;
 
     return (SDL_GLContext)context;
 }
@@ -113,6 +120,18 @@ Emscripten_GLES_CreateContext(_THIS, SDL_Window * window)
 void
 Emscripten_GLES_DeleteContext(_THIS, SDL_GLContext context)
 {
+    SDL_Window *window;
+
+    /* remove the context from its window */
+    for (window = _this->windows; window != NULL; window = window->next) {
+        SDL_WindowData *window_data;
+        window_data = (SDL_WindowData *) window->driverdata;
+
+        if (window_data->gl_context == context) {
+            window_data->gl_context = NULL;
+        }
+    }
+
     emscripten_webgl_destroy_context((EMSCRIPTEN_WEBGL_CONTEXT_HANDLE)context);
 }
 
@@ -129,7 +148,16 @@ Emscripten_GLES_SwapWindow(_THIS, SDL_Window * window)
 int
 Emscripten_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
 {
-    /* ignores window, as it isn't possible to reuse contexts across canvases */
+    /* it isn't possible to reuse contexts across canvases */
+    if (window && context) {
+        SDL_WindowData *window_data;
+        window_data = (SDL_WindowData *) window->driverdata;
+
+        if (context != window_data->gl_context) {
+            return SDL_SetError("Cannot make context current to another window");
+        }
+    }
+
     if (emscripten_webgl_make_context_current((EMSCRIPTEN_WEBGL_CONTEXT_HANDLE)context) != EMSCRIPTEN_RESULT_SUCCESS) {
         return SDL_SetError("Unable to make context current");
     }
diff --git a/src/video/emscripten/SDL_emscriptenvideo.h b/src/video/emscripten/SDL_emscriptenvideo.h
index 20481235e5b5..4cd0a5ce59e2 100644
--- a/src/video/emscripten/SDL_emscriptenvideo.h
+++ b/src/video/emscripten/SDL_emscriptenvideo.h
@@ -33,6 +33,8 @@ typedef struct SDL_WindowData
     SDL_Window *window;
     SDL_Surface *surface;
 
+    SDL_GLContext gl_context;
+
     char *canvas_id;
 
     float pixel_ratio;

From b5aedaad5923edd88ca33e6dab4b86503e8cb0f3 Mon Sep 17 00:00:00 2001
From: Charlie Birks <charlie@daftgames.net>
Date: Sun, 8 Apr 2018 16:54:29 +0100
Subject: [PATCH 003/153] emscripten: Modify UpdateWindowFramebuffer

To work with multiple canvases
---
 src/video/emscripten/SDL_emscriptenframebuffer.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/src/video/emscripten/SDL_emscriptenframebuffer.c b/src/video/emscripten/SDL_emscriptenframebuffer.c
index 03fea04efa30..05e4aa7453f2 100644
--- a/src/video/emscripten/SDL_emscriptenframebuffer.c
+++ b/src/video/emscripten/SDL_emscriptenframebuffer.c
@@ -75,12 +75,15 @@ int Emscripten_UpdateWindowFramebuffer(_THIS, SDL_Window * window, const SDL_Rec
         var w = $0;
         var h = $1;
         var pixels = $2;
+        var canvasId = UTF8ToString($3);
+        var canvas = document.querySelector(canvasId);
 
+        //TODO: this should store a context per canvas
         if (!Module['SDL2']) Module['SDL2'] = {};
         var SDL2 = Module['SDL2'];
-        if (SDL2.ctxCanvas !== Module['canvas']) {
-            SDL2.ctx = Module['createContext'](Module['canvas'], false, true);
-            SDL2.ctxCanvas = Module['canvas'];
+        if (SDL2.ctxCanvas !== canvas) {
+            SDL2.ctx = Module['createContext'](canvas, false, true);
+            SDL2.ctxCanvas = canvas;
         }
         if (SDL2.w !== w || SDL2.h !== h || SDL2.imageCtx !== SDL2.ctx) {
             SDL2.image = SDL2.ctx.createImageData(w, h);
@@ -156,7 +159,7 @@ int Emscripten_UpdateWindowFramebuffer(_THIS, SDL_Window * window, const SDL_Rec
         }
 
         SDL2.ctx.putImageData(SDL2.image, 0, 0);
-    }, surface->w, surface->h, surface->pixels);
+    }, surface->w, surface->h, surface->pixels, data->canvas_id);
 
     if (emscripten_has_asyncify() && SDL_GetHintBoolean(SDL_HINT_EMSCRIPTEN_ASYNCIFY, SDL_TRUE)) {
         /* give back control to browser for screen refresh */

From d75fb0995dcf533bbc03bdac1c7d41caad678d68 Mon Sep 17 00:00:00 2001
From: Charlie Birks <charlie@daft.games>
Date: Sat, 26 Feb 2022 14:52:08 +0000
Subject: [PATCH 004/153] emscripten: Add a hint for specifying the canvas
 selector

Now that we're not going through EGL, this is easy
---
 include/SDL_hints.h                        | 9 +++++++++
 src/video/emscripten/SDL_emscriptenvideo.c | 8 +++++++-
 2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/include/SDL_hints.h b/include/SDL_hints.h
index 48f4f3689a70..6fee3e5fce47 100644
--- a/include/SDL_hints.h
+++ b/include/SDL_hints.h
@@ -366,6 +366,15 @@ extern "C" {
  */
 #define SDL_HINT_EMSCRIPTEN_ASYNCIFY   "SDL_EMSCRIPTEN_ASYNCIFY"
 
+/**
+ *  \brief Specify the CSS selector used for the "default" window/canvas
+ *
+ * This hint only applies to the emscripten platform
+ *
+ * The default value is "#canvas"
+ */
+#define SDL_HINT_EMSCRIPTEN_CANVAS_SELECTOR "SDL_EMSCRIPTEN_CANVAS_SELECTOR"
+
 /**
  *  \brief override the binding element for keyboard inputs for Emscripten builds
  *
diff --git a/src/video/emscripten/SDL_emscriptenvideo.c b/src/video/emscripten/SDL_emscriptenvideo.c
index 46813a721798..c8efac48f850 100644
--- a/src/video/emscripten/SDL_emscriptenvideo.c
+++ b/src/video/emscripten/SDL_emscriptenvideo.c
@@ -215,6 +215,7 @@ Emscripten_CreateWindow(_THIS, SDL_Window * window)
     SDL_WindowData *wdata;
     double scaled_w, scaled_h;
     double css_w, css_h;
+    const char *selector;
 
     /* Allocate window internal data */
     wdata = (SDL_WindowData *) SDL_calloc(1, sizeof(SDL_WindowData));
@@ -222,7 +223,12 @@ Emscripten_CreateWindow(_THIS, SDL_Window * window)
         return SDL_OutOfMemory();
     }
 
-    wdata->canvas_id = SDL_strdup("#canvas");
+    selector = SDL_GetHint(SDL_HINT_EMSCRIPTEN_CANVAS_SELECTOR);
+    if (!selector) {
+        selector = "#canvas";
+    }
+
+    wdata->canvas_id = SDL_strdup(selector);
 
     if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
         wdata->pixel_ratio = emscripten_get_device_pixel_ratio();

From 0dfc829a6b75b5a3c4c1d49fb943b622c12d67bc Mon Sep 17 00:00:00 2001
From: Sam Lantinga <slouken@libsdl.org>
Date: Thu, 10 Nov 2022 19:16:53 -0800
Subject: [PATCH 005/153] Added simple BLE Steam Controller support on all
 platforms

This is still disabled by default via the hint SDL_HINT_JOYSTICK_HIDAPI_STEAM
---
 Makefile.os2                               |  2 +-
 Makefile.w32                               |  2 +-
 VisualC-GDK/SDL/SDL.vcxproj                |  1 +
 VisualC-GDK/SDL/SDL.vcxproj.filters        |  3 ++
 VisualC/SDL/SDL.vcxproj                    |  1 +
 VisualC/SDL/SDL.vcxproj.filters            |  3 ++
 Xcode/SDL/SDL.xcodeproj/project.pbxproj    |  6 +++
 include/SDL_hints.h                        |  2 +-
 src/joystick/hidapi/SDL_hidapi_steam.c     | 48 +++++++++++++++-------
 src/joystick/hidapi/SDL_hidapijoystick_c.h |  6 +--
 test/testgamecontroller.c                  |  1 +
 11 files changed, 53 insertions(+), 22 deletions(-)

diff --git a/Makefile.os2 b/Makefile.os2
index 76b2b398dfe9..6ec172b37d5e 100644
--- a/Makefile.os2
+++ b/Makefile.os2
@@ -94,7 +94,7 @@ SRCS+= SDL_systimer.c
 SRCS+= SDL_sysloadso.c
 SRCS+= SDL_sysfilesystem.c
 SRCS+= SDL_os2joystick.c SDL_syshaptic.c SDL_sysjoystick.c SDL_virtualjoystick.c
-SRCS+= SDL_hidapijoystick.c SDL_hidapi_rumble.c SDL_hidapi_combined.c SDL_hidapi_gamecube.c SDL_hidapi_luna.c SDL_hidapi_ps3.c SDL_hidapi_ps4.c SDL_hidapi_ps5.c SDL_hidapi_shield.c SDL_hidapi_stadia.c SDL_hidapi_switch.c SDL_hidapi_wii.c SDL_hidapi_xbox360.c SDL_hidapi_xbox360w.c SDL_hidapi_xboxone.c SDL_hidapi_steam.c
+SRCS+= SDL_hidapijoystick.c SDL_hidapi_rumble.c SDL_hidapi_combined.c SDL_hidapi_gamecube.c SDL_hidapi_luna.c SDL_hidapi_ps3.c SDL_hidapi_ps4.c SDL_hidapi_ps5.c SDL_hidapi_shield.c SDL_hidapi_stadia.c SDL_hidapi_steam.c SDL_hidapi_switch.c SDL_hidapi_wii.c SDL_hidapi_xbox360.c SDL_hidapi_xbox360w.c SDL_hidapi_xboxone.c SDL_hidapi_steam.c
 SRCS+= SDL_dummyaudio.c SDL_diskaudio.c
 SRCS+= SDL_nullvideo.c SDL_nullframebuffer.c SDL_nullevents.c
 SRCS+= SDL_dummysensor.c
diff --git a/Makefile.w32 b/Makefile.w32
index 68c3a3731598..407bfd2a0110 100644
--- a/Makefile.w32
+++ b/Makefile.w32
@@ -73,7 +73,7 @@ SRCS+= SDL_systimer.c
 SRCS+= SDL_sysloadso.c
 SRCS+= SDL_sysfilesystem.c
 SRCS+= SDL_syshaptic.c SDL_sysjoystick.c SDL_virtualjoystick.c
-SRCS+= SDL_hidapijoystick.c SDL_hidapi_rumble.c SDL_hidapi_combined.c SDL_hidapi_gamecube.c SDL_hidapi_luna.c SDL_hidapi_ps3.c SDL_hidapi_ps4.c SDL_hidapi_ps5.c SDL_hidapi_shield.c SDL_hidapi_stadia.c SDL_hidapi_switch.c SDL_hidapi_wii.c SDL_hidapi_xbox360.c SDL_hidapi_xbox360w.c SDL_hidapi_xboxone.c SDL_hidapi_steam.c
+SRCS+= SDL_hidapijoystick.c SDL_hidapi_rumble.c SDL_hidapi_combined.c SDL_hidapi_gamecube.c SDL_hidapi_luna.c SDL_hidapi_ps3.c SDL_hidapi_ps4.c SDL_hidapi_ps5.c SDL_hidapi_shield.c SDL_hidapi_stadia.c SDL_hidapi_steam.c SDL_hidapi_switch.c SDL_hidapi_wii.c SDL_hidapi_xbox360.c SDL_hidapi_xbox360w.c SDL_hidapi_xboxone.c SDL_hidapi_steam.c
 SRCS+= SDL_dummyaudio.c SDL_diskaudio.c
 SRCS+= SDL_nullvideo.c SDL_nullframebuffer.c SDL_nullevents.c
 SRCS+= SDL_dummysensor.c
diff --git a/VisualC-GDK/SDL/SDL.vcxproj b/VisualC-GDK/SDL/SDL.vcxproj
index e3966e693d6a..c8208b41f7e8 100644
--- a/VisualC-GDK/SDL/SDL.vcxproj
+++ b/VisualC-GDK/SDL/SDL.vcxproj
@@ -600,6 +600,7 @@
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_rumble.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_shield.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_stadia.c" />
+    <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_steam.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_switch.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_wii.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360.c" />
diff --git a/VisualC-GDK/SDL/SDL.vcxproj.filters b/VisualC-GDK/SDL/SDL.vcxproj.filters
index 0c02e0796564..02dc97ef30f0 100644
--- a/VisualC-GDK/SDL/SDL.vcxproj.filters
+++ b/VisualC-GDK/SDL/SDL.vcxproj.filters
@@ -1078,6 +1078,9 @@
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_stadia.c">
       <Filter>joystick\hidapi</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_steam.c">
+      <Filter>joystick\hidapi</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_switch.c">
       <Filter>joystick\hidapi</Filter>
     </ClCompile>
diff --git a/VisualC/SDL/SDL.vcxproj b/VisualC/SDL/SDL.vcxproj
index e3b66d1cb16a..2c85790e2cab 100644
--- a/VisualC/SDL/SDL.vcxproj
+++ b/VisualC/SDL/SDL.vcxproj
@@ -491,6 +491,7 @@
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_rumble.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_shield.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_stadia.c" />
+    <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_steam.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_switch.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_wii.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360.c" />
diff --git a/VisualC/SDL/SDL.vcxproj.filters b/VisualC/SDL/SDL.vcxproj.filters
index 167e40d29769..082e257b4547 100644
--- a/VisualC/SDL/SDL.vcxproj.filters
+++ b/VisualC/SDL/SDL.vcxproj.filters
@@ -1069,6 +1069,9 @@
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_stadia.c">
       <Filter>joystick\hidapi</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_steam.c">
+      <Filter>joystick\hidapi</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_switch.c">
       <Filter>joystick\hidapi</Filter>
     </ClCompile>
diff --git a/Xcode/SDL/SDL.xcodeproj/project.pbxproj b/Xcode/SDL/SDL.xcodeproj/project.pbxproj
index 9c086f1ff2ec..a0741e06c9e9 100644
--- a/Xcode/SDL/SDL.xcodeproj/project.pbxproj
+++ b/Xcode/SDL/SDL.xcodeproj/project.pbxproj
@@ -3393,6 +3393,9 @@
 		F323060528939F6400E66D30 /* SDL_hidapi_combined.c in Sources */ = {isa = PBXBuildFile; fileRef = F32305FE28939F6400E66D30 /* SDL_hidapi_combined.c */; };
 		F323060628939F6400E66D30 /* SDL_hidapi_combined.c in Sources */ = {isa = PBXBuildFile; fileRef = F32305FE28939F6400E66D30 /* SDL_hidapi_combined.c */; };
 		F323060728939F6400E66D30 /* SDL_hidapi_combined.c in Sources */ = {isa = PBXBuildFile; fileRef = F32305FE28939F6400E66D30 /* SDL_hidapi_combined.c */; };
+		F34B9895291DEFF500AAC96E /* SDL_hidapi_steam.c in Sources */ = {isa = PBXBuildFile; fileRef = A75FDAAC23E2795C00529352 /* SDL_hidapi_steam.c */; };
+		F34B9896291DEFF700AAC96E /* SDL_hidapi_steam.c in Sources */ = {isa = PBXBuildFile; fileRef = A75FDAAC23E2795C00529352 /* SDL_hidapi_steam.c */; };
+		F34B9897291DEFFA00AAC96E /* SDL_hidapi_steam.c in Sources */ = {isa = PBXBuildFile; fileRef = A75FDAAC23E2795C00529352 /* SDL_hidapi_steam.c */; };
 		F3631C6424884ACF004F28EA /* SDL_locale.h in Headers */ = {isa = PBXBuildFile; fileRef = 566E26792462701100718109 /* SDL_locale.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		F3631C652488534E004F28EA /* SDL_locale.h in Headers */ = {isa = PBXBuildFile; fileRef = 566E26792462701100718109 /* SDL_locale.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		F376F6192559B29300CFC0BC /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F376F6182559B29300CFC0BC /* OpenGLES.framework */; platformFilter = ios; };
@@ -8909,6 +8912,7 @@
 				A7D8BBD923E2574800DCD162 /* SDL_uikitmessagebox.m in Sources */,
 				A7D8AD2923E2514100DCD162 /* SDL_vulkan_utils.c in Sources */,
 				A7D8A95123E2514000DCD162 /* SDL_spinlock.c in Sources */,
+				F34B9895291DEFF500AAC96E /* SDL_hidapi_steam.c in Sources */,
 				A7D8BAAF23E2514400DCD162 /* s_atan.c in Sources */,
 				A7D8B75223E2514300DCD162 /* SDL_sysloadso.c in Sources */,
 				A7D8BBE123E2574800DCD162 /* SDL_uikitopenglview.m in Sources */,
@@ -9103,6 +9107,7 @@
 				A7D8B41F23E2514300DCD162 /* SDL_systls.c in Sources */,
 				A7D8AD2C23E2514100DCD162 /* SDL_vulkan_utils.c in Sources */,
 				A7D8A95423E2514000DCD162 /* SDL_spinlock.c in Sources */,
+				F34B9896291DEFF700AAC96E /* SDL_hidapi_steam.c in Sources */,
 				A7D8BAB223E2514400DCD162 /* s_atan.c in Sources */,
 				F3A490A12554D38600E92A8B /* SDL_hidapi_ps5.c in Sources */,
 				A7D8B75523E2514300DCD162 /* SDL_sysloadso.c in Sources */,
@@ -9297,6 +9302,7 @@
 				A7D8AD2E23E2514100DCD162 /* SDL_vulkan_utils.c in Sources */,
 				A7D8A95623E2514000DCD162 /* SDL_spinlock.c in Sources */,
 				A7D8BAB423E2514400DCD162 /* s_atan.c in Sources */,
+				F34B9897291DEFFA00AAC96E /* SDL_hidapi_steam.c in Sources */,
 				A7D8B75723E2514300DCD162 /* SDL_sysloadso.c in Sources */,
 				F3A490A42554D38600E92A8B /* SDL_hidapi_ps5.c in Sources */,
 				A7D8B98B23E2514400DCD162 /* SDL_render_metal.m in Sources */,
diff --git a/include/SDL_hints.h b/include/SDL_hints.h
index ce2225440fb3..d51525936c4b 100644
--- a/include/SDL_hints.h
+++ b/include/SDL_hints.h
@@ -817,7 +817,7 @@ extern "C" {
 #define SDL_HINT_JOYSTICK_HIDAPI_STADIA "SDL_JOYSTICK_HIDAPI_STADIA"
 
 /**
- *  \brief  A variable controlling whether the HIDAPI driver for Steam Controllers should be used.
+ *  \brief  A variable controlling whether the HIDAPI driver for Bluetooth Steam Controllers should be used.
  *
  *  This variable can be set to the following values:
  *    "0"       - HIDAPI driver is not used
diff --git a/src/joystick/hidapi/SDL_hidapi_steam.c b/src/joystick/hidapi/SDL_hidapi_steam.c
index 7b497fa9594e..9221d12e887a 100644
--- a/src/joystick/hidapi/SDL_hidapi_steam.c
+++ b/src/joystick/hidapi/SDL_hidapi_steam.c
@@ -356,30 +356,41 @@ static int GetFeatureReport( SDL_hid_device *dev, unsigned char uBuffer[65] )
     if ( bBle )
     {
         int nRetries = 0;
-        uint8_t uSegmentBuffer[ MAX_REPORT_SEGMENT_SIZE ];
+        uint8_t uSegmentBuffer[ MAX_REPORT_SEGMENT_SIZE + 1 ];
+        uint8_t ucBytesToRead = MAX_REPORT_SEGMENT_SIZE;
+        uint8_t ucDataStartOffset = 0;
 
         SteamControllerPacketAssembler assembler;
         InitializeSteamControllerPacketAssembler( &assembler );
         
+        // On Windows and macOS, BLE devices get 2 copies of the feature report ID, one that is removed by ReadFeatureReport,
+        // and one that's included in the buffer we receive. We pad the bytes to read and skip over the report ID
+        // if necessary.
+#if defined(__WIN32__) || defined(__MACOSX__)
+        ++ucBytesToRead;
+        ++ucDataStartOffset;
+#endif
+
         while( nRetries < BLE_MAX_READ_RETRIES )
         {
             SDL_memset( uSegmentBuffer, 0, sizeof( uSegmentBuffer ) );
             uSegmentBuffer[ 0 ] = BLE_REPORT_NUMBER;
-            nRet = SDL_hid_get_feature_report( dev, uSegmentBuffer, sizeof( uSegmentBuffer ) );
+            nRet = SDL_hid_get_feature_report( dev, uSegmentBuffer, ucBytesToRead );
+
             DPRINTF( "GetFeatureReport ble ret=%d\n", nRet );
             HEXDUMP( uSegmentBuffer, nRet );
             
             // Zero retry counter if we got data
-            if ( nRet > 2 && ( uSegmentBuffer[ 1 ] & REPORT_SEGMENT_DATA_FLAG ) )
+            if ( nRet > 2 && ( uSegmentBuffer[ ucDataStartOffset + 1 ] & REPORT_SEGMENT_DATA_FLAG ) )
                 nRetries = 0;
             else
                 nRetries++;
-            
+
             if ( nRet > 0 )
             {
                 int nPacketLength = WriteSegmentToSteamControllerPacketAssembler( &assembler,
-                                                                                 uSegmentBuffer,
-                                                                                 nRet );
+                                                                                 uSegmentBuffer + ucDataStartOffset,
+                                                                                 nRet - ucDataStartOffset );
                 
                 if ( nPacketLength > 0 && nPacketLength < 65 )
                 {
@@ -424,7 +435,8 @@ static bool ResetSteamController( SDL_hid_device *dev, bool bSuppressErrorSpew,
 {
     // Firmware quirk: Set Feature and Get Feature requests always require a 65-byte buffer.
     unsigned char buf[65];
-    int res = -1, i;
+    unsigned int i;
+    int res = -1;
     int nSettings = 0;
     int nAttributesLength;
     FeatureReportMsg *msg;
@@ -803,8 +815,8 @@ static void FormatStatePacketUntilGyro( SteamControllerStateInternal_t *pState,
     pState->sRightPadX = clamp(nRightPadX + nPadOffset, SDL_MIN_SINT16, SDL_MAX_SINT16);
     pState->sRightPadY = clamp(nRightPadY + nPadOffset, SDL_MIN_SINT16, SDL_MAX_SINT16);
 
-    pState->sTriggerL = (unsigned short)RemapValClamped( (pStatePacket->ButtonTriggerData.Triggers.nLeft << 7) | pStatePacket->ButtonTriggerData.Triggers.nLeft, 0, STEAMCONTROLLER_TRIGGER_MAX_ANALOG, 0, SDL_MAX_SINT16 );
-    pState->sTriggerR = (unsigned short)RemapValClamped( (pStatePacket->ButtonTriggerData.Triggers.nRight << 7) | pStatePacket->ButtonTriggerData.Triggers.nRight, 0, STEAMCONTROLLER_TRIGGER_MAX_ANALOG, 0, SDL_MAX_SINT16 );
+    pState->sTriggerL = (unsigned short)RemapValClamped( (float)((pStatePacket->ButtonTriggerData.Triggers.nLeft << 7) | pStatePacket->ButtonTriggerData.Triggers.nLeft), 0, STEAMCONTROLLER_TRIGGER_MAX_ANALOG, 0, SDL_MAX_SINT16 );
+    pState->sTriggerR = (unsigned short)RemapValClamped( (float)((pStatePacket->ButtonTriggerData.Triggers.nRight << 7) | pStatePacket->ButtonTriggerData.Triggers.nRight), 0, STEAMCONTROLLER_TRIGGER_MAX_ANALOG, 0, SDL_MAX_SINT16 );
 }
 
 
@@ -827,8 +839,8 @@ static bool UpdateBLESteamControllerState( const uint8_t *pData, int nDataSize,
     if ( ucOptionDataMask & k_EBLEButtonChunk2 )
     {
         // The middle 2 bytes of the button bits over the wire are triggers when over the wire and non-SC buttons in the internal controller state packet
-        pState->sTriggerL = (unsigned short)RemapValClamped( ( pData[ 0 ] << 7 ) | pData[ 0 ], 0, STEAMCONTROLLER_TRIGGER_MAX_ANALOG, 0, SDL_MAX_SINT16 );
-        pState->sTrigge

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



The patch
From 3d8a7e4c15bb8e1340157b73831266c9e79ff12d Mon Sep 17 00:00:00 2001
From: Steven Noonan <[EMAIL REDACTED]>
Date: Fri, 9 Apr 2021 07:44:38 -0700
Subject: [PATCH] cocoa: implement GL_GetDrawableSize for OpenGL ES

---
 src/video/cocoa/SDL_cocoaopengles.h |  2 ++
 src/video/cocoa/SDL_cocoaopengles.m | 23 ++++++++++++++++++++++-
 src/video/cocoa/SDL_cocoavideo.m    |  1 +
 src/video/cocoa/SDL_cocoawindow.m   |  7 +++++++
 4 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/src/video/cocoa/SDL_cocoaopengles.h b/src/video/cocoa/SDL_cocoaopengles.h
index 05800e3e426e..4b3b53cc66d0 100644
--- a/src/video/cocoa/SDL_cocoaopengles.h
+++ b/src/video/cocoa/SDL_cocoaopengles.h
@@ -39,6 +39,8 @@ extern int Cocoa_GLES_LoadLibrary(_THIS, const char *path);
 extern SDL_GLContext Cocoa_GLES_CreateContext(_THIS, SDL_Window * window);
 extern int Cocoa_GLES_SwapWindow(_THIS, SDL_Window * window);
 extern int Cocoa_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context);
+extern void Cocoa_GLES_GetDrawableSize(_THIS, SDL_Window * window,
+                                     int * w, int * h);
 extern void Cocoa_GLES_DeleteContext(_THIS, SDL_GLContext context);
 extern int Cocoa_GLES_SetupWindow(_THIS, SDL_Window * window);
 extern SDL_EGLSurface Cocoa_GLES_GetEGLSurface(_THIS, SDL_Window * window);
diff --git a/src/video/cocoa/SDL_cocoaopengles.m b/src/video/cocoa/SDL_cocoaopengles.m
index b8f17282d2c6..6df958f1db5a 100644
--- a/src/video/cocoa/SDL_cocoaopengles.m
+++ b/src/video/cocoa/SDL_cocoaopengles.m
@@ -114,8 +114,29 @@
     return SDL_EGL_MakeCurrent(_this, window ? ((__bridge SDL_WindowData *) window->driverdata).egl_surface : EGL_NO_SURFACE, context);
 }}
 
+void
+Cocoa_GLES_GetDrawableSize(_THIS, SDL_Window * window, int * w, int * h)
+{ @autoreleasepool
+{
+    SDL_WindowData *windata = (__bridge SDL_WindowData *)window->driverdata;
+    NSView *contentView = windata.nswindow.contentView;
+    CALayer *layer = [contentView layer];
+
+    int width = layer.bounds.size.width * layer.contentsScale;
+    int height = layer.bounds.size.height * layer.contentsScale;
+
+    if (w) {
+        *w = width;
+    }
+
+    if (h) {
+        *h = height;
+    }
+}}
+
 int
 Cocoa_GLES_SetupWindow(_THIS, SDL_Window * window)
+{ @autoreleasepool
 {
     NSView* v;
     /* The current context is lost in here; save it and reset it. */
@@ -145,7 +166,7 @@
     }
 
     return Cocoa_GLES_MakeCurrent(_this, current_win, current_ctx);
-}
+}}
 
 SDL_EGLSurface
 Cocoa_GLES_GetEGLSurface(_THIS, SDL_Window * window)
diff --git a/src/video/cocoa/SDL_cocoavideo.m b/src/video/cocoa/SDL_cocoavideo.m
index a354a2451ee7..da43da732ef0 100644
--- a/src/video/cocoa/SDL_cocoavideo.m
+++ b/src/video/cocoa/SDL_cocoavideo.m
@@ -150,6 +150,7 @@ @implementation SDL_VideoData
         device->GL_UnloadLibrary = Cocoa_GLES_UnloadLibrary;
         device->GL_CreateContext = Cocoa_GLES_CreateContext;
         device->GL_MakeCurrent = Cocoa_GLES_MakeCurrent;
+        device->GL_GetDrawableSize = Cocoa_GLES_GetDrawableSize;
         device->GL_SetSwapInterval = Cocoa_GLES_SetSwapInterval;
         device->GL_GetSwapInterval = Cocoa_GLES_GetSwapInterval;
         device->GL_SwapWindow = Cocoa_GLES_SwapWindow;
diff --git a/src/video/cocoa/SDL_cocoawindow.m b/src/video/cocoa/SDL_cocoawindow.m
index eea7f981a662..7d5ee093165a 100644
--- a/src/video/cocoa/SDL_cocoawindow.m
+++ b/src/video/cocoa/SDL_cocoawindow.m
@@ -1787,6 +1787,13 @@ - (BOOL)acceptsFirstMouse:(NSEvent *)theEvent
     if ((window->flags & SDL_WINDOW_OPENGL) &&
         _this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
         [contentView setWantsLayer:TRUE];
+        if (!(window->flags & SDL_WINDOW_ALLOW_HIGHDPI)) {
+            contentView.layer.contentsScale = 1;
+        } else {
+            if ([nswindow.screen respondsToSelector:@selector(backingScaleFactor)]) {
+                contentView.layer.contentsScale = nswindow.screen.backingScaleFactor;
+            }
+        }
     }
 #endif /* SDL_VIDEO_OPENGL_EGL */
 #endif /* SDL_VIDEO_OPENGL_ES2 */