Просмотр исходного кода

wayland: Make external window reconfiguration more robust

External window surfaces can't be destroyed and recreated, so try our best to reconfigure them when switching between GL profiles, or between GL and Vulkan.
Frank Praznik 2 дней назад
Родитель
Сommit
b3f8367134
2 измененных файлов с 53 добавлено и 14 удалено
  1. 22 5
      src/video/SDL_video.c
  2. 31 9
      src/video/wayland/SDL_waylandwindow.c

+ 22 - 5
src/video/SDL_video.c

@@ -2666,11 +2666,6 @@ static bool SDL_ReconfigureWindowInternal(SDL_Window *window, SDL_WindowFlags fl
         return false;
         return false;
     }
     }
 
 
-    // Only attempt to reconfigure if the window has no existing graphics flags.
-    if (window->flags & (SDL_WINDOW_OPENGL | SDL_WINDOW_METAL | SDL_WINDOW_VULKAN)) {
-        return false;
-    }
-
     const SDL_WindowFlags graphics_flags = flags & (SDL_WINDOW_OPENGL | SDL_WINDOW_METAL | SDL_WINDOW_VULKAN);
     const SDL_WindowFlags graphics_flags = flags & (SDL_WINDOW_OPENGL | SDL_WINDOW_METAL | SDL_WINDOW_VULKAN);
     if (graphics_flags & (graphics_flags - 1)) {
     if (graphics_flags & (graphics_flags - 1)) {
         return SDL_SetError("Conflicting window flags specified");
         return SDL_SetError("Conflicting window flags specified");
@@ -2686,6 +2681,28 @@ static bool SDL_ReconfigureWindowInternal(SDL_Window *window, SDL_WindowFlags fl
         return SDL_ContextNotSupported("Metal");
         return SDL_ContextNotSupported("Metal");
     }
     }
 
 
+    if (!(window->flags & SDL_WINDOW_EXTERNAL)) {
+        // Only attempt to reconfigure if the window has no existing graphics flags.
+        if (window->flags & (SDL_WINDOW_OPENGL | SDL_WINDOW_METAL | SDL_WINDOW_VULKAN)) {
+            return false;
+        }
+    } else {
+        // Can't destroy and recreate an external window, so try our best to reconfigure it.
+        if (!_this->ReconfigureWindow(_this, window, 0)) {
+            return false;
+        }
+
+        // Reload the GL/Vulkan libraries in case the profile changed.
+        if (window->flags & SDL_WINDOW_OPENGL) {
+            SDL_GL_UnloadLibrary();
+        }
+        if (window->flags & SDL_WINDOW_VULKAN) {
+            SDL_Vulkan_UnloadLibrary();
+        }
+
+        window->flags &= ~(SDL_WINDOW_OPENGL | SDL_WINDOW_METAL | SDL_WINDOW_VULKAN);
+    }
+
     SDL_DestroyWindowSurface(window);
     SDL_DestroyWindowSurface(window);
 
 
     if (graphics_flags & SDL_WINDOW_OPENGL) {
     if (graphics_flags & SDL_WINDOW_OPENGL) {

+ 31 - 9
src/video/wayland/SDL_waylandwindow.c

@@ -2870,8 +2870,9 @@ bool Wayland_ReconfigureWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_W
         return false;
         return false;
     }
     }
 
 
-    /* The caller guarantees that only one of the GL or Vulkan flags will be set,
-     * and the window will have no previous video flags.
+    /* The caller guarantees that only one of the GL or Vulkan flags will be set.
+     * Note that Vulkan doesn't require any specific configuration, so only EGL
+     * objects are added and removed as required.
      */
      */
     if (flags & SDL_WINDOW_OPENGL) {
     if (flags & SDL_WINDOW_OPENGL) {
         if (!data->egl_window) {
         if (!data->egl_window) {
@@ -2879,11 +2880,10 @@ bool Wayland_ReconfigureWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_W
         }
         }
 
 
 #ifdef SDL_VIDEO_OPENGL_EGL
 #ifdef SDL_VIDEO_OPENGL_EGL
-        // Create the GLES window surface
         data->egl_surface = SDL_EGL_CreateSurface(_this, window, (NativeWindowType)data->egl_window);
         data->egl_surface = SDL_EGL_CreateSurface(_this, window, (NativeWindowType)data->egl_window);
 
 
         if (data->egl_surface == EGL_NO_SURFACE) {
         if (data->egl_surface == EGL_NO_SURFACE) {
-            return false; // SDL_EGL_CreateSurface should have set error
+            return false; // SDL_EGL_CreateSurface should have set the error.
         }
         }
 #endif
 #endif
 
 
@@ -2894,14 +2894,36 @@ bool Wayland_ReconfigureWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_W
             data->gles_swap_frame_callback = wl_surface_frame(data->gles_swap_frame_surface_wrapper);
             data->gles_swap_frame_callback = wl_surface_frame(data->gles_swap_frame_surface_wrapper);
             wl_callback_add_listener(data->gles_swap_frame_callback, &gles_swap_frame_listener, data);
             wl_callback_add_listener(data->gles_swap_frame_callback, &gles_swap_frame_listener, data);
         }
         }
+    } else {
+#ifdef SDL_VIDEO_OPENGL_EGL
+        if (data->egl_surface) {
+            SDL_EGL_DestroySurface(_this, data->egl_surface);
+            data->egl_surface = EGL_NO_SURFACE;
+        }
+#endif
 
 
-        return true;
-    } else if (flags & SDL_WINDOW_VULKAN) {
-        // Nothing to configure for Vulkan.
-        return true;
+        if (data->egl_window) {
+            WAYLAND_wl_egl_window_destroy(data->egl_window);
+            data->egl_window = NULL;
+        }
+
+        if (data->gles_swap_frame_callback) {
+            wl_callback_destroy(data->gles_swap_frame_callback);
+            data->gles_swap_frame_callback = NULL;
+        }
+
+        if (data->gles_swap_frame_surface_wrapper) {
+            WAYLAND_wl_proxy_wrapper_destroy(data->gles_swap_frame_surface_wrapper);
+            data->gles_swap_frame_surface_wrapper = NULL;
+        }
+
+        if (data->gles_swap_frame_event_queue) {
+            WAYLAND_wl_event_queue_destroy(data->gles_swap_frame_event_queue);
+            data->gles_swap_frame_event_queue = NULL;
+        }
     }
     }
 
 
-    return false;
+    return true;
 }
 }
 
 
 bool Wayland_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props)
 bool Wayland_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props)