Skip to content

Add anisotropic Gaussian blur - #1997

Open
theashraf wants to merge 1 commit into
linebender:mainfrom
theashraf:anisotropic-blur
Open

theashraf wants to merge 1 commit into
linebender:mainfrom
theashraf:anisotropic-blur

Conversation

@theashraf

Copy link
Copy Markdown

FilterPrimitive::GaussianBlur now takes a standard deviation per axis (std_deviation_x, std_deviation_y), matching SVG's two-value stdDeviation. Equal values behave exactly as before; a zero deviation leaves that axis untouched. This resolves the two TODOs in filter_effects.rs and transform_blur_params.

Approach

  • Per-axis plan. GaussianBlur carries a decimation count and kernel per axis. The finest decimation levels are shared between the axes; once the smaller axis runs out of levels only the larger one keeps being halved (decimation_levels). DecimationSizer tracks the axes separately through downscale_axes / upscale_axes.
  • CPU. Single-axis downscale/upscale, and the convolution pass of an identity kernel is skipped.
  • GPU. New DOWNSCALE_X/Y and UPSCALE_X/Y passes; downscale/upscale in scale.wesl take an axis mask. The filter data grows from 48 to 64 bytes to carry a second kernel, and the header packs the y-axis decimation and tap counts in the previously reserved bits. Drop shadows still blur both axes with one kernel, so their layout is unchanged.
  • Transforms. An anisotropic blur is scaled through the covariance of the Gaussian: a 90° rotation swaps the axes and a non-uniform scale scales each axis on its own. The off-diagonal term of a rotation that is not a multiple of 90° cannot be represented by an axis-aligned kernel and is dropped. Uniform blurs keep the previous averaged scale factor.

Tests

  • Unit tests for the per-axis plan, the sizer with mixed axes, and the transform math.
  • CPU tests that a single-axis blur leaves the other axis bit-exact, and that an x-only blur is the transpose of a y-only blur.
  • GPU pass-plan tests for single-axis and mixed-axis blurs.
  • New snapshots: filter_gaussian_blur_horizontal, _vertical, _anisotropic, _anisotropic_rotated, _anisotropic_scaled. Existing snapshots are unchanged.

Breaking changes

FilterPrimitive::GaussianBlur { std_deviation } is now { std_deviation_x, std_deviation_y }, and GaussianBlur::new takes both deviations.

`FilterPrimitive::GaussianBlur` now takes a standard deviation per axis
(`std_deviation_x`, `std_deviation_y`), matching SVG's two-value
`stdDeviation`. A zero deviation leaves that axis untouched.

Each axis gets its own decimation plan and kernel. The finest decimation
levels are shared between the axes; once the smaller axis runs out of
levels only the larger one keeps being halved. `DecimationSizer` tracks
the axes separately through `downscale_axes` / `upscale_axes`.

The CPU path gains single-axis downscale/upscale and skips the
convolution pass of an identity kernel. The GPU path adds
`DOWNSCALE_X/Y` and `UPSCALE_X/Y` passes, carries a second kernel in the
filter data (filter size 48 -> 64 bytes) and packs the y-axis decimation
count and tap count into the header.

Transforms scale the deviations through the covariance of the Gaussian,
so a 90 degree rotation swaps the axes and a non-uniform scale scales
each axis on its own. Uniform blurs keep the previous averaged scale.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant