feat: support dynamic work buffer formats in compute GSplat renderers#8547
Merged
mvaligursky merged 3 commits intomainfrom Mar 24, 2026
Merged
feat: support dynamic work buffer formats in compute GSplat renderers#8547mvaligursky merged 3 commits intomainfrom
mvaligursky merged 3 commits intomainfrom
Conversation
Compute tiled renderers now dynamically support different work buffer formats instead of hardcoding the compact format's bindings and decode logic. Format-specific shader code is generated from GSplatFormat metadata, with shader recreation on format changes at runtime. Made-with: Cursor
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates the unified compute-based GSplat renderers to work with multiple work-buffer layouts (compact vs large/packed) by generating compute shader bindings/declarations and read/decode logic from GSplatFormat metadata instead of hardcoding compact-only streams and decoders.
Changes:
- Add compute-specific stream declaration/bind-format generation on
GSplatFormat, and new WGSL helper chunks for compute splat indexing + explicit bindings. - Refactor compute tile-count shaders to use format-provided declarations/read code and clamp negative color before gamma conversion.
- Recreate compute shaders when the work-buffer format (hash) or tonemap/gamma changes, consolidating recreation triggers.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| src/scene/shader-lib/wgsl/chunks/gsplat/vert/gsplatComputeStreamDecl.js | New WGSL template to declare compute-bound stream textures with explicit @binding and load helpers. |
| src/scene/shader-lib/wgsl/chunks/gsplat/vert/gsplatComputeSplat.js | New WGSL chunk providing a compute-compatible Splat struct and setSplat() helper. |
| src/scene/shader-lib/wgsl/chunks/gsplat/compute-gsplat-tile-count.js | Switch to format-generated declarations/read code and remove compact-specific decode paths; clamp color before gamma. |
| src/scene/shader-lib/wgsl/chunks/gsplat/compute-gsplat-local-tile-count.js | Same as global tile-count, updated for the local/compacted-ID path. |
| src/scene/shader-lib/wgsl/chunks/gsplat/compute-gsplat-common.js | Remove compact-only decode helpers now replaced by format read chunks. |
| src/scene/gsplat/gsplat-format.js | Add getComputeInputDeclarations() and getComputeBindFormats() to generate compute bindings from format metadata. |
| src/scene/gsplat-unified/gsplat-compute-local-renderer.js | Bind all format streams dynamically and recreate count compute when format hash/tonemap/gamma changes. |
| src/scene/gsplat-unified/gsplat-compute-global-renderer.js | Same dynamic binding + recreation logic for the global compute renderer. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…ity(), repack compact format, getColor() returns vec3 - Derive formatStartBinding from fixed bindings array length instead of hardcoding - Include extra streams (pcId, pcNodeIndex) in compute bind formats, declarations, and dispatch loops - Add getOpacity() to work buffer format readers for early opacity culling before loading color - Repack compact format: co-locate alpha with center in dataTransformA, move rotation to dataTransformB - Change getColor() to return vec3 (RGB only) for both work buffer formats; opacity handled separately - Remove conditional colorLoaded branch in packed format reader; getOpacity() unconditionally caches color - Add GSPLAT_SEPARATE_OPACITY define for quad VS to call getOpacity() before getColor() - Consolidate shader recreation to avoid redundant double-recreation per frame Made-with: Cursor
Contributor
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 18 out of 18 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
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.
Compute tiled GSplat renderers now dynamically support different work buffer formats (compact and large) instead of hardcoding the compact format's texture bindings and decode logic.
Changes:
getComputeInputDeclarations()andgetComputeBindFormats()toGSplatFormatfor generating compute shader bindings and declarations from format metadata (including extra streams likepcId,pcNodeIndex)#includedirectives (gsplatComputeSplatCS,gsplatFormatDeclCS,gsplatFormatReadCS)decodeRotation(),decodeScale(),decodeColor()fromcompute-gsplat-common.js— format read chunks now handle all decodingformatStartBindingfrom fixed bindings array length instead of hardcoding magic numbersGSPLAT_COLOR_FLOATdefine for non-RGBA16U color formats to use the correct float reading pathpow()on negative inputs, matching the quad rendererCompact format repack:
dataTransformA(scale.xyz 3×8-bit + alpha 8-bit), move rotation todataTransformBdataColoranddataTransformBloads entirelyWork buffer getOpacity()/getColor() API:
getOpacity()to both work buffer format readers for early culling before loading color datagetColor()to returnvec3(RGB only) for both work buffer formats; opacity handled separately viagetOpacity()getOpacity()unconditionally loads and caches color (no conditional branch);getColor()returns cached RGBgetOpacity()reads alpha fromcachedTransformA(no extra texture load);getColor()returns decoded RGBGSPLAT_SEPARATE_OPACITYdefine to callgetOpacity()beforegetColor()when rendering from work buffergetCenter()→getOpacity()→getColor()for all work buffer consumers (compute shaders and quad VS)Performance: