diff --git a/include/SDL_video.h b/include/SDL_video.h index cfbed9c89..ed7bcd36f 100644 --- a/include/SDL_video.h +++ b/include/SDL_video.h @@ -223,6 +223,14 @@ typedef void *SDL_GLContext; typedef void *SDL_EGLDisplay; typedef void *SDL_EGLConfig; typedef void *SDL_EGLSurface; +typedef intptr_t SDL_EGLAttrib; +typedef int SDL_EGLint; + +/** + * \brief EGL attribute initialization callback types. + */ +typedef SDL_EGLAttrib *(SDLCALL *SDL_EGLAttribArrayCallback)(void); +typedef SDL_EGLint *(SDLCALL *SDL_EGLIntArrayCallback)(void); /** * \brief OpenGL configuration attributes @@ -2089,6 +2097,30 @@ extern DECLSPEC SDL_EGLConfig SDLCALL SDL_EGL_GetCurrentEGLConfig(void); */ extern DECLSPEC SDL_EGLSurface SDLCALL SDL_EGL_GetWindowEGLSurface(SDL_Window * 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. + * + * NOTE: These callback pointers will be reset after SDL_GL_ResetAttributes. + * + * \param platformAttribCallback Callback for attributes to pass to + * eglGetPlatformDisplay. + * \param surfaceAttribCallback Callback for attributes to pass to + * eglCreateSurface. + * \param contextAttribCallback Callback for attributes to pass to + * eglCreateContext. + */ +extern DECLSPEC void SDLCALL SDL_EGL_SetEGLAttributeCallbacks(SDL_EGLAttribArrayCallback platformAttribCallback, + SDL_EGLIntArrayCallback surfaceAttribCallback, + SDL_EGLIntArrayCallback contextAttribCallback); + /** * 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 072b99ba9..78f64b59f 100644 --- a/src/video/SDL_egl.c +++ b/src/video/SDL_egl.c @@ -514,7 +514,16 @@ SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_displa } if (_this->egl_data->eglGetPlatformDisplay) { - _this->egl_data->egl_display = _this->egl_data->eglGetPlatformDisplay(platform, (void *)(uintptr_t)native_display, NULL); + EGLAttrib *attribs = NULL; + if (_this->egl_platformattrib_callback) { + attribs = _this->egl_platformattrib_callback(); + if (!attribs) { + _this->gl_config.driver_loaded = 0; + *_this->gl_config.driver_path = '\0'; + return SDL_SetError("EGL platform attribute callback returned NULL pointer"); + } + } + _this->egl_data->egl_display = _this->egl_data->eglGetPlatformDisplay(platform, (void *)(uintptr_t)native_display, attribs); } else { if (SDL_EGL_HasExtension(_this, SDL_EGL_CLIENT_EXTENSION, "EGL_EXT_platform_base")) { _this->egl_data->eglGetPlatformDisplayEXT = SDL_EGL_GetProcAddressInternal(_this, "eglGetPlatformDisplayEXT"); @@ -934,8 +943,8 @@ SDL_EGL_ChooseConfig(_THIS) SDL_GLContext SDL_EGL_CreateContext(_THIS, EGLSurface egl_surface) { - /* max 14 values plus terminator. */ - EGLint attribs[15]; + /* max 16 key+value pairs plus terminator. */ + EGLint attribs[33]; int attr = 0; EGLContext egl_context, share_context = EGL_NO_CONTEXT; @@ -1024,6 +1033,29 @@ SDL_EGL_CreateContext(_THIS, EGLSurface egl_surface) } #endif + if (_this->egl_contextattrib_callback) { + const int maxAttribs = sizeof(attribs) / sizeof(attribs[0]); + EGLint *userAttribs, *userAttribP; + userAttribs = _this->egl_contextattrib_callback(); + if (!userAttribs) { + _this->gl_config.driver_loaded = 0; + *_this->gl_config.driver_path = '\0'; + SDL_SetError("EGL context attribute callback returned NULL pointer"); + return NULL; + } + + for (userAttribP = userAttribs; *userAttribP != EGL_NONE; ) { + if (attr + 3 >= maxAttribs) { + _this->gl_config.driver_loaded = 0; + *_this->gl_config.driver_path = '\0'; + SDL_SetError("EGL context attribute callback returned too many attributes"); + return NULL; + } + attribs[attr++] = *userAttribP++; + attribs[attr++] = *userAttribP++; + } + } + attribs[attr++] = EGL_NONE; /* Bind the API */ @@ -1190,8 +1222,8 @@ SDL_EGL_CreateSurface(_THIS, NativeWindowType nw) EGLint format_wanted; EGLint format_got; #endif - /* max 2 key+value pairs, plus terminator. */ - EGLint attribs[5]; + /* max 16 key+value pairs, plus terminator. */ + EGLint attribs[33]; int attr = 0; EGLSurface * surface; @@ -1232,6 +1264,29 @@ SDL_EGL_CreateSurface(_THIS, NativeWindowType nw) } #endif + if (_this->egl_surfaceattrib_callback) { + const int maxAttribs = sizeof(attribs) / sizeof(attribs[0]); + EGLint *userAttribs, *userAttribP; + userAttribs = _this->egl_surfaceattrib_callback(); + if (!userAttribs) { + _this->gl_config.driver_loaded = 0; + *_this->gl_config.driver_path = '\0'; + SDL_SetError("EGL surface attribute callback returned NULL pointer"); + return EGL_NO_SURFACE; + } + + for (userAttribP = userAttribs; *userAttribP != EGL_NONE; ) { + if (attr + 3 >= maxAttribs) { + _this->gl_config.driver_loaded = 0; + *_this->gl_config.driver_path = '\0'; + SDL_SetError("EGL surface attribute callback returned too many attributes"); + return EGL_NO_SURFACE; + } + attribs[attr++] = *userAttribP++; + attribs[attr++] = *userAttribP++; + } + } + attribs[attr++] = EGL_NONE; surface = _this->egl_data->eglCreateWindowSurface( diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index 63d3eea84..5fd794a55 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -398,6 +398,10 @@ struct SDL_VideoDevice void *dll_handle; } gl_config; + SDL_EGLAttribArrayCallback egl_platformattrib_callback; + SDL_EGLIntArrayCallback egl_surfaceattrib_callback; + SDL_EGLIntArrayCallback egl_contextattrib_callback; + /* * * */ /* Cache current GL context; don't call the OS when it hasn't changed. */ /* We have the global pointers here so Cocoa continues to work the way diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index 36276e969..294f93d54 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -3646,6 +3646,18 @@ SDL_GL_DeduceMaxSupportedESProfile(int* major, int* minor) #endif } +void SDL_EGL_SetEGLAttributeCallbacks(SDL_EGLAttribArrayCallback platformAttribCallback, + SDL_EGLIntArrayCallback surfaceAttribCallback, + SDL_EGLIntArrayCallback contextAttribCallback) +{ + if (!_this) { + return; + } + _this->egl_platformattrib_callback = platformAttribCallback; + _this->egl_surfaceattrib_callback = surfaceAttribCallback; + _this->egl_contextattrib_callback = contextAttribCallback; +} + void SDL_GL_ResetAttributes() { @@ -3653,6 +3665,10 @@ SDL_GL_ResetAttributes() return; } + _this->egl_platformattrib_callback = NULL; + _this->egl_surfaceattrib_callback = NULL; + _this->egl_contextattrib_callback = NULL; + _this->gl_config.red_size = 3; _this->gl_config.green_size = 3; _this->gl_config.blue_size = 2;