From dce3adbc4cae486e2f3c080b995669d6db5ef58f Mon Sep 17 00:00:00 2001 From: Takoroka <137927095+Takoroka@users.noreply.github.com> Date: Tue, 27 Oct 2026 17:04:06 -0400 Subject: Switch 2: window image sizes, queue semaphores, built-in fonts, memory budget - gsv 1510 CalculateRequirements: block-linear size/alignment for window images. - nvhost-gpu: Switch 2 channel event 7 is a real (unsignalled) event. - Puller mirrors NVN2 queue semaphore releases into the page the CPU and GPU wait on (the first two-page nx2:gpu region); EDEN_NX2_METHOD_TRACE logs methods. - pl:u 2000/2010 GetBuiltInFontSharedMemory/GetBuiltInFontData serve plain TTF copies of the shared fonts. - Switch 2 processes count the alias region in their max memory, so the game's nninitStartup heap (total - 6.3 GiB) has room for its sound heap. - gdbrsp.py: interrupt, threads, selthread, hits, continue_async, sleep. --- src/video_core/engines/puller.cpp | 20 ++++++++++++++++++++ src/video_core/nx2.h | 8 ++++++++ 2 files changed, 28 insertions(+) (limited to 'src/video_core') diff --git a/src/video_core/engines/puller.cpp b/src/video_core/engines/puller.cpp index c9c1153bbf..9e78d586d1 100644 --- a/src/video_core/engines/puller.cpp +++ b/src/video_core/engines/puller.cpp @@ -110,6 +110,12 @@ void Puller::ProcessSemaphoreTriggerMethod(DmaPusher& dma_pusher) { const GPUVAddr sequence_address{regs.semaphore_address.SemaphoreAddress()}; const u32 payload = regs.semaphore_sequence; dma_pusher.rasterizer->Query(sequence_address, VideoCommon::QueryType::Payload, VideoCommon::QueryPropertiesFlags::HasTimeout, payload, 0); + const u64 source_page = g_nx2_semaphore_source_page; + if (source_page != 0 && (sequence_address & ~GPUVAddr{0xFFF}) == source_page) { + const GPUVAddr mirror = g_nx2_semaphore_mirror_page + (sequence_address & 0xFFF); + LOG_DEBUG(HW_GPU, "Switch 2 semaphore {:#x}={:#x} mirrored to {:#x}", sequence_address, payload, mirror); + dma_pusher.rasterizer->Query(mirror, VideoCommon::QueryType::Payload, VideoCommon::QueryPropertiesFlags::HasTimeout, payload, 0); + } } else { do { const u32 word = dma_pusher.memory_manager.Read(regs.semaphore_address.SemaphoreAddress()); @@ -234,8 +240,18 @@ void Puller::CallPullerMethod(DmaPusher& dma_pusher, const MethodCall& method_ca } /// Calls a GPU engine method. +static bool Nx2MethodTrace() { + static const bool trace = std::getenv("EDEN_NX2_METHOD_TRACE") != nullptr; + return trace; +} + void Puller::CallEngineMethod(DmaPusher& dma_pusher, const MethodCall& method_call) { const EngineID engine = bound_engines[method_call.subchannel]; + if (Nx2MethodTrace()) { + LOG_INFO(HW_GPU, "nx2 method sub={} engine={:04X} method={:#x} arg={:#x}", + method_call.subchannel, static_cast(engine), method_call.method, + method_call.argument); + } switch (engine) { case EngineID::FERMI_TWOD_A: dma_pusher.channel_state.payload->fermi_2d.CallMethod(dma_pusher.system, method_call.method, method_call.argument, method_call.IsLastCall()); @@ -264,6 +280,10 @@ void Puller::CallEngineMethod(DmaPusher& dma_pusher, const MethodCall& method_ca /// Calls a GPU engine multivalue method. void Puller::CallEngineMultiMethod(DmaPusher& dma_pusher, u32 method, u32 subchannel, const u32* base_start, u32 amount, u32 methods_pending) { const EngineID engine = bound_engines[subchannel]; + if (Nx2MethodTrace()) { + LOG_INFO(HW_GPU, "nx2 multimethod sub={} engine={:04X} method={:#x} amount={} first={:#x}", + subchannel, static_cast(engine), method, amount, base_start[0]); + } switch (engine) { case EngineID::FERMI_TWOD_A: dma_pusher.channel_state.payload->fermi_2d.CallMultiMethod(dma_pusher.system, method, base_start, amount, methods_pending); diff --git a/src/video_core/nx2.h b/src/video_core/nx2.h index b8258ca243..9fdf0a7c68 100644 --- a/src/video_core/nx2.h +++ b/src/video_core/nx2.h @@ -5,10 +5,18 @@ #include +#include "common/common_types.h" + namespace Tegra { // Set once a Switch 2 (Ampere, NVN2) driver is talking to the GPU. Its command streams use // Ampere classes and the Turing+ macro ISA, which Eden's Maxwell engines don't implement. inline std::atomic g_nx2_ampere{false}; +// NVN2 queues release their progress values into one GPU page and wait (GPU acquires and CPU +// polls) on the same offsets in the page below it. Something on the console copies one into +// the other; until that is known, the puller mirrors releases that land in the source page. +inline std::atomic g_nx2_semaphore_source_page{0}; // GPU VA of the released-to page +inline std::atomic g_nx2_semaphore_mirror_page{0}; // GPU VA of the waited-on page + } // namespace Tegra -- cgit v1.2.3