From 70656b133c89c614422130b6c7e0a52cdccc6d4f Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Tue, 15 Nov 2022 10:18:41 -0800
Subject: [PATCH] Don't recreate the window when creating a Metal renderer on
an OpenGL window.
It turns out that we can safely create a Metal view on an existing window, and that avoids issues with the window being recreated with the wrong orientation in iOS 16.
Fixes https://github.com/libsdl-org/SDL/issues/6289
---
src/render/metal/SDL_render_metal.m | 25 -------------------------
src/video/SDL_video.c | 12 ++++++++++--
src/video/uikit/SDL_uikitmetalview.m | 12 ------------
src/video/uikit/SDL_uikitview.h | 2 --
src/video/uikit/SDL_uikitview.m | 25 +------------------------
5 files changed, 11 insertions(+), 65 deletions(-)
diff --git a/src/render/metal/SDL_render_metal.m b/src/render/metal/SDL_render_metal.m
index 3dc346d57e45..80fd96f07542 100644
--- a/src/render/metal/SDL_render_metal.m
+++ b/src/render/metal/SDL_render_metal.m
@@ -55,9 +55,6 @@
/* Apple Metal renderer implementation */
-/* Used to re-create the window with Metal capability */
-extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags);
-
/* macOS requires constants in a buffer to have a 256 byte alignment. */
/* Use native type alignments from https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf */
#if defined(__MACOSX__) || TARGET_OS_SIMULATOR || TARGET_OS_MACCATALYST
@@ -1635,13 +1632,11 @@ static SDL_MetalView GetWindowView(SDL_Window *window)
SDL_MetalView view = NULL;
CAMetalLayer *layer = nil;
SDL_SysWMinfo syswm;
- SDL_bool changed_window = SDL_FALSE;
NSError *err = nil;
dispatch_data_t mtllibdata;
char *constantdata;
int maxtexsize, quadcount = UINT16_MAX / 4;
UInt16 *indexdata;
- Uint32 window_flags;
size_t indicessize = sizeof(UInt16) * quadcount * 6;
MTLSamplerDescriptor *samplerdesc;
id<MTLCommandQueue> mtlcmdqueue;
@@ -1697,20 +1692,9 @@ static SDL_MetalView GetWindowView(SDL_Window *window)
return NULL;
}
- window_flags = SDL_GetWindowFlags(window);
- if (!(window_flags & SDL_WINDOW_METAL)) {
- changed_window = SDL_TRUE;
- if (SDL_RecreateWindow(window, (window_flags & ~(SDL_WINDOW_VULKAN | SDL_WINDOW_OPENGL)) | SDL_WINDOW_METAL) < 0) {
- return NULL;
- }
- }
-
renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
if (!renderer) {
SDL_OutOfMemory();
- if (changed_window) {
- SDL_RecreateWindow(window, window_flags);
- }
return NULL;
}
@@ -1720,9 +1704,6 @@ static SDL_MetalView GetWindowView(SDL_Window *window)
if (mtldevice == nil) {
SDL_free(renderer);
SDL_SetError("Failed to obtain Metal device");
- if (changed_window) {
- SDL_RecreateWindow(window, window_flags);
- }
return NULL;
}
@@ -1733,9 +1714,6 @@ static SDL_MetalView GetWindowView(SDL_Window *window)
if (view == NULL) {
SDL_free(renderer);
- if (changed_window) {
- SDL_RecreateWindow(window, window_flags);
- }
return NULL;
}
@@ -1749,9 +1727,6 @@ 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);
- }
return NULL;
}
diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c
index 51e282f066c5..c75b026d981a 100644
--- a/src/video/SDL_video.c
+++ b/src/video/SDL_video.c
@@ -4853,8 +4853,16 @@ SDL_Metal_CreateView(SDL_Window * window)
CHECK_WINDOW_MAGIC(window, NULL);
if (!(window->flags & SDL_WINDOW_METAL)) {
- SDL_SetError("The specified window isn't a Metal window");
- return NULL;
+ /* No problem, we can convert to Metal */
+ if (window->flags & SDL_WINDOW_OPENGL) {
+ window->flags &= ~SDL_WINDOW_OPENGL;
+ SDL_GL_UnloadLibrary();
+ }
+ if (window->flags & SDL_WINDOW_VULKAN) {
+ window->flags &= ~SDL_WINDOW_VULKAN;
+ SDL_Vulkan_UnloadLibrary();
+ }
+ window->flags |= SDL_WINDOW_METAL;
}
return _this->Metal_CreateView(_this, window);
diff --git a/src/video/uikit/SDL_uikitmetalview.m b/src/video/uikit/SDL_uikitmetalview.m
index af6eb0cd3ebe..8bc3380955e8 100644
--- a/src/video/uikit/SDL_uikitmetalview.m
+++ b/src/video/uikit/SDL_uikitmetalview.m
@@ -69,18 +69,6 @@ - (void)updateDrawableSize
CGSize size = self.bounds.size;
size.width *= self.layer.contentsScale;
size.height *= self.layer.contentsScale;
-
- /* Make sure the width/height are oriented correctly
- *
- * This works around an issue in iOS 16 where the bounds come back in portrait mode
- * instead of landscape until the event loop runs.
- */
- if ([self shouldSwapDimensions:(size.width >= size.height)]) {
- CGFloat temp = size.width;
- size.width = size.height;
- size.height = temp;
- }
-
((CAMetalLayer *)self.layer).drawableSize = size;
}
diff --git a/src/video/uikit/SDL_uikitview.h b/src/video/uikit/SDL_uikitview.h
index 5369bb212455..dcd63c7a5645 100644
--- a/src/video/uikit/SDL_uikitview.h
+++ b/src/video/uikit/SDL_uikitview.h
@@ -35,8 +35,6 @@
- (void)setSDLWindow:(SDL_Window *)window;
-- (BOOL)shouldSwapDimensions:(BOOL)portrait;
-
#if !TARGET_OS_TV && defined(__IPHONE_13_4)
- (UIPointerRegion *)pointerInteraction:(UIPointerInteraction *)interaction regionForRequest:(UIPointerRegionRequest *)request defaultRegion:(UIPointerRegion *)defaultRegion API_AVAILABLE(ios(13.4));
- (UIPointerStyle *)pointerInteraction:(UIPointerInteraction *)interaction styleForRegion:(UIPointerRegion *)region API_AVAILABLE(ios(13.4));
diff --git a/src/video/uikit/SDL_uikitview.m b/src/video/uikit/SDL_uikitview.m
index 50d7393e7f30..8c48cfa503b9 100644
--- a/src/video/uikit/SDL_uikitview.m
+++ b/src/video/uikit/SDL_uikitview.m
@@ -120,8 +120,6 @@ - (void)setSDLWindow:(SDL_Window *)window
[data.uiwindow layoutIfNeeded];
}
- sdlwindow = window;
-
/* Add ourself to the new window. */
if (window) {
data = (__bridge SDL_WindowData *) window->driverdata;
@@ -146,29 +144,8 @@ - (void)setSDLWindow:(SDL_Window *)window
* layout now to immediately update the bounds. */
[data.uiwindow layoutIfNeeded];
}
-}
-
-- (BOOL)shouldSwapDimensions:(BOOL)landscape
-{
-#if !TARGET_OS_TV
- if (sdlwindow) {
- SDL_VideoDisplay *display = SDL_GetDisplayForWindow(sdlwindow);
- SDL_DisplayData *displaydata = (__bridge SDL_DisplayData *) display->driverdata;
- if (displaydata.uiscreen == [UIScreen mainScreen]) {
- NSUInteger orients = UIKit_GetSupportedOrientations(sdlwindow);
- BOOL supportsLandscape = (orients & UIInterfaceOrientationMaskLandscape) != 0;
- BOOL supportsPortrait = (orients & (UIInterfaceOrientationMaskPortrait|UIInterfaceOrientationMaskPortraitUpsideDown)) != 0;
-
- /* Make sure the width/height are oriented correctly */
- if ((landscape && !supportsLandscape) || (!landscape && !supportsPortrait)) {
- return YES;
- }
- }
- }
-#endif /* !TARGET_OS_TV */
-
- return NO;
+ sdlwindow = window;
}
#if !TARGET_OS_TV && defined(__IPHONE_13_4)