<feed xmlns='http://www.w3.org/2005/Atom'>
<title>eglantine-cirakg/src/video_core/gpu_split.cpp, branch nx2</title>
<subtitle>Mirror of github.com/cira0100/Eglantine-public nx2, a fork of Djihads80/Eglantine.</subtitle>
<id>https://git.cirakg.xyz/eglantine-cirakg/atom?h=nx2</id>
<link rel='self' href='https://git.cirakg.xyz/eglantine-cirakg/atom?h=nx2'/>
<link rel='alternate' type='text/html' href='https://git.cirakg.xyz/eglantine-cirakg/'/>
<updated>2026-11-02T16:24:19+00:00</updated>
<entry>
<title>nx2: read GPU-written command lists from copies instead of draining</title>
<updated>2026-11-02T16:24:19+00:00</updated>
<author>
<name>Takoroka</name>
<email>137927095+Takoroka@users.noreply.github.com</email>
</author>
<published>2026-11-02T16:24:19+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cirakg.xyz/eglantine-cirakg/commit/?id=8f1435f8db104351fa3388551eee9d12d2043b40'/>
<id>urn:sha1:8f1435f8db104351fa3388551eee9d12d2043b40</id>
<content type='text'>
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 -&gt; ~45 fps, trees
drawn, no list drains left.
</content>
</entry>
<entry>
<title>Merge pull request #38 from Djihads80/nx2-accuracy-switch</title>
<updated>2026-10-30T15:00:28+00:00</updated>
<author>
<name>Djihads</name>
<email>76681596+Djihads80@users.noreply.github.com</email>
</author>
<published>2026-10-30T15:00:28+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cirakg.xyz/eglantine-cirakg/commit/?id=9e2d8d27a8f8065a74fd3d4eb51efc426bd742f7'/>
<id>urn:sha1:9e2d8d27a8f8065a74fd3d4eb51efc426bd742f7</id>
<content type='text'>
nx2: Fix the current crash when switching from fast to accurate and vice versa</content>
</entry>
<entry>
<title>nx2: apply GPU accuracy changes mid-game by stopping and restarting the GPU split</title>
<updated>2026-10-30T13:57:05+00:00</updated>
<author>
<name>kraibse</name>
<email>33869366+kraibse@users.noreply.github.com</email>
</author>
<published>2026-10-30T13:57:05+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cirakg.xyz/eglantine-cirakg/commit/?id=dfb3241838c17bd0e6c392cc29f24d085185dd73'/>
<id>urn:sha1:dfb3241838c17bd0e6c392cc29f24d085185dd73</id>
<content type='text'>
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.
</content>
</entry>
<entry>
<title>video_core: arm64 spin hint in the GPU split</title>
<updated>2026-10-30T12:58:10+00:00</updated>
<author>
<name>givethesourceplox</name>
<email>272928635+givethesourceplox@users.noreply.github.com</email>
</author>
<published>2026-10-30T12:58:10+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cirakg.xyz/eglantine-cirakg/commit/?id=9ad01b60c8cefe0bb2d91eabf67cf54a1eeeb92c'/>
<id>urn:sha1:9ad01b60c8cefe0bb2d91eabf67cf54a1eeeb92c</id>
<content type='text'>
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)
</content>
</entry>
<entry>
<title>gpu_split: reset the ring when the split stops</title>
<updated>2026-10-30T04:54:38+00:00</updated>
<author>
<name>Takoroka</name>
<email>137927095+Takoroka@users.noreply.github.com</email>
</author>
<published>2026-10-30T04:54:19+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cirakg.xyz/eglantine-cirakg/commit/?id=092c16d6f39b395e7b3e105a42963733bf9de045'/>
<id>urn:sha1:092c16d6f39b395e7b3e105a42963733bf9de045</id>
<content type='text'>
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.
</content>
</entry>
<entry>
<title>video_core: GPU thread split on by default for Switch 2 titles; cheaper front paths</title>
<updated>2026-10-30T00:49:48+00:00</updated>
<author>
<name>Takoroka</name>
<email>137927095+Takoroka@users.noreply.github.com</email>
</author>
<published>2026-10-29T15:55:07+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cirakg.xyz/eglantine-cirakg/commit/?id=15e953cafd5cb348833cb373d7ddd996b81307f7'/>
<id>urn:sha1:15e953cafd5cb348833cb373d7ddd996b81307f7</id>
<content type='text'>
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.
</content>
</entry>
<entry>
<title>video_core: split the GPU thread in two (EDEN_NX2_SPLIT, off by default)</title>
<updated>2026-10-30T00:49:48+00:00</updated>
<author>
<name>Takoroka</name>
<email>137927095+Takoroka@users.noreply.github.com</email>
</author>
<published>2026-10-29T15:16:43+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cirakg.xyz/eglantine-cirakg/commit/?id=7a251d3a92f870649dab6068007ca3a1c910bbb5'/>
<id>urn:sha1:7a251d3a92f870649dab6068007ca3a1c910bbb5</id>
<content type='text'>
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.
</content>
</entry>
</feed>
