Repository navigation
perf: BC5 −22%, BC7 lossless gray tail, ETC2 −5%; WebGL parity + ETC2 WebGL encoder - #12
Merged
Merged
Conversation
BC5 (both modules): texels as quad-major vec4s, pass-1 moments ΣL, ΣL², Σd, ΣL·d with no clamp (the seed covers the data), branch-free vec2 refit, and pass-2 levels packed as float Σ L·8^k with a SWAR level → index map. GPU −22% f16 / −20% f32 (rg8 source), −17% on rgba8; quality unchanged. BC7 (both modules): gray + opaque blocks take an integer 1-D tail — lossless for spans ≤ 15 with odd endpoints so alpha decodes to exactly 255, closed-form scalar LSQ refit with alpha-aware p-bit pricing above. RGBA PSNR on gray maps +0.8..+19 dB (RGB alone +0.2..0.65), GPU neutral: covariance moved out of the load loop onto the colour path (f32 module −30% on colour content), float-nibble index packing. ETC2 (both modules): gray-only two-channel planar solve, subblock pairs searched together with the lower-neighbour scores skipped when both covers are table 0, precomputed table-score constants. GPU −5% f16 / −7% f32 geomean, −15..17% on smooth maps at 2K/4K. Gray test now also requires equal planar moments (CPU mirror updated); otherwise byte-identical. /eval: src=rgba8 option and worst easy-block details. Suite gray BC7 pins raised. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The GLSL fragment encoders had drifted behind the WGSL f32 modules. Each is now a line-for-line port and produces byte-identical blocks to the WebGPU f32 shader (verified on the texture corpus, all four formats): - BC1: solid-colour path for near-flat blocks, moment-form projection passes, looped accept-if-better refits (normal card +1.3 dB, displacement +0.4 dB) - BC5: moment-form kernel with reprojection, float-packed levels + SWAR index map (+0.08..0.12 dB) - BC7: lossless gray tail with alpha-exact odd endpoints and alpha-aware refit (gray maps up to +8.5 dB), covariance off the load loop, straight-line packing, roundEven seeds - ASTC: QUANT_192 bit budgets and 3-channel opaque path, fit-pass weights for translucent blocks (colour +0.06..1.2 dB) The WebGL host now caches its source texture and RGBA32UI target across encodes and skips re-uploading an ImageBitmap it already holds (the upload is ~65% of a 4096² WebGL encode). Output bytes unchanged across memo hits, flipY and size changes. WebGL wall time vs before: 4096² ASTC −17..34%, BC5 −11%, BC7/BC1 par to −8% (shaders); with host caching, fresh encodes −24..30% and repeat-bitmap encodes −67% at 4096². An rg8 source for BC5 was measured and not ported: WebGL's RG8 upload is slower than RGBA8. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
compressTexture({ forceWebGL: true }) / loader.forceWebGL skips the WebGPU
tier and encodes on the WebGL2 fallback, so that path can be tested on
WebGPU-capable browsers. The transcode-cache fingerprint now includes the
backend, so forced-WebGL calls are never served WebGPU bytes.
compressTexture()'s WebGL tier now keeps one encoder per format on the
shared context across calls (it recompiled the fragment program on every
call), matching the WebGPU tier's shared encoders; released by
releaseSharedGpuResources().
Example app: ?forcewebgl=1 on any page encodes through WebGL2 (the demo via
compressTexture, the per-format pages via each *WebGLEncoder twin — ETC2
has none and says so) and renders through three's WebGL2 backend
(WebGPURenderer forceWebGL). Nav links keep the flag; a WebGL2 toggle in
the nav reloads with or without it; the panels show the backend.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
ETC2 was WebGPU-only, so the WebGL tier could only offer BC1 at quality: 'low' and nothing on ETC-only devices. ETC2WebGLEncoder is a line-for-line GLSL port of etc2.wgsl (texelFetch quads in gather order, since WebGL2 has no textureGather) and produces byte-identical blocks to the WebGPU encoder — verified on the colour card, packed atlas, rock/wood colour, roughness, displacement and normal maps, an odd 133×61 image and flipY. WebGL capabilities gain `etc` (WEBGL_compressed_texture_etc) and selectWebGLFormat now mirrors the WebGPU rules: ETC2 RGB8 is the 'low' pick when s3tc is absent and the final opaque-colour fallback after BPTC, ASTC and BC1. The example's /etc2?forcewebgl=1 uses it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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.
WebGPU encoders
WebGL path
ETC2WebGLEncoder(byte-identical to WebGPU),etccapability (WEBGL_compressed_texture_etc), and WebGL format selection mirroring WebGPU (ETC2 as thequality: 'low'pick without s3tc and the final opaque fallback).compressTexture()keeps one WebGL encoder per format across calls instead of recompiling each time.API / tooling
compressTexture({ forceWebGL })/loader.forceWebGLto test the fallback on WebGPU browsers; transcode-cache keys now include the backend.?forcewebgl=1on any page encodes and renders through WebGL2 (nav toggle included)./eval:src=rgba8option and worst-easy-block details.Validation
/test: 0 failures (BC7 gray pins raised to the new baselines).bun test: 222 pass. Format, lint, typecheck, warden clean.🤖 Generated with Claude Code