Skip to content

Textures

In a similar fashion to buffers, textures provide a way to store and manage data on the GPU. They allow for both read and write access from WGSL shaders, and can also be sampled in the case of sampled textures. The main advantage of using textures over buffers is their optimized memory layout for spatial data, which can lead to better performance in certain scenarios as well as additional functionality such as filtering and mipmapping.

TypeGPU textures serve as a wrapper that provides type safety and higher level utilities (such as automatic mipmap generation). They also allow - in a similar way to buffers - for fixed resource creation that can be used directly in shaders without the need for manual bind group management.

Let’s look at an example of creating and using a typed texture.

import {
const tgpu: {
const: typeof import("node_modules/typegpu/src/core/constant/tgpuConstant").constant;
fn: typeof import("node_modules/typegpu/src/core/function/tgpuFn").fn;
comptime: typeof import("node_modules/typegpu/src/core/function/comptime").comptime;
resolve: typeof import("node_modules/typegpu/src/core/resolve/tgpuResolve").resolve;
resolveWithContext: typeof import("node_modules/typegpu/src/core/resolve/tgpuResolve").resolveWithContext;
init: typeof import("node_modules/typegpu/src/core/root/init").init;
initFromDevice: typeof import("node_modules/typegpu/src/core/root/init").initFromDevice;
slot: typeof import("node_modules/typegpu/src/core/slot/slot").slot;
lazy: typeof import("node_modules/typegpu/src/core/slot/lazy").lazy;
... 10 more ...;
'~unstable': typeof import("node_modules/typegpu/src/tgpuUnstable");
}

@module ― typegpu

tgpu
} from 'typegpu';
const
const root: TgpuRoot
root
= await
const tgpu: {
const: typeof import("node_modules/typegpu/src/core/constant/tgpuConstant").constant;
fn: typeof import("node_modules/typegpu/src/core/function/tgpuFn").fn;
comptime: typeof import("node_modules/typegpu/src/core/function/comptime").comptime;
resolve: typeof import("node_modules/typegpu/src/core/resolve/tgpuResolve").resolve;
resolveWithContext: typeof import("node_modules/typegpu/src/core/resolve/tgpuResolve").resolveWithContext;
init: typeof import("node_modules/typegpu/src/core/root/init").init;
initFromDevice: typeof import("node_modules/typegpu/src/core/root/init").initFromDevice;
slot: typeof import("node_modules/typegpu/src/core/slot/slot").slot;
lazy: typeof import("node_modules/typegpu/src/core/slot/lazy").lazy;
... 10 more ...;
'~unstable': typeof import("node_modules/typegpu/src/tgpuUnstable");
}

@module ― typegpu

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

@see ― initFromDevice. *

@example

When given no options, the function will ask the browser for a suitable GPU device.

const root = await tgpu.init();

@example

If there are specific options that should be used when requesting a device, you can pass those in.

const adapterOptions: GPURequestAdapterOptions = ...;
const deviceDescriptor: GPUDeviceDescriptor = ...;
const root = await tgpu.init({ adapter: adapterOptions, device: deviceDescriptor });

init
();
const
const response: Response
response
= await
function fetch(input: string | URL | Request, init?: RequestInit): Promise<Response> (+1 overload)
fetch
('path/to/image.png');
const
const blob: Blob
blob
= await
const response: Response
response
.
Body.blob(): Promise<Blob>
blob
();
const
const imageBitmap: ImageBitmap
imageBitmap
= await
function createImageBitmap(image: ImageBitmapSource, options?: ImageBitmapOptions): Promise<ImageBitmap> (+1 overload)
createImageBitmap
(
const blob: Blob
blob
);
const
const texture: TgpuTexture<{
size: [number, number];
format: "rgba8unorm";
}> & SampledFlag & RenderFlag
texture
=
const root: TgpuRoot
root
.
TgpuRoot.createTexture<number, number, number, [number, number], "rgba8unorm", number, number, GPUTextureFormat[], GPUTextureDimension>(props: CreateTextureOptions<[number, number], "rgba8unorm", number, number, GPUTextureFormat[], GPUTextureDimension>): TgpuTexture<{
size: [number, number];
format: "rgba8unorm";
}>
createTexture
({
size: [number, number]

The width, height, and depth or layer count of the texture.

size
: [
const imageBitmap: ImageBitmap
imageBitmap
.
ImageBitmap.width: number

The ImageBitmap.width read-only property returns the ImageBitmap object's width in CSS pixels.

MDN Reference

width
,
const imageBitmap: ImageBitmap
imageBitmap
.
ImageBitmap.height: number

The ImageBitmap.height read-only property returns the ImageBitmap object's height in CSS pixels.

MDN Reference

height
],
format: "rgba8unorm"

The format of the texture.

format
: 'rgba8unorm' as
type const = "rgba8unorm"
const
,
}).
TgpuTexture<{ size: [number, number]; format: "rgba8unorm"; }>.$usage<["sampled", "render"]>(usages_0: "sampled", usages_1: "render"): TgpuTexture<{
size: [number, number];
format: "rgba8unorm";
}> & SampledFlag & RenderFlag
$usage
('sampled', 'render');
// Uploading image data to the texture
const texture: TgpuTexture<{
size: [number, number];
format: "rgba8unorm";
}> & SampledFlag & RenderFlag
texture
.
TgpuTexture<{ size: [number, number]; format: "rgba8unorm"; }>.write(source: GPUCopyExternalImageSource | GPUCopyExternalImageSource[], options?: TextureWriteOptions): void (+1 overload)

Writes image sources to the texture, one per array layer. Requires the 'render' usage flag

write
(
const imageBitmap: ImageBitmap
imageBitmap
);
// Creating a view to use in shader
const sampledView =
const texture: TgpuTexture<{
size: [number, number];
format: "rgba8unorm";
}> & SampledFlag & RenderFlag
texture
.
TgpuTexture<{ size: [number, number]; format: "rgba8unorm"; }>.createView(): TgpuTextureView<WgslTexture2d<F32>> (+3 overloads)
createView
();
const sampledView: TgpuTextureView<WgslTexture2d<F32>>

Textures can be created using the root.createTexture method. It accepts a descriptor similar to vanilla GPUTextureDescriptor. If specified, the properties will be reflected in the created texture type - this will later help with static checks when creating views or binding the texture in a layout.

type TextureProps = {
size: readonly number[];
format: GPUTextureFormat;
viewFormats?: GPUTextureFormat[] | undefined;
dimension?: GPUTextureDimension | undefined;
mipLevelCount?: number | undefined;
sampleCount?: number | undefined;
};
const texture =
const root: TgpuRoot
root
.
TgpuRoot.createTexture<number, number, number, [512, 512, 128], "rgba8unorm", 4, number, GPUTextureFormat[], "3d">(props: CreateTextureOptions<[512, 512, 128], "rgba8unorm", 4, number, GPUTextureFormat[], "3d">): TgpuTexture<{
size: [512, 512, 128];
format: "rgba8unorm";
dimension: "3d";
mipLevelCount: 4;
}>
createTexture
({
const texture: TgpuTexture<{
size: [512, 512, 128];
format: "rgba8unorm";
dimension: "3d";
mipLevelCount: 4;
}>
size: [512, 512, 128]

The width, height, and depth or layer count of the texture.

size
: [512, 512, 128],
format: "rgba8unorm"

The format of the texture.

format
: 'rgba8unorm',
mipLevelCount?: 4 | undefined

The number of mip levels the texture will contain.

@default ― 1

mipLevelCount
: 4,
dimension?: "3d" | undefined

Whether the texture is one-dimensional, an array of two-dimensional layers, or three-dimensional.

@default ― '2d'

dimension
: '3d',
})

Similar to buffers, textures need usage flags to specify how they will be used. You can add usage flags using the .$usage(...) method.

const
const texture: TgpuTexture<{
size: [256, 256];
format: "rgba8unorm";
}> & SampledFlag & StorageFlag & RenderFlag
texture
=
const root: TgpuRoot
root
.
TgpuRoot.createTexture<number, number, number, [256, 256], "rgba8unorm", number, number, GPUTextureFormat[], GPUTextureDimension>(props: CreateTextureOptions<[256, 256], "rgba8unorm", number, number, GPUTextureFormat[], GPUTextureDimension>): TgpuTexture<{
size: [256, 256];
format: "rgba8unorm";
}>
createTexture
({
size: [256, 256]

The width, height, and depth or layer count of the texture.

size
: [256, 256],
format: "rgba8unorm"

The format of the texture.

format
: 'rgba8unorm',
})
.
TgpuTexture<{ size: [256, 256]; format: "rgba8unorm"; }>.$usage<["sampled"]>(usages_0: "sampled"): TgpuTexture<{
size: [256, 256];
format: "rgba8unorm";
}> & SampledFlag
$usage
('sampled') // Can be sampled in shaders
.
TgpuTexture<{ size: [256, 256]; format: "rgba8unorm"; }>.$usage<["storage"]>(usages_0: "storage"): TgpuTexture<{
size: [256, 256];
format: "rgba8unorm";
}> & SampledFlag & StorageFlag
$usage
('storage') // Can be written or read to as storage texture
.
TgpuTexture<{ size: [256, 256]; format: "rgba8unorm"; }>.$usage<["render"]>(usages_0: "render"): TgpuTexture<{
size: [256, 256];
format: "rgba8unorm";
}> & SampledFlag & StorageFlag & RenderFlag
$usage
('render'); // Can be used as a render target or image upload target

You can also add multiple flags at once:

const
const texture: TgpuTexture<{
size: [256, 256];
format: "rgba8unorm";
}> & SampledFlag & RenderFlag & StorageFlag
texture
=
const root: TgpuRoot
root
.
TgpuRoot.createTexture<number, number, number, [256, 256], "rgba8unorm", number, number, GPUTextureFormat[], GPUTextureDimension>(props: CreateTextureOptions<[256, 256], "rgba8unorm", number, number, GPUTextureFormat[], GPUTextureDimension>): TgpuTexture<{
size: [256, 256];
format: "rgba8unorm";
}>
createTexture
({
size: [256, 256]

The width, height, and depth or layer count of the texture.

size
: [256, 256],
format: "rgba8unorm"

The format of the texture.

format
: 'rgba8unorm',
}).
TgpuTexture<{ size: [256, 256]; format: "rgba8unorm"; }>.$usage<["sampled", "storage", "render"]>(usages_0: "sampled", usages_1: "storage", usages_2: "render"): TgpuTexture<{
size: [256, 256];
format: "rgba8unorm";
}> & SampledFlag & RenderFlag & StorageFlag
$usage
('sampled', 'storage', 'render');

For raw WebGPU usage flags, use .$overrideFlags(...):

const
const texture: TgpuTexture<{
size: [256, 256];
format: "rgba8unorm";
}> & StorageFlag & SampledFlag & RenderFlag
texture
=
const root: TgpuRoot
root
.
TgpuRoot.createTexture<number, number, number, [256, 256], "rgba8unorm", number, number, GPUTextureFormat[], GPUTextureDimension>(props: CreateTextureOptions<[256, 256], "rgba8unorm", number, number, GPUTextureFormat[], GPUTextureDimension>): TgpuTexture<{
size: [256, 256];
format: "rgba8unorm";
}>
createTexture
({
size: [256, 256]

The width, height, and depth or layer count of the texture.

size
: [256, 256],
format: "rgba8unorm"

The format of the texture.

format
: 'rgba8unorm',
})
.
TgpuTexture<{ size: [256, 256]; format: "rgba8unorm"; }>.$overrideFlags(flags: GPUTextureUsageFlags): TgpuTexture<{
size: [256, 256];
format: "rgba8unorm";
}> & StorageFlag & SampledFlag & RenderFlag
$overrideFlags
(
var GPUTextureUsage: GPUTextureUsage
GPUTextureUsage
.
GPUTextureUsage.RENDER_ATTACHMENT: number
RENDER_ATTACHMENT
);

The .write() method accepts a variety of data sources. Here’s a quick overview of the available options:

SourceUse when
texture.write(imageBitmap)You already have a decoded image that matches the texture size.
texture.write(imageBitmap, { fit: 'stretch' })You want the image resampled to fit the texture.
texture.write(imageBitmap, { fit: 'clip' })You want a 1:1 copy of the overlapping region.
texture.writeAsync(blob, { ... })You have a fetched Blob and don’t need to keep the decoded bitmap around.
texture.write([layer0, layer1])You want to fill a texture array or 3D texture one layer at a time.
texture.write(bytes)You already have raw texel bytes.
texture.write(imageBitmap, { origin, size, ... })You need a crop or a destination region.
common.writeChannels(texture, { ... })You want to pack image sources into individual channels.

Writing image sources requires the 'render' usage flag (raw binary writes do not), and the source and destination sizes have to match unless you pick a mismatch behavior with the fit option.

You can write various image sources to textures. If the image dimensions match the texture size, all it takes is a single .write() call:

const
const texture: TgpuTexture<{
size: [number, number];
format: "rgba8unorm";
}> & SampledFlag & RenderFlag
texture
=
const root: TgpuRoot
root
.
TgpuRoot.createTexture<number, number, number, [number, number], "rgba8unorm", number, number, GPUTextureFormat[], GPUTextureDimension>(props: CreateTextureOptions<[number, number], "rgba8unorm", number, number, GPUTextureFormat[], GPUTextureDimension>): TgpuTexture<{
size: [number, number];
format: "rgba8unorm";
}>
createTexture
({
size: [number, number]

The width, height, and depth or layer count of the texture.

size
: [
const imageBitmap: ImageBitmap
imageBitmap
.
ImageBitmap.width: number

The ImageBitmap.width read-only property returns the ImageBitmap object's width in CSS pixels.

MDN Reference

width
,
const imageBitmap: ImageBitmap
imageBitmap
.
ImageBitmap.height: number

The ImageBitmap.height read-only property returns the ImageBitmap object's height in CSS pixels.

MDN Reference

height
],
format: "rgba8unorm"

The format of the texture.

format
: 'rgba8unorm',
}).
TgpuTexture<{ size: [number, number]; format: "rgba8unorm"; }>.$usage<["sampled", "render"]>(usages_0: "sampled", usages_1: "render"): TgpuTexture<{
size: [number, number];
format: "rgba8unorm";
}> & SampledFlag & RenderFlag
$usage
('sampled', 'render');
const texture: TgpuTexture<{
size: [number, number];
format: "rgba8unorm";
}> & SampledFlag & RenderFlag
texture
.
TgpuTexture<{ size: [number, number]; format: "rgba8unorm"; }>.write(source: GPUCopyExternalImageSource | GPUCopyExternalImageSource[], options?: TextureWriteOptions): void (+1 overload)

Writes image sources to the texture, one per array layer. Requires the 'render' usage flag

write
(
const imageBitmap: ImageBitmap
imageBitmap
);

If the image dimensions don’t match the texture size, a plain .write() call throws. The fit option picks what happens instead: 'stretch' resamples the source to fill the target region, while 'clip' copies texels 1:1 and cuts off whatever doesn’t overlap.

const texture = root.createTexture({
size: [512, 512],
format: 'rgba8unorm',
}).$usage('sampled', 'render');
texture.write(imageBitmap, { fit: 'stretch' });
texture.write(imageBitmap, {
sourceOrigin: [16, 16],
sourceSize: [128, 128],
size: [256, 256],
fit: 'stretch',
});
texture.write(tileBitmap, { origin: [128, 64], fit: 'clip' });

If you fetched an image and don’t need to keep the decoded ImageBitmap around, you can hand the Blob directly to writeAsync and let TypeGPU handle the decoding. With fit: 'stretch', the resize options are passed along to createImageBitmap before uploading.

const
const texture: TgpuTexture<{
size: [512, 512];
format: "rgba8unorm";
}> & SampledFlag & RenderFlag
texture
=
const root: TgpuRoot
root
.
TgpuRoot.createTexture<number, number, number, [512, 512], "rgba8unorm", number, number, GPUTextureFormat[], GPUTextureDimension>(props: CreateTextureOptions<[512, 512], "rgba8unorm", number, number, GPUTextureFormat[], GPUTextureDimension>): TgpuTexture<{
size: [512, 512];
format: "rgba8unorm";
}>
createTexture
({
size: [512, 512]

The width, height, and depth or layer count of the texture.

size
: [512, 512],
format: "rgba8unorm"

The format of the texture.

format
: 'rgba8unorm',
}).
TgpuTexture<{ size: [512, 512]; format: "rgba8unorm"; }>.$usage<["sampled", "render"]>(usages_0: "sampled", usages_1: "render"): TgpuTexture<{
size: [512, 512];
format: "rgba8unorm";
}> & SampledFlag & RenderFlag
$usage
('sampled', 'render');
const
const blob: Blob
blob
= await (await
function fetch(input: string | URL | Request, init?: RequestInit): Promise<Response> (+1 overload)
fetch
('path/to/image.png')).
Body.blob(): Promise<Blob>
blob
();
await
const texture: TgpuTexture<{
size: [512, 512];
format: "rgba8unorm";
}> & SampledFlag & RenderFlag
texture
.
TgpuTexture<{ size: [512, 512]; format: "rgba8unorm"; }>.writeAsync(source: Blob, options?: TextureBlobWriteOptions): Promise<void>

Decodes an image blob and writes it to the texture. Requires the 'render' usage flag

writeAsync
(
const blob: Blob
blob
, {
fit?: TextureWriteFit | undefined
fit
: 'stretch' });

If you don’t specify a size, it defaults to the size of the written region - the target mip level minus the origin offset. Keep in mind that the decoded bitmap is still written as an image source, so the texture needs the 'render' usage flag.

For texture arrays, you can write multiple images at once - one per layer:

const
const texture: TgpuTexture<{
size: [256, 256, 3];
format: "rgba8unorm";
}> & SampledFlag & RenderFlag
texture
=
const root: TgpuRoot
root
.
TgpuRoot.createTexture<number, number, number, [256, 256, 3], "rgba8unorm", number, number, GPUTextureFormat[], GPUTextureDimension>(props: CreateTextureOptions<[256, 256, 3], "rgba8unorm", number, number, GPUTextureFormat[], GPUTextureDimension>): TgpuTexture<{
size: [256, 256, 3];
format: "rgba8unorm";
}>
createTexture
({
size: [256, 256, 3]

The width, height, and depth or layer count of the texture.

size
: [256, 256, 3],
format: "rgba8unorm"

The format of the texture.

format
: 'rgba8unorm',
}).
TgpuTexture<{ size: [256, 256, 3]; format: "rgba8unorm"; }>.$usage<["sampled", "render"]>(usages_0: "sampled", usages_1: "render"): TgpuTexture<{
size: [256, 256, 3];
format: "rgba8unorm";
}> & SampledFlag & RenderFlag
$usage
('sampled', 'render');
const texture: TgpuTexture<{
size: [256, 256, 3];
format: "rgba8unorm";
}> & SampledFlag & RenderFlag
texture
.
TgpuTexture<{ size: [256, 256, 3]; format: "rgba8unorm"; }>.write(source: GPUCopyExternalImageSource | GPUCopyExternalImageSource[], options?: TextureWriteOptions): void (+1 overload)

Writes image sources to the texture, one per array layer. Requires the 'render' usage flag

write
([
const layer0: ImageBitmap
layer0
,
const layer1: ImageBitmap
layer1
,
const layer2: ImageBitmap
layer2
]);

Each image has to match the layer size, unless you pass a fit mode.

The same form works for 3D textures (created with dimension: '3d') - each image in the array fills one depth slice:

const
const texture3d: TgpuTexture<{
size: [256, 256, 3];
format: "rgba8unorm";
dimension: "3d";
}> & SampledFlag & RenderFlag
texture3d
=
const root: TgpuRoot
root
.
TgpuRoot.createTexture<number, number, number, [256, 256, 3], "rgba8unorm", number, number, GPUTextureFormat[], "3d">(props: CreateTextureOptions<[256, 256, 3], "rgba8unorm", number, number, GPUTextureFormat[], "3d">): TgpuTexture<{
size: [256, 256, 3];
format: "rgba8unorm";
dimension: "3d";
}>
createTexture
({
size: [256, 256, 3]

The width, height, and depth or layer count of the texture.

size
: [256, 256, 3],
format: "rgba8unorm"

The format of the texture.

format
: 'rgba8unorm',
dimension?: "3d" | undefined

Whether the texture is one-dimensional, an array of two-dimensional layers, or three-dimensional.

@default ― '2d'

dimension
: '3d',
}).
TgpuTexture<{ size: [256, 256, 3]; format: "rgba8unorm"; dimension: "3d"; }>.$usage<["sampled", "render"]>(usages_0: "sampled", usages_1: "render"): TgpuTexture<{
size: [256, 256, 3];
format: "rgba8unorm";
dimension: "3d";
}> & SampledFlag & RenderFlag
$usage
('sampled', 'render');
const texture3d: TgpuTexture<{
size: [256, 256, 3];
format: "rgba8unorm";
dimension: "3d";
}> & SampledFlag & RenderFlag
texture3d
.
TgpuTexture<{ size: [256, 256, 3]; format: "rgba8unorm"; dimension: "3d"; }>.write(source: GPUCopyExternalImageSource | GPUCopyExternalImageSource[], options?: TextureWriteOptions): void (+1 overload)

Writes image sources to the texture, one per array layer. Requires the 'render' usage flag

write
([
const slice0: ImageBitmap
slice0
,
const slice1: ImageBitmap
slice1
,
const slice2: ImageBitmap
slice2
]);

You can write raw binary data directly to textures using ArrayBuffer, typed arrays, or DataView:

const
const texture: TgpuTexture<{
size: [2, 2];
format: "rgba8unorm";
mipLevelCount: 2;
}> & SampledFlag
texture
=
const root: TgpuRoot
root
.
TgpuRoot.createTexture<number, number, number, [2, 2], "rgba8unorm", 2, number, GPUTextureFormat[], GPUTextureDimension>(props: CreateTextureOptions<[2, 2], "rgba8unorm", 2, number, GPUTextureFormat[], GPUTextureDimension>): TgpuTexture<{
size: [2, 2];
format: "rgba8unorm";
mipLevelCount: 2;
}>
createTexture
({
size: [2, 2]

The width, height, and depth or layer count of the texture.

size
: [2, 2],
format: "rgba8unorm"

The format of the texture.

format
: 'rgba8unorm',
mipLevelCount?: 2 | undefined

The number of mip levels the texture will contain.

@default ― 1

mipLevelCount
: 2,
}).
TgpuTexture<{ size: [2, 2]; format: "rgba8unorm"; mipLevelCount: 2; }>.$usage<["sampled"]>(usages_0: "sampled"): TgpuTexture<{
size: [2, 2];
format: "rgba8unorm";
mipLevelCount: 2;
}> & SampledFlag
$usage
('sampled');
// Using Uint8Array for RGBA data (4 pixels, 4 bytes each)
const
const data: Uint8Array<ArrayBuffer>
data
= new
var Uint8Array: Uint8ArrayConstructor
new (elements: Iterable<number>) => Uint8Array<ArrayBuffer> (+6 overloads)
Uint8Array
([
255, 0, 0, 255, // Red pixel
0, 255, 0, 255, // Green pixel
0, 0, 255, 255, // Blue pixel
255, 255, 0, 255, // Yellow pixel
]);
const texture: TgpuTexture<{
size: [2, 2];
format: "rgba8unorm";
mipLevelCount: 2;
}> & SampledFlag
texture
.
TgpuTexture<{ size: [2, 2]; format: "rgba8unorm"; mipLevelCount: 2; }>.write(source: ArrayBuffer | TypedArray | DataView, options?: number | TextureRawWriteOptions): void (+1 overload)

Writes raw texel data to the texture

write
(
const data: Uint8Array<ArrayBuffer>
data
);
// Write to a specific mip level
const
const mipData: Uint8Array<ArrayBuffer>
mipData
= new
var Uint8Array: Uint8ArrayConstructor
new (length: number) => Uint8Array<ArrayBuffer> (+6 overloads)
Uint8Array
(4); // Data for 1 pixel
const texture: TgpuTexture<{
size: [2, 2];
format: "rgba8unorm";
mipLevelCount: 2;
}> & SampledFlag
texture
.
TgpuTexture<{ size: [2, 2]; format: "rgba8unorm"; mipLevelCount: 2; }>.write(source: ArrayBuffer | TypedArray | DataView, options?: number | TextureRawWriteOptions): void (+1 overload)

Writes raw texel data to the texture

write
(
const mipData: Uint8Array<ArrayBuffer>
mipData
, 1); // Write to mip level 1
// Update just a region
const
const regionData: Uint8Array<ArrayBuffer>
regionData
= new
var Uint8Array: Uint8ArrayConstructor
new (length: number) => Uint8Array<ArrayBuffer> (+6 overloads)
Uint8Array
(4); // Data for 1 pixel
const texture: TgpuTexture<{
size: [2, 2];
format: "rgba8unorm";
mipLevelCount: 2;
}> & SampledFlag
texture
.
TgpuTexture<{ size: [2, 2]; format: "rgba8unorm"; mipLevelCount: 2; }>.write(source: ArrayBuffer | TypedArray | DataView, options?: number | TextureRawWriteOptions): void (+1 overload)

Writes raw texel data to the texture

write
(
const regionData: Uint8Array<ArrayBuffer>
regionData
, {
origin?: readonly [x: number, y: number, z?: number | undefined] | undefined
origin
: [1, 1],
size?: readonly [width: number, height: number, depthOrArrayLayers?: number | undefined] | undefined
size
: [1, 1] });

Writing raw data doesn’t require the 'render' usage flag, but the byte length has to exactly match the written region for the given texture format.

If you only want to update a part of the texture, or copy just a fragment of the source image, you can pass options with source and destination regions. The options also let you flip the source vertically (flipY), premultiply alpha (premultipliedAlpha), or convert to a specific color space (colorSpace).

const
const texture: TgpuTexture<{
size: [512, 512];
format: "rgba8unorm";
}> & SampledFlag & RenderFlag
texture
=
const root: TgpuRoot
root
.
TgpuRoot.createTexture<number, number, number, [512, 512], "rgba8unorm", number, number, GPUTextureFormat[], GPUTextureDimension>(props: CreateTextureOptions<[512, 512], "rgba8unorm", number, number, GPUTextureFormat[], GPUTextureDimension>): TgpuTexture<{
size: [512, 512];
format: "rgba8unorm";
}>
createTexture
({
size: [512, 512]

The width, height, and depth or layer count of the texture.

size
: [512, 512],
format: "rgba8unorm"

The format of the texture.

format
: 'rgba8unorm',
}).
TgpuTexture<{ size: [512, 512]; format: "rgba8unorm"; }>.$usage<["sampled", "render"]>(usages_0: "sampled", usages_1: "render"): TgpuTexture<{
size: [512, 512];
format: "rgba8unorm";
}> & SampledFlag & RenderFlag
$usage
('sampled', 'render');
const texture: TgpuTexture<{
size: [512, 512];
format: "rgba8unorm";
}> & SampledFlag & RenderFlag
texture
.
TgpuTexture<{ size: [512, 512]; format: "rgba8unorm"; }>.write(source: GPUCopyExternalImageSource | GPUCopyExternalImageSource[], options?: TextureWriteOptions): void (+1 overload)

Writes image sources to the texture, one per array layer. Requires the 'render' usage flag

write
(
const imageBitmap: ImageBitmap
imageBitmap
, {
sourceOrigin?: readonly [x: number, y: number] | undefined
sourceOrigin
: [16, 16],
sourceSize?: readonly [width: number, height: number] | undefined
sourceSize
: [128, 128],
origin?: readonly [x: number, y: number, z?: number | undefined] | undefined
origin
: [128, 64],
size?: readonly [width: number, height: number] | undefined
size
: [128, 128],
});

Sometimes you’ll want to pack multiple grayscale maps into a single texture - for example combining separate roughness, metalness, and mask maps into one material texture. The common.writeChannels utility does exactly that. Each entry writes a single channel of the texture, with from selecting which channel of the source to read. Entries set to undefined are skipped.

const
const texture: TgpuTexture<{
size: [512, 512];
format: "rgba8unorm";
}> & SampledFlag & RenderFlag
texture
=
const root: TgpuRoot
root
.
TgpuRoot.createTexture<number, number, number, [512, 512], "rgba8unorm", number, number, GPUTextureFormat[], GPUTextureDimension>(props: CreateTextureOptions<[512, 512], "rgba8unorm", number, number, GPUTextureFormat[], GPUTextureDimension>): TgpuTexture<{
size: [512, 512];
format: "rgba8unorm";
}>
createTexture
({
size: [512, 512]

The width, height, and depth or layer count of the texture.

size
: [512, 512],
format: "rgba8unorm"

The format of the texture.

format
: 'rgba8unorm',
}).
TgpuTexture<{ size: [512, 512]; format: "rgba8unorm"; }>.$usage<["sampled", "render"]>(usages_0: "sampled", usages_1: "render"): TgpuTexture<{
size: [512, 512];
format: "rgba8unorm";
}> & SampledFlag & RenderFlag
$usage
('sampled', 'render');
import common
common
.
function writeChannels(texture: TgpuTexture & RenderFlag, channels: TextureChannels, options?: TextureWriteOptions): void
export writeChannels

Writes image sources into individual channels of texture. Each entry writes a single channel, with from selecting which channel of the source to read. Omitted channels are left untouched.

Requires the 'render' usage flag on the texture.

@example

common.writeChannels(material, {
r: { source: roughnessMap, from: 'r' },
g: { source: metalnessMap, from: 'r' },
a: { source: maskMap, from: 'r' },
});

writeChannels
(
const texture: TgpuTexture<{
size: [512, 512];
format: "rgba8unorm";
}> & SampledFlag & RenderFlag
texture
, {
r?: TextureChannelSource | undefined
r
: {
source: GPUCopyExternalImageSource
source
:
const roughnessMap: ImageBitmap
roughnessMap
,
from: TextureChannel
from
: 'r' },
g?: TextureChannelSource | undefined
g
: {
source: GPUCopyExternalImageSource
source
:
const metalnessMap: ImageBitmap
metalnessMap
,
from: TextureChannel
from
: 'r' },
a?: TextureChannelSource | undefined
a
: {
source: GPUCopyExternalImageSource
source
:
const maskMap: ImageBitmap
maskMap
,
from: TextureChannel
from
: 'r' },
});

Region and channel writes follow the same rules as other image writes - they require the 'render' usage flag, and sizes have to match unless you pass a fit mode.

TypeGPU provides automatic mipmap generation for textures:

const
const texture: TgpuTexture<{
size: [256, 256];
format: "rgba8unorm";
mipLevelCount: 9;
}> & SampledFlag & RenderFlag
texture
=
const root: TgpuRoot
root
.
TgpuRoot.createTexture<number, number, number, [256, 256], "rgba8unorm", 9, number, GPUTextureFormat[], GPUTextureDimension>(props: CreateTextureOptions<[256, 256], "rgba8unorm", 9, number, GPUTextureFormat[], GPUTextureDimension>): TgpuTexture<{
size: [256, 256];
format: "rgba8unorm";
mipLevelCount: 9;
}>
createTexture
({
size: [256, 256]

The width, height, and depth or layer count of the texture.

size
: [256, 256],
format: "rgba8unorm"

The format of the texture.

format
: 'rgba8unorm',
mipLevelCount?: 9 | undefined

The number of mip levels the texture will contain.

@default ― 1

mipLevelCount
: 9, // log2(256) + 1
}).
TgpuTexture<{ size: [256, 256]; format: "rgba8unorm"; mipLevelCount: 9; }>.$usage<["sampled", "render"]>(usages_0: "sampled", usages_1: "render"): TgpuTexture<{
size: [256, 256];
format: "rgba8unorm";
mipLevelCount: 9;
}> & SampledFlag & RenderFlag
$usage
('sampled', 'render');
const texture: TgpuTexture<{
size: [256, 256];
format: "rgba8unorm";
mipLevelCount: 9;
}> & SampledFlag & RenderFlag
texture
.
TgpuTexture<{ size: [256, 256]; format: "rgba8unorm"; mipLevelCount: 9; }>.write(source: GPUCopyExternalImageSource | GPUCopyExternalImageSource[], options?: TextureWriteOptions): void (+1 overload)

Writes image sources to the texture, one per array layer. Requires the 'render' usage flag

write
(
const imageBitmap: ImageBitmap
imageBitmap
, {
fit?: TextureWriteFit | undefined
fit
: 'stretch' });
const texture: TgpuTexture<{
size: [256, 256];
format: "rgba8unorm";
mipLevelCount: 9;
}> & SampledFlag & RenderFlag
texture
.
TgpuTexture<{ size: [256, 256]; format: "rgba8unorm"; mipLevelCount: 9; }>.generateMipmaps(baseMipLevel?: number, mipLevels?: number): void
generateMipmaps
(); // Generate all mip levels automatically

You can also copy data from another texture. If both textures have the same size and format, a plain targetTexture.copyFrom(sourceTexture) is all you need. To copy a region, target a specific mip level, or copy between differently sized textures, pass copy options:

const targetTexture: TgpuTexture<{
size: [512, 512];
format: "rgba8unorm";
}>
targetTexture
.
TgpuTexture<{ size: [512, 512]; format: "rgba8unorm"; }>.copyFrom<TgpuTexture<{
size: [64, 64];
format: "rgba8unorm";
}>>(source: TgpuTexture<{
size: [64, 64];
format: "rgba8unorm";
}>, options: TextureCopyOptions): void (+1 overload)

Copies a region between textures of the same format

copyFrom
(
const sourceTexture: TgpuTexture<{
size: [64, 64];
format: "rgba8unorm";
}>
sourceTexture
, {
sourceOrigin?: readonly [x: number, y: number, z?: number | undefined] | undefined
sourceOrigin
: [16, 16],
origin?: readonly [x: number, y: number, z?: number | undefined] | undefined
origin
: [128, 64],
size?: readonly [width: number, height: number, depthOrArrayLayers?: number | undefined] | undefined
size
: [32, 32],
});

To wipe a texture clean, use texture.clear(), which fills every mip level with zeros, or pass a mip level to clear only that level. You can also pass an rgba color to fill the texture with instead (this requires the 'render' usage flag):

const texture: TgpuTexture<{
size: [512, 512];
format: "rgba8unorm";
}> & RenderFlag
texture
.
TgpuTexture<{ size: [512, 512]; format: "rgba8unorm"; }>.clear(color: readonly [number, number, number, number], mipLevel?: number | "all"): void (+1 overload)

Clears the texture to color. Requires the 'render' usage flag

clear
([0, 0.5, 0, 1]);

Call .destroy() when the texture is no longer needed. This releases the underlying GPUTexture; subsequent operations on the TypeGPU texture are invalid.

To create a view - which will also serve as fixed texture usage - you can use one of the available texture schemas. You can pass it to the .createView method of the texture.

const
const texture: TgpuTexture<{
size: [512, 512];
format: "rgba8unorm";
}> & SampledFlag
texture
=
const root: TgpuRoot
root
.
TgpuRoot.createTexture<number, number, number, [512, 512], "rgba8unorm", number, number, GPUTextureFormat[], GPUTextureDimension>(props: CreateTextureOptions<[512, 512], "rgba8unorm", number, number, GPUTextureFormat[], GPUTextureDimension>): TgpuTexture<{
size: [512, 512];
format: "rgba8unorm";
}>
createTexture
({
size: [512, 512]

The width, height, and depth or layer count of the texture.

size
: [512, 512],
format: "rgba8unorm"

The format of the texture.

format
: 'rgba8unorm',
}).
TgpuTexture<{ size: [512, 512]; format: "rgba8unorm"; }>.$usage<["sampled"]>(usages_0: "sampled"): TgpuTexture<{
size: [512, 512];
format: "rgba8unorm";
}> & SampledFlag
$usage
('sampled');
const
const sampledView: TgpuTextureView<d.WgslTexture2d<d.F32>>
sampledView
=
const texture: TgpuTexture<{
size: [512, 512];
format: "rgba8unorm";
}> & SampledFlag
texture
.
TgpuTexture<{ size: [512, 512]; format: "rgba8unorm"; }>.createView<d.WgslTexture2d<d.F32>>(schema: d.WgslTexture2d<d.F32>, viewDescriptor?: (TgpuTextureViewDescriptor & {
sampleType?: "float" | "unfilterable-float" | undefined;
}) | undefined): TgpuTextureView<d.WgslTexture2d<d.F32>> (+3 overloads)
createView
(
import d
d
.
texture2d<d.F32>(sampleType: d.F32): d.WgslTexture2d<d.F32> (+1 overload)
export texture2d
texture2d
(
import d
d
.
const f32: d.F32
export 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.

@example const value = f32(); // 0

@example const value = f32(1.23); // 1.23

@example const value = f32(true); // 1

f32
));
// in this case the same as:
// - texture.createView(d.texture2d()); (defaults to f32)
// - texture.createView(); (defaults to texture2d<f32>)

To sample textures in shaders, you’ll often need a sampler that defines how the texture should be filtered and addressed. The createSampler method accepts the same descriptor as the vanilla WebGPU GPUSamplerDescriptor:

const
const sampler: TgpuFixedSampler
sampler
=
const root: TgpuRoot
root
.
TgpuRoot.createSampler(props: WgslSamplerProps): TgpuFixedSampler
createSampler
({
WgslSamplerProps.magFilter?: GPUFilterMode | undefined

Specifies the sampling behavior when the sample footprint is smaller than or equal to one texel.

magFilter
: 'linear',
WgslSamplerProps.minFilter?: GPUFilterMode | undefined

Specifies the sampling behavior when the sample footprint is larger than one texel.

minFilter
: 'linear',
WgslSamplerProps.mipmapFilter?: GPUMipmapFilterMode | undefined

Specifies behavior for sampling between mipmap levels.

mipmapFilter
: 'linear',
WgslSamplerProps.addressModeU?: GPUAddressMode | undefined
addressModeU
: 'repeat',
WgslSamplerProps.addressModeV?: GPUAddressMode | undefined
addressModeV
: 'repeat',
});

The returned sampler object can be used like a fixed resource directly in shaders, or bound in a bind group for manual binding.

Depth comparisons use a distinct sampler type. Create one with root.createComparisonSampler, then pass it to std.textureSampleCompare with a depth texture:

const
const shadowMap: TgpuTexture<{
size: [1024, 1024];
format: "depth24plus";
}> & SampledFlag
shadowMap
=
const root: TgpuRoot
root
.
TgpuRoot.createTexture<number, number, number, [1024, 1024], "depth24plus", number, number, GPUTextureFormat[], GPUTextureDimension>(props: CreateTextureOptions<[1024, 1024], "depth24plus", number, number, GPUTextureFormat[], GPUTextureDimension>): TgpuTexture<{
size: [1024, 1024];
format: "depth24plus";
}>
createTexture
({
size: [1024, 1024]

The width, height, and depth or layer count of the texture.

size
: [1024, 1024],
format: "depth24plus"

The format of the texture.

format
: 'depth24plus',
}).
TgpuTexture<{ size: [1024, 1024]; format: "depth24plus"; }>.$usage<["sampled"]>(usages_0: "sampled"): TgpuTexture<{
size: [1024, 1024];
format: "depth24plus";
}> & SampledFlag
$usage
('sampled');
const
const shadowView: TgpuTextureView<d.WgslTextureDepth2d>
shadowView
=
const shadowMap: TgpuTexture<{
size: [1024, 1024];
format: "depth24plus";
}> & SampledFlag
shadowMap
.
TgpuTexture<{ size: [1024, 1024]; format: "depth24plus"; }>.createView<d.WgslTextureDepth2d>(schema: d.WgslTextureDepth2d, viewDescriptor?: (TgpuTextureViewDescriptor & {
sampleType?: "float" | "unfilterable-float" | undefined;
}) | undefined): TgpuTextureView<d.WgslTextureDepth2d> (+3 overloads)
createView
(
import d
d
.
function textureDepth2d(): d.WgslTextureDepth2d
export textureDepth2d
textureDepth2d
());
const
const shadowSampler: TgpuFixedComparisonSampler
shadowSampler
=
const root: TgpuRoot
root
.
TgpuRoot.createComparisonSampler(props: WgslComparisonSamplerProps): TgpuFixedComparisonSampler
createComparisonSampler
({
WgslComparisonSamplerProps.compare: GPUCompareFunction
compare
: 'less-equal',
WgslComparisonSamplerProps.magFilter?: GPUFilterMode | undefined

Specifies the sampling behavior when the sample footprint is smaller than or equal to one texel.

magFilter
: 'linear',
WgslComparisonSamplerProps.minFilter?: GPUFilterMode | undefined

Specifies the sampling behavior when the sample footprint is larger than one texel.

minFilter
: 'linear',
});
const
const sampleShadow: TgpuFn<(uv: d.Vec2f, depth: d.F32) => d.F32>
sampleShadow
=
const tgpu: {
const: typeof import("node_modules/typegpu/src/core/constant/tgpuConstant").constant;
fn: typeof import("node_modules/typegpu/src/core/function/tgpuFn").fn;
comptime: typeof import("node_modules/typegpu/src/core/function/comptime").comptime;
resolve: typeof import("node_modules/typegpu/src/core/resolve/tgpuResolve").resolve;
resolveWithContext: typeof import("node_modules/typegpu/src/core/resolve/tgpuResolve").resolveWithContext;
init: typeof import("node_modules/typegpu/src/core/root/init").init;
initFromDevice: typeof import("node_modules/typegpu/src/core/root/init").initFromDevice;
slot: typeof import("node_modules/typegpu/src/core/slot/slot").slot;
lazy: typeof import("node_modules/typegpu/src/core/slot/lazy").lazy;
... 10 more ...;
'~unstable': typeof import("node_modules/typegpu/src/tgpuUnstable");
}

@module ― typegpu

tgpu
.
fn: <[d.Vec2f, d.F32], d.F32>(argTypes: [d.Vec2f, d.F32], returnType: d.F32) => TgpuFnShell<[d.Vec2f, d.F32], d.F32> (+2 overloads)
fn
([
import d
d
.
const vec2f: d.Vec2f
vec2f
,
import d
d
.
const f32: d.F32
export 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.

@example const value = f32(); // 0

@example const value = f32(1.23); // 1.23

@example const value = f32(true); // 1

f32
],
import d
d
.
const f32: d.F32
export 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.

@example const value = f32(); // 0

@example const value = f32(1.23); // 1.23

@example const value = f32(true); // 1

f32
)((
uv: d.v2f
uv
,
depth: number
depth
) => {
'use gpu';
return
import std
std
.
textureSampleCompare<d.textureDepth2d>(texture: d.textureDepth2d, sampler: d.comparisonSampler, coords: d.v2f, depthRef: number): number (+5 overloads)
export textureSampleCompare
textureSampleCompare
(
const shadowView: TgpuTextureView<d.WgslTextureDepth2d>
shadowView
.
TgpuTextureView<WgslTextureDepth2d>.$: d.textureDepth2d
$
,
const shadowSampler: TgpuFixedComparisonSampler
shadowSampler
.
TgpuComparisonSampler.$: d.comparisonSampler
$
,
uv: d.v2f
uv
,
depth: number
depth
);
});

For manual binding, pair d.comparisonSampler() with a comparison layout entry:

const layout = tgpu.bindGroupLayout({
shadowMap: { texture: d.textureDepth2d() },
shadowSampler: { sampler: 'comparison' },
});

Regular samplers created with createSampler use d.sampler() and a 'filtering' or 'non-filtering' layout entry instead.

Textures can be used in shaders through bind groups or as fixed resources, similar to buffers.

const
const texture: TgpuTexture<{
size: [256, 256];
format: "rgba8unorm";
}> & SampledFlag
texture
=
const root: TgpuRoot
root
.
TgpuRoot.createTexture<number, number, number, [256, 256], "rgba8unorm", number, number, GPUTextureFormat[], GPUTextureDimension>(props: CreateTextureOptions<[256, 256], "rgba8unorm", number, number, GPUTextureFormat[], GPUTextureDimension>): TgpuTexture<{
size: [256, 256];
format: "rgba8unorm";
}>
createTexture
({
size: [256, 256]

The width, height, and depth or layer count of the texture.

size
: [256, 256],
format: "rgba8unorm"

The format of the texture.

format
: 'rgba8unorm',
}).
TgpuTexture<{ size: [256, 256]; format: "rgba8unorm"; }>.$usage<["sampled"]>(usages_0: "sampled"): TgpuTexture<{
size: [256, 256];
format: "rgba8unorm";
}> & SampledFlag
$usage
('sampled');
const
const sampler: TgpuFixedSampler
sampler
=
const root: TgpuRoot
root
.
TgpuRoot.createSampler(props: WgslSamplerProps): TgpuFixedSampler
createSampler
({
WgslSamplerProps.magFilter?: GPUFilterMode | undefined

Specifies the sampling behavior when the sample footprint is smaller than or equal to one texel.

magFilter
: 'linear',
WgslSamplerProps.minFilter?: GPUFilterMode | undefined

Specifies the sampling behavior when the sample footprint is larger than one texel.

minFilter
: 'linear',
});
const
const bindGroupLayout: TgpuBindGroupLayout<{
myTexture: {
texture: d.WgslTexture2d<d.F32>;
};
mySampler: {
sampler: "filtering";
};
}>
bindGroupLayout
=
const tgpu: {
const: typeof import("node_modules/typegpu/src/core/constant/tgpuConstant").constant;
fn: typeof import("node_modules/typegpu/src/core/function/tgpuFn").fn;
comptime: typeof import("node_modules/typegpu/src/core/function/comptime").comptime;
resolve: typeof import("node_modules/typegpu/src/core/resolve/tgpuResolve").resolve;
resolveWithContext: typeof import("node_modules/typegpu/src/core/resolve/tgpuResolve").resolveWithContext;
init: typeof import("node_modules/typegpu/src/core/root/init").init;
initFromDevice: typeof import("node_modules/typegpu/src/core/root/init").initFromDevice;
slot: typeof import("node_modules/typegpu/src/core/slot/slot").slot;
lazy: typeof import("node_modules/typegpu/src/core/slot/lazy").lazy;
... 10 more ...;
'~unstable': typeof import("node_modules/typegpu/src/tgpuUnstable");
}

@module ― typegpu

tgpu
.
bindGroupLayout: <{
myTexture: {
texture: d.WgslTexture2d<d.F32>;
};
mySampler: {
sampler: "filtering";
};
}>(entries: {
myTexture: {
texture: d.WgslTexture2d<d.F32>;
};
mySampler: {
sampler: "filtering";
};
}) => TgpuBindGroupLayout<{
myTexture: {
texture: d.WgslTexture2d<d.F32>;
};
mySampler: {
sampler: "filtering";
};
}>
bindGroupLayout
({
myTexture: {
texture: d.WgslTexture2d<d.F32>;
}
myTexture
: {
texture: d.WgslTexture2d<d.F32>
texture
:
import d
d
.
function texture2d(): d.WgslTexture2d<d.F32> (+1 overload)
export texture2d
texture2d
() },
mySampler: {
sampler: "filtering";
}
mySampler
: {
sampler: "filtering"
sampler
: 'filtering' },
});
const
const bindGroup: TgpuBindGroup<{
myTexture: {
texture: d.WgslTexture2d<d.F32>;
};
mySampler: {
sampler: "filtering";
};
}>
bindGroup
=
const root: TgpuRoot
root
.
TgpuRoot.createBindGroup<{
myTexture: {
texture: d.WgslTexture2d<d.F32>;
};
mySampler: {
sampler: "filtering";
};
}>(layout: TgpuBindGroupLayout<{
myTexture: {
texture: d.WgslTexture2d<d.F32>;
};
mySampler: {
sampler: "filtering";
};
}>, entries: ExtractBindGroupInputFromLayout<{
myTexture: {
texture: d.WgslTexture2d<d.F32>;
};
mySampler: {
sampler: "filtering";
};
}>): TgpuBindGroup<{
myTexture: {
texture: d.WgslTexture2d<d.F32>;
};
mySampler: {
sampler: "filtering";
};
}>

Creates a group of resources that can be bound to a shader based on a specified layout.

@remarks ― Typed wrapper around a GPUBindGroup.

@example

const fooLayout = tgpu.bindGroupLayout({ foo: { uniform: d.vec3f }, bar: { texture: d.texture2d(d.f32) }, });

const fooBuffer = ...; const barTexture = ...;

const fooBindGroup = root.createBindGroup(fooLayout, { foo: fooBuffer, bar: barTexture, });

@param ― layout Layout describing the bind group to be created.

@param ― entries A record with values being the resources populating the bind group and keys being their associated names, matching the layout keys.

createBindGroup
(
const bindGroupLayout: TgpuBindGroupLayout<{
myTexture: {
texture: d.WgslTexture2d<d.F32>;
};
mySampler: {
sampler: "filtering";
};
}>
bindGroupLayout
, {
myTexture: GPUTextureView | GPUTexture | (SampledFlag & TgpuTexture<{
size: readonly number[];
format: GPUTextureFormat;
dimension?: "2d" | undefined;
sampleCount?: 1 | undefined;
}>) | TgpuTextureView<d.WgslTexture<WgslTextureProps>>
myTexture
:
const texture: TgpuTexture<{
size: [256, 256];
format: "rgba8unorm";
}> & SampledFlag
texture
,
// views can also be used - as long as the schema matches
// myTexture: texture.createView(),
mySampler: TgpuSampler | GPUSampler
mySampler
:
const sampler: TgpuFixedSampler
sampler
,
});

For textures that remain consistent across operations, you can create fixed texture views:

const
const texture: TgpuTexture<{
size: [256, 256];
format: "rgba8unorm";
}> & SampledFlag
texture
=
const root: TgpuRoot
root
.
TgpuRoot.createTexture<number, number, number, [256, 256], "rgba8unorm", number, number, GPUTextureFormat[], GPUTextureDimension>(props: CreateTextureOptions<[256, 256], "rgba8unorm", number, number, GPUTextureFormat[], GPUTextureDimension>): TgpuTexture<{
size: [256, 256];
format: "rgba8unorm";
}>
createTexture
({
size: [256, 256]

The width, height, and depth or layer count of the texture.

size
: [256, 256],
format: "rgba8unorm"

The format of the texture.

format
: 'rgba8unorm',
}).
TgpuTexture<{ size: [256, 256]; format: "rgba8unorm"; }>.$usage<["sampled"]>(usages_0: "sampled"): TgpuTexture<{
size: [256, 256];
format: "rgba8unorm";
}> & SampledFlag
$usage
('sampled');
// Create a fixed sampled view
const
const sampledView: TgpuTextureView<d.WgslTexture2d<d.F32>>
sampledView
=
const texture: TgpuTexture<{
size: [256, 256];
format: "rgba8unorm";
}> & SampledFlag
texture
.
TgpuTexture<{ size: [256, 256]; format: "rgba8unorm"; }>.createView(): TgpuTextureView<d.WgslTexture2d<d.F32>> (+3 overloads)
createView
();
const
const sampler: TgpuFixedSampler
sampler
=
const root: TgpuRoot
root
.
TgpuRoot.createSampler(props: WgslSamplerProps): TgpuFixedSampler
createSampler
({
WgslSamplerProps.magFilter?: GPUFilterMode | undefined

Specifies the sampling behavior when the sample footprint is smaller than or equal to one texel.

magFilter
: 'linear',
WgslSamplerProps.minFilter?: GPUFilterMode | undefined

Specifies the sampling behavior when the sample footprint is larger than one texel.

minFilter
: 'linear',
});
const
const myShader: TgpuFn<(uv: d.Vec2f) => d.Vec4f>
myShader
=
const tgpu: {
const: typeof import("node_modules/typegpu/src/core/constant/tgpuConstant").constant;
fn: typeof import("node_modules/typegpu/src/core/function/tgpuFn").fn;
comptime: typeof import("node_modules/typegpu/src/core/function/comptime").comptime;
resolve: typeof import("node_modules/typegpu/src/core/resolve/tgpuResolve").resolve;
resolveWithContext: typeof import("node_modules/typegpu/src/core/resolve/tgpuResolve").resolveWithContext;
init: typeof import("node_modules/typegpu/src/core/root/init").init;
initFromDevice: typeof import("node_modules/typegpu/src/core/root/init").initFromDevice;
slot: typeof import("node_modules/typegpu/src/core/slot/slot").slot;
lazy: typeof import("node_modules/typegpu/src/core/slot/lazy").lazy;
... 10 more ...;
'~unstable': typeof import("node_modules/typegpu/src/tgpuUnstable");
}

@module ― typegpu

tgpu
.
fn: <[d.Vec2f], d.Vec4f>(argTypes: [d.Vec2f], returnType: d.Vec4f) => TgpuFnShell<[d.Vec2f], d.Vec4f> (+2 overloads)
fn
([
import d
d
.
const vec2f: d.Vec2f
vec2f
],
import d
d
.
const vec4f: d.Vec4f
vec4f
)((
uv: d.v2f
uv
) => {
'use gpu';
// Use the fixed texture view directly
return
import std
std
.
textureSample<d.texture2d<d.F32>>(texture: d.texture2d<d.F32>, sampler: d.sampler, coords: d.v2f, offset?: d.v2i): d.v4f (+8 overloads)
export textureSample
textureSample
(
const sampledView: TgpuTextureView<d.WgslTexture2d<d.F32>>
sampledView
.
TgpuTextureView<WgslTexture2d<F32>>.$: d.texture2d<d.F32>
$
,
const sampler: TgpuFixedSampler
sampler
.
TgpuSampler.$: d.sampler
$
,
uv: d.v2f
uv
);
});

© Software Mansion 2026. All trademarks and copyrights belong to their respective owners. Read about our Privacy Policy.