From 9a5d5a2839d41fc6250a7f8c48ab4fa54386ac8c Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Thu, 3 Oct 2024 20:09:58 -0400
Subject: [PATCH] video: Improve the EGL attribute callbacks.
Now it has access to information it needs and it's clear who is reponsible
for memory management.
Fixes #11039.
---
include/SDL3/SDL_video.h | 69 ++++++++++++++++++++++++++++++++--------
src/video/SDL_egl.c | 7 ++--
2 files changed, 61 insertions(+), 15 deletions(-)
diff --git a/include/SDL3/SDL_video.h b/include/SDL3/SDL_video.h
index 9fba67c200e38..55bfd72bd0350 100644
--- a/include/SDL3/SDL_video.h
+++ b/include/SDL3/SDL_video.h
@@ -239,12 +239,60 @@ typedef intptr_t SDL_EGLAttrib;
typedef int SDL_EGLint;
/**
- * EGL attribute initialization callback types.
+ * EGL platform attribute initialization callback.
+ *
+ * This is called when SDL is attempting to create an EGL context, to let
+ * the app add extra attributes to its eglGetPlatformDisplay() call.
+ *
+ * The callback should return a pointer to an EGL attribute array terminated
+ * with `EGL_NONE`. If this function returns NULL, the SDL_CreateWindow
+ * process will fail gracefully.
+ *
+ * The returned pointer should be allocated with SDL_malloc() and will be
+ * passed to SDL_free().
+ *
+ * The arrays returned by each callback will be appended to the existing
+ * attribute arrays defined by SDL.
+ *
+ * \param userdata an app-controlled pointer that is passed to the callback.
+ * \returns a newly-allocated array of attributes, terminated with `EGL_NONE`.
*
* \since This datatype is available since SDL 3.0.0.
+ *
+ * \sa SDL_EGL_SetAttributeCallbacks
*/
typedef SDL_EGLAttrib *(SDLCALL *SDL_EGLAttribArrayCallback)(void *userdata);
-typedef SDL_EGLint *(SDLCALL *SDL_EGLIntArrayCallback)(void *userdata);
+
+/**
+ * EGL surface/context attribute initialization callback types.
+ *
+ * This is called when SDL is attempting to create an EGL surface, to let
+ * the app add extra attributes to its eglCreateWindowSurface() or
+ * eglCreateContext calls.
+ *
+ * For convenience, the EGLDisplay and EGLConfig to use are provided to the
+ * callback.
+ *
+ * The callback should return a pointer to an EGL attribute array terminated
+ * with `EGL_NONE`. If this function returns NULL, the SDL_CreateWindow
+ * process will fail gracefully.
+ *
+ * The returned pointer should be allocated with SDL_malloc() and will be
+ * passed to SDL_free().
+ *
+ * The arrays returned by each callback will be appended to the existing
+ * attribute arrays defined by SDL.
+ *
+ * \param userdata an app-controlled pointer that is passed to the callback.
+ * \param display the EGL display to be used.
+ * \param config the EGL config to be used.
+ * \returns a newly-allocated array of attributes, terminated with `EGL_NONE`.
+ *
+ * \since This datatype is available since SDL 3.0.0.
+ *
+ * \sa SDL_EGL_SetAttributeCallbacks
+ */
+typedef SDL_EGLint *(SDLCALL *SDL_EGLIntArrayCallback)(void *userdata, SDL_EGLDisplay display, SDL_EGLConfig config);
/**
* An enumeration of OpenGL configuration attributes.
@@ -2742,28 +2790,23 @@ extern SDL_DECLSPEC SDL_EGLSurface SDLCALL SDL_EGL_GetWindowSurface(SDL_Window *
* Sets the callbacks for defining custom EGLAttrib arrays for EGL
* initialization.
*
- * Each callback should return a pointer to an EGL attribute array terminated
- * with EGL_NONE. Callbacks may return NULL pointers to signal an error, which
- * will cause the SDL_CreateWindow process to fail gracefully.
- *
- * The arrays returned by each callback will be appended to the existing
- * attribute arrays defined by SDL.
+ * Callbacks that aren't needed can be set to NULL.
*
* NOTE: These callback pointers will be reset after SDL_GL_ResetAttributes.
*
* \param platformAttribCallback callback for attributes to pass to
- * eglGetPlatformDisplay.
+ * eglGetPlatformDisplay. May be NULL.
* \param surfaceAttribCallback callback for attributes to pass to
- * eglCreateSurface.
+ * eglCreateSurface. May be NULL.
* \param contextAttribCallback callback for attributes to pass to
- * eglCreateContext.
+ * eglCreateContext. May be NULL.
* \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, void *userdata);
+ SDL_EGLIntArrayCallback surfaceAttribCallback,
+ SDL_EGLIntArrayCallback contextAttribCallback, void *userdata);
/**
* Set the swap interval for the current OpenGL context.
diff --git a/src/video/SDL_egl.c b/src/video/SDL_egl.c
index 19a92fc6b85e1..4caf2db5b3b44 100644
--- a/src/video/SDL_egl.c
+++ b/src/video/SDL_egl.c
@@ -537,6 +537,7 @@ bool SDL_EGL_LoadLibrary(SDL_VideoDevice *_this, const char *egl_path, NativeDis
}
}
_this->egl_data->egl_display = _this->egl_data->eglGetPlatformDisplay(platform, (void *)(uintptr_t)native_display, attribs);
+ SDL_free(attribs);
} else {
if (SDL_EGL_HasExtension(_this, SDL_EGL_CLIENT_EXTENSION, "EGL_EXT_platform_base")) {
_this->egl_data->eglGetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC)SDL_EGL_GetProcAddressInternal(_this, "eglGetPlatformDisplayEXT");
@@ -1038,7 +1039,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(_this->egl_attrib_callback_userdata);
+ userAttribs = _this->egl_contextattrib_callback(_this->egl_attrib_callback_userdata, _this->egl_data->egl_display, _this->egl_data->egl_config);
if (!userAttribs) {
_this->gl_config.driver_loaded = 0;
*_this->gl_config.driver_path = '\0';
@@ -1056,6 +1057,7 @@ SDL_GLContext SDL_EGL_CreateContext(SDL_VideoDevice *_this, EGLSurface egl_surfa
attribs[attr++] = *userAttribP++;
attribs[attr++] = *userAttribP++;
}
+ SDL_free(userAttribs);
}
attribs[attr++] = EGL_NONE;
@@ -1264,7 +1266,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(_this->egl_attrib_callback_userdata);
+ userAttribs = _this->egl_surfaceattrib_callback(_this->egl_attrib_callback_userdata, _this->egl_data->egl_display, _this->egl_data->egl_config);
if (!userAttribs) {
_this->gl_config.driver_loaded = 0;
*_this->gl_config.driver_path = '\0';
@@ -1282,6 +1284,7 @@ EGLSurface SDL_EGL_CreateSurface(SDL_VideoDevice *_this, SDL_Window *window, Nat
attribs[attr++] = *userAttribP++;
attribs[attr++] = *userAttribP++;
}
+ SDL_free(userAttribs);
}
attribs[attr++] = EGL_NONE;