Repository navigation
GPU: resident effect stacks, in-frame texture reuse, upload-cache budget, stable footprint keys (#687) - #688
Merged
h-a-n-a-s-h-i merged 5 commits intoOct 13, 2026
Conversation
This was referenced Oct 11, 2026
… time-dependent effect (Noise) no longer re-keys it and the GPU re-uploads it every frame (storytold#687)
…f allocating new ones for every intermediate of a frame (storytold#687)
…en full, instead of evicting layer textures silently (storytold#687)
…rectly, instead of a readback and re-upload around every GPU effect run (storytold#687)
MatejKozlovsky
force-pushed
the
gpu-resident-effects
branch
from
October 12, 2026 08:35
b72043f to
bc6a145
Compare
Contributor
Author
MatejKozlovsky
added a commit
to MatejKozlovsky/effectcraft
that referenced
this pull request
Oct 13, 2026
…o PRs merge without a duplicate field Both this PR and storytold#688 add `GpuContext::upload_budget`. Here the field and its initialiser sat in different places than in storytold#688, so git merged both copies and the result failed with E0124/E0062; `set_pool_budget` and the `Pool` budget field also overlapped storytold#688's hunks and conflicted. The upload-budget field, its initialiser, `set_upload_budget`/`upload_budget`, the `UPLOAD_BUDGET` doc and the check in `upload_buf` now match storytold#688 line for line, including storytold#688's one-time "upload cache full" warning, so either merge order applies them once. `set_pool_budget` moves next to `check` and the `Pool::budget` field above `bytes`, away from storytold#688's changes. Budgets and eviction behave as before.
Member
|
Merged. Thank you for the contribution, @MatejKozlovsky! It landed on |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #687.
Changes (4 commits, one change each)
through the masks), so a time-dependent effect such as Noise no longer re-keys it every frame.
Encreuses the working textures it released at once. Its later commands run aftereverything it recorded before (one queue, recording order), so it may overwrite them; other encoders
only get them after the
Encis gone, through the existing pool.GpuContext::set_upload_budget/upload_budget(default unchanged, 1536 MB), and onewarning when the upload cache is full and starts evicting layer textures.
walk::draw_resident_fx: a plain layer's effect stack runs resident on the GPU (GpuFx, ineffect space, as 0.7.0 defines it, then rebased to layer space) and is placed directly; CPU-only effects
in the stack read back, run and upload as before. A layer whose processed buffer is cached and unchanged
since the last frame (
Renderer::layer_is_static) keeps the usual path, so it uploads once instead ofre-running its effects every frame. Layers with layer styles, Preserve Transparency or a track matte
keep the usual path.
Numbers (measured, test PC, main
2ec87e9vs main + this PR)4K comp with effect stacks, 3 s / 90 frames,
--gpu,RAYON_NUM_THREADS=1:--gpu--gpuBoth GPU exports differ from the CPU export (MD5), so the frames really came from the GPU. They are
bit-identical to each other (PSNR ∞) and both 50.9 dB average PSNR vs CPU (Y 49.7 dB). No GPU-declined or
upload-cache-full lines in either log.
effectcraft-cli bench --gpu, same comp, median of 5 (ms/frame):GPU vs CPU: 0.000% of pixels over 1/255 on both. Upload traffic on this comp is 0.0 MB/frame warm on both
(nothing in it re-keys), so the footprint-key and upload-budget changes don't show here; their tests
measure them. An earlier version of this PR re-ran static effect stacks every frame and was slower at
1080p warm (83.7 ms vs 51.8 ms); commit 4's
layer_is_staticcheck fixed that (48.9 ms above).Tests
effect_stacks_render_resident: GPU vs CPU parity, 8 and 32 bpc, full and half resolution: GPU effectswith a CPU-only effect in the middle, opacity, a blend mode, rotation, and a shape layer (effect space
from its bounds' corner).
static_effect_layers_draw_from_the_cache: a static layer with effects uploads nothing after it iscached, frames repeat exactly, matches the CPU.
texture_reuse_does_not_change_output: a busy frame is bit-identical with in-Encreuse on and off,and matches the CPU.
enc_reuses_its_own_released_textures: theEncgets its own texture back at once;another
Encdoes not.adjustment_footprint_uploads_once_under_time_dependent_effects: the footprint key is equal at twotimes (no GPU needed); on the GPU, frames 3 and 4 upload 0 bytes (before the fix: 64,000 bytes, the
footprint, every frame); output still changes every frame and matches the CPU.
upload_budget_bounds_the_layer_textures_kept: within the budget static layers upload once; under a1 MB budget they upload again; the frame is the same.
CI
Rust 1.95, on top of main
2ec87e9:cargo fmt --check: clean.xtask layers,assets(39 assets),wasm(32 crates): ok.effectcraft-gputests_fx_pixel2::stylize(cchextile, 2 of 770 px) andtests_fx_stylize::posterize_thresholds_strobe_vignette(ccthresholdrgb, 13 of 5917 px), on a softwareVulkan adapter.
clippy -D warnings: clean for this PR's code. Upstream errors on unmodified main, not touched here:collapsible_matchincrates/psd/src/lib.rs:660,crates/text/src/path_text.rs:36,crates/effects/src/audio_fx.rs:249,crates/effects/src/generate3.rs:507, andnonminimal_boolincrates/ui-egui/src/panels/text_panels.rs:856.--gpu) of the 4K comp is byte-identical between main and this PR.Limitations
is the next PR (the scheduler). The export numbers above use
RAYON_NUM_THREADS=1for that reason.