playcanvas / playcanvas/engine
Deprecate Texture#flipY (upload flag): inconsistent / no-op on WebGPU and ImageBitmap sources
@mvaligursky is already working on this.
Since Jul 23, 2026.
- Dominant language
- JavaScript
- Stars
- 16.8k
- Forks
- 2k
- Avg merge
- 4h 9m
- Merged PRs (30d)
- 218
Description
Summary
Texture#flipY (the texture upload orientation flag, distinct from the now-removed RenderTarget#flipY) is applied inconsistently and, for the common asset-loading path, is effectively a silent no-op. This issue captures the investigation so it can be resolved in the future — the recommendation is to deprecate it.
Note: this is not about RenderTarget#flipY / render-to-texture orientation, which has been addressed by the new RenderTarget origin option (RENDERTARGET_ORIGIN_TOP / BOTTOM / NATIVE, #9101 + #9105). See also #6334 (RenderTarget upside-down on WebGPU), which the origin work resolves.
Current behavior
Texture#flipY only has any effect for HTML-element sources (<img> / <canvas> / <video>) on WebGL2, where the upload path calls device.setUnpackFlipY(texture._flipY):
src/platform/graphics/webgl/webgl-texture.js(element / image-canvas-video upload paths)
It is a silent no-op for:
ImageBitmapsources — the WebGL2 spec ignoresUNPACK_FLIP_Y_WEBGLforImageBitmap(the bitmap's baked orientation wins). The image parser creates bitmaps with noimageOrientation:src/framework/parsers/texture/img.js→createImageBitmap(blob, { premultiplyAlpha: 'none', colorSpaceConversion: 'none' })
- WebGPU, all sources — the upload descriptor hardcodes
flipY: false, even thoughcopyExternalImageToTexturesupports it (notepremultipliedAlpharight beside it is wired —flipYis simply an unfinished orphan):src/platform/graphics/webgpu/webgpu-texture.js→uploadExternalImagesource{ ..., flipY: false }
- Raw byte-array / compressed uploads — forced
falseby design (documented; flipping raw pixel data is out of scope).
The cross-browser sting
supportsImageBitmap gates which source type the asset loader produces:
src/platform/graphics/webgl/webgl-graphics-device.js→this.supportsImageBitmap = !isSafari && typeof ImageBitmap !== 'undefined';src/platform/graphics/webgpu/webgpu-graphics-device.js→this.supportsImageBitmap = true;
So for a texture asset with flipY: true in its data (src/framework/handlers/texture.js passes assetData.flipY through):
| Safari WebGL2 | Chrome/FF WebGL2 | Any WebGPU | |
|---|---|---|---|
| upload source | <img> |
ImageBitmap |
ImageBitmap |
flipY: true result |
flips | ignored | ignored |
i.e. the same asset flips in Safari-WebGL2 and nowhere else — not merely "ignored," but inconsistent across browsers, which is arguably worse (a latent cross-browser bug for anyone who sets it).
flipY still works reliably only when a texture is built manually from a <canvas> / <video> / <img> element on WebGL2.
Impact / who relies on it
Effectively nothing:
- Engine: only the asset-JSON passthrough in
src/framework/handlers/texture.js(options.flipY = !!assetData.flipY). No engine-internal texture setsflipY: true. - Examples / scripts: none rely on it (the hidden
test/render-target-orientationexample has an "upload flipY on" tile that documents this exact behavior;scripts/utils/download-texture.jshas an unrelated CPU readback row-flip). - PlayCanvas defaults
flipYtofalse(unlike three.js'strue), so it is a rare opt-in.
Recommendation: deprecate Texture#flipY
Rationale, consistent with the RenderTarget.origin direction (orientation is handled explicitly in content / material / render-target origin, not via a magic upload flag):
- Unreliable today — Safari-only for assets, WebGL2-only for manual element sources, never WebGPU.
- WebGPU-only future — where it has never worked, so any content relying on it is already WebGL-era-only.
- Near-zero blast radius — nothing in engine/examples/scripts depends on it; default is
false. - Clear migration — author the texture with the intended orientation / bake the flip into content, flip the UVs in the material, or use
RenderTarget.originfor render-to-texture.
Deprecation shape (when implemented)
Debug.deprecated(...)in theflipYsetter and the constructor-option resolution, mirroring theRenderTarget#flipYdeprecation — but only warn when the value is truthy (falseis the default no-op and should not nag).@deprecatedJSDoc with the migration note above.- No functional change until removal — WebGL2 element uploads keep flipping.
- Removal at the next major.
Caveats to weigh
- Removes a genuinely-working capability for the manual
<canvas>/<video>→ WebGL2 case (e.g. a bottom-up video texture). Migration = flip in material UVs. - The deprecation warning would surface for existing texture assets carrying
flipY: truein their data (editor-exported). Worth checking how often the editor emits it (likely rare given thefalsedefault).
Alternative considered: fix parity instead of deprecating
Wire WebGPU's copyExternalImageToTexture flipY (easy) and pass imageOrientation: 'flipY' at createImageBitmap time. The WebGL ImageBitmap side genuinely cannot honor UNPACK_FLIP_Y (would need a blit), and the parser creates the bitmap before the Texture/flipY is known (ordering problem). Given the WebGPU-only trajectory this is investment in a WebGL-shaped problem — not recommended.
Verification asset
The hidden test/render-target-orientation example ("upload flipY on" tile) already demonstrates the current behavior and can validate whatever change is made.
EOF
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.