aboutsummaryrefslogtreecommitdiff
path: root/src/video_core
Commit message (Collapse)AuthorAgeFilesLines
* video_core: accept an empty Streamline device-extension listDuck9128 hours1-5/+4
| | | | | | | | | | | Streamline may report that DLSS needs no extra device extensions. The check required a non-empty list, so that result counted as "extensions unavailable": Streamline was stopped and FSR 3.1 used. Only require that every listed extension is supported. Found by CodeRabbit review. Assisted-by: Claude Opus 5.5 (implementation) Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
* video_core, yuzu: write NVIDIA DLSS file paths to logs as UTF-8Duck9128 hours1-7/+10
| | | | | | | | | | | | | | | The Streamline start-up and DLSS download code formatted paths with std::filesystem::path::string(), which on MSVC converts to the active code page and throws when a character has no mapping there, for example a user name in another script under %APPDATA%. The start-up log runs inside the renderer's constructor, which only catches vk::Exception, so such a user would crash at game start with the setting on. Use Common::FS::PathToUTF8String for every path in these logs and messages. Found by CodeRabbit review. Assisted-by: Claude Opus 5.5 (implementation) Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
* video_core: clear the DLSS output when Streamline writes nothing to itDuck9128 hours1-0/+39
| | | | | | | | | | | | | | | The upscaler records its work on the worker thread and reports success once it is queued. When Streamline then rejects the DLSS options, gives no frame token or fails the evaluation, nothing is written to the output image, but the caller still draws it into the game's image that frame: undefined contents after a resize, the previous frame otherwise. FSR 3.1 takes over from the next frame. Clear the output on those paths, with barriers around the clear, so that frame is black instead. Found by CodeRabbit review. Assisted-by: Claude Opus 5.5 (implementation) Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
* video_core: NVIDIA DLSS through NVIDIA Streamline in place of a game's DLSSDuck9129 hours14-17/+1255
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Adds a Graphics setting, "Use NVIDIA DLSS in place of a game's DLSS" (nvidia_dlss, off by default). When it is on, in Windows builds configured with EGLANTINE_STREAMLINE_SDK, the evaluation Eglantine already replaces with FSR 3.1 goes to NVIDIA DLSS on GeForce RTX cards, with the same inputs (colour, depth, motion vectors, jitter). When DLSS can't run, FSR 3.1 runs as before. Only Streamline's MIT-licensed headers are compiled in; nothing of NVIDIA's is linked or shipped. At run time Eglantine looks for sl.interposer.dll in the user folder's "streamline" folder (or EDEN_STREAMLINE_DIR, or "streamline" next to the executable), checks its Streamline signature and starts Streamline with manual hooking. Streamline's plugins come from that folder or the NVIDIA app's downloads. DLSS itself is nvngx_dlss.dll in the same folder, else the newest DLSS 310 or later that the NVIDIA app has downloaded, checked for NVIDIA's Authenticode signature and copied as streamline/nvidia-app/nvngx_dlss.dll. Like other tools that call DLSS outside a game, it uses its own fixed project id with the custom engine type. - Preset K for all modes (EDEN_NX2_DLSS_PRESET overrides it): the default Performance model (M) and L draw thin dark horizontal lines in some frames at 2x resolution scale; K doesn't. - HDR input with auto exposure; the mode follows the render/output ratio. - Buffer device address stays enabled when DLSS needs it, for DLSS only. - The upscaler waits for the device instead of submitting when it is destroyed: by then the game's channels are released, and a submit read the state tracker's stale flags (a crash when stopping a game). With the setting off, or in builds without the SDK path (the setting is hidden there), nothing changes. Testing: Windows 11, RTX 5080, Fire Emblem: Fortune's Weave docked at 1x (720p -> 1440p) and 2x (1440p -> 2880p), CLI runs and GUI play, stopping and restarting games with DLSS on. Not tested on other GPUs or games. Assisted-by: Claude Opus 5.5 (implementation, debugging) Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
* video_core: read the framebuffer before recording the upscaled-output blitDuck9129 hours1-7/+11
| | | | | | | | | | | | | | | BlitColor(VkImageView, VkImage, ...), which draws FSR 3.1's output into the game's DLSS output, captured the Framebuffer pointer and read its render pass, handle and size on the worker thread. The pointer points into the texture cache's framebuffer slots, which can be reallocated before the worker records the command, so the render pass could begin with a stale or null render pass and framebuffer. FSR 3.1 records quickly enough that this rarely shows; with a slower first evaluation (NVIDIA DLSS creating its feature) it crashed in vkCmdBeginRenderPass at the first evaluation in every run. Read the three values on the calling thread and capture those instead. Nothing else changes. Assisted-by: Claude Opus 5.5 (debugging, implementation) Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
* video_core: cut per-draw work on the GPU back thread in crowded scenes (#374)Duck19 hours2-3/+13
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * video_core: demote the texture cache's per-draw debug logs to trace The invalid sampler and image view index messages fire for unused binding slots on every draw. Filtered LOG_DEBUG messages still cost a call and argument packing: in a Fire Emblem: Fortune's Weave city scene (about 2,100 draws per frame) they were 3.1% of the GPUBack thread's samples. LOG_TRACE compiles them out of release builds. Assisted-by: Claude Opus 5.5 (profiling, porting and drafting) Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com> * texture_cache: read a descriptor with one page lookup DescriptorTable::Read runs for every texture and sampler of every draw, and it read each 32-byte TIC/TSC entry through the generic ReadBlockUnsafe page walk. In a Fire Emblem: Fortune's Weave city scene (about 2,100 draws per frame) that was 5.0% of the GPUBack thread's samples. An entry within one page is contiguous in host memory, so it is now a single page lookup and memcpy. Entries that cross a page and pages without host memory still take the block read, so unmapped and unbacked entries still read as zero. The same change in another Eden-based build cut these reads from 6.4% to 0.4% of its GPU thread. Assisted-by: Claude Opus 5.5 (profiling, porting and drafting) Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com> --------- Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
* nx2: fewer render pass splits on tiled GPUs, log failed GPU waits (Pokopia) ↵Alex20 hours2-2/+13
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | (#361) * buffer_cache: don't end the render pass after mapped buffer uploads Every upload set any_buffer_uploaded, and the next draw or dispatch then recorded a transfer-to-shader barrier outside the render pass. On Vulkan the uploads are mapped: each copy either records its own barriers (CopyBuffer with barrier set) or goes to the upload command buffer, which ends with a barrier before the frame's commands run. The extra barrier only ended the render pass. On tiled GPUs every such split writes the attachments out and reads them back. Pokopia's first gameplay scene had ~50 of these splits a frame. Without them, an M3 MacBook Air (MoltenVK, 1x docked) goes from ~35 to ~29.5 ms of GPU time a frame and from 28.5 to 32 fps. OpenGL uploads immediately and keeps the barrier. Assisted-by: Claude Opus 5.5 (profiling, implementation and commit message) * vulkan: log a failed GPU wait before it ends the process When the device is lost, vkWaitSemaphores in MasterSemaphore::Wait returns VK_ERROR_DEVICE_LOST and the exception goes uncaught on the fence thread or the GPU thread, so the process aborts without a line in the log: ReportLoss is only reached from submit and present. A Pokopia crash on macOS left the log ending a second before the abort, with no hint that the GPU was lost. Log the wait's result before rethrowing. On macOS, MoltenVK prints the Metal reason (a GPU hang or page fault) to stderr only. Assisted-by: Claude Opus 5.5 (diagnosis, implementation and commit message)
* video_core: fix the -Wshadow error in the FSR 3.1 upscalerJonas25 hours1-3/+3
| | | | | | Fsr3Upscaler::Pass::Dispatch took a scheduler parameter that shadows Fsr3Upscaler::scheduler, which fails the Windows MinGW PGO build under -Werror=shadow.
* Merge pull request #346 from Duck912/fe-fsr31nowhere0226 hours20-173/+1549
|\ | | | | FSR 3.1 implementation for DLSS games
| * Merge remote-tracking branch 'origin/nx2' into fe-fsr31Duck91227 hours44-145/+607
| |\ | | | | | | | | | | | | | | | # Conflicts: # src/video_core/renderer_vulkan/blit_image.cpp # src/video_core/renderer_vulkan/blit_image.h
| * | video_core: replace Fortune's Weave's DLSS with AMD FSR 3.1Duck91229 hours17-31/+1116
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Fire Emblem: Fortune's Weave's DLSS network can't run here, and the temporal stand-in is only an approximation of it. FSR 3.1 takes the same inputs DLSS does: the jittered colour, motion vectors, the jitter and the depth, which the game's first DLSS pass reads through cbuf0+0x298 (Z32, reversed, the colour's size). Kepler compute keeps it next to the motion vectors. Fsr3Upscaler ports the host side of the SDK's ffx_fsr3upscaler.cpp: the eight passes (prepare inputs, luma and shading-change pyramids, shading change, reactivity, luma instability, accumulate, RCAS), the internal images and the constants, recorded through the scheduler with the shaders from externals/FidelityFX-SDK. It takes HDR colour, render-size motion vectors and reversed depth, computes its own exposure, and uses the no-wave SPD variants on devices without compute quad operations. The SDK's GLSL uses separate textures and samplers, so DescriptorBankInfo gains sampled image and sampler counts (default 0). FSR's RCAS follows the RCAS Sharpness slider. The result goes to FSR's own RGBA16F image and is drawn into the game's output, which keeps its format. TextureCacheRuntime::TemporalUpscale runs FSR 3.1 first. Without the depth, at mismatched scales, on a device lacking FSR's formats or features, or if its pipelines fail to build, the stand-in runs instead, and the bilinear blit stays last. EDEN_NX2_DLSS_REPLACEMENT=standin forces the stand-in. A gap of more than 250 ms between evaluations restarts the history. The BlitColor overload that takes a raw image view transitions its source to SHADER_READ_ONLY_OPTIMAL but described it as GENERAL in the descriptor (a validation error); it now describes the layout it uses. Assisted-by: Claude Opus 5.5 (debugging, implementation and drafting) Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
| * | video_core: sharpen the temporal DLSS stand-inDuck91229 hours8-145/+436
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Fire Emblem: Fortune's Weave's DLSS input matches Eden's (same 720p image, same detail), but the stand-in's 1440p output was blurrier than a plain bilinear 2x of it (Laplacian 0.0066 vs 0.0081; Eden's real DLSS 0.0111), and the image drifted darker over time: - the sample kernel was about twice too wide for the output resolution; - the history was kept in the output's B10G11R11 format, whose 5-6 bit mantissas round away a frame's 0.03-0.1 share; - the 1-sigma neighbourhood clip removed detail that only some jitter positions sample (railings, thin edges). The history is now an RGBA16F pair the shader writes as a storage image, with no per-frame copy. Still pixels use a third of the kernel width and a 1.5-sigma clip, so detail from many jitter positions accumulates. Moving pixels keep the old kernel and 1-sigma clip, and so do pixels that moved recently or whose history falls far outside the neighbourhood (content that changes without motion vectors), remembered in the history's alpha. Static output goes from 0.0066 to 0.0102 with no brightness drift and no new ghosting. With resolution scaling the stand-in used to fall back to a bilinear blit. The images are now scaled up as BlitImage does, the jitter is scaled to host pixels and the history follows the framebuffer's render area. RCAS (temporal_sharpen.frag) sharpens a copy of each result, never the history, in range-compressed space since the output is HDR. Its strength is the sharpness slider, relabelled "RCAS Sharpness" (0% turns it off). EDEN_NX2_TEMPORAL_KERNEL, _CLIP, _KERNEL_MOTION, _CLIP_MOTION and _WEIGHT tune the filter (all four filter values at 1 give the old one), and EDEN_NX2_TEMPORAL_SHARPEN=<stops>|off overrides the slider. Assisted-by: Claude Opus 5.5 (debugging, implementation and drafting) Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
* | | nx2: video decoder: copy NV12 frames from a GPU decoder without swscaleJonas27 hours1-0/+14
| | | | | | | | | | | | | | | | | | | | | FFmpeg 6.1's swscale leaves the chroma plane of an NV12 to NV12 copy at zero, so movies decoded on the host GPU (Mario Kart World's pre-race movie, Hyrule Warriors' cutscenes) showed green. CPU-decoded frames (YUV420P) were not affected.
* | | nx2: vdecsvc picks H.264 when the configure carries no codec name and the ↵rdenno27 hours2-0/+67
| | | | | | | | | | | | | | | | | | stream is H.264 (Yoshi demo) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* | | [video_core/host1x] VP9 Video Playback Fixes (#4590)PavelBARABANOV27 hours2-19/+32
| |/ |/| | | | | | | | | | | | | | | | | | | | | | | | | | | - [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions). - [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability. ------------------- https://git.eden-emu.dev/eden-emu/eden/pulls/4542 Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4590 Reviewed-by: crueter <crueter@eden-emu.dev> Reviewed-by: John <john@eden-emu.dev> (cherry picked from commit 0731f40f4d86227f05da3fffbc44831065b53a8a) Co-Authored-By: Claude Code <noreply@anthropic.com> (cherry picked from commit 7c3821da0e678978d55df14d65e047539eafba4c)
* | Merge pull request #295 from rdenno/fix/texture-x8z24-componentsJonas27 hours1-0/+1
|\ \ | | | | | | texture_cache: look up X8Z24 with UNORM, UINT, UNORM, UNORM components
| * | texture_cache: look up X8Z24 with UNORM, UINT, UNORM, UNORM componentsrdenno39 hours1-0/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | X8Z24 was only known with UINT in the last three components. Mario Tennis Fever samples its depth buffer as X8Z24 with components UNORM, UINT, UNORM, UNORM (as S8Z24 already is in the table), which hit the "texture format=42" fallback to A8B8G8R8. The depth image was then copied into a colour image of the wrong format every frame (with "Unimplemented" layer-count asserts) and read as colour, and distant scenery around the court (the arch and the castle stadium) wasn't drawn. Map it to X8_D24_UNORM like the other X8Z24 entry. Assisted-by: Claude Opus 5.5 (diagnosis, fix and testing)
* | | Merge pull request #305 from Djihads80/fix/nx2-cache-version-fselJonas27 hours2-2/+2
|\ \ \ | | | | | | | | video_core: bump the shader cache versions for the FSEL lowering fix
| * | | video_core: bump the shader cache versions for the FSEL lowering fixTakoroka36 hours2-2/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The disk shader cache keeps the lowered native code. "shader: apply FSEL's floating operand modifiers" (ef3ae4ae23) changed that code without a version bump, so caches built before it keep programs that drop FSEL's negate until the user deletes them by hand. In Splatoon Raiders those stale programs leave the tutorial island and the dock with no shadows (the depth linearization ends with FSEL R0, -R0, 1.0, P and comes out negated), no aiming reticle and no steam (particle quads pick their corners with FSEL +0.5 / -0.5 and collapse to a point).
* | | | Merge pull request #334 from snowstormxd/codex/upstream-mkw-testJonas28 hours12-30/+266
|\ \ \ \ | | | | | | | | | | MKW performance improvements
| * | | | nx2: rearm clean read areas when the GPU writes them againsnowstormxd30 hours2-3/+14
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Port the coherency changes from alarok/Eglantine 77fc365f2 without its diagnostic framework or shutdown changes. Only GPU-dirty CPU reads become permanently preflushable, clean areas can be trapped on the next write, non-core readers avoid indexing core arrays, and collected CPU writes precede readback. Assisted-by: Codex (source review, selective integration and verification) (cherry picked from commit b64e211957180aa218ec6d9a3bcb020332279c3f)
| * | | | vulkan: submit native work sooner and use the active draw countsnowstormxd31 hours4-3/+24
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Adapted from sylvieistaken/selevet-eglantine performance builds, including 8b076b167ffc5ca1ba8ffedcd00e255accbe018c and d8c95fef. Preserve upstream command-list coherency and submission ordering. Assisted by Codex.
| * | | | texture_cache: clear only exposed descriptor bitmap wordssnowstormxd31 hours1-4/+9
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Avoid zeroing unused preallocation during invalidation and pool refresh. Clear newly exposed words whenever limits grow, bound clearing to allocated storage, and test word/allocation boundaries, shrink/regrowth and malformed large limits. Assisted-by: Codex (implementation, review, commit text and automated validation) (cherry picked from commit 4bc1ae01f79cef43be016504c850ca8a6998457a)
| * | | | tests: verify deferred descriptors against eager invalidationsnowstormxd31 hours1-2/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Exercise 40,000 mutations and table switches plus repeated deletion across five channels. Make the existing descriptor read work with a memory reader fixture and add an explicit CPU benchmark with opaque invalidation calls. Assisted-by: Codex (implementation, review, commit text and automated validation) (cherry picked from commit 3b62a551da8ec0b4edf19a1c4e14fa2519dd20e2)
| * | | | shader_cache: use sorted membership for large removal batchessnowstormxd31 hours1-4/+12
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Keep the linear path for sixteen or fewer removals. For larger batches, sort the auxiliary pointer list and binary-search it while preserving storage order and the same invalidation decisions. Existing real-cache differential tests cover both paths. Assisted-by: Codex (implementation, review, commit text and automated validation) (cherry picked from commit 7e2c8a535230d9810db07706d79130ce0f1b88f1)
| * | | | shader_cache: batch memory-write invalidations without skipping rangessnowstormxd31 hours3-5/+18
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Adapt the batching from ymatrix1/Eglantine PR #237, retaining all CPU invalidations. Acquire the lock once and remove pending shaders once per write batch. Compare real cache contents with sequential invalidation across randomized overlapping writes and pending removals. Assisted-by: Codex (implementation, review, commit text and automated validation) (cherry picked from commit b65f818d7789ffadfb58fe4543b18060fd88ce53)
| * | | | video_core/buffer_cache: reuse unchanged small uniform buffers within ↵gabrielskaminski32 hours3-4/+168
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | command buffer (cherry picked from commit 4aa5cd89fd1862751b3297036f2d21a0dc924b23) (cherry picked from commit f1bdd5b13a1bdca81243b4aa1d8529f0485d3671)
| * | | | gpu: make register-write history opt-in in release buildssnowstormxd32 hours2-0/+14
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Keep error reporting and debug-build history. EDEN_NX2_3D_HISTORY enables the full ring in release builds without recording every method during normal play. Assisted by Codex. (cherry picked from commit cac6081916e8e5461e2754308cd8986deaec774b)
| * | | | macro: execute native parameters without a second FIFO copysnowstormxd32 hours1-5/+4
| | |_|/ | |/| | | | | | | | | | | | | | | | | | | | | | | | | | Use the owned parameter vector for DMA FIFO appends. Add a native JIT regression covering reallocation and repeated invocations against the copied-input path. Assisted by Codex. (cherry picked from commit 5b6803aaab18e332493903ee49cab026c041d5dc)
* | | | Merge pull request #337 from Sssnowyyy/nx2-review-fixesJonas28 hours31-110/+282
|\ \ \ \ | | | | | | | | | | nx2: fix pokopia regressions, textures that handle shader computes, and more
| * | | | nx2: map GPU memory before later command lists are readSssnowyyy31 hours4-4/+24
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 837133792d queues the GMMU maps on the GPU thread (GPU::RunInOrder) so the service thread never waits for the texture cache. With the GPU split (Low GPU accuracy) the GPU thread defers queued functions to its back, but its front reads the command lists: it read the lists submitted after a map through GPU addresses that weren't mapped yet. Pokopia stopped after its first frame. Add GPU::MapInOrder for the GMMU maps and the sparse tile remaps. It runs in order like RunInOrder, and with the split it runs on the front after draining the back, before the front reads further command lists. The service thread still never takes the texture cache lock, and the back is idle while the map changes the caches. Unmaps and the other queued work still run on the back. Assisted-by: Claude Opus 5.5 (bisect, fix, testing and commit message)
| * | | | vulkan: repack 69-byte vertices without dynamic vertex input on MoltenVKSssnowyyy31 hours7-10/+33
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | e38b738b84 repacks the 69-byte vertex stride to 72 only with dynamic vertex input, unless EGLANTINE_EXPERIMENTAL_STATIC_VERTEX_REPACK=1. MoltenVK has no VK_EXT_vertex_input_dynamic_state and Metal needs strides that are a multiple of 4, so the stride was never fixed on Macs. Enable the static path automatically when the device's minimum vertex binding stride alignment does not divide 69. The device reports 4 for MoltenVK, matching its portability subset limit. The environment variable still overrides it: 1 forces the repack on, 0 forces it off. Assisted-by: Claude Sonnet 5.5 (implementation and commit message)
| * | | | vk_pipeline_cache: keep the pipelines on MoltenVK and preload eight sessionsSssnowyyy31 hours1-4/+17
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 5de94bdd1d cut the boot preload to the last two sessions and 2f94fb9680 evicts pipelines unused for 9000 frames, both because rebuilding one costs 2-3 ms through the driver's pipeline cache and each holds ~0.45 MB of driver memory. On MoltenVK a pipeline built while playing is translated from SPIR-V to MSL and compiled by Metal, which takes far longer even with a VkPipelineCache and shows as a stutter. On MoltenVK, keep the previous eight sessions' pipelines in vulkan_used.bin (be76402ab5's window) so they are built at boot, and do not evict. The memory is bounded by what a title builds; the stutter is not. Other drivers are unchanged and EDEN_NX2_PRELOAD_ALL_PIPELINES=1 still builds every cached pipeline. Assisted-by: Claude Sonnet 5.5 (implementation and commit message)
| * | | | vulkan: back a sparse tiled image whole when its tiles can't be set upSssnowyyy31 hours1-13/+32
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | In the aliased mode (AMD) a SparseTiles image is created unbound, and only InitSparseTiles binds every block to the shared zeroed one. When it fails (an unusual block shape, no memory for the zeroed block or the mip tail, a failed bind), the constructor went on to the next branch and flagged the image UnwrittenSparse with nothing bound. AMD's drivers can't sample such an image, and it is sampled before its first write replaces it, which is the hang a855e8373f avoided for large sparse images. Create the image again as an ordinary backed image in that case, as before sparse tiles, and drop the Unbacked flag. The other modes keep falling back to UnwrittenSparse, since their drivers sample unbound memory. Follow-up to 130c255ed9 (with a855e8373f and 1c794af564). Assisted-by: Claude Sonnet 5.5 (implementation and commit message)
| * | | | video_core: continue a split instance loop at its own instance indexSssnowyyy31 hours3-5/+20
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Writing any register outside the instance loop's own methods now draws the waiting instances first, so the batch sees the base instance it was begun with. When a title writes another register in the middle of a loop, such as a per-instance constant buffer, the loop is drawn in several batches, and each later batch started again at global_base_instance_index with one extra instance, so it used the instance IDs of the first records. Count the instances already drawn for the current loop and start the next batch after them, without the extra first-instance draw. A loop that is not split is drawn exactly as before. Follow-up to 2ad0830d2f and eb99da6072. Assisted-by: Claude Sonnet 5.5 (implementation and commit message)
| * | | | buffer_cache: fix the already-disabled check for uniform buffersSssnowyyy31 hours1-1/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | DisableGraphicsUniformBuffer tested !current.buffer_id to detect a binding that is already NULL_BINDING. SlotId converts to true unless it is the invalid id, and NULL_BUFFER_ID is BufferId{0}, so the check was false for NULL_BINDING and the early return never triggered. Compare against NULL_BUFFER_ID instead. Follow-up to 46b2577bf7. Assisted-by: Claude Sonnet 5.5 (implementation and commit message)
| * | | | vulkan: repack 69-byte vertices only when neededSssnowyyy31 hours7-12/+68
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | SetVertexRepackLayout returned old_mask | new_mask, which stays non-zero on every draw that uses a 69-byte binding. PrepareDraw then re-dirtied the vertex buffers and vertex input each time, so the repack compute pass ran and the render pass ended once per draw, which is costly on tiled GPUs. Return old_mask ^ new_mask so only a layout change re-dirties the bindings. The repacked copy only stays valid while the source data is unchanged, so the buffer cache now flags the vertex buffers overlapping a CPU write, inline or DMA write, or GPU write, and re-dirties the repacked ones before binding. Command buffer submission already invalidates all vertex buffer state, which keeps the staging copy within its tick. Also pass the source buffer size to the repack pass and clamp the word-rounded storage descriptor range to it; it could run up to three bytes past the end of the buffer. A binding that does not fit is skipped like one over the device limits. Follow-up to e38b738b84. Assisted-by: Claude Sonnet 5.5 (implementation and commit message)
| * | | | video_core: don't execute command lists copied before their channel waitedSssnowyyy31 hours3-0/+14
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | cce6d44af2 executes each command list entry from a copy of its words taken at submit. Games submit command lists before writing them: the lists wait behind a semaphore acquire, and the game writes their commands just before it releases the acquire (Mario Kart World after present). The copies of those lists were stale. Pokopia stopped after its first frame on macOS: its GPU never reached the fence the game spun on (EDEN_NX2_PB_SNAPSHOT=0 made it run again). Count each channel's suspensions on an acquire and the resumes after them, and record the count with each copy. A list copied while its channel was suspended, or whose channel suspended since, reads guest memory instead. Lists submitted and run without a wait in between keep the copy. EDEN_NX2_PB_SNAPSHOT=0 still disables it altogether. Assisted-by: Claude Sonnet 5.5 (first version); Claude Opus 5.5 (bisect, suspension count, testing and commit message)
| * | | | nx2: don't stall presents on a current-frame wait the GPU can't finishSssnowyyy31 hours4-0/+15
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 0f14696044 made PresentClientBuffer also wait for the current frame's fence whenever the previous frame's wasn't reached. Mario Kart World's GPU waits on semaphores its CPU releases only after the present returns, so in that state the current fence can't be reached until the present returns, and each such present stalled up to the 4 s deadline. Wait for the current frame by default, but give up after a few ms once a GPU channel was seen suspended on a semaphore acquire and wait for the previous frame instead. EDEN_NX2_FRAMES_AHEAD=1 always waits for the previous frame (with 0f14696044's current-frame wait when the GPU is behind), =0 always for the current one. The scheduler gains a lock-free flag so the present thread can see suspended channels. Assisted-by: Claude Sonnet 5.5 (implementation and commit message)
| * | | | video_core: flush GPU-written code when capturing native shadersSssnowyyy31 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 2Sssnowyyy31 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: evaluate handle programs for image and texture buffer descriptorsSssnowyyy31 hours4-50/+44
| |/ / / | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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)
* | | | Merge pull request #113 from ymatrix1/fix/storage-buffers-32Jonas28 hours1-1/+2
|\ \ \ \ | | | | | | | | | | buffer_cache: allow 32 storage buffers per stage
| * | | | buffer_cache: allow 32 storage buffers per stageYuri Olive35 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-srgbJonas28 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 doesTakoroka43 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.
* | | | nx2: read GPU-written command lists from copies instead of drainingTakoroka34 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 nx2 into nx2-experimentalkraibse37 hours28-21/+1005
|\ \ \ \ | | |/ / | |/| / | |_|/ |/| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 ↵Whovian6443 hours6-13/+26
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 ↵ymatrix143 hours1-1/+18
| | | | | | | | | | | | disable (#264)