Buffers
Memory on the GPU can be allocated and managed through buffers. That way, WGSL shaders can be provided with an additional context, or retrieve the results of parallel computation back to JS. When creating a buffer, a schema for the contained values has to be provided, which allows for:
- Calculating the required size of the buffer,
- Automatic conversion to-and-from a binary representation,
- Type-safe APIs for writing and reading.
As an example, letβs create a buffer for storing particles.
import const tgpu: { const: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/constant/tgpuConstant").constant; fn: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/tgpuFn").fn; comptime: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/comptime").comptime; resolve: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolve; resolveWithContext: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolveWithContext; init: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").init; initFromDevice: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").initFromDevice; slot: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/slot").slot; lazy: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/lazy").lazy; ... 10 more ...; '~unstable': typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/tgpuUnstable");}
tgpu, { import d
d } from 'typegpu';
// Defining a struct typeconst const Particle: d.WgslStruct<{ position: d.Vec3f; velocity: d.Vec3f; health: d.F32;}>
Particle = import d
d.struct<{ position: d.Vec3f; velocity: d.Vec3f; health: d.F32;}>(props: { position: d.Vec3f; velocity: d.Vec3f; health: d.F32;}): d.WgslStruct<{ position: d.Vec3f; velocity: d.Vec3f; health: d.F32;}>export struct
Creates a struct schema that can be used to construct GPU buffers.
Ensures proper alignment and padding of properties (as opposed to a d.unstruct schema).
The order of members matches the passed in properties object.
struct({ position: d.Vec3f
position: import d
d.const vec3f: d.Vec3fexport vec3f
Schema representing vec3f - a vector with 3 elements of type f32.
Also a constructor function for this vector value.
vec3f, velocity: d.Vec3f
velocity: import d
d.const vec3f: d.Vec3fexport vec3f
Schema representing vec3f - a vector with 3 elements of type f32.
Also a constructor function for this vector value.
vec3f, health: d.F32
health: import d
d.const f32: d.F32export f32
A schema that represents a 32-bit float value. (equivalent to f32 in WGSL)
Can also be called to cast a value to an f32.
f32,});
// Utility for creating a random particlefunction function createParticle(): d.Infer<typeof Particle>
createParticle(): import d
d.type Infer<T> = T extends { readonly [$repr]: infer TRepr;} ? TRepr : Texport Infer
Extracts the inferred representation of a resource.
For inferring types as seen by the GPU, see
InferGPU
Infer<typeof const Particle: d.WgslStruct<{ position: d.Vec3f; velocity: d.Vec3f; health: d.F32;}>
Particle> { return { position: d.v3f
position: import d
d.function vec3f(x: number, y: number, z: number): d.v3f (+5 overloads)export vec3f
Schema representing vec3f - a vector with 3 elements of type f32.
Also a constructor function for this vector value.
vec3f(var Math: Math
An intrinsic object that provides basic mathematics functionality and constants.
Math.Math.random(): number
Returns a pseudorandom number between 0 and 1.
random(), 2, var Math: Math
An intrinsic object that provides basic mathematics functionality and constants.
Math.Math.random(): number
Returns a pseudorandom number between 0 and 1.
random()), velocity: d.v3f
velocity: import d
d.function vec3f(x: number, y: number, z: number): d.v3f (+5 overloads)export vec3f
Schema representing vec3f - a vector with 3 elements of type f32.
Also a constructor function for this vector value.
vec3f(0, 9.8, 0), health: number
health: 100, };}
const const root: TgpuRoot
root = await const tgpu: { const: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/constant/tgpuConstant").constant; fn: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/tgpuFn").fn; comptime: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/comptime").comptime; resolve: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolve; resolveWithContext: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolveWithContext; init: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").init; initFromDevice: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").initFromDevice; slot: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/slot").slot; lazy: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/lazy").lazy; ... 10 more ...; '~unstable': typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/tgpuUnstable");}
tgpu.init: (options?: InitOptions) => Promise<TgpuRoot>
Requests a new GPU device and creates a root around it.
If a specific device should be used instead, use
init();
// Creating and initializing a buffer.const const buffer: TgpuBuffer<d.WgslArray<d.WgslStruct<{ position: d.Vec3f; velocity: d.Vec3f; health: d.F32;}>>> & StorageFlag
buffer = const root: TgpuRoot
root .TgpuRoot.createBuffer<d.WgslArray<d.WgslStruct<{ position: d.Vec3f; velocity: d.Vec3f; health: d.F32;}>>>(typeSchema: d.WgslArray<d.WgslStruct<{ position: d.Vec3f; velocity: d.Vec3f; health: d.F32;}>>, initial?: { position: d.v3f; velocity: d.v3f; health: number;}[] | undefined): TgpuBuffer<d.WgslArray<d.WgslStruct<{ position: d.Vec3f; velocity: d.Vec3f; health: d.F32;}>>> (+1 overload)
Allocates memory on the GPU, allows passing data between host and shader.
createBuffer( import d
d.arrayOf<d.WgslStruct<{ position: d.Vec3f; velocity: d.Vec3f; health: d.F32;}>>(elementType: d.WgslStruct<{ position: d.Vec3f; velocity: d.Vec3f; health: d.F32;}>, elementCount: number): d.WgslArray<d.WgslStruct<{ position: d.Vec3f; velocity: d.Vec3f; health: d.F32;}>> (+1 overload)export arrayOf
Creates an array schema that can be used to construct gpu buffers.
Describes arrays with fixed-size length, storing elements of the same type.
arrayOf(const Particle: d.WgslStruct<{ position: d.Vec3f; velocity: d.Vec3f; health: d.F32;}>
Particle, 100), // <- holds 100 particles var Array: ArrayConstructor
Array.ArrayConstructor.from<unknown>(iterable: Iterable<unknown> | ArrayLike<unknown>): unknown[] (+3 overloads)
Creates an array from an iterable object.
from({ ArrayLike<T>.length: number
length: 100 }).Array<unknown>.map<{ position: d.v3f; velocity: d.v3f; health: number;}>(callbackfn: (value: unknown, index: number, array: unknown[]) => { position: d.v3f; velocity: d.v3f; health: number;}, thisArg?: any): { position: d.v3f; velocity: d.v3f; health: number;}[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
map(function createParticle(): d.Infer<typeof Particle>
createParticle), // <- initial value ) .TgpuBuffer<WgslArray<WgslStruct<{ position: Vec3f; velocity: Vec3f; health: F32; }>>>.$usage<["storage"]>(usages_0: "storage"): TgpuBuffer<d.WgslArray<d.WgslStruct<{ position: d.Vec3f; velocity: d.Vec3f; health: d.F32;}>>> & StorageFlag
$usage('storage'); // <- can be used as a "storage buffer"
// -// --// --- Shader omitted for brevity...// --// -
// Reading back from the bufferconst value = await const buffer: TgpuBuffer<d.WgslArray<d.WgslStruct<{ position: d.Vec3f; velocity: d.Vec3f; health: d.F32;}>>> & StorageFlag
buffer.TgpuBuffer<WgslArray<WgslStruct<{ position: Vec3f; velocity: Vec3f; health: F32; }>>>.read(): Promise<{ position: d.v3f; velocity: d.v3f; health: number;}[]>
read();const value: { position: d.v3f; velocity: d.v3f; health: number;}[]
This buffer can then be used and/or updated by a WGSL shader.
Creating a buffer
Section titled βCreating a bufferβTo create a buffer, you will need to define its schema by composing data types imported from typegpu/data. Every WGSL data-type can be represented as JS schemas, including
structs and arrays. They will be explored in more detail in a following chapter.
const countBuffer = const root: TgpuRoot
root.TgpuRoot.createBuffer<d.U32>(typeSchema: d.U32, initial?: number | undefined): TgpuBuffer<d.U32> (+1 overload)
Allocates memory on the GPU, allows passing data between host and shader.
createBuffer(import d
d.const u32: d.U32export u32
A schema that represents an unsigned 32-bit integer value. (equivalent to u32 in WGSL)
Can also be called to cast a value to an u32 in accordance with WGSL casting rules.
u32);const countBuffer: TgpuBuffer<d.U32>
const listBuffer = const root: TgpuRoot
root.TgpuRoot.createBuffer<d.WgslArray<d.F32>>(typeSchema: d.WgslArray<d.F32>, initial?: number[] | undefined): TgpuBuffer<d.WgslArray<d.F32>> (+1 overload)
Allocates memory on the GPU, allows passing data between host and shader.
createBuffer(import d
d.arrayOf<d.F32>(elementType: d.F32, elementCount: number): d.WgslArray<d.F32> (+1 overload)export arrayOf
Creates an array schema that can be used to construct gpu buffers.
Describes arrays with fixed-size length, storing elements of the same type.
arrayOf(import d
d.const f32: d.F32export f32
A schema that represents a 32-bit float value. (equivalent to f32 in WGSL)
Can also be called to cast a value to an f32.
f32, 10));const listBuffer: TgpuBuffer<d.WgslArray<d.F32>>
const uniformsBuffer = const root: TgpuRoot
root.TgpuRoot.createBuffer<d.WgslStruct<{ a: d.F32; b: d.F32;}>>(typeSchema: d.WgslStruct<{ a: d.F32; b: d.F32;}>, initial?: { a: number; b: number;} | undefined): TgpuBuffer<d.WgslStruct<{ a: d.F32; b: d.F32;}>> (+1 overload)
Allocates memory on the GPU, allows passing data between host and shader.
createBuffer(import d
d.struct<{ a: d.F32; b: d.F32;}>(props: { a: d.F32; b: d.F32;}): d.WgslStruct<{ a: d.F32; b: d.F32;}>export struct
Creates a struct schema that can be used to construct GPU buffers.
Ensures proper alignment and padding of properties (as opposed to a d.unstruct schema).
The order of members matches the passed in properties object.
struct({ a: d.F32
a: import d
d.const f32: d.F32export f32
A schema that represents a 32-bit float value. (equivalent to f32 in WGSL)
Can also be called to cast a value to an f32.
f32, b: d.F32
b: import d
d.const f32: d.F32export f32
A schema that represents a 32-bit float value. (equivalent to f32 in WGSL)
Can also be called to cast a value to an f32.
f32 }));const uniformsBuffer: TgpuBuffer<d.WgslStruct<{ a: d.F32; b: d.F32;}>>
Usage flags
Section titled βUsage flagsβTo be able to use these buffers in WGSL shaders, we have to declare their usage upfront with .$usage(...).
const const buffer: TgpuBuffer<d.U32> & UniformFlag & IndirectFlag & StorageFlag & VertexFlag
buffer = const root: TgpuRoot
root.TgpuRoot.createBuffer<d.U32>(typeSchema: d.U32, initial?: number | undefined): TgpuBuffer<d.U32> (+1 overload)
Allocates memory on the GPU, allows passing data between host and shader.
createBuffer(import d
d.const u32: d.U32export u32
A schema that represents an unsigned 32-bit integer value. (equivalent to u32 in WGSL)
Can also be called to cast a value to an u32 in accordance with WGSL casting rules.
u32) .TgpuBuffer<U32>.$usage<["uniform"]>(usages_0: "uniform"): TgpuBuffer<d.U32> & UniformFlag
$usage('uniform') .TgpuBuffer<U32>.$usage<["uniform" | "indirect" | "storage" | "vertex", ...("uniform" | "indirect" | "storage" | "vertex")[]]>(usages_0: "uniform" | "indirect" | "storage" | "vertex", ...usages: ("uniform" | "indirect" | "storage" | "vertex")[]): TgpuBuffer<d.U32> & UniformFlag & IndirectFlag & StorageFlag & VertexFlag
$usage(' ')uniformindirectstoragevertex
You can also add all flags in a single $usage().
const const buffer: TgpuBuffer<d.U32> & UniformFlag & IndirectFlag & StorageFlag & VertexFlag
buffer = const root: TgpuRoot
root.TgpuRoot.createBuffer<d.U32>(typeSchema: d.U32, initial?: number | undefined): TgpuBuffer<d.U32> (+1 overload)
Allocates memory on the GPU, allows passing data between host and shader.
createBuffer(import d
d.const u32: d.U32export u32
A schema that represents an unsigned 32-bit integer value. (equivalent to u32 in WGSL)
Can also be called to cast a value to an u32 in accordance with WGSL casting rules.
u32) .TgpuBuffer<U32>.$usage<["uniform" | "indirect" | "storage" | "vertex", ...("uniform" | "indirect" | "storage" | "vertex")[]]>(usages_0: "uniform" | "indirect" | "storage" | "vertex", ...usages: ("uniform" | "indirect" | "storage" | "vertex")[]): TgpuBuffer<d.U32> & UniformFlag & IndirectFlag & StorageFlag & VertexFlag
$usage('uniform', 'storage', ' ');uniformindirectstoragevertex
Additional flags
Section titled βAdditional flagsβIt is also possible to add any of the GPUBufferUsage flags to a typed buffer object, using the .$addFlags method.
Though it shouldnβt be necessary in most scenarios as majority of the flags are handled automatically by the library
or indirectly through the .$usage method.
const buffer: TgpuBuffer<d.F32>
buffer.TgpuBuffer<F32>.$addFlags(flags: GPUBufferUsageFlags): TgpuBuffer<d.F32>
$addFlags(var GPUBufferUsage: GPUBufferUsage
GPUBufferUsage.GPUBufferUsage.QUERY_RESOLVE: number
QUERY_RESOLVE);Flags can only be added this way if the typed buffer was not created with an existing GPU buffer. If it was, then all flags need to be provided to the existing buffer when constructing it.
Initial value
Section titled βInitial valueβYou can also pass an initial value to the root.createBuffer function.
When the buffer is created, it will be mapped at creation, and the initial value will be written to the buffer.
// Will be initialized to `100`const const buffer1: TgpuBuffer<d.U32>
buffer1 = const root: TgpuRoot
root.TgpuRoot.createBuffer<d.U32>(typeSchema: d.U32, initial?: number | undefined): TgpuBuffer<d.U32> (+1 overload)
Allocates memory on the GPU, allows passing data between host and shader.
createBuffer(import d
d.const u32: d.U32export u32
A schema that represents an unsigned 32-bit integer value. (equivalent to u32 in WGSL)
Can also be called to cast a value to an u32 in accordance with WGSL casting rules.
u32, 100);
// Will be initialized to an array of two vec3fs with the specified values.const const buffer2: TgpuBuffer<d.WgslArray<d.Vec3f>>
buffer2 = const root: TgpuRoot
root.TgpuRoot.createBuffer<d.WgslArray<d.Vec3f>>(typeSchema: d.WgslArray<d.Vec3f>, initial?: d.v3f[] | undefined): TgpuBuffer<d.WgslArray<d.Vec3f>> (+1 overload)
Allocates memory on the GPU, allows passing data between host and shader.
createBuffer(import d
d.arrayOf<d.Vec3f>(elementType: d.Vec3f, elementCount: number): d.WgslArray<d.Vec3f> (+1 overload)export arrayOf
Creates an array schema that can be used to construct gpu buffers.
Describes arrays with fixed-size length, storing elements of the same type.
arrayOf(import d
d.const vec3f: d.Vec3fexport vec3f
Schema representing vec3f - a vector with 3 elements of type f32.
Also a constructor function for this vector value.
vec3f, 2), [ import d
d.function vec3f(x: number, y: number, z: number): d.v3f (+5 overloads)export vec3f
Schema representing vec3f - a vector with 3 elements of type f32.
Also a constructor function for this vector value.
vec3f(0, 1, 2), import d
d.function vec3f(x: number, y: number, z: number): d.v3f (+5 overloads)export vec3f
Schema representing vec3f - a vector with 3 elements of type f32.
Also a constructor function for this vector value.
vec3f(3, 4, 5),]);Using an existing buffer
Section titled βUsing an existing bufferβYou can also create a buffer using an existing WebGPU buffer. This is useful when you have existing logic but want to introduce type-safe data operations.
// A raw WebGPU bufferconst const existingBuffer: GPUBuffer
existingBuffer = const root: TgpuRoot
root.TgpuRoot.device: GPUDevice
The GPU device associated with this root.
device.GPUDevice.createBuffer(descriptor: GPUBufferDescriptor): GPUBuffer
Creates a
GPUBuffer
.
createBuffer({ GPUBufferDescriptor.size: number
The size of the buffer in bytes.
size: 4, GPUBufferDescriptor.usage: number
The allowed usages for the buffer.
usage: var GPUBufferUsage: GPUBufferUsage
GPUBufferUsage.GPUBufferUsage.STORAGE: number
STORAGE | var GPUBufferUsage: GPUBufferUsage
GPUBufferUsage.GPUBufferUsage.COPY_DST: number
COPY_DST,});
const const buffer: TgpuBuffer<d.U32>
buffer = const root: TgpuRoot
root.TgpuRoot.createBuffer<d.U32>(typeSchema: d.U32, gpuBuffer: GPUBuffer): TgpuBuffer<d.U32> (+1 overload)
Allocates memory on the GPU, allows passing data between host and shader.
createBuffer(import d
d.const u32: d.U32export u32
A schema that represents an unsigned 32-bit integer value. (equivalent to u32 in WGSL)
Can also be called to cast a value to an u32 in accordance with WGSL casting rules.
u32, const existingBuffer: GPUBuffer
existingBuffer);
const buffer: TgpuBuffer<d.U32>
buffer.TgpuBuffer<U32>.write(data: number): void
write(12); // Writing to `existingBuffer` through a type-safe APIWriting to a buffer
Section titled βWriting to a bufferβTo write data to a buffer from the CPU, you can use the .write(value) method. The typed schema enables auto-complete as well as static validation of this
methodβs arguments.
const const Particle: d.WgslStruct<{ position: d.Vec2f; health: d.U32;}>
Particle = import d
d.struct<{ position: d.Vec2f; health: d.U32;}>(props: { position: d.Vec2f; health: d.U32;}): d.WgslStruct<{ position: d.Vec2f; health: d.U32;}>export struct
Creates a struct schema that can be used to construct GPU buffers.
Ensures proper alignment and padding of properties (as opposed to a d.unstruct schema).
The order of members matches the passed in properties object.
struct({ position: d.Vec2f
position: import d
d.const vec2f: d.Vec2fexport vec2f
Schema representing vec2f - a vector with 2 elements of type f32.
Also a constructor function for this vector value.
vec2f, health: d.U32
health: import d
d.const u32: d.U32export u32
A schema that represents an unsigned 32-bit integer value. (equivalent to u32 in WGSL)
Can also be called to cast a value to an u32 in accordance with WGSL casting rules.
u32,});
const const particleBuffer: TgpuBuffer<d.WgslStruct<{ position: d.Vec2f; health: d.U32;}>>
particleBuffer = const root: TgpuRoot
root.TgpuRoot.createBuffer<d.WgslStruct<{ position: d.Vec2f; health: d.U32;}>>(typeSchema: d.WgslStruct<{ position: d.Vec2f; health: d.U32;}>, initial?: { position: d.v2f; health: number;} | undefined): TgpuBuffer<d.WgslStruct<{ position: d.Vec2f; health: d.U32;}>> (+1 overload)
Allocates memory on the GPU, allows passing data between host and shader.
createBuffer(const Particle: d.WgslStruct<{ position: d.Vec2f; health: d.U32;}>
Particle);
const particleBuffer: TgpuBuffer<d.WgslStruct<{ position: d.Vec2f; health: d.U32;}>>
particleBuffer.TgpuBuffer<WgslStruct<{ position: Vec2f; health: U32; }>>.write(data: { position: d.v2f; health: number;}): void
write({ position: d.v2f
position: import d
d.function vec2f(x: number, y: number): d.v2f (+3 overloads)export vec2f
Schema representing vec2f - a vector with 2 elements of type f32.
Also a constructor function for this vector value.
vec2f(1.0, 2.0), heal heal: any
health});Partial writes
Section titled βPartial writesβWhen you want to update only a subset of a bufferβs fields, you can use the .writePartial(data) method. This method updates only the fields provided in the data object and leaves the rest unchanged.
The format of the data value depends on your schema type:
-
For
d.structschemas: Provide an object with keys corresponding to the subset of the schemaβs fields you wish to update. -
For
d.arrayschemas: Provide an array of objects. Each object should specify:idx: the index of the element to update.value: the new value for that element.
const const Planet: d.WgslStruct<{ radius: d.F32; mass: d.F32; position: d.Vec3f; colors: d.WgslArray<d.Vec3f>;}>
Planet = import d
d.struct<{ radius: d.F32; mass: d.F32; position: d.Vec3f; colors: d.WgslArray<d.Vec3f>;}>(props: { radius: d.F32; mass: d.F32; position: d.Vec3f; colors: d.WgslArray<d.Vec3f>;}): d.WgslStruct<{ radius: d.F32; mass: d.F32; position: d.Vec3f; colors: d.WgslArray<d.Vec3f>;}>export struct
Creates a struct schema that can be used to construct GPU buffers.
Ensures proper alignment and padding of properties (as opposed to a d.unstruct schema).
The order of members matches the passed in properties object.
struct({ radius: d.F32
radius: import d
d.const f32: d.F32export f32
A schema that represents a 32-bit float value. (equivalent to f32 in WGSL)
Can also be called to cast a value to an f32.
f32, mass: d.F32
mass: import d
d.const f32: d.F32export f32
A schema that represents a 32-bit float value. (equivalent to f32 in WGSL)
Can also be called to cast a value to an f32.
f32, position: d.Vec3f
position: import d
d.const vec3f: d.Vec3fexport vec3f
Schema representing vec3f - a vector with 3 elements of type f32.
Also a constructor function for this vector value.
vec3f, colors: d.WgslArray<d.Vec3f>
colors: import d
d.arrayOf<d.Vec3f>(elementType: d.Vec3f, elementCount: number): d.WgslArray<d.Vec3f> (+1 overload)export arrayOf
Creates an array schema that can be used to construct gpu buffers.
Describes arrays with fixed-size length, storing elements of the same type.
arrayOf(import d
d.const vec3f: d.Vec3fexport vec3f
Schema representing vec3f - a vector with 3 elements of type f32.
Also a constructor function for this vector value.
vec3f, 5),});
const const planetBuffer: TgpuBuffer<d.WgslStruct<{ radius: d.F32; mass: d.F32; position: d.Vec3f; colors: d.WgslArray<d.Vec3f>;}>>
planetBuffer = const root: TgpuRoot
root.TgpuRoot.createBuffer<d.WgslStruct<{ radius: d.F32; mass: d.F32; position: d.Vec3f; colors: d.WgslArray<d.Vec3f>;}>>(typeSchema: d.WgslStruct<{ radius: d.F32; mass: d.F32; position: d.Vec3f; colors: d.WgslArray<d.Vec3f>;}>, initial?: { radius: number; mass: number; position: d.v3f; colors: d.v3f[];} | undefined): TgpuBuffer<d.WgslStruct<{ radius: d.F32; mass: d.F32; position: d.Vec3f; colors: d.WgslArray<d.Vec3f>;}>> (+1 overload)
Allocates memory on the GPU, allows passing data between host and shader.
createBuffer(const Planet: d.WgslStruct<{ radius: d.F32; mass: d.F32; position: d.Vec3f; colors: d.WgslArray<d.Vec3f>;}>
Planet);
const planetBuffer: TgpuBuffer<d.WgslStruct<{ radius: d.F32; mass: d.F32; position: d.Vec3f; colors: d.WgslArray<d.Vec3f>;}>>
planetBuffer.TgpuBuffer<WgslStruct<{ radius: F32; mass: F32; position: Vec3f; colors: WgslArray<Vec3f>; }>>.writePartial(data: { radius?: number | undefined; mass?: number | undefined; position?: d.v3f | undefined; colors?: { idx: number; value: d.v3f | undefined; }[] | undefined;} | undefined): void
writePartial({ mass?: number | undefined
mass: 123.1, colors?: { idx: number; value: d.v3f | undefined;}[] | undefined
colors: [ { idx: number
idx: 2, value: d.v3f | undefined
value: import d
d.function vec3f(x: number, y: number, z: number): d.v3f (+5 overloads)export vec3f
Schema representing vec3f - a vector with 3 elements of type f32.
Also a constructor function for this vector value.
vec3f(1, 0, 0) }, { idx: number
idx: 4, value: d.v3f | undefined
value: import d
d.function vec3f(x: number, y: number, z: number): d.v3f (+5 overloads)export vec3f
Schema representing vec3f - a vector with 3 elements of type f32.
Also a constructor function for this vector value.
vec3f(0, 0, 1) }, ],});Copying
Section titled βCopyingβThereβs also an option to copy value from another typed buffer using the .copyFrom(buffer) method,
as long as both buffers have a matching data schema.
const const backupParticleBuffer: TgpuBuffer<d.WgslStruct<{ position: d.Vec2f; health: d.U32;}>>
backupParticleBuffer = const root: TgpuRoot
root.TgpuRoot.createBuffer<d.WgslStruct<{ position: d.Vec2f; health: d.U32;}>>(typeSchema: d.WgslStruct<{ position: d.Vec2f; health: d.U32;}>, initial?: { position: d.v2f; health: number;} | undefined): TgpuBuffer<d.WgslStruct<{ position: d.Vec2f; health: d.U32;}>> (+1 overload)
Allocates memory on the GPU, allows passing data between host and shader.
createBuffer(const Particle: d.WgslStruct<{ position: d.Vec2f; health: d.U32;}>
Particle);const backupParticleBuffer: TgpuBuffer<d.WgslStruct<{ position: d.Vec2f; health: d.U32;}>>
backupParticleBuffer.TgpuBuffer<WgslStruct<{ position: Vec2f; health: U32; }>>.copyFrom(srcBuffer: TgpuBuffer<d.WgslStruct<{ position: d.Vec2f; health: d.U32 | d.Atomic<d.U32> | DecoratedLocation<d.U32>;}>>): void
copyFrom(const particleBuffer: TgpuBuffer<d.WgslStruct<{ position: d.Vec2f; health: d.U32;}>>
particleBuffer);Reading from a buffer
Section titled βReading from a bufferβTo read data from a buffer on the CPU, you can use the .read() method.
It returns a promise that resolves to the data read from the buffer.
const const buffer: TgpuBuffer<d.WgslArray<d.U32>>
buffer = const root: TgpuRoot
root.TgpuRoot.createBuffer<d.WgslArray<d.U32>>(typeSchema: d.WgslArray<d.U32>, initial?: number[] | undefined): TgpuBuffer<d.WgslArray<d.U32>> (+1 overload)
Allocates memory on the GPU, allows passing data between host and shader.
createBuffer(import d
d.arrayOf<d.U32>(elementType: d.U32, elementCount: number): d.WgslArray<d.U32> (+1 overload)export arrayOf
Creates an array schema that can be used to construct gpu buffers.
Describes arrays with fixed-size length, storing elements of the same type.
arrayOf(import d
d.const u32: d.U32export u32
A schema that represents an unsigned 32-bit integer value. (equivalent to u32 in WGSL)
Can also be called to cast a value to an u32 in accordance with WGSL casting rules.
u32, 10));
const data = await const buffer: TgpuBuffer<d.WgslArray<d.U32>>
buffer.TgpuBuffer<WgslArray<U32>>.read(): Promise<number[]>
read();const data: number[]
Index Buffers
Section titled βIndex BuffersβTypeGPU also allows for the use of index buffers. An index buffer is a buffer containing a sequence of u32 or u16 indices, which indicate in which order vertices will be processed. This is particulary useful for rendering geometry, where vertices are often shared between multiple primitives (e.g., triangles), as it avoids duplicating vertex data.
You may refer to the pipelines section for usage details.
const const indexBuffer: TgpuBuffer<d.WgslArray<d.U16>> & IndexFlag
indexBuffer = const root: TgpuRoot
root .TgpuRoot.createBuffer<d.WgslArray<d.U16>>(typeSchema: d.WgslArray<d.U16>, initial?: number[] | undefined): TgpuBuffer<d.WgslArray<d.U16>> (+1 overload)
Allocates memory on the GPU, allows passing data between host and shader.
createBuffer(import d
d.arrayOf<d.U16>(elementType: d.U16, elementCount: number): d.WgslArray<d.U16> (+1 overload)export arrayOf
Creates an array schema that can be used to construct gpu buffers.
Describes arrays with fixed-size length, storing elements of the same type.
arrayOf(import d
d.const u16: d.U16export u16
u16, 6), [0, 2, 1, 0, 3, 2]) .TgpuBuffer<WgslArray<U16>>.$usage<["index"]>(usages_0: "index"): TgpuBuffer<d.WgslArray<d.U16>> & IndexFlag
$usage('index');Binding buffers
Section titled βBinding buffersβTo use a buffer in a shader, it needs to be bound using a bind group. There are two approaches provided by TypeGPU.
Manual binding
Section titled βManual bindingβThe default option is to create bind group layouts and bind your buffers via bind groups. Read more in the chapter dedicated to bind groups.
const const layout: TgpuBindGroupLayout<{ points: { storage: (elementCount: number) => d.WgslArray<d.Vec2i>; access: "mutable"; };}>
layout = const tgpu: { const: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/constant/tgpuConstant").constant; fn: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/tgpuFn").fn; comptime: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/comptime").comptime; resolve: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolve; resolveWithContext: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolveWithContext; init: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").init; initFromDevice: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").initFromDevice; slot: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/slot").slot; lazy: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/lazy").lazy; ... 10 more ...; '~unstable': typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/tgpuUnstable");}
tgpu.bindGroupLayout: <{ points: { storage: (elementCount: number) => d.WgslArray<d.Vec2i>; access: "mutable"; };}>(entries: { points: { storage: (elementCount: number) => d.WgslArray<d.Vec2i>; access: "mutable"; };}) => TgpuBindGroupLayout<{ points: { storage: (elementCount: number) => d.WgslArray<d.Vec2i>; access: "mutable"; };}> (+1 overload)
bindGroupLayout({ points: { storage: (elementCount: number) => d.WgslArray<d.Vec2i>; access: "mutable";}
points: { storage: (elementCount: number) => d.WgslArray<d.Vec2i>
storage: import d
d.arrayOf<d.Vec2i>(elementType: d.Vec2i): (elementCount: number) => d.WgslArray<d.Vec2i> (+1 overload)export arrayOf
Creates an array schema that can be used to construct gpu buffers.
Describes arrays with fixed-size length, storing elements of the same type.
arrayOf(import d
d.const vec2i: d.Vec2iexport vec2i
Schema representing vec2i - a vector with 2 elements of type i32.
Also a constructor function for this vector value.
vec2i), access: "mutable"
access: 'mutable' },});
const const pipeline: TgpuGuardedComputePipeline<[x: number]>
pipeline = const root: TgpuRoot
root.WithBinding.createGuardedComputePipeline<[x: number]>(callback: (x: number) => void): TgpuGuardedComputePipeline<[x: number]>
Creates a compute pipeline that executes the given callback in an exact number of threads.
This is different from withCompute(...).createPipeline() in that it does a bounds check on the
thread id, where as regular pipelines do not and work in units of workgroups.
createGuardedComputePipeline((x: number
x) => { 'use gpu'; // Access and modify the bound buffer via the layout const layout: TgpuBindGroupLayout<{ points: { storage: (elementCount: number) => d.WgslArray<d.Vec2i>; access: "mutable"; };}>
layout.TgpuBindGroupLayout<{ points: { storage: (elementCount: number) => WgslArray<Vec2i>; access: "mutable"; }; }>.$: { points: d.v2i[];}
$.points: d.v2i[]
points[x: number
x] = import d
d.function vec2i(x: number, y: number): d.v2i (+3 overloads)export vec2i
Schema representing vec2i - a vector with 2 elements of type i32.
Also a constructor function for this vector value.
vec2i(1, 2);});
const const pointsBuffer: TgpuBuffer<d.WgslArray<d.Vec2i>> & StorageFlag
pointsBuffer = const root: TgpuRoot
root .TgpuRoot.createBuffer<d.WgslArray<d.Vec2i>>(typeSchema: d.WgslArray<d.Vec2i>, initial?: d.v2i[] | undefined): TgpuBuffer<d.WgslArray<d.Vec2i>> (+1 overload)
Allocates memory on the GPU, allows passing data between host and shader.
createBuffer(import d
d.arrayOf<d.Vec2i>(elementType: d.Vec2i, elementCount: number): d.WgslArray<d.Vec2i> (+1 overload)export arrayOf
Creates an array schema that can be used to construct gpu buffers.
Describes arrays with fixed-size length, storing elements of the same type.
arrayOf(import d
d.const vec2i: d.Vec2iexport vec2i
Schema representing vec2i - a vector with 2 elements of type i32.
Also a constructor function for this vector value.
vec2i, 100)) .TgpuBuffer<WgslArray<Vec2i>>.$usage<["storage"]>(usages_0: "storage"): TgpuBuffer<d.WgslArray<d.Vec2i>> & StorageFlag
$usage('storage');
const const bindGroup: TgpuBindGroup<{ points: { storage: (elementCount: number) => d.WgslArray<d.Vec2i>; access: "mutable"; };}>
bindGroup = const root: TgpuRoot
root.TgpuRoot.createBindGroup<{ points: { storage: (elementCount: number) => d.WgslArray<d.Vec2i>; access: "mutable"; };}>(layout: TgpuBindGroupLayout<{ points: { storage: (elementCount: number) => d.WgslArray<d.Vec2i>; access: "mutable"; };}>, entries: ExtractBindGroupInputFromLayout<{ points: { storage: (elementCount: number) => d.WgslArray<d.Vec2i>; access: "mutable"; };}>): TgpuBindGroup<{ points: { storage: (elementCount: number) => d.WgslArray<d.Vec2i>; access: "mutable"; };}>
Creates a group of resources that can be bound to a shader based on a specified layout.
createBindGroup(const layout: TgpuBindGroupLayout<{ points: { storage: (elementCount: number) => d.WgslArray<d.Vec2i>; access: "mutable"; };}>
layout, { points: GPUBuffer | (TgpuBuffer<d.WgslArray<d.Vec2i>> & StorageFlag)
points: const pointsBuffer: TgpuBuffer<d.WgslArray<d.Vec2i>> & StorageFlag
pointsBuffer});
const pipeline: TgpuGuardedComputePipeline<[x: number]>
pipeline.TgpuGuardedComputePipeline<[x: number]>.with(bindGroup: TgpuBindGroup): TgpuGuardedComputePipeline<[x: number]>
Returns a pipeline wrapper with the specified bind group bound.
Analogous to TgpuComputePipeline.with(bindGroup).
with(const bindGroup: TgpuBindGroup<{ points: { storage: (elementCount: number) => d.WgslArray<d.Vec2i>; access: "mutable"; };}>
bindGroup).TgpuGuardedComputePipeline<[x: number]>.dispatchThreads(x: number): void
Dispatches the pipeline.
Unlike TgpuComputePipeline.dispatchWorkgroups(), this method takes in the
number of threads to run in each dimension.
Under the hood, the number of expected threads is sent as a uniform, and
"guarded" by a bounds check.
dispatchThreads(100);Using fixed resources
Section titled βUsing fixed resourcesβFor scenarios where buffers remain consistent across multiple compute or render operations, TypeGPU offers fixed resources that appear bindless from a code perspective. Fixed buffers are created using dedicated root methods.
| WGSL type | TypeGPU constructor |
|---|---|
var<uniform> | root.createUniform() |
var<storage, read> | root.createReadonly() |
var<storage, read_write> | root.createMutable() |
const const pointsMutable: TgpuMutable<d.WgslArray<d.Vec2i>>
pointsMutable = const root: TgpuRoot
root.TgpuRoot.createMutable<d.WgslArray<d.Vec2i>>(typeSchema: d.WgslArray<d.Vec2i>, initial?: d.v2i[] | undefined): TgpuMutable<d.WgslArray<d.Vec2i>> (+1 overload)
Allocates memory on the GPU, allows passing data between host and shader.
Can be mutated in-place on the GPU. For a general-purpose buffer,
use
TgpuRoot.createBuffer
.
createMutable(import d
d.arrayOf<d.Vec2i>(elementType: d.Vec2i, elementCount: number): d.WgslArray<d.Vec2i> (+1 overload)export arrayOf
Creates an array schema that can be used to construct gpu buffers.
Describes arrays with fixed-size length, storing elements of the same type.
arrayOf(import d
d.const vec2i: d.Vec2iexport vec2i
Schema representing vec2i - a vector with 2 elements of type i32.
Also a constructor function for this vector value.
vec2i, 100));
const const pipeline: TgpuGuardedComputePipeline<[x: number]>
pipeline = const root: TgpuRoot
root.WithBinding.createGuardedComputePipeline<[x: number]>(callback: (x: number) => void): TgpuGuardedComputePipeline<[x: number]>
Creates a compute pipeline that executes the given callback in an exact number of threads.
This is different from withCompute(...).createPipeline() in that it does a bounds check on the
thread id, where as regular pipelines do not and work in units of workgroups.
createGuardedComputePipeline((x: number
x) => { 'use gpu'; // Access and modify the fixed buffer directly const pointsMutable: TgpuMutable<d.WgslArray<d.Vec2i>>
pointsMutable.TgpuMutable<WgslArray<Vec2i>>.$: d.v2i[]
$[x: number
x] = import d
d.function vec2i(): d.v2i (+3 overloads)export vec2i
Schema representing vec2i - a vector with 2 elements of type i32.
Also a constructor function for this vector value.
vec2i();});
const pipeline: TgpuGuardedComputePipeline<[x: number]>
pipeline.TgpuGuardedComputePipeline<[x: number]>.dispatchThreads(x: number): void
Dispatches the pipeline.
Unlike TgpuComputePipeline.dispatchWorkgroups(), this method takes in the
number of threads to run in each dimension.
Under the hood, the number of expected threads is sent as a uniform, and
"guarded" by a bounds check.
dispatchThreads(100);TypeGPU automatically generates a βcatch-allβ bind group and populates it with the fixed resources.
You can also use resolveWithContext to access the automatically generated bind group and layout containing your fixed resources.