Conversation
Add a 4x5 color matrix filter (`feColorMatrix` style): each output channel is a linear combination of the straight-alpha input channels plus a constant offset. vello_cpu applies matrices that only mix the color channels and preserve alpha directly to the premultiplied channels, skipping the unpremultiply/premultiply round trip. vello_gpu now packs filter parameters back to back with a per-filter texel stride, like encoded paints, instead of a fixed three-texel slot, so the six-texel color matrix doesn't widen every other filter: offset and flood take one texel, gaussian blur two, drop shadow three. Builds on the original color matrix work in linebender#1623. Co-authored-by: Bruce Mitchener <bruce.mitchener@gmail.com>
A filter layer can now apply several filter primitives in sequence, each operating on the output of the previous one. This is what CSS filter lists need. - vello_common: `FilterGraph` is treated as an ordered chain; `add` accumulates the layer expansion as a sum instead of a union so that e.g. `blur -> drop-shadow` is not clipped. `PreparedFilter::chain` replaces `PreparedFilter::new` and skips unsupported primitives instead of panicking. `Filter::from_primitives`/`from_functions` build chains, and all CSS `FilterFunction`s lower to `ColorMatrix` (new `matrices::*` constructors) instead of hitting `unimplemented!`. - vello_cpu: run the prepared chain in place on the layer pixmap. - vello_gpu: `FilterContext::push` encodes all primitives of a layer and returns a `PreparedGpuFilterChain`; `FilterPassPlan` emits the passes of each primitive back-to-back. A drop shadow inside a chain copies its actual input (the previous primitive's output) to the scratch texture right before its own passes, instead of a single up-front copy of the layer. Both the wgpu and WebGL executors handle the per-step copy passes. - vello_tests: snapshot tests for order-sensitive color chains, blur/drop shadow/offset combinations and neutral functions.
|
I'll fix CI failures and address comments from users with write access that start with 'Devin'.
|
This branch has not been deployed
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.
Summary
Adds ordered (linear) filter chains so a CSS
filter: f1() f2() ...list can be rendered by both backends. PreviouslyPreparedFilter::newpanicked on graphs with more than one primitive andFilterGraph::addunioned per-primitive expansions, which clips chained spatial filters. Explicit SVG graph inputs, multithreadedvello_cpuandComponentTransferremain out of scope.Built on top of linebender#1765 (
ColorMatrix, included as the first commits here) because chain encoding on the GPU relies on its variable-stride filter data.vello_common
Filter::from_primitives(iter)/Filter::from_functions(&[FilterFunction]);from_primitivedelegates. Primitives are treated as a chain in insertion order (each takes the previous output).blur(5) → drop-shadow(10,10,5)now expands by15 + (10+15)px per side instead ofmax(15, 25).PreparedFilter::chain(&Filter, &Affine) -> PreparedFilterChain(aSmallVec<[PreparedFilter; 1]>); unsupported primitives are skipped instead of panicking.FilterFunction::to_primitivelowers brightness/contrast/grayscale/hue-rotate/invert/opacity/saturate/sepia toColorMatrix(removes theunimplemented!()s inFilter::from_function).vello_cpu —
filter_lowp/filter_highprun the prepared chain in order against the same layerPixmap+ scratch buffer.vello_gpu
FilterContextencodes every primitive of a layer back-to-back;FilterOpnow references aPreparedGpuFilterChain(contiguous range) instead of a single header/offset.FilterPassBuilder::emit_filteremits each primitive's passes consecutively (blurDecimationSizerreset per blur); the result is returned to the original region only once at the end.FilterStep { copies, filter }: the copy-to-scratch for a drop-shadow happens at its step (after ensuring the previous stage's output is in the original region), so a mid-chain drop-shadow composites against its real input rather than the unfiltered layer. wgpu and WebGL executors updated to run copies before each step's filter passes.Tests — unit tests for the CSS matrices and summed expansion, GPU pass-plan tests (chain sequencing, drop-shadow input preservation, empty chain), and
vello_testssnapshotsfilter_chain_*(order-sensitivebrightness→contrastvs reversed, grayscale/invert/opacity, sepia/hue-rotate/saturate, identity functions, blur↔drop-shadow, offset→drop-shadow, drop-shadow→grayscale) run on CPU u8/f32 (all SIMD levels) and GPU.Follow-up (separate repo):
anyrender_vello_cpu/anyrender_vello_hybridstill truncate tonodes()[0].Link to Devin session: https://dioxus.staging.devinenterprise.com/sessions/5cb5c4089ef348c49c6038b9047cb2d3
Open in Devin Desktop: https://dioxus.staging.devinenterprise.com/desktop/session/5cb5c4089ef348c49c6038b9047cb2d3?variant=devin-insiders
Requested by: @nicoburns