Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions src/scene/gsplat-unified/gsplat-work-buffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,14 @@ class GSplatWorkBuffer {
/** @type {GSplatWorkBufferRenderPass} */
colorRenderPass;

/**
* Stream-set version the render targets were created for.
*
* @type {number}
* @private
*/
_renderTargetsVersion = -1;

/**
* GPU frustum culler for octree node visibility.
*
Expand Down Expand Up @@ -317,6 +325,7 @@ class GSplatWorkBuffer {

// Collect all textures in order for MRT
const colorBuffers = this.streams.getTexturesInOrder();
this._renderTargetsVersion = this.streams._formatVersion;
// viewport rects used to fill the work buffer must address identical texel rows on all
// graphics APIs, matching the WebGL layout
this.renderTarget = new RenderTarget({
Expand Down Expand Up @@ -345,11 +354,13 @@ class GSplatWorkBuffer {
* Call this before rendering to ensure all streams have textures.
*/
syncWithFormat() {
const prevVersion = this.streams._formatVersion;
this.streams.syncWithFormat(this.format);

// If format changed, recreate render targets to include new textures
if (prevVersion !== this.streams._formatVersion) {
// Recreate the render targets when they were built for an older stream set. Compared
// against the version the targets were built for, not the streams' version before this
// call: getTexture() syncs the streams on its own, so by the time this runs they can
// already be up to date while the targets still lack the new textures.
if (this._renderTargetsVersion !== this.streams._formatVersion) {
this._createRenderTargets();
}
}
Expand Down
49 changes: 49 additions & 0 deletions test/scene/gsplat-unified/gsplat-work-buffer.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { expect } from 'chai';

import { PIXELFORMAT_R8 } from '../../../src/platform/graphics/constants.js';
import { NullGraphicsDevice } from '../../../src/platform/graphics/null/null-graphics-device.js';
import { GSplatParams } from '../../../src/scene/gsplat-unified/gsplat-params.js';
import { GSplatWorkBuffer } from '../../../src/scene/gsplat-unified/gsplat-work-buffer.js';

describe('GSplatWorkBuffer#syncWithFormat', function () {
let device;
let workBuffer;

beforeEach(function () {
device = new NullGraphicsDevice({ width: 1, height: 1 });
});

afterEach(function () {
workBuffer?.destroy();
workBuffer = null;
device.destroy();
});

it('attaches a stream added after creation', function () {
const params = new GSplatParams(device);
workBuffer = new GSplatWorkBuffer(device, params.format);
const before = workBuffer.renderTarget.colorBufferCount;

params.format.addExtraStreams([{ name: 'testStream', format: PIXELFORMAT_R8 }]);
workBuffer.syncWithFormat();

expect(workBuffer.renderTarget.colorBufferCount).to.equal(before + 1);
expect(workBuffer.renderTarget.getColorBuffer(before)).to.equal(workBuffer.getTexture('testStream'));
});

it('attaches a stream added after creation even if getTexture() synced the streams first', function () {
const params = new GSplatParams(device);
workBuffer = new GSplatWorkBuffer(device, params.format);
const before = workBuffer.renderTarget.colorBufferCount;

params.format.addExtraStreams([{ name: 'testStream', format: PIXELFORMAT_R8 }]);

// a renderer binding textures by name syncs the streams on its own
const texture = workBuffer.getTexture('testStream');
expect(texture).to.not.equal(undefined);

workBuffer.syncWithFormat();
expect(workBuffer.renderTarget.colorBufferCount).to.equal(before + 1);
expect(workBuffer.renderTarget.getColorBuffer(before)).to.equal(texture);
});
});
Loading