WebGPU Interoperability
TypeGPU is built in a way that allows you to pick and choose the primitives you need, incrementally adopt them into your project and have a working app at each step of the process. We go to great lengths to ensure that turning even a single buffer into our typed variant improves the developer experience, and does not require changes to the rest of the codebase.
The non-contagious nature of TypeGPU means that ejecting out, in case raw WebGPU access is required, can be done on a very granular level.
Points of integration
Accessing underlying WebGPU resources
Since TypeGPU is a very thin abstraction over WebGPU, there is a 1-to-1 mapping between most typed resources and the raw WebGPU resources used underneath.
Plugging WebGPU resources into typed APIs.
Many TypeGPU APIs accept either typed resources, or their untyped equivalent.
Buffers
Instead of passing an initial value to root.createBuffer
, we can pass it a raw WebGPU buffer and interact with it through
TypeGPU’s APIs.
Bind Group Layouts
When creating typed bind groups from a layout, entries can be populated with equivalent raw WebGPU resources.
Incremental adoption recipes
To deliver on the promise of interoperability, below are the small code changes necessary to adopt TypeGPU, and the benefits gained at each step.
Since adoption can start growing from many points in a WebGPU codebase, feel free to choose whichever path suits your use-case the most:
Starting at buffers
Define a schema for a buffer’s contents
Benefits gained:
- Increased context - a data-type schema allows developers to quickly determine what a buffer is supposed to contain, without the need to jump around the codebase.
- Automatic sizing - schemas understand WebGPU memory layout rules, therefore can calculate the required size of a buffer.
Wrap the buffer in a typed shell
Benefits gained:
- Typed I/O - typed buffers have
.write
and.read
methods that accept/return properly typed JavaScript values that match that buffer’s schema. Trying to write anything other than an array ofvec3f
will result in a type error, surfaced immediately by the IDE and at build time. - Automatic padding - TypeGPU understands how to translate JS values into binary and back,
adhering to memory layout rules. This reduces the room for error, and no longer requires knowledge
about
vec3f
s having to be aligned to multiples of 16 bytes.
Let TypeGPU create the buffer
Benefits gained:
- Automatic flags - buffer flags can be inferred based on the usages passed into
.$usage
. That way they can be consistent both on the type-level, as well as at runtime. - Initial value - an optional initial value can be passed in, which takes care of mapping the buffer at creation, and unmapping it.
Starting at bind group layouts
Replace the WebGPU API call with a typed variant
Benefits gained:
- Increased context - replacing indices with named keys (
'ambientColor'
,'intensity'
, …) and providing data types reduces the need to jump around the codebase to find a layout’s semantic meaning. - Good defaults - binding indices are inferred automatically based on the order of properties in the descriptor, starting from
0
. Properties with the valuenull
are skipped. The visibility is assumed based on the type of resource. Can be explicitly limited using the optionalvisibility
property.
Create bind groups from typed layouts
Benefits gained:
- Reduced fragility - no longer susceptible to shifts in binding indices, as the resources are associated with a named key instead.
- Autocomplete - the IDE can suggest what resources need to be passed in, and what their data types should be.
- Static validation - when the layout gains a new entry, or the kind of resource it holds changes, the IDE and build system will catch it before the error surfaces at runtime. When using typed buffers, the validity of the data-type and usage is also validated on the type level.
Inject shader code
Benefits gained:
- Reduced fragility - binding indices are now being handled end-to-end by TypeGPU, leaving human-readable keys as the way to connect the shader with JavaScript.
- Single source of truth - typed bind group layouts not only describe JS behavior, but also WGSL behavior. This
allows
tgpu.resolve
to generate the appropriate WGSL code. Definitions of structs used as part of the layout will also be included in the returned shader code.