gfx: fall back to RGBA8 where the backend has no BGRA8 (fixes images on wasm)#2147
Conversation
…rmat Uploading an image on WebAssembly raised WebGL: INVALID_ENUM: texSubImage2D: invalid format from QRhiGles2::executeCommandBuffer, so most library shaders that use an image rendered nothing. QRhiGles2::toGlTextureFormat() sets glformat to GL_BGRA for QRhiTexture::BGRA8 unconditionally; caps.bgraExternalFormat only gates isTextureFormatSupported(), which none of these call sites checked. WebGL has no BGRA format at all -- EXT_texture_format_BGRA8888 is not exposed there -- so both texImage2D and texSubImage2D reject it. Verified in the browser against a plain WebGL2 context: of the formats this code uses, only BGRA8 fails, while RGBA8, R8, R32F, RGBA16F and RGBA32F are all accepted. Ask the QRhi whether it really has BGRA8, and fall back to RGBA8 when it does not. This is a runtime decision rather than a wasm ifdef, so any other backend missing the format is covered too, and desktop keeps using BGRA8 and its existing QImage::Format_ARGB32 data unchanged. QRhi uploads a QImage's bits as-is, so the image has to be in whichever byte order the texture ended up with; adaptImageFormat() converts it, preserving premultiplication so only the channel order changes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019oPj1zRcxSQX7FNni7EHM6
Verified end-to-end on wasm: the INVALID_ENUM is goneDriven headlessly through CDP: open the process library → create an interval → double-click Before (no fix): After (this PR's commit): Same scenario, same machine, same headless Chrome. The two Important caveat about which builds those numbers come fromThis PR cannot be observed on wasm on its own. Built from So the A/B above was run on two purpose-built images:
(both deployed under the usual test server; the branch itself was not modified, and the temporary merge branch has been deleted). Worth knowing for whoever merges: #2147 is only user-visible on wasm once #2144 is in. Content renderingThe render pipeline runs and the background renderer takes over the timeline background, but I could not get the glyphs themselves to show up in a screenshot even at 300pt, so I am not claiming visual confirmation — only that the uploads now succeed and the graph renders without error. Worth a human eyeball on a real shader. Channel order — checked in code, not visuallyNo swap risk in the four sites: every ImageNode upload goes through Sites this PR does not coverNot blockers for the stated scope, but they are the same bug and will bite on wasm:
|
On WebAssembly, uploading any image raised
so most library shaders that use an image rendered nothing.
Cause
QRhiGles2::toGlTextureFormat()setsglformat = GL_BGRAforQRhiTexture::BGRA8unconditionally (qrhigles2.cpp:1395).caps.bgraExternalFormatonly gatesisTextureFormatSupported(), which none of these call sites checked. WebGL has no BGRA format at all —EXT_texture_format_BGRA8888is not exposed — so bothtexImage2DandtexSubImage2Dreject it.Reproduced against a plain WebGL2 context, replicating the exact
(internalformat, format, type)triples Qt produces:Only BGRA8 fails; the context is WebGL2 / GLSL ES 3.00, so
GL_REDand the float formats are all fine.Fix
Ask the QRhi whether it actually has BGRA8 and fall back to RGBA8 when it does not. A runtime check rather than a wasm
#ifdef, so any other backend missing the format is covered; desktop keeps BGRA8 and its existingQImage::Format_ARGB32data unchanged.QRhi uploads a QImage's bits as-is, so
adaptImageFormat()puts the image in whichever byte order the texture ended up with, preserving premultiplication so only channel order changes.Four call sites:
ImageNode×3,TextNode×1. No shader changes.Verification