diff options
| author | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-11-01 15:14:37 -0500 |
|---|---|---|
| committer | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-11-01 15:14:37 -0500 |
| commit | 91b7400a27a89f1ff9bef7f148913aa76f0a39ad (patch) | |
| tree | 1d2ff177cb93ed6af25ad011bf3b06c0bb9a89c2 /src/video_core/nx2.h | |
| parent | 76812d0bd86c3dfbef473ad6236a68045ad3d4b5 (diff) | |
| parent | bef001c1515a13a9b8e361a5a7d372fc2e01094c (diff) | |
Merge remote-tracking branch 'origin/fix/nx2-gpu-written-command-lists' into test/linux-all-prs-plus
# Conflicts:
# src/core/hle/service/nvdrv/nvdrv.cpp
Diffstat (limited to 'src/video_core/nx2.h')
| -rw-r--r-- | src/video_core/nx2.h | 38 |
1 files changed, 38 insertions, 0 deletions
diff --git a/src/video_core/nx2.h b/src/video_core/nx2.h index 318607384b..1fb49e15a6 100644 --- a/src/video_core/nx2.h +++ b/src/video_core/nx2.h @@ -20,6 +20,44 @@ namespace Tegra { // Ampere classes and the Turing+ macro ISA, which Eden's Maxwell engines don't implement. inline std::atomic<bool> g_nx2_ampere{false}; +// Device pages the GPU has written through the buffer cache (shader stores, copies), ever. Title 1 +// runs command lists the GPU writes each frame (20-byte entries its culling fills in); read +// without a flush they are stale and the draws behind them (trees) go missing. The bits never +// clear: the dispatch that rewrites a page may still be queued on the split's back when its front +// reads the command list. One bit per 4 KiB of the 36-bit device address space (2 MiB). +inline constexpr u64 Nx2WrittenPageBits = 12; +inline std::array<std::atomic<u64>, (u64{1} << (36 - Nx2WrittenPageBits)) / 64> g_nx2_gpu_written_pages{}; + +inline void Nx2MarkGpuWritten(u64 device_address, u64 size) { + if (size == 0) { + return; + } + const u64 last = std::min<u64>((device_address + size - 1) >> Nx2WrittenPageBits, + g_nx2_gpu_written_pages.size() * 64 - 1); + for (u64 page = device_address >> Nx2WrittenPageBits; page <= last; ++page) { + auto& word = g_nx2_gpu_written_pages[page / 64]; + const u64 bit = u64{1} << (page % 64); + if ((word.load(std::memory_order_relaxed) & bit) == 0) { + word.fetch_or(bit, std::memory_order_relaxed); + } + } +} + +/// A new emulation session starts: no page has been written by its GPU yet. +inline void Nx2ClearGpuWrittenPages() { + for (auto& word : g_nx2_gpu_written_pages) { + word.store(0, std::memory_order_relaxed); + } +} + +[[nodiscard]] inline bool Nx2IsGpuWritten(u64 device_address) { + const u64 page = device_address >> Nx2WrittenPageBits; + if (page >= g_nx2_gpu_written_pages.size() * 64) { + return false; + } + return (g_nx2_gpu_written_pages[page / 64].load(std::memory_order_relaxed) >> (page % 64)) & 1; +} + // NVN2 queues release their progress values into the second page of a two-page GPU-accessible // region and GPU acquires read the same offsets in the first page (the CPU polls the second). // Something on the console copies one into the other; until that is known, the puller mirrors |
