<feed xmlns='http://www.w3.org/2005/Atom'>
<title>eglantine-cirakg/src/video_core/dma_pusher.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-02T19:53:47+00:00</updated>
<entry>
<title>video_core: don't execute command lists copied before their channel waited</title>
<updated>2026-11-02T19:53:47+00:00</updated>
<author>
<name>Sssnowyyy</name>
<email>78863999+Sssnowyyy@users.noreply.github.com</email>
</author>
<published>2026-11-02T16:34:40+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cirakg.xyz/eglantine-cirakg/commit/?id=256b1dc346e19bc60c2884d4af875fc53ef0a99a'/>
<id>urn:sha1:256b1dc346e19bc60c2884d4af875fc53ef0a99a</id>
<content type='text'>
cce6d44af2 executes each command list entry from a copy of its words taken
at submit. Games submit command lists before writing them: the lists wait
behind a semaphore acquire, and the game writes their commands just before
it releases the acquire (Mario Kart World after present). The copies of
those lists were stale. Pokopia stopped after its first frame on macOS: its
GPU never reached the fence the game spun on (EDEN_NX2_PB_SNAPSHOT=0 made it
run again).

Count each channel's suspensions on an acquire and the resumes after them,
and record the count with each copy. A list copied while its channel was
suspended, or whose channel suspended since, reads guest memory instead.
Lists submitted and run without a wait in between keep the copy.
EDEN_NX2_PB_SNAPSHOT=0 still disables it altogether.

Assisted-by: Claude Sonnet 5.5 (first version); Claude Opus 5.5 (bisect, suspension count, testing and commit message)
</content>
</entry>
<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>dma_pusher: restores the trees as the lorax wouldn't be happy without them (add IsGpuWrittenCommands method to check GPU-written entries)</title>
<updated>2026-11-02T00:06:48+00:00</updated>
<author>
<name>kraibse</name>
<email>33869366+kraibse@users.noreply.github.com</email>
</author>
<published>2026-11-02T00:06:48+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cirakg.xyz/eglantine-cirakg/commit/?id=6612817cb4b6da97c4fc88e232a8efa07a3704db'/>
<id>urn:sha1:6612817cb4b6da97c4fc88e232a8efa07a3704db</id>
<content type='text'>
</content>
</entry>
<entry>
<title>nx2: execute command lists as submitted</title>
<updated>2026-11-01T23:11:25+00:00</updated>
<author>
<name>kraibse</name>
<email>33869366+kraibse@users.noreply.github.com</email>
</author>
<published>2026-11-01T02:20:42+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cirakg.xyz/eglantine-cirakg/commit/?id=cce6d44af23f08a7287a66d745fec34e38c9eb25'/>
<id>urn:sha1:cce6d44af23f08a7287a66d745fec34e38c9eb25</id>
<content type='text'>
With the present waiting for the previous frame's fence, the game
refills command memory it already submitted while the GPU thread is
still running that frame, so some frames rendered into the wrong image.
Copy each entry's words at submit and execute the copy. Resumed entries
and ranges the GPU has newer words for still read memory.
EDEN_NX2_PB_SNAPSHOT=0 executes from memory.

Ported from Wael3rd/Eglantine-MKW (bd3119a86f).

Assisted-by: Claude Sonnet 5.5 (porting the fix)
(cherry picked from commit 408bb84d06ae0729697ef9bed2c2ba76ce6dff42)
</content>
</entry>
<entry>
<title>nx2: read command lists the GPU wrote from the GPU's copy</title>
<updated>2026-10-30T19:39:21+00:00</updated>
<author>
<name>Takoroka</name>
<email>137927095+Takoroka@users.noreply.github.com</email>
</author>
<published>2026-10-30T19:39:08+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cirakg.xyz/eglantine-cirakg/commit/?id=bef001c1515a13a9b8e361a5a7d372fc2e01094c'/>
<id>urn:sha1:bef001c1515a13a9b8e361a5a7d372fc2e01094c</id>
<content type='text'>
Mario Kart World runs small command lists (20-byte entries) that its
culling dispatches fill in each frame. Accurate GPU mode reads every
command list through the caches; Fast mode reads guest memory directly
(on the split's front thread too), where those entries were still the
words of an older frame, so the draws behind them were left out: the
trees around the courses vanished in Fast mode only.

The buffer cache now also marks the device pages the GPU writes (shader
stores, copies of GPU-written data) in a bitmap the split's front can
read. A command list on such a page waits for the back to run what was
queued before it and is flushed when its words are still only in host
buffers. In a race that is ~5% of command lists (13,500 a second of
262,000) and ~400 flushes a second.
</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: 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>
<entry>
<title>nx2: profile engine method calls and semaphore acquires; notes 140-141</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-29T13:45:30+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cirakg.xyz/eglantine-cirakg/commit/?id=24d3a1dbb3f2bb6dc5b8a515c1be1f7bad956b4b'/>
<id>urn:sha1:24d3a1dbb3f2bb6dc5b8a515c1be1f7bad956b4b</id>
<content type='text'>
EDEN_NX2_GPU_PROFILE now times engine method calls (the work a split GPU thread's back half
would run) and counts semaphore acquires and those that wait. Title 1: method calls ~343 ms
a second (6.9 million), front-half work (command parsing, macros) ~333 ms, acquires ~2,700 a
second of which ~220 wait. Notes 140 (macro compiler) and 141 (draw setup).
</content>
</entry>
<entry>
<title>nx2: measure the TSC on AMD, no rethrows for rejected shaders, debug hooks off the hot path</title>
<updated>2026-10-29T03:07:49+00:00</updated>
<author>
<name>Takoroka</name>
<email>137927095+Takoroka@users.noreply.github.com</email>
</author>
<published>2026-10-29T03:07:49+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cirakg.xyz/eglantine-cirakg/commit/?id=25b674eabdb92212a6d8149d6616b2af59317695'/>
<id>urn:sha1:25b674eabdb92212a6d8149d6616b2af59317695</id>
<content type='text'>
- AMD CPUs have no CPUID leaf 0x15, so the TSC frequency stayed 0 and
  every guest CNTPCT read went through QueryPerformanceCounter (~10% of
  the game's main core in title 1). Measure it like Intel CPUs without
  a crystal frequency.
- A rejected native shader was rethrown (two C++ throws) every time it
  was bound; return false instead (~1-2% of the GPU thread).
- The semaphore watch, pushbuffer entry hashing, first-write trace and
  per-macro debug logs ran on every command word or macro call; they
  now cost a flag check unless their environment variable is set
  (~4% of the GPU thread). Also starts the macro engine's profile zone.
</content>
</entry>
<entry>
<title>nx2: method data continues across GPFIFO entries</title>
<updated>2026-10-28T11:47:45+00:00</updated>
<author>
<name>Takoroka</name>
<email>137927095+Takoroka@users.noreply.github.com</email>
</author>
<published>2026-10-28T11:47:45+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cirakg.xyz/eglantine-cirakg/commit/?id=1d7758b714da7eede15664676007668bdee19946'/>
<id>urn:sha1:1d7758b714da7eede15664676007668bdee19946</id>
<content type='text'>
Title 4 calls a 3D macro with a 6-word IncreaseOnce header, ends the main
GPFIFO entry after the first word and supplies the other five in a 5-word
subroutine entry. The split-method parking (an entry elsewhere was treated
as a call with a clean method state) fed those parameters to the parser as
headers: the macro ran with garbage, later draws read megabytes of unmapped
memory and the host driver timed out at the loading screen after the dock
scene. As on the hardware, the method state now simply continues; the old
guess stays behind EDEN_NX2_PARK_SPLIT_METHODS.

Debug aids: splits are logged at debug level with the words around them,
and a 3D write that interrupts a macro's parameters dumps the last 48 writes.
</content>
</entry>
</feed>
