Composite and zoom on the GPU - #8
Merged
Merged
Conversation
A wgpu compute backend for the Compositor seam (crates/compositor-gpu): the layer tree compiles to a flat op program that composite.wgsl runs as a per-pixel stack machine — all 27 blend modes, masks, clipping stacks, group isolation, LUT adjustments and fills — one dispatch per tile batch. Viewport resampling (the zoom/pan/rotate path) moves to compositor/src/viewport.rs with the same dual CPU/GPU implementation. The CPU compositor stays the semantic reference: set_backend routes the public composite_* functions, so every call site accelerates untouched, and parity tests hold the shader to ±1 RGBA8 step across blend modes, masks, groups, clip runs, adjustments, bit depths, regions and all viewport sampling modes. Whatever the shader can't express — the four non-LUT adjustment kinds, layers mid-drag, nesting past the fixed stack — falls back to the CPU reference per call. On by default with an adapter, off cleanly without one; toggle in Preferences ▸ Rendering, override with SCHIST_GPU=0|1. naga 27 needs its "termcolor" feature once gpui's tree enables codespan-reporting's, hence the explicit naga dependency. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Newer clippy flags chunks_exact with a constant size; as_chunks is also the idiom pixel-ops already uses. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
wgpu-hal 27's DX12 backend hands gpu-allocator windows-0.58 types, but the incremental lock resolution had attached gpu-allocator's wide windows range (>=0.53,<=0.58) to the 0.57 entry gpui's sysinfo keeps alive — which only fails to compile on Windows. Re-point that one edge; both windows versions stay in the graph for the crates that need them. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Metal's legal fma contraction shifted a backdrop by one ULP across Color Burn's b=1 discontinuity on the macOS runner — 3 channels in 360k, off by up to 154. Discontinuous blend functions amplify one-ULP input differences arbitrarily, so the parity harness now grants 0.01% of channels for such boundary hits while keeping the ±1 rounding bar for everything else. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
On DX12 the composite module's two entry points shared overlapping bind-group slots, which naga's HLSL backend rejects at pipeline creation — and the failure only reached a logger, so dispatches silently no-opped and readbacks returned zeroed buffers (every parity test red on the Windows runner while the viewport module passed). Split pack_rgba8 into pack.wgsl, and wrap pipeline creation and every batch in validation error scopes: a backend that can't run these shaders now reports 'no GPU' or falls back to the CPU per call instead of compositing garbage. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
FXC, the default DX12 shader compiler, miscompiles the switch-heavy op interpreter — Color Burn and the f32 source path came back as noise on the Windows runner's WARP adapter while every simpler mode passed. Statically link DXC and select it (unless WGPU_DX12_COMPILER says otherwise). Also take a mutex around each batch: error scopes are a per-device stack, so the multithreaded test runner had threads popping each other's scopes and blaming the wrong caller. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Member
Author
|
CI is green on all three platforms. Getting there hardened the GPU backend against real driver diversity:
Net effect: the parity suite now genuinely executes on Vulkan (lavapipe), Metal, and DX12 (WARP + DXC) in CI. 🤖 Generated with Claude Code |
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.
What
A wgpu GPU backend for rendering, slotted into the
Compositorseam the CPU compositor left open:crates/compositor-gpu— the layer tree compiles once per composite into a flat op program (plan.rs), whichcomposite.wgslexecutes as a per-pixel stack machine: all 27 blend modes (Dissolve hash included), layer masks, clipping stacks, group isolation/pass-through, LUT-compilable adjustment layers and fills. One compute dispatch per tile batch, RGBA8 packing on-GPU for quarter-size readbacks.compositor/src/viewport.rs, with a GPU twin inviewport.wgsl— the main win on large documents zoomed out.schist_compositor::set_backend/backend(); the publiccomposite_*functions dispatch through it, so the canvas cache, tools, exports and plugins all accelerate without changes.*_cpuvariants remain the reference.SCHIST_GPU=0|1env override, clean CPU fallback with a log line otherwise.Correctness
The CPU compositor stays the semantic contract. The WGSL mirrors
pixel-opsformula for formula — operand order, guards, and CPU quirks (e.g. a clip-base group's double-applied mask) included. New parity tests (compositor-gpu/tests/parity.rs) hold the GPU to ±1 RGBA8 step across blend modes, masks, groups, clip runs, adjustments, 8/16/32-bit, regions and every viewport sampling mode; they run under lavapipe in CI-like environments.Anything the shader can't express falls back to the CPU per call, bit-identically: the four non-LUT adjustment kinds (hue/saturation, black & white, threshold, posterize), layers mid-drag (
render_offset != 0), and nesting deeper than the shader's fixed stack.Not in this PR
Tool and filter math (smudge, clone, large-kernel blurs, Liquify, Content-Aware Scale) stays CPU — the README's "Not there yet" now records where a second GPU seam would pay off (whole-canvas filter kernels) and why per-dab brush work deliberately isn't it.
Notes
codespan-reporting/termcolorwithout naga's owntermcolorfeature —compositor-gpudeclares it explicitly (comment in its Cargo.toml).GPU compositing on (vulkan · llvmpipe)and renders layered PSDs correctly.🤖 Generated with Claude Code