From 9ad01b60c8cefe0bb2d91eabf67cf54a1eeeb92c Mon Sep 17 00:00:00 2001 From: givethesourceplox <272928635+givethesourceplox@users.noreply.github.com> Date: Fri, 30 Oct 2026 09:58:10 -0300 Subject: video_core: arm64 spin hint in the GPU split Pause() fell back to a sched_yield system call on arm64; use the yield instruction like the x86 PAUSE. Mark the Windows-only back thread id unused for clang. Assisted-by: Claude (Anthropic) --- src/video_core/gpu_split.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/video_core/gpu_split.cpp') diff --git a/src/video_core/gpu_split.cpp b/src/video_core/gpu_split.cpp index f913ca82ce..2bc8e29470 100644 --- a/src/video_core/gpu_split.cpp +++ b/src/video_core/gpu_split.cpp @@ -34,12 +34,14 @@ void Pause() { _mm_pause(); #elif defined(__x86_64__) || defined(__i386__) __builtin_ia32_pause(); +#elif defined(__aarch64__) + asm volatile("yield"); #else std::this_thread::yield(); #endif } -std::atomic g_back_thread_id{}; +[[maybe_unused]] std::atomic g_back_thread_id{}; std::atomic g_back_busy{}; } // Anonymous namespace -- cgit v1.2.3 From dfb3241838c17bd0e6c392cc29f24d085185dd73 Mon Sep 17 00:00:00 2001 From: kraibse <33869366+kraibse@users.noreply.github.com> Date: Fri, 30 Oct 2026 14:57:05 +0100 Subject: nx2: apply GPU accuracy changes mid-game by stopping and restarting the GPU split The split starts only with unsafe command reads, decided once at start-up. Switching to accurate afterwards made the front thread flush caches the back thread owns, which raced on Scheduler::chunk and crashed. MaybeStart now re-checks the settings between commands: it drains and stops the split when they no longer allow it and starts it again when they do. DmaPusher keeps unsafe reads while the split is active to cover the gap until then. --- src/video_core/dma_pusher.cpp | 5 ++++- src/video_core/gpu_split.cpp | 16 ++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) (limited to 'src/video_core/gpu_split.cpp') diff --git a/src/video_core/dma_pusher.cpp b/src/video_core/dma_pusher.cpp index 62f7e6bfdb..88d571ae5f 100644 --- a/src/video_core/dma_pusher.cpp +++ b/src/video_core/dma_pusher.cpp @@ -151,7 +151,10 @@ bool DmaPusher::Step() { } } // A resumed entry is read again: the words after the acquire may be new by now. - const bool use_safe = Settings::IsDMALevelDefault() ? Settings::IsGPULevelHigh() : Settings::IsDMALevelSafe(); + // A safe read flushes the caches, which belong to the split's back thread while it runs + // (the split only starts with unsafe reads; the settings can change mid-game). + const bool use_safe = !VideoCommon::GpuSplit::Get().Active() && + (Settings::IsDMALevelDefault() ? Settings::IsGPULevelHigh() : Settings::IsDMALevelSafe()); if (use_safe) { Tegra::Memory::GpuGuestMemoryheaders(memory_manager, dma_state.dma_get, header.size, &command_headers); const std::span commands{headers.data(), headers.size()}; diff --git a/src/video_core/gpu_split.cpp b/src/video_core/gpu_split.cpp index f913ca82ce..3997ea4565 100644 --- a/src/video_core/gpu_split.cpp +++ b/src/video_core/gpu_split.cpp @@ -88,15 +88,23 @@ void GpuSplit::MaybeStart(Core::System& system_) { return value != nullptr ? value[0] : '2'; }(); const bool wanted = mode == '1' || mode == '2'; - if (active || !wanted || !Tegra::g_nx2_ampere.load(std::memory_order_relaxed)) { + if (!wanted || !Tegra::g_nx2_ampere.load(std::memory_order_relaxed)) { return; } // The front reads command lists straight from guest memory; a read that flushes the caches - // first (safe DMA, accurate GPU) would touch back-owned state. + // first (safe DMA, accurate GPU) would touch back-owned state. The settings can change + // mid-game: hand the engines back to the front (and start again when they allow it). const bool safe_reads = Settings::IsDMALevelDefault() ? Settings::IsGPULevelHigh() : Settings::IsDMALevelSafe(); - if (safe_reads || Settings::IsGPULevelHigh() || - Settings::values.renderer_backend.GetValue() != Settings::RendererBackend::Vulkan) { + const bool allowed = !safe_reads && !Settings::IsGPULevelHigh() && + Settings::values.renderer_backend.GetValue() == Settings::RendererBackend::Vulkan; + if (active && !allowed) { + Drain(); + Stop(); + LOG_INFO(HW_GPU, "GPU thread split: stopped, the accuracy settings need the caches on the front"); + return; + } + if (active || !allowed) { return; } system = &system_; -- cgit v1.2.3