Turn off the Vulkan thread when switching away from the app.

This commit is contained in:
Henrik Rydgård 2024-05-23 12:52:16 +02:00
parent b66f7ea909
commit aa3256f4e8
5 changed files with 75 additions and 39 deletions

View file

@ -1,4 +1,5 @@
#import "AppDelegate.h" #import "AppDelegate.h"
#import "ViewControllerCommon.h"
#import "ViewController.h" #import "ViewController.h"
#import "ViewControllerMetal.h" #import "ViewControllerMetal.h"
#import "iOSCoreAudio.h" #import "iOSCoreAudio.h"
@ -119,6 +120,9 @@
} }
-(void) applicationWillResignActive:(UIApplication *)application { -(void) applicationWillResignActive:(UIApplication *)application {
INFO_LOG(G3D, "willResignActive");
[self.viewController willResignActive];
if (g_Config.bEnableSound) { if (g_Config.bEnableSound) {
iOSCoreAudioShutdown(); iOSCoreAudioShutdown();
} }
@ -127,11 +131,13 @@
} }
-(void) applicationDidBecomeActive:(UIApplication *)application { -(void) applicationDidBecomeActive:(UIApplication *)application {
INFO_LOG(G3D, "didBecomeActive");
if (g_Config.bEnableSound) { if (g_Config.bEnableSound) {
iOSCoreAudioInit(); iOSCoreAudioInit();
} }
System_PostUIMessage(UIMessage::GOT_FOCUS); System_PostUIMessage(UIMessage::GOT_FOCUS);
[self.viewController didBecomeActive];
} }
- (void)applicationWillTerminate:(UIApplication *)application { - (void)applicationWillTerminate:(UIApplication *)application {

View file

@ -238,6 +238,14 @@ extern float g_safeInsetBottom;
[self shutdown]; [self shutdown];
} }
- (void)willResignActive {
}
- (void)didBecomeActive {
}
- (void)shutdown - (void)shutdown
{ {
if (sharedViewController == nil) { if (sharedViewController == nil) {

View file

@ -16,6 +16,10 @@
- (void)startVideo:(int)width height:(int)height; - (void)startVideo:(int)width height:(int)height;
- (void)stopVideo; - (void)stopVideo;
// Forwarded from the AppDelegate
- (void)didBecomeActive;
- (void)willResignActive;
@end @end
extern id <PPSSPPViewController> sharedViewController; extern id <PPSSPPViewController> sharedViewController;

View file

@ -26,6 +26,9 @@
#include "Core/HLE/sceUsbCam.h" #include "Core/HLE/sceUsbCam.h"
#include "Core/HLE/sceUsbGps.h" #include "Core/HLE/sceUsbGps.h"
// ViewController lifecycle:
// https://www.progressconcepts.com/blog/ios-appdelegate-viewcontroller-method-order/
// TODO: Share this between backends. // TODO: Share this between backends.
static uint32_t FlagsFromConfig() { static uint32_t FlagsFromConfig() {
uint32_t flags; uint32_t flags;
@ -178,33 +181,7 @@ bool IOSVulkanContext::InitAPI() {
info.app_name = "PPSSPP"; info.app_name = "PPSSPP";
info.app_ver = gitVer.ToInteger(); info.app_ver = gitVer.ToInteger();
info.flags = FlagsFromConfig(); info.flags = FlagsFromConfig();
VkResult res = g_Vulkan->CreateInstance(info); if (!g_Vulkan->CreateInstanceAndDevice(info)) {
if (res != VK_SUCCESS) {
ERROR_LOG(G3D, "Failed to create vulkan context: %s", g_Vulkan->InitError().c_str());
VulkanSetAvailable(false);
delete g_Vulkan;
g_Vulkan = nullptr;
state_ = GraphicsContextState::FAILED_INIT;
return false;
}
int physicalDevice = g_Vulkan->GetBestPhysicalDevice();
if (physicalDevice < 0) {
ERROR_LOG(G3D, "No usable Vulkan device found.");
g_Vulkan->DestroyInstance();
delete g_Vulkan;
g_Vulkan = nullptr;
state_ = GraphicsContextState::FAILED_INIT;
return false;
}
g_Vulkan->ChooseDevice(physicalDevice);
INFO_LOG(G3D, "Creating Vulkan device (flags: %08x)", info.flags);
if (g_Vulkan->CreateDevice() != VK_SUCCESS) {
INFO_LOG(G3D, "Failed to create vulkan device: %s", g_Vulkan->InitError().c_str());
System_Toast("No Vulkan driver found. Using OpenGL instead.");
g_Vulkan->DestroyInstance();
delete g_Vulkan; delete g_Vulkan;
g_Vulkan = nullptr; g_Vulkan = nullptr;
state_ = GraphicsContextState::FAILED_INIT; state_ = GraphicsContextState::FAILED_INIT;
@ -228,6 +205,7 @@ static std::atomic<bool> exitRenderLoop;
static std::atomic<bool> renderLoopRunning; static std::atomic<bool> renderLoopRunning;
static bool renderer_inited = false; static bool renderer_inited = false;
static std::mutex renderLock; static std::mutex renderLock;
static std::thread g_vulkanRenderLoopThread;
@interface PPSSPPViewControllerMetal () { @interface PPSSPPViewControllerMetal () {
ICadeTracker g_iCadeTracker; ICadeTracker g_iCadeTracker;
@ -258,7 +236,7 @@ static std::mutex renderLock;
} }
// Should be very similar to the Android one, probably mergeable. // Should be very similar to the Android one, probably mergeable.
void VulkanRenderLoop(IOSVulkanContext *graphicsContext, CAMetalLayer *metalLayer, int desiredBackbufferSizeX, int desiredBackbufferSizeY) { void VulkanRenderLoop(IOSVulkanContext *graphicsContext, CAMetalLayer *metalLayer) {
SetCurrentThreadName("EmuThread"); SetCurrentThreadName("EmuThread");
if (!graphicsContext) { if (!graphicsContext) {
@ -278,6 +256,9 @@ void VulkanRenderLoop(IOSVulkanContext *graphicsContext, CAMetalLayer *metalLaye
// This is up here to prevent race conditions, in case we pause during init. // This is up here to prevent race conditions, in case we pause during init.
renderLoopRunning = true; renderLoopRunning = true;
int desiredBackbufferSizeX = g_display.pixel_xres;
int desiredBackbufferSizeY = g_display.pixel_yres;
//WARN_LOG(G3D, "runVulkanRenderLoop. desiredBackbufferSizeX=%d desiredBackbufferSizeY=%d", //WARN_LOG(G3D, "runVulkanRenderLoop. desiredBackbufferSizeX=%d desiredBackbufferSizeY=%d",
// desiredBackbufferSizeX, desiredBackbufferSizeY); // desiredBackbufferSizeX, desiredBackbufferSizeY);
@ -328,6 +309,45 @@ void VulkanRenderLoop(IOSVulkanContext *graphicsContext, CAMetalLayer *metalLaye
WARN_LOG(G3D, "Render loop function exited."); WARN_LOG(G3D, "Render loop function exited.");
} }
- (bool)runVulkanRenderLoop {
if (!graphicsContext) {
ERROR_LOG(G3D, "runVulkanRenderLoop: Tried to enter without a created graphics context.");
return false;
}
if (g_vulkanRenderLoopThread.joinable()) {
ERROR_LOG(G3D, "runVulkanRenderLoop: Already running");
return false;
}
CAMetalLayer *metalLayer = (CAMetalLayer *)self.view.layer;
g_vulkanRenderLoopThread = std::thread(VulkanRenderLoop, graphicsContext, metalLayer);
return true;
}
- (void)requestExitVulkanRenderLoop {
if (!renderLoopRunning) {
ERROR_LOG(SYSTEM, "Render loop already exited");
return;
}
_assert_(g_vulkanRenderLoopThread.joinable());
exitRenderLoop = true;
g_vulkanRenderLoopThread.join();
_assert_(!g_vulkanRenderLoopThread.joinable());
g_vulkanRenderLoopThread = std::thread();
}
// These two are forwarded from the appDelegate
- (void)didBecomeActive {
// Spin up the emu thread. It will in turn spin up the Vulkan render thread
// on its own.
[self runVulkanRenderLoop];
}
- (void)willResignActive {
[self requestExitVulkanRenderLoop];
}
- (void)loadView { - (void)loadView {
INFO_LOG(G3D, "Creating metal view"); INFO_LOG(G3D, "Creating metal view");
@ -356,15 +376,11 @@ void VulkanRenderLoop(IOSVulkanContext *graphicsContext, CAMetalLayer *metalLaye
_assert_msg_(false, "Failed to init Vulkan"); _assert_msg_(false, "Failed to init Vulkan");
} }
int desiredBackbufferSizeX = g_display.pixel_xres;
int desiredBackbufferSizeY = g_display.pixel_yres;
if ([[GCController controllers] count] > 0) { if ([[GCController controllers] count] > 0) {
[self setupController:[[GCController controllers] firstObject]]; [self setupController:[[GCController controllers] firstObject]];
} }
INFO_LOG(G3D, "Detected size: %dx%d", desiredBackbufferSizeX, desiredBackbufferSizeY); INFO_LOG(G3D, "Detected size: %dx%d", g_display.pixel_xres, g_display.pixel_yres);
CAMetalLayer *layer = (CAMetalLayer *)self.view.layer;
cameraHelper = [[CameraHelper alloc] init]; cameraHelper = [[CameraHelper alloc] init];
[cameraHelper setDelegate:self]; [cameraHelper setDelegate:self];
@ -378,11 +394,6 @@ void VulkanRenderLoop(IOSVulkanContext *graphicsContext, CAMetalLayer *metalLaye
[mBackGestureRecognizer setEdges:UIRectEdgeLeft]; [mBackGestureRecognizer setEdges:UIRectEdgeLeft];
[[self view] addGestureRecognizer:mBackGestureRecognizer]; [[self view] addGestureRecognizer:mBackGestureRecognizer];
// Spin up the emu thread. It will in turn spin up the Vulkan render thread
// on its own.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
VulkanRenderLoop(graphicsContext, layer, desiredBackbufferSizeX, desiredBackbufferSizeY);
});
} }
// Allow device rotation to resize the swapchain // Allow device rotation to resize the swapchain
@ -397,10 +408,16 @@ void VulkanRenderLoop(IOSVulkanContext *graphicsContext, CAMetalLayer *metalLaye
} }
- (void)viewWillAppear:(BOOL)animated { - (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear: animated]; [super viewWillAppear:animated];
INFO_LOG(G3D, "viewWillAppear");
self.view.contentScaleFactor = UIScreen.mainScreen.nativeScale; self.view.contentScaleFactor = UIScreen.mainScreen.nativeScale;
} }
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
INFO_LOG(G3D, "viewWillDisappear");
}
- (void)viewDidDisappear:(BOOL)animated { - (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear: animated]; [super viewDidDisappear: animated];
} }

View file

@ -392,6 +392,7 @@ void System_Notify(SystemNotification notification) {
bool System_MakeRequest(SystemRequestType type, int requestId, const std::string &param1, const std::string &param2, int64_t param3, int64_t param4) { bool System_MakeRequest(SystemRequestType type, int requestId, const std::string &param1, const std::string &param2, int64_t param3, int64_t param4) {
switch (type) { switch (type) {
case SystemRequestType::EXIT_APP: case SystemRequestType::EXIT_APP:
// NOTE: on iOS, this is considered a crash and not a valid way to exit.
exit(0); exit(0);
// The below seems right, but causes hangs. See #12140. // The below seems right, but causes hangs. See #12140.
// dispatch_async(dispatch_get_main_queue(), ^{ // dispatch_async(dispatch_get_main_queue(), ^{