diff --git a/Common/File/FileUtil.cpp b/Common/File/FileUtil.cpp index 5aa74027b7..df550d0a45 100644 --- a/Common/File/FileUtil.cpp +++ b/Common/File/FileUtil.cpp @@ -340,6 +340,9 @@ std::string ResolvePath(const std::string &path) { delete [] buf; return output; +#elif PPSSPP_PLATFORM(IOS) + // Resolving has wacky effects on documents paths. + return path; #else std::unique_ptr buf(new char[PATH_MAX + 32768]); if (realpath(path.c_str(), buf.get()) == nullptr) @@ -404,8 +407,8 @@ bool Exists(const Path &path) { SetErrorMode(OldMode); #endif return true; -#else - struct stat file_info; +#else // !WIN32 + struct stat file_info{}; return stat(path.c_str(), &file_info) == 0; #endif } diff --git a/Common/GPU/Vulkan/VulkanLoader.cpp b/Common/GPU/Vulkan/VulkanLoader.cpp index 24e128aada..b16e6357f2 100644 --- a/Common/GPU/Vulkan/VulkanLoader.cpp +++ b/Common/GPU/Vulkan/VulkanLoader.cpp @@ -381,8 +381,8 @@ void VulkanSetAvailable(bool available) { bool VulkanMayBeAvailable() { #if PPSSPP_PLATFORM(IOS) g_vulkanAvailabilityChecked = true; + // MoltenVK does no longer seem to support iOS <= 12, despite what the docs say. g_vulkanMayBeAvailable = System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= 13; - INFO_LOG(SYSTEM, "VulkanMayBeAvailable: Detected version: %d", (int)System_GetPropertyInt(SYSPROP_SYSTEMVERSION)); return g_vulkanMayBeAvailable; #else // Unsupported in VR at the moment diff --git a/Core/Config.cpp b/Core/Config.cpp index ee757a61e1..b2403960bf 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -1367,7 +1367,7 @@ bool Config::Save(const char *saveReason) { playTimeTracker_.Save(playTime); if (!iniFile.Save(iniFilename_)) { - ERROR_LOG(LOADER, "Error saving config (%s)- can't write ini '%s'", saveReason, iniFilename_.c_str()); + ERROR_LOG(LOADER, "Error saving config (%s) - can't write ini '%s'", saveReason, iniFilename_.c_str()); return false; } INFO_LOG(LOADER, "Config saved (%s): '%s' (%0.1f ms)", saveReason, iniFilename_.c_str(), (time_now_d() - startTime) * 1000.0); @@ -1546,6 +1546,34 @@ void Config::RemoveRecent(const std::string &file) { recentIsos.erase(iter, recentIsos.end()); } +// On iOS, the path to the app documents directory changes on each launch. +// Example path: +// /var/mobile/Containers/Data/Application/0E0E89DE-8D8E-485A-860C-700D8BC87B86/Documents/PSP/GAME/SuicideBarbie +// The GUID part changes on each launch. +bool TryUpdateSavedPath(Path *path) { +#if PPSSPP_PLATFORM(IOS) + INFO_LOG(LOADER, "Original path: %s", path->c_str()); + std::string pathStr = path->ToString(); + + const std::string_view applicationRoot = "/var/mobile/Containers/Data/Application/"; + if (startsWith(pathStr, applicationRoot)) { + size_t documentsPos = pathStr.find("/Documents/"); + if (documentsPos == std::string::npos) { + return false; + } + std::string memstick = g_Config.memStickDirectory.ToString(); + size_t memstickDocumentsPos = memstick.find("/Documents"); // Note: No trailing slash, or we won't find it. + *path = Path(memstick.substr(0, memstickDocumentsPos) + pathStr.substr(documentsPos)); + return true; + } else { + // Path can't be auto-updated. + return false; + } +#else + return false; +#endif +} + void Config::CleanRecent() { private_->SetRecentIsosThread([this] { SetCurrentThreadName("RecentISOs"); @@ -1556,6 +1584,10 @@ void Config::CleanRecent() { std::lock_guard guard(private_->recentIsosLock); std::vector cleanedRecent; + if (recentIsos.empty()) { + INFO_LOG(LOADER, "No recents list found."); + } + for (size_t i = 0; i < recentIsos.size(); i++) { bool exists = false; Path path = Path(recentIsos[i]); @@ -1563,6 +1595,12 @@ void Config::CleanRecent() { case PathType::CONTENT_URI: case PathType::NATIVE: exists = File::Exists(path); + if (!exists) { + if (TryUpdateSavedPath(&path)) { + exists = File::Exists(path); + INFO_LOG(LOADER, "Exists=%d when checking updated path: %s", exists, path.c_str()); + } + } break; default: FileLoader *loader = ConstructFileLoader(path); @@ -1572,11 +1610,14 @@ void Config::CleanRecent() { } if (exists) { + std::string pathStr = path.ToString(); // Make sure we don't have any redundant items. - auto duplicate = std::find(cleanedRecent.begin(), cleanedRecent.end(), recentIsos[i]); + auto duplicate = std::find(cleanedRecent.begin(), cleanedRecent.end(), pathStr); if (duplicate == cleanedRecent.end()) { - cleanedRecent.push_back(recentIsos[i]); + cleanedRecent.push_back(pathStr); } + } else { + DEBUG_LOG(LOADER, "Removed %s from recent. errno=%d", path.c_str(), errno); } } diff --git a/ios/ViewController.mm b/ios/ViewController.mm index 224b22cc65..fcf29ec9ef 100644 --- a/ios/ViewController.mm +++ b/ios/ViewController.mm @@ -292,6 +292,8 @@ void GLRenderLoop(IOSGLESContext *graphicsContext) { { INFO_LOG(SYSTEM, "shutdown GL"); + g_Config.Save("shutdown GL"); + _dbg_assert_(graphicsContext); _dbg_assert_(sharedViewController != nil); sharedViewController = nil; diff --git a/ios/ViewControllerMetal.mm b/ios/ViewControllerMetal.mm index 3e76471178..f21bc031fa 100644 --- a/ios/ViewControllerMetal.mm +++ b/ios/ViewControllerMetal.mm @@ -353,6 +353,8 @@ void VulkanRenderLoop(IOSVulkanContext *graphicsContext, CAMetalLayer *metalLaye { INFO_LOG(SYSTEM, "shutdown VK"); + g_Config.Save("shutdown vk"); + _dbg_assert_(sharedViewController != nil); sharedViewController = nil;