فهرست منبع

Leave the Metal view active on the window when recreating the Metal renderer

Fixes https://github.com/libsdl-org/SDL/issues/5140

Also move the metal tag definition to SDL_syswm.h so it can be used by applications
Sam Lantinga 3 سال پیش
والد
کامیت
4b38d4c96b

+ 4 - 0
include/SDL_syswm.h

@@ -98,6 +98,10 @@ typedef struct _UIViewController UIViewController;
 typedef Uint32 GLuint;
 #endif
 
+#if defined(SDL_VIDEO_VULKAN) || defined(SDL_VIDEO_METAL)
+#define SDL_METALVIEW_TAG 255
+#endif
+
 #if defined(SDL_VIDEO_DRIVER_ANDROID)
 typedef struct ANativeWindow ANativeWindow;
 typedef void *EGLSurface;

+ 42 - 3
src/render/metal/SDL_render_metal.m

@@ -32,6 +32,7 @@
 #import <QuartzCore/CAMetalLayer.h>
 
 #ifdef __MACOSX__
+#import <AppKit/NSWindow.h>
 #import <AppKit/NSView.h>
 #endif
 
@@ -1565,7 +1566,11 @@ METAL_DestroyRenderer(SDL_Renderer * renderer)
 
         DestroyAllPipelines(data.allpipelines, data.pipelinescount);
 
-        SDL_Metal_DestroyView(data.mtlview);
+        /* Release the metal view instead of destroying it,
+           in case we want to use it later (recreating the renderer)
+         */
+        /* SDL_Metal_DestroyView(data.mtlview); */
+        CFBridgingRelease(data.mtlview);
     }
 
     SDL_free(renderer);
@@ -1608,6 +1613,33 @@ METAL_SetVSync(SDL_Renderer * renderer, const int vsync)
     return SDL_SetError("This Apple OS does not support displaySyncEnabled!");
 }
 
+static SDL_MetalView GetWindowView(SDL_Window *window)
+{
+    SDL_SysWMinfo info;
+
+    SDL_VERSION(&info.version);
+    if (SDL_GetWindowWMInfo(window, &info)) {
+#ifdef __MACOSX__
+        if (info.subsystem == SDL_SYSWM_COCOA) {
+            NSView *view = info.info.cocoa.window.contentView;
+            if (view.subviews.count > 0) {
+                view = view.subviews[0];
+                if (view.tag == SDL_METALVIEW_TAG) {
+                    return (SDL_MetalView)CFBridgingRetain(view);
+                }
+            }
+        }
+#else
+        if (info.subsystem == SDL_SYSWM_UIKIT) {
+            UIView *view = info.info.uikit.window.rootViewController.view;
+            if (view.tag == SDL_METALVIEW_TAG) {
+                return (SDL_MetalView)CFBridgingRetain(view);
+            }
+        }
+#endif
+    }
+    return nil;
+}
 
 static SDL_Renderer *
 METAL_CreateRenderer(SDL_Window * window, Uint32 flags)
@@ -1659,7 +1691,10 @@ METAL_CreateRenderer(SDL_Window * window, Uint32 flags)
         return NULL;
     }
 
-    view = SDL_Metal_CreateView(window);
+    view = GetWindowView(window);
+    if (view == nil) {
+        view = SDL_Metal_CreateView(window);
+    }
 
     if (view == NULL) {
 #if !__has_feature(objc_arc)
@@ -1679,7 +1714,11 @@ METAL_CreateRenderer(SDL_Window * window, Uint32 flags)
 #if !__has_feature(objc_arc)
         [mtldevice release];
 #endif
-        SDL_Metal_DestroyView(view);
+        /* Release the metal view instead of destroying it,
+           in case we want to use it later (recreating the renderer)
+         */
+        /* SDL_Metal_DestroyView(view); */
+        CFBridgingRelease(view);
         SDL_free(renderer);
         if (changed_window) {
             SDL_RecreateWindow(window, window_flags);

+ 0 - 1
src/video/cocoa/SDL_cocoametalview.h

@@ -39,7 +39,6 @@
 #import <Metal/Metal.h>
 #import <QuartzCore/CAMetalLayer.h>
 
-#define METALVIEW_TAG 255
 
 @interface SDL_cocoametalview : NSView
 

+ 4 - 2
src/video/cocoa/SDL_cocoametalview.m

@@ -31,6 +31,8 @@
 #if SDL_VIDEO_DRIVER_COCOA && (SDL_VIDEO_VULKAN || SDL_VIDEO_METAL)
 
 #include "SDL_events.h"
+#include "SDL_syswm.h"
+
 
 static int SDLCALL
 SDL_MetalViewEventWatch(void *userdata, SDL_Event *event)
@@ -103,7 +105,7 @@ SDL_MetalViewEventWatch(void *userdata, SDL_Event *event)
 
 - (NSInteger)tag
 {
-    return METALVIEW_TAG;
+    return SDL_METALVIEW_TAG;
 }
 
 - (void)updateDrawableSize
@@ -173,7 +175,7 @@ Cocoa_Metal_GetDrawableSize(_THIS, SDL_Window * window, int * w, int * h)
 { @autoreleasepool {
     SDL_WindowData *data = (__bridge SDL_WindowData *)window->driverdata;
     NSView *contentView = data->sdlContentView;
-    SDL_cocoametalview* metalview = [contentView viewWithTag:METALVIEW_TAG];
+    SDL_cocoametalview* metalview = [contentView viewWithTag:SDL_METALVIEW_TAG];
     if (metalview) {
         CAMetalLayer *layer = (CAMetalLayer*)metalview.layer;
         SDL_assert(layer != NULL);

+ 0 - 1
src/video/uikit/SDL_uikitmetalview.h

@@ -38,7 +38,6 @@
 #import <Metal/Metal.h>
 #import <QuartzCore/CAMetalLayer.h>
 
-#define METALVIEW_TAG 255
 
 @interface SDL_uikitmetalview : SDL_uikitview
 

+ 5 - 3
src/video/uikit/SDL_uikitmetalview.m

@@ -30,7 +30,9 @@
 
 #if SDL_VIDEO_DRIVER_UIKIT && (SDL_VIDEO_VULKAN || SDL_VIDEO_METAL)
 
-#import "../SDL_sysvideo.h"
+#include "SDL_syswm.h"
+#include "../SDL_sysvideo.h"
+
 #import "SDL_uikitwindow.h"
 #import "SDL_uikitmetalview.h"
 
@@ -47,7 +49,7 @@
                         scale:(CGFloat)scale
 {
     if ((self = [super initWithFrame:frame])) {
-        self.tag = METALVIEW_TAG;
+        self.tag = SDL_METALVIEW_TAG;
         self.layer.contentsScale = scale;
         [self updateDrawableSize];
     }
@@ -122,7 +124,7 @@ UIKit_Metal_GetDrawableSize(_THIS, SDL_Window * window, int * w, int * h)
     @autoreleasepool {
         SDL_WindowData *data = (__bridge SDL_WindowData *)window->driverdata;
         SDL_uikitview *view = (SDL_uikitview*)data.uiwindow.rootViewController.view;
-        SDL_uikitmetalview* metalview = [view viewWithTag:METALVIEW_TAG];
+        SDL_uikitmetalview* metalview = [view viewWithTag:SDL_METALVIEW_TAG];
         if (metalview) {
             CAMetalLayer *layer = (CAMetalLayer*)metalview.layer;
             assert(layer != NULL);