From 8e23439b26d65bb4e5f129bc2be4da8fdd34f036 Mon Sep 17 00:00:00 2001 From: jpolo1224 Date: Fri, 24 Jul 2026 02:40:17 -0400 Subject: [PATCH] Android 2.6.5: Adreno Vulkan default, low-latency default, UI sounds, RA client hardening, GameDB Rendering - Auto renderer now resolves to Vulkan HW on Adreno (OpenGL elsewhere). - Mobile hardware ROV (Phase 0): tile-native depth feedback behind the ROV toggle. Performance & input - Low Latency frame pacing is the default on capable devices, with a one-time migration for existing installs; low-end devices keep the queued pacing. - Reduce Android input latency and improve input handling (PR #403, Splaser). - Experimental CPU clock hint (ADPF) toggle in Performance settings (default off). Audio & UI - Pop-up open/close sound cues (info, hardcore confirm, patches & cheats). - Alternating controller navigation / slider tick sounds. RetroAchievements - Inject the RA client version from a build-time secret kept out of public source, with a stock-PCSX2 fallback (no hardcore) for secret-less builds. Applies to the iOS client token too. Prevents third parties from copying our User-Agent. Game compatibility - Delta Force: Black Hawk Down (SLUS-21124 / SLES-53299) GameDB fixes (PR #401, XDarkFallenX). --- .gitignore | 4 + bin/resources-overlay/armsx2_overrides.yaml | 13 + pcsx2/Counters.cpp | 2 + pcsx2/GS/GSUtil.cpp | 20 +- pcsx2/GS/Renderers/HW/GSTextureCache.cpp | 17 +- pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp | 77 +++++- pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h | 1 + pcsx2/GS/Renderers/Vulkan/VKBuilders.cpp | 5 + pcsx2/GS/Renderers/Vulkan/VKBuilders.h | 1 + pcsx2/Host.cpp | 54 ++++- pcsx2/MTGS.cpp | 2 + pcsx2/MTVU.cpp | 2 + pcsx2/PerformanceMetrics.cpp | 228 ++++++++++++++++++ pcsx2/PerformanceMetrics.h | 21 ++ pcsx2/VMManager.cpp | 13 + .../app/src/main/assets/i18n/zh-CN.json | 2 + .../app/src/main/assets/i18n/zh-TW.json | 2 + .../android/app/src/main/cpp/native-lib.cpp | 29 +++ .../app/src/main/java/com/armsx2/MenuSfx.kt | 23 +- .../java/com/armsx2/config/ConfigStore.kt | 29 +++ .../app/src/main/java/com/armsx2/i18n/I18n.kt | 6 +- .../com/armsx2/input/ControllerMappings.kt | 161 +++++++++++-- .../com/armsx2/runtime/EmulationSurface.kt | 181 +++++++++++++- .../com/armsx2/runtime/MainActivityRuntime.kt | 148 +++++++----- .../ui/achievements/AchievementsScreen.kt | 4 + .../ui/emulation/EmulationMenuScreen.kt | 4 + .../armsx2/ui/patches/PatchManagerScreen.kt | 8 + .../java/com/armsx2/ui/settings/FixesTab.kt | 9 - .../com/armsx2/ui/settings/PerformanceTab.kt | 37 +++ .../com/armsx2/ui/settings/SettingsWidgets.kt | 4 + .../ui/settingshub/SettingsSearchIndex.kt | 3 +- .../java/com/armsx2/ui/touch/TouchControls.kt | 33 ++- .../java/kr/co/iefriends/pcsx2/NativeApp.java | 9 + .../app/src/main/res/raw/sfx_nav_a.wav | Bin 0 -> 16802 bytes .../app/src/main/res/raw/sfx_nav_b.wav | Bin 0 -> 16802 bytes .../app/src/main/res/raw/sfx_popup_close.wav | Bin 0 -> 66194 bytes .../app/src/main/res/raw/sfx_popup_open.wav | Bin 0 -> 66194 bytes 37 files changed, 1026 insertions(+), 126 deletions(-) create mode 100644 platforms/android/app/src/main/res/raw/sfx_nav_a.wav create mode 100644 platforms/android/app/src/main/res/raw/sfx_nav_b.wav create mode 100644 platforms/android/app/src/main/res/raw/sfx_popup_close.wav create mode 100644 platforms/android/app/src/main/res/raw/sfx_popup_open.wav diff --git a/.gitignore b/.gitignore index 80f2446209..a9e93f20e7 100644 --- a/.gitignore +++ b/.gitignore @@ -147,3 +147,7 @@ CMakeSettings.json # Achievement sounds are shipped assets, not build output — keep them tracked !platforms/android/app/src/main/assets/resources/sounds/**/*.wav + +# RetroAchievements client User-Agent secret — the real pinned version is injected +# from this header at build time and must NEVER be committed (spoofing prevention). +ra_ua_secret.h diff --git a/bin/resources-overlay/armsx2_overrides.yaml b/bin/resources-overlay/armsx2_overrides.yaml index 04599c35a1..ad6f66a1a5 100644 --- a/bin/resources-overlay/armsx2_overrides.yaml +++ b/bin/resources-overlay/armsx2_overrides.yaml @@ -13,6 +13,19 @@ # Generated from the Android GameIndex delta vs bin plus the former runtime # armsx2_overrides.yaml. Regenerate via devs/bmdhacks tooling; do not bulk # hand-edit. +# Delta Force: Black Hawk Down — GameDB fixes (PR #401, XDarkFallenX) +SLUS-21124: + gameFixes: + - InstantDMAHack + - BlitInternalFPSHack + gsHWFixes: + hwDownloadMode: 3 +SLES-53299: + gameFixes: + - InstantDMAHack + - BlitInternalFPSHack + gsHWFixes: + hwDownloadMode: 3 PAPX-90522: clampModes: eeClampMode: 3 diff --git a/pcsx2/Counters.cpp b/pcsx2/Counters.cpp index 17e5874fe0..d3d3cf7e9c 100644 --- a/pcsx2/Counters.cpp +++ b/pcsx2/Counters.cpp @@ -493,6 +493,8 @@ static __fi void VSyncStart(u64 sCycle) // Don't bother throttling if we're going to pause. if (!VMManager::Internal::IsExecutionInterrupted()) VMManager::Internal::Throttle(); + else + PerformanceMetrics::AdpfPauseFrameWork(); // interrupted → no Throttle → drop the ADPF period so the resume report excludes the pause gsPostVsyncStart(); // MUST be after framelimit; doing so before causes funk with frame times! diff --git a/pcsx2/GS/GSUtil.cpp b/pcsx2/GS/GSUtil.cpp index e050a53543..bfa1c52b2f 100644 --- a/pcsx2/GS/GSUtil.cpp +++ b/pcsx2/GS/GSUtil.cpp @@ -282,6 +282,12 @@ u32 GSUtil::GetChannelMask(u32 spsm, u32 fbmsk) return mask; } +#if defined(__ANDROID__) +// Set by the Android app from the GL_RENDERER string (NativeApp.setPreferVulkan): true steers the +// Auto renderer resolution to Vulkan HW on Adreno; false keeps OpenGL HW (Mali/Xclipse/others). +bool g_gs_android_prefer_vk = false; +#endif + GSRendererType GSUtil::GetPreferredRenderer() { // Memorize the value, so we don't keep re-querying it. @@ -298,13 +304,13 @@ GSRendererType GSUtil::GetPreferredRenderer() // Use D3D device info to select renderer. preferred_renderer = D3D::GetPreferredRenderer(); #elif defined(__ANDROID__) - // Android: prefer OpenGL HW. Vulkan's suitability probe is fragile - // across the wide spread of mobile driver stacks, and falling through - // to SW for alpha-heavy games (FFX battles, smoke effects) is far - // worse than running OGL HW even on devices where Vulkan would also - // have worked. Users can still pick Vulkan or SW explicitly via the - // renderer setting; this only steers the Auto resolution. -#if defined(ENABLE_OPENGL) + // Android: Auto resolves to Vulkan HW on Adreno (the tile-memory framebuffer-fetch fast + // path), OpenGL HW elsewhere (Mali runs GL_ARM_shader_framebuffer_fetch; Xclipse has no + // working VK fbfetch). The app sets g_gs_android_prefer_vk from the GL_RENDERER string + // before the GS starts. This only steers Auto — an explicit Vulkan/OpenGL/SW pick still wins. +#if defined(ENABLE_VULKAN) && defined(ENABLE_OPENGL) + preferred_renderer = g_gs_android_prefer_vk ? GSRendererType::VK : GSRendererType::OGL; +#elif defined(ENABLE_OPENGL) preferred_renderer = GSRendererType::OGL; #elif defined(ENABLE_VULKAN) preferred_renderer = GSRendererType::VK; diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp index ca54b8e5a5..ca6f38ce52 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp @@ -15,6 +15,8 @@ #include "common/HashCombine.h" #include "common/SmallString.h" +#include + #include "fmt/format.h" #include @@ -430,7 +432,14 @@ GSVector4i GSTextureCache::TranslateAlignedRectByPage(u32 tbp, u32 tebp, u32 tbw // The width is mismatched to the page. if (!is_invalidation && GSConfig.UserHacks_TextureInsideRt < GSTextureInRtMode::MergeTargets) { - DevCon.Warning("Uneven pages mess up sbp %x dbp %x spgw %d dpgw %d src fmt %d dst fmt %d src_rect %d, %d, %d, %d draw %lld", sbp, tbp, src_pgw, dst_pgw, spsm, tpsm, in_rect.x, in_rect.y, in_rect.z, in_rect.w, GSRendererHW::GetInstance()->s_n); + // Rate-limited: on render-target churn this fires thousands of times/second (Rogue Galaxy: + // 5000+ per session) and a synchronous log per hit is itself a cost that drowns the log. + // Lock-free geometric backoff — atomic, not a plain static, since the TC can be reached + // off the GS back thread under pipelined GS. Each emitted line carries the running total. + static std::atomic s_uneven_hits{0}; + const u64 uneven_n = s_uneven_hits.fetch_add(1, std::memory_order_relaxed) + 1; + if ((uneven_n & (uneven_n - 1)) == 0) + DevCon.Warning("Uneven pages mess up (#%llu) sbp %x dbp %x spgw %d dpgw %d src fmt %d dst fmt %d src_rect %d, %d, %d, %d draw %lld", uneven_n, sbp, tbp, src_pgw, dst_pgw, spsm, tpsm, in_rect.x, in_rect.y, in_rect.z, in_rect.w, GSRendererHW::GetInstance()->s_n); return GSVector4i::zero(); } @@ -573,7 +582,11 @@ GSVector4i GSTextureCache::TranslateAlignedRectByPage(u32 tbp, u32 tebp, u32 tbw // Results won't be square, if it's not invalidation, it's a texture, which is problematic to translate, so let's not (FIFA 2005). if (!is_invalidation) { - DevCon.Warning("Uneven pages mess up sbp %x dbp %x spgw %d dpgw %d", sbp, tbp, src_pgw, dst_pgw); + // Rate-limited (see the sibling site above): lock-free geometric backoff. + static std::atomic s_uneven_hits2{0}; + const u64 n = s_uneven_hits2.fetch_add(1, std::memory_order_relaxed) + 1; + if ((n & (n - 1)) == 0) + DevCon.Warning("Uneven pages mess up (#%llu) sbp %x dbp %x spgw %d dpgw %d", n, sbp, tbp, src_pgw, dst_pgw); return GSVector4i::zero(); } diff --git a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp index 35edfc7435..40894a1ca2 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp +++ b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp @@ -730,6 +730,21 @@ bool GSDeviceVK::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer if (m_optional_extensions.vk_ext_rasterization_order_attachment_access) { rasterization_order_access_feature.rasterizationOrderColorAttachmentAccess = VK_TRUE; + + // Tile-native ordered DEPTH feedback ("mobile ROV"): the depth aspect of ROAA is an + // OPTIONAL sub-feature — a driver may expose the extension and color access yet not + // depth. The full feature reconcile (ProcessDeviceExtensions) runs only AFTER + // vkCreateDevice, too late to gate this, and requesting an unsupported feature fails + // device creation with VK_ERROR_FEATURE_NOT_PRESENT. So probe the depth bit up-front + // and only request it when the device actually advertises it. + VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT roaa_probe = { + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT}; + VkPhysicalDeviceFeatures2 roaa_probe2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, &roaa_probe}; + vkGetPhysicalDeviceFeatures2(m_physical_device, &roaa_probe2); + m_optional_extensions.vk_ext_roaa_depth = (roaa_probe.rasterizationOrderDepthAttachmentAccess == VK_TRUE); + if (m_optional_extensions.vk_ext_roaa_depth) + rasterization_order_access_feature.rasterizationOrderDepthAttachmentAccess = VK_TRUE; + Vulkan::AddPointerToChain(&device_info, &rasterization_order_access_feature); } if (m_optional_extensions.vk_ext_attachment_feedback_loop_layout) @@ -869,6 +884,9 @@ bool GSDeviceVK::ProcessDeviceExtensions() m_optional_extensions.vk_ext_provoking_vertex &= (provoking_vertex_features.provokingVertexLast == VK_TRUE); m_optional_extensions.vk_ext_rasterization_order_attachment_access &= (rasterization_order_access_feature.rasterizationOrderColorAttachmentAccess == VK_TRUE); + // Depth ROAA is meaningless (and its subpass/pipeline flags invalid) without the color + // extension being usable; keep them consistent after the post-create reconcile. + m_optional_extensions.vk_ext_roaa_depth &= m_optional_extensions.vk_ext_rasterization_order_attachment_access; m_optional_extensions.vk_ext_attachment_feedback_loop_layout &= (attachment_feedback_loop_feature.attachmentFeedbackLoopLayout == VK_TRUE); @@ -897,6 +915,10 @@ bool GSDeviceVK::ProcessDeviceExtensions() if (m_device_properties.vendorID == 0x13B5u && m_optional_extensions.vk_khr_driver_properties && std::string_view(m_device_driver_properties.driverInfo).find("r44p1") != std::string_view::npos) { + // NOTE: this layout disable alone did NOT stop the DEVICE_LOST — the per-primitive barrier / + // fbfetch path it falls back to lowers to the same faulting in-tile silicon. The real fix + // forces r44p1 onto the RT-copy blend path by ALSO disabling texture_barrier; see the matching + // "Mali r44p1:" block where m_features.texture_barrier is resolved. Console.WriteLn("Mali r44p1: disabling attachment-feedback-loop blend path (DEVICE_LOST workaround)."); m_optional_extensions.vk_ext_attachment_feedback_loop_layout = false; } @@ -1976,10 +1998,17 @@ VkRenderPass GSDeviceVK::CreateCachedRenderPass(RenderPassCacheKey key) num_attachments++; } - const VkSubpassDescriptionFlags subpass_flags = + VkSubpassDescriptionFlags subpass_flags = (key.color_feedback_loop && m_optional_extensions.vk_ext_rasterization_order_attachment_access) ? VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_EXT : 0; + // Mobile ordered depth feedback: on the framebuffer_fetch path the depth self-dependency above + // is skipped, so declare ordered depth access here to make the in-tile subpassLoad of depth + // coherent (mirror of the colour flag). Gated on depth_feedback (HWROV) so it never fires when + // the toggle is off; the pipeline built for this pass sets the matching depth-stencil flag. + if (key.depth_sampling && m_features.depth_feedback && m_features.framebuffer_fetch && + m_optional_extensions.vk_ext_roaa_depth) + subpass_flags |= VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_EXT; const VkSubpassDescription subpass = {subpass_flags, VK_PIPELINE_BIND_POINT_GRAPHICS, num_subpass_inputs, num_subpass_inputs ? input_reference.data() : nullptr, color_reference_ptr ? 1u : 0u, color_reference_ptr ? color_reference_ptr : nullptr, nullptr, depth_reference_ptr, 0, nullptr}; @@ -3331,6 +3360,21 @@ bool GSDeviceVK::CheckFeatures() m_features.framebuffer_fetch = m_optional_extensions.vk_ext_rasterization_order_attachment_access; m_features.texture_barrier = true; } + // Mali r44p1: the attachment-feedback-loop-layout disable in CreateDevice only swapped the + // RT-as-texture LAYOUT/descriptor — it never removed the in-tile RT self-read itself, so Maximum + // blending kept sampling the colour attachment IN-TILE (fbfetch/ROAA subpassLoad OR the + // texture-barrier feedback loop; both lower to the same faulting tile-feedback silicon) and the + // device kept dying (VK_ERROR_DEVICE_LOST at vkWaitForFences, Rogue Galaxy). Force texture_barrier + // off so accurate blending routes through the RT-COPY path (draw_rt_clone) instead — the + // "fbfetch needs barriers" line below (framebuffer_fetch &= texture_barrier) then also turns + // fbfetch off, so the RT is only ever read from a SEPARATE copy, never in-tile. Slower but stable, + // and strictly r44p1-only (no other GPU, not even other Mali-G615 units, is touched). + if (is_mali_vk && m_optional_extensions.vk_khr_driver_properties && + std::string_view(m_device_driver_properties.driverInfo).find("r44p1") != std::string_view::npos) + { + Console.WriteLn("Mali r44p1: forcing RT-copy blend path (texture_barrier off) — in-tile self-read faults."); + m_features.texture_barrier = false; + } m_features.multidraw_fb_copy = false; m_features.broken_point_sampler = false; @@ -3443,13 +3487,24 @@ bool GSDeviceVK::CheckFeatures() m_features.line_expand = (m_device_features.wideLines && limits.lineWidthRange[0] <= f_upscale && limits.lineWidthRange[1] >= f_upscale); - // Same class of issue as framebuffer_fetch above: the upstream-sync SW-Z - // depth feedback (depth bound as input attachment + shader depth test/write) - // is untested on the Android mobile GPUs and the pre-sync core never used it. - // Force it off on Android so the renderer takes the well-tested avoid/copy - // fallbacks (same as D3D11); desktop keeps canonical feedback-loop behavior. + // Mobile tile-native ordered depth feedback ("mobile ROV"), opt-in via HWROV. Reads the + // depth buffer in-tile (subpassLoad on a depth input attachment) instead of copying it to a + // colour RT (BeginDSAsRT), so SW-Z / DATE / alpha-test / AA1 depth passes fuse in-pass rather + // than round-tripping. It needs an ordered in-tile depth read: ROAA on the depth aspect on the + // framebuffer_fetch path (Mali-default / opt-in Adreno), or the render-pass self-dependency on + // the texture_barrier path. Gated behind HWROV so toggle-off is byte-for-byte the well-tested + // avoid/copy fallback (same as D3D11). Mali r44p1 excludes itself: texture_barrier is forced + // off for it above, so framebuffer_fetch is off and the ordered read is unavailable. + // Read at device init, so the depth half applies on game restart (HWROV's colour half is live). + // Desktop keeps canonical feedback-loop behaviour. #if defined(__ANDROID__) - m_features.depth_feedback = false; + const bool depth_feedback_ordered = + m_features.framebuffer_fetch ? m_optional_extensions.vk_ext_roaa_depth : m_features.texture_barrier; + m_features.depth_feedback = GSConfig.HWROV && m_features.feedback_loops() && depth_feedback_ordered; + Console.WriteLn("Mobile depth feedback (ROV): %s [HWROV=%s fbfetch=%s roaa_depth=%s texbarrier=%s]", + m_features.depth_feedback ? "ENABLED" : "disabled", GSConfig.HWROV ? "on" : "off", + m_features.framebuffer_fetch ? "yes" : "no", m_optional_extensions.vk_ext_roaa_depth ? "yes" : "no", + m_features.texture_barrier ? "yes" : "no"); #else m_features.depth_feedback = m_features.feedback_loops(); #endif @@ -6196,6 +6251,14 @@ VkPipeline GSDeviceVK::CreateTFXPipeline(const PipelineSelector& p) if (m_features.framebuffer_fetch && p.IsRTFeedbackLoop()) gpb.AddBlendFlags(VK_PIPELINE_COLOR_BLEND_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_BIT_EXT); + // Mobile ordered depth feedback: the render pass declares ordered depth access (subpass flag + // above) whenever depth is sampled on the fbfetch path with the toggle on — the pipeline bound + // in that pass must carry the matching depth-stencil rasterization-order flag or it is invalid. + // Condition mirrors the subpass flag exactly (key.depth_sampling == p.IsTestingAndSamplingDepth()). + if (m_features.depth_feedback && m_features.framebuffer_fetch && p.IsTestingAndSamplingDepth() && + m_optional_extensions.vk_ext_roaa_depth) + gpb.AddDepthStencilFlags(VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_EXT); + VkPipeline pipeline = gpb.Create(m_device, g_vulkan_shader_cache->GetPipelineCache(true)); if (pipeline) { diff --git a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h index 749f163ebb..ae07bbc915 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h +++ b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h @@ -39,6 +39,7 @@ public: bool vk_ext_memory_budget : 1; bool vk_ext_calibrated_timestamps : 1; bool vk_ext_rasterization_order_attachment_access : 1; + bool vk_ext_roaa_depth : 1; ///< ROAA depth sub-feature (rasterizationOrderDepthAttachmentAccess); optional, often absent when color ROAA is present. bool vk_ext_full_screen_exclusive : 1; bool vk_ext_line_rasterization : 1; bool vk_swapchain_maintenance1 : 1; diff --git a/pcsx2/GS/Renderers/Vulkan/VKBuilders.cpp b/pcsx2/GS/Renderers/Vulkan/VKBuilders.cpp index 7a10842f35..b3327dc44f 100644 --- a/pcsx2/GS/Renderers/Vulkan/VKBuilders.cpp +++ b/pcsx2/GS/Renderers/Vulkan/VKBuilders.cpp @@ -505,6 +505,11 @@ void Vulkan::GraphicsPipelineBuilder::AddBlendFlags(u32 flags) m_blend_state.flags |= flags; } +void Vulkan::GraphicsPipelineBuilder::AddDepthStencilFlags(u32 flags) +{ + m_depth_state.flags |= flags; +} + void Vulkan::GraphicsPipelineBuilder::SetBlendFlags(u32 flags) { m_blend_state.flags = flags; diff --git a/pcsx2/GS/Renderers/Vulkan/VKBuilders.h b/pcsx2/GS/Renderers/Vulkan/VKBuilders.h index 04f6ce838f..fafae1c7f0 100644 --- a/pcsx2/GS/Renderers/Vulkan/VKBuilders.h +++ b/pcsx2/GS/Renderers/Vulkan/VKBuilders.h @@ -124,6 +124,7 @@ namespace Vulkan VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT); void AddBlendFlags(u32 flags); void SetBlendFlags(u32 flags); + void AddDepthStencilFlags(u32 flags); void ClearBlendAttachments(); void SetBlendConstants(float r, float g, float b, float a); diff --git a/pcsx2/Host.cpp b/pcsx2/Host.cpp index a0d39292c8..f3558b1fa0 100644 --- a/pcsx2/Host.cpp +++ b/pcsx2/Host.cpp @@ -20,6 +20,13 @@ #include #include +#if defined(__APPLE__) +#include +#if TARGET_OS_IPHONE +#include +#endif +#endif + namespace Host { static std::pair LookupTranslationString( @@ -155,14 +162,49 @@ void Host::ReportFormattedErrorAsync(const std::string_view title, const char* f ReportErrorAsync(title, message); } +// The RetroAchievements client versions are injected from a gitignored header +// (ra_ua_secret.h) so the exact strings RA pins are not present in public source — +// third parties were spoofing our clients by copying the User-Agent verbatim. A fork or +// code-lift without the secret gets a stock UA that RA treats as unknown (no hardcore). +#if defined(__has_include) +# if __has_include("ra_ua_secret.h") +# include "ra_ua_secret.h" +# endif +#endif + +#if defined(__APPLE__) && TARGET_OS_IPHONE +// Human-readable iOS version for the RA User-Agent detail (e.g. "iOS 17.5"). +static std::string GetIOSVersionForUserAgent() +{ + char version[64] = {}; + size_t version_len = sizeof(version); + if (sysctlbyname("kern.osproductversion", version, &version_len, nullptr, 0) == 0 && version[0] != '\0') + return fmt::format("iOS {}", version); + + return Host::GetOSVersionString(); +} +#endif + std::string Host::GetHTTPUserAgent() { - // RetroAchievements identifies the client by the leading Name/Version token of - // this User-Agent, so report ARMSX2 with the stable dotted version the RA server - // has registered/pinned (matches the refresh-experimental Android build). A - // "PCSX2 " UA is rejected as an outdated/unknown emulator, which disables - // hardcore unlocks ("Warning: Outdated Emulator"). - return fmt::format("ARMSX2/2.7.407.0 ({})", GetOSVersionString()); + // RetroAchievements identifies the client by the leading Name/Version token of this + // User-Agent. iOS ships the ARMSX2-iOS client, everything else the ARMSX2 client; the + // version comes from the gitignored ra_ua_secret.h. A build without the secret sends a + // token RA doesn't recognise (no hardcore) rather than leaking a real, still-valid one. +#if defined(__APPLE__) && TARGET_OS_IPHONE +#if defined(ARMSX2_IOS_RA_UA_VERSION) + const char* core_version = (BuildVersion::GitTag && BuildVersion::GitTag[0]) ? BuildVersion::GitTag : BuildVersion::GitRev; + return fmt::format("ARMSX2-iOS/v" ARMSX2_IOS_RA_UA_VERSION " ({}) pcsx2/{}", GetIOSVersionForUserAgent(), core_version); +#else + return fmt::format("PCSX2 {} ({})", BuildVersion::GitRev, GetOSVersionString()); +#endif +#else +#if defined(ARMSX2_RA_UA_VERSION) + return fmt::format("ARMSX2/" ARMSX2_RA_UA_VERSION " ({})", GetOSVersionString()); +#else + return fmt::format("PCSX2-community ({})", GetOSVersionString()); +#endif +#endif } std::unique_lock Host::GetSettingsLock() diff --git a/pcsx2/MTGS.cpp b/pcsx2/MTGS.cpp index 98b453cf79..0e60d3ee30 100644 --- a/pcsx2/MTGS.cpp +++ b/pcsx2/MTGS.cpp @@ -7,6 +7,7 @@ #include "MTVU.h" #include "Host.h" #include "IconsFontAwesome.h" +#include "PerformanceMetrics.h" #include "VMManager.h" #include "common/FPControl.h" @@ -144,6 +145,7 @@ void MTGS::ShutdownThread() void MTGS::ThreadEntryPoint() { Threading::SetNameOfCurrentThread("GS"); + PerformanceMetrics::AdpfRegisterCallingThread(); // ADPF: hint the GS thread's core (Android) // GS can hit SMC write traps when executing InitAndReadFIFO // As racey as it sounds, it should be safe, since InitAndReadFIFO is requested and immediately waited for, diff --git a/pcsx2/MTVU.cpp b/pcsx2/MTVU.cpp index 797b3fb8cf..a4c501a8c1 100644 --- a/pcsx2/MTVU.cpp +++ b/pcsx2/MTVU.cpp @@ -4,6 +4,7 @@ #include "Common.h" #include "Gif_Unit.h" #include "MTVU.h" +#include "PerformanceMetrics.h" #include "VMManager.h" #include "Vif_Dynarec.h" @@ -128,6 +129,7 @@ void VU_Thread::Reset() void VU_Thread::ExecuteRingBuffer() { Threading::SetNameOfCurrentThread("MTVU"); + PerformanceMetrics::AdpfRegisterCallingThread(); // ADPF: MTVU is often the limiting CPU thread (Android) for (;;) { diff --git a/pcsx2/PerformanceMetrics.cpp b/pcsx2/PerformanceMetrics.cpp index 41d24483ba..0bd1df6dd2 100644 --- a/pcsx2/PerformanceMetrics.cpp +++ b/pcsx2/PerformanceMetrics.cpp @@ -16,6 +16,16 @@ #include "MTVU.h" #include "VMManager.h" +#if defined(__ANDROID__) +#include +#include +#include +#include +#include +#include +#include +#endif + static const float UPDATE_INTERVAL = 0.5f; static float s_fps = 0.0f; @@ -55,6 +65,103 @@ static u64 s_last_vu_time = 0; static u64 s_last_capture_time = 0; static u64 s_last_ticks = 0; +#if defined(__ANDROID__) +// ---- Android ADPF (PerformanceHintManager) --------------------------------- +// Tells the OS "these threads produce a frame every N ns, clock them to hit it." +// PS2 emulation is bursty and latency-sensitive, so Android's DVFS governor +// routinely under-clocks the CPU/GPU under it; ADPF is the purpose-built fix. +// Symbols are resolved at runtime from libandroid.so so the app still loads on +// pre-API-33 devices (there the session is never created — everything no-ops). +struct AdpfApi +{ + void* (*getManager)() = nullptr; + void* (*createSession)(void*, const int32_t*, size_t, int64_t) = nullptr; + int (*updateTarget)(void*, int64_t) = nullptr; + int (*reportActual)(void*, int64_t) = nullptr; + void (*closeSession)(void*) = nullptr; + bool tried = false; + + bool Available() + { + if (!tried) + { + tried = true; + if (void* lib = dlopen("libandroid.so", RTLD_NOW | RTLD_LOCAL)) + { + getManager = reinterpret_cast(dlsym(lib, "APerformanceHint_getManager")); + createSession = reinterpret_cast(dlsym(lib, "APerformanceHint_createSession")); + updateTarget = reinterpret_cast(dlsym(lib, "APerformanceHint_updateTargetWorkDuration")); + reportActual = reinterpret_cast(dlsym(lib, "APerformanceHint_reportActualWorkDuration")); + closeSession = reinterpret_cast(dlsym(lib, "APerformanceHint_closeSession")); + } + } + return getManager && createSession && updateTarget && reportActual && closeSession; + } +}; + +static std::mutex s_adpf_mutex; +static AdpfApi s_adpf; +static std::vector s_adpf_tids; +static void* s_adpf_manager = nullptr; +static void* s_adpf_session = nullptr; +static bool s_adpf_enabled = false; // experimental, opt-in +static bool s_adpf_create_failed = false; +static bool s_adpf_report_warned = false; +static bool s_adpf_paused = false; // reporting suspended (unlimited/vsync/interrupted), edge-logged +static int64_t s_adpf_target_ns = 0; +static Common::Timer::Value s_adpf_work_start = 0; // start of the current active-work period (0 = none) + +// The frame deadline in ns: emulated refresh scaled by the limiter's target speed, so turbo / +// slow-motion move the deadline correctly. Returns 0 when there is no finite deadline (Unlimited, +// GetTargetSpeed()==0), so the caller pauses ADPF rather than feeding a bogus/inf target. +static int64_t AdpfTargetNs() +{ + const double fps = VMManager::GetFrameRate() * static_cast(VMManager::GetTargetSpeed()); + return (fps > 1.0) ? static_cast(1.0e9 / fps) : 0; +} + +// Must hold s_adpf_mutex. Creates the session once a perf thread has registered and a finite +// deadline exists, and LOGS the real outcome — so "ACTIVE" means a session genuinely exists, +// not merely that the user flipped the toggle. +static void AdpfEnsureSession() +{ + if (s_adpf_session || s_adpf_create_failed || !s_adpf_enabled || s_adpf_tids.empty()) + return; + if (!s_adpf.Available()) + { + s_adpf_create_failed = true; // pre-API-33 / no libandroid; stop retrying + Console.WriteLn("ADPF: PerformanceHintManager symbols unavailable (needs Android 13+) — clock hint inactive."); + return; + } + if (!s_adpf_manager) + s_adpf_manager = s_adpf.getManager(); + if (!s_adpf_manager) + { + s_adpf_create_failed = true; + Console.WriteLn("ADPF: getManager() returned null — clock hint inactive."); + return; + } + const int64_t target = AdpfTargetNs(); + if (target <= 0) + return; // no finite deadline yet (Unlimited / VM not paced); retry once one exists + s_adpf_session = s_adpf.createSession(s_adpf_manager, s_adpf_tids.data(), s_adpf_tids.size(), target); + if (!s_adpf_session) + { + s_adpf_create_failed = true; + Console.Warning("ADPF: createSession() over %zu threads failed — clock hint inactive.", s_adpf_tids.size()); + return; + } + s_adpf_target_ns = target; + s_adpf_report_warned = false; + s_adpf_paused = false; + std::string tid_list; + for (size_t i = 0; i < s_adpf_tids.size(); i++) + tid_list += (i ? "," : "") + std::to_string(s_adpf_tids[i]); + Console.WriteLn("ADPF: session ACTIVE over %zu threads [tids %s], deadline %.2f ms.", s_adpf_tids.size(), + tid_list.c_str(), static_cast(target) / 1.0e6); +} +#endif // __ANDROID__ + static double s_cpu_thread_usage = 0.0f; static double s_cpu_thread_time = 0.0f; static float s_gs_thread_usage = 0.0f; @@ -290,6 +397,127 @@ void PerformanceMetrics::SetCPUThread(Threading::ThreadHandle thread) s_cpu_thread_handle = std::move(thread); } +void PerformanceMetrics::AdpfRegisterCallingThread() +{ +#if defined(__ANDROID__) + const int32_t tid = static_cast(syscall(SYS_gettid)); + std::lock_guard lock(s_adpf_mutex); + if (std::find(s_adpf_tids.begin(), s_adpf_tids.end(), tid) != s_adpf_tids.end()) + return; + s_adpf_tids.push_back(tid); + // The session's thread list is fixed at creation, so a newly-registered thread + // means the current session is missing it — drop it and let the next frame + // recreate it over the full set. + if (s_adpf_session) + { + s_adpf.closeSession(s_adpf_session); + s_adpf_session = nullptr; + } + s_adpf_create_failed = false; +#endif +} + +void PerformanceMetrics::AdpfSetEnabled(bool enabled) +{ +#if defined(__ANDROID__) + std::lock_guard lock(s_adpf_mutex); + if (s_adpf_enabled == enabled) + return; + s_adpf_enabled = enabled; + if (!enabled && s_adpf_session) + { + s_adpf.closeSession(s_adpf_session); + s_adpf_session = nullptr; + } + if (enabled) + s_adpf_create_failed = false; // allow the next frame to recreate +#else + (void)enabled; +#endif +} + +void PerformanceMetrics::AdpfShutdown() +{ +#if defined(__ANDROID__) + std::lock_guard lock(s_adpf_mutex); + if (s_adpf_session) + { + s_adpf.closeSession(s_adpf_session); + s_adpf_session = nullptr; + } + s_adpf_tids.clear(); + s_adpf_create_failed = false; + s_adpf_work_start = 0; +#endif +} + +void PerformanceMetrics::AdpfOnFrameWorkComplete() +{ +#if defined(__ANDROID__) + // Sampled at Throttle() entry — the instant the frame's active CPU work finished, before the + // limiter sleep — so (now - work_start) excludes the deliberate limiter sleep. It is NOT pure + // CPU compute: the EE can still block behind a full MTGS queue that is itself stalled on + // presentation, so some present-wait can leak in. Acceptable for a first experiment, and a far + // better approximation of ADPF's "last workload cycle" than the present interval. + const Common::Timer::Value now = Common::Timer::GetCurrentValue(); + std::lock_guard lock(s_adpf_mutex); + if (!s_adpf_enabled) + return; + AdpfEnsureSession(); + if (!s_adpf_session || s_adpf_work_start == 0) + return; + const int64_t target = AdpfTargetNs(); + if (target > 0 && target != s_adpf_target_ns) + { + s_adpf.updateTarget(s_adpf_session, target); + s_adpf_target_ns = target; + } + const int64_t work_ns = static_cast(Common::Timer::ConvertValueToSeconds(now - s_adpf_work_start) * 1.0e9); + // Drop absurd outliers (savestate load, renderer recreation, debugger stall): a period several + // times the deadline is not a real frame and would spam a spurious max-frequency demand. + if (work_ns <= 0 || (s_adpf_target_ns > 0 && work_ns > s_adpf_target_ns * 4)) + return; + if (s_adpf_paused) + { + Console.WriteLn("ADPF: reporting resumed."); + s_adpf_paused = false; + } + const int ret = s_adpf.reportActual(s_adpf_session, work_ns); + if (ret != 0 && !s_adpf_report_warned) + { + s_adpf_report_warned = true; + Console.Warning("ADPF: reportActualWorkDuration returned %d — driver is ignoring the hint.", ret); + } +#endif +} + +void PerformanceMetrics::AdpfBeginFrameWork() +{ +#if defined(__ANDROID__) + // Opens a work period at the post-sleep instant (Throttle exit), so the deliberate limiter + // sleep is excluded from the next reported duration. + const Common::Timer::Value now = Common::Timer::GetCurrentValue(); + std::lock_guard lock(s_adpf_mutex); + s_adpf_work_start = now; +#endif +} + +void PerformanceMetrics::AdpfPauseFrameWork() +{ +#if defined(__ANDROID__) + // Not frame-limiting (unlimited / host-vsync / interrupted) — invalidate the period so no + // wall-time-with-wait duration is reported, and edge-log so a tester never sees "ACTIVE" while + // nothing is actually being submitted. + std::lock_guard lock(s_adpf_mutex); + if (s_adpf_session && !s_adpf_paused) + { + Console.WriteLn("ADPF: reporting paused (unlimited / host-vsync / interrupted) — no durations submitted."); + s_adpf_paused = true; + } + s_adpf_work_start = 0; +#endif +} + void PerformanceMetrics::SetGSSWThreadCount(u32 count) { s_gs_sw_threads.clear(); diff --git a/pcsx2/PerformanceMetrics.h b/pcsx2/PerformanceMetrics.h index db400e432b..ca833b0c29 100644 --- a/pcsx2/PerformanceMetrics.h +++ b/pcsx2/PerformanceMetrics.h @@ -27,6 +27,27 @@ namespace PerformanceMetrics /// wall time). Called at VM shutdown so every -logfile run records it. void LogSessionSummary(); + /// Android ADPF (PerformanceHintManager): register the calling thread as perf-critical + /// so the OS ramps its CPU/GPU clocks toward the frame deadline instead of leaving them + /// low under emulation's bursty load. Called on the EE (CPU), GS and MTVU threads. + /// No-op on non-Android and below API 33 (symbols resolved via dlsym). + void AdpfRegisterCallingThread(); + /// Enable/disable ADPF hinting at runtime (settings toggle). Default OFF (experimental). + void AdpfSetEnabled(bool enabled); + /// Close the ADPF session and forget registered threads (VM shutdown). + void AdpfShutdown(); + + /// ADPF work-period brackets, driven by the frame limiter (VMManager::Internal::Throttle). + /// The reported duration must be the active EE/GS/VU work per frame, EXCLUDING the deliberate + /// limiter sleep and present wait, per the PerformanceHintManager contract (reportActualWork + /// = the last workload cycle, not the frame interval). OnFrameWorkComplete() reports the + /// period that just ended (called at Throttle entry, before the sleep); BeginFrameWork() + /// opens a new period after the sleep; PauseFrameWork() invalidates it when we are not + /// frame-limiting (unlimited / host-vsync pacing), so no bogus duration is reported. + void AdpfOnFrameWorkComplete(); + void AdpfBeginFrameWork(); + void AdpfPauseFrameWork(); + /// Sets the EE thread for CPU usage calculations. void SetCPUThread(Threading::ThreadHandle thread); diff --git a/pcsx2/VMManager.cpp b/pcsx2/VMManager.cpp index fc53b51f22..880517312e 100644 --- a/pcsx2/VMManager.cpp +++ b/pcsx2/VMManager.cpp @@ -382,6 +382,7 @@ bool VMManager::Internal::CPUThreadInitialize() { Threading::SetNameOfCurrentThread("CPU Thread"); PerformanceMetrics::SetCPUThread(Threading::ThreadHandle::GetForCallingThread()); + PerformanceMetrics::AdpfRegisterCallingThread(); // ADPF: hint the EE thread's core (Android) // On Win32, we have a bunch of things which use COM (e.g. SDL, XAudio2, etc). // We need to initialize COM first, before anything else does, because otherwise they might @@ -460,6 +461,7 @@ void VMManager::Internal::CPUThreadShutdown() WaitForSaveStateFlush(); PerformanceMetrics::SetCPUThread(Threading::ThreadHandle()); + PerformanceMetrics::AdpfShutdown(); // ADPF: close the hint session on VM shutdown (Android) USBshutdown(); @@ -2334,7 +2336,18 @@ void VMManager::ResetFrameLimiter() void VMManager::Internal::Throttle() { if (s_target_speed == 0.0f || s_use_vsync_for_timing) + { + // Not frame-limiting this frame (unlimited / host-vsync pacing): invalidate the ADPF work + // period so no wall-time-with-wait duration is submitted. + PerformanceMetrics::AdpfPauseFrameWork(); return; + } + + // ADPF: report the active-work period that just ended (before the limiter sleep below), then + // re-open a new period AFTER the sleep. The ScopedGuard fires on EVERY exit past here — + // including the missed-frame early return — so measurement survives the can't-hit-target case. + PerformanceMetrics::AdpfOnFrameWorkComplete(); + ScopedGuard adpf_begin_next_work([]() { PerformanceMetrics::AdpfBeginFrameWork(); }); const u64 uExpectedEnd = s_limiter_frame_start + diff --git a/platforms/android/app/src/main/assets/i18n/zh-CN.json b/platforms/android/app/src/main/assets/i18n/zh-CN.json index 5f0470c207..a9873b294a 100644 --- a/platforms/android/app/src/main/assets/i18n/zh-CN.json +++ b/platforms/android/app/src/main/assets/i18n/zh-CN.json @@ -171,6 +171,8 @@ "fixes.opt.upper": "上部", "fixes.optimalFramePacing.desc": "以零排队帧运行 GS 线程,获得最紧凑的帧调度和最低输入延迟(与 PCSX2 一致)。若较弱设备用小帧队列更平滑,可关闭。", "fixes.optimalFramePacing.label": "最佳帧调度", + "perf.lowLatencyMode.label": "低延迟模式", + "perf.lowLatencyMode.description": "使用零帧 GS 队列,并请求与游戏帧率匹配的高刷新率显示模式,降低实体手柄到画面的延迟。推荐中高端掌机开启;如果较弱设备出现不流畅,请关闭。", "fixes.overrideTextureBarriers.desc": "强制开/关渲染器的纹理屏障支持。推荐 Auto。", "fixes.overrideTextureBarriers.label": "覆盖纹理屏障", "fixes.preloadFrameData.desc": "在绘制前上传上一帧数据。修复部分效果。", diff --git a/platforms/android/app/src/main/assets/i18n/zh-TW.json b/platforms/android/app/src/main/assets/i18n/zh-TW.json index 88030152d9..6ed5edc037 100644 --- a/platforms/android/app/src/main/assets/i18n/zh-TW.json +++ b/platforms/android/app/src/main/assets/i18n/zh-TW.json @@ -171,6 +171,8 @@ "fixes.opt.upper": "較高", "fixes.optimalFramePacing.desc": "以零排隊影格執行 GS 執行緒,取得最緊湊的影格節奏與最低輸入延遲 (符合 PCSX2)。若較弱裝置搭配小影格佇列更順暢,請關閉。", "fixes.optimalFramePacing.label": "最佳影格節奏", + "perf.lowLatencyMode.label": "低延遲模式", + "perf.lowLatencyMode.description": "使用零影格 GS 佇列,並要求與遊戲影格率匹配的高更新率顯示模式,降低實體控制器到畫面的延遲。建議中高階掌機開啟;若較弱裝置變得不順暢,請關閉。", "fixes.overrideTextureBarriers.desc": "強制開/關渲染器的 texture-barrier 支援。建議使用 Auto。", "fixes.overrideTextureBarriers.label": "覆寫 Texture Barriers", "fixes.preloadFrameData.desc": "在繪製前上傳前一影格的資料。修正部分效果。", diff --git a/platforms/android/app/src/main/cpp/native-lib.cpp b/platforms/android/app/src/main/cpp/native-lib.cpp index 9a9adc9fcd..b45a49f6a4 100644 --- a/platforms/android/app/src/main/cpp/native-lib.cpp +++ b/platforms/android/app/src/main/cpp/native-lib.cpp @@ -230,6 +230,19 @@ Java_kr_co_iefriends_pcsx2_NativeApp_setEeDiffVerify(JNIEnv*, jclass, jboolean e Cpu->Reset(); } +// ADPF (PerformanceHintManager): hint the OS scheduler to raise the EE/GS/MTVU threads' CPU +// frequency toward the frame deadline instead of the DVFS governor under-clocking emulation's +// bursty load. Basic API-33 path — CPU scheduling only, no explicit GPU timing. Applies live; +// no-op below API 33 (symbols dlsym'd from libandroid.so). This only records the user's request: +// whether a session actually exists is logged from PerformanceMetrics when a game runs. +extern "C" +JNIEXPORT void JNICALL +Java_kr_co_iefriends_pcsx2_NativeApp_setAdpfEnabled(JNIEnv*, jclass, jboolean enabled) { + PerformanceMetrics::AdpfSetEnabled(enabled == JNI_TRUE); + Console.WriteLnFmt("ADPF hint {} by user (session state logged separately when a game runs)", + enabled == JNI_TRUE ? "requested" : "disabled"); +} + extern "C" JNIEXPORT void JNICALL Java_kr_co_iefriends_pcsx2_NativeApp_emulog(JNIEnv *env, jclass, jstring p_msg) { @@ -782,6 +795,12 @@ Java_kr_co_iefriends_pcsx2_NativeApp_getFPS(JNIEnv *env, jclass clazz) { return (jfloat)PerformanceMetrics::GetFPS(); } +extern "C" +JNIEXPORT jfloat JNICALL +Java_kr_co_iefriends_pcsx2_NativeApp_getNominalFrameRate(JNIEnv*, jclass) { + return VMManager::HasValidVM() ? static_cast(VMManager::GetFrameRate()) : 0.0f; +} + extern "C" JNIEXPORT jstring JNICALL Java_kr_co_iefriends_pcsx2_NativeApp_getPauseGameTitle(JNIEnv *env, jclass clazz) { @@ -1855,6 +1874,16 @@ Java_kr_co_iefriends_pcsx2_NativeApp_renderOpenGL(JNIEnv *env, jclass clazz) { } } +// Android renderer Auto steering: g_gs_android_prefer_vk (GSUtil.cpp) makes GetPreferredRenderer's +// Auto resolution pick Vulkan HW on Adreno instead of OpenGL. The app sets it from GL_RENDERER +// before the GS starts — a plain global (no settings interface), so it's safe to set at startup. +extern bool g_gs_android_prefer_vk; +extern "C" +JNIEXPORT void JNICALL +Java_kr_co_iefriends_pcsx2_NativeApp_setPreferVulkan(JNIEnv*, jclass, jboolean enabled) { + g_gs_android_prefer_vk = (enabled == JNI_TRUE); +} + extern "C" JNIEXPORT void JNICALL Java_kr_co_iefriends_pcsx2_NativeApp_renderVulkan(JNIEnv *env, jclass clazz) { diff --git a/platforms/android/app/src/main/java/com/armsx2/MenuSfx.kt b/platforms/android/app/src/main/java/com/armsx2/MenuSfx.kt index 9fc031f819..56d49d2c1b 100644 --- a/platforms/android/app/src/main/java/com/armsx2/MenuSfx.kt +++ b/platforms/android/app/src/main/java/com/armsx2/MenuSfx.kt @@ -39,8 +39,8 @@ object MenuSfx { /** UI events a sound binds to. [fileName] is the base name to use when importing a custom pack * (case- and extension-insensitive); [defaultRes] is the bundled fallback clip. */ - enum class Event(val fileName: String, val defaultRes: Int) { - NAV("nav", R.raw.sfx_cursor), // controller moves the selection highlight + enum class Event(val fileName: String, val defaultRes: Int, val altRes: Int = 0) { + NAV("nav", R.raw.sfx_nav_a, R.raw.sfx_nav_b), // alternates two soft ticks as the highlight moves SELECT("select", R.raw.sfx_select), // confirm / launch a game SUBMENU("submenu", R.raw.sfx_submenu), // open a settings menu / sub-screen MENU_OPEN("menu", R.raw.sfx_menu), // open the in-game pause menu @@ -48,9 +48,11 @@ object MenuSfx { TOGGLE_ON("toggle_on", R.raw.sfx_toggle_on), TOGGLE_OFF("toggle_off", R.raw.sfx_toggle_off), RESET("reset", R.raw.sfx_reset), - SLIDER("slider", R.raw.sfx_cursor), // shares the cursor tick with NAV + SLIDER("slider", R.raw.sfx_nav_a, R.raw.sfx_nav_b), // shares the alternating nav ticks SLEEP("sleep", R.raw.sfx_sleep), // DS-lid-style chime when the device sleeps WAKE("wake", R.raw.sfx_wake), // chime when waking back to the app + POPUP_OPEN("popup_open", R.raw.sfx_popup_open), // a dialog/popup appears (hardcore confirm, info) + POPUP_CLOSE("popup_close", R.raw.sfx_popup_close), // ...and dismisses } /** On by default — the bundled sounds give the launcher its "personality" out of the box. */ @@ -64,6 +66,10 @@ object MenuSfx { private var pool: SoundPool? = null /** event -> loaded SoundPool sample id. */ private val sampleIds = HashMap() + /** Second sample for events with an [Event.altRes] (NAV/SLIDER): [play] alternates between + * this and the primary so a fast walk/drag varies the tick instead of machine-gunning one. */ + private val altSampleIds = HashMap() + private var navAlt = false /** Per-event last-play time, to throttle rapid emitters (a slider drag fires onChange many * times/second — without this it buzzes instead of ticking). */ private val lastPlayMs = HashMap() @@ -144,12 +150,17 @@ object MenuSfx { fun play(event: Event) { if (!enabled.value) return val p = pool ?: return - val id = sampleIds[event] ?: return val now = SystemClock.uptimeMillis() // NAV and SLIDER fire on every highlight move / value step — a longer floor keeps a fast // D-pad walk or drag ticking pleasantly instead of buzzing. val minGap = if (event == Event.SLIDER || event == Event.NAV) 45L else 18L if (now - (lastPlayMs[event] ?: 0L) < minGap) return + // Alternate the two loaded ticks for events that have a second sample (NAV/SLIDER); flip + // only when we actually play (post-throttle) so the alternation follows audible ticks. + val id = if (altSampleIds.containsKey(event)) { + navAlt = !navAlt + (if (navAlt) altSampleIds[event] else sampleIds[event]) ?: return + } else (sampleIds[event] ?: return) lastPlayMs[event] = now lastPlayedMs = now val g = gain() @@ -179,6 +190,9 @@ object MenuSfx { val id = if (custom.length() > 0L) sp.load(custom.absolutePath, 1) else sp.load(context, ev.defaultRes, 1) if (id != 0) sampleIds[ev] = id + // Second (alternating) sample: bundled-only. A custom "nav" import overrides the + // primary tick and alternates against this bundled hover tick. + if (ev.altRes != 0) sp.load(context, ev.altRes, 1).let { if (it != 0) altSampleIds[ev] = it } }.onFailure { Log.w(TAG, "load failed for ${ev.fileName}", it) } } pool = sp @@ -186,6 +200,7 @@ object MenuSfx { private fun releasePool() { sampleIds.clear() + altSampleIds.clear() lastPlayMs.clear() pool?.let { runCatching { it.release() } } pool = null diff --git a/platforms/android/app/src/main/java/com/armsx2/config/ConfigStore.kt b/platforms/android/app/src/main/java/com/armsx2/config/ConfigStore.kt index b44000a78b..ec8d021e90 100644 --- a/platforms/android/app/src/main/java/com/armsx2/config/ConfigStore.kt +++ b/platforms/android/app/src/main/java/com/armsx2/config/ConfigStore.kt @@ -177,6 +177,35 @@ object ConfigStore { writeBackupMirror() } + /** + * Persist capability-aware defaults only when this is genuinely a fresh install. + * + * Call after [reconcileReusedFolder]: a reused data directory gets first chance to + * restore its prior global settings, while an empty install starts with the + * zero-frame GS queue on capable devices. Low-end devices retain the smoother + * two-frame queue. Once persisted, this never changes an existing user's choice. + */ + fun seedFreshInstallDefaults(context: android.content.Context) { + if (MainActivityRuntime.prefs.getString(KEY_GLOBAL, null) != null) return + val queueSize = if (com.armsx2.DeviceTier.isLowEnd(context)) 2 else 0 + saveGlobal(Settings(vsyncQueueSize = queueSize)) + } + + private const val KEY_LOWLATENCY_MIGRATED = "config.migrated.lowLatencyDefault" + /** + * One-time flip of EXISTING capable installs to Low Latency (zero-frame GS queue), matching the + * fresh-install default seeded above. Flagged so it runs exactly once — a user who later turns it + * off keeps that choice. Low-end devices keep the smoother two-frame queue. + */ + fun migrateLowLatencyDefault(context: android.content.Context) { + if (MainActivityRuntime.prefs.getBoolean(KEY_LOWLATENCY_MIGRATED, false)) return + MainActivityRuntime.prefs.edit().putBoolean(KEY_LOWLATENCY_MIGRATED, true).apply() + // Fresh installs are handled by seedFreshInstallDefaults; only touch an existing global save. + if (MainActivityRuntime.prefs.getString(KEY_GLOBAL, null) == null || com.armsx2.DeviceTier.isLowEnd(context)) return + val g = loadGlobal() + if (g.vsyncQueueSize != 0) saveGlobal(g.copy(vsyncQueueSize = 0)) + } + /** Load the sparse per-game override blob, or null if there are none. */ fun loadOverrides(serial: String): JSONObject? { val raw = MainActivityRuntime.prefs.getString(keyForGame(serial), null) ?: return null diff --git a/platforms/android/app/src/main/java/com/armsx2/i18n/I18n.kt b/platforms/android/app/src/main/java/com/armsx2/i18n/I18n.kt index d73d95f52a..bb723ba271 100644 --- a/platforms/android/app/src/main/java/com/armsx2/i18n/I18n.kt +++ b/platforms/android/app/src/main/java/com/armsx2/i18n/I18n.kt @@ -1006,10 +1006,14 @@ val EN: Map = mapOf( "perf.speedhackProfile.help" to "Tap a preset. Optimal = safe for most games. Fast = aggressive speedhacks + native resolution for low-end devices; may glitch some. Low-End = Fast plus every cheap GPU lever (native res, min blending, no mipmaps/palette-conv, partial texture preload) with MTVU auto-set from your CPU. Tweaking any setting un-highlights the presets (custom).", "perf.speedhackProfile.label" to "Speedhack Profile", "perf.speedhackProfile.lowEnd" to "Low-End", + "perf.lowLatencyMode.label" to "Low Latency Mode", + "perf.lowLatencyMode.description" to "Uses a zero-frame GS queue and requests a matching high-refresh display mode to reduce controller-to-screen latency. Recommended on mid/high-end handhelds. Turn off if a weaker device becomes less smooth.", "perf.speedhackProfile.optimal" to "Optimal", "perf.speedhacks.title" to "Speedhacks", "perf.sustainedPerformance.description" to "Holds a steady, thermally-sustainable GPU/CPU clock for long play sessions — reduces mid-session throttling, heat and battery drain on handhelds. Trade-off: it caps the peak clock, so demanding games that rely on short bursts of max speed may run a little slower. Off = full peak clocks (default).", "perf.sustainedPerformance.label" to "Sustained Performance", + "perf.adpf.description" to "EXPERIMENTAL, off by default. Reports each frame's active CPU work to Android's performance-hint system (ADPF) so the scheduler can raise the emulation threads' CPU frequency toward the frame deadline, countering the governor under-clocking emulation's bursty load. Helps most when a game can't quite hit full speed and is CPU-bound. This basic path hints CPU scheduling only — no explicit GPU timing — and the measured work can still include a stall behind the GS/present queue. May raise power draw and heat; gains vary by device (needs Android 13+) and can be zero if your governor is already aggressive. Measure with your own A/B before trusting it.", + "perf.adpf.label" to "CPU clock hint (ADPF)", "perf.vu0RoundMode.description" to "VU0 float rounding. Chop is the PS2 default. Restart the game to apply.", "perf.vu0RoundMode.label" to "VU0 Round Mode", "perf.vu1RoundMode.description" to "VU1 float rounding. Chop is the PS2 default. Restart the game to apply.", @@ -1156,7 +1160,7 @@ val EN: Map = mapOf( "renderer.orientation.portrait" to "Portrait", "renderer.precacheTexturePacks.description" to "Scans replacements at boot. Slower startup, fewer in-game hitches.", "renderer.precacheTexturePacks.label" to "Precache Texture Packs", - "renderer.rov.description" to "Vulkan only: accurate blending via fragment-shader interlock. Mainly benefits desktop GPUs — most mobile GPUs either lack the required interlock (e.g. Turnip) or run it slower than the default blending path. Leave off unless your own benchmarks show a gain. No effect on OpenGL. Applies live.", + "renderer.rov.description" to "Vulkan only. On mobile GPUs this enables tile-native ordered depth feedback: the renderer reads the depth buffer in-tile instead of copying it out, so depth-writing alpha-test passes fold into one pass and depth-feedback draws keep hardware blending. Needs a driver that advertises ordered depth access (many don't — then it has no effect). Off = the well-tested depth-copy path, so nothing is lost. Restart the game to apply on mobile. No effect on OpenGL.", "renderer.rov.label" to "Rasterizer Ordered View (ROV)", "renderer.saturation.label" to "Saturation", "renderer.section.blendingAdvanced" to "Blending & Advanced", diff --git a/platforms/android/app/src/main/java/com/armsx2/input/ControllerMappings.kt b/platforms/android/app/src/main/java/com/armsx2/input/ControllerMappings.kt index 0791c27392..f8bcca996a 100644 --- a/platforms/android/app/src/main/java/com/armsx2/input/ControllerMappings.kt +++ b/platforms/android/app/src/main/java/com/armsx2/input/ControllerMappings.kt @@ -1,5 +1,6 @@ package com.armsx2.input +import android.content.SharedPreferences import android.view.KeyEvent import androidx.compose.runtime.mutableStateOf import com.armsx2.runtime.MainActivityRuntime @@ -230,10 +231,12 @@ object ControllerMappings { // longer sends digital d-pad presses in-game. Same Global/per-game scope as the // axis corrections above (it appears on the same per-game Pad screen). private const val KEY_DPAD_AS_LSTICK = "pad.dpadAsLeftStick" - fun dpadAsLeftStick(): Boolean = resolveBoolean(KEY_DPAD_AS_LSTICK, false) // runtime (per-game aware) + fun dpadAsLeftStick(): Boolean = runtimeBindings().dpadAsLeftStick // runtime (per-game aware) fun dpadAsLeftStickScope(serial: String?): Boolean = scopedBoolean(KEY_DPAD_AS_LSTICK, serial, false) - fun setDpadAsLeftStick(on: Boolean, serial: String? = null) = + fun setDpadAsLeftStick(on: Boolean, serial: String? = null) { MainActivityRuntime.prefs.edit { putBoolean(scopedKey(KEY_DPAD_AS_LSTICK, serial), on) } + invalidateRuntimeCaches() + } // ---- Analog stick response shaping (physical sticks → PS2 analog) ---- // Sensitivity = a linear output scale. Acceleration = an exponential response @@ -572,6 +575,7 @@ object ControllerMappings { ), physicalKeyCode ) } + invalidateRuntimeCaches() } /** Unbind a pad button: store KEYCODE_UNKNOWN — the same "unbound" sentinel the @@ -581,6 +585,7 @@ object ControllerMappings { * [serial], unbinds the button for that game only (per-game override). */ fun clearAction(action: Action, player: Int = 0, serial: String? = null) { MainActivityRuntime.prefs.edit().putInt(scopedKey(playerPrefix(player) + KEY_PREFIX + action.id, serial), KeyEvent.KEYCODE_UNKNOWN).apply() + invalidateRuntimeCaches() } /** Reset button binds for [player]. serial=null clears the GLOBAL binds; a @@ -589,6 +594,7 @@ object ControllerMappings { val edit = MainActivityRuntime.prefs.edit() actions.forEach { edit.remove(scopedKey(playerPrefix(player) + KEY_PREFIX + it.id, serial)) } edit.apply() + invalidateRuntimeCaches() } /** Clear ALL per-game controller overrides for [serial] / [player] — button @@ -604,6 +610,7 @@ object ControllerMappings { for (dir in StickDir.values()) edit.remove(gameKey(serial, customKey(left, dir, player))) edit.apply() + invalidateRuntimeCaches() stickBindTick.value++ } @@ -668,6 +675,7 @@ object ControllerMappings { } } edit.apply() + invalidateRuntimeCaches() stickBindTick.value++ } @@ -799,7 +807,7 @@ object ControllerMappings { // Unbound actions store KEYCODE_UNKNOWN; never let a stray UNKNOWN event match // one (it would otherwise map to the first unbound action's PS2 button). if (physicalKeyCode == KeyEvent.KEYCODE_UNKNOWN) return null - return actions.firstOrNull { physicalFor(it, player) == physicalKeyCode }?.targetKeyCode + return runtimeBindings().targets[if (player == P2) P2 else P1][physicalKeyCode] } // ---- Turbo / rapid-fire (per PS2 button, per player) ------------------- @@ -811,13 +819,14 @@ object ControllerMappings { private fun turboKey(action: Action, player: Int) = playerPrefix(player) + TURBO_PREFIX + action.id fun isTurboAction(action: Action, player: Int = 0): Boolean = MainActivityRuntime.prefs.getBoolean(turboKey(action, player), false) - fun setTurboAction(action: Action, player: Int, on: Boolean) = + fun setTurboAction(action: Action, player: Int, on: Boolean) { MainActivityRuntime.prefs.edit { putBoolean(turboKey(action, player), on) } + invalidateRuntimeCaches() + } /** True when a physical button's PS2 target [targetKeyCode] is turbo-flagged. */ fun isTurboTarget(targetKeyCode: Int, player: Int = 0): Boolean { - val action = actions.firstOrNull { it.targetKeyCode == targetKeyCode } ?: return false - return isTurboAction(action, player) + return targetKeyCode in runtimeBindings().turboTargets[if (player == P2) P2 else P1] } // ---- System hotkeys (menu / quick save / quick load) ----------------- @@ -873,6 +882,105 @@ object ControllerMappings { // pressed) under prefKey + MOD_SUFFIX. UNKNOWN modifier = single-button. private const val MOD_SUFFIX = ".mod" + private data class RuntimeHotkey( + val action: SysHotkey, + val keyCode: Int, + val modifierCode: Int, + ) + + /** + * Immutable snapshot used by the gameplay input path. Building it may read + * SharedPreferences, but key/motion events only perform map/set lookups. + * Slot 1 has P2 mappings; every other unified slot intentionally reuses P1. + */ + private data class RuntimeBindings( + val serial: String?, + val targets: Array>, + val turboTargets: Array>, + val hotkeys: List, + val dpadAsLeftStick: Boolean, + ) + + @Volatile private var runtimeBindingsCache: RuntimeBindings? = null + private var runtimeCacheListener: SharedPreferences.OnSharedPreferenceChangeListener? = null + + private fun buildRuntimeBindings(serial: String?): RuntimeBindings { + val targets = Array(2) { player -> + buildMap { + // Preserve actions.firstOrNull semantics when duplicate physical + // bindings exist: the first action in display order wins. + actions.forEach { action -> + val physical = physicalFor(action, player) + if (physical != KeyEvent.KEYCODE_UNKNOWN && !containsKey(physical)) + put(physical, action.targetKeyCode) + } + } + } + val turboTargets = Array(2) { player -> + actions.asSequence() + .filter { isTurboAction(it, player) } + .map { it.targetKeyCode } + .toSet() + } + val hotkeys = SysHotkey.values().map { action -> + RuntimeHotkey(action, hotkeyCode(action), hotkeyModCode(action)) + } + return RuntimeBindings( + serial, + targets, + turboTargets, + hotkeys, + resolveBoolean(KEY_DPAD_AS_LSTICK, false), + ) + } + + private fun runtimeBindings(): RuntimeBindings { + val serial = runtimeSerial() + runtimeBindingsCache?.takeIf { it.serial == serial }?.let { return it } + return synchronized(this) { + runtimeBindingsCache?.takeIf { it.serial == serial } + ?: buildRuntimeBindings(serial).also { runtimeBindingsCache = it } + } + } + + fun invalidateRuntimeCaches() { + runtimeBindingsCache = null + } + + /** Build the snapshot before gameplay so the first button press does no preference I/O. */ + fun warmRuntimeCaches() { + runtimeBindings() + com.armsx2.ui.touch.TouchControls.warmRuntimeMacroCache() + } + + /** + * Register once after MainActivityRuntime.prefs is initialized. Only binding + * keys invalidate the snapshot, so unrelated preferences such as play-time + * counters do not force rebuilds during gameplay. + */ + fun installRuntimeCacheInvalidation() { + if (runtimeCacheListener != null) return + val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, key -> + val changedKey = key ?: "" + val padMappingChanged = + changedKey.startsWith("pad.map.") || + changedKey.startsWith("p2.pad.map.") || + (changedKey.startsWith("game.") && changedKey.contains(".pad.map.")) || + changedKey.startsWith("pad.turbo.") || + changedKey.startsWith("p2.pad.turbo.") || + changedKey == KEY_DPAD_AS_LSTICK || + (changedKey.startsWith("game.") && changedKey.endsWith(".$KEY_DPAD_AS_LSTICK")) + val hotkeyChanged = SysHotkey.values().any { + changedKey == it.prefKey || changedKey == it.prefKey + MOD_SUFFIX + } + if (padMappingChanged || hotkeyChanged) invalidateRuntimeCaches() + if (changedKey.startsWith("touch.macro.")) + com.armsx2.ui.touch.TouchControls.invalidateRuntimeMacroCache() + } + runtimeCacheListener = listener + MainActivityRuntime.prefs.registerOnSharedPreferenceChangeListener(listener) + } + fun hotkeyCode(h: SysHotkey): Int = MainActivityRuntime.prefs.getInt(h.prefKey, KeyEvent.KEYCODE_UNKNOWN) @@ -886,6 +994,7 @@ object ControllerMappings { putInt(h.prefKey, physicalKeyCode) .putInt(h.prefKey + MOD_SUFFIX, KeyEvent.KEYCODE_UNKNOWN) } + invalidateRuntimeCaches() } /** Bind a two-button combo: [modCode] held + [keyCode] pressed. */ @@ -894,6 +1003,7 @@ object ControllerMappings { putInt(h.prefKey, keyCode) .putInt(h.prefKey + MOD_SUFFIX, modCode) } + invalidateRuntimeCaches() } fun clearHotkey(h: SysHotkey) { @@ -901,6 +1011,7 @@ object ControllerMappings { putInt(h.prefKey, KeyEvent.KEYCODE_UNKNOWN) .putInt(h.prefKey + MOD_SUFFIX, KeyEvent.KEYCODE_UNKNOWN) } + invalidateRuntimeCaches() } /** Clear ALL system hotkey bindings (the global "Reset to defaults"). Bumps @@ -912,6 +1023,7 @@ object ControllerMappings { .putInt(it.prefKey + MOD_SUFFIX, KeyEvent.KEYCODE_UNKNOWN) } } + invalidateRuntimeCaches() hotkeyBindTick.value++ } @@ -927,9 +1039,9 @@ object ControllerMappings { /** Single-button match (combos excluded). Used by the frontend MENU shortcut. */ fun hotkeyFor(physicalKeyCode: Int): SysHotkey? { if (physicalKeyCode == KeyEvent.KEYCODE_UNKNOWN) return null - return SysHotkey.values().firstOrNull { - hotkeyCode(it) == physicalKeyCode && hotkeyModCode(it) == KeyEvent.KEYCODE_UNKNOWN - } + return runtimeBindings().hotkeys.firstOrNull { + it.keyCode == physicalKeyCode && it.modifierCode == KeyEvent.KEYCODE_UNKNOWN + }?.action } /** Combo-aware match for the just-pressed [keyCode] given the set of @@ -938,16 +1050,31 @@ object ControllerMappings { * instead of a bare-R1 binding while Select is held. */ fun matchHotkey(keyCode: Int, heldKeys: Set): SysHotkey? { if (keyCode == KeyEvent.KEYCODE_UNKNOWN) return null - SysHotkey.values().firstOrNull { - hotkeyCode(it) == keyCode && - hotkeyModCode(it) != KeyEvent.KEYCODE_UNKNOWN && - heldKeys.contains(hotkeyModCode(it)) - }?.let { return it } - return SysHotkey.values().firstOrNull { - hotkeyCode(it) == keyCode && hotkeyModCode(it) == KeyEvent.KEYCODE_UNKNOWN - } + val bindings = runtimeBindings().hotkeys + bindings.firstOrNull { + it.keyCode == keyCode && + it.modifierCode != KeyEvent.KEYCODE_UNKNOWN && + heldKeys.contains(it.modifierCode) + }?.let { return it.action } + return bindings.firstOrNull { + it.keyCode == keyCode && it.modifierCode == KeyEvent.KEYCODE_UNKNOWN + }?.action } + /** True when [keyCode] participates in any hotkey as its main or modifier key. */ + fun isHotkeyKeyOrModifier(keyCode: Int): Boolean = + keyCode != KeyEvent.KEYCODE_UNKNOWN && + runtimeBindings().hotkeys.any { + it.keyCode == keyCode || it.modifierCode == keyCode + } + + fun matchesSingleHotkey(action: SysHotkey, keyCode: Int): Boolean = + runtimeBindings().hotkeys.any { + it.action == action && + it.keyCode == keyCode && + it.modifierCode == KeyEvent.KEYCODE_UNKNOWN + } + // True while the Pad tab is waiting for a button to bind. MainActivityRuntime.dispatchKeyEvent // checks this and lets EVERY key fall through to Compose's onPreviewKeyEvent so // any button — including B/A/Y/D-pad/L1/R1 the overlay nav would otherwise diff --git a/platforms/android/app/src/main/java/com/armsx2/runtime/EmulationSurface.kt b/platforms/android/app/src/main/java/com/armsx2/runtime/EmulationSurface.kt index b27d0c83bc..7e17e95b87 100644 --- a/platforms/android/app/src/main/java/com/armsx2/runtime/EmulationSurface.kt +++ b/platforms/android/app/src/main/java/com/armsx2/runtime/EmulationSurface.kt @@ -3,15 +3,38 @@ package com.armsx2.runtime import android.app.Activity import android.content.Context import android.content.ContextWrapper +import android.hardware.display.DisplayManager +import android.os.Build +import android.view.Display +import android.view.Surface import android.view.SurfaceHolder import android.view.SurfaceView import android.view.Window import android.view.WindowManager +import com.armsx2.config.ConfigStore import kr.co.iefriends.pcsx2.NativeApp +import kotlin.math.abs +import kotlin.math.roundToInt -class EmulationSurface(context: Context) : SurfaceView(context), SurfaceHolder.Callback { +class EmulationSurface(context: Context) : + SurfaceView(context), + SurfaceHolder.Callback, + DisplayManager.DisplayListener { private var viewWidth = 0 private var viewHeight = 0 + private var gameActive = false + private var lastRequestedFrameRate = Float.NaN + private val displayManager = + context.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager + private val frameRateMonitor = object : Runnable { + override fun run() { + if (!gameActive || !isAttachedToWindow) return + applyFrameRatePreference() + // The VM's nominal rate becomes available after the Surface. Keep this + // cheap poll alive so PAL/NTSC changes and disc swaps are picked up too. + postDelayed(this, FRAME_RATE_MONITOR_MS) + } + } init { holder.addCallback(this) @@ -33,9 +56,13 @@ class EmulationSurface(context: Context) : SurfaceView(context), SurfaceHolder.C override fun onAttachedToWindow() { super.onAttachedToWindow() hostWindow()?.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) + displayManager.registerDisplayListener(this, null) } override fun onDetachedFromWindow() { + removeCallbacks(frameRateMonitor) + clearFrameRatePreference() + displayManager.unregisterDisplayListener(this) hostWindow()?.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) super.onDetachedFromWindow() } @@ -45,14 +72,145 @@ class EmulationSurface(context: Context) : SurfaceView(context), SurfaceHolder.C } override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) { - NativeApp.setDisplayRefreshRate(currentDisplayRefreshHz()) + reportActualDisplayRefreshRate() + applyFrameRatePreference() NativeApp.onNativeSurfaceChanged(holder.surface, width, height) } override fun surfaceDestroyed(holder: SurfaceHolder) { + lastRequestedFrameRate = Float.NaN NativeApp.onNativeSurfaceChanged(null, 0, 0) } + override fun onDisplayAdded(displayId: Int) = Unit + + override fun onDisplayRemoved(displayId: Int) = Unit + + override fun onDisplayChanged(displayId: Int) { + if (displayId != currentDisplay()?.displayId) return + reportActualDisplayRefreshRate() + } + + /** + * Called from the Activity's VM-state effect. The high-refresh vote only + * exists during gameplay; menus and the library remain under Android's + * normal power-saving policy. + */ + fun setGameActive(active: Boolean) { + if (gameActive == active) { + if (active) applyFrameRatePreference() + return + } + gameActive = active + removeCallbacks(frameRateMonitor) + if (active) { + applyFrameRatePreference() + postDelayed(frameRateMonitor, FRAME_RATE_RETRY_MS) + } else { + clearFrameRatePreference() + } + } + + /** + * Low Latency Mode asks Android 11+ for a high-refresh mode which is an + * integer multiple of the emulated game's nominal rate. Thus ~60 fps picks + * 120 Hz and PAL 50 fps prefers 100 Hz, while a 90 Hz-only panel falls back + * to its ~60 Hz mode instead of introducing 3:2 cadence. + */ + fun applyFrameRatePreference() { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R || + !gameActive || + !holder.surface.isValid || + !lowLatencyEnabled() + ) { + clearFrameRatePreference() + return + } + + val nominalRate = runCatching { NativeApp.getNominalFrameRate() } + .getOrDefault(0f) + .takeIf { it in MIN_GAME_RATE..MAX_GAME_RATE } + ?: DEFAULT_GAME_RATE + val requestedRate = preferredDisplayRefreshRate(nominalRate) + if (!requestedRate.isFinite() || requestedRate <= 0f || + abs(requestedRate - lastRequestedFrameRate) < RATE_EPSILON + ) return + + runCatching { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + holder.surface.setFrameRate( + requestedRate, + Surface.FRAME_RATE_COMPATIBILITY_DEFAULT, + Surface.CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, + ) + } else { + @Suppress("DEPRECATION") + holder.surface.setFrameRate( + requestedRate, + Surface.FRAME_RATE_COMPATIBILITY_DEFAULT, + ) + } + lastRequestedFrameRate = requestedRate + } + } + + private fun clearFrameRatePreference() { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R || + !holder.surface.isValid || + lastRequestedFrameRate.isNaN() + ) return + runCatching { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + holder.surface.setFrameRate( + 0f, + Surface.FRAME_RATE_COMPATIBILITY_DEFAULT, + Surface.CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, + ) + } else { + @Suppress("DEPRECATION") + holder.surface.setFrameRate(0f, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT) + } + } + lastRequestedFrameRate = Float.NaN + } + + private fun lowLatencyEnabled(): Boolean = runCatching { + val settingsKey = MainActivityRuntime.currentGame.value?.settingsKey + ?: NativeApp.getGameSerial().takeIf { it.isNotBlank() } + ConfigStore.resolveForGame(settingsKey) + .vsyncQueueSize == 0 + }.getOrDefault(false) + + private fun preferredDisplayRefreshRate(nominalRate: Float): Float { + val current = currentDisplay() ?: return 0f + val rates = current.supportedModes + .asSequence() + // Avoid a refresh vote which also asks Android to change resolution. + .filter { + it.physicalWidth == current.mode.physicalWidth && + it.physicalHeight == current.mode.physicalHeight + } + .map { it.refreshRate } + .filter { it > 0f } + .distinct() + .toList() + if (rates.isEmpty()) return current.refreshRate + + val integerMultiples = rates.filter { rate -> + val multiple = (rate / nominalRate).roundToInt() + multiple >= 2 && abs(rate - nominalRate * multiple) <= RATE_MATCH_TOLERANCE_HZ + } + integerMultiples.maxOrNull()?.let { return it } + + // No clean high-refresh multiple (for example 60 fps on a 90 Hz-only + // panel): preserve even pacing by choosing the closest native-rate mode. + return rates.minBy { abs(it - nominalRate) } + } + + private fun reportActualDisplayRefreshRate() { + NativeApp.setDisplayRefreshRate(currentDisplayRefreshHz()) + } + override fun onSizeChanged(width: Int, height: Int, oldWidth: Int, oldHeight: Int) { super.onSizeChanged(width, height, oldWidth, oldHeight) viewWidth = width @@ -98,8 +256,19 @@ class EmulationSurface(context: Context) : SurfaceView(context), SurfaceHolder.C return if (w in 64..8192 && h in 64..8192) Pair(w, h) else null } - private fun currentDisplayRefreshHz(): Float = runCatching { - val currentDisplay = if (android.os.Build.VERSION.SDK_INT >= 30) context.display else display - currentDisplay?.refreshRate ?: 0f - }.getOrDefault(0f) + private fun currentDisplay(): Display? = + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) context.display else display + + private fun currentDisplayRefreshHz(): Float = + runCatching { currentDisplay()?.refreshRate ?: 0f }.getOrDefault(0f) + + private companion object { + const val DEFAULT_GAME_RATE = 59.94f + const val MIN_GAME_RATE = 20f + const val MAX_GAME_RATE = 125f + const val RATE_EPSILON = 0.05f + const val RATE_MATCH_TOLERANCE_HZ = 0.6f + const val FRAME_RATE_RETRY_MS = 500L + const val FRAME_RATE_MONITOR_MS = 5_000L + } } diff --git a/platforms/android/app/src/main/java/com/armsx2/runtime/MainActivityRuntime.kt b/platforms/android/app/src/main/java/com/armsx2/runtime/MainActivityRuntime.kt index a2a9e80280..4976223129 100644 --- a/platforms/android/app/src/main/java/com/armsx2/runtime/MainActivityRuntime.kt +++ b/platforms/android/app/src/main/java/com/armsx2/runtime/MainActivityRuntime.kt @@ -40,10 +40,6 @@ import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.input.key.KeyEventType -import androidx.compose.ui.input.key.key -import androidx.compose.ui.input.key.nativeKeyCode -import androidx.compose.ui.input.key.onKeyEvent -import androidx.compose.ui.input.key.type import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -591,6 +587,9 @@ open class MainActivityRuntime : ComponentActivity() { // serial-less ELF/homebrew) so ELF per-game settings survive a reboot // instead of falling back to global (issue #253). var resolved = com.armsx2.config.ConfigStore.resolveForGame(currentGame.value?.settingsKey) + // Build immutable input maps before the VM starts so the first ABXY + // edge never pays SharedPreferences parsing on the UI thread. + ControllerMappings.warmRuntimeCaches() // Per-game memory cards (NetherSX2-style): when the global toggle is // on, point Slot 1 at a serial-named card (the core auto-creates + // formats it at boot) — but ONLY for games still on the factory-default @@ -1515,6 +1514,20 @@ open class MainActivityRuntime : ComponentActivity() { // settings from the in-folder mirror, or seed from the folder's old PCSX2-Android.ini, // BEFORE the core loads/rewrites it. No-op (guarded) for anyone already on the new UI. runCatching { com.armsx2.config.ConfigStore.reconcileReusedFolder() } + // A genuinely empty install gets capability-aware frame-queue defaults only + // after reused-folder recovery had its chance. Capable handhelds start in + // low-latency mode (queue 0); low-end devices retain the smoother queue 2. + runCatching { com.armsx2.config.ConfigStore.seedFreshInstallDefaults(applicationContext) } + // One-time: existing capable devices also get the Low Latency default (matches fresh installs). + runCatching { com.armsx2.config.ConfigStore.migrateLowLatencyDefault(applicationContext) } + // Steer the renderer's Auto resolution to Vulkan HW on Adreno (tile-memory framebuffer-fetch + // fast path); Mali/others stay on OpenGL. Sets a native flag GSUtil::GetPreferredRenderer reads + // before the GS starts, so an explicit GL/SW pick still wins. Re-asserted each launch. + runCatching { + kr.co.iefriends.pcsx2.NativeApp.setPreferVulkan( + com.armsx2.GpuInfo.rendererName()?.contains("Adreno", ignoreCase = true) == true + ) + } // Default resources — shaders, GameIndex, fonts, fullscreenui, // patches.zip, controller DB. assetCopyRoot resolves to the @@ -1801,6 +1814,7 @@ open class MainActivityRuntime : ComponentActivity() { } } prefs = applicationContext.getSharedPreferences("ARMSX2", MODE_PRIVATE) + ControllerMappings.installRuntimeCacheInvalidation() com.armsx2.i18n.I18n.init(applicationContext) applyEmulationOrientation() com.armsx2.CoverArtStyle.load() @@ -1915,6 +1929,10 @@ open class MainActivityRuntime : ComponentActivity() { runCatching { window.setSustainedPerformanceMode(true) } } + // ADPF CPU clock hint (experimental, default OFF): re-assert the saved state to native + // before any game runs. Referencing NativeApp also loads the native lib (static init). + runCatching { kr.co.iefriends.pcsx2.NativeApp.setAdpfEnabled(prefs.getBoolean("ui.adpf", false)) } + // Defer asset copy + emucore init until setup is complete. On the // first-ever run, `systemDir` isn't picked yet at onCreate time — // so initializeOnce would resolve to the app-private fallback and @@ -2078,13 +2096,24 @@ open class MainActivityRuntime : ComponentActivity() { androidx.compose.runtime.LaunchedEffect(currentGame.value?.settingsKey) { instance?.applyEmulationOrientation() } + // Keep Android's high-refresh vote scoped to an active VM. PAUSED + // remains active because the in-game overlay is also where users + // toggle Low Latency Mode; clearing/re-requesting on every overlay + // open would cause needless display-mode churn. + androidx.compose.runtime.LaunchedEffect( + eState.value, currentGame.value?.settingsKey, surface.value + ) { + val gameActive = + eState.value == EmuState.RUNNING || eState.value == EmuState.PAUSED + surface.value?.setGameActive(gameActive) + } WindowImpl.Window { if (surface.value != null) { - // Pull Compose focus onto the surface as soon as it's - // composed AND whenever a game starts running. Without - // this the AndroidView starts un-focused, so onKeyEvent - // silently drops gamepad input until the user taps the - // screen / presses A to grant focus by hand. + // Keep focus on the SurfaceView while gameplay is active. + // Activity-level key dispatch no longer depends on Compose + // focus, but the surface still needs focus for IME/pointer + // interoperability and to keep frontend focus transitions + // deterministic. // // Keying only on surface.value (which is created once at // onCreate and never reassigned) meant focus was grabbed @@ -2194,48 +2223,6 @@ open class MainActivityRuntime : ComponentActivity() { } }, ) - } - .onKeyEvent { event -> - if (eState.value != EmuState.RUNNING) - return@onKeyEvent false - // Note: the physical menu button is handled in - // MainActivityRuntime.dispatchKeyEvent (so it can catch BACK / - // back-paddle keys); it never reaches here. - // Local co-op: route by the originating device — first - // controller = P1 (port 0), next = P2 (port 1) — and - // resolve the bind against THAT player's mapping. - val port = com.armsx2.input.PadRouter.portForDevice(event.nativeKeyEvent.deviceId) - // Physical-controller macro: a bound button fires the - // macro's whole button set at once (down on press, up on - // release), reusing the macro slots the on-screen M1-M4 - // buttons use. Checked before normal pad routing so a - // macro overrides that button's regular mapping. - val macro = com.armsx2.ui.touch.TouchControls.macroForPhysicalCode(event.key.nativeKeyCode) - if (macro != null) { - // Through fireMacro so a macro with a Frequency set - // TOGGLES its button set while held (turbo) instead of - // just holding it. Keyed per port, so P1 and P2 can - // hold the same macro without cancelling each other. - com.armsx2.ui.touch.TouchControls.fireMacro( - macro, "pad$port", event.type == KeyEventType.KeyDown, - ) { code, pressed -> - sendKeyAction( - if (pressed) KeyEventType.KeyDown else KeyEventType.KeyUp, - code, port, - ) - } - return@onKeyEvent true - } - val target = ControllerMappings.targetForPhysical(event.key.nativeKeyCode, port) - ?: return@onKeyEvent false - // Turbo/rapid-fire: while the physical button is held, the - // PS2 button auto-presses at ~15 Hz (see handleTurbo). - if (ControllerMappings.isTurboTarget(target, port)) { - handleTurbo(event.key.nativeKeyCode, event.type, target, port) - return@onKeyEvent true - } - sendKeyAction(event.type, target, port) - true }) } @@ -2428,10 +2415,8 @@ open class MainActivityRuntime : ComponentActivity() { // If the user bound BACK to a hotkey (e.g. Menu), that binding WINS — do // not hijack it for hold-to-exit. (Regression fix: hold-back consumed // BACK before the hotkey dispatch below, killing a BACK-bound Menu key.) - val backBoundToHotkey = ControllerMappings.SysHotkey.values().any { - ControllerMappings.hotkeyCode(it) == KeyEvent.KEYCODE_BACK || - ControllerMappings.hotkeyModCode(it) == KeyEvent.KEYCODE_BACK - } + val backBoundToHotkey = + ControllerMappings.isHotkeyKeyOrModifier(KeyEvent.KEYCODE_BACK) val inGame = eState.value == EmuState.RUNNING && !WindowImpl.overlayVisible.value && !WindowImpl.showLibrary.value if (event.action == KeyEvent.ACTION_DOWN && event.repeatCount == 0) @@ -2473,9 +2458,7 @@ open class MainActivityRuntime : ComponentActivity() { // Single-button binding only (combos keep their normal hotkey behaviour). run { val pm = ControllerMappings.SysHotkey.PRESSURE_MOD - val pmKey = ControllerMappings.hotkeyCode(pm) - if (pmKey != KeyEvent.KEYCODE_UNKNOWN && kc == pmKey && - ControllerMappings.hotkeyModCode(pm) == KeyEvent.KEYCODE_UNKNOWN) { + if (ControllerMappings.matchesSingleHotkey(pm, kc)) { when (event.action) { KeyEvent.ACTION_DOWN -> com.armsx2.ui.touch.TouchControls.pressureModifierHeld.value = true KeyEvent.ACTION_UP -> com.armsx2.ui.touch.TouchControls.pressureModifierHeld.value = false @@ -2889,9 +2872,48 @@ open class MainActivityRuntime : ComponentActivity() { null -> {} } } + // Gameplay buttons take the shortest path after every higher-priority + // frontend/capture/hotkey owner has declined them. This avoids routing + // ABXY through View -> Compose -> onKeyEvent before the JNI pad write. + if (dispatchGameplayKey(event)) return true return super.dispatchKeyEvent(event) } + /** Route one gameplay key edge directly from Activity dispatch to the native pad. */ + private fun dispatchGameplayKey(event: KeyEvent): Boolean { + if (eState.value != EmuState.RUNNING || controllerDrivesFrontend()) return false + val type = when (event.action) { + KeyEvent.ACTION_DOWN -> KeyEventType.KeyDown + KeyEvent.ACTION_UP -> KeyEventType.KeyUp + else -> return false + } + val physicalCode = event.keyCode + if (physicalCode == KeyEvent.KEYCODE_UNKNOWN) return false + + // Local co-op routing and macro precedence exactly match the old Compose + // onKeyEvent path; only the dispatch layer has changed. + val port = com.armsx2.input.PadRouter.portForDevice(event.deviceId) + com.armsx2.ui.touch.TouchControls.macroForPhysicalCode(physicalCode)?.let { macro -> + com.armsx2.ui.touch.TouchControls.fireMacro( + macro, "pad$port", type == KeyEventType.KeyDown, + ) { code, pressed -> + sendKeyAction( + if (pressed) KeyEventType.KeyDown else KeyEventType.KeyUp, + code, port, + ) + } + return true + } + + val target = ControllerMappings.targetForPhysical(physicalCode, port) ?: return false + if (ControllerMappings.isTurboTarget(target, port)) { + handleTurbo(physicalCode, type, target, port) + } else { + sendKeyAction(type, target, port) + } + return true + } + /** #254: forward a hardware keyboard KeyEvent to the emulated USB keyboard. * Returns true (event consumed) only when the game runs with the USB * keyboard attached, the event comes from a real keyboard, no menu/overlay @@ -3107,7 +3129,7 @@ open class MainActivityRuntime : ComponentActivity() { dispatchDpadCombined(ev, port) // Analog triggers (L2/R2). Xbox / DualShock / most modern pads // report these as 0..1 motion-axis values, not Key.ButtonL2/R2 - // key events, so the onKeyEvent path above never sees them. + // key events, so the direct key path never sees them. // AXIS_LTRIGGER/RTRIGGER is the modern path; some controllers // (older Moga, certain BT mappings) report via AXIS_BRAKE/GAS // instead — take the max so we handle whichever the device @@ -3232,12 +3254,14 @@ open class MainActivityRuntime : ComponentActivity() { // Dumps EXACTLY what a physical controller emits so a reporter can capture // (adb logcat -s ARMSX2_JOYCON) what e.g. a Nintendo Joy-Con d-pad actually // sends on their Android build — the unknown that blocks the real remap fix. - // Pure logging, zero behaviour change. Default-ON for this diagnostic build; - // silence with prefs "debug.joyconLog"=false (no UI needed). Full device info + // Pure logging, zero behaviour change. Release builds never enable this path. + // Debug builds default OFF and can opt in with prefs "debug.joyconLog"=true. + // Full device info // is logged once per deviceId; the per-event axis dump is throttled + non-zero. private val joyconLoggedDevices = HashSet() private var lastJoyconMotionLogMs = 0L - private fun joyconLogEnabled(): Boolean = prefs.getBoolean("debug.joyconLog", true) + private fun joyconLogEnabled(): Boolean = + BuildConfig.DEBUG && prefs.getBoolean("debug.joyconLog", false) /** Emit a diagnostic line to BOTH logcat (adb `-s ARMSX2_JOYCON`) AND the emulog (in-app * Save Log — so a handheld tester with no PC can capture it). NativeApp.emulog no-ops diff --git a/platforms/android/app/src/main/java/com/armsx2/ui/achievements/AchievementsScreen.kt b/platforms/android/app/src/main/java/com/armsx2/ui/achievements/AchievementsScreen.kt index 14865200f0..71b9bcf2b3 100644 --- a/platforms/android/app/src/main/java/com/armsx2/ui/achievements/AchievementsScreen.kt +++ b/platforms/android/app/src/main/java/com/armsx2/ui/achievements/AchievementsScreen.kt @@ -135,6 +135,10 @@ fun AchievementsScreen(onBack: () -> Unit, viewModel: AchievementsViewModel = vi } state.pendingHardcore?.let { enabling -> + androidx.compose.runtime.DisposableEffect(Unit) { + com.armsx2.MenuSfx.play(com.armsx2.MenuSfx.Event.POPUP_OPEN) + onDispose { com.armsx2.MenuSfx.play(com.armsx2.MenuSfx.Event.POPUP_CLOSE) } + } AlertDialog( onDismissRequest = viewModel::cancelToggleHardcore, title = { Text(str(if (enabling) "ra.hardcore.enable.title" else "ra.hardcore.disable.title")) }, diff --git a/platforms/android/app/src/main/java/com/armsx2/ui/emulation/EmulationMenuScreen.kt b/platforms/android/app/src/main/java/com/armsx2/ui/emulation/EmulationMenuScreen.kt index a3cc40fb38..212f73d18d 100644 --- a/platforms/android/app/src/main/java/com/armsx2/ui/emulation/EmulationMenuScreen.kt +++ b/platforms/android/app/src/main/java/com/armsx2/ui/emulation/EmulationMenuScreen.kt @@ -115,6 +115,10 @@ fun EmulationMenuScreen(viewModel: EmulationMenuViewModel = viewModel()) { BackHandler(onBack = closeMenu) state.pendingHardcore?.let { enabling -> + androidx.compose.runtime.DisposableEffect(Unit) { + com.armsx2.MenuSfx.play(com.armsx2.MenuSfx.Event.POPUP_OPEN) + onDispose { com.armsx2.MenuSfx.play(com.armsx2.MenuSfx.Event.POPUP_CLOSE) } + } AlertDialog( onDismissRequest = viewModel::cancelToggleHardcore, title = { Text(str(if (enabling) "ra.hardcore.enable.title" else "ra.hardcore.disable.title")) }, diff --git a/platforms/android/app/src/main/java/com/armsx2/ui/patches/PatchManagerScreen.kt b/platforms/android/app/src/main/java/com/armsx2/ui/patches/PatchManagerScreen.kt index 7bf18085c3..3a12a04b9f 100644 --- a/platforms/android/app/src/main/java/com/armsx2/ui/patches/PatchManagerScreen.kt +++ b/platforms/android/app/src/main/java/com/armsx2/ui/patches/PatchManagerScreen.kt @@ -97,6 +97,10 @@ fun PatchManagerScreen(onBack: () -> Unit, game: GameInfo? = null, viewModel: Pa } } (state.error ?: state.message)?.let { message -> + androidx.compose.runtime.DisposableEffect(Unit) { + com.armsx2.MenuSfx.play(com.armsx2.MenuSfx.Event.POPUP_OPEN) + onDispose { com.armsx2.MenuSfx.play(com.armsx2.MenuSfx.Event.POPUP_CLOSE) } + } AlertDialog( onDismissRequest = viewModel::dismissMessage, title = { Text(if (state.error == null) str("action.ok") else str("patches.dialog.patchesAndCheats")) }, @@ -174,6 +178,10 @@ fun PatchesSettingsTab(game: GameInfo? = null, viewModel: PatchManagerViewModel } } (state.error ?: state.message)?.let { message -> + androidx.compose.runtime.DisposableEffect(Unit) { + com.armsx2.MenuSfx.play(com.armsx2.MenuSfx.Event.POPUP_OPEN) + onDispose { com.armsx2.MenuSfx.play(com.armsx2.MenuSfx.Event.POPUP_CLOSE) } + } AlertDialog( onDismissRequest = viewModel::dismissMessage, title = { Text(if (state.error == null) str("action.ok") else str("patches.dialog.patchesAndCheats")) }, diff --git a/platforms/android/app/src/main/java/com/armsx2/ui/settings/FixesTab.kt b/platforms/android/app/src/main/java/com/armsx2/ui/settings/FixesTab.kt index 01109048db..f755f2652b 100644 --- a/platforms/android/app/src/main/java/com/armsx2/ui/settings/FixesTab.kt +++ b/platforms/android/app/src/main/java/com/armsx2/ui/settings/FixesTab.kt @@ -170,15 +170,6 @@ fun FixesTab(state: MutableState) { description = str("fixes.dithering.desc"), onChange = { apply(s.copy(dithering = it)) }, ) - SettingsDivider() - // PCSX2's "Optimal Frame Pacing" checkbox = force the GS-thread frame queue to 0. - // On -> tightest pacing + lowest input latency; Off -> the default small queue (2), - // which is smoother on weaker devices at the cost of a little lag. - ToggleRow( - str("fixes.optimalFramePacing.label"), - s.vsyncQueueSize == 0, - description = str("fixes.optimalFramePacing.desc"), - ) { apply(s.copy(vsyncQueueSize = if (it) 0 else 2)) } } CollapsibleSection(str("fixes.section.upscaling")) { diff --git a/platforms/android/app/src/main/java/com/armsx2/ui/settings/PerformanceTab.kt b/platforms/android/app/src/main/java/com/armsx2/ui/settings/PerformanceTab.kt index d1e077ca09..76ea700c99 100644 --- a/platforms/android/app/src/main/java/com/armsx2/ui/settings/PerformanceTab.kt +++ b/platforms/android/app/src/main/java/com/armsx2/ui/settings/PerformanceTab.kt @@ -44,6 +44,23 @@ fun PerformanceTab(state: MutableState) { modifier = Modifier .fillMaxWidth(), ) { + // Prominent latency preset: zero queued GS frames keeps the emulated CPU + // from running ahead of presentation, and the Surface requests a matching + // high-refresh display mode. Settings scope is supplied by InGameOverlay, + // so the same switch naturally supports Global and Game overrides. Off + // restores the small, smoother queue and Android's automatic refresh policy. + ToggleRow( + label = str("perf.lowLatencyMode.label"), + value = s.vsyncQueueSize == 0, + description = str("perf.lowLatencyMode.description"), + ) { enabled -> + apply(s.copy(vsyncQueueSize = if (enabled) 0 else 2)) + // Apply the scoped Surface frame-rate vote immediately while the + // paused in-game overlay is open. + com.armsx2.runtime.MainActivityRuntime.surface.value + ?.applyFrameRatePreference() + } + SettingsDivider() // Speedhack profile presets. Equality against s.copy(...) means the // segment auto-reflects "Custom" once the user tweaks any speedhack below. run { @@ -151,6 +168,26 @@ fun PerformanceTab(state: MutableState) { }, ) } + // ---- CPU clock hint (ADPF) --------------------------------------------- + // PerformanceHintManager: reports the per-frame CPU work to the OS scheduler so it can + // raise the EE/GS/MTVU threads' CPU frequency toward the frame deadline, countering the + // DVFS governor under-clocking emulation's bursty load. EXPERIMENTAL, default OFF. + // No-op below API 33. Applied at launch (MainActivityRuntime) + live here. + run { + val adpf = remember { androidx.compose.runtime.mutableStateOf(com.armsx2.runtime.MainActivityRuntime.prefs.getBoolean("ui.adpf", false)) } + SegmentedRow( + label = str("perf.adpf.label"), + options = listOf(str("common.off"), str("common.on")), + selectedIndex = if (adpf.value) 1 else 0, + description = str("perf.adpf.description"), + onChange = { + val on = it == 1 + adpf.value = on + com.armsx2.runtime.MainActivityRuntime.prefs.edit { putBoolean("ui.adpf", on) } + runCatching { kr.co.iefriends.pcsx2.NativeApp.setAdpfEnabled(on) } + }, + ) + } SettingsDivider() CollapsibleSection(str("perf.speedhacks.title"), initiallyExpanded = false) { IntSliderRow( diff --git a/platforms/android/app/src/main/java/com/armsx2/ui/settings/SettingsWidgets.kt b/platforms/android/app/src/main/java/com/armsx2/ui/settings/SettingsWidgets.kt index 949dd5f668..6802cc0bf9 100644 --- a/platforms/android/app/src/main/java/com/armsx2/ui/settings/SettingsWidgets.kt +++ b/platforms/android/app/src/main/java/com/armsx2/ui/settings/SettingsWidgets.kt @@ -1133,6 +1133,10 @@ private fun InfoHint(title: String, message: String) { Text("i", color = MaterialTheme.colorScheme.primary, fontSize = 13.sp, fontWeight = FontWeight.Bold) } if (open) { + androidx.compose.runtime.DisposableEffect(Unit) { + com.armsx2.MenuSfx.play(com.armsx2.MenuSfx.Event.POPUP_OPEN) + onDispose { com.armsx2.MenuSfx.play(com.armsx2.MenuSfx.Event.POPUP_CLOSE) } + } AlertDialog( onDismissRequest = { open = false }, title = { Text(title) }, diff --git a/platforms/android/app/src/main/java/com/armsx2/ui/settingshub/SettingsSearchIndex.kt b/platforms/android/app/src/main/java/com/armsx2/ui/settingshub/SettingsSearchIndex.kt index 995f9b501a..201b727f56 100644 --- a/platforms/android/app/src/main/java/com/armsx2/ui/settingshub/SettingsSearchIndex.kt +++ b/platforms/android/app/src/main/java/com/armsx2/ui/settingshub/SettingsSearchIndex.kt @@ -58,10 +58,12 @@ internal val SETTINGS_SEARCH_INDEX: List = listOf( SettingsSearchEntry("perf.ntscFramerate.label", true, SettingsCategory.Performance), SettingsSearchEntry("perf.palFramerate.label", true, SettingsCategory.Performance), SettingsSearchEntry("perf.frameSkip.label", true, SettingsCategory.Performance), + SettingsSearchEntry("perf.lowLatencyMode.label", true, SettingsCategory.Performance), SettingsSearchEntry("perf.speedhackProfile.label", true, SettingsCategory.Performance), SettingsSearchEntry("perf.displayResolution.label", true, SettingsCategory.Performance), SettingsSearchEntry("perf.screenRes.label", true, SettingsCategory.Performance), SettingsSearchEntry("perf.sustainedPerformance.label", true, SettingsCategory.Performance), + SettingsSearchEntry("perf.adpf.label", true, SettingsCategory.Performance), SettingsSearchEntry("perf.eeFpuClamping.label", true, SettingsCategory.Performance), SettingsSearchEntry("perf.vuClamping.label", true, SettingsCategory.Performance), SettingsSearchEntry("perf.eeFpuRoundMode.label", true, SettingsCategory.Performance), @@ -196,7 +198,6 @@ internal val SETTINGS_SEARCH_INDEX: List = listOf( SettingsSearchEntry("fixes.useBlitSwapChain.label", true, SettingsCategory.Advanced), SettingsSearchEntry("fixes.disableShaderCache.label", true, SettingsCategory.Advanced), SettingsSearchEntry("fixes.integerScaling.label", true, SettingsCategory.Advanced), - SettingsSearchEntry("fixes.optimalFramePacing.label", true, SettingsCategory.Advanced), SettingsSearchEntry("fixes.alignSprite.label", true, SettingsCategory.Advanced), SettingsSearchEntry("fixes.mergeSprite.label", true, SettingsCategory.Advanced), SettingsSearchEntry("fixes.wildArmsOffset.label", true, SettingsCategory.Advanced), diff --git a/platforms/android/app/src/main/java/com/armsx2/ui/touch/TouchControls.kt b/platforms/android/app/src/main/java/com/armsx2/ui/touch/TouchControls.kt index 26382d3291..86ca35d568 100644 --- a/platforms/android/app/src/main/java/com/armsx2/ui/touch/TouchControls.kt +++ b/platforms/android/app/src/main/java/com/armsx2/ui/touch/TouchControls.kt @@ -333,6 +333,7 @@ object TouchControls { val wanted = codes.toSet() val csv = macroAssignableTargets.map { it.code }.filter { it in wanted }.joinToString(",") MainActivityRuntime.prefs.edit { putString(KEY_MACRO_PREFIX + id.name, csv) } + invalidateRuntimeMacroCache() macroBindTick.intValue++ } @@ -347,6 +348,7 @@ object TouchControls { fun setMacroPhysicalCode(id: TouchButtonId, keycode: Int) { MainActivityRuntime.prefs.edit { putInt(KEY_MACRO_PHYS_PREFIX + id.name, keycode)} + invalidateRuntimeMacroCache() macroBindTick.intValue++ } @@ -436,12 +438,35 @@ object TouchControls { /** The macro a physical [keycode] triggers — only if it's bound AND has buttons * configured. Checked in the gameplay key path (Main) before normal pad routing. */ + @Volatile private var runtimeMacroMap: Map? = null + + fun invalidateRuntimeMacroCache() { + runtimeMacroMap = null + } + + private fun runtimeMacroMap(): Map = + runtimeMacroMap ?: synchronized(this) { + runtimeMacroMap ?: buildMap { + listOf(TouchButtonId.MACRO1, TouchButtonId.MACRO2, TouchButtonId.MACRO3, TouchButtonId.MACRO4) + .forEach { id -> + val physical = macroPhysicalCode(id) + if (physical != KeyEvent.KEYCODE_UNKNOWN && + macroCodes(id).isNotEmpty() && + !containsKey(physical) + ) { + put(physical, id) + } + } + }.also { runtimeMacroMap = it } + } + + fun warmRuntimeMacroCache() { + runtimeMacroMap() + } + fun macroForPhysicalCode(keycode: Int): TouchButtonId? { if (keycode == KeyEvent.KEYCODE_UNKNOWN) return null - for (id in listOf(TouchButtonId.MACRO1, TouchButtonId.MACRO2, TouchButtonId.MACRO3, TouchButtonId.MACRO4)) { - if (macroPhysicalCode(id) == keycode && macroCodes(id).isNotEmpty()) return id - } - return null + return runtimeMacroMap()[keycode] } /** Set true once load() has run — used to avoid clobbering disk state diff --git a/platforms/android/app/src/main/java/kr/co/iefriends/pcsx2/NativeApp.java b/platforms/android/app/src/main/java/kr/co/iefriends/pcsx2/NativeApp.java index 2a3cf1334c..b30ccee7e6 100644 --- a/platforms/android/app/src/main/java/kr/co/iefriends/pcsx2/NativeApp.java +++ b/platforms/android/app/src/main/java/kr/co/iefriends/pcsx2/NativeApp.java @@ -132,6 +132,11 @@ public class NativeApp { /** Real state of the diagnostic flag (the UI toggle must not keep its own copy). */ public static native boolean isEeDiffVerify(); + // ADPF (PerformanceHintManager): hint the OS to clock the EE/GS threads' cores up toward + // the frame deadline instead of the DVFS governor under-clocking emulation. Applies live; + // no-op below API 33. Persisted app-side (pref "ui.adpf") and re-applied at startup. + public static native void setAdpfEnabled(boolean enabled); + /** * Push one EmuCore setting into the base settings layer. Mirrors * pcsx2-qt's Settings save flow — Host::SetBase*SettingValue sticks @@ -182,6 +187,8 @@ public class NativeApp { public static native String getGameSerial(); public static native String getGameCRC(); public static native float getFPS(); + /** Current game's nominal emulated refresh (~59.94 NTSC / 50 PAL), or 0 without a VM. */ + public static native float getNominalFrameRate(); /** Build version string from BuildVersion::GitRev — formatted as * "GitTagHi.GitTagMid.GitTagLo.ARMSX2Build-SNAPSHOT". Used by the @@ -624,6 +631,8 @@ public class NativeApp { public static native void renderOpenGL(); public static native void renderVulkan(); public static native void renderAuto(); + // When true, the Auto renderer resolves to Vulkan HW instead of OpenGL (set for Adreno devices). + public static native void setPreferVulkan(boolean enabled); public static native void renderPreloading(int value); /** Flip texture dumping on/off live (PCSX2's ToggleTextureDumping hotkey). diff --git a/platforms/android/app/src/main/res/raw/sfx_nav_a.wav b/platforms/android/app/src/main/res/raw/sfx_nav_a.wav new file mode 100644 index 0000000000000000000000000000000000000000..bbe72d65f6700d18b638572734601e76b24a3352 GIT binary patch literal 16802 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 literal 0 HcmV?d00001 diff --git a/platforms/android/app/src/main/res/raw/sfx_nav_b.wav b/platforms/android/app/src/main/res/raw/sfx_nav_b.wav new file mode 100644 index 0000000000000000000000000000000000000000..2e2817fe35e386f3cdd2ff499bf0d74f554d2d3a GIT binary patch literal 16802 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 literal 0 HcmV?d00001 diff --git a/platforms/android/app/src/main/res/raw/sfx_popup_open.wav b/platforms/android/app/src/main/res/raw/sfx_popup_open.wav new file mode 100644 index 0000000000000000000000000000000000000000..838ad2e650727cc0709a7dca20d512282721d56d GIT binary patch literal 66194 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

K{*&&SZl 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 literal 0 HcmV?d00001