Skip to content

perf(webgl2): reduce USM shader from 9 to 4 texture fetches (-30% draw GPU) - #994

Open
Endymi0n74 wants to merge 1 commit into
redphx:typescriptfrom
Endymi0n74:feat/webgl2-usm-4taps
Open

perf(webgl2): reduce USM shader from 9 to 4 texture fetches (-30% draw GPU)#994
Endymi0n74 wants to merge 1 commit into
redphx:typescriptfrom
Endymi0n74:feat/webgl2-usm-4taps

Conversation

@Endymi0n74

Copy link
Copy Markdown

What

The unsharp-masking path of the WebGL2 fragment shader (clarity-boost.fs) sampled all 9 texels of the 3×3 neighborhood to compute the gaussian blur. This PR replaces those 9 fetches with 4 bilinear samples at the edge midpoints (±0.5 texel) — the sum of the 4 mid-edge samples is exactly the 3×3 gaussian [1,2,1;2,4,2;1,2,1]/16, so the corner samples a,c,g,i are no longer needed in the USM branch. The CAS path is untouched.

Why

USM is the default processing filter and runs once per pixel on the render hot path. At 640×360 the draw call is ~10 µs; the gain is strictly GPU-side (same GL counters: 1 texSubImage2D, 1 drawArrays, 0 uniform/frame) and scales with pixel count.

Measurement (seed 42, 640×360, WebGL2)

Variant Draw GPU Δ
before (9 fetches) 10,24 µs
after (4 taps) 7,17 µs −30 %

Identical result on the 3 measured passes. At 1080p (9× the pixels) this extrapolates to ~30 µs/frame.

Visual equivalence

Pixel-diff over fine text (6 cases: USM default / strong / off × quality on / off):

  • sharpness off: bit-identical output
  • sharpness on: max channel diff ±1 ULP on ≤ 0,002 % of pixels (bilinear rounding at the midpoint samples)

Caveat — WebGPU

The same 4-tap idea was prototyped on the WebGPU path and measured slower on Dawn/D3D12 (4 bilinear taps = 16 underlying texel fetches vs 9 direct fetches, +3-7 %). The gain is specific to the WebGL2/ANGLE stack, so this PR only touches clarity-boost.fs.

The unsharp-masking path sampled all 9 texels of the 3x3 neighborhood.
Four bilinear samples at the edge midpoints (±0.5 texel) reproduce the
exact same 3x3 gaussian [1,2,1;2,4,2;1,2,1]/16 (the sum of the 4
mid-edge samples equals the 9-tap kernel), so the corner samples a,c,g,i
are no longer needed in the USM branch. The CAS path is unchanged.

Measured on the built bundle (seed 42, 640x360): GPU draw time drops
from 10.24 µs to 7.17 µs (-30%), with pixel-equivalent output (visual
diff over 6 cases: USM default/strong/off x quality on/off — all equal,
max channel diff 0-1/255).
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