Repository navigation
Conversation
…ports upstream 1f52ac7) (zortos293#659) * fsp: no SD card read throttle for Switch 2 titles IStorage::Read sleeps to emulate a 40 MB/s Switch 1 card, charging up to 64 KiB per read (Eden cbd4cf2, for Mario Strikers' intro). Switch 2 storage is many times faster. Ocarina of Time streams its title movie with 300-460 reads a second on the thread that also returns decoder images, so that thread slept for much of each second. Switch 1 titles keep the throttle. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * am: serve the Switch 2 graphics system on three host threads nx2:gsv comes from ISelfController, so it and every session it hands out (vi2, vdecsvc, syncpt, gpu, nvsrv) run on AM's server, which had one host thread. vi2's PresentClientBuffer blocks until the frame's fence and the next vblank, about 14 ms of each 16.7 ms frame at 60 fps, and every other request queued behind it. In Ocarina of Time the movie thread's decoder calls took 1.2 ms each instead of 0.1 ms; it returned decoder images at about 33 a second while presenting at 60, and the title movie fell 10 s behind its audio. With two more threads it falls 4 s behind, all at start-up; the rest is the input queue (next commit in the series). Each service keeps its own lock, as with bsdsocket's extra threads. ServerManager::LoopProcess now joins its additional threads before it returns, so state a server keeps on its caller's stack (AM's WindowSystem) outlives any request they are still handling at shutdown. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * core: refuse video decoder packets with nn::codec 3603 when the input queue is full The SDK refuses a packet with nn::codec 3603 when the decoder cannot take it, and the client retries after the submission-ready event. Ocarina of Time's movie player feeds DecodeAsync until it fails. Accepting every packet let it queue its whole title movie (~2,600 packets in 20 s); its pictures came at 20-28 fps until then and the video started ~11 s behind its audio. SubmitInput now refuses from 24 queued packets, 3x the readiness watermark of 8. Players that send one packet per ready signal and ignore the result (Mario Tennis Fever, zortos293#49) never reach it, because the auto-clear event stops at 8. End of stream is never refused. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * core: document Nx2VideoInputQueue::Full Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * nx2: drop late movie frames so the picture keeps up with the sound Ocarina of Time shows one decoded frame per frame it draws and never skips one, while the movie's audio plays in real time. Below 60 fps the picture falls further behind the sound with every frame: in a user's log the opening cutscene (7040 frames, 117 s) took 148 s at 48 fps and ended about 30 s behind its audio. The title video falls behind the same way (Eglantine-Community/Eglantine#629). The video session now keeps a movie clock, started from the frames the game acquires. When an output image comes free, decoded frames that a later frame has already overtaken on that clock are dropped without being converted or written, so the next image holds the frame the sound is at. Frames are only dropped, never held back, and never the end-of-stream frame. A gap of over 1 s between acquires (a pause) or a lag over 3 s restarts the clock instead, as do flush, stop, finalize and a new configure. Streams without rising timestamps are left alone. At full speed nothing is dropped. EDEN_NX2_VDEC_PACE=0 turns it off. The decoder log line now counts the dropped frames. Assisted-by: Claude Opus 5.5 (debugging, implementation, commit message draft) Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com> * nx2: log how far movie frames lag their timestamps Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * nx2: pace movies unconditionally (no EDEN_NX2_VDEC_PACE switch) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * service: lock domain handler tables and applet messages for AM's extra host threads Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * nx2: restart the movie clock after an emulator pause; am: lock the context stack and user channel Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * service: read the domain flag atomically Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --------- Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com> Co-authored-by: BlAnK182C-bak <207436459+BlAnK182C-bak@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Duck912 <350528965+Duck912@users.noreply.github.com> Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
…urations again (Mario Kart World 30 fps lock) (zortos293#664) * video_core: scale Ampere GPU time since the last present under Boost and Overclock Since zortos293#84, Switch 2 report timestamps are CoreTiming nanoseconds and the GPU Clocks setting no longer affects them. Ocarina of Time sizes its dynamic resolution from GPU marker durations within a frame, and emulated GPU work measured in host wall-clock time keeps it at 854x480. Boost now divides the time since the last present by 4 and Overclock by 16; Normal keeps exact nanoseconds. A timestamp never runs ahead of CPU time and trails it by less than the time since that present, and it stays monotonic when the anchor moves, so CPU/GPU calibrations such as Star Fox's frame throttle keep the same clock domain. With a divisor of 4 (the EDEN_NX2_GPU_TIME_DIV experiment) Ocarina rose to 1920x1080. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * video_core: latch the GPU clock with each present and keep Ampere time exact before the first one GPU Clocks can change while a game runs. Reading it per report let a change mid-frame move timestamps backward (Normal at P + 12 ms gave P + 12 ms, Boost at P + 13 ms gave P + 3.25 ms). The clock is now latched with the present time in one atomic word, so a change applies at the next present, where timestamps stay monotonic. Before the first present the anchor was zero, so Boost returned host uptime / 4 while nvdrv GetGpuTime returned full uptime. Timestamps are now exact until the first present. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --------- Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
… (EGLA-67) (zortos293#679) Imports the EASY AMD fixes from the CheezerWheezer/Lichii survey (EGLA-67): occlusion query last-query wait on AMD, non-Dref compare sampler variant, blend key rebuild without EDS3 blend, null texture for out-of-range TIC handles, pipeline cache reset on driver rejection, zortos293#448 uneven BCn mips stay RGBA8 on AMD, zortos293#555 preloaded pipelines kept from eviction, docs/nx2/amd.md (zortos293#437). Not run on AMD hardware. Co-authored-by: conongnang <conongnang@users.noreply.github.com> Co-authored-by: chuppatricky <74110004+chuppatricky@users.noreply.github.com> Co-authored-by: sharkiix <Shakoquo@users.noreply.github.com> Co-authored-by: Erick <ezava85@gmail.com> Co-authored-by: persluffy-cl <hansgamers1999@gmail.com> Co-authored-by: ne1i <valentinfroment7@gmail.com> Co-authored-by: EtienneDefranc <156627201+EtienneDefranc@users.noreply.github.com>
… 2, AMD fixes Three commits Zortos merged since the last sync: - zortos293#659 is Zortos's version of the movie sync this tree took from zortos293#571 in #12. It also brings what serving AM on three host threads needs and zortos293#571 lacked: sessions cloned from one domain share a manager, so domain handlers are now guarded (appending one returned a count another thread could change); the applet's launch parameters, message queue and context stack are taken under its lock; and CoreTiming's pause end time is atomic. Its movie clock (emulated time, pause aware) is left out: this tree's late-frame dropping keeps Ocarina's title movie in time here (0.15 s at 20 s), so nx2_gsv.h stays as it was, with the same decoder backpressure. - zortos293#664 makes GPU Clocks Boost and Overclock scale Switch 2 GPU durations again (Normal is exact): Ocarina sizes its dynamic resolution from them, and under Boost it renders at 1920x1080 instead of 854x480. - zortos293#679 imports AMD fixes (occlusion query wait, compare samplers, blend keys without EDS3 blend, null textures), documented in docs/nx2/amd.md. Nothing here runs on AMD. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Starting a game with a missing mod root could dereference a null directory: PatchExeFS always put the SD mod root into its patch dirs and then named every entry; ApplyLayeredFS returned early only when both roots were missing; and the BIS and SDMC factories passed a null root on. NUP titles reach ApplyLayeredFS at every boot (zortos293#203). Each missing root is skipped now. The new test, with no filesystem factories, crashed before. Port of Zortos zortos293#686, upstream Eglantine 34a791d (zortos293#728) by SmileyTatsu. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With delayed fence operations (accurate GPU with default fences, or balanced or accurate fence behaviour), a semaphore release without a fence waits in FenceManager::SyncOperation for the next fence. A channel whose acquire missed released the fences once and suspended; CanResumeAcquire then only re-read the semaphore, so a release queued after that waited for a fence nobody made once every channel was suspended, and the GPU stopped with "waits on semaphore". The recheck now releases the fences again, at most once a millisecond, while fence operations are delayed. Default fences at lower accuracy are unchanged. No test reaches a suspended channel without a System. Port of Zortos zortos293#687 (fixes zortos293#540), upstream Eglantine 90ff431 by kraibse. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…te mode With GPU accuracy Accurate (no split), CallMethodSlow asserted unless every write during a macro call went to executing_macro + 1, but NVN writes increasing runs over several macro registers and all of them are the macro's parameters (ProcessMacro appends them, as the split front does): only a write to an ordinary register while a macro collects is reported now. And MacroEngine::Execute re-read native macros' parameters from guest memory after the pusher had fetched them, which could only pick up memory reused since; native MME now runs the fetched words, as FrontRunMacro does. HLE and interpreter macros keep their refresh. Fast and split modes are unchanged. Port of Zortos zortos293#688 (fixes zortos293#538, refs zortos293#183, zortos293#598). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d CPUs On Linux, LinuxProcessors() classified cores by cpu_capacity, which hybrid Intel CPUs report as 1024 for P- and E-cores alike (an i7-12700K or i7-12700H), so every core counted as a performance core and the GPU thread pinning of zortos293#530 could put the GPU threads or the guest on E-cores. It now reads the kernel's P-core list (/sys/bus/event_source/devices/cpu_core/cpus) where there is one, parsed by Common::ParseCpuList with a test, and keeps cpu_capacity elsewhere. Pinning stays off by default. Port of Zortos zortos293#693, whose author measured pinning on against off in Ocarina of Time at 1080p on an i7-12700K with RADV: 50.86 against 48.79 fps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The matrix lambda's parameter shadowed the function's own columns parameter, which GCC 16 reports under -Wshadow; ENABLE_WERROR is on by default, so the build failed there (Zortos issue zortos293#674). Renamed, with no change in what is emitted. Port of Zortos zortos293#681. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The logging code calls format_string::get, which fmt has only from version 10, but a system fmt 8 or 9 was accepted (Ubuntu 22.04 ships one), so the build failed instead of taking the bundled fmt 12. The minimum is 10 now, and older system copies fall back to the bundled one. Port of Zortos zortos293#682 (fixes zortos293#668). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…for it With the hybrid P-core detection of the previous commit, pin_gpu_threads puts the split GPU thread's front and back on a performance core each and the guest on the other performance cores. In Ocarina of Time on an i7-12700H with an RTX 3050 Laptop, alternating runs with it off and on: 24.4 and 25.3 against 26.9 and 26.1 fps in Kokiri Forest at half resolution, and 34.8 against 36.8 fps in Link's house at native resolution. Presets now turn it on where Common::CanPinGpuThreads says the host has the cores (six physical performance cores on Windows or Linux) and off elsewhere; the detected host profile carries it, and the Performance page says so (Spanish translation updated). Tested in performance_presets.cpp. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A decoder output image (gsv 911) is written pitch-linear until the client first asks for it with gsv 428/426, and block-linear RGBA after. Nintendo Switch 2 Welcome Tour draws its "How Rumble Works" slide once, from its clip's first frame, decoded before that first query, so the GPU read a pitch-linear (and for code 5 BGRA) frame as block-linear and the slide came out sheared. The image now remembers it holds a pitch-linear frame, and the first 428/426 rewrites it in place as block-linear RGBA, swapping channels if needed, and invalidates the GPU's copy of the region. Port of Zortos zortos293#689, a cherry-pick of 42fd03b23e by Jonas (jojo-chaechae) from Eglantine zortos293#699. Not tested here: nothing on this machine runs Welcome Tour. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With a firmware installed, Mario Tennis Fever drew its controller button icons as "?": Switch 2 titles look them up in the standard font (type 0), and the firmware's standard font has no private-use glyphs; they are in the extension font (type 5). Service::NS::MergeGlyphs copies the 24 button glyphs into a copy of the standard font, which the Switch 2 font commands serve as type 0; when the fonts can't be merged, or the standard font already has them (the synthesized no-firmware font), the firmware's font is served as before. Bounds-checked table reads, with tests in font_merge.cpp. Port of Zortos zortos293#691, a cherry-pick of 34bf6746b3 by ymatrix1 (Yuri Olive) from Eglantine zortos293#534. Not tested in game here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… out Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…uery walks early InvalidationAccumulator::Add took the range size before aligning the address down to its 32-byte block, so a write starting past its block's start got a range ending short of it: a lone word at 0x54 invalidated [0x40, 0x4c), missing the word itself. Inline uploads and constant buffer data written from mid-block (WriteWordsCached, WriteBlockCached) left the rest of the first block uninvalidated, so storage buffers, textures and shaders over those words could keep stale data. The bug dates back to yuzu. QueryCacheBase::IterateCache tested std::invoke_result (the trait type) instead of invoke_result_t, so callbacks returning bool never ended the walk early. IsRegionGpuModified now stops at the first dirty query; SemiFlushRegion's callback no longer returns a value, so it still writes every final value. Ported from Zortos PR 700, which cherry-picks ProphetWild/ocarina b3ce9f1 (a port of nemyu 99c953389 and Orchid d38d025) without its experiment switch, and adds the tests. On the old code the first one gets a 12-byte range for the word at 0x1054 instead of its 32-byte block. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
EDEN_NX2_GPU_PROFILE, EDEN_NX2_CMDPAGE_DIAG, EDEN_NX2_DOWNLOAD_TRACE, EDEN_NX2_PB_CHECK, EDEN_NX2_3D_METHODS and EDEN_NX2_SEM_WATCH were read by namespace-scope initializers, which run before main() and so before the frontend puts nx2_switches.txt into the environment. Set in that file, the only way for a GUI launch, they did nothing. The profile, command page and download trace flags stay plain globals, since Enabled() runs several times per method write, and VideoCore::CreateGPU reads them again before any GPU thread starts. The DmaPusher and Maxwell3D switches become const members read when the channel is made. These six were the only namespace-scope switch reads. Ported from Zortos PR 714 (Segmentree), with a test that a switch set after startup takes effect when read again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A deferred clear begins its framebuffer's render pass with a variant whose load ops clear. RequestRenderpass compared the framebuffer's own pass with that variant, which never match, so the next draw ended the pass and began it again loading: on a tile-based GPU that stored the attachments just cleared and loaded them back, and the multisampled contents a variant discards (only tilers discard them) were lost after the first draw. On tilers the draws now stay in the variant, which is compatible since it differs only in load and store ops. A pass continues only while one is open, as ending a pass leaves the framebuffer it had in the state. Immediate-mode GPUs keep restarting. With draws continuing on every GPU, Ocarina of Time on the RTX 3050 Laptop restarted passes from draws about 135 times a second instead of 390, but ran at 35.0 against 35.5 fps in Link's house (nine alternating runs, slower in seven of them) and the same in Kokiri Forest. Ported from Zortos PR 699 (vouion/oot-test-stack-integration 19c5ff0 by Gavin Schiller, with Zortos's fix for an ended pass), limited to tilers, with the decision in render_pass_continuation.h and tested. Nothing here is a tiler, so nothing changes on this machine. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cores On a hybrid CPU with fewer than 8 performance logical processors, such as an i5-1235U (2 P-cores, 4 logical), the hybrid placement kept about ten time-critical threads (six guest cores, GPU front and back, Vulkan worker, timing, fencing) on those few processors. Its author measured Ocarina of Time in Kokiri Forest at 9.3 fps that way and at 11.5 fps with placement off (EDEN_HYBRID_CORES=0). Placement now needs 8 or more performance logical processors; below that the threads are left to Windows and the log says so. Ported from Zortos PR 698 (AxelBcr/oot-next fb0b747), with the decision moved to Common::UsesHybridPlacement so it is tested on every platform. Only Windows uses it, and nothing here runs Windows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The 2026 Steam Controller stops sending sensor reports while it stays
connected: after it reconnects, and when Steam Input changes its sensor
mode. UpdateMotion restarted sensors only when reports arrived all zero,
not when they stopped, so gyro and accelerometer stayed dead until the
emulator restarted. The issue also reports that motion mapping ("Shake!")
never detects the controller, probably from the same silence.
SDLDriver::PumpEvents now restarts the sensors of a connected controller
with motion that has been silent for a second, backing off to eight
seconds while it stays silent and back to one once reports arrive
(MotionStallWatch, tested). The restart runs under the joystick's lock,
outside the joystick map's.
From Zortos PR 712 (emiliopedrollo, fixes Zortos issue 710), whose author
tested it with the controller on Linux. Its other half, comparing motion
with the first value since mapping began, is left out: while mapping,
InputEngine::SetMotion already keeps the stored value from before mapping
began, so the comparison already has a fixed baseline.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Zortos pull requests 715, 712's first half, 635, 638 and 621, and Eglantine 292a68d, de4ed9d and 900ab5a, each with why it is not here. Also notes that Zortos issue 619 (a GPU hang on NVIDIA driver 580) did not happen in 13 minutes on driver 595. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #13: this branch contains its commits, so merging this merges both.
Five more open Zortos pull requests, each checked against this tree first, and the ones that turned out unneeded here recorded in
docs/ai/investigations.mdwith the reason.Changes
InvalidationAccumulator::Addtook the range size before aligning the address down, so a write starting mid-block missed the end of its last block: a word at0x1054invalidated 12 bytes from0x1040, missing the word itself. Inline uploads and constant buffer data could leave stale buffers, textures and shaders.QueryCacheBase::IterateCachetestedstd::invoke_resultinstead ofinvoke_result_t, soIsRegionGpuModifiednever stopped at the first dirty query. Tests from the PR.render_pass_continuation.hand tested.nx2_switches.txt. Six diagnostic switches (EDEN_NX2_GPU_PROFILE,_CMDPAGE_DIAG,_DOWNLOAD_TRACE,_PB_CHECK,_3D_METHODS,_SEM_WATCH) were read beforemain(), so setting them innx2_switches.txt(the GUI's only way) did nothing. Now they are read when the GPU or channel is made. These were all the namespace-scope switch reads insrc/. Includes a test.Common::UsesHybridPlacement, which is tested.SetMotionalready keeps the value from before mapping began, so the baseline it adds changes nothing here.Measured
Ocarina of Time (0400486024DEC000), i7-12700H, RTX 3050 Laptop, No sharpening, CPU ASTC. Builds alternated within each batch.
The GPU did less work with zortos293#699, but frame rates didn't rise and slipped slightly, so zortos293#699 applies only to tilers. The final build behaves as before on NVIDIA: 36.5 fps in Link's house, ~405 restarts a second.
Issue 286 (dialogue panel and HUD missing in half the frames, the reason for zortos293#715, reported on AMD) doesn't show here: in eight screenshots taken in a row in Kokiri Forest after Saria's cutscene, the hearts, minimap, button prompts and speech bubble are in all of them.
Testing
-Werror: every C++ test passes. Clang 20 build of the first two commits: passes.quick-checks.shandcheck_repo.pypass.nx2_switches.txt([Bugfix] video_core: read diagnostic switches after nx2_switches.txt loads zortos293/Lichii#714), Windows (common: leave threads to Windows on hybrid CPUs with few performance cores (Ocarina of Time) zortos293/Lichii#698), a Steam Controller (input_common: map motion from fast sensors and restart sensors that stop reporting (#710) zortos293/Lichii#712).🤖 Generated with Claude Code