| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
(#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)
|
| |
|
|
|
|
| |
Fsr3Upscaler::Pass::Dispatch took a scheduler parameter that shadows
Fsr3Upscaler::scheduler, which fails the Windows MinGW PGO build under
-Werror=shadow.
|
| |\
| |
| |
| |
| |
| | |
# Conflicts:
# src/video_core/renderer_vulkan/blit_image.cpp
# src/video_core/renderer_vulkan/blit_image.h
|
| | |\
| | |
| | | |
video_core: bump the shader cache versions for the FSEL lowering fix
|
| | | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
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).
|
| | |\ \
| | | |
| | | | |
MKW performance improvements
|
| | | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
Adapted from sylvieistaken/selevet-eglantine performance builds, including 8b076b167ffc5ca1ba8ffedcd00e255accbe018c and d8c95fef. Preserve upstream command-list coherency and submission ordering.
Assisted by Codex.
|
| | | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
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)
|
| | | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
command buffer
(cherry picked from commit 4aa5cd89fd1862751b3297036f2d21a0dc924b23)
(cherry picked from commit f1bdd5b13a1bdca81243b4aa1d8529f0485d3671)
|
| | |\ \ \
| | | | |
| | | | | |
nx2: fix pokopia regressions, textures that handle shader computes, and more
|
| | | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | | |
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)
|
| | | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | | |
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)
|
| | | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | | |
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)
|
| | | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | | |
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)
|
| | | |/ /
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
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: 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.
|
| | | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
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>
|
| |/ / /
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
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>
|
| | | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
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.
|
| |\ \ \
| | |/
| |/|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
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)
|
| | |/
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
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.
|
| | |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
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>
|
| | |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
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>
|
| | |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
The collector's usage leaves out the unused part of VMA's blocks, but
the driver counts it and a heap at its budget cannot give it to a new
image. On an RX 7800 XT that slack was 1.06 GiB, the whole 1 GiB margin:
the heap sat at its budget for a minute while the collector saw room,
then images stopped fitting and the process died. Reserve the slack
(capped at 1.5 GiB) on top of the margin: at once when it grows, slowly
when it shrinks, so eviction leaving partly used blocks doesn't chase
the threshold down.
Assisted-by: Claude Sonnet 5.5 (diagnosis and code)
(cherry picked from commit 73fd5a489ea28226fa16a55f5008e622d631b54c)
|
| | |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
When VRAM ran out, any image that failed to allocate became a sparse
image with nothing bound, which AMD's drivers don't survive being
sampled (an RX 6600 died mid-flood, an RX 7800 XT made 211 of them,
8x8 ones included). Try host memory first, and count the images that
didn't fit: the texture cache then keeps more room under the budget
(512 MiB a step, up to 3 GiB, decaying) so its collector runs earlier.
The sparse fallback stays for images too large to back.
|
| | |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
Native programs were captured and lowered when their ShaderInfo was
made and again for every environment built for their pipelines. The
ShaderInfo now keeps the lowered code and the environments adopt it.
Capture also reads a 4 KiB page at a time instead of flushing caches per
instruction, and cached native programs fold bank 1 reads like live ones.
Ported from Wael3rd/Eglantine-MKW (0ae093058e, 65a6aa877a, df076133c4).
Assisted-by: Claude Sonnet 5.5 (porting the fixes)
(cherry picked from commit 3af11ac401ad3061c183281d8c98c16c1d6da456)
|
| | |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
Image::InitSparseLayers divided by the imageGranularity the driver
returns, which AMD's driver reports as 0 and crashed. Use Vulkan's
standard 2D block shape when the device reports
residencyStandard2DBlockShape, otherwise don't use sparse layers.
Ported from Wael3rd/Eglantine-MKW (7a77946af3).
Assisted-by: Claude Sonnet 5.5 (porting the fix)
(cherry picked from commit eadb9fc0f06f32ff1684fe202519c0505669095d)
|
| | |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
Deleting by age alone left every block partly used: the collector deletes
thousands of images a minute and new ones land in the holes, so blocks
seldom empty (title 1: ~0.8 GB of holes in ~190 32 MiB blocks after ten
minutes, counted by the driver as used). Among the oldest candidates, 8
per image a pass may delete, those in the emptiest blocks go first, so
blocks drain and VMA returns them; placement already prefers the fullest
blocks.
(cherry picked from commit 2f8f0716fafd874cfbb3cc9086141aea61aff2df)
|
| |\ \
| | |
| | |
| | | |
test/linux-all-prs-plus
|
| | | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
A trimmed ASTC array kept up to 512 MiB on the host. On GPUs with less
than 7 GiB it now keeps up to 256 MiB (one mip level less): Mario Kart
World's two terrain arrays took 724 MiB of a 6 GB card next to ~1.2 GB
of other sparse terrain textures. EDEN_NX2_ASTC_ARRAY_MIB=<MiB> sets the
limit.
|
| |\ \ \
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
test/linux-all-prs
# Conflicts:
# src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
|
| | | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
Without vulkan_used.bin (the first boot with this change, or a session
that ended before saving it) every cached graphics pipeline was still
built at boot. A Linux tester's cache had grown to 47,951 pipelines over
many builds: ~21 GB of driver memory built before the game started,
filling RAM and swap. The list is only saved at exit or after two
minutes, so a boot that ran out of memory never saved one and the next
boot did the same.
Build at most 3,000 cached graphics pipelines at boot in that case and
the rest when first needed; the next session uses the saved list.
EDEN_NX2_PRELOAD_ALL_PIPELINES=1 still builds all of them.
|
| | | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
Each built pipeline holds ~0.45 MB of driver memory and none was ever
destroyed, so it grew with every place a session went. One unused for
9000 frames is destroyed once the GPU is past it and built again from
the driver's pipeline cache (2-3 ms) if it is needed later; the
transitions between pipelines are cleared, and pipelines used this
session still go to the used list. Mario Kart World's title screen, 10
minutes: 1,714 evicted, 1,700-1,850 kept instead of a count that only
grows.
(cherry picked from commit 24a37800034f83ec1d8fe9e8e5642d27eb2935b8)
|
| | | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
Each pipeline built at boot holds ~0.45 MB of driver memory. Mario Kart
World built 4,789 from the eight sessions the list kept, while one
session of its title screen uses ~1,500. With the last two sessions it
built 1,035 at boot and 972 when first needed: the emulator's own memory
at five minutes 6.4 -> 5.6 GB, frames over 100 ms 9 -> 10 (none built at
boot: 4.9 GB, but 38 frames over 100 ms). Lists saved with the longer
window are trimmed when they are loaded.
|
| | | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | | |
Every graphics pipeline in the disk cache was built at boot, and each one
holds driver memory: Mario Kart World builds 6.5k (the NVIDIA driver keeps
~1.6 GB for them) and a session uses about a quarter. Record the pipelines
each session uses in <title>/vulkan_used.bin (key hash + sessions since the
last use, dropped after 8), build only those at boot and the rest when a
game first needs them, without storing them in the disk cache again. The
first session without the file builds everything as before.
EDEN_NX2_PRELOAD_ALL_PIPELINES=1 keeps building all of them.
|
| |\ \ \ \
| | | | |
| | | | |
| | | | | |
into test/linux-all-prs
|
| | | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | | |
The RGBA8 image an ASTC texture is decoded into before BC1/BC3
compression was made for each texture (263 us) and freed once the GPU
was past it. Once the GPU is done with one it now decodes the next
texture of the same shape: title 1's title screen decodes dozens of
textures a frame, mostly of a few shapes. Free ones are kept up to
256 MiB and destroyed after 60 unused frames.
Taking them from VMA's shared blocks instead was faster (90 us), but
freeing dozens a frame there left ~1 GB of those blocks unused. Against
that, Mario Kart World's title screen over 10 minutes: VRAM in use 6.34
-> 5.90 GB on average, peak 6.99 -> 6.45 GB.
|
| |\ \ \ \ \
| | | | | |
| | | | | |
| | | | | | |
test/linux-all-prs
|
| | |/ / / /
| | | | |
| | | | |
| | | | |
| | | | | |
256 MiB sat mostly unused in device memory on Switch 2 titles. FreeBSD
already used 128 MiB.
|
| |\ \ \ \ \
| | | | | |
| | | | | |
| | | | | | |
test/linux-all-prs
|
| | |/ / / /
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | | |
Their drivers keep a disk cache of built pipelines of their own. Eden's
VkPipelineCache on top loaded every pipeline the title ever built into
host memory (title 1: a 245 MB file) and copied it whole at each save.
Without it, title 1's title screen over ten minutes: private memory
-373 MiB, frames over 100 ms 30 -> 21, worst frame 141 -> 94 ms, and
pipelines built as fast (2.26 vs 2.46 ms each on the GPU thread).
(cherry picked from commit ea3dcd444cad7de301ec949a350cc45abb48d3bf)
|
| |\ \ \ \ \
| | | | | |
| | | | | |
| | | | | | |
test/linux-all-prs
|
| | |/ / / /
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | | |
Nothing reads a pipeline's shader modules after the pipeline exists, and
the driver keeps a copy of each module's SPIR-V for as long as it lives:
title 1 keeps ~1,500 graphics pipelines with 2-5 modules each. The
graphics pipeline picks its configure function before queuing the build,
which now frees what it looks at.
(cherry picked from commit aaa414ec1dd96e466282b0c4501574cbe7c2494e)
|
| |\ \ \ \ \
| | | | | |
| | | | | |
| | | | | | |
test/linux-all-prs
|
| | |/ / / /
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | |
| | | | | |
Deleted images kept their device memory for TICKS_TO_DESTROY (8)
frames. While the collector deletes dozens a frame that held 1-1.5 GB
of VRAM on top of its threshold, which the collector does not count
(Mario Kart World on an 8 GB card: 6.6-7.0 GB in use against 5 GiB). On
runtimes that report GPU progress (Vulkan) an image is destroyed as
soon as the GPU is past it. Title screen, 10 minutes: VRAM in use 6.75
-> 6.34 GB on average, frames over 100 ms 22 -> 15.
(cherry picked from commit 8c899541baf398deb892a857a932590f32d2aa4f)
|