refactor(particles): use lossless RGBA32U fallback instead of pack8#8926
Merged
Conversation
When float textures are not renderable (some WebGL2 devices lacking EXT_color_buffer_float), GPU particle state was stored in RGBA8 textures via a lossy bit-packing (pack8) with per-frame bounds remapping. Replace this with lossless RGBA32U integer textures that store exact float bits, selected in-shader via the global CAPS_TEXTURE_FLOAT_RENDERABLE define. WebGPU is always float-renderable, so its shaders are unaffected (dead PACK8 branches removed). This removes the pack8 flag, calculateBoundsMad, and the maxVel / inBounds / outBounds remapping machinery, and drops the integer state-texture height from 4 rows back to 2. Also remove two dead WebGL1-era useCpu guards (maxVertexTextures <= 1 and fragmentUniformsCount < 64) that cannot trigger under WebGL2 spec minimums.
Build size reportThis PR changes the size of the minified bundles.
|
The float and u32 readInput/writeOutput chunks differed only in the texel cast, so fold them into single particleInput / particleOutput chunks. The GLSL chunk handles the difference internally with a small #ifdef CAPS_TEXTURE_FLOAT_RENDERABLE around just the cast; the WGSL chunk is the float logic (WebGPU is always float-renderable). Include sites in both backends are now identical and the per-format branch is gone from them.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR refactors the GPU particle system fallback path by removing the legacy lossy pack8 (RGBA8 packing) approach and introducing a lossless “store float bits” path that uses RGBA32U integer state textures when float render targets are unavailable, with shader selection controlled via CAPS_TEXTURE_FLOAT_RENDERABLE.
Changes:
- Consolidates particle state read/write shader chunks into unified
particleInput/particleOutputimplementations (GLSL + WGSL) and removes the oldPACK8branches/chunks. - Switches GPU particle state textures to
RGBA32Fwhen float-renderable, otherwiseRGBA32U, and updates CPU uploads to reinterpret float bytes asUint32bit patterns. - Removes pack8-related bounds/velocity remapping machinery and deletes unreachable legacy CPU-forcing guards.
Reviewed changes
Copilot reviewed 21 out of 23 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/scene/shader-lib/wgsl/collections/particle-chunks-wgsl.js | Rewires WGSL particle chunk registry to use unified input/output chunks. |
| src/scene/shader-lib/wgsl/chunks/particle/vert/particle-shader.js | Removes PACK8 include branching; always includes unified input chunk. |
| src/scene/shader-lib/wgsl/chunks/particle/frag/particleOutputRgba8.js | Deletes the old RGBA8 packing output path. |
| src/scene/shader-lib/wgsl/chunks/particle/frag/particleOutput.js | Adds unified WGSL particle state output (2-row layout). |
| src/scene/shader-lib/wgsl/chunks/particle/frag/particleInputRgba8.js | Deletes the old RGBA8 packing input path. |
| src/scene/shader-lib/wgsl/chunks/particle/frag/particleInput.js | Adds unified WGSL particle state input (2-row layout). |
| src/scene/shader-lib/wgsl/chunks/particle/frag/particle-simulation.js | Removes PACK8 branching; uses unified input/output chunks. |
| src/scene/shader-lib/programs/particle.js | Removes PACK8 define generation from particle render shader program. |
| src/scene/shader-lib/glsl/collections/particle-chunks-glsl.js | Rewires GLSL particle chunk registry to use unified input/output chunks. |
| src/scene/shader-lib/glsl/chunks/particle/vert/particle-shader.js | Removes PACK8 include branching; always includes unified input chunk. |
| src/scene/shader-lib/glsl/chunks/particle/vert/particle_init.js | Switches particle state samplers between sampler2D / usampler2D based on CAPS_TEXTURE_FLOAT_RENDERABLE. |
| src/scene/shader-lib/glsl/chunks/particle/frag/particleUpdaterInit.js | Switches particleTexIN between sampler2D / usampler2D based on CAPS_TEXTURE_FLOAT_RENDERABLE. |
| src/scene/shader-lib/glsl/chunks/particle/frag/particleOutputRgba8.js | Deletes the old RGBA8 packing output path. |
| src/scene/shader-lib/glsl/chunks/particle/frag/particleOutputFloat.js | Deletes the old float output chunk (replaced by unified output). |
| src/scene/shader-lib/glsl/chunks/particle/frag/particleOutput.js | Adds unified GLSL particle state output, writing float or float-bit uvec4 based on capability define. |
| src/scene/shader-lib/glsl/chunks/particle/frag/particleInputRgba8.js | Deletes the old RGBA8 packing input path. |
| src/scene/shader-lib/glsl/chunks/particle/frag/particleInputFloat.js | Deletes the old float input chunk (replaced by unified input). |
| src/scene/shader-lib/glsl/chunks/particle/frag/particleInput.js | Adds unified GLSL particle state input, reading float or uint-bit floats based on capability define. |
| src/scene/shader-lib/glsl/chunks/particle/frag/particle-simulation.js | Removes PACK8 branching; uses unified input/output chunks. |
| src/scene/particle-system/particle-material.js | Removes pack8 option from particle material shader option set. |
| src/scene/particle-system/particle-emitter.js | Selects RGBA32F vs RGBA32U for GPU state textures; removes pack8 sizing/remap logic; sets integer fragment output type. |
| src/scene/particle-system/gpu-updater.js | Removes pack8-only uniforms/bounds remap uploads. |
| src/scene/particle-system/cpu-updater.js | Removes pack8 encoding logic and simplifies spawn-state initialization. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
624
to
+630
| if (!this.useCpu) { | ||
| if (this.pack8) { | ||
| this.particleTexIN = _createTexture(gd, this.numParticlesPot, particleTexHeight, this.particleTex, PIXELFORMAT_RGBA8, 1, false); | ||
| this.particleTexOUT = _createTexture(gd, this.numParticlesPot, particleTexHeight, this.particleTex, PIXELFORMAT_RGBA8, 1, false); | ||
| this.particleTexStart = _createTexture(gd, this.numParticlesPot, particleTexHeight, this.particleTexStart, PIXELFORMAT_RGBA8, 1, false); | ||
| } else { | ||
| this.particleTexIN = _createTexture(gd, this.numParticlesPot, particleTexHeight, this.particleTex); | ||
| this.particleTexOUT = _createTexture(gd, this.numParticlesPot, particleTexHeight, this.particleTex); | ||
| this.particleTexStart = _createTexture(gd, this.numParticlesPot, particleTexHeight, this.particleTexStart); | ||
| } | ||
| // use float textures when renderable, otherwise fall back to integer textures storing | ||
| // the exact float bits (RGBA32U is always renderable on WebGL2 and WebGPU) | ||
| const particleFormat = gd.textureFloatRenderable ? PIXELFORMAT_RGBA32F : PIXELFORMAT_RGBA32U; | ||
| this.particleTexIN = _createTexture(gd, this.numParticlesPot, particleTexHeight, this.particleTex, particleFormat); | ||
| this.particleTexOUT = _createTexture(gd, this.numParticlesPot, particleTexHeight, this.particleTex, particleFormat); | ||
| this.particleTexStart = _createTexture(gd, this.numParticlesPot, particleTexHeight, this.particleTexStart, particleFormat); |
Contributor
Author
There was a problem hiding this comment.
rubbish, those are in code webgl 2.0 spec as renderable.
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.
Replaces the GPU particle system's lossy
pack8(RGBA8 bit-packing) fallback — used when float textures aren't renderable on some WebGL2 devices lackingEXT_color_buffer_float— with losslessRGBA32Uinteger textures that store exact float bits. The storage format is selected in-shader via the globalCAPS_TEXTURE_FLOAT_RENDERABLEdefine, mirroring the depth prepass. WebGPU is always float-renderable, so its shaders are unaffected.Changes:
particleInputU32/particleOutputU32chunks (read viausampler2D+uintBitsToFloat, write viafloatBitsToUintwithfragmentOutputTypes: 'uvec4'); simulation and render shaders branch onCAPS_TEXTURE_FLOAT_RENDERABLE.RGBA32Fwhen renderable, elseRGBA32U; CPU uploads the same float bytes reinterpreted asUint32(lossless, no bounds remapping).pack8path entirely: thepack8flag,calculateBoundsMad, and themaxVel/inBounds/outBoundsremapping machinery; the fallback state-texture height drops from 4 rows back to 2.useCpuguards (maxVertexTextures <= 1,fragmentUniformsCount < 64) — both are unreachable under WebGL2 spec minimums. CPU sorting remains the genuine CPU-mode trigger.particleInputRgba8/particleOutputRgba8chunks (GLSL and WGSL) and the dead WGSLPACK8branches.Performance:
Notes:
textureFloatRenderable = falserun to exercise theRGBA32Upath.