Skip to content

Commit

Permalink
opengl: Allow SDL_GL_MakeCurrent() to accept a NULL window (thanks, M…
Browse files Browse the repository at this point in the history
…artin!).

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.
  • Loading branch information
icculus committed Apr 13, 2020
1 parent e6c640f commit 389c899
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 8 deletions.
34 changes: 33 additions & 1 deletion src/video/SDL_egl.c
Expand Up @@ -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
*/
Expand Down Expand Up @@ -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;
}

Expand All @@ -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,
Expand Down
7 changes: 1 addition & 6 deletions src/video/SDL_egl_c.h
Expand Up @@ -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 \
Expand Down
5 changes: 5 additions & 0 deletions src/video/SDL_sysvideo.h
Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion src/video/SDL_video.c
Expand Up @@ -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);
Expand Down

0 comments on commit 389c899

Please sign in to comment.