From 1c49ad7b2944846aa2765902a2fe57f22d479116 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 27 May 2025 15:50:39 +0200 Subject: [PATCH 1/3] Support screen rotation on iOS (unrestricted) --- Common/GPU/Vulkan/VulkanFrameData.h | 8 ++++ Common/GPU/Vulkan/VulkanRenderManager.cpp | 3 +- Core/Dialog/SavedataParam.cpp | 4 +- Core/ELF/ParamSFO.cpp | 2 - Core/HLE/sceDisplay.cpp | 2 +- UI/GameSettingsScreen.cpp | 8 +++- UI/ImDebugger/ImDisasmView.cpp | 4 +- ios/AppDelegate.mm | 4 ++ ios/Controls.mm | 6 +-- ios/DisplayManager.mm | 4 -- ios/PPSSPP-Info.plist | 2 + ios/SceneDelegate.h | 2 +- ios/SceneDelegate.mm | 15 +++---- ios/ViewController.mm | 4 +- ios/ViewControllerMetal.mm | 50 +++++++++++------------ ios/main.mm | 4 +- 16 files changed, 65 insertions(+), 57 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanFrameData.h b/Common/GPU/Vulkan/VulkanFrameData.h index bcad1ed798..dbde815515 100644 --- a/Common/GPU/Vulkan/VulkanFrameData.h +++ b/Common/GPU/Vulkan/VulkanFrameData.h @@ -8,9 +8,17 @@ #include "Common/GPU/Vulkan/VulkanContext.h" #include "Common/Data/Collections/Hashmaps.h" +#if PPSSPP_PLATFORM(IOS) +// iOS doesn't support a large number of timestamp queries natively. +// We don't want MoltenVK to fall back to emulation. +enum { + MAX_TIMESTAMP_QUERIES = 32, +}; +#else enum { MAX_TIMESTAMP_QUERIES = 128, }; +#endif enum class VKRRunType { SUBMIT, diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index 34ee1126ec..add3fe357e 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -423,8 +423,9 @@ void VulkanRenderManager::StartThreads() { } } -// Called from main thread. +// MUST be called from emuthread! void VulkanRenderManager::StopThreads() { + INFO_LOG(Log::G3D, "VulkanRenderManager::StopThreads"); // Make sure we don't have an open non-backbuffer render pass if (curRenderStep_ && curRenderStep_->render.framebuffer != nullptr) { EndCurRenderStep(); diff --git a/Core/Dialog/SavedataParam.cpp b/Core/Dialog/SavedataParam.cpp index 4a6ac820bc..a94acc9a6e 100644 --- a/Core/Dialog/SavedataParam.cpp +++ b/Core/Dialog/SavedataParam.cpp @@ -200,7 +200,9 @@ void SaveFileInfo::DoState(PointerWrap &p) delete texture; texture = new PPGeImage(""); } - texture->DoState(p); + if (texture) { + texture->DoState(p); + } } } } diff --git a/Core/ELF/ParamSFO.cpp b/Core/ELF/ParamSFO.cpp index b92c437591..63041fc250 100644 --- a/Core/ELF/ParamSFO.cpp +++ b/Core/ELF/ParamSFO.cpp @@ -132,8 +132,6 @@ bool ParamSFOData::ReadSFO(const u8 *paramsfo, size_t size) { return false; } - const u8 *data_start = paramsfo + header->data_table_start; - auto readStringCapped = [paramsfo, size](size_t offset, size_t maxLen) -> std::string { std::string str; while (offset < size) { diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index 7d231e4b15..22417b5172 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -614,7 +614,7 @@ void __DisplayFlip(int cyclesLate) { const double fpsLimit = FrameTimingLimit(); bool throttle = fpsLimit != 0.0; - bool refreshRateNeedsSkip = fpsLimit != framerate && fpsLimit > refreshRate || !throttle; + bool refreshRateNeedsSkip = (fpsLimit != framerate && fpsLimit > refreshRate) || !throttle; g_frameTiming.ComputePresentMode(draw, refreshRateNeedsSkip); diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 94035085ad..7fc46e9e4d 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1332,19 +1332,23 @@ void GameSettingsScreen::CreateSystemSettings(UI::ViewGroup *systemSettings) { PopupSliderChoice *exitConfirmation = systemSettings->Add(new PopupSliderChoice(&g_Config.iAskForExitConfirmationAfterSeconds, 0, 1200, 60, sy->T("Ask for exit confirmation after seconds"), screenManager(), "s")); exitConfirmation->SetZeroLabel(sy->T("Off")); -#if PPSSPP_PLATFORM(ANDROID) if (System_GetPropertyInt(SYSPROP_DEVICE_TYPE) == DEVICE_TYPE_MOBILE) { auto co = GetI18NCategory(I18NCat::CONTROLS); static const char *screenRotation[] = { "Auto", "Landscape", "Portrait", "Landscape Reversed", "Portrait Reversed", "Landscape Auto" }; PopupMultiChoice *rot = systemSettings->Add(new PopupMultiChoice(&g_Config.iScreenRotation, co->T("Screen Rotation"), screenRotation, 0, ARRAY_SIZE(screenRotation), I18NCat::CONTROLS, screenManager())); + #if PPSSPP_PLATFORM(IOS) + // Portrait Reversed is not recommended on iPhone (and we also ban it in the plist). + // However it's recommended to support it on iPad, so maybe we will in the future. + rot->HideChoice(4); + #endif + rot->OnChoice.Handle(this, &GameSettingsScreen::OnScreenRotation); if (System_GetPropertyBool(SYSPROP_SUPPORTS_SUSTAINED_PERF_MODE)) { systemSettings->Add(new CheckBox(&g_Config.bSustainedPerformanceMode, sy->T("Sustained performance mode")))->OnClick.Handle(this, &GameSettingsScreen::OnSustainedPerformanceModeChange); } } -#endif systemSettings->Add(new Choice(sy->T("Restore Default Settings")))->OnClick.Handle(this, &GameSettingsScreen::OnRestoreDefaultSettings); systemSettings->Add(new CheckBox(&g_Config.bEnableStateUndo, sy->T("Savestate slot backups"))); diff --git a/UI/ImDebugger/ImDisasmView.cpp b/UI/ImDebugger/ImDisasmView.cpp index ac8d369d65..7d5b42acd5 100644 --- a/UI/ImDebugger/ImDisasmView.cpp +++ b/UI/ImDebugger/ImDisasmView.cpp @@ -52,8 +52,10 @@ static ImColor scaleColor(ImColor color, float factor) { } bool ImDisasmView::getDisasmAddressText(u32 address, char *dest, size_t bufSize, bool abbreviateLabels, bool showData) { - if (PSP_GetBootState() != BootState::Complete) + if (PSP_GetBootState() != BootState::Complete) { + dest[0] = '\0'; return false; + } return GetDisasmAddressText(address, dest, bufSize, abbreviateLabels, showData, displaySymbols_); } diff --git a/ios/AppDelegate.mm b/ios/AppDelegate.mm index 0b9a30d0b0..f2c4e0b609 100644 --- a/ios/AppDelegate.mm +++ b/ios/AppDelegate.mm @@ -107,4 +107,8 @@ __attribute__((used)) static Class _forceLinkSceneDelegate = [SceneDelegate clas - (void)applicationWillTerminate:(UIApplication *)application { } +- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window { + return UIInterfaceOrientationMaskAll; // or at least include Portrait +} + @end diff --git a/ios/Controls.mm b/ios/Controls.mm index 71d8cacca8..652a3bb9bb 100644 --- a/ios/Controls.mm +++ b/ios/Controls.mm @@ -86,7 +86,6 @@ bool InitController(GCController *controller) { analogTriggerPressed(JOYSTICK_AXIS_RTRIGGER, value); }; -#if defined(__IPHONE_12_1) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_12_1 if ([extendedProfile respondsToSelector:@selector(leftThumbstickButton)] && extendedProfile.leftThumbstickButton != nil) { extendedProfile.leftThumbstickButton.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { controllerButtonPressed(pressed, NKCODE_BUTTON_THUMBL); @@ -97,8 +96,7 @@ bool InitController(GCController *controller) { controllerButtonPressed(pressed, NKCODE_BUTTON_THUMBR); }; } -#endif -#if defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0 + if ([extendedProfile respondsToSelector:@selector(buttonOptions)] && extendedProfile.buttonOptions != nil) { extendedProfile.buttonOptions.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { controllerButtonPressed(pressed, NKCODE_BUTTON_SELECT); @@ -109,7 +107,7 @@ bool InitController(GCController *controller) { controllerButtonPressed(pressed, NKCODE_BUTTON_START); }; } -#endif + #if defined(__IPHONE_14_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_0 if ([extendedProfile respondsToSelector:@selector(buttonHome)] && extendedProfile.buttonHome != nil) { extendedProfile.buttonHome.valueChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { diff --git a/ios/DisplayManager.mm b/ios/DisplayManager.mm index dc891dd859..a8b72cb912 100644 --- a/ios/DisplayManager.mm +++ b/ios/DisplayManager.mm @@ -140,10 +140,6 @@ - (void)updateResolution:(UIScreen *)screen { float scale = screen.nativeScale; CGSize size = screen.bounds.size; - - if (size.height > size.width) { - std::swap(size.height, size.width); - } float dpi; if (screen == [UIScreen mainScreen]) { diff --git a/ios/PPSSPP-Info.plist b/ios/PPSSPP-Info.plist index c23fc0655d..b32d595237 100644 --- a/ios/PPSSPP-Info.plist +++ b/ios/PPSSPP-Info.plist @@ -60,11 +60,13 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + UIInterfaceOrientationPortrait UISupportedInterfaceOrientations~ipad UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + UIInterfaceOrientationPortrait UILaunchImageFile Default.png diff --git a/ios/SceneDelegate.h b/ios/SceneDelegate.h index dba6229282..213895595f 100644 --- a/ios/SceneDelegate.h +++ b/ios/SceneDelegate.h @@ -1,12 +1,12 @@ // SceneDelegate.h #import +#import "ViewControllerCommon.h" @interface SceneDelegate : UIResponder - (void)restart:(const char *)args; @property (strong, nonatomic) UIWindow * window; -@property (strong, nonatomic) UIViewController *viewController; @property (strong, nonatomic) UIWindowScene *windowScene; @end diff --git a/ios/SceneDelegate.mm b/ios/SceneDelegate.mm index cc722e336a..d55e59c2c0 100644 --- a/ios/SceneDelegate.mm +++ b/ios/SceneDelegate.mm @@ -61,14 +61,12 @@ // Choose viewcontroller depending on backend. if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN) { PPSSPPViewControllerMetal *vc = [[PPSSPPViewControllerMetal alloc] init]; - - self.viewController = vc; + // sharedViewController gets initialized in the constructor. self.window.rootViewController = vc; } else { PPSSPPViewControllerGL *vc = [[PPSSPPViewControllerGL alloc] init]; // Here we can switch viewcontroller depending on backend. - self.viewController = vc; self.window.rootViewController = vc; } @@ -79,12 +77,11 @@ INFO_LOG(Log::G3D, "SceneDelegate: Restart requested: %s", restartArgs); // Notify current view controller - [self.viewController willResignActive]; - [self.viewController shutdown]; + [sharedViewController willResignActive]; + [sharedViewController shutdown]; // Remove the current root view controller self.window.rootViewController = nil; - self.viewController = nil; INFO_LOG(Log::G3D, "SceneDelegate: viewController nilled"); @@ -95,13 +92,13 @@ [self launchPPSSPP]; // Notify new view controller - [self.viewController didBecomeActive]; + [sharedViewController didBecomeActive]; } - (void)sceneWillResignActive:(UIScene *)scene { INFO_LOG(Log::G3D, "sceneWillResignActive"); - [self.viewController willResignActive]; + [sharedViewController willResignActive]; if (g_Config.bEnableSound) { iOSCoreAudioShutdown(); @@ -119,6 +116,6 @@ System_PostUIMessage(UIMessage::GOT_FOCUS); - [self.viewController didBecomeActive]; + [sharedViewController didBecomeActive]; } @end diff --git a/ios/ViewController.mm b/ios/ViewController.mm index ad90523eb8..62e776e21c 100644 --- a/ios/ViewController.mm +++ b/ios/ViewController.mm @@ -390,9 +390,9 @@ void GLRenderLoop(IOSGLESContext *graphicsContext) { INFO_LOG(Log::System, "dealloc GL"); } -- (NSUInteger)supportedInterfaceOrientations +- (UIInterfaceOrientationMask)supportedInterfaceOrientations { - return UIInterfaceOrientationMaskLandscape; + return UIInterfaceOrientationMaskAll; } - (void)glkView:(GLKView *)view drawInRect:(CGRect)rect diff --git a/ios/ViewControllerMetal.mm b/ios/ViewControllerMetal.mm index 7d5ab12245..cdf794dc79 100644 --- a/ios/ViewControllerMetal.mm +++ b/ios/ViewControllerMetal.mm @@ -53,7 +53,7 @@ public: void ShutdownFromRenderThread() override; // Inverses InitFromRenderThread. void Shutdown() override; - void Resize() override; + void Resize() override {} void *GetAPIContext() override { return g_Vulkan; } Draw::DrawContext *GetDrawContext() override { return draw_; } @@ -85,7 +85,11 @@ bool IOSVulkanContext::InitFromRenderThread(CAMetalLayer *layer, int desiredBack draw_ = Draw::T3DCreateVulkanContext(g_Vulkan, useMultiThreading); VkPresentModeKHR presentMode = ConfigPresentModeToVulkan(draw_); - if (!g_Vulkan->InitSwapchain(presentMode)) { + + // This MUST run on the main thread. We're taking our chances with a dispatch_sync here. + g_Vulkan->InitSwapchain(presentMode); + + if (false) { delete draw_; ERROR_LOG(Log::G3D, "InitSwapchain failed"); g_Vulkan->DestroySwapchain(); @@ -126,19 +130,6 @@ void IOSVulkanContext::Shutdown() { INFO_LOG(Log::G3D, "IOSVulkanContext::Shutdown completed"); } -void IOSVulkanContext::Resize() { - INFO_LOG(Log::G3D, "IOSVulkanContext::Resize begin (oldsize: %dx%d)", g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); - - draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); - g_Vulkan->DestroySwapchain(); - g_Vulkan->DestroySurface(); - g_Vulkan->ReinitSurface(); - VkPresentModeKHR presentMode = ConfigPresentModeToVulkan(draw_); - g_Vulkan->InitSwapchain(presentMode); - draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); - INFO_LOG(Log::G3D, "IOSVulkanContext::Resize end (final size: %dx%d)", g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); -} - bool IOSVulkanContext::InitAPI() { INFO_LOG(Log::G3D, "IOSVulkanContext::Init"); init_glslang(); @@ -232,6 +223,7 @@ static std::thread g_renderLoopThread; } // Should be very similar to the Android one, probably mergeable. +// This is the EmuThread for iOS. void VulkanRenderLoop(IOSVulkanContext *graphicsContext, CAMetalLayer *metalLayer) { SetCurrentThreadName("EmuThreadVulkan"); INFO_LOG(Log::G3D, "Entering EmuThreadVulkan"); @@ -435,12 +427,6 @@ void VulkanRenderLoop(IOSVulkanContext *graphicsContext, CAMetalLayer *metalLaye self.motionManager = [[CMMotionManager alloc] init]; } -// Allow device rotation to resize the swapchain --(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator { - [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; - // TODO: Handle resizing properly. -} - - (UIView *)getView { return [self view]; } @@ -560,11 +546,6 @@ extern float g_safeInsetBottom; // Do nothing } -- (NSUInteger)supportedInterfaceOrientations -{ - return UIInterfaceOrientationMaskLandscape; -} - - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { g_touchTracker.Began(touches, self.view); @@ -763,6 +744,23 @@ extern float g_safeInsetBottom; [self hideKeyboard]; } +- (void)viewWillTransitionToSize:(CGSize)size + withTransitionCoordinator:(id)coordinator { + [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; + + [self.view endEditing:YES]; // clears any input focus + + [coordinator animateAlongsideTransition:^(id context) { + NSLog(@"Rotating to size: %@", NSStringFromCGSize(size)); + } completion:^(id context) { + NSLog(@"Rotation finished"); + // Reinitialize graphics context to match new size + [self requestExitVulkanRenderLoop]; + [self runVulkanRenderLoop]; + [[DisplayManager shared] updateResolution:[UIScreen mainScreen]]; + }]; +} + @end @implementation PPSSPPMetalView diff --git a/ios/main.mm b/ios/main.mm index 47597ccaf4..31a1fdd712 100644 --- a/ios/main.mm +++ b/ios/main.mm @@ -630,9 +630,7 @@ AudioBackend *System_CreateAudioBackend() { return nullptr; } -int main(int argc, char *argv[]) -{ - // SetCurrentThreadName("MainThread"); +int main(int argc, char *argv[]) { version = [[[UIDevice currentDevice] systemVersion] UTF8String]; if (1 != sscanf(version.c_str(), "%d", &g_iosVersionMajor)) { // Just set it to 14.0 if the parsing fails for whatever reason. From c5dcb0009cc96330674fb4b55d820e79fe42e034 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 22 Oct 2025 15:19:12 +0200 Subject: [PATCH 2/3] Support screen rotation in OpenGL as well. --- ios/ViewController.mm | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/ios/ViewController.mm b/ios/ViewController.mm index 62e776e21c..57e04de1ab 100644 --- a/ios/ViewController.mm +++ b/ios/ViewController.mm @@ -643,6 +643,23 @@ void GLRenderLoop(IOSGLESContext *graphicsContext) { [self hideKeyboard]; } +- (void)viewWillTransitionToSize:(CGSize)size + withTransitionCoordinator:(id)coordinator { + [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; + + [self.view endEditing:YES]; // clears any input focus + + [coordinator animateAlongsideTransition:^(id context) { + NSLog(@"Rotating to size: %@", NSStringFromCGSize(size)); + } completion:^(id context) { + NSLog(@"Rotation finished"); + // Reinitialize graphics context to match new size + [self requestExitGLRenderLoop]; + [self runGLRenderLoop]; + [[DisplayManager shared] updateResolution:[UIScreen mainScreen]]; + }]; +} + @end void bindDefaultFBO() From e2b21d26bfd6906183ad1e2b11addb903fa0b3ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 22 Oct 2025 15:54:00 +0200 Subject: [PATCH 3/3] Rotation on iOS fixes: Make sure the setting is saved, etc. --- Core/Config.cpp | 13 +++++++++++-- ios/AppDelegate.mm | 18 +++++++++++++++++- ios/ViewController.mm | 4 ++-- ios/ViewControllerMetal.mm | 1 + ios/main.mm | 8 ++++++++ 5 files changed, 39 insertions(+), 5 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index dc9576cae2..ebac1e73a0 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -213,6 +213,14 @@ static int DefaultUIScaleFactor() { #endif } +static int DefaultScreenRotation() { +#if PPSSPP_PLATFORM(ANDROID) + return ROTATION_LOCKED_HORIZONTAL; +#else + return ROTATION_AUTO; +#endif +} + static const ConfigSetting generalSettings[] = { ConfigSetting("FirstRun", &g_Config.bFirstRun, true, CfgFlag::DEFAULT), ConfigSetting("RunCount", &g_Config.iRunCount, 0, CfgFlag::DEFAULT), @@ -297,9 +305,10 @@ static const ConfigSetting generalSettings[] = { ConfigSetting("RemoteISOShareType", &g_Config.iRemoteISOShareType, (int)RemoteISOShareType::RECENT, CfgFlag::DEFAULT), ConfigSetting("AskForExitConfirmationAfterSeconds", &g_Config.iAskForExitConfirmationAfterSeconds, 60, CfgFlag::PER_GAME), -#ifdef __ANDROID__ - ConfigSetting("ScreenRotation", &g_Config.iScreenRotation, ROTATION_AUTO_HORIZONTAL), +#if PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(IOS) + ConfigSetting("ScreenRotation", &g_Config.iScreenRotation, &DefaultScreenRotation, CfgFlag::DEFAULT), #endif + ConfigSetting("InternalScreenRotation", &g_Config.iInternalScreenRotation, ROTATION_LOCKED_HORIZONTAL, CfgFlag::PER_GAME), ConfigSetting("BackgroundAnimation", &g_Config.iBackgroundAnimation, 1, CfgFlag::DEFAULT), diff --git a/ios/AppDelegate.mm b/ios/AppDelegate.mm index f2c4e0b609..94634c1f39 100644 --- a/ios/AppDelegate.mm +++ b/ios/AppDelegate.mm @@ -108,7 +108,23 @@ __attribute__((used)) static Class _forceLinkSceneDelegate = [SceneDelegate clas } - (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window { - return UIInterfaceOrientationMaskAll; // or at least include Portrait + switch (g_Config.iScreenRotation) { + case ROTATION_LOCKED_HORIZONTAL: + return UIInterfaceOrientationMaskLandscapeRight; + case ROTATION_LOCKED_VERTICAL: + case ROTATION_LOCKED_VERTICAL180: + // We do not support reverse portrait on iOS. + return UIInterfaceOrientationMaskPortrait; + case ROTATION_LOCKED_HORIZONTAL180: + return UIInterfaceOrientationMaskLandscapeLeft; + case ROTATION_AUTO_HORIZONTAL: + return UIInterfaceOrientationMaskLandscape; + case ROTATION_AUTO: + default: + return UIInterfaceOrientationMaskAll; + } + + return UIInterfaceOrientationMaskAll; // or at least include Portrait } @end diff --git a/ios/ViewController.mm b/ios/ViewController.mm index 57e04de1ab..b6b2b40e38 100644 --- a/ios/ViewController.mm +++ b/ios/ViewController.mm @@ -269,8 +269,6 @@ void GLRenderLoop(IOSGLESContext *graphicsContext) { [EAGLContext setCurrentContext:self.context]; self.preferredFramesPerSecond = 60; // NOTE: We don't yet take advantage of 120hz screens - [[DisplayManager shared] updateResolution:[UIScreen mainScreen]]; - graphicsContext = new IOSGLESContext(); graphicsContext->GetDrawContext()->SetErrorCallback([](const char *shortDesc, const char *details, void *userdata) { @@ -336,6 +334,8 @@ void GLRenderLoop(IOSGLESContext *graphicsContext) { INFO_LOG(Log::G3D, "No accelerometer available, not starting updates."); } [self runGLRenderLoop]; + [[DisplayManager shared] updateResolution:[UIScreen mainScreen]]; + INFO_LOG(Log::System, "didBecomeActive end"); } diff --git a/ios/ViewControllerMetal.mm b/ios/ViewControllerMetal.mm index cdf794dc79..f7ce3c38ef 100644 --- a/ios/ViewControllerMetal.mm +++ b/ios/ViewControllerMetal.mm @@ -343,6 +343,7 @@ void VulkanRenderLoop(IOSVulkanContext *graphicsContext, CAMetalLayer *metalLaye // Spin up the emu thread. It will in turn spin up the Vulkan render thread // on its own. [self runVulkanRenderLoop]; + [[DisplayManager shared] updateResolution:[UIScreen mainScreen]]; } - (void)willResignActive { diff --git a/ios/main.mm b/ios/main.mm index 31a1fdd712..bfc64a3034 100644 --- a/ios/main.mm +++ b/ios/main.mm @@ -431,6 +431,14 @@ void System_Notify(SystemNotification notification) { iOSCoreAudioUpdateSession(); }); break; + case SystemNotification::ROTATE_UPDATED: + dispatch_async(dispatch_get_main_queue(), ^{ + if (sharedViewController) { + // [sharedViewController setNeedsUpdateOfSupportedInterfaceOrientations]; + INFO_LOG(Log::System, "Requesting device orientation update"); + [UIViewController attemptRotationToDeviceOrientation]; + } + }); default: break; }