aboutsummaryrefslogtreecommitdiff
path: root/src
Commit message (Collapse)AuthorAgeFilesLines
...
| * | | | | | | | video_core: flush GPU-written code when capturing native shadersSssnowyyy32 hours1-5/+5
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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)
| * | | | | | | | video_core: read texture handles as header offsets only on Switch 2Sssnowyyy32 hours3-6/+8
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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)
| * | | | | | | | shader: drop the slots of a failed handle subtree with its codeSssnowyyy32 hours1-4/+13
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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)
| * | | | | | | | shader: restore the handle build depth when a build throwsSssnowyyy32 hours1-4/+7
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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)
| * | | | | | | | shader: evaluate handle programs for image and texture buffer descriptorsSssnowyyy32 hours6-55/+82
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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)
| * | | | | | | | nx2: make the 216 sparse request range checks overflow-safeSssnowyyy32 hours2-5/+11
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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)
| * | | | | | | | file_sys: reject NUP tables with wrapping bounds or cyclic directoriesSssnowyyy32 hours3-15/+144
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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)
| * | | | | | | | file_sys: decompress large NUP zstd members onceSssnowyyy32 hours4-21/+205
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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)
| * | | | | | | | frontend: bound the wait for the emulation thread at shutdownSssnowyyy32 hours2-4/+30
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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)
| * | | | | | | | shader: tell handle-program textures apart when adding descriptorsSssnowyyy32 hours1-1/+6
| |/ / / / / / / | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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)
* | | | | | | | Merge pull request #113 from ymatrix1/fix/storage-buffers-32Jonas29 hours1-1/+2
|\ \ \ \ \ \ \ \ | | | | | | | | | | | | | | | | | | buffer_cache: allow 32 storage buffers per stage
| * | | | | | | | buffer_cache: allow 32 storage buffers per stageYuri Olive37 hours1-1/+2
| | |/ / / / / / | |/| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* | | | | | | | Merge pull request #284 from Djihads80/fix/nx2-upscale-fallback-srgbJonas29 hours6-2/+54
|\ \ \ \ \ \ \ \ | |_|/ / / / / / |/| | | | | | | nx2: decode sRGB in the upscale fallback when the program does (washed-out Splatoon Raiders)
| * | | | | | | nx2: decode sRGB in the upscale fallback when the program doesTakoroka44 hours6-2/+54
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* | | | | | | | Merge pull request #322 from Djihads80/fix/nx2-cmdlist-copiesnowhere0234 hours12-6/+478
|\ \ \ \ \ \ \ \ | | | | | | | | | | | | | | | | | | nx2: read GPU-written command lists from copies instead of draining
| * | | | | | | | nx2: read GPU-written command lists from copies instead of drainingTakoroka35 hours12-6/+478
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* | | | | | | | | Merge pull request #318 from Djihads80/feat/nup-packer-uikraibse35 hours9-64/+820
|\ \ \ \ \ \ \ \ \ | |/ / / / / / / / |/| | | | | | | | [emu-ui] Add a metadata mask to the NUP-packer
| * | | | | | | | qt: add a metadata dialog and a progress window to Convert to NUPkraibse35 hours5-44/+624
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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)
| * | | | | | | | loader: read the display version from GameDataList.Product.NNN tookraibse35 hours2-17/+52
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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)
| * | | | | | | | file_sys: let the NUP packer override and probe the name, icon and versionkraibse35 hours3-3/+144
| | |_|_|_|_|/ / | |/| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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)
* / | | | | | | qt_common: remove unused path capture to fix MSVC buildsnowstormxd36 hours1-1/+1
|/ / / / / / / | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | LooseDumpSize was removed, leaving path unused in addEntry. MSVC treats this as error C5233 through /we5233. Assisted-by: Codex (diagnosis and one-line fix)
* | | | | | | refactor: remove redundant EnsureRomFS call in ↵kraibse36 hours1-2/+0
| | | | | | | | | | | | | | | | | | | | | | | | | | | | AppLoader_DeconstructedRomDirectory
* | | | | | | Merge remote-tracking branch 'origin/nx2' into codex/upstream-loading-hotkeyskraibse37 hours205-953/+11078
|\ \ \ \ \ \ \ | | |_|/ / / / | |/| | | | |
| * | | | | | Merge nx2 into nx2-experimentalkraibse38 hours61-203/+4198
| |\ \ \ \ \ \ | | | |/ / / / | | |/| / / / | | |_|/ / / | |/| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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)
| | * | | | Linux and AMD: BC3 flashing on RADV, ASTC decode stalls, lower RAM usage, a ↵Whovian6444 hours8-15/+50
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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)
| | * | | | video_core/buffer_cache: fast-guard stage buffer updates and uniform buffer ↵ymatrix144 hours1-1/+18
| | | | | | | | | | | | | | | | | | | | | | | | disable (#264)
| | * | | | file_sys: add a deterministic NUP packer, Convert to NUP in Qt and eden-cli ↵Jonas44 hours12-1/+2156
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | --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)
| | * | | | vulkan: repack 69-byte vertices to 72 bytes (#281)Mako44 hours11-2/+397
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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.
| | * | | | qt: save frame generation settings (#283)spaina9344 hours2-4/+26
| | |/ / / | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
| | * | | Merge pull request #270 from Duck912/fe-rendernowhere022 days35-171/+1724
| | |\ \ \ | | | | | | | | | | | | Fe render
| | | * | | am: decode the native swkbd config for library version 0x160012Duck9122 days2-0/+68
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
| | | * | | video_core: temporal upscale stand-in for Fortune's Weave's DLSSDuck9122 days13-1/+610
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
| | | * | | kepler_compute: stand in for Fortune's Weave's DLSS with an upscaleDuck9122 days1-6/+15
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
| | | * | | shader: keep root table reads the blit constants would zeroDuck9122 days1-1/+11
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
| | | * | | video_core: keep root tables and bind table 0 as constant bank 17Duck9122 days4-0/+68
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
| | | * | | nx2:vi2: report the display's maximum buffer resolutionDuck9122 days1-0/+24
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
| | | * | | shader: count only register writes in the callee link checkDuck9122 days2-2/+34
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
| | | * | | shader: apply FSEL's floating operand modifiersDuck9122 days1-1/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
| | | * | | shader: lower more conversion, comparison and memory formsDuck9122 days1-28/+66
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
| | | * | | shader: lower more 64-bit integer carry formsDuck9122 days1-31/+171
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
| | | * | | shader: lower warp reductions, shared atomics and descriptor loadsDuck9122 days1-15/+32
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
| | | * | | shader: lower more integer formsDuck9122 days1-20/+127
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
| | | * | | shader: read extra texture descriptor buffers bindlessDuck9122 days1-43/+108
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
| | | * | | nx2:vi2: sleep in the guest kernel while pacing presentsDuck9122 days1-1/+8
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
| | | * | | nx2:gsv: map decoder images the client reads on the GPUDuck9122 days1-5/+153
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
| | | * | | nx2:vi2: pace presents by their swap intervalDuck9122 days1-4/+20
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
| | | * | | nvhost_as_gpu: share Switch 2 device ranges between a process's address spacesduck9122 days4-11/+90
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
| | | * | | nx2:vi2: reply to 104 with the display's output formatduck9122 days1-2/+23
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
| | | * | | nx2:vi2: crop presents to their frame size and honour RGB10A2 imagesduck9122 days5-3/+24
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
| | | * | | audio_core: accept the Switch 2 audio renderer revisionduck9122 days4-11/+35
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>