| Commit message (Collapse) | Author | Age | Files | Lines |
| ... | |
| | | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | | |
10e7063905 moved native program capture from one ReadBlock per instruction to
ReadBlockUnsafe per 4 KiB page. ReadBlockUnsafe skips the rasterizer flush, so
code that a GPU copy had written and not yet flushed to guest memory was
captured stale. The speed-up comes from reading a page at a time, not from
skipping the flush: read each page (and the odd single instruction outside a
fully mapped page) with ReadBlock, which flushes once per page instead of once
per instruction.
Follow-up to 10e7063905.
Assisted-by: Claude Sonnet 5.5 (implementation and commit message)
|
| | | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | | |
049c9633ed made TextureHeaderIndex take index / 32 for any texture index past the
pool that is a multiple of 32, in VisitImageView and in the shader environment.
That was written for Switch 2 handles that hold a header byte offset, but it ran
for Switch 1 games too, where such an out-of-range index used to give a null view
(and fail the shader environment's range check) and now binds an unrelated
header. Pass whether the memory manager uses native tiling, which is how Switch 2
titles are set up, and keep the previous behaviour otherwise.
Follow-up to 049c9633ed.
Assisted-by: Claude Sonnet 5.5 (implementation and commit message)
|
| | | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | | |
When BuildHandleProgram failed on a subtree it truncated the code back to where
the subtree started, which removed the Tee ops of the values the subtree had
kept, but their entries stayed in g_handle_slots. A Phi tries its other inputs
after the first one fails; if one of them reused a value from the dropped
subtree, it emitted a Load of a slot that nothing wrote, so the handle read 0.
Number slots with a counter instead of counting map entries, and on failure
erase the entries numbered from the subtree's first slot on and rewind the
counter, so such a value is built again.
Follow-up to 561f87abec.
Assisted-by: Claude Sonnet 5.5 (implementation and commit message)
|
| | | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | | |
BuildHandleProgram incremented g_handle_depth and decremented it at the end, so
a NotImplementedException from BuildHandleNode left the thread-local depth above
zero. That thread never cleared g_handle_slots again, and stale IR::Inst* keys
from an earlier program could match instructions of a later one (a freed
instruction's address can be reused). Do the decrement and the outermost clear in
SCOPE_EXIT.
Follow-up to e23b0f2fab.
Assisted-by: Claude Sonnet 5.5 (implementation and commit message)
|
| | | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | | |
561f87abec only gave TextureDescriptor a handle_program. Image load/store/atomics
and texture/image buffers whose handle comes from a storage buffer still got the
placeholder constant buffer address (index 0, offset 0), so the pipelines read
cbuf 0 word 0 as the handle (and asserted if cbuf 0 was unbound). Add
handle_program to TextureBufferDescriptor, ImageBufferDescriptor and
ImageDescriptor, compare it when merging, and let all four pipelines evaluate it
for every descriptor kind instead of only TextureDescriptor.
ImageQueryDimensions on such a handle was always declared Color2D, so array,
cube and 3D views got a 2D declaration. The instruction carries no type, so take
it from another instruction using the same handle program, falling back to
Color2D when there is none.
Follow-up to 561f87abec. The OpenGL pipeline edits are the same change as the
Vulkan ones but were not compiled here.
Assisted-by: Claude Sonnet 5.5 (implementation and commit message)
|
| | | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | | |
4d6a13e3d9 and 3d6156434a added bounds checks to the nx2:gpu 216 sparse
map path, but the region checks still compute gpu_address + size, which
wraps for a guest-controlled size. 3d6156434a only guards size == 0 and
the memory offset on the map path, so an unmap (memory handle 0) with a
huge size matches a region through the wrapped sum and reaches
Nx2SparseTile, whose own check wraps the same way, and then
smmu.Unmap(device, size) with a giant page count.
Reject a request whose end wraps the address space before it is used,
for map and unmap alike, with a warning like the existing unknown-memory
check. Also compare by subtraction in the region lookups here and in
Nx2SparseTile and Nx2BackSparse, so none of them depends on the sum.
Assisted-by: Claude Sonnet 5.5 (implementation and commit message)
|
| | | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | | |
31b901b93b checked the TOC with unchecked arithmetic on counts and
offsets read from the file. The record-table size (u64 count times
record size) and u32 first_child + child_count can wrap, so the bounds
checks pass and later reads go out of bounds; the same holds for the
TOC range, name ranges, file extents and the meta range. A directory
that lists its own ancestor as a child also made BuildDirTree recurse
until the stack overflowed.
Bound the counts by the TOC size before multiplying, compare ranges by
subtraction, and widen the child range to u64. Walk the directory graph
once after parsing with an explicit stack and reject cycles and nesting
deeper than 128, so BuildDirTree can no longer recurse without bound.
The file is rejected with ErrorNUPBadFormat.
Assisted-by: Claude Sonnet 5.5 (implementation and commit message)
|
| | | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | | |
31b901b93b only cached a zstd member while it fit the 512 MiB cache.
Anything larger was never cached, so every Read() allocated the full
uncompressed size and decompressed the whole extent again, which makes a
multi-GB RomFS read in small chunks unusably slow. Members between 256
and 512 MiB evicted each other on alternate reads, and Insert copied the
vector so memory briefly doubled. Two threads decompressing the same
member also left a duplicate LRU entry and a wrong byte count.
The writer emits one zstd frame per member, so there are no frame
boundaries to seek by. Members larger than half the cache are now
streamed once into a temporary file under the cache directory and read
from there, using bounded memory. The file is removed when the
container is released. Smaller members stay in the LRU, which now moves
the vector in and ignores a duplicate insert.
Assisted-by: Claude Sonnet 5.5 (implementation and commit message)
|
| | | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | | |
426f120ee8 dropped the 10 s wait and terminate() fallback when stopping
emulation, and ShutdownGame and closeEvent now wait for the emulation
thread with no limit. If the thread hangs (for example a GPU or present
deadlock), stopping a game, switching games or quitting never completes.
Keep the asynchronous teardown, but once the thread has been asked to
stop, give it 10 s and then terminate it and finish cleanup, as before.
ShutdownGame's nested event loop gets the same bound. A terminated
thread is logged as an error.
Assisted-by: Claude Sonnet 5.5 (implementation and commit message)
|
| | |/ / / / / / /
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | | |
Every texture whose handle is computed per draw gets the same placeholder
constant buffer address (index 0, offset 0), and Descriptors::Add did not
compare handle_program. Two such textures of the same type and depth in one
shader therefore shared a descriptor, so the second sampled the first, and one
could also merge with a real texture bound at constant buffer 0 offset 0.
Compare handle_program too.
The pixel-format-integer lookup cached its last answer by (index, offset), which
has the same problem for handle programs; skip that cache for them.
Follow-up to 561f87abec.
Assisted-by: Claude Sonnet 5.5 (implementation and commit message)
|
| |\ \ \ \ \ \ \ \
| | | | | | | | |
| | | | | | | | | |
buffer_cache: allow 32 storage buffers per stage
|
| | | |/ / / / / /
| |/| | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | | |
Native Switch 2 compute shaders (such as Donkey Kong Bananza) bind up to 18 global memory ranges, causing out-of-bounds binding errors:
HW.GPU <Error> buffer_cache.h:BindComputeStorageBuffer: Storage buffer index 16 exceeds maximum storage buffer count
HW.GPU <Error> buffer_cache.h:BindComputeStorageBuffer: Storage buffer index 17 exceeds maximum storage buffer count
followed by GPU driver access violations (0xc0000005).
The enabled and written storage buffer bitmasks (enabled_compute_storage_buffers and written_compute_storage_buffers) are already u32, so widening NUM_STORAGE_BUFFERS from 16 to 32 fits naturally within the existing 32-bit masks.
|
| |\ \ \ \ \ \ \ \
| |_|/ / / / / /
|/| | | | | | | |
nx2: decode sRGB in the upscale fallback when the program does (washed-out Splatoon Raiders)
|
| | | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | | |
Splatoon Raiders' upscaler program ends by decoding its result from
sRGB to linear (HSETP2 against 0.04045, HMUL2 by 2.4 between MUFU.LG2
and MUFU.EX2) before its surface store. The bilinear copy that stands in
for it while HMMA isn't emulated wrote the sRGB input as-is, so the
later passes encoded it a second time: outdoor scenes were washed out,
with a pale sky and a white haze.
When the program carries those two immediates, the copy now decodes
like it, through a new copy operation of the blit helper (a fragment
shader with the piecewise sRGB decode). Programs without them, such as
Kirby Air Riders' upscaler, keep the plain copy. The OpenGL backend
ignores the operation.
|
| |\ \ \ \ \ \ \ \
| | | | | | | | |
| | | | | | | | | |
nx2: read GPU-written command lists from copies instead of draining
|
| | | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | | |
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.
|
| |\ \ \ \ \ \ \ \ \
| |/ / / / / / / /
|/| | | | | | | | |
[emu-ui] Add a metadata mask to the NUP-packer
|
| | | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | | |
Convert to NUP now opens a dialog with the icon (preview, drop zone,
file picker, and a Use Detected button only when the dump has an icon),
the name, and the version (auto-detected or manual), next to the paths,
space estimate and low-storage option. The conversion runs in a window
with a full-width progress bar, percentage, speed and time remaining, and
a cancel that also covers closing the window.
Assisted-by: Claude Sonnet 5.5 (wrote the metadata dialog, icon drop zone and progress window)
|
| | | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | | |
Donkey Kong Bananza names its resource size table without a version, so
no version was found for a loose dump. Its GameData/GameDataList.Product
.320.* files carry it (3.2.0), so read them as well and use the newest
tag from either source.
Assisted-by: Claude Sonnet 5.5 (wrote the GameDataList version lookup and its test)
|
| | | |_|_|_|_|/ /
| |/| | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | | |
PackOptions::metadata overrides the title name, icon and display version
found in the dump. A version override is written to the base and to the
newest update, since the NUP loader reads the version from the newest
update first. ProbeMetadata reads what a dump would be packed with, the
version coming from the newest update that reports one, else the base.
Assisted-by: Claude Sonnet 5.5 (wrote the metadata overrides, ProbeMetadata and their test)
|
| |/ / / / / / /
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | |
| | | | | | | |
LooseDumpSize was removed, leaving path unused in addEntry. MSVC treats this as error C5233 through /we5233.
Assisted-by: Codex (diagnosis and one-line fix)
|
| | | | | | | |
| | | | | | |
| | | | | | |
| | | | | | | |
AppLoader_DeconstructedRomDirectory
|
| |\ \ \ \ \ \ \
| | |_|/ / / /
| |/| | | | | |
|
| | |\ \ \ \ \ \
| | | |/ / / /
| | |/| / / /
| | |_|/ / /
| |/| | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | | |
Resolved by area:
- audio feature_support.h: nx2's native revision handling.
- fiber.cpp: ours, which also drops the unused rewind stack.
- host_memory.cpp: ours granule bitmap and HintCold, plus nx2's
fallocate hole punching per whole dirty granule on Linux.
- texture_cache.h: nx2's old-age eviction pass, then our Collect().
- kepler_compute.cpp: shared upscale slots, then Fortune's Weave's,
then the Kirby Air Riders scan.
- nx2_gsv.h: ours, plus nx2's GetBufferMaxResolution and graphics
device ids (1-based).
- nvhost_ctrl_gpu.cpp: engine support flag bits 40-44.
- lower_to_maxwell.h: ours as the base, with nx2's seven lowering
commits applied one at a time. Second texture descriptor buffers
are read bindless in TEX, TLD.SCR (level zero) and SUST; FSEL
keeps its operand modifiers; TXD takes any channel mask.
lower_to_maxwell.h lowers 837 Fortune's Weave and 1183 Mario Kart
World shader dumps with the same rejects as nx2 and ours (12 and 0).
Assisted-by: Claude Sonnet 5.5 (conflict analysis and drafting)
|
| | | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | | |
buffer cache crash (#260)
* host_memory: punch holes in the backing on Linux instead of zero filling freed memory
Freeing guest memory zero filled the memfd backing with memset, which
commits every page it touches. fallocate(PUNCH_HOLE) hands the pages back
to the kernel instead, and they read as zero afterwards. Only the partial
pages at the ends are still cleared by hand.
Mario Kart World on Linux (RX 9070 XT, 31 GB): peak RSS 23.1 -> 15.9 GB.
EDEN_PUNCH_HOLE=0 restores the memset.
Assisted-by: Claude Opus 5.5 (debugging, profiling and code drafts)
* fiber: don't zero fill the stacks, untouched pages stay unbacked
The value initialised stack arrays were zero filled when each fiber was
made, which commits the whole stack. Left uninitialised, the pages a
fiber never touches stay unbacked. Together with the descriptor ring
change, about 1.2 GB less RSS in Mario Kart World.
Assisted-by: Claude Opus 5.5 (debugging, profiling and code drafts)
* vulkan: don't zero fill the descriptor update ring
Same as the fiber stacks: make_unique value initialised the whole ring
for every frame in flight. Entries are always written before they are
read, so allocate it without initialising it.
Assisted-by: Claude Opus 5.5 (debugging, profiling and code drafts)
* vulkan: wait for the GPU after an ASTC transcode decode like the other ASTC decodes
TranscodeAstcToBcn (astc_recompression Bc1/Bc3 with GPU decode) was the
only ASTC decode recorded with wait = false. On RADV (RX 9070 XT, Mesa)
Mario Kart World with BC3 flashed heavily all over the screen, while the
uncompressed GPU decode, which waits, did not. CPU decode with BC3 does
not flash either. Waiting after the transcode removes the flashing; full
pipeline barriers around its copy did not, so the wait hides a race
somewhere else rather than fixing one in the transcode itself.
Assisted-by: Claude Opus 5.5 (debugging, profiling and code drafts)
* vulkan: submit after an ASTC decode instead of waiting for the GPU by default
Every ASTC decode ended with scheduler.Finish(). Over a 19 minute Mario
Kart World Grand Prix that stalled the GPU thread 30.7 s in total, up to
1.2 s out of every 5 s while new textures stream in (track sections,
race starts), which is where the hitches were. Flushing keeps the
ordering that stops the BC3 flashing on RADV without the CPU waiting:
no flashing in play, and frames over 100 ms went from dozens to 3 in
about 7 minutes. EDEN_NX2_ASTC_FLUSH=0 restores the wait.
Assisted-by: Claude Opus 5.5 (debugging, profiling and code drafts)
* texture_cache: over the expected use, evict costly images unused for 1800 frames first
The collector never deletes CostlyLoad images outside aggressive mode, so
once a cup moves on, the previous tracks' textures stay resident and the
cache sits over its expected use deleting the cheap images still in use.
When over the expected use, costly images unused for 1800 frames (half a
minute) now go first.
Mario Kart World Grand Prix on an RX 9070 XT: frames over 20 ms 8.8% ->
4.0%, 58.7 fps average. EDEN_NX2_TC_OLD_AGE=<frames> sets the age, 0
turns it off.
Assisted-by: Claude Opus 5.5 (debugging, profiling and code drafts)
* buffer_cache: no buffer for device addresses past the page table
FindBuffer indexed page_table, which covers 2^36 bytes, with any address.
Mario Kart World crashed after about 4.5 minutes with a uniform buffer at
0x72253b2f2890 (FindBuffer <- UpdateUniformBuffers <- DrawEnd from a
macro), reading far past the table. Treat such an address as no buffer.
Where that address comes from is still unknown; this only stops the
crash.
Assisted-by: Claude Opus 5.5 (debugging, profiling and code drafts)
|
| | | | | | |
| | | | | |
| | | | | |
| | | | | | |
disable (#264)
|
| | | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | | |
--pack-nup (#271)
* file_sys: add a NUP packer for loose dumps
Packs a loose dump (exefs/romfs, base/, updates/<version>/ and
dlc/<titleid>/<n>/) into a NUP v1 container with the aligned record
layout. Every package is kept, files are deduplicated by SHA-256 and
compressed with zstd unless that does not shrink them, and files over
256 MiB are stored raw.
Output is byte-identical on every platform: compression is
single-threaded with every frame parameter set explicitly, and zstd is
always bundled so all builds use the same version.
A low-storage mode deletes each source file once its extent is synced
and journaled, and an interrupted run resumes from the journal.
Assisted-by: Claude Opus 5.5 (wrote the packer, its EdenPack-free dump detection, the aligned record layout and the deterministic zstd setup; ran the Raiders and Donkey Kong Bananza packs and boot checks)
* tests: cover the NUP packer
Round-trips a dump through NupContainer, checks standalone updates, a
bare exefs/romfs dump, low-storage resume and overwrite rejection, and
pins the hash of a packed dump so changes to the output are deliberate.
Assisted-by: Claude Opus 5.5 (wrote the tests, including the pinned output hash)
* qt: add Convert to NUP to the game list
Shown for loose dumps. Asks for confirmation with the estimated space,
offers low-storage mode, runs in the background with progress and
cancel, and resumes an interrupted low-storage conversion.
Assisted-by: Claude Opus 5.5 (wrote the Convert to NUP action and its progress and resume handling)
* cli: add --pack-nup <dump> [out.nup]
Assisted-by: Claude Opus 5.5 (wrote the --pack-nup option)
|
| | | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | | |
Splatoon Raiders draws with a 69-byte vertex stride and a packed 4-byte
attribute at byte 65. Those fetches are unaligned, which Vulkan leaves
undefined: NVIDIA reads them as meant, the AMD Windows driver does not,
and the outdoor scenes turn into a white haze with horizontal streaks.
When a binding uses that layout, a compute pass copies it to a 72-byte
stride with the tail moved to byte 68, and the vertex input offsets and
stride follow. EGLANTINE_TEST_VERTEX_REPACK=0 turns it off;
EGLANTINE_EXPERIMENTAL_STATIC_VERTEX_REPACK=1 also covers pipelines
without dynamic vertex input.
Based on an outside patch (02-portable-vertex-repacking). Changes from
it: a range over the device limits skips the repack instead of throwing,
and the pipeline cache version stays, so caches are kept.
|
| | | |/ / /
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | | |
Six frame generation settings are paired with frame_gen, so each widget
made its own checkbox and saved it to frame_gen on apply. The last one
won, so ticking only the first box left frame generation off.
Don't make a checkbox for a paired setting without the Paired
specialization. frame_gen is the only such setting, and it gets its own
widget again. Keep the pairing itself, Android uses it to hide the
options. On Qt, hide them while frame generation is off.
Fixes #251
Assisted-by: Claude Opus 5.5 (diagnosis, code and commit message)
Signed-off-by: spaina93 <72979505+spaina93@users.noreply.github.com>
|
| | | |\ \ \
| | | | | |
| | | | | | |
Fe render
|
| | | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | | |
Fire Emblem: Fortune's Weave opens the keyboard with library version
0x160012 and a 0x530-byte config. Read with the Switch 1 layout, the
byte taken as use_utf8 belonged to initial_string_offset, so the name
entry returned UTF-16 and the game kept only its first letter. The
text prefix of the common part keeps its layout; the flags, lengths,
string offsets and dictionary fields move (checked against the game's
nn::swkbd::keyboardConfig2kbdConfig). Version 0x140010 is unchanged.
Assisted-by: Claude Opus 5.5 (debugging, implementation and drafting)
Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
|
| | | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | | |
The one-frame blit left 3D edges aliased and shaking: the game jitters
its camera every frame for DLSS to accumulate. Fire Emblem: Fortune's
Weave's first DLSS pass (also rejected) has the motion vectors
(cbuf0+0x290, R16G16) and the frame's jitter (+0x1b0/+0x1b4, in input
pixels). Kepler compute keeps them, and the stand-in for the last
network pass now draws temporal_upscale.frag: input samples placed where
the jitter put them and weighted by distance, blended with the previous
result reprojected along the motion vectors (Catmull-Rom) and clipped to
the 3x3 neighbourhood in YCoCg. The history is copied from the result
right after drawing it, so post-processing the game later applies to its
output does not feed back. EDEN_NX2_TEMPORAL_UPSCALE=0 restores the blit.
Assisted-by: Claude Opus 5.5 (debugging, implementation and drafting)
Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
|
| | | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | | |
Every 3D frame of Fire Emblem: Fortune's Weave goes through its DLSS
network, which the HMMA lowering cannot run, so its 3D scenes stayed
black. The stand-in written for title 4 (handles at cbuf0+0x90/0xa0)
never matched it. The network's last pass reads the input colour through
cbuf0+0x328 and writes the output through cbuf0+0x348; when title 4's
pair does not fit, blit those instead.
Assisted-by: Claude Opus 5.5 (debugging, implementation and drafting)
Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
|
| | | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | | |
Fire Emblem: Fortune's Weave's enemy health gauges read only offset 0x40
of root table 0, which is inside the blit parameter block (title 4's
zero dither bias). The pass replaced it with zero and the gauges drew
black. A shader that reads only words the block leaves zero now keeps
its reads: an unbound bank reads zero anyway, and a bound root table
keeps its values.
Assisted-by: Claude Opus 5.5 (debugging, implementation and drafting)
Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
|
| | | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | | |
The 3D methods 0x504/0x508 write eight 256-byte root tables, which
shaders read as constant banks 24-31; NVN2 keeps push constants in table
0 (bank 17 after the Ampere lowering). Fire Emblem: Fortune's Weave
keeps its material constants there and never binds bank 17, and the
blit constants pass replaced those reads with render-target sizes,
flooding its 3D scenes red.
Maxwell3D now keeps the tables, the buffer cache streams table 0 as bank
17 when the game has not bound one, and the blit constants pass leaves
shaders that read bank 17 outside its parameter block alone.
Assisted-by: Claude Opus 5.5 (debugging, implementation and drafting)
Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
|
| | | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | | |
Command 106 was auto-stubbed, and Fire Emblem: Fortune's Weave treats
its empty reply as mode 0 and picks its 720p tier (rendering at 360p).
Report mode 4 (1440p) docked and 2 (1080p, the screen) handheld; the
game then renders at 720p and 540p and upscales to those.
EDEN_VI2_MAX_RESOLUTION_MODE overrides the mode.
Assisted-by: Claude Opus 5.5 (debugging, implementation and drafting)
Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
|
| | | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | | |
The check that a native callee keeps its link register read bits 16-23
of every instruction as a destination. RET was exempt, but BRA, NOP and
ISETP/FSETP (which write predicates) also have zero there, so callees
with an R0 link that compare or branch were rejected. IMAD.WIDE writes a
register pair, so its second register now counts as well.
Assisted-by: Claude Opus 5.5 (debugging, implementation and drafting)
Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
|
| | | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | | |
FSEL dropped the negate and absolute value modifiers of its sources.
Fire Emblem: Fortune's Weave's sky vertex shader builds its cube corners
with FSEL R, -1.0 forms: every corner came out +1.0, the cube collapsed
to one point and the sky was flat. SEL (integer) is unchanged.
Assisted-by: Claude Opus 5.5 (debugging, implementation and drafting)
Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
|
| | | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | | |
Other instruction forms Fire Emblem: Fortune's Weave's shaders use:
- I2F.F32.U64/S64 from a register pair, and F2I.S32.TRUNC without FTZ.
- FMNMX.NAN (an unordered pair gives the canonical NaN).
- FSET.BF with a uniform register operand (0xc0a), used by battle scene
shaders that were rejected and left the screen white.
- MATCH.ALL.U32, next to U64.
- IDP.2A.LO.U16.U8.
- USHF with UR16-UR27 (was UR0-UR15).
- STG with desc[URn][Ra.64] addressing, as LDG, and the LDG descriptor
form with any URn (was UR0 only).
Assisted-by: Claude Opus 5.5 (debugging, implementation and drafting)
Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
|
| | | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | | |
Address arithmetic in Fire Emblem: Fortune's Weave's shaders that the
lowering rejected:
- IADD3 with a third source, negated sources or two carry-outs, and
IADD3.X with two carry-ins.
- IMAD.X RZ, RZ, c, Pn and IMAD.X Ra, 1, ~c, Pn.
- IMAD.WIDE (register, immediate and cbuf pair forms) and IMAD.HI with
an addend, both with a carry-out.
- LEA with a carry-out, LEA.HI with a high source (a funnel shift), and
LEA with a uniform register (0xc11).
Assisted-by: Claude Opus 5.5 (debugging, implementation and drafting)
Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
|
| | | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | | |
Compute forms Fire Emblem: Fortune's Weave uses:
- REDUX.OR and REDUX.MIN (unsigned), next to SUM and MAX. Inactive lanes
give the identity (all ones for MIN).
- ATOMS.MIN, MAX and OR (U32); the native operation field numbers them
as Maxwell's.
- LDG with desc[URn][Ra.64] addressing: the uniform pair is a memory
descriptor (cache policy), so Ra alone is the address.
- BAR.SYNC.DEFER_BLOCKING (bit 80), the usual workgroup barrier.
Assisted-by: Claude Opus 5.5 (debugging, implementation and drafting)
Signed-off-by: duck912 <350528965+Duck912@users.noreply.github.com>
Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
|
| | | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | | |
Forms Fire Emblem: Fortune's Weave's shaders use that the lowering
rejected, mostly 64-bit address and index arithmetic:
- ISETP.EX: EQ/NE as the high comparison ANDed/ORed with the low words'
predicate, unsigned LT/LE/GT/GE as (hi < or > hi) || (hi == hi && low).
- IMAD.HI signed (bit 73), and with a constant buffer multiplier (0xa27).
- IMAD.X Rd, Ra, 1, Rc, Pn (an add with carry).
- IADD3.X with a register first source or a uniform operand, and IADD3
with a uniform operand and a carry out.
- LEA.HI.X (carry in) with a register base, and LEA.HI.X.SX32 with a
constant base.
- SHF with a constant buffer shift amount (0xa19).
- IMNMX with a negative immediate.
- F2I.FTZ.U64.TRUNC (0x311).
Assisted-by: Claude Opus 5.5 (debugging, implementation and drafting)
Signed-off-by: duck912 <350528965+Duck912@users.noreply.github.com>
Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
|
| | | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | | |
Maxwell's bound texture instructions read every descriptor from one
constant buffer per program, but Fire Emblem: Fortune's Weave's shaders
sample from more than one (bindings 4-7, 14 and 15 next to an earlier one). The
lowering rejected the second binding, so most of its graphics programs
failed and 3D scenes stayed black.
A binding that conflicts with the program's buffer is now read bindless:
the handle is loaded from its buffer with an unpredicated MOV and passed
as the first meta register of TEX.B, TLD.B or SUST.B. The TEXS fast path
and the array depth form check the buffer instead of setting it to 2.
Also lowered: TEX with the handle in a register (0x361, packed or not) or
a uniform register (0xf60), TXQ on any binding and the mip count query,
TXQ.B (0x370), TXD with any channel mask and .NODEP, and SUST.STRONG.GPU
fenced with MEMBAR.GL on both sides.
Assisted-by: Claude Opus 5.5 (debugging, implementation and drafting)
Signed-off-by: duck912 <350528965+Duck912@users.noreply.github.com>
Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
|
| | | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | | |
The vi2 session is served by AM's thread on guest core 3, so the host
sleep in PaceToVblank held that core for most of every frame. Game
threads scheduled there only ran between presents: Fire Emblem:
Fortune's Weave's loader got one RomFS read per frame (33 ms apart
instead of about 4 ms), which doubled its load times.
Assisted-by: Claude Opus 5.5 (debugging, implementation and drafting)
Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
|
| | | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | | |
Fire Emblem: Fortune's Weave's movie player queries (428) and maps (426)
each decoder output image, then blits it (RGBA, format 0xd5, block-linear
with 16-GOB blocks) into a texture of its own. The pool memory is process
memory (114) that no GPU mapping covered, so the blit read zeros and the
movies were black.
For decoder images, 426 now maps the image at its own address for the
GPU unless a mapping already covers it, and replies with the address,
the last byte's address and the image descriptor as our Eden tree does.
427 drops the mapping after the last unmap, as do 430 and 112. Images the
client reads on the GPU are written as block-linear RGBA, and the GPU
caches are invalidated after each frame. NV12 images and images read
with 961 keep the pitch-linear layout.
Assisted-by: Claude Opus 5.5 (debugging, implementation and drafting)
Signed-off-by: duck912 <350528965+Duck912@users.noreply.github.com>
|
| | | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | | |
Present word 12 holds (swap interval << 16) | refresh rate. Presents were
always held to the next 60 Hz vblank, so Fire Emblem: Fortune's Weave,
which sends 0x2003c (interval 2) after its boot logos, ran at 60 fps and
double speed instead of 30.
Pace each present by its interval and rate (interval clamped to 1-4, rate
60 if outside 30-240 Hz) and log when the word changes.
EDEN_NX2_SWAP_INTERVAL=<n> forces the interval.
Assisted-by: Claude Opus 5.5 (debugging, implementation and drafting)
Signed-off-by: duck912 <350528965+Duck912@users.noreply.github.com>
|
| | | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | | |
Each address space allocated its own SMMU range for the same memory
outside the heap. The caches key memory by device address, so these were
separate copies, and presentation used whichever range was recorded
last: Fire Emblem: Fortune's Weave drew into one alias while VI showed
another, and the screen stayed black.
Key these ranges by (ASID, CPU address, size) and count references. The
first address space allocates the range, the last release frees it, and
a closed session's entries are dropped so a reused ASID can't inherit
them. EDEN_NX2_PRIVATE_DEVICE_RANGES=1 restores a range per address
space.
Assisted-by: Claude Opus 5.5 (debugging, implementation and drafting)
Signed-off-by: duck912 <350528965+Duck912@users.noreply.github.com>
|
| | | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | | |
GetHdrStatus returns a u64 output format after the result. The bare
success reply left it to stale reply words, and Fire Emblem: Fortune's
Weave set up HDR output from them: its tone map constants came out NaN
and every frame was black. Report format 1 (SDR) for the "default"
display.
Assisted-by: Claude Opus 5.5 (debugging and drafting)
Signed-off-by: duck912 <350528965+Duck912@users.noreply.github.com>
|
| | | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | | |
Present word 7 holds the size of the frame drawn into the image's
top-left corner, and image preference word 6 its format (1 RGBA8,
4 RGB10A2). Fire Emblem: Fortune's Weave draws 1280x720 RGB10A2 frames
into 3840x2160 images; showing the whole image as RGBA8 gave a corner
of wrongly decoded pixels.
Assisted-by: Claude Opus 5.5 (debugging, porting and drafting)
Signed-off-by: duck912 <350528965+Duck912@users.noreply.github.com>
|
| | | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | |
| | | | | | |
Switch 2 titles send revision 16 with the 'REv' magic and use the
voice crossfade fields. Without them GetWorkBufferSize failed with
0xc0299 and Fire Emblem: Fortune's Weave aborted (2153-1537). Ported
from the Eden NS2 tree, keeping Eglantine's lenient revision compare.
Assisted-by: Claude Opus 5.5 (debugging, porting and drafting)
Signed-off-by: duck912 <350528965+Duck912@users.noreply.github.com>
|