github Djihads80/Eglantine build-194
Eglantine nx2 build 194 (09e539a)

latest releases: build-203, build-202, build-196...
pre-release3 hours ago

What's new in this build

Build 194 of nx2 (09e539a) is a batch merge — 145 files, +6,843/−695, 40 merges — and four games move:

  • Fire Emblem: Fortune's Weave now runs its own DLSS network as translated shaders instead of the FSR 3.1 stand-in, with a health check that falls back the moment the output stops making sense.
  • Mario Tennis Fever gets its text back, stops hanging at boot, stops having its geometry shaders refused, and stops losing the device three seconds into its first court.
  • Fast Fusion gets its track floor, minimap and sky back, and stops hanging at 0 fps while a race loads.
  • Pokopia's sky renders on the Steam Deck.

Around them: two Mario Kart World frame-pacing options, a shipped nx2_switches.txt of tuned Switch 2 defaults, and a wide performance and correctness batch.

Builds 190–193 have no release: 190 and 191 failed, 192 and 193 were cancelled when a newer push arrived, and only this final run published.

In short

  • The game's own DLSS (Fire Emblem: Fortune's Weave): new Graphics setting Use the game's own DLSS, on by default. Its 13-pass network runs on your GPU; NVIDIA DLSS (if you turn it on) is tried first, then the game's own network, then AMD FSR 3.1. A status line under the checkbox says what is drawing right now and why.
  • Mario Tennis Fever: missing text and wrong font fixed, boot hang fixed, geometry shaders no longer refused, and a framebuffer created with the wrong layer count — which wrote ~2 MiB past its allocation and lost the device — fixed. The kernel also gives the client's core the run it needs before an HLE reply wakes it, which this game's boot depends on.
  • Fast Fusion: more Ampere instruction forms lowered (the floor's I2F.S16, TLD.SCR.LZ with a uniform handle, SHFL.DOWN, WARPSYNC, SUST.P.R and more), the sky's depth size query built after its descriptor is known, and G8R24 mapped to D24_UNORM_S8_UINT. The GPU-split hang while loading a race is fixed too: the front no longer reads command pages the back has not marked GPU-written yet.
  • Pokopia: the black sky on the Steam Deck is fixed (guarded ULEA, with #387's author credited), and more compute forms (LEA, SHF, UIADD3, DEPBAR, USHF) lower, so almost all of its shaders stop being rejected. Photographs in game are still black — separate issue.
  • Mario Kart World: 30 FPS mode and Mario Kart World: dynamic FPS (experimental) — two new checkboxes under Graphics → Advanced, off by default, applied only to that game, taking effect after restarting it. Dynamic FPS takes precedence, and EDEN_NX2_SWAP_INTERVAL still wins over both.
  • nx2_switches.txt ships with the build and is read when the GUI starts: EDEN_NX2_SPLIT=2 and EDEN_NX2_FENCE_BATCH=1 on, buffer downloads off (they cost 38–63% FPS), frame-ahead left commented out (it adds 1–2 frames of input latency), plus documented workarounds. Your own copy in the config dir wins over the shipped one.
  • Performance batch: descriptor reallocations eliminated, buffer-cache guards made cheap on the hot path, zero-copy chunked texture uploads, image downloads batched into one GPU wait, flat array lookups for image views and samplers, DMA fast-path batching, and 128-byte-aligned GPU split atomics.
  • Correctness: the page-table block id can no longer overflow and fake page contiguity (after 65,535 allocations), H.264 packet framing is detected per stream, audio in/out managers are no longer destroyed under their sessions, and newer AArch64 SIMD forms (SQDMULL, SQDMLAL, SQDMLSL, SQRSHRN, SQRSHL, …) are implemented.
  • Expect one shader-cache rebuild: the pipeline cache versions went up (Vulkan 20 → 21, OpenGL 17 → 18).

Fire Emblem: Fortune's Weave runs its own DLSS network

Fortune's Weave upscales with its own neural network on the console's tensor cores — 13 compute passes per frame from 13 dumped programs. Nine of those programs still failed to lower, so the network could not run and frames fell back to the FSR 3.1 replacement. All 13 lower now, and #478 added the network runner itself:

  • Setting: Graphics → Use the game's own DLSS (game_dlss_network), on by default, applied when a game starts. Order of preference: NVIDIA DLSS if you turned it on, then the game's own network, then AMD FSR 3.1.
  • Show, then check: the network's output is used once every pass has run in eight consecutive evaluations and the output has passed 30 health checks in a row (about a second). Until then FSR 3.1 draws over the output pass. Ten failed checks in a row drop the network for the session and the reason is logged.
  • The health check: a small compute pass compares the output's brightness against its input on a 32×18 grid of blocks and counts non-finite samples, read back through a ring of four host-visible buffers once the GPU is finished, so it never waits. A check fails if more than 3% of blocks are off by more than half, or if any sample is NaN or infinite. The thresholds come from the game: a working network mismatches at most 3 of 576 blocks, a frozen one 6–10%.
  • When it is not used: with resolution scaling (the game fixes its own image sizes), without Vulkan and compute shaders that can be made 32 threads wide (the network's matrix multiplies are emulated with subgroup shuffles), or on a GPU that rejects one of its passes. The reason is kept for the status line, which is refreshed every second.
  • Scope: matrix multiplies are only lowered for the passes of such an evaluation, so bigger networks in other titles are still rejected rather than compiled for minutes by the driver.

Measured by the author (RTX 5080, docked, 720p → 1440p): the title screen shows the network after 11 s and its 1,081 checks are all good; 95 s walking Kunlun Base gives 2,277 good checks, the worst with 3 of 576 blocks mismatched; a 150 s run into a battle shows it at 12 s with 995 good checks and no mismatched blocks. A deliberately frozen network is dropped and FSR 3.1 takes over, with the log saying why.

The lowering work behind it: HFMA2.RELU with a predicate operand, the packed-half HSET2 forms (0x233/0x433/0x633), LEA.HI.X with a high source, LDC.U8, LDSM with a uniform offset, MUFU.TANH through a new FPTanh operation, LDGSTS.E.BYPASS.128 as a synchronous LDG+STS, LDGDEPBAR/DEPBAR SB0 as MEMBAR.CTA, TRAP 0x95c, an EXIT whose trailing code is still called, and register pressure handled by copying native scratch registers (R246 and up) into an IR-only bank around each instruction that needs them (IR::NUM_REGS grows to 768). HMMA.1688/.16816 F16 now sums each product in f32 and rounds to half every eight products, checked against a CPU reference of the console's results. Offline, the game's 271-program corpus lowers 271/271 with matrix multiplies (was 262) and 261/271 without (was 259). Pragmata's DLSS programs lower 11/12; its TLD with a uniform handle (0xf66) is still missing.

Mario Tennis Fever: text, boot, and a lost device

Four separate causes, all fixed:

  • Missing text, wrong font (#393): the built-in font handling assumed every slot was available; when some were not, it reported the wrong font and loaded data from the wrong source. All the game's text renders again.
  • Boot hang: the game hung at launch; the fix is in #393 as well, and geometry shaders it needs are no longer refused.
  • Device lost three seconds after the title screen: the framebuffer took the largest layer count among its attachments, but Vulkan requires every attachment to have at least the framebuffer's layers. The game pairs a single-layer 512×335 colour target with a 4-layer 1024×1024 depth array when its first court loads, so the colour image was written as four layers, about 2 MiB past the end of its allocation. VK_EXT_device_fault reported an invalid write at the page right after its memory block. Framebuffers now use the fewest layers of their attachments.
  • The kernel window its boot depends on: early in boot its main thread starts six workers through a helper that captures its own stack frame, and the core-0 worker can only run while the main thread waits on IPC. HLE services answer almost instantly, so that worker was preempted before executing anything and read a reused stack frame. The client's core now runs its next ready thread before an HLE reply wakes the caller, as hardware does.

Fast Fusion: the track, the sky, and the loading hang

  • Missing ground and minimap: their shaders use I2F.S16, which the lowering rejected, so those draws were skipped. The auto-exposure chain and several others needed further Ampere forms — TLD.SCR.LZ with a uniform handle, BRA.CONV/.DIV, SHFL.DOWN, I2F/I2FP of immediates, WARPSYNC Rn, a call link set early, SUST.P.R, an EXIT a branch jumps over — all of which now lower.
  • Black tree-shaped blobs and washed-out exposure in the sky: the sky samples depth with texel coordinates, and texture_pass built the size query before the sample's descriptor was assigned, so it used descriptor 0's size — the sky panorama — and read the depth at the wrong scale. The query is now built once the descriptor is known, and G8R24, which the game samples its depth as, maps to D24_UNORM_S8_UINT.
  • 0 fps while a race loads: with the GPU thread split on (the default), the game's culling compute writes the arguments of its instanced draws into their own command entry. The split's back marks pages as GPU-written only when it runs that work, so the front, running ahead, read them as CPU-written and took stale words — an instance count of 0xbf800000 among them — which became about a million garbage draws and a lost device. Before reading an entry from a page not marked GPU-written, the front now waits for the compute and copy work still queued for the back and checks again: 700–900 waits a second in a race, with no measurable frame-rate cost.

Pokopia: the sky on the Steam Deck

The sky was black on Steam Deck because a guarded ULEA without .HI or a carry-out was not lowered; that part of #387 is now in, with its author credited as co-author. More compute forms (LEA, SHF, UIADD3, DEPBAR, USHF) lower as well, so nearly all of the game's shaders stop being rejected. In-game photographs still come out black — the author flags that as a separate issue and it is not fixed here.

Mario Kart World: 30 FPS and dynamic FPS

Two options under Graphics → Advanced, both off by default, both restricted to Mario Kart World and both taking effect after restarting the game:

  • Mario Kart World: 30 FPS mode — forces the game's native 30 FPS mode at normal game speed.
  • Mario Kart World: dynamic FPS (experimental) — enables the game's own switching between 30 and 60 FPS using whole-frame timing (including GPU wait) instead of CPU time, and adjusts VBlank pacing for this title. It does not force a fixed rate like 43 FPS; the game picks its mode. If both are ticked, dynamic FPS wins. EDEN_NX2_SWAP_INTERVAL still takes priority over both.

The patch is applied when Mario Kart World's main NSO program loads, by instruction pattern matching, and only when exactly one location matches — otherwise it is skipped with a warning in the log, which keeps a future game update from being patched at the wrong address. The author's own measurement: about 22 fps on a Ryzen 5 3600 with an RX 5700, unchanged in frame rate, but noticeably more playable because the game's internal timing follows the real frame time.

nx2_switches.txt: tuned Switch 2 defaults you can edit

A new file ships next to the executable and is read when the GUI starts, so EDEN_NX2_* switches apply to GUI launches without a shell:

  • On by default: EDEN_NX2_SPLIT=2 (offload method/macro execution to the back thread) and EDEN_NX2_FENCE_BATCH=1.
  • Off, with the reason written next to it: buffer downloads (copying back 90–220 MB/s of buffers the CPU never touches drops frame rate by 38–63%), and FRAMES_AHEAD (it adds 1–2 frames of input latency).
  • Documented workarounds: EDEN_NX2_RESETFIX for Donkey Kong Bananza's indirect draws, EDEN_NX2_NO_REACTIVE (now strictly opt-in — bypassing read traps measured 24 vs 29 fps in Mario Kart World), and EDEN_NX2_KEEP_ASTC, plus the tuning switches from earlier builds.
  • Precedence: a variable already in the environment wins; between files, your copy in %APPDATA%\eden\nx2_switches.txt or $XDG_CONFIG_HOME/eden/nx2_switches.txt wins over the shipped one, so updating never loses your edits.

Related: the BC3 recompression threshold for Switch 2 ASTC textures went from 12 to 20 GiB of VRAM (dense ASTC expands 16× when decoded to RGBA8), and reactive-flushing read-trap bypass is no longer automatic.

Performance and correctness batch

  • Descriptors and buffers: descriptor reallocations eliminated and stage texture buffer binding reworked; buffer synchronization, state transitions, stage bindings and pipeline key comparison fast-guarded on the hot path; consecutive non-execution DMA methods batched.
  • Textures: zero-copy chunked staging uploads for large 2D images, finishing between chunks so staging memory is reused; image downloads batched into a single GPU wait; diagnostic statistics skipped when debug logging is off; image views and samplers looked up in a flat array instead of hashing into an unordered_map dozens of times per draw; the environment read once instead of per call.
  • GPU split: ring atomics aligned to 128 bytes, and the diagnostic sorting gated.
  • Memory: the page-table block id (16 bits) could overflow after 65,535 allocations and make unrelated regions look contiguous; page contiguity is now validated; the previous backing is released when a GPU-only region is re-created.
  • Video: H.264 packet framing is detected per stream, so short NAL lengths are not mistaken for Annex-B start codes (#362); undecodable render-target formats are logged rather than guessed; the software blit refuses when either format is undecodable.
  • Audio: in/out managers are kept alive while their sessions are open and unregistered before destruction; libopus state stays on the host with fixed work-buffer sizes.
  • CPU (dynarmic): scalar SQDMLAL, SQDMLSL, SQDMULL, SQRSHRN, SQRSHRUN, UQRSHRN, SQRSHL and UQRSHL implemented, with register declarations fixed (they named general-purpose registers where vector ones were meant).
  • Smaller: the loader requires an update directory's name to be entirely numeric, says why a loose base dump with its data in an update cannot boot, macro position writes are bound-checked, constant buffer words past the end of the buffer are dropped, storage compare-and-swap loops are defined whenever they are used, the guest subgroup size is only forced for warp-level compute, and 0x59f is dropped from the lowering batch because it is SURED on Ampere.

Known issues and caveats

  • Pokopia's in-game photographs are still black; its sky is fixed.
  • Pragmata's DLSS programs lower 11 of 12 (TLD with a uniform handle is still missing).
  • The NVIDIA DLSS setting is still Windows-MSVC-only, as in build 187; the game's own network needs Vulkan and runs anywhere it can.
  • The socket and SSL compatibility changes in this build are labelled WIP by their author — pending review and testing — so treat LAN/network behaviour as unproven.

Coming from build 189?

Everything above. Nothing from 189 is missing: the two native-shader fixes are part of this batch.

Coming from build 183, 187 or 188?

Also new to you: NVIDIA DLSS in the Windows MSVC zip (187), the NUP tools (188), and the first build where Fortune's Weave's own network is usable.

How it works, for the technically curious

  • git diff build-189..build-194 is 145 files, +6,843/−695, with 40 merge commits in the batch — from #78 up to #478. The batch branch was merged with nx2 mid-way (903c86dc), which is where #465's tensor lowering met #443's geometry work and #413's DEPBAR.
  • src/video_core/game_dlss_status.{h,cpp}, vk_dlss_network_probe.{h,cpp} and dlss_network_probe.comp are the probe: VideoCore::GetGameDlssStatus is what the Graphics tab polls once a second.
  • 09e539a6 is the last commit: the LDGSTS barrier is only added to programs that actually issue async copies (uses_async_copy), which the merge had left unused and GCC's -Werror rejected — it broke the non-PGO Linux builds.
  • dist/nx2_switches.txt is installed next to the binary by src/yuzu/CMakeLists.txt and parsed in main.cpp (ParseSwitchFile), executable directory first, then the config directory.

Automatic build of nx2 at 09e539a.

Linux

Linux packages come as an AppImage (self-contained, needs glibc 2.39 or newer: Ubuntu 24.04, Fedora 40, Debian 13, Arch) and a tar.gz (uses your system libraries, so Qt 6 and the usual libraries must be installed).

Build Type Standard PGO (Recommended) Notes
amd64 AppImage · tar.gz AppImage · tar.gz Make the AppImage executable (chmod +x) and run it
ARM (aarch64) AppImage · tar.gz AppImage · tar.gz

Windows

Windows packages are in-place zip files: extract and run eglantine.exe, or eden-cli.exe from a terminal.

Build Type Standard PGO (Recommended) Notes
amd64 / x86_64 (MSVC) MSVC zip Use if you run into graphical issues on other builds
amd64 / x86_64 (MinGW) PGO zip Built with MinGW clang; bundles its own DLLs, no Visual C++ redistributable needed

macOS

Build Type Standard PGO (Recommended) Notes
arm64 (Apple Silicon) zip macOS 15 or newer. Not notarized: right-click and choose Open the first time, or run xattr -dr com.apple.quarantine eglantine.app. eden-cli is inside the app, in Contents/MacOS

The PGO builds are the same programs compiled with profile-guided optimization (clang plus Eglantine's profile); prefer them when your CPU supports it.

Don't miss a new Eglantine release

NewReleases is sending notifications on new releases.