opengl: Allow SDL_GL_MakeCurrent() to accept a NULL window (thanks, Martin!). This allows you to bind surfaceless contexts on a background thread to, for example, load assets in a separate context, for platforms that have different requirements about sharing surfaces, etc. Martin's notes on the matter: "Here's a patch that enables passing NULL windows to SDL_GL_MakeCurrent, if the involved APIs allow it. Currently, this is only the case for EGL, and even then only if some specific extensions are present (which they usually are). If "surfaceless" contexts are not supported, SDL_GL_MakeCurrent continues to generate an error (albeit with a more specific error message than it used to), so this should not break anything that wasn't broken before." (Please see https://bugzilla.libsdl.org/show_bug.cgi?id=3695 for more discussion.) Fixes Bugzilla #3695.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
diff --git a/src/video/SDL_egl.c b/src/video/SDL_egl.c
index f89e21b..3a84e4a 100644
--- a/src/video/SDL_egl.c
+++ b/src/video/SDL_egl.c
@@ -81,6 +81,10 @@
#define DEFAULT_OGL_ES "libGLESv1_CM.so.1"
#endif /* SDL_VIDEO_DRIVER_RPI */
+#if SDL_VIDEO_OPENGL
+#include "SDL_opengl.h"
+#endif
+
/** If we happen to not have this defined because of an older EGL version, just define it 0x0
as eglGetPlatformDisplayEXT will most likely be NULL if this is missing
*/
@@ -943,6 +947,34 @@ SDL_EGL_CreateContext(_THIS, EGLSurface egl_surface)
return NULL;
}
+ /* Check whether making contexts current without a surface is supported.
+ * First condition: EGL must support it. That's the case for EGL 1.5
+ * or later, or if the EGL_KHR_surfaceless_context extension is present. */
+ if ((_this->egl_data->egl_version_major > 1) ||
+ ((_this->egl_data->egl_version_major == 1) && (_this->egl_data->egl_version_minor >= 5)) ||
+ SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "EGL_KHR_surfaceless_context"))
+ {
+ /* Secondary condition: The client API must support it. */
+ if (profile_es) {
+ /* On OpenGL ES, the GL_OES_surfaceless_context extension must be
+ * present. */
+ if (SDL_GL_ExtensionSupported("GL_OES_surfaceless_context")) {
+ _this->gl_allow_no_surface = 1;
+ }
+ } else {
+ /* Desktop OpenGL supports it by default from version 3.0 on. */
+ void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params);
+ glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv");
+ if (glGetIntegervFunc) {
+ GLint v = 0;
+ glGetIntegervFunc(GL_MAJOR_VERSION, &v);
+ if (v >= 3) {
+ _this->gl_allow_no_surface = 1;
+ }
+ }
+ }
+ }
+
return (SDL_GLContext) egl_context;
}
@@ -958,7 +990,7 @@ SDL_EGL_MakeCurrent(_THIS, EGLSurface egl_surface, SDL_GLContext context)
/* The android emulator crashes badly if you try to eglMakeCurrent
* with a valid context and invalid surface, so we have to check for both here.
*/
- if (!egl_context || !egl_surface) {
+ if (!egl_context || (!egl_surface && !_this->gl_allow_no_surface)) {
_this->egl_data->eglMakeCurrent(_this->egl_data->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
} else {
if (!_this->egl_data->eglMakeCurrent(_this->egl_data->egl_display,
diff --git a/src/video/SDL_egl_c.h b/src/video/SDL_egl_c.h
index 83bd634..b01d4be 100644
--- a/src/video/SDL_egl_c.h
+++ b/src/video/SDL_egl_c.h
@@ -147,12 +147,7 @@ BACKEND ## _GLES_SwapWindow(_THIS, SDL_Window * window) \
#define SDL_EGL_MakeCurrent_impl(BACKEND) int \
BACKEND ## _GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context) \
{\
- if (window && context) { \
- return SDL_EGL_MakeCurrent(_this, ((SDL_WindowData *) window->driverdata)->egl_surface, context); \
- }\
- else {\
- return SDL_EGL_MakeCurrent(_this, NULL, NULL);\
- }\
+ return SDL_EGL_MakeCurrent(_this, window ? ((SDL_WindowData *) window->driverdata)->egl_surface : EGL_NO_SURFACE, context);\
}
#define SDL_EGL_CreateContext_impl(BACKEND) SDL_GLContext \
diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h
index 6f1faa0..ea907c2 100644
--- a/src/video/SDL_sysvideo.h
+++ b/src/video/SDL_sysvideo.h
@@ -375,6 +375,11 @@ struct SDL_VideoDevice
SDL_TLSID current_glwin_tls;
SDL_TLSID current_glctx_tls;
+ /* Flag that stores whether it's allowed to call SDL_GL_MakeCurrent()
+ * with a NULL window, but a non-NULL context. (Not allowed in most cases,
+ * except on EGL under some circumstances.) */
+ int gl_allow_no_surface;
+
/* * * */
/* Data used by the Vulkan drivers */
struct
diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c
index d8778aa..5cb82b6 100644
--- a/src/video/SDL_video.c
+++ b/src/video/SDL_video.c
@@ -3585,12 +3585,14 @@ SDL_GL_MakeCurrent(SDL_Window * window, SDL_GLContext ctx)
if (!ctx) {
window = NULL;
- } else {
+ } else if (window) {
CHECK_WINDOW_MAGIC(window, -1);
if (!(window->flags & SDL_WINDOW_OPENGL)) {
return SDL_SetError("The specified window isn't an OpenGL window");
}
+ } else if (!_this->gl_allow_no_surface) {
+ return SDL_SetError("Use of OpenGL without a window is not supported on this platform");
}
retval = _this->GL_MakeCurrent(_this, window, ctx);