vgpu/coreAdvanced4 symbolsView source ↗

Symbols in this topic

UniformPool

Dynamic-offset ring allocator for many per-draw uniforms. Allocate a typed UniformSlot once, push values each frame, call endFrame(), and pass returned offsets through p.draw(draw, { offsets }).

Import

TypeScript
1
2
import { UniformPool } from "vgpu/core";
import type { UniformPoolOptions, UniformLayout, UniformSlot } from "vgpu/core";

Signature

TypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import type { Device } from "vgpu/core";
 
interface UniformPoolOptions {
  readonly capacityBytes?: number;
}
 
interface UniformLayout<T> {
  readonly size: number;
  readonly bindings?: readonly GPUBindGroupLayoutEntry[];
  readonly bindGroupLayout?: GPUBindGroupLayout;
  encode(value: T, dst: ArrayBuffer, byteOffset: number): void;
}
 
interface UniformSlot<T> {
  readonly pool: UniformPool;
  readonly layout: UniformLayout<T>;
  readonly bindGroup: GPUBindGroup;
  readonly bindGroupLayout: GPUBindGroupLayout;
  readonly gpu: GPUBuffer;
  readonly stride: number;
  push(value: T): number;
  pushBytes(bytes: ArrayBufferView<ArrayBuffer>): number;
}
 
declare class UniformPool {
  readonly device: Device;
  readonly minOffsetAlignment: number;
  readonly capacityBytes: number;
  readonly maxUniformBindingSize: number;
  readonly cpuMirror: ArrayBuffer;
  readonly gpu: GPUBuffer;
  constructor(device: Device, opts?: UniformPoolOptions);
  get usedBytes(): number;
  get disposed(): boolean;
  alloc<T>(layout: UniformLayout<T>): UniformSlot<T>;
  push<T>(slot: UniformSlot<T>, value: T): number;
  pushBytes(slot: UniformSlot<unknown>, bytes: ArrayBufferView<ArrayBuffer>): number;
  beginFrame(frameIndex: number): void;
  endFrame(): void;
  assertReadyForSubmit(where: string): void;
  dispose(): void;
}

Parameters

ParamTypeRequiredDefaultNotes
deviceDeviceCore device. Device limits determine alignment and max binding size.
optsUniformPoolOptions{}Pool capacity options.
opts.capacityBytesnumber4 * 1024 * 1024CPU mirror and GPU buffer size.
layout.sizenumberLogical uniform byte size before stride alignment. Must fit both pool capacity and maxUniformBufferBindingSize.
layout.bindingsreadonly GPUBindGroupLayoutEntry[]Binding 0 uniform, dynamic offset, visibility vertex+fragmentUsed only when layout.bindGroupLayout is omitted.
layout.bindGroupLayoutGPUBindGroupLayoutNew layout from layout.bindings or default binding 0Usually draw.layout(group, { dynamicOffsets: true }) so the draw pipeline and slot agree.
layout.encode(value, dst, byteOffset) => voidWrites one value into the pool CPU mirror at byteOffset.
alloc.layoutUniformLayout<T>Layout used for one reusable slot. Slot stride is roundUp(layout.size, minUniformBufferOffsetAlignment).
push.slotUniformSlot<T>Must be allocated by the same pool.
push.valueTEncoded into the CPU mirror; returned offset is passed as dynamic offset.
pushBytes.bytesArrayBufferView<ArrayBuffer>Must have byte length exactly equal to slot.layout.size.
beginFrame.frameIndexnumberCurrently unused marker; call before pushes to reset the ring head to 0.
assertReadyForSubmit.wherestringError context if pushes are unflushed.

Returns: Constructor returns UniformPool; alloc() returns UniformSlot<T>; push() / pushBytes() return the dynamic byte offset; usedBytes returns current ring head; lifecycle methods return void.

Throws: VGPU-UNIFORM-POOL-OVERFLOW when a push would exceed capacityBytes; VGPU-UNIFORM-LAYOUT-OVERSIZED when layout.size exceeds pool capacity or device maxUniformBufferBindingSize; VGPU-CORE-INVALID-USAGE when using a disposed pool, pushing a slot from another pool, pushBytes length mismatches, or submitting before endFrame() flushes unflushed pushes.

Examples

TypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import { init, clock, draw, frame, target } from "vgpu/mock";
import { UniformPool, type UniformLayout } from "vgpu/core";
 
const gpu = await init();
const colorTarget = target(gpu, { size: [32, 32] });
const drawable = draw(gpu, { shader: `
  struct Object { model: mat4x4f }
  @group(0) @binding(0) var<uniform> object: Object;
  @vertex fn vs_main(@builtin(vertex_index) vi: u32) -> @builtin(position) vec4f {
    var p = array<vec2f, 3>(vec2f(-1, -1), vec2f(3, -1), vec2f(-1, 3));
    return object.model * vec4f(p[vi], 0, 1);
  }
  @fragment fn fs_main() -> @location(0) vec4f { return vec4f(1); }
` });
 
type ObjectUniforms = { model: Float32Array };
const objectLayout: UniformLayout<ObjectUniforms> = {
  size: 64,
  bindGroupLayout: drawable.layout(0, { dynamicOffsets: true }),
  encode(value, dst, byteOffset) {
    new Float32Array(dst, byteOffset, 16).set(value.model);
  },
};
const pool = new UniformPool(gpu.device, { capacityBytes: 1 << 20 });
const slot = pool.alloc(objectLayout);
drawable.group(0, slot.bindGroup);
 
pool.beginFrame(clock(gpu).frameCount);
const offset = slot.push({ model: new Float32Array(16) });
pool.endFrame();
frame(gpu, (currentFrame) => currentFrame.pass({ target: colorTarget }, (pass) => pass.draw(drawable, { offsets: { 0: [offset] } })));
TypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { init } from "vgpu/mock";
import { UniformPool, type UniformLayout } from "vgpu/core";
 
const gpu = await init();
const pool = new UniformPool(gpu.device, { capacityBytes: 1024 });
const layout: UniformLayout<Float32Array> = {
  size: 16,
  encode(value, dst, byteOffset) { new Float32Array(dst, byteOffset, 4).set(value); },
};
const slot = pool.alloc(layout);
pool.beginFrame(0);
const offset = slot.pushBytes(new Float32Array([1, 0, 0, 0]));
pool.endFrame();
void offset;

Notes

  • Call beginFrame() before pushes and endFrame() before submitting commands that use the returned offsets.
  • A dynamic-offset bind group stores offset: 0; the per-draw offset comes from DrawCallOptions.offsets.
  • The pool is a ring for transient per-frame data, not long-lived storage. Persistent globals usually fit Uniform or SharedUniforms better.
  • See also: Draw.layout, DrawCallOptions.offsets, FramePass.draw, Uniform, StructuredUniform.