This commit is contained in:
Andras Schmelczer 2026-05-13 21:07:10 +01:00
commit 39b0160064
136 changed files with 7129 additions and 1950 deletions

View file

@ -0,0 +1,58 @@
import { describe, expect, it, vi } from 'vitest';
import {
createCachedFloat32BufferWrite,
writeFloat32BufferIfChanged,
} from './cached-buffer-write';
const createGpuWriteStub = () => {
const writeBuffer = vi.fn();
const device = {
queue: {
writeBuffer,
},
} as unknown as GPUDevice;
return { device, writeBuffer };
};
describe('cached float32 buffer writes', () => {
it('writes the first value set and skips unchanged values', () => {
const { device, writeBuffer } = createGpuWriteStub();
const buffer = {} as GPUBuffer;
const cache = createCachedFloat32BufferWrite(3);
const values = new Float32Array([1, 2, 3]);
expect(writeFloat32BufferIfChanged(device, buffer, values, cache)).toBe(true);
expect(writeBuffer).toHaveBeenCalledTimes(1);
expect(writeBuffer).toHaveBeenLastCalledWith(buffer, 0, values);
expect(writeFloat32BufferIfChanged(device, buffer, values, cache)).toBe(false);
expect(writeBuffer).toHaveBeenCalledTimes(1);
});
it('writes again when any float changes', () => {
const { device, writeBuffer } = createGpuWriteStub();
const buffer = {} as GPUBuffer;
const cache = createCachedFloat32BufferWrite(3);
expect(
writeFloat32BufferIfChanged(device, buffer, new Float32Array([1, 2, 3]), cache)
).toBe(true);
expect(
writeFloat32BufferIfChanged(device, buffer, new Float32Array([1, 2, 4]), cache)
).toBe(true);
expect(writeBuffer).toHaveBeenCalledTimes(2);
});
it('rejects cache length mismatches before writing', () => {
const { device, writeBuffer } = createGpuWriteStub();
const buffer = {} as GPUBuffer;
const cache = createCachedFloat32BufferWrite(2);
expect(() =>
writeFloat32BufferIfChanged(device, buffer, new Float32Array([1]), cache)
).toThrow('Cached buffer write length mismatch');
expect(writeBuffer).not.toHaveBeenCalled();
});
});

View file

@ -0,0 +1,36 @@
export interface CachedFloat32BufferWrite {
hasValue: boolean;
previous: Float32Array;
}
export const createCachedFloat32BufferWrite = (
length: number
): CachedFloat32BufferWrite => ({
hasValue: false,
previous: new Float32Array(length),
});
export const writeFloat32BufferIfChanged = (
device: GPUDevice,
buffer: GPUBuffer,
values: Float32Array,
cache: CachedFloat32BufferWrite
): boolean => {
if (values.length !== cache.previous.length) {
throw new Error('Cached buffer write length mismatch');
}
let hasChanged = !cache.hasValue;
for (let i = 0; i < values.length && !hasChanged; i++) {
hasChanged = !Object.is(values[i], cache.previous[i]);
}
if (!hasChanged) {
return false;
}
cache.previous.set(values);
cache.hasValue = true;
device.queue.writeBuffer(buffer, 0, values);
return true;
};