aboutsummaryrefslogtreecommitdiff
path: root/src/video_core/gpu_split.cpp
Commit message (Collapse)AuthorAgeFilesLines
* nx2: read GPU-written command lists from copies instead of drainingTakoroka33 hours1-2/+28
| | | | | | | | | | | | | | | | | | | | | | The trees fix (#52) drains the split and flushes for every command list on a GPU-written page: in a Mario Kart World race ~13,500 lists and ~400 GPU round trips a second, during which the back has nothing to do. The replay ran at ~40 fps instead of ~45. The front now marks the pages those lists are on. The buffer cache notes writes to them; after a compute dispatch or DMA copy that writes one it copies the page into host memory and submits. The front waits for the back only up to the last compute or copy work it sent (not everything queued), then reads the copy once the GPU is done with it. Pages the GPU wrote once, long before, and the CPU now writes lists to have no copy: their first list drains and flushes the whole page, which is then read from guest memory until GPU work writes it again. CPU writes and inline uploads reach guest memory, so they keep such a page synced but make a copy stale. A page a draw writes always drains. Mario Kart World time-trial replay, Radeon 780M: ~40 -> ~45 fps, trees drawn, no list drains left.
* Merge pull request #38 from Djihads80/nx2-accuracy-switchDjihads4 days1-4/+12
|\ | | | | nx2: Fix the current crash when switching from fast to accurate and vice versa
| * nx2: apply GPU accuracy changes mid-game by stopping and restarting the GPU ↵kraibse4 days1-4/+12
| | | | | | | | | | | | | | | | | | | | 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.
* | video_core: arm64 spin hint in the GPU splitgivethesourceplox5 days1-1/+3
|/ | | | | | | | 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)
* gpu_split: reset the ring when the split stopsTakoroka5 days1-0/+15
| | | | | | | | | | | | | | | | GpuSplit is a static instance and outlives the emulation session. Stop() joined the back thread but kept the ring positions and engine pointers, so the next session's back thread started reading at 0 of a new, empty ring while `published` still held the old session's position: each empty entry reads as a wrap, the back thread skipped ahead a ring at a time and never landed on the old position. The front then spun in Drain(), the next game's first GPU work never ran, and it waited on its first syncpoint forever (Mario Kart World loaded after another Switch 2 game: syncpoint 2 stuck at 0, waiting for 2). The back thread also held the previous session's freed engines. Stop() now drops the ring and resets the positions, the engines and the front macro mode, so MaybeStart() begins a clean ring.
* video_core: GPU thread split on by default for Switch 2 titles; cheaper ↵Takoroka5 days1-32/+4
| | | | | | | | | | | | | front paths Clean A/B in title 1 (3 rounds each): 1.46x the draws a second of one thread, frames 17% shorter, no crashes, front register copies equal to the back's in 57,089 checks. EDEN_NX2_SPLIT=0 runs everything on one thread, =1 keeps macros on the back. The front's per-write paths no longer check guarded statics (GpuSplit::Get, Nx2Profile::Enabled, the skip-same switches) and the ring's method writes are inline. Notes row 145.
* video_core: split the GPU thread in two (EDEN_NX2_SPLIT, off by default)Takoroka5 days1-0/+363
The GPU thread (front) takes the CPU's commands, parses command lists and runs the puller; engine method calls and everything behind them (registers, draws, dispatches, the rasterizer and its caches) run in order on a second thread (back), fed through a single-producer single-consumer ring (gpu_split.h). Work the front did on back-owned state (end of command list flushes, channel binds, semaphore releases, syncpoint increments, flush/invalidate requests, presentation) is deferred into the same ring; the front waits for the back only where it needs a result from that state: semaphore acquires and MME DMA reads. EDEN_NX2_SPLIT=1 runs macros on the back. EDEN_NX2_SPLIT=2 runs the 3D and compute macros on the front against copies of the registers they read (Maxwell3D/KeplerCompute Front*), drops state writes that keep a register's value there, and sends the rest. EDEN_NX2_SPLIT_VERIFY=1 compares the copies with the back's registers every 4096 macro calls (0 differences in 40,193 checks in title 1); EDEN_NX2_SPLIT_CHECK=1 logs the stack of any other thread using the Vulkan scheduler while the back runs. Switch 2 titles, Vulkan, non-accurate GPU only. Title 1, 3D attract loop: ~44,000 draws a second on one thread, ~47,400 with EDEN_NX2_SPLIT=1, 50,000-66,500 with EDEN_NX2_SPLIT=2.