SDL: Added a userdata parameter for EGL attribute callbacks

From eced9f58a9cff8b9aa33d1c36fccb2a20c7a8b38 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Tue, 1 Oct 2024 10:43:51 -0700
Subject: [PATCH] Added a userdata parameter for EGL attribute callbacks

Fixes https://github.com/libsdl-org/SDL/issues/11013
---
 include/SDL3/SDL_video.h      | 9 +++++----
 src/dynapi/SDL_dynapi_procs.h | 2 +-
 src/video/SDL_egl.c           | 6 +++---
 src/video/SDL_sysvideo.h      | 1 +
 src/video/SDL_video.c         | 7 +++++--
 5 files changed, 15 insertions(+), 10 deletions(-)

diff --git a/include/SDL3/SDL_video.h b/include/SDL3/SDL_video.h
index 3207120e5a675..d2f8e3cf14ab1 100644
--- a/include/SDL3/SDL_video.h
+++ b/include/SDL3/SDL_video.h
@@ -243,8 +243,8 @@ typedef int SDL_EGLint;
  *
  * \since This datatype is available since SDL 3.0.0.
  */
-typedef SDL_EGLAttrib *(SDLCALL *SDL_EGLAttribArrayCallback)(void);
-typedef SDL_EGLint *(SDLCALL *SDL_EGLIntArrayCallback)(void);
+typedef SDL_EGLAttrib *(SDLCALL *SDL_EGLAttribArrayCallback)(void *userdata);
+typedef SDL_EGLint *(SDLCALL *SDL_EGLIntArrayCallback)(void *userdata);
 
 /**
  * An enumeration of OpenGL configuration attributes.
@@ -2756,13 +2756,14 @@ extern SDL_DECLSPEC SDL_EGLSurface SDLCALL SDL_EGL_GetWindowSurface(SDL_Window *
  * \param surfaceAttribCallback callback for attributes to pass to
  *                              eglCreateSurface.
  * \param contextAttribCallback callback for attributes to pass to
- *                              eglCreateContext.
+ *                              eglCreateContext. 
+ * \param userdata a pointer that is passed to the callbacks.
  *
  * \since This function is available since SDL 3.0.0.
  */
 extern SDL_DECLSPEC void SDLCALL SDL_EGL_SetAttributeCallbacks(SDL_EGLAttribArrayCallback platformAttribCallback,
                                                               SDL_EGLIntArrayCallback surfaceAttribCallback,
-                                                              SDL_EGLIntArrayCallback contextAttribCallback);
+                                                              SDL_EGLIntArrayCallback contextAttribCallback, void *userdata);
 
 /**
  * Set the swap interval for the current OpenGL context.
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index 1ece8bd1d5d76..0af785b79795c 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -199,7 +199,7 @@ SDL_DYNAPI_PROC(SDL_EGLConfig,SDL_EGL_GetCurrentConfig,(void),(),return)
 SDL_DYNAPI_PROC(SDL_EGLDisplay,SDL_EGL_GetCurrentDisplay,(void),(),return)
 SDL_DYNAPI_PROC(SDL_FunctionPointer,SDL_EGL_GetProcAddress,(const char *a),(a),return)
 SDL_DYNAPI_PROC(SDL_EGLSurface,SDL_EGL_GetWindowSurface,(SDL_Window *a),(a),return)
-SDL_DYNAPI_PROC(void,SDL_EGL_SetAttributeCallbacks,(SDL_EGLAttribArrayCallback a, SDL_EGLIntArrayCallback b, SDL_EGLIntArrayCallback c),(a,b,c),)
+SDL_DYNAPI_PROC(void,SDL_EGL_SetAttributeCallbacks,(SDL_EGLAttribArrayCallback a, SDL_EGLIntArrayCallback b, SDL_EGLIntArrayCallback c, void *d),(a,b,c,d),)
 SDL_DYNAPI_PROC(bool,SDL_EnableScreenSaver,(void),(),return)
 SDL_DYNAPI_PROC(void,SDL_EndGPUComputePass,(SDL_GPUComputePass *a),(a),)
 SDL_DYNAPI_PROC(void,SDL_EndGPUCopyPass,(SDL_GPUCopyPass *a),(a),)
diff --git a/src/video/SDL_egl.c b/src/video/SDL_egl.c
index c85c6abc60d65..19a92fc6b85e1 100644
--- a/src/video/SDL_egl.c
+++ b/src/video/SDL_egl.c
@@ -529,7 +529,7 @@ bool SDL_EGL_LoadLibrary(SDL_VideoDevice *_this, const char *egl_path, NativeDis
         if (_this->egl_data->eglGetPlatformDisplay) {
             EGLAttrib *attribs = NULL;
             if (_this->egl_platformattrib_callback) {
-                attribs = _this->egl_platformattrib_callback();
+                attribs = _this->egl_platformattrib_callback(_this->egl_attrib_callback_userdata);
                 if (!attribs) {
                     _this->gl_config.driver_loaded = 0;
                     *_this->gl_config.driver_path = '\0';
@@ -1038,7 +1038,7 @@ SDL_GLContext SDL_EGL_CreateContext(SDL_VideoDevice *_this, EGLSurface egl_surfa
     if (_this->egl_contextattrib_callback) {
         const int maxAttribs = sizeof(attribs) / sizeof(attribs[0]);
         EGLint *userAttribs, *userAttribP;
-        userAttribs = _this->egl_contextattrib_callback();
+        userAttribs = _this->egl_contextattrib_callback(_this->egl_attrib_callback_userdata);
         if (!userAttribs) {
             _this->gl_config.driver_loaded = 0;
             *_this->gl_config.driver_path = '\0';
@@ -1264,7 +1264,7 @@ EGLSurface SDL_EGL_CreateSurface(SDL_VideoDevice *_this, SDL_Window *window, Nat
     if (_this->egl_surfaceattrib_callback) {
         const int maxAttribs = sizeof(attribs) / sizeof(attribs[0]);
         EGLint *userAttribs, *userAttribP;
-        userAttribs = _this->egl_surfaceattrib_callback();
+        userAttribs = _this->egl_surfaceattrib_callback(_this->egl_attrib_callback_userdata);
         if (!userAttribs) {
             _this->gl_config.driver_loaded = 0;
             *_this->gl_config.driver_path = '\0';
diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h
index aada061e9b225..db53fe6e00aff 100644
--- a/src/video/SDL_sysvideo.h
+++ b/src/video/SDL_sysvideo.h
@@ -443,6 +443,7 @@ struct SDL_VideoDevice
     SDL_EGLAttribArrayCallback egl_platformattrib_callback;
     SDL_EGLIntArrayCallback egl_surfaceattrib_callback;
     SDL_EGLIntArrayCallback egl_contextattrib_callback;
+    void *egl_attrib_callback_userdata;
 
     /* * * */
     // Cache current GL context; don't call the OS when it hasn't changed.
diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c
index 716a4bede8073..a0a147caec2c0 100644
--- a/src/video/SDL_video.c
+++ b/src/video/SDL_video.c
@@ -4448,8 +4448,9 @@ void SDL_GL_DeduceMaxSupportedESProfile(int *major, int *minor)
 }
 
 void SDL_EGL_SetAttributeCallbacks(SDL_EGLAttribArrayCallback platformAttribCallback,
-                                      SDL_EGLIntArrayCallback surfaceAttribCallback,
-                                      SDL_EGLIntArrayCallback contextAttribCallback)
+                                   SDL_EGLIntArrayCallback surfaceAttribCallback,
+                                   SDL_EGLIntArrayCallback contextAttribCallback,
+                                   void *userdata)
 {
     if (!_this) {
         return;
@@ -4457,6 +4458,7 @@ void SDL_EGL_SetAttributeCallbacks(SDL_EGLAttribArrayCallback platformAttribCall
     _this->egl_platformattrib_callback = platformAttribCallback;
     _this->egl_surfaceattrib_callback = surfaceAttribCallback;
     _this->egl_contextattrib_callback = contextAttribCallback;
+    _this->egl_attrib_callback_userdata = userdata;
 }
 
 void SDL_GL_ResetAttributes(void)
@@ -4468,6 +4470,7 @@ void SDL_GL_ResetAttributes(void)
     _this->egl_platformattrib_callback = NULL;
     _this->egl_surfaceattrib_callback = NULL;
     _this->egl_contextattrib_callback = NULL;
+    _this->egl_attrib_callback_userdata = NULL;
 
     _this->gl_config.red_size = 8;
     _this->gl_config.green_size = 8;