Roots
Roots are responsible for resource allocation and management. Whether you’d like to wrap an existing WebGPU buffer with a typed shell or create a brand new buffer, roots are the place to start.
You can create a root using the tgpu.init function.
It requests a GPU device with default requirements. An optional parameter
can be passed in with special requirements for the GPU device.
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 from 'typegpu';
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();If you already have a device that you want to use, you can pass it into tgpu.initFromDevice instead.
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 from 'typegpu';
const const adapter: GPUAdapter | null
adapter = await var navigator: Navigator
The Window.navigator read-only property returns a reference to the Navigator object, which has methods and properties about the application running the script.
navigator.NavigatorGPU.gpu: GPU
A global singleton providing top-level entry points like
GPU#requestAdapter
.
gpu.GPU.requestAdapter(options?: GPURequestAdapterOptions): Promise<GPUAdapter | null>
Requests an adapter from the user agent.
The user agent chooses whether to return an adapter, and, if so,
chooses according to the provided options.
requestAdapter();const const device: GPUDevice
device = await const adapter: GPUAdapter | null
adapter?.GPUAdapter.requestDevice(descriptor?: GPUDeviceDescriptor): Promise<GPUDevice>
Requests a device from the adapter.
This is a one-time action: if a device is returned successfully,
the adapter becomes
adapter# [[state]]#"consumed"
.
requestDevice() as interface GPUDevice
GPUDevice;
// using a preexisting deviceconst const root: TgpuRoot
root = 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.initFromDevice: (options: InitFromDeviceOptions) => TgpuRoot
Creates a root from the given device, instead of requesting it like
initFromDevice({ device: GPUDevice
device });Configuring context
Section titled “Configuring context”In order to draw on a canvas, you need to create and configure a context that will be later passed to a pipeline.
const const context: GPUCanvasContext
context = const canvas: HTMLCanvasElement
canvas.HTMLCanvasElement.getContext(contextId: "webgpu"): GPUCanvasContext | null (+5 overloads)
The HTMLCanvasElement.getContext() method returns a drawing context on the canvas, or null if the context identifier is not supported, or the canvas has already been set to a different context mode.
getContext("webgpu") as interface GPUCanvasContext
GPUCanvasContext;const const presentationFormat: GPUTextureFormat
presentationFormat = var navigator: Navigator
The Window.navigator read-only property returns a reference to the Navigator object, which has methods and properties about the application running the script.
navigator.NavigatorGPU.gpu: GPU
A global singleton providing top-level entry points like
GPU#requestAdapter
.
gpu.GPU.getPreferredCanvasFormat(): GPUTextureFormat
Returns an optimal
GPUTextureFormat
for displaying 8-bit depth, standard dynamic range
content on this system. Must only return
GPUTextureFormat
"rgba8unorm" or
GPUTextureFormat
"bgra8unorm".
The returned value can be passed as the
GPUCanvasConfiguration#format
to
GPUCanvasContext#configure
calls on a
GPUCanvasContext
to ensure the associated
canvas is able to display its contents efficiently.
Note: Canvases which are not displayed to the screen may or may not benefit from using this
format.
getPreferredCanvasFormat();const context: GPUCanvasContext
context.GPUCanvasContext.configure(configuration: GPUCanvasConfiguration): undefined
Configures the context for this canvas.
This clears the drawing buffer to transparent black (in [$Replace the drawing buffer$]).
See
GPUCanvasContext#getConfiguration
for information on feature detection.
configure({ GPUCanvasConfiguration.device: GPUDevice
The
GPUDevice
that textures returned by
GPUCanvasContext#getCurrentTexture
will be
compatible with.
device: const root: TgpuRoot
root.TgpuRoot.device: GPUDevice
The GPU device associated with this root.
device, GPUCanvasConfiguration.format: GPUTextureFormat
The format that textures returned by
GPUCanvasContext#getCurrentTexture
will have.
Must be one of the Supported context formats.
format: const presentationFormat: GPUTextureFormat
presentationFormat, GPUCanvasConfiguration.alphaMode?: GPUCanvasAlphaMode
Determines the effect that alpha values will have on the content of textures returned by
GPUCanvasContext#getCurrentTexture
when read, displayed, or used as an image source.
alphaMode: 'premultiplied',});TypeGPU streamlines this process with root.configureContext method.
// format defaults to `navigator.gpu.getPreferredCanvasFormat()`const const context: GPUCanvasContext
context = const root: TgpuRoot
root.TgpuRoot.configureContext(options: ConfigureContextOptions): GPUCanvasContext
Creates and configures context for the provided canvas.
Automatically sets the format to navigator.gpu.getPreferredCanvasFormat() if not provided.
configureContext({ canvas: HTMLCanvasElement | OffscreenCanvas
The canvas for which a context will be created and configured.
canvas, alphaMode?: GPUCanvasAlphaMode
Determines the effect that alpha values will have on the content of textures returned by
GPUCanvasContext#getCurrentTexture
when read, displayed, or used as an image source.
alphaMode: 'premultiplied' });Creating resources
Section titled “Creating resources”Resources independent from the device, such as bind group layouts, functions, variables, TypeGPU slots etc., are created using dedicated tgpu.* methods.
Resources requiring a device, such as bind groups, buffers, samplers, pipelines, etc., are created using root.create* methods.
For more information, see corresponding chapters.
Destroying resources
Section titled “Destroying resources”Calling root.destroy() will call device.destroy() to let the browser know that it can free up all the resources.
If the root was created via tgpu.initFromDevice(), this method does nothing.
root.destroy(); // <- frees up all the resourcesBest practices
Section titled “Best practices”Treat roots as their own separate universes, meaning resources created from the same root can interact with each other, while resources created by seperate roots can have a hard time interacting. This usually means creating just one root at the start of the program is the safest bet, but there are exceptions.
If you do not own the GPU device
Section titled “If you do not own the GPU device”If you cannot control the lifetime of the GPU device you are to use for computing/rendering, but are instead given the device in a lifecycle hook (e.g., react-native-wgpu), you can create a new root each time, as long as you recreate every resource as well.
import React from 'react';
function SceneView() { const ref = useWebGPU(({ context, device, presentationFormat }) => { const root = tgpu.initFromDevice({ device });
// create all resources... });
// ...}If you pass the GPU device everywhere
Section titled “If you pass the GPU device everywhere”It is common practice to pass a GPUDevice to classes or functions for them to allocate their required resources. At first glance, this poses a problem when trying to
incorporate TypeGPU, since we would need to pass a root around instead of a device for all functionality that wants to move towards a typed API. We can create a global mapping
between devices and roots to solve this.
You can copy and paste the utility below that implements a basic global cache for roots.
const deviceToRootMap = new WeakMap<GPUDevice, TgpuRoot>();
function getOrInitRoot(device: GPUDevice): TgpuRoot { let root = deviceToRootMap.get(device);
if (!root) { root = tgpu.initFromDevice({ device }); deviceToRootMap.set(device, root); }
return root;}If you reuse the same getOrInitRoot function across code that has to create resources, the root will be shared
across them.
class GameObject { constructor(device: GPUDevice) { const root = getOrInitRoot(device);
// create all resources... }}