Skip to content

Remove per-resource instance vertex buffer from GSplat rendering#8513

Merged
mvaligursky merged 2 commits intomainfrom
mv-gsplat-attributeless-instancing
Mar 9, 2026
Merged

Remove per-resource instance vertex buffer from GSplat rendering#8513
mvaligursky merged 2 commits intomainfrom
mv-gsplat-attributeless-instancing

Conversation

@mvaligursky
Copy link
Contributor

@mvaligursky mvaligursky commented Mar 9, 2026

Replaces the per-resource instance vertex buffer (vertex_id_attrib) in GSplat rendering with attributeless instancing, deriving the splat base index from gl_InstanceID / pcInstanceIndex GPU builtins instead.

Changes:

  • Remove createInstanceIndices and all per-resource instance VB allocation/reallocation from GSplatResourceBase
  • Remove setMaxNumSplats dynamic reallocation from GSplatRenderer
  • Update GLSL and WGSL gsplatSource shaders to compute source.order from the instance index builtin multiplied by a GSPLAT_INSTANCE_SIZE define
  • Apply the same changes to both the unified (GSplatRenderer) and legacy (GSplatInstance) rendering paths

API Changes:

  • MeshInstance.setInstancing now accepts true as the vertexBuffer parameter to enable attributeless instancing (count-only, no per-instance vertex buffer). The caller must set instancingCount manually.

Performance:

  • Eliminates per-resource GPU memory allocation for instance index vertex buffers
  • Removes dynamic reallocation when total splat count grows

Replace vertex_id_attrib with attributeless instancing, deriving the
splat base index from gl_InstanceID / pcInstanceIndex GPU builtins.
This eliminates per-resource GPU memory allocation and dynamic
reallocation for instance index vertex buffers.

MeshInstance.setInstancing now accepts `true` for attributeless
instancing (count-only, no per-instance VB).

Made-with: Cursor
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors GSplat rendering to remove the per-resource instance-index vertex buffer and instead derive the base splat index from the GPU instance index builtins (gl_InstanceID / pcInstanceIndex), reducing GPU allocations and reallocations as splat counts change.

Changes:

  • Switched GSplat shaders (GLSL/WGSL) to compute source.order from the instance index builtin and a {GSPLAT_INSTANCE_SIZE} replacement define.
  • Removed per-resource instance index vertex buffer creation/ownership from GSplatResourceBase and removed dynamic resizing logic from the unified renderer/manager path.
  • Extended MeshInstance.setInstancing to accept true for attributeless instancing (instance-count only).

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/scene/shader-lib/wgsl/chunks/gsplat/vert/gsplatSource.js Uses pcInstanceIndex + {GSPLAT_INSTANCE_SIZE} to derive splat order (no vertex_id_attrib).
src/scene/shader-lib/glsl/chunks/gsplat/vert/gsplatSource.js Uses gl_InstanceID + {GSPLAT_INSTANCE_SIZE} to derive splat order (no vertex_id_attrib).
src/scene/mesh-instance.js Adds attributeless instancing mode via setInstancing(true, ...).
src/scene/gsplat/gsplat-resource-base.js Removes per-resource instance index VB allocation and lifetime management.
src/scene/gsplat/gsplat-material.js Drops vertex_id_attrib attribute binding; injects {GSPLAT_INSTANCE_SIZE} define.
src/scene/gsplat/gsplat-instance.js Switches legacy path to attributeless instancing; injects {GSPLAT_INSTANCE_SIZE} define during configuration.
src/scene/gsplat-unified/gsplat-renderer.js Switches unified path to attributeless instancing; removes setMaxNumSplats; injects/protects {GSPLAT_INSTANCE_SIZE} define.
src/scene/gsplat-unified/gsplat-manager.js Removes calls to the deleted renderer.setMaxNumSplats.
Comments suppressed due to low confidence (1)

src/scene/gsplat-unified/gsplat-renderer.js:426

  • In indirect-draw mode (when draw commands are provided), instancingCount is GPU-driven and numInstances is ignored by WebgpuGraphicsDevice.draw(), but the forward/shadow renderers still skip any draw call where instancingData.count <= 0. With attributeless instancing, setInstancing(true, ...) initializes InstancingData with count = 0 and createMeshInstance() leaves instancingCount = 0, so indirect GSplat rendering will be skipped entirely. Consider setting meshInstance.instancingCount to a non-zero sentinel (for example 1) when indirect draw is enabled (e.g. in setIndirectDraw / updateIndirect) or initializing attributeless instancing with a default count of 1 for indirect-driven paths.
        const mesh = GSplatResourceBase.createMesh(this.device);
        const meshInstance = new MeshInstance(mesh, this._material);
        meshInstance.node = this.node;
        meshInstance.setInstancing(true, true);

        // only start rendering the splat after we've received the splat order data
        meshInstance.instancingCount = 0;


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@mvaligursky mvaligursky merged commit 3fa2f0b into main Mar 9, 2026
8 checks passed
@mvaligursky mvaligursky deleted the mv-gsplat-attributeless-instancing branch March 9, 2026 12:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants