This commit is contained in:
jpolo1224
2026-05-29 13:29:06 -04:00
parent 30cc553a3d
commit 759911fe53
20 changed files with 1845 additions and 131 deletions
File diff suppressed because it is too large Load Diff
+3 -1
View File
@@ -13,8 +13,10 @@ typedef NS_ENUM(NSInteger, ARMSX2EmulatorState) {
};
typedef NS_ENUM(NSInteger, ARMSX2CoreType) {
ARMSX2CoreTypeJIT = 0,
ARMSX2CoreTypeLegacyRecompiler = 0,
ARMSX2CoreTypeInterpreter = 1,
ARMSX2CoreTypeARM64JIT = 2,
ARMSX2CoreTypeJIT = ARMSX2CoreTypeARM64JIT,
};
typedef NS_ENUM(NSInteger, ARMSX2PadButton) {
+90 -9
View File
@@ -18,7 +18,9 @@ extern "C" void ARMSX2_SetSDLFullscreen(bool enabled);
#include "common/Path.h"
#include "common/ZipHelpers.h"
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <future>
#include <optional>
#include <string_view>
@@ -89,6 +91,49 @@ static NSData* ARMSX2ReadSaveStatePreviewPNG(const std::string& path)
return [NSData dataWithBytes:data->data() length:data->size()];
}
static void ARMSX2ApplyLiveGSBoolSetting(const char* section, const char* key, bool value)
{
if (std::strcmp(section, "EmuCore/GS") != 0)
return;
#define APPLY_OSD_BOOL(name) \
do { \
if (std::strcmp(key, #name) == 0) { \
EmuConfig.GS.name = value; \
GSConfig.name = value; \
return; \
} \
} while (0)
APPLY_OSD_BOOL(OsdShowFPS);
APPLY_OSD_BOOL(OsdShowVPS);
APPLY_OSD_BOOL(OsdShowSpeed);
APPLY_OSD_BOOL(OsdShowCPU);
APPLY_OSD_BOOL(OsdShowGPU);
APPLY_OSD_BOOL(OsdShowResolution);
APPLY_OSD_BOOL(OsdShowGSStats);
APPLY_OSD_BOOL(OsdShowIndicators);
APPLY_OSD_BOOL(OsdShowSettings);
APPLY_OSD_BOOL(OsdShowInputs);
APPLY_OSD_BOOL(OsdShowFrameTimes);
APPLY_OSD_BOOL(OsdShowVersion);
APPLY_OSD_BOOL(OsdShowHardwareInfo);
APPLY_OSD_BOOL(OsdShowVideoCapture);
APPLY_OSD_BOOL(OsdShowInputRec);
#undef APPLY_OSD_BOOL
}
static void ARMSX2ApplyLiveGSIntSetting(const char* section, const char* key, int value)
{
if (std::strcmp(section, "EmuCore/GS") != 0 || std::strcmp(key, "OsdPerformancePos") != 0)
return;
const int clamped = std::clamp(value, static_cast<int>(OsdOverlayPos::None), static_cast<int>(OsdOverlayPos::TopRight));
EmuConfig.GS.OsdPerformancePos = static_cast<OsdOverlayPos>(clamped);
GSConfig.OsdPerformancePos = static_cast<OsdOverlayPos>(clamped);
}
@implementation ARMSX2Bridge
+ (UIView *)gameRenderView {
@@ -195,7 +240,7 @@ static NSData* ARMSX2ReadSaveStatePreviewPNG(const std::string& path)
+ (void)requestVMStop {
extern std::atomic<bool> s_requestVMStop;
s_requestVMStop.store(true);
[[NSNotificationCenter defaultCenter] postNotificationName:@"ARMSX2iOSVMDidShutdown" object:nil];
NSLog(@"[ARMSX2Bridge] VM stop requested");
}
+ (void)setFullScreen:(BOOL)enabled {
@@ -209,7 +254,9 @@ static NSData* ARMSX2ReadSaveStatePreviewPNG(const std::string& path)
+ (nullable NSString *)currentISOPath {
NSString *docsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSString *iniPath = [docsPath stringByAppendingPathComponent:@"PCSX2-iOS.ini"];
NSString *iniPath = [docsPath stringByAppendingPathComponent:@"ARMSX2-iOS.ini"];
if (![[NSFileManager defaultManager] fileExistsAtPath:iniPath])
iniPath = [docsPath stringByAppendingPathComponent:@"PCSX2-iOS.ini"];
// Read BootISO from INI
FILE *f = fopen(iniPath.UTF8String, "r");
if (!f) return nil;
@@ -310,28 +357,60 @@ static NSData* ARMSX2ReadSaveStatePreviewPNG(const std::string& path)
GSConfig.OsdShowFrameTimes = false;
GSConfig.OsdShowVersion = false;
GSConfig.OsdShowHardwareInfo = false;
GSConfig.OsdShowIndicators = false;
GSConfig.OsdShowSettings = false;
GSConfig.OsdShowInputs = false;
GSConfig.OsdShowVideoCapture = false;
GSConfig.OsdShowInputRec = false;
switch (preset) {
case 1: // simple: FPS + CPU usage
GSConfig.OsdShowFPS = true;
GSConfig.OsdShowCPU = true;
break;
case 2: // detail: simple + speed + resolution
case 1: // simple: Android-style quick readout
GSConfig.OsdShowFPS = true;
GSConfig.OsdShowSpeed = true;
GSConfig.OsdShowCPU = true;
GSConfig.OsdShowResolution = true;
GSConfig.OsdShowIndicators = true;
break;
case 3: // full: detail + frame times
case 2: // detail: performance and renderer diagnostics
GSConfig.OsdShowFPS = true;
GSConfig.OsdShowVPS = true;
GSConfig.OsdShowSpeed = true;
GSConfig.OsdShowCPU = true;
GSConfig.OsdShowGPU = true;
GSConfig.OsdShowResolution = true;
GSConfig.OsdShowIndicators = true;
break;
case 3: // full: closest to Android's full stats section
GSConfig.OsdShowFPS = true;
GSConfig.OsdShowVPS = true;
GSConfig.OsdShowSpeed = true;
GSConfig.OsdShowCPU = true;
GSConfig.OsdShowGPU = true;
GSConfig.OsdShowResolution = true;
GSConfig.OsdShowGSStats = true;
GSConfig.OsdShowFrameTimes = true;
GSConfig.OsdShowVersion = true;
GSConfig.OsdShowHardwareInfo = true;
GSConfig.OsdShowIndicators = true;
GSConfig.OsdShowSettings = true;
GSConfig.OsdShowInputs = true;
break;
default: // 0 = off
break;
}
EmuConfig.GS.OsdShowFPS = GSConfig.OsdShowFPS;
EmuConfig.GS.OsdShowVPS = GSConfig.OsdShowVPS;
EmuConfig.GS.OsdShowSpeed = GSConfig.OsdShowSpeed;
EmuConfig.GS.OsdShowCPU = GSConfig.OsdShowCPU;
EmuConfig.GS.OsdShowGPU = GSConfig.OsdShowGPU;
EmuConfig.GS.OsdShowResolution = GSConfig.OsdShowResolution;
EmuConfig.GS.OsdShowGSStats = GSConfig.OsdShowGSStats;
EmuConfig.GS.OsdShowFrameTimes = GSConfig.OsdShowFrameTimes;
EmuConfig.GS.OsdShowVersion = GSConfig.OsdShowVersion;
EmuConfig.GS.OsdShowHardwareInfo = GSConfig.OsdShowHardwareInfo;
EmuConfig.GS.OsdShowIndicators = GSConfig.OsdShowIndicators;
EmuConfig.GS.OsdShowSettings = GSConfig.OsdShowSettings;
EmuConfig.GS.OsdShowInputs = GSConfig.OsdShowInputs;
}
// ============================================================
@@ -438,12 +517,14 @@ static NSData* ARMSX2ReadSaveStatePreviewPNG(const std::string& path)
if (!g_p44_settings_interface) return;
g_p44_settings_interface->SetIntValue(section.UTF8String, key.UTF8String, value);
g_p44_settings_interface->Save();
ARMSX2ApplyLiveGSIntSetting(section.UTF8String, key.UTF8String, value);
}
+ (void)setINIBool:(nonnull NSString *)section key:(nonnull NSString *)key value:(BOOL)value {
if (!g_p44_settings_interface) return;
g_p44_settings_interface->SetBoolValue(section.UTF8String, key.UTF8String, value);
g_p44_settings_interface->Save();
ARMSX2ApplyLiveGSBoolSetting(section.UTF8String, key.UTF8String, value);
}
+ (void)setINIFloat:(nonnull NSString *)section key:(nonnull NSString *)key value:(float)value {
+1 -1
View File
@@ -228,7 +228,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/Frameworks /usr/lib/swift"
XCODE_ATTRIBUTE_LIBRARY_SEARCH_PATHS "$(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) /usr/lib/swift"
XCODE_ATTRIBUTE_OTHER_SWIFT_FLAGS ""
XCODE_ATTRIBUTE_MTL_HEADER_SEARCH_PATHS "${CMAKE_SOURCE_DIR}/pcsx2/GS/Renderers/Metal ${CMAKE_SOURCE_DIR}/../assets"
XCODE_ATTRIBUTE_MTL_HEADER_SEARCH_PATHS "${CMAKE_SOURCE_DIR}/pcsx2/GS/Renderers/Metal ${CMAKE_SOURCE_DIR}/3rdparty/include ${CMAKE_SOURCE_DIR}/../assets ${CMAKE_SOURCE_DIR}/../assets/resources"
XCODE_ATTRIBUTE_MTL_ENABLE_DEBUG_INFO "$<IF:$<CONFIG:Debug>,INCLUDE_SOURCE,>"
)
+6 -2
View File
@@ -119,7 +119,7 @@ elseif("${CMAKE_HOST_SYSTEM_PROCESSOR}" STREQUAL "arm64" OR "${CMAKE_HOST_SYSTEM
# add_compile_options("-march=armv8.4-a" "-mcpu=apple-m1")
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
add_definitions("-march=armv8-a+crc")
add_compile_options("$<$<COMPILE_LANGUAGE:C,CXX,OBJC,OBJCXX>:-march=armv8-a+crc>")
# If we're running on Linux, we need to detect the page/cache line size.
# It could be a virtual machine with 4K pages, or 16K with Asahi.
@@ -159,7 +159,11 @@ if(MSVC)
# Disable Exceptions
string(REPLACE "/EHsc" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
else()
add_compile_options(-pipe -fvisibility=hidden -pthread)
add_compile_options(
"$<$<COMPILE_LANGUAGE:C,CXX,OBJC,OBJCXX>:-pipe>"
"$<$<COMPILE_LANGUAGE:C,CXX,OBJC,OBJCXX>:-fvisibility=hidden>"
"$<$<COMPILE_LANGUAGE:C,CXX,OBJC,OBJCXX>:-pthread>"
)
add_compile_options(
"$<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions>"
)
+38 -4
View File
@@ -832,6 +832,10 @@ void DarwinMisc::MunmapCodeDualMap(void* rx_ptr, size_t size)
bool DarwinMisc::IsJITAvailable()
{
static std::optional<bool> s_cached_jit_available;
if (s_cached_jit_available.has_value())
return *s_cached_jit_available;
#if ARMSX2_APPLE_IOS_DEVICE
uint32_t cs_flags = 0;
int rv = csops(getpid(), 0, &cs_flags, sizeof(cs_flags));
@@ -844,11 +848,13 @@ bool DarwinMisc::IsJITAvailable()
fprintf(stderr, "@@JIT_DETECT@@ result=UNAVAILABLE (no CS_DEBUGGED — launch via StikDebug)\n");
s_jit_mode = JitMode::Legacy;
s_jit_mode_detected = true;
return false;
s_cached_jit_available = false;
return *s_cached_jit_available;
}
fprintf(stderr, "@@JIT_DETECT@@ result=AVAILABLE (CS_DEBUGGED set)\n");
return true;
s_cached_jit_available = true;
return *s_cached_jit_available;
#else
const size_t probe_size = static_cast<size_t>(getpagesize());
void* probe = mmap(nullptr, probe_size, PROT_READ | PROT_WRITE | PROT_EXEC,
@@ -856,12 +862,14 @@ bool DarwinMisc::IsJITAvailable()
if (probe == MAP_FAILED)
{
fprintf(stderr, "@@JIT_DETECT@@ MAP_JIT probe failed errno=%d\n", errno);
return false;
s_cached_jit_available = false;
return *s_cached_jit_available;
}
munmap(probe, probe_size);
fprintf(stderr, "@@JIT_DETECT@@ MAP_JIT probe result=AVAILABLE\n");
return true;
s_cached_jit_available = true;
return *s_cached_jit_available;
#endif
}
@@ -1088,8 +1096,21 @@ void HostSys::BeginCodeWrite()
}
} else {
static auto func = reinterpret_cast<void(*)(int)>(dlsym(RTLD_DEFAULT, "pthread_jit_write_protect_np"));
static bool s_logged_pthread_jit_begin = false;
if (func)
{
if (!s_logged_pthread_jit_begin)
{
fprintf(stderr, "@@JIT_WRITE_PROTECT@@ pthread_jit_write_protect_np available=1 action=begin_write protect=0\n");
s_logged_pthread_jit_begin = true;
}
func(0);
}
else if (!s_logged_pthread_jit_begin)
{
fprintf(stderr, "@@JIT_WRITE_PROTECT@@ pthread_jit_write_protect_np available=0 action=begin_write\n");
s_logged_pthread_jit_begin = true;
}
}
}
}
@@ -1120,8 +1141,21 @@ void HostSys::EndCodeWrite()
}
} else {
static auto func = reinterpret_cast<void(*)(int)>(dlsym(RTLD_DEFAULT, "pthread_jit_write_protect_np"));
static bool s_logged_pthread_jit_end = false;
if (func)
{
if (!s_logged_pthread_jit_end)
{
fprintf(stderr, "@@JIT_WRITE_PROTECT@@ pthread_jit_write_protect_np available=1 action=end_write protect=1\n");
s_logged_pthread_jit_end = true;
}
func(1);
}
else if (!s_logged_pthread_jit_end)
{
fprintf(stderr, "@@JIT_WRITE_PROTECT@@ pthread_jit_write_protect_np available=0 action=end_write\n");
s_logged_pthread_jit_end = true;
}
}
}
}
+131 -19
View File
@@ -22,6 +22,7 @@
#include <cstdio>
#include <cstring>
#include <string>
#include <string_view>
#include <iostream>
#include <algorithm>
#include <deque>
@@ -729,6 +730,7 @@ bool PCAPAdapter::ValidateEtherFrame(NetPacket*) { return false; }
#include "pcsx2/INISettingsInterface.h"
static INISettingsInterface* s_settings_interface = nullptr;
static std::string s_iosSettingsPath;
// Expose to ARMSX2Bridge.mm via extern
INISettingsInterface* g_p44_settings_interface = nullptr;
@@ -826,22 +828,36 @@ static void ARMSX2LogIOSSettingsSnapshot(const char* tag, INISettingsInterface*
const bool recVU0 = si->GetBoolValue("EmuCore/CPU/Recompiler", "EnableVU0", false);
const bool recVU1 = si->GetBoolValue("EmuCore/CPU/Recompiler", "EnableVU1", false);
const bool extraMemory = si->GetBoolValue("EmuCore/CPU", "ExtraMemory", false);
const bool fastmem = si->GetBoolValue("EmuCore/CPU/Recompiler", "EnableFastmem", false);
const int gsRenderer = si->GetIntValue("EmuCore/GS", "Renderer", -999);
const int vsyncQueue = si->GetIntValue("EmuCore/GS", "VsyncQueueSize", -999);
const bool mtvu = si->GetBoolValue("EmuCore/Speedhacks", "MTVU", false);
const bool vuThread = si->GetBoolValue("EmuCore/Speedhacks", "vuThread", false);
const std::string bootISO = si->GetStringValue("GameISO", "BootISO", "");
const std::string biosName = si->GetStringValue("Filenames", "BIOS", "");
#if ARMSX2_APPLE_MAC_RUNTIME
const bool jitAvailable = true;
const bool noJitActive = false;
#else
const bool forceEEInterp = (DarwinMisc::ARMSX2_FORCE_EE_INTERP != 0);
const bool forceJit = (DarwinMisc::ARMSX2_FORCE_JIT != 0);
const bool jitAvailable = forceJit || (!forceEEInterp && DarwinMisc::IsJITAvailable());
const bool noJitActive = forceEEInterp || (!forceJit && !jitAvailable) || cpuCore == 1;
#endif
fprintf(stderr,
"@@IOS_SETTINGS@@ tag=%s si=%p spu2_backend=%s cpu_core=%d arm64_dynarec=%d rec_ee=%d rec_iop=%d rec_vu0=%d rec_vu1=%d extra_memory=%d gs_renderer=%d vsync_queue=%d mtvu=%d vu_thread=%d\n",
tag, si, spu2Backend.c_str(), cpuCore, arm64Dynarec ? 1 : 0, recEE ? 1 : 0, recIOP ? 1 : 0,
recVU0 ? 1 : 0, recVU1 ? 1 : 0, extraMemory ? 1 : 0, gsRenderer, vsyncQueue, mtvu ? 1 : 0,
vuThread ? 1 : 0);
"@@IOS_SETTINGS@@ tag=%s si=%p config_path=%s data_root=%s bios_dir=%s boot_iso=\"%s\" bios_name=\"%s\" spu2_backend=%s cpu_core=%d arm64_dynarec=%d rec_ee=%d rec_iop=%d rec_vu0=%d rec_vu1=%d fastmem=%d extra_memory=%d gs_renderer=%d vsync_queue=%d mtvu=%d vu_thread=%d jit_available=%d no_jit_active=%d\n",
tag, si, s_iosSettingsPath.c_str(), EmuFolders::DataRoot.c_str(), EmuFolders::Bios.c_str(), bootISO.c_str(),
biosName.c_str(), spu2Backend.c_str(), cpuCore, arm64Dynarec ? 1 : 0, recEE ? 1 : 0, recIOP ? 1 : 0,
recVU0 ? 1 : 0, recVU1 ? 1 : 0, fastmem ? 1 : 0, extraMemory ? 1 : 0, gsRenderer, vsyncQueue,
mtvu ? 1 : 0, vuThread ? 1 : 0, jitAvailable ? 1 : 0, noJitActive ? 1 : 0);
fflush(stderr);
Console.WriteLn(
"@@IOS_SETTINGS@@ tag=%s si=%p spu2_backend=%s cpu_core=%d arm64_dynarec=%d rec_ee=%d rec_iop=%d rec_vu0=%d rec_vu1=%d extra_memory=%d gs_renderer=%d vsync_queue=%d mtvu=%d vu_thread=%d",
tag, si, spu2Backend.c_str(), cpuCore, arm64Dynarec ? 1 : 0, recEE ? 1 : 0, recIOP ? 1 : 0,
recVU0 ? 1 : 0, recVU1 ? 1 : 0, extraMemory ? 1 : 0, gsRenderer, vsyncQueue, mtvu ? 1 : 0,
vuThread ? 1 : 0);
"@@IOS_SETTINGS@@ tag=%s si=%p config_path=%s data_root=%s bios_dir=%s boot_iso=\"%s\" bios_name=\"%s\" spu2_backend=%s cpu_core=%d arm64_dynarec=%d rec_ee=%d rec_iop=%d rec_vu0=%d rec_vu1=%d fastmem=%d extra_memory=%d gs_renderer=%d vsync_queue=%d mtvu=%d vu_thread=%d jit_available=%d no_jit_active=%d",
tag, si, s_iosSettingsPath.c_str(), EmuFolders::DataRoot.c_str(), EmuFolders::Bios.c_str(), bootISO.c_str(),
biosName.c_str(), spu2Backend.c_str(), cpuCore, arm64Dynarec ? 1 : 0, recEE ? 1 : 0, recIOP ? 1 : 0,
recVU0 ? 1 : 0, recVU1 ? 1 : 0, fastmem ? 1 : 0, extraMemory ? 1 : 0, gsRenderer, vsyncQueue,
mtvu ? 1 : 0, vuThread ? 1 : 0, jitAvailable ? 1 : 0, noJitActive ? 1 : 0);
}
static constexpr const char* ARMSX2_IOS_JIT_SECTION = "ARMSX2iOS/JIT";
@@ -894,6 +910,36 @@ static void ARMSX2RestoreIOSJitDefaults(INISettingsInterface* si)
si->SetBoolValue("EmuCore/CPU/Recompiler", "EnableFastmem", true);
}
static const char* ARMSX2NormalizeGSAspectRatio(std::string_view value)
{
if (value == "Stretch" || value == "0")
return "Stretch";
if (value == "Auto 4:3/3:2" || value == "1")
return "Auto 4:3/3:2";
if (value == "4:3" || value == "2")
return "4:3";
if (value == "16:9" || value == "3")
return "16:9";
if (value == "10:7" || value == "4")
return "10:7";
return nullptr;
}
static const char* ARMSX2NormalizeGSFMVAspectRatioSwitch(std::string_view value)
{
if (value == "Off" || value == "0")
return "Off";
if (value == "Auto 4:3/3:2" || value == "1")
return "Auto 4:3/3:2";
if (value == "4:3" || value == "2")
return "4:3";
if (value == "16:9" || value == "3")
return "16:9";
if (value == "10:7" || value == "4")
return "10:7";
return nullptr;
}
static void ARMSX2ApplyIOSRuntimeDefaults(INISettingsInterface* si)
{
if (!si)
@@ -948,9 +994,10 @@ static void ARMSX2ApplyIOSRuntimeDefaults(INISettingsInterface* si)
si->SetBoolValue("EmuCore/CPU/Recompiler", "EnableVU1", true);
si->SetBoolValue("EmuCore/CPU/Recompiler", "EnableFastmem", true);
#else
const int configured_core_type = si->GetIntValue("EmuCore/CPU", "CoreType", 2);
if (!si->ContainsValue("EmuCore/CPU", "CoreType"))
si->SetIntValue("EmuCore/CPU", "CoreType", 2);
if (!si->ContainsValue("EmuCore/CPU", "UseArm64Dynarec"))
if (configured_core_type == 2 || !si->ContainsValue("EmuCore/CPU", "UseArm64Dynarec"))
si->SetBoolValue("EmuCore/CPU", "UseArm64Dynarec", true);
if (!si->ContainsValue("EmuCore/CPU/Recompiler", "EnableEE"))
si->SetBoolValue("EmuCore/CPU/Recompiler", "EnableEE", true);
@@ -984,8 +1031,25 @@ static void ARMSX2ApplyIOSRuntimeDefaults(INISettingsInterface* si)
break;
}
#endif
si->SetStringValue("EmuCore/GS", "AspectRatio", "Auto 4:3/3:2");
si->SetStringValue("EmuCore/GS", "FMVAspectRatioSwitch", "Off");
const std::string configured_aspect_ratio = si->GetStringValue("EmuCore/GS", "AspectRatio", "");
const char* normalized_aspect_ratio = ARMSX2NormalizeGSAspectRatio(configured_aspect_ratio);
if (!normalized_aspect_ratio) {
Console.Warning("@@IOS_SETTINGS@@ invalid AspectRatio=\"%s\" fallback=\"Auto 4:3/3:2\"",
configured_aspect_ratio.c_str());
normalized_aspect_ratio = "Auto 4:3/3:2";
}
if (configured_aspect_ratio != normalized_aspect_ratio)
si->SetStringValue("EmuCore/GS", "AspectRatio", normalized_aspect_ratio);
const std::string configured_fmv_aspect = si->GetStringValue("EmuCore/GS", "FMVAspectRatioSwitch", "");
const char* normalized_fmv_aspect = ARMSX2NormalizeGSFMVAspectRatioSwitch(configured_fmv_aspect);
if (!normalized_fmv_aspect) {
Console.Warning("@@IOS_SETTINGS@@ invalid FMVAspectRatioSwitch=\"%s\" fallback=\"Off\"",
configured_fmv_aspect.c_str());
normalized_fmv_aspect = "Off";
}
if (configured_fmv_aspect != normalized_fmv_aspect)
si->SetStringValue("EmuCore/GS", "FMVAspectRatioSwitch", normalized_fmv_aspect);
ARMSX2ClampINIInt(si, "EmuCore/GS", "VsyncQueueSize", 2, 0, 8);
ARMSX2ClampINIInt(si, "EmuCore/GS", "deinterlace_mode", static_cast<int>(GSInterlaceMode::Automatic), 0, static_cast<int>(GSInterlaceMode::Count) - 1);
ARMSX2ClampINIInt(si, "EmuCore/GS", "accurate_blending_unit", static_cast<int>(AccBlendLevel::Basic), 0, static_cast<int>(AccBlendLevel::Maximum));
@@ -1026,12 +1090,12 @@ static bool ARMSX2IOSConfigRequestsInterpreter(INISettingsInterface* si)
// --- SDL Initialization ---
static bool s_initialized = false;
if (!s_initialized) {
SDL_SetMainReady();
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMEPAD) < 0) {
NSLog(@"SDL_Init failed: %s", SDL_GetError());
return;
}
if (!s_initialized) {
SDL_SetMainReady();
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMEPAD)) {
NSLog(@"SDL_Init failed: %s", SDL_GetError());
return;
}
s_initialized = true;
}
@@ -1059,6 +1123,7 @@ static bool ARMSX2IOSConfigRequestsInterpreter(INISettingsInterface* si)
}
std::string iniPath = [iniPathString UTF8String];
s_iosSettingsPath = iniPath;
s_settings_interface = new INISettingsInterface(iniPath);
if (!static_cast<INISettingsInterface*>(s_settings_interface)->Load()) {
Console.WriteLn("Creating new config at %s", iniPath.c_str());
@@ -1509,8 +1574,17 @@ static bool ARMSX2IOSConfigRequestsInterpreter(INISettingsInterface* si)
const bool force_jit = (DarwinMisc::ARMSX2_FORCE_JIT != 0);
const bool jit_available = force_jit || (!force_ee_interp && DarwinMisc::IsJITAvailable());
const bool jit_unavailable = !force_ee_interp && !force_jit && !jit_available;
const bool config_interpreter = ARMSX2IOSConfigRequestsInterpreter(s_settings_interface);
const char* fallback_reason =
force_ee_interp ? "env_force_ee_interp" :
(config_interpreter ? "config_interpreter" :
(jit_unavailable ? "jit_unavailable" : "none"));
if (!jit_available || force_ee_interp || ARMSX2IOSConfigRequestsInterpreter(s_settings_interface)) {
Console.WriteLn("@@JIT_GATE@@ force_ee_interp=%d force_jit=%d jit_available=%d config_interpreter=%d fallback_reason=%s",
force_ee_interp ? 1 : 0, force_jit ? 1 : 0, jit_available ? 1 : 0, config_interpreter ? 1 : 0,
fallback_reason);
if (!jit_available || force_ee_interp || config_interpreter) {
if (s_settings_interface) {
if (jit_unavailable)
ARMSX2SetAutoNoJitFallback(s_settings_interface);
@@ -1727,6 +1801,35 @@ static bool ARMSX2IOSConfigRequestsInterpreter(INISettingsInterface* si)
}
const std::string bios_path = Path::Combine(EmuFolders::Bios, EmuConfig.BaseFilenames.Bios);
const std::string selected_game_path =
!boot_params.elf_override.empty() ? boot_params.elf_override :
(!boot_params.filename.empty() ? boot_params.filename : std::string());
const bool boot_arm64_dynarec =
s_settings_interface ? s_settings_interface->GetBoolValue("EmuCore/CPU", "UseArm64Dynarec", EmuConfig.Cpu.CoreType == 2) :
(EmuConfig.Cpu.CoreType == 2);
#if ARMSX2_APPLE_MAC_RUNTIME
const bool boot_jit_available = true;
const bool boot_no_jit_active = false;
const char* boot_fallback_reason = "none";
#else
const bool boot_force_ee_interp = (DarwinMisc::ARMSX2_FORCE_EE_INTERP != 0);
const bool boot_force_jit = (DarwinMisc::ARMSX2_FORCE_JIT != 0);
const bool boot_jit_available = boot_force_jit || (!boot_force_ee_interp && DarwinMisc::IsJITAvailable());
const bool boot_no_jit_active = boot_force_ee_interp || (!boot_force_jit && !boot_jit_available) || EmuConfig.Cpu.CoreType == 1;
const char* boot_fallback_reason =
boot_force_ee_interp ? "env_force_ee_interp" :
(EmuConfig.Cpu.CoreType == 1 ? "config_interpreter" :
(!boot_jit_available ? "jit_unavailable" : "none"));
#endif
Console.WriteLn(
"@@IOS_BOOT_DIAG@@ config_path=%s data_root=%s bios_dir=%s bios_name=\"%s\" bios_path=%s bios_exists=%d game_path=%s renderer=%d core_type=%d arm64_dynarec=%d ee_rec=%d iop_rec=%d vu0_rec=%d vu1_rec=%d fastmem=%d jit_available=%d no_jit_active=%d fallback_reason=%s",
s_iosSettingsPath.c_str(), EmuFolders::DataRoot.c_str(), EmuFolders::Bios.c_str(),
EmuConfig.BaseFilenames.Bios.c_str(), bios_path.c_str(), FileSystem::FileExists(bios_path.c_str()) ? 1 : 0,
selected_game_path.c_str(), static_cast<int>(EmuConfig.GS.Renderer), EmuConfig.Cpu.CoreType,
boot_arm64_dynarec ? 1 : 0, EmuConfig.Cpu.Recompiler.EnableEE ? 1 : 0,
EmuConfig.Cpu.Recompiler.EnableIOP ? 1 : 0, EmuConfig.Cpu.Recompiler.EnableVU0 ? 1 : 0,
EmuConfig.Cpu.Recompiler.EnableVU1 ? 1 : 0, EmuConfig.Cpu.Recompiler.EnableFastmem ? 1 : 0,
boot_jit_available ? 1 : 0, boot_no_jit_active ? 1 : 0, boot_fallback_reason);
#if ARMSX2_APPLE_MAC_RUNTIME
const bool mac_fast_boot_value = boot_params.fast_boot.value_or(false);
LogUnified("@@MAC_VM_BOOT_PARAMS@@ filename=%s elf=%s source_type=%d fast_boot=%d bios_name=%s bios_path=%s bios_exists=%d renderer=%d cpu_core=%d rec_ee=%d rec_iop=%d rec_vu0=%d rec_vu1=%d\n",
@@ -1842,18 +1945,26 @@ static bool ARMSX2IOSConfigRequestsInterpreter(INISettingsInterface* si)
}
- (void)sceneDidDisconnect:(UIScene *)scene {
Console.WriteLn("@@IOS_LIFECYCLE@@ sceneDidDisconnect vm_state=%d active=%d",
static_cast<int>(VMManager::GetState()), s_vmThreadActive.load() ? 1 : 0);
}
- (void)sceneDidBecomeActive:(UIScene *)scene {
Console.WriteLn("@@IOS_LIFECYCLE@@ sceneDidBecomeActive vm_state=%d active=%d",
static_cast<int>(VMManager::GetState()), s_vmThreadActive.load() ? 1 : 0);
}
- (void)sceneWillResignActive:(UIScene *)scene {
// NVM save when app loses focus
extern void cdvdSaveNVRAM();
cdvdSaveNVRAM();
Console.WriteLn("@@IOS_LIFECYCLE@@ sceneWillResignActive vm_state=%d active=%d saved_nvram=1",
static_cast<int>(VMManager::GetState()), s_vmThreadActive.load() ? 1 : 0);
}
- (void)sceneWillEnterForeground:(UIScene *)scene {
Console.WriteLn("@@IOS_LIFECYCLE@@ sceneWillEnterForeground vm_state=%d active=%d",
static_cast<int>(VMManager::GetState()), s_vmThreadActive.load() ? 1 : 0);
}
- (void)sceneDidEnterBackground:(UIScene *)scene {
@@ -1863,7 +1974,8 @@ static bool ARMSX2IOSConfigRequestsInterpreter(INISettingsInterface* si)
// happens when iOS terminates the app via SIGTERM.
extern void cdvdSaveNVRAM();
cdvdSaveNVRAM();
Console.WriteLn("[NVM] NVM saved on sceneDidEnterBackground");
Console.WriteLn("@@IOS_LIFECYCLE@@ sceneDidEnterBackground vm_state=%d active=%d saved_nvram=1",
static_cast<int>(VMManager::GetState()), s_vmThreadActive.load() ? 1 : 0);
}
@end
@@ -5,7 +5,7 @@
#define A_MSL 1
#define A_HALF 1
#include "../../../../bin/resources/shaders/common/ffx_a.h"
#include "shaders/common/ffx_a.h"
struct CASTextureF
{
@@ -35,7 +35,7 @@ A_STATIC AH3 CasLoadH(CASTextureH tex, ASW2 coord)
A_STATIC void CasInputH(inoutAH2 r, inoutAH2 g, inoutAH2 b){}
#include "../../../../bin/resources/shaders/common/ffx_cas.h"
#include "shaders/common/ffx_cas.h"
#include "GSMTLShaderCommon.h"
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: GPL-3.0+
#include "GSMTLShaderCommon.h"
#include "../../../../bin/resources/shaders/common/fxaa.fx"
#include "shaders/common/fxaa.fx"
fragment float4 ps_fxaa(ConvertShaderData data [[stage_in]], texture2d<float> tex [[texture(GSMTLTextureIndexNonHW)]])
{
+22 -22
View File
@@ -1404,7 +1404,7 @@ void FullscreenUI::DrawLandingTemplate(ImVec2* menu_pos, ImVec2* menu_size)
logo_pos, logo_pos + logo_size);
dl->AddText(heading_font, heading_font->FontSize,
ImVec2(logo_pos.x + logo_size.x + LayoutScale(LAYOUT_MENU_BUTTON_X_PADDING), logo_pos.y),
ImGui::GetColorU32(ImGuiCol_Text), "PCSX2");
ImGui::GetColorU32(ImGuiCol_Text), "ARMSX2");
}
// draw time
@@ -1620,7 +1620,7 @@ void FullscreenUI::DrawExitWindow()
QueueResetFocus(FocusResetType::WindowChanged);
}
if (HorizontalMenuItem(GetCachedTexture("fullscreenui/exit.png"), FSUI_CSTR("Exit PCSX2"),
if (HorizontalMenuItem(GetCachedTexture("fullscreenui/exit.png"), FSUI_CSTR("Exit ARMSX2"),
FSUI_CSTR("Completely exits the application, returning you to your desktop.")))
{
DoRequestExit();
@@ -3430,7 +3430,7 @@ void FullscreenUI::DrawInterfaceSettingsPage()
FSUI_NSTR("Untouched Lagoon"),
FSUI_NSTR("Baby Pastel"),
FSUI_NSTR("Pizza Time!"),
FSUI_NSTR("PCSX2 Blue"),
FSUI_NSTR("ARMSX2 Blue"),
FSUI_NSTR("Scarlet Devil"),
FSUI_NSTR("Violet Angel"),
FSUI_NSTR("Cobalt Sky"),
@@ -3585,8 +3585,8 @@ void FullscreenUI::DrawInterfaceSettingsPage()
FSUI_CSTR(
"Shows on-screen-display messages when events occur such as save states being created/loaded, screenshots being taken, etc."),
"EmuCore/GS", "OsdShowMessages", true);
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_INFO, "Show PCSX2 Version"),
FSUI_CSTR("Shows the current PCSX2 version on the top-right corner of the display."), "EmuCore/GS",
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_INFO, "Show ARMSX2 Version"),
FSUI_CSTR("Shows the current ARMSX2 version on the top-right corner of the display."), "EmuCore/GS",
"OsdShowVersion", false);
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_TACHOMETER_ALT, "Show Speed"),
FSUI_CSTR("Shows the current emulation speed of the system in the top-right corner of the display as a percentage."), "EmuCore/GS",
@@ -3817,7 +3817,7 @@ void FullscreenUI::DrawEmulationSettingsPage()
FSUI_CSTR("Speeds up emulation so that the guest refresh rate matches the host."), "EmuCore/GS", "SyncToHostRefreshRate", false);
DrawToggleSetting(bsi, FSUI_CSTR("Use Host VSync Timing"),
FSUI_CSTR("Disables PCSX2's internal frame timing, and uses host vsync instead."), "EmuCore/GS", "UseVSyncForTiming", false,
FSUI_CSTR("Disables the emulator's internal frame timing, and uses host vsync instead."), "EmuCore/GS", "UseVSyncForTiming", false,
GetEffectiveBoolSetting(bsi, "EmuCore/GS", "VsyncEnable", false) && GetEffectiveBoolSetting(bsi, "EmuCore/GS", "SyncToHostRefreshRate", false));
EndMenuButtons();
@@ -5148,8 +5148,8 @@ void FullscreenUI::DrawAdvancedSettingsPage()
if (!IsEditingGameSettings(bsi))
{
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_BIOHAZARD, "Show Advanced Settings"),
FSUI_CSTR("Changing these options may cause games to become non-functional. Modify at your own risk, the PCSX2 team will not "
"provide support for configurations with these settings changed."),
FSUI_CSTR("Changing these options may cause games to become non-functional. Modify at your own risk; support is not "
"guaranteed for configurations with these settings changed."),
"UI", "ShowAdvancedSettings", false);
}
@@ -5337,7 +5337,7 @@ void FullscreenUI::DrawPatchesOrCheatsSettingsPage(bool cheats)
FSUI_CSTR("Activating game patches can cause unpredictable behavior, crashing, soft-locks, or broken saved games."),
false, false, ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY);
ActiveButton(
FSUI_CSTR("Use patches at your own risk, the PCSX2 team will provide no support for users who have enabled game patches."),
FSUI_CSTR("Use patches at your own risk; support is not guaranteed for users who have enabled game patches."),
false, false, ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY);
}
@@ -7223,7 +7223,7 @@ void FullscreenUI::DrawAchievementsSettingsPage(std::unique_lock<std::mutex>& se
MenuHeading(FSUI_CSTR("Settings"));
check_challenge_state = DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_TROPHY, "Enable Achievements"),
FSUI_CSTR("When enabled and logged in, PCSX2 will scan for achievements on startup."), "Achievements", "Enabled", false);
FSUI_CSTR("When enabled and logged in, ARMSX2 will scan for achievements on startup."), "Achievements", "Enabled", false);
const bool enabled = bsi->GetBoolValue("Achievements", "Enabled", false);
@@ -7247,11 +7247,11 @@ void FullscreenUI::DrawAchievementsSettingsPage(std::unique_lock<std::mutex>& se
FSUI_CSTR("When enabled, each session will behave as if no achievements have been unlocked."), "Achievements", "EncoreMode", false,
enabled);
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_EYE, "Spectator Mode"),
FSUI_CSTR("When enabled, PCSX2 will assume all achievements are locked and not send any unlock notifications to the server."),
FSUI_CSTR("When enabled, ARMSX2 will assume all achievements are locked and not send any unlock notifications to the server."),
"Achievements", "SpectatorMode", false, enabled);
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_MEDAL, "Test Unofficial Achievements"),
FSUI_CSTR(
"When enabled, PCSX2 will list achievements from unofficial sets. These achievements are not tracked by RetroAchievements."),
"When enabled, ARMSX2 will list achievements from unofficial sets. These achievements are not tracked by RetroAchievements."),
"Achievements", "UnofficialTestMode", false, enabled);
// Check for challenge mode just being enabled.
@@ -7426,7 +7426,7 @@ TRANSLATE_NOOP("FullscreenUI", "Start BIOS");
TRANSLATE_NOOP("FullscreenUI", "Start the console without any disc inserted.");
TRANSLATE_NOOP("FullscreenUI", "Back");
TRANSLATE_NOOP("FullscreenUI", "Return to the previous menu.");
TRANSLATE_NOOP("FullscreenUI", "Exit PCSX2");
TRANSLATE_NOOP("FullscreenUI", "Exit ARMSX2");
TRANSLATE_NOOP("FullscreenUI", "Completely exits the application, returning you to your desktop.");
TRANSLATE_NOOP("FullscreenUI", "Desktop Mode");
TRANSLATE_NOOP("FullscreenUI", "Exits Big Picture mode, returning to the desktop interface.");
@@ -7467,7 +7467,7 @@ TRANSLATE_NOOP("FullscreenUI", "On-Screen Display");
TRANSLATE_NOOP("FullscreenUI", "Determines how large the on-screen messages and monitor are.");
TRANSLATE_NOOP("FullscreenUI", "%d%%");
TRANSLATE_NOOP("FullscreenUI", "Shows on-screen-display messages when events occur such as save states being created/loaded, screenshots being taken, etc.");
TRANSLATE_NOOP("FullscreenUI", "Shows the current PCSX2 version on the top-right corner of the display.");
TRANSLATE_NOOP("FullscreenUI", "Shows the current ARMSX2 version on the top-right corner of the display.");
TRANSLATE_NOOP("FullscreenUI", "Shows the current emulation speed of the system in the top-right corner of the display as a percentage.");
TRANSLATE_NOOP("FullscreenUI", "Shows the number of video frames (or v-syncs) displayed per second by the system in the top-right corner of the display.");
TRANSLATE_NOOP("FullscreenUI", "Shows the CPU usage based on threads in the top-right corner of the display.");
@@ -7520,7 +7520,7 @@ TRANSLATE_NOOP("FullscreenUI", "Synchronizes frame presentation with host refres
TRANSLATE_NOOP("FullscreenUI", "Sync to Host Refresh Rate");
TRANSLATE_NOOP("FullscreenUI", "Speeds up emulation so that the guest refresh rate matches the host.");
TRANSLATE_NOOP("FullscreenUI", "Use Host VSync Timing");
TRANSLATE_NOOP("FullscreenUI", "Disables PCSX2's internal frame timing, and uses host vsync instead.");
TRANSLATE_NOOP("FullscreenUI", "Disables the emulator's internal frame timing, and uses host vsync instead.");
TRANSLATE_NOOP("FullscreenUI", "Renderer");
TRANSLATE_NOOP("FullscreenUI", "Selects the API used to render the emulated GS.");
TRANSLATE_NOOP("FullscreenUI", "Display");
@@ -7727,7 +7727,7 @@ TRANSLATE_NOOP("FullscreenUI", "Determines the pressure required to activate the
TRANSLATE_NOOP("FullscreenUI", "Toggle every %d frames");
TRANSLATE_NOOP("FullscreenUI", "Clears all bindings for this USB controller.");
TRANSLATE_NOOP("FullscreenUI", "Data Save Locations");
TRANSLATE_NOOP("FullscreenUI", "Changing these options may cause games to become non-functional. Modify at your own risk, the PCSX2 team will not provide support for configurations with these settings changed.");
TRANSLATE_NOOP("FullscreenUI", "Changing these options may cause games to become non-functional. Modify at your own risk; support is not guaranteed for configurations with these settings changed.");
TRANSLATE_NOOP("FullscreenUI", "Logging");
TRANSLATE_NOOP("FullscreenUI", "Writes log messages to the system console (console window/standard output).");
TRANSLATE_NOOP("FullscreenUI", "Writes log messages to emulog.txt.");
@@ -7782,7 +7782,7 @@ TRANSLATE_NOOP("FullscreenUI", "No patches are available for this game.");
TRANSLATE_NOOP("FullscreenUI", "Game Patches");
TRANSLATE_NOOP("FullscreenUI", "Activating cheats can cause unpredictable behavior, crashing, soft-locks, or broken saved games.");
TRANSLATE_NOOP("FullscreenUI", "Activating game patches can cause unpredictable behavior, crashing, soft-locks, or broken saved games.");
TRANSLATE_NOOP("FullscreenUI", "Use patches at your own risk, the PCSX2 team will provide no support for users who have enabled game patches.");
TRANSLATE_NOOP("FullscreenUI", "Use patches at your own risk; support is not guaranteed for users who have enabled game patches.");
TRANSLATE_NOOP("FullscreenUI", "Game Fixes");
TRANSLATE_NOOP("FullscreenUI", "Game fixes should not be modified unless you are aware of what each option does and the implications of doing so.");
TRANSLATE_NOOP("FullscreenUI", "FPU Multiply Hack");
@@ -7845,15 +7845,15 @@ TRANSLATE_NOOP("FullscreenUI", "About PCSX2");
TRANSLATE_NOOP("FullscreenUI", "PCSX2 is a free and open-source PlayStation 2 (PS2) emulator. Its purpose is to emulate the PS2's hardware, using a combination of MIPS CPU Interpreters, Recompilers and a Virtual Machine which manages hardware states and PS2 system memory. This allows you to play PS2 games on your PC, with many additional features and benefits.");
TRANSLATE_NOOP("FullscreenUI", "PlayStation 2 and PS2 are registered trademarks of Sony Interactive Entertainment. This application is not affiliated in any way with Sony Interactive Entertainment.");
TRANSLATE_NOOP("FullscreenUI", "Version: %s");
TRANSLATE_NOOP("FullscreenUI", "When enabled and logged in, PCSX2 will scan for achievements on startup.");
TRANSLATE_NOOP("FullscreenUI", "When enabled and logged in, ARMSX2 will scan for achievements on startup.");
TRANSLATE_NOOP("FullscreenUI", "\"Challenge\" mode for achievements, including leaderboard tracking. Disables save state, cheats, and slowdown functions.");
TRANSLATE_NOOP("FullscreenUI", "Displays popup messages on events such as achievement unlocks and leaderboard submissions.");
TRANSLATE_NOOP("FullscreenUI", "Displays popup messages when starting, submitting, or failing a leaderboard challenge.");
TRANSLATE_NOOP("FullscreenUI", "Plays sound effects for events such as achievement unlocks and leaderboard submissions.");
TRANSLATE_NOOP("FullscreenUI", "Shows icons in the lower-right corner of the screen when a challenge/primed achievement is active.");
TRANSLATE_NOOP("FullscreenUI", "When enabled, each session will behave as if no achievements have been unlocked.");
TRANSLATE_NOOP("FullscreenUI", "When enabled, PCSX2 will assume all achievements are locked and not send any unlock notifications to the server.");
TRANSLATE_NOOP("FullscreenUI", "When enabled, PCSX2 will list achievements from unofficial sets. These achievements are not tracked by RetroAchievements.");
TRANSLATE_NOOP("FullscreenUI", "When enabled, ARMSX2 will assume all achievements are locked and not send any unlock notifications to the server.");
TRANSLATE_NOOP("FullscreenUI", "When enabled, ARMSX2 will list achievements from unofficial sets. These achievements are not tracked by RetroAchievements.");
TRANSLATE_NOOP("FullscreenUI", "Sound Effects");
TRANSLATE_NOOP("FullscreenUI", "Account");
TRANSLATE_NOOP("FullscreenUI", "Logs out of RetroAchievements.");
@@ -7921,7 +7921,7 @@ TRANSLATE_NOOP("FullscreenUI", "Grey Matter");
TRANSLATE_NOOP("FullscreenUI", "Untouched Lagoon");
TRANSLATE_NOOP("FullscreenUI", "Baby Pastel");
TRANSLATE_NOOP("FullscreenUI", "Pizza Time!");
TRANSLATE_NOOP("FullscreenUI", "PCSX2 Blue");
TRANSLATE_NOOP("FullscreenUI", "ARMSX2 Blue");
TRANSLATE_NOOP("FullscreenUI", "Scarlet Devil");
TRANSLATE_NOOP("FullscreenUI", "Violet Angel");
TRANSLATE_NOOP("FullscreenUI", "Cobalt Sky");
@@ -8145,7 +8145,7 @@ TRANSLATE_NOOP("FullscreenUI", "Double-Click Toggles Fullscreen");
TRANSLATE_NOOP("FullscreenUI", "Hide Cursor In Fullscreen");
TRANSLATE_NOOP("FullscreenUI", "OSD Scale");
TRANSLATE_NOOP("FullscreenUI", "Show Messages");
TRANSLATE_NOOP("FullscreenUI", "Show PCSX2 Version");
TRANSLATE_NOOP("FullscreenUI", "Show ARMSX2 Version");
TRANSLATE_NOOP("FullscreenUI", "Show Speed");
TRANSLATE_NOOP("FullscreenUI", "Show FPS");
TRANSLATE_NOOP("FullscreenUI", "Show CPU Usage");
+12 -8
View File
@@ -37,6 +37,10 @@
#include "fmt/format.h"
#include "imgui.h"
#if defined(__APPLE__)
#include <TargetConditionals.h>
#endif
#include <array>
#include <chrono>
#include <cmath>
@@ -137,13 +141,11 @@ __ri void ImGuiManager::DrawPerformanceOverlay(float& position_y, float scale, f
switch (PerformanceMetrics::GetInternalFPSMethod())
{
case PerformanceMetrics::InternalFPSMethod::GSPrivilegedRegister:
text.append_format("FPS: {:.2f} [P]", PerformanceMetrics::GetInternalFPS(),
PerformanceMetrics::GetFPS());
text.append_format("FPS: {:.2f} [P]", PerformanceMetrics::GetInternalFPS());
break;
case PerformanceMetrics::InternalFPSMethod::DISPFBBlit:
text.append_format("FPS: {:.2f} [B]", PerformanceMetrics::GetInternalFPS(),
PerformanceMetrics::GetFPS());
text.append_format("FPS: {:.2f} [B]", PerformanceMetrics::GetInternalFPS());
break;
case PerformanceMetrics::InternalFPSMethod::None:
@@ -156,8 +158,7 @@ __ri void ImGuiManager::DrawPerformanceOverlay(float& position_y, float scale, f
if (GSConfig.OsdShowVPS)
{
text.append_format("{}VPS: {:.2f}", first ? "" : " | ", PerformanceMetrics::GetFPS(),
PerformanceMetrics::GetFPS());
text.append_format("{}VPS: {:.2f}", first ? "" : " | ", PerformanceMetrics::GetFPS());
first = false;
}
@@ -175,8 +176,11 @@ __ri void ImGuiManager::DrawPerformanceOverlay(float& position_y, float scale, f
if (GSConfig.OsdShowVersion)
{
// text.append_format("{}PCSX2 {}", first ? "" : " | ", BuildVersion::GitRev);
text.append_format("{}ARMSX2 {}", first ? "" : " | ", "v2.3.430");
#if defined(__APPLE__) && TARGET_OS_IPHONE
text.append_format("{}ARMSX2 iOS", first ? "" : " | ");
#else
text.append_format("{}ARMSX2 {}", first ? "" : " | ", BuildVersion::GitRev);
#endif
}
if (!text.empty())
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-3.0+
import SwiftUI
import Foundation
import UniformTypeIdentifiers
@Observable
@@ -83,12 +84,14 @@ final class FileImportHandler: @unchecked Sendable {
if preferredDestination == .game {
guard Self.gameExtensions.contains(ext) else {
NSLog("[ARMSX2 iOS Import] unsupported game file: %@", fileName)
return .unsupported(fileName)
}
destDir = (docsPath as NSString).appendingPathComponent("iso")
category = "Game"
} else if preferredDestination == .bios {
guard Self.biosExtensions.contains(ext) else {
NSLog("[ARMSX2 iOS Import] unsupported BIOS file: %@", fileName)
return .unsupported(fileName)
}
destDir = (docsPath as NSString).appendingPathComponent("bios")
@@ -108,6 +111,7 @@ final class FileImportHandler: @unchecked Sendable {
category = "BIOS"
}
} else {
NSLog("[ARMSX2 iOS Import] unsupported file: %@", fileName)
return .unsupported(fileName)
}
@@ -122,8 +126,10 @@ final class FileImportHandler: @unchecked Sendable {
try FileManager.default.removeItem(atPath: destPath)
}
try FileManager.default.copyItem(at: url, to: URL(fileURLWithPath: destPath))
NSLog("[ARMSX2 iOS Import] %@ imported: %@ -> %@", category, fileName, destPath)
return .success("\(category) imported: \(fileName)")
} catch {
NSLog("[ARMSX2 iOS Import] failed: %@ -> %@ error=%@", fileName, destPath, error.localizedDescription)
return .failure("\(fileName): \(error.localizedDescription)")
}
}
+117 -18
View File
@@ -26,7 +26,10 @@ final class SettingsStore: @unchecked Sendable {
// Emulator / CPU
var eeCoreType: Int {
didSet { ARMSX2Bridge.setINIInt("EmuCore/CPU", key: "CoreType", value: Int32(eeCoreType)) }
didSet {
ARMSX2Bridge.setINIInt("EmuCore/CPU", key: "CoreType", value: Int32(eeCoreType))
ARMSX2Bridge.setINIBool("EmuCore/CPU", key: "UseArm64Dynarec", value: eeCoreType == 2)
}
}
var iopRecompiler: Bool {
didSet { ARMSX2Bridge.setINIBool("EmuCore/CPU/Recompiler", key: "EnableIOP", value: iopRecompiler) }
@@ -89,7 +92,7 @@ final class SettingsStore: @unchecked Sendable {
didSet { ARMSX2Bridge.setINIInt("EmuCore/GS", key: "deinterlace_mode", value: Int32(interlaceMode)) }
}
var aspectRatio: Int {
didSet { ARMSX2Bridge.setINIInt("EmuCore/GS", key: "AspectRatio", value: Int32(aspectRatio)) }
didSet { ARMSX2Bridge.setINIString("EmuCore/GS", key: "AspectRatio", value: Self.aspectRatioName(for: aspectRatio)) }
}
var blendingAccuracy: Int {
didSet { ARMSX2Bridge.setINIInt("EmuCore/GS", key: "accurate_blending_unit", value: Int32(blendingAccuracy)) }
@@ -105,21 +108,48 @@ final class SettingsStore: @unchecked Sendable {
applyOsdPreset(osdPreset)
}
}
var osdPerformancePosition: Int {
didSet { ARMSX2Bridge.setINIInt("EmuCore/GS", key: "OsdPerformancePos", value: Int32(osdPerformancePosition)) }
}
var osdShowFPS: Bool {
didSet { ARMSX2Bridge.setINIBool("EmuCore/GS", key: "OsdShowFPS", value: osdShowFPS) }
}
var osdShowVPS: Bool {
didSet { ARMSX2Bridge.setINIBool("EmuCore/GS", key: "OsdShowVPS", value: osdShowVPS) }
}
var osdShowSpeed: Bool {
didSet { ARMSX2Bridge.setINIBool("EmuCore/GS", key: "OsdShowSpeed", value: osdShowSpeed) }
}
var osdShowCPU: Bool {
didSet { ARMSX2Bridge.setINIBool("EmuCore/GS", key: "OsdShowCPU", value: osdShowCPU) }
}
var osdShowGPU: Bool {
didSet { ARMSX2Bridge.setINIBool("EmuCore/GS", key: "OsdShowGPU", value: osdShowGPU) }
}
var osdShowResolution: Bool {
didSet { ARMSX2Bridge.setINIBool("EmuCore/GS", key: "OsdShowResolution", value: osdShowResolution) }
}
var osdShowGSStats: Bool {
didSet { ARMSX2Bridge.setINIBool("EmuCore/GS", key: "OsdShowGSStats", value: osdShowGSStats) }
}
var osdShowIndicators: Bool {
didSet { ARMSX2Bridge.setINIBool("EmuCore/GS", key: "OsdShowIndicators", value: osdShowIndicators) }
}
var osdShowSettings: Bool {
didSet { ARMSX2Bridge.setINIBool("EmuCore/GS", key: "OsdShowSettings", value: osdShowSettings) }
}
var osdShowInputs: Bool {
didSet { ARMSX2Bridge.setINIBool("EmuCore/GS", key: "OsdShowInputs", value: osdShowInputs) }
}
var osdShowFrameTimes: Bool {
didSet { ARMSX2Bridge.setINIBool("EmuCore/GS", key: "OsdShowFrameTimes", value: osdShowFrameTimes) }
}
var osdShowVersion: Bool {
didSet { ARMSX2Bridge.setINIBool("EmuCore/GS", key: "OsdShowVersion", value: osdShowVersion) }
}
var osdShowHardwareInfo: Bool {
didSet { ARMSX2Bridge.setINIBool("EmuCore/GS", key: "OsdShowHardwareInfo", value: osdShowHardwareInfo) }
}
// Gamepad / UI
var padOpacity: Float {
@@ -129,6 +159,28 @@ final class SettingsStore: @unchecked Sendable {
didSet { ARMSX2Bridge.setINIBool("ARMSX2iOS/UI", key: "HapticFeedback", value: hapticFeedback) }
}
private static func aspectRatioName(for value: Int) -> String {
switch value {
case 0: return "Stretch"
case 1: return "Auto 4:3/3:2"
case 2: return "4:3"
case 3: return "16:9"
case 4: return "10:7"
default: return "Auto 4:3/3:2"
}
}
private static func aspectRatioValue(from name: String) -> Int {
switch name {
case "Stretch", "0": return 0
case "Auto 4:3/3:2", "1": return 1
case "4:3", "2": return 2
case "16:9", "3": return 3
case "10:7", "4": return 4
default: return 1
}
}
// Init from INI
private init() {
// CPU
@@ -159,19 +211,29 @@ final class SettingsStore: @unchecked Sendable {
casMode = Int(ARMSX2Bridge.getINIInt("EmuCore/GS", key: "CASMode", defaultValue: 0))
casSharpness = Int(ARMSX2Bridge.getINIInt("EmuCore/GS", key: "CASSharpness", defaultValue: 50))
interlaceMode = Int(ARMSX2Bridge.getINIInt("EmuCore/GS", key: "deinterlace_mode", defaultValue: 7))
aspectRatio = Int(ARMSX2Bridge.getINIInt("EmuCore/GS", key: "AspectRatio", defaultValue: 0))
aspectRatio = Self.aspectRatioValue(from: ARMSX2Bridge.getINIString("EmuCore/GS", key: "AspectRatio", defaultValue: "Auto 4:3/3:2"))
blendingAccuracy = Int(ARMSX2Bridge.getINIInt("EmuCore/GS", key: "accurate_blending_unit", defaultValue: 1))
dithering = Int(ARMSX2Bridge.getINIInt("EmuCore/GS", key: "dithering_ps2", defaultValue: 2))
// OSD
osdPreset = OsdPreset(rawValue: Int(ARMSX2Bridge.getINIInt("ARMSX2iOS/UI", key: "OsdPreset", defaultValue: 0))) ?? .off
osdPerformancePosition = Int(ARMSX2Bridge.getINIInt("EmuCore/GS", key: "OsdPerformancePos", defaultValue: 2))
osdShowFPS = ARMSX2Bridge.getINIBool("EmuCore/GS", key: "OsdShowFPS", defaultValue: false)
osdShowVPS = ARMSX2Bridge.getINIBool("EmuCore/GS", key: "OsdShowVPS", defaultValue: false)
osdShowSpeed = ARMSX2Bridge.getINIBool("EmuCore/GS", key: "OsdShowSpeed", defaultValue: false)
osdShowCPU = ARMSX2Bridge.getINIBool("EmuCore/GS", key: "OsdShowCPU", defaultValue: false)
osdShowGPU = ARMSX2Bridge.getINIBool("EmuCore/GS", key: "OsdShowGPU", defaultValue: false)
osdShowResolution = ARMSX2Bridge.getINIBool("EmuCore/GS", key: "OsdShowResolution", defaultValue: false)
osdShowGSStats = ARMSX2Bridge.getINIBool("EmuCore/GS", key: "OsdShowGSStats", defaultValue: false)
osdShowIndicators = ARMSX2Bridge.getINIBool("EmuCore/GS", key: "OsdShowIndicators", defaultValue: false)
osdShowSettings = ARMSX2Bridge.getINIBool("EmuCore/GS", key: "OsdShowSettings", defaultValue: false)
osdShowInputs = ARMSX2Bridge.getINIBool("EmuCore/GS", key: "OsdShowInputs", defaultValue: false)
osdShowFrameTimes = ARMSX2Bridge.getINIBool("EmuCore/GS", key: "OsdShowFrameTimes", defaultValue: false)
osdShowVersion = ARMSX2Bridge.getINIBool("EmuCore/GS", key: "OsdShowVersion", defaultValue: false)
osdShowHardwareInfo = ARMSX2Bridge.getINIBool("EmuCore/GS", key: "OsdShowHardwareInfo", defaultValue: false)
// UI
padOpacity = ARMSX2Bridge.getINIFloat("ARMSX2iOS/UI", key: "PadOpacity", defaultValue: 0.6)
hapticFeedback = ARMSX2Bridge.getINIBool("ARMSX2iOS/UI", key: "HapticFeedback", defaultValue: true)
ARMSX2Bridge.setINIString("EmuCore/GS", key: "AspectRatio", value: Self.aspectRatioName(for: aspectRatio))
// [P60] Force MTVU off (known buggy)
ARMSX2Bridge.setINIBool("EmuCore/Speedhacks", key: "vuThread", value: false)
// Apply OSD preset
@@ -204,15 +266,24 @@ final class SettingsStore: @unchecked Sendable {
casMode = Int(ARMSX2Bridge.getINIInt("EmuCore/GS", key: "CASMode", defaultValue: 0))
casSharpness = Int(ARMSX2Bridge.getINIInt("EmuCore/GS", key: "CASSharpness", defaultValue: 50))
interlaceMode = Int(ARMSX2Bridge.getINIInt("EmuCore/GS", key: "deinterlace_mode", defaultValue: 7))
aspectRatio = Int(ARMSX2Bridge.getINIInt("EmuCore/GS", key: "AspectRatio", defaultValue: 0))
aspectRatio = Self.aspectRatioValue(from: ARMSX2Bridge.getINIString("EmuCore/GS", key: "AspectRatio", defaultValue: "Auto 4:3/3:2"))
blendingAccuracy = Int(ARMSX2Bridge.getINIInt("EmuCore/GS", key: "accurate_blending_unit", defaultValue: 1))
dithering = Int(ARMSX2Bridge.getINIInt("EmuCore/GS", key: "dithering_ps2", defaultValue: 2))
osdPreset = OsdPreset(rawValue: Int(ARMSX2Bridge.getINIInt("ARMSX2iOS/UI", key: "OsdPreset", defaultValue: 0))) ?? .off
osdPerformancePosition = Int(ARMSX2Bridge.getINIInt("EmuCore/GS", key: "OsdPerformancePos", defaultValue: 2))
osdShowFPS = ARMSX2Bridge.getINIBool("EmuCore/GS", key: "OsdShowFPS", defaultValue: false)
osdShowVPS = ARMSX2Bridge.getINIBool("EmuCore/GS", key: "OsdShowVPS", defaultValue: false)
osdShowSpeed = ARMSX2Bridge.getINIBool("EmuCore/GS", key: "OsdShowSpeed", defaultValue: false)
osdShowCPU = ARMSX2Bridge.getINIBool("EmuCore/GS", key: "OsdShowCPU", defaultValue: false)
osdShowGPU = ARMSX2Bridge.getINIBool("EmuCore/GS", key: "OsdShowGPU", defaultValue: false)
osdShowResolution = ARMSX2Bridge.getINIBool("EmuCore/GS", key: "OsdShowResolution", defaultValue: false)
osdShowGSStats = ARMSX2Bridge.getINIBool("EmuCore/GS", key: "OsdShowGSStats", defaultValue: false)
osdShowIndicators = ARMSX2Bridge.getINIBool("EmuCore/GS", key: "OsdShowIndicators", defaultValue: false)
osdShowSettings = ARMSX2Bridge.getINIBool("EmuCore/GS", key: "OsdShowSettings", defaultValue: false)
osdShowInputs = ARMSX2Bridge.getINIBool("EmuCore/GS", key: "OsdShowInputs", defaultValue: false)
osdShowFrameTimes = ARMSX2Bridge.getINIBool("EmuCore/GS", key: "OsdShowFrameTimes", defaultValue: false)
osdShowVersion = ARMSX2Bridge.getINIBool("EmuCore/GS", key: "OsdShowVersion", defaultValue: false)
osdShowHardwareInfo = ARMSX2Bridge.getINIBool("EmuCore/GS", key: "OsdShowHardwareInfo", defaultValue: false)
padOpacity = ARMSX2Bridge.getINIFloat("ARMSX2iOS/UI", key: "PadOpacity", defaultValue: 0.6)
hapticFeedback = ARMSX2Bridge.getINIBool("ARMSX2iOS/UI", key: "HapticFeedback", defaultValue: true)
}
@@ -220,37 +291,65 @@ final class SettingsStore: @unchecked Sendable {
/// Apply OSD preset writes ALL OSD flags to INI + GSConfig
private func applyOsdPreset(_ preset: OsdPreset) {
ARMSX2Bridge.applyOsdPreset(Int32(preset.rawValue))
if preset == .off {
osdPerformancePosition = 0
} else if osdPerformancePosition == 0 {
osdPerformancePosition = 2
}
let isSimple = preset == .simple
let isDetail = preset == .detail
let isFull = preset == .full
osdShowFPS = isSimple || isDetail || isFull
osdShowSpeed = isDetail || isFull
osdShowVPS = isDetail || isFull
osdShowSpeed = isSimple || isDetail || isFull
osdShowCPU = isSimple || isDetail || isFull
osdShowGPU = isDetail || isFull
osdShowResolution = isDetail || isFull
osdShowGSStats = isFull
osdShowIndicators = isSimple || isDetail || isFull
osdShowSettings = isFull
osdShowInputs = isFull
osdShowFrameTimes = isFull
ARMSX2Bridge.setINIBool("EmuCore/GS", key: "OsdShowVPS", value: false)
ARMSX2Bridge.setINIBool("EmuCore/GS", key: "OsdShowVersion", value: false)
ARMSX2Bridge.setINIBool("EmuCore/GS", key: "OsdShowHardwareInfo", value: false)
ARMSX2Bridge.setINIBool("EmuCore/GS", key: "OsdShowGPU", value: false)
ARMSX2Bridge.setINIBool("EmuCore/GS", key: "OsdShowGSStats", value: false)
osdShowVersion = isFull
osdShowHardwareInfo = isFull
}
/// Reset emulator settings to PC PCSX2 defaults
/// Reset emulator settings to ARMSX2 iOS defaults
func resetEmulatorDefaults() {
eeCoreType = 2 // ARM64 JIT
iopRecompiler = true
vu0Recompiler = true // PC PCSX2 default: microVU JIT
vu1Recompiler = true // PC PCSX2 default: microVU JIT
vu0Recompiler = true
vu1Recompiler = true
fastBoot = false
fastmem = true
fastCDVD = false
eeCycleRate = 0
vu1Instant = true // PC PCSX2 recommended default
waitLoop = true // PC PCSX2 recommended default
intcStat = true // PC PCSX2 recommended default
vu1Instant = true
waitLoop = true
intcStat = true
}
/// Reset graphics settings to PC PCSX2 defaults
/// Keep EE/IOP/VU0 fast while isolating suspected VU1 JIT regressions.
func applyVU1CompatibilityPreset() {
eeCoreType = 2
iopRecompiler = true
vu0Recompiler = true
vu1Recompiler = false
vu1Instant = false
fastmem = false
}
/// Slow diagnostic preset for crash isolation when dynarec state is suspect.
func applyFullInterpreterPreset() {
eeCoreType = 1
iopRecompiler = false
vu0Recompiler = false
vu1Recompiler = false
vu1Instant = false
fastmem = false
}
/// Reset graphics settings to ARMSX2 iOS defaults
func resetGraphicsDefaults() {
renderer = 17 // Metal
upscaleMultiplier = 1.0 // Native PS2
@@ -260,7 +359,7 @@ final class SettingsStore: @unchecked Sendable {
casMode = 0 // Disabled
casSharpness = 50
interlaceMode = 7 // Adaptive
aspectRatio = 0 // Auto 4:3/3:2
aspectRatio = 1 // Auto 4:3/3:2
blendingAccuracy = 1 // Basic
dithering = 2 // Scaled
}
@@ -25,7 +25,7 @@ struct BootSplashView: View {
}
.task {
try? await Task.sleep(nanoseconds: Self.hardTimeout)
await finish()
finish()
}
}
@@ -79,7 +79,7 @@ private struct BootSplashPlayerView: UIViewRepresentable {
coordinator.stopObserving()
}
final class Coordinator {
final class Coordinator: @unchecked Sendable {
var player: AVPlayer?
private let onFinished: () -> Void
private var endToken: NSObjectProtocol?
+18 -12
View File
@@ -205,22 +205,28 @@ private struct SaveStatesPanel: View {
}
private func save(_ slot: ARMSX2SaveStateSlotInfo) {
busySlot = slot.slot
ARMSX2Bridge.saveState(toSlot: slot.slot) { success in
busySlot = nil
refresh()
statusHandler(success ? "State saved to slot \(slot.slot)" : "Failed to save slot \(slot.slot)")
let slotNumber = slot.slot
busySlot = slotNumber
ARMSX2Bridge.saveState(toSlot: slotNumber) { success in
Task { @MainActor in
busySlot = nil
refresh()
statusHandler(success ? "State saved to slot \(slotNumber)" : "Failed to save slot \(slotNumber)")
}
}
}
private func load(_ slot: ARMSX2SaveStateSlotInfo) {
busySlot = slot.slot
ARMSX2Bridge.loadState(fromSlot: slot.slot) { success in
busySlot = nil
refresh()
statusHandler(success ? "State loaded from slot \(slot.slot)" : "Failed to load slot \(slot.slot)")
if success {
dismiss()
let slotNumber = slot.slot
busySlot = slotNumber
ARMSX2Bridge.loadState(fromSlot: slotNumber) { success in
Task { @MainActor in
busySlot = nil
refresh()
statusHandler(success ? "State loaded from slot \(slotNumber)" : "Failed to load slot \(slotNumber)")
if success {
dismiss()
}
}
}
}
+1 -1
View File
@@ -60,7 +60,7 @@ private let helpData: [HelpSection] = [
HelpSection(title: "Overlay", icon: "speedometer", items: [
HelpItem(
question: "Overlay presets",
answer: "OFF: No overlay. Simple: FPS + CPU usage. Detail: FPS, Speed, CPU, Resolution. Full: Everything including Frame Times graph. Configure in Settings > Overlay."
answer: "OFF hides the overlay. Simple shows FPS, speed, CPU, and indicators. Detail adds VPS, GPU, and resolution. Full enables the Android-style diagnostic set including GS stats, settings, inputs, frame times, version, and hardware info."
),
HelpItem(
question: "In-game toggle",
@@ -69,6 +69,22 @@ struct EmulatorSettingsView: View {
.foregroundStyle(.secondary)
}
Section {
Button("Use VU1 Interpreter Preset") {
settings.applyVU1CompatibilityPreset()
}
Button("Use Full Interpreter Preset") {
settings.applyFullInterpreterPreset()
}
Text("Use the VU1 preset first for boot crashes or VU1-related texture/rendering glitches. Full Interpreter is much slower, but helps isolate dynarec/JIT issues.")
.font(.caption)
.foregroundStyle(.secondary)
} header: {
Text("Compatibility")
} footer: {
Text("Changes take effect on next VM boot.")
}
Section {
Stepper("EE Cycle Rate: \(settings.eeCycleRate)", value: $settings.eeCycleRate, in: -3...3)
Text("0 = Default. Negative = underclock (stable). Positive = overclock (fast but risky).")
@@ -80,7 +96,7 @@ struct EmulatorSettingsView: View {
Toggle("Wait Loop Detection", isOn: $settings.waitLoop)
Toggle("INTC Stat Hack", isOn: $settings.intcStat)
Text("These are recommended defaults from PCSX2. Disable only if a specific game has issues.")
Text("These are recommended compatibility defaults. Disable only if a specific game has issues.")
.font(.caption)
.foregroundStyle(.secondary)
} header: {
@@ -126,8 +126,10 @@ struct GamepadSettingsView: View {
let captured = ARMSX2Bridge.capturedButton()
if captured >= 0 {
ARMSX2Bridge.setButtonMapping(Int32(ps2Index), toSDLButton: captured)
stopCapture()
mappingVersion += 1
Task { @MainActor in
stopCapture()
mappingVersion += 1
}
}
}
}
@@ -90,10 +90,11 @@ struct GraphicsSettingsView: View {
}
Picker("Aspect Ratio", selection: $settings.aspectRatio) {
Text("Auto 4:3 / 3:2 (Default)").tag(0)
Text("4:3").tag(1)
Text("16:9 (Widescreen)").tag(2)
Text("Stretch to Window").tag(3)
Text("Auto 4:3 / 3:2 (Default)").tag(1)
Text("4:3").tag(2)
Text("16:9 (Widescreen)").tag(3)
Text("10:7").tag(4)
Text("Stretch to Window").tag(0)
}
}
@@ -15,30 +15,33 @@ struct OverlaySettingsView: View {
}
}
.pickerStyle(.segmented)
Picker("Position", selection: $settings.osdPerformancePosition) {
Text("Hidden").tag(0)
Text("Top Left").tag(1)
Text("Top Right").tag(2)
}
}
Section {
switch settings.osdPreset {
case .off:
Text("Overlay is hidden.")
.foregroundStyle(.secondary)
case .simple:
Label("FPS", systemImage: "checkmark")
Label("CPU Usage (EE/GS)", systemImage: "checkmark")
case .detail:
Label("FPS", systemImage: "checkmark")
Label("Speed %", systemImage: "checkmark")
Label("CPU Usage (EE/GS)", systemImage: "checkmark")
Label("Resolution", systemImage: "checkmark")
case .full:
Label("FPS", systemImage: "checkmark")
Label("Speed %", systemImage: "checkmark")
Label("CPU Usage (EE/GS)", systemImage: "checkmark")
Label("Resolution", systemImage: "checkmark")
Label("Frame Times Graph", systemImage: "checkmark")
}
} header: {
Text("Displayed Items")
Section("Displayed Items") {
Toggle("Show FPS", isOn: $settings.osdShowFPS)
Toggle("Show VPS", isOn: $settings.osdShowVPS)
Toggle("Show Speed", isOn: $settings.osdShowSpeed)
Toggle("Show CPU", isOn: $settings.osdShowCPU)
Toggle("Show GPU", isOn: $settings.osdShowGPU)
Toggle("Show Resolution", isOn: $settings.osdShowResolution)
Toggle("Show GS Stats", isOn: $settings.osdShowGSStats)
Toggle("Show Indicators", isOn: $settings.osdShowIndicators)
Toggle("Show Settings", isOn: $settings.osdShowSettings)
Toggle("Show Inputs", isOn: $settings.osdShowInputs)
Toggle("Show Frame Times", isOn: $settings.osdShowFrameTimes)
Toggle("Show Version", isOn: $settings.osdShowVersion)
Toggle("Show Hardware Info", isOn: $settings.osdShowHardwareInfo)
}
Section("Notes") {
Text("These match ARMSX2 Android's OSD/stat controls where practical. When Show Version is enabled, the overlay label displays ARMSX2 iOS.")
.foregroundStyle(.secondary)
}
}
.navigationTitle("Overlay")