ソースを参照

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.
Ryan C. Gordon 5 年 前
コミット
389c8995d2
4 ファイル変更42 行追加8 行削除
  1. 33 1
      src/video/SDL_egl.c
  2. 1 6
      src/video/SDL_egl_c.h
  3. 5 0
      src/video/SDL_sysvideo.h
  4. 3 1
      src/video/SDL_video.c

+ 33 - 1
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,

+ 1 - 6
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 \

+ 5 - 0
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

+ 3 - 1
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);