fix(textures): enable compression extension before upload (fixes GL 1280)#88
Merged
Merged
Conversation
…280) A compressed format enum is only valid in compressedTexImage2D after its owning extension has been enabled via getExtension; otherwise the driver rejects it with GL_INVALID_ENUM (1280). KTX (S3TC/ETC/ETC2) and PVR (PVRTC) uploads never called getExtension — they relied on the boot-time getWebGlExtensions() probe (removed in #60, 1.4.0) incidentally enabling every compression extension. #60 saw the probe's result cache was dead and removed the whole function, not realizing the getExtension() calls themselves were load-bearing. ASTC survived only because uploadASTC re-queried its extension itself. Result: the first KTX or PVR upload throws 1280 on 1.4.0–1.4.3. Enable the owning extension at the point of use (resolved by GL internal format) for all three paths, throwing a clear "not supported by this device" error instead of leaking a silent 1280. Candidate name lists are hoisted to module constants so the resolver allocates nothing per upload. Also fix two VRT examples that hung the (timeout-less) snapshot runner: - tx-compression: promote to an automated VRT (it was manual-only, which is why this regression shipped). A format the GPU lacks now surfaces as a failed texture that never fires 'loaded', so wait with a timeout backstop. - texture-free-reload: 'idle' had already fired by the time automation() ran, so waitUntilIdle() waited forever; force a final frame instead. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
chiefcll
added a commit
that referenced
this pull request
Jun 9, 2026
…280) (#88) A compressed format enum is only valid in compressedTexImage2D after its owning extension has been enabled via getExtension; otherwise the driver rejects it with GL_INVALID_ENUM (1280). KTX (S3TC/ETC/ETC2) and PVR (PVRTC) uploads never called getExtension — they relied on the boot-time getWebGlExtensions() probe (removed in #60, 1.4.0) incidentally enabling every compression extension. #60 saw the probe's result cache was dead and removed the whole function, not realizing the getExtension() calls themselves were load-bearing. ASTC survived only because uploadASTC re-queried its extension itself. Result: the first KTX or PVR upload throws 1280 on 1.4.0–1.4.3. Enable the owning extension at the point of use (resolved by GL internal format) for all three paths, throwing a clear "not supported by this device" error instead of leaking a silent 1280. Candidate name lists are hoisted to module constants so the resolver allocates nothing per upload. Also fix two VRT examples that hung the (timeout-less) snapshot runner: - tx-compression: promote to an automated VRT (it was manual-only, which is why this regression shipped). A format the GPU lacks now surfaces as a failed texture that never fires 'loaded', so wait with a timeout backstop. - texture-free-reload: 'idle' had already fired by the time automation() ran, so waitUntilIdle() waited forever; force a final frame instead. Co-authored-by: Claude Opus 4.8 (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.
Problem
Users on 1.4.0–1.4.3 hit
WebGL: INVALID_ENUM (1280)and a blank/failed texture when loading.ktx(S3TC/ETC/ETC2) or.pvr(PVRTC) compressed textures. ASTC was unaffected.Root cause
In WebGL, a compressed format enum is only valid in
compressedTexImage2Dafter its owning extension has been enabled viagetExtension—getExtensionis the enable; there is no separate call.uploadKTX/uploadPVRnever callgetExtension. They relied on the boot-timegetWebGlExtensions()probe, which calledgetExtensionon every compression extension as a side effect. #60 (1.4.0) correctly found the probe's result cache was dead and removed the whole function — but thegetExtensioncalls themselves were load-bearing.uploadASTCsurvived only because it re-queries its own extension.Result: the first KTX/PVR upload throws 1280. Not fixed by
forceWebGL2(#70) — WebGL2 still requiresgetExtensionfor these formats.Fix
"...not supported by this device"error instead of leaking a silent 1280.getExtensionis CPU-side + browser-cached and upload is not a per-frame path, so no runtime cache is warranted.)Why it shipped: missing VRT coverage
tx-compression.tsexisted but was a manual-only example (noautomation/snapshot), so CI never exercised it. This PR promotes it to an automated VRT and commits a certified snapshot.Also: two hung-test fixes
The VRT runner has no per-test timeout, so a never-resolving wait hangs the whole capture/compare run:
failedtexture that never firesloaded. Added a timeout backstop so the snapshot captures whatever the device produced.automation()ran afteridlehad already fired, sowaitUntilIdle()waited forever. Force a final frame + short delay instead.Tests
src/core/lib/textureCompression.test.ts— 8 deterministic unit tests assertinggetExtensionprecedescompressedTexImage2Don every path, the WebKit-prefixed PVRTC fallback, and a clear throw (no upload) when unsupported.pnpm build,pnpm test, lint all clean.🤖 Generated with Claude Code