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
This commit is contained in:
Sam Lantinga 2022-01-07 12:37:28 -08:00
parent 88ac517df0
commit 4b38d4c96b
6 changed files with 55 additions and 10 deletions

View File

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

View File

@ -32,6 +32,7 @@
#import <QuartzCore/CAMetalLayer.h> #import <QuartzCore/CAMetalLayer.h>
#ifdef __MACOSX__ #ifdef __MACOSX__
#import <AppKit/NSWindow.h>
#import <AppKit/NSView.h> #import <AppKit/NSView.h>
#endif #endif
@ -1565,7 +1566,11 @@ METAL_DestroyRenderer(SDL_Renderer * renderer)
DestroyAllPipelines(data.allpipelines, data.pipelinescount); 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); 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!"); 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 * static SDL_Renderer *
METAL_CreateRenderer(SDL_Window * window, Uint32 flags) METAL_CreateRenderer(SDL_Window * window, Uint32 flags)
@ -1659,7 +1691,10 @@ METAL_CreateRenderer(SDL_Window * window, Uint32 flags)
return NULL; return NULL;
} }
view = SDL_Metal_CreateView(window); view = GetWindowView(window);
if (view == nil) {
view = SDL_Metal_CreateView(window);
}
if (view == NULL) { if (view == NULL) {
#if !__has_feature(objc_arc) #if !__has_feature(objc_arc)
@ -1679,7 +1714,11 @@ METAL_CreateRenderer(SDL_Window * window, Uint32 flags)
#if !__has_feature(objc_arc) #if !__has_feature(objc_arc)
[mtldevice release]; [mtldevice release];
#endif #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); SDL_free(renderer);
if (changed_window) { if (changed_window) {
SDL_RecreateWindow(window, window_flags); SDL_RecreateWindow(window, window_flags);

View File

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

View File

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

View File

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

View File

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