typegpu 0.12.5 → 0.12.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/common/index.d.ts +1 -0
- package/common/index.js +1 -0
- package/common/writeChannels.d.ts +31 -0
- package/common/writeChannels.js +32 -0
- package/common/writeSoA.js +16 -0
- package/core/buffer/buffer.js +47 -11
- package/core/commandEncoder/attachments.js +5 -2
- package/core/commandEncoder/computePass.d.ts +13 -0
- package/core/commandEncoder/computePass.js +5 -2
- package/core/commandEncoder/renderPass.d.ts +18 -4
- package/core/commandEncoder/renderPass.js +6 -2
- package/core/declare/tgpuDeclare.d.ts +11 -0
- package/core/declare/tgpuDeclare.js +1 -1
- package/core/function/autoIO.js +4 -2
- package/core/function/ioSchema.d.ts +7 -2
- package/core/function/ioSchema.js +41 -15
- package/core/function/tgpuFragmentFn.d.ts +1 -1
- package/core/function/tgpuFragmentFn.js +2 -1
- package/core/function/tgpuVertexFn.js +2 -1
- package/core/immediate/immediateVar.d.ts +52 -0
- package/core/immediate/immediateVar.js +149 -0
- package/core/pipeline/computePipeline.d.ts +17 -0
- package/core/pipeline/computePipeline.js +23 -9
- package/core/pipeline/connectAttachmentToShader.d.ts +2 -2
- package/core/pipeline/connectAttachmentToShader.js +16 -21
- package/core/pipeline/connectTargetsToShader.d.ts +5 -1
- package/core/pipeline/connectTargetsToShader.js +23 -18
- package/core/pipeline/drawState.d.ts +8 -4
- package/core/pipeline/drawState.js +41 -51
- package/core/pipeline/priors.js +1 -0
- package/core/pipeline/renderPipeline.d.ts +22 -4
- package/core/pipeline/renderPipeline.js +25 -13
- package/core/resolve/namespace.js +2 -2
- package/core/root/init.js +3 -0
- package/core/root/rootTypes.d.ts +17 -2
- package/core/slot/accessor.d.ts +1 -1
- package/core/slot/accessor.js +72 -5
- package/core/slot/slotTypes.d.ts +2 -1
- package/core/texture/texture.d.ts +20 -14
- package/core/texture/texture.js +78 -69
- package/core/texture/textureUtils.d.ts +3 -6
- package/core/texture/textureUtils.js +142 -165
- package/core/texture/textureWrite.d.ts +61 -0
- package/core/texture/textureWrite.js +59 -0
- package/data/autoStruct.d.ts +1 -1
- package/data/autoStruct.js +8 -4
- package/data/dataIO.d.ts +2 -2
- package/data/deepEqual.js +19 -9
- package/data/matrix.js +10 -3
- package/data/partialIO.d.ts +8 -1
- package/data/partialIO.js +36 -19
- package/data/ref.js +2 -2
- package/data/snippet.d.ts +11 -5
- package/data/snippet.js +9 -4
- package/data/wgslTypes.d.ts +4 -1
- package/errors.d.ts +7 -0
- package/errors.js +15 -0
- package/indexNamedExports.d.ts +5 -2
- package/indexNamedExports.js +2 -1
- package/internal.d.ts +2 -1
- package/internal.js +1 -1
- package/nameUtils.d.ts +7 -0
- package/nameUtils.js +60 -0
- package/package.json +2 -2
- package/resolutionCtx.d.ts +5 -0
- package/resolutionCtx.js +11 -0
- package/serial/restore.d.ts +3 -1
- package/serial/restore.js +2 -0
- package/shared/meta.js +1 -1
- package/shared/symbols.js +1 -1
- package/shared/tseynit.d.ts +1 -0
- package/shared/tseynit.js +80 -44
- package/std/atomic.d.ts +13 -0
- package/std/atomic.js +63 -29
- package/std/boolean.js +9 -10
- package/std/derivative.js +14 -9
- package/std/index.d.ts +4 -4
- package/std/index.js +5 -5
- package/std/numeric.d.ts +5 -1
- package/std/numeric.js +3 -3
- package/std/operators.js +9 -4
- package/std/packing.d.ts +61 -1
- package/std/packing.js +214 -25
- package/std/subgroup.d.ts +4 -0
- package/std/subgroup.js +34 -0
- package/std/texture.d.ts +15 -2
- package/std/texture.js +48 -0
- package/tgpuUnstable.d.ts +1 -0
- package/tgpuUnstable.js +1 -0
- package/tgsl/accessIndex.js +19 -23
- package/tgsl/conversion.d.ts +2 -0
- package/tgsl/conversion.js +3 -0
- package/tgsl/forOfUtils.js +6 -6
- package/tgsl/generationHelpers.js +2 -2
- package/tgsl/shaderGenerator.d.ts +1 -1
- package/tgsl/wgslGenerator.d.ts +5 -0
- package/tgsl/wgslGenerator.js +288 -58
- package/types.d.ts +9 -1
- package/types.js +5 -0
package/common/index.d.ts
CHANGED
package/common/index.js
CHANGED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { TgpuTexture } from '../core/texture/texture.ts';
|
|
2
|
+
import { type TextureChannel, type TextureWriteOptions } from '../core/texture/textureWrite.ts';
|
|
3
|
+
import type { RenderFlag } from '../core/texture/usageExtension.ts';
|
|
4
|
+
export type TextureChannelSource = {
|
|
5
|
+
source: GPUCopyExternalImageSource;
|
|
6
|
+
from: TextureChannel;
|
|
7
|
+
};
|
|
8
|
+
export type TextureChannels = {
|
|
9
|
+
[Channel in TextureChannel]?: TextureChannelSource | undefined;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Writes image sources into individual channels of `texture`. Each entry
|
|
13
|
+
* writes a single channel, with `from` selecting which channel of the
|
|
14
|
+
* source to read. Omitted channels are left untouched.
|
|
15
|
+
*
|
|
16
|
+
* Requires the `'render'` usage flag on the texture.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* common.writeChannels(material, {
|
|
21
|
+
* r: { source: roughnessMap, from: 'r' },
|
|
22
|
+
* g: { source: metalnessMap, from: 'r' },
|
|
23
|
+
* a: { source: maskMap, from: 'r' },
|
|
24
|
+
* });
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare function writeChannels(texture: TgpuTexture & RenderFlag, channels: TextureChannels, options?: TextureWriteOptions): void;
|
|
28
|
+
export declare namespace writeChannels {
|
|
29
|
+
type Channels = TextureChannels;
|
|
30
|
+
type Source = TextureChannelSource;
|
|
31
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { writeImages } from "../core/texture/textureUtils.js";
|
|
2
|
+
import { resolveImageWrite, } from "../core/texture/textureWrite.js";
|
|
3
|
+
import { $internal, $soul } from "../shared/symbols.js";
|
|
4
|
+
/**
|
|
5
|
+
* Writes image sources into individual channels of `texture`. Each entry
|
|
6
|
+
* writes a single channel, with `from` selecting which channel of the
|
|
7
|
+
* source to read. Omitted channels are left untouched.
|
|
8
|
+
*
|
|
9
|
+
* Requires the `'render'` usage flag on the texture.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* common.writeChannels(material, {
|
|
14
|
+
* r: { source: roughnessMap, from: 'r' },
|
|
15
|
+
* g: { source: metalnessMap, from: 'r' },
|
|
16
|
+
* a: { source: maskMap, from: 'r' },
|
|
17
|
+
* });
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export function writeChannels(texture, channels, options = {}) {
|
|
21
|
+
const writes = [];
|
|
22
|
+
for (const to of ['r', 'g', 'b', 'a']) {
|
|
23
|
+
const entry = channels[to];
|
|
24
|
+
if (entry) {
|
|
25
|
+
writes.push({
|
|
26
|
+
...resolveImageWrite(texture.props, entry.source, options),
|
|
27
|
+
channel: { from: entry.from, to },
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
writeImages(texture[$soul].device, texture[$internal].materialize(), writes);
|
|
32
|
+
}
|
package/common/writeSoA.js
CHANGED
|
@@ -5,6 +5,7 @@ import { undecorate } from "../data/dataTypes.js";
|
|
|
5
5
|
import { offsetsForProps } from "../data/offsets.js";
|
|
6
6
|
import { sizeOf } from "../data/sizeOf.js";
|
|
7
7
|
import { isAtomic, isMat, isMat2x2f, isMat3x3f, isWgslArray } from "../data/wgslTypes.js";
|
|
8
|
+
import { getName } from "../shared/meta.js";
|
|
8
9
|
function packedSchemaOf(schema) {
|
|
9
10
|
const unpackedSchema = undecorate(schema);
|
|
10
11
|
return isAtomic(unpackedSchema) ? unpackedSchema.inner : unpackedSchema;
|
|
@@ -92,6 +93,17 @@ function scatterSoA(target, arraySchema, soaData, startOffset, endOffset) {
|
|
|
92
93
|
}
|
|
93
94
|
}
|
|
94
95
|
}
|
|
96
|
+
// Mirrors the check in `buffer.write()`. That check only runs after the data has been
|
|
97
|
+
// scattered into `buffer.arrayBuffer`, so we check up front to leave it untouched on failure.
|
|
98
|
+
function assertAlignedWrite(buffer, startOffset, endOffset) {
|
|
99
|
+
// Writes that reach the end of the schema also cover the padding up to a multiple of 4
|
|
100
|
+
const paddedEndOffset = endOffset === sizeOf(buffer.dataType) ? roundUp(endOffset, 4) : endOffset;
|
|
101
|
+
if (startOffset % 4 !== 0 || (paddedEndOffset - startOffset) % 4 !== 0) {
|
|
102
|
+
throw new Error(`Cannot write to bytes ${startOffset}-${endOffset} of buffer '${getName(buffer) ?? '<unnamed>'}'. ` +
|
|
103
|
+
'WebGPU requires writes to start and end at a multiple of 4 bytes. ' +
|
|
104
|
+
'Align the range to 4 bytes, write the whole buffer, or use 4-byte elements (e.g. d.u32 instead of d.u16).');
|
|
105
|
+
}
|
|
106
|
+
}
|
|
95
107
|
export function writeSoA(buffer, data, options) {
|
|
96
108
|
const arrayBuffer = buffer.arrayBuffer;
|
|
97
109
|
const startOffset = options?.startOffset ?? 0;
|
|
@@ -99,6 +111,10 @@ export function writeSoA(buffer, data, options) {
|
|
|
99
111
|
const naturalSize = computeSoAByteLength(buffer.dataType, data);
|
|
100
112
|
const endOffset = options?.endOffset ??
|
|
101
113
|
(naturalSize === undefined ? bufferSize : Math.min(startOffset + naturalSize, bufferSize));
|
|
114
|
+
// Writes to mapped memory have no alignment rules
|
|
115
|
+
if (buffer.buffer.mapState !== 'mapped') {
|
|
116
|
+
assertAlignedWrite(buffer, startOffset, endOffset);
|
|
117
|
+
}
|
|
102
118
|
scatterSoA(new Uint8Array(arrayBuffer), buffer.dataType, data, startOffset, endOffset);
|
|
103
119
|
buffer.write(arrayBuffer, { startOffset, endOffset });
|
|
104
120
|
}
|
package/core/buffer/buffer.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getCompiledWriter } from "../../data/compiledIO.js";
|
|
2
2
|
import { convertPartialToPatch, getPatchInstructions } from "../../data/partialIO.js";
|
|
3
3
|
import { sizeOf } from "../../data/sizeOf.js";
|
|
4
|
+
import { roundUp } from "../../mathUtils.js";
|
|
4
5
|
import { isWgslData } from "../../data/wgslTypes.js";
|
|
5
6
|
import { getName, setName } from "../../shared/meta.js";
|
|
6
7
|
import { $internal, $soul } from "../../shared/symbols.js";
|
|
@@ -10,6 +11,14 @@ import { patchArrayBuffer } from "../../data/partialIO.js";
|
|
|
10
11
|
import { mutable, readonly, uniform, } from "./bufferBinding.js";
|
|
11
12
|
import { warnIfNotUniformAligned } from "../pipeline/webgpuLimitations.js";
|
|
12
13
|
const usageToUsageConstructor = { uniform, mutable, readonly };
|
|
14
|
+
/**
|
|
15
|
+
* WebGPU requires buffer sizes, writes, copies and mappings
|
|
16
|
+
* to be multiples of 4 bytes. Schemas like `arrayOf(u16, 3)` can have a smaller logical
|
|
17
|
+
* size, so the underlying allocation gets padded up to the next multiple of 4.
|
|
18
|
+
*/
|
|
19
|
+
function physicalSizeOf(schema) {
|
|
20
|
+
return roundUp(sizeOf(schema), 4);
|
|
21
|
+
}
|
|
13
22
|
export function INTERNAL_createBuffer(group, typeSchema, initialOrBuffer) {
|
|
14
23
|
if (!isWgslData(typeSchema)) {
|
|
15
24
|
return new TgpuBufferImpl(group, typeSchema, initialOrBuffer, ['storage', 'uniform']);
|
|
@@ -32,7 +41,7 @@ class TgpuBufferImpl {
|
|
|
32
41
|
#destroyed = false;
|
|
33
42
|
#internalBuffer;
|
|
34
43
|
get #hostBuffer() {
|
|
35
|
-
return (this.#internalBuffer ??= new ArrayBuffer(
|
|
44
|
+
return (this.#internalBuffer ??= new ArrayBuffer(physicalSizeOf(this.dataType)));
|
|
36
45
|
}
|
|
37
46
|
#mappedRange;
|
|
38
47
|
#initialCallback;
|
|
@@ -76,7 +85,7 @@ class TgpuBufferImpl {
|
|
|
76
85
|
const soul = this[$soul];
|
|
77
86
|
if (!soul.raw) {
|
|
78
87
|
soul.raw = soul.device.createBuffer({
|
|
79
|
-
size:
|
|
88
|
+
size: physicalSizeOf(soul.dataType),
|
|
80
89
|
usage: soul.flags,
|
|
81
90
|
mappedAtCreation: !!this.initial || !!this.#initialCallback,
|
|
82
91
|
label: getName(this) ?? '<unnamed>',
|
|
@@ -195,15 +204,31 @@ class TgpuBufferImpl {
|
|
|
195
204
|
writeToArrayBuffer(mapped, this.dataType, data, options);
|
|
196
205
|
return;
|
|
197
206
|
}
|
|
207
|
+
const { startOffset, endOffset } = calculateOffsets(options, this.dataType, data);
|
|
208
|
+
const size = this.#alignedWriteSize(startOffset, endOffset);
|
|
198
209
|
// If the caller already wrote directly into #hostBuffer via
|
|
199
210
|
// arrayBuffer, skip the redundant copy, the data is already in place.
|
|
200
211
|
if (!(data instanceof ArrayBuffer && data === this.#hostBuffer)) {
|
|
201
212
|
writeToArrayBuffer(this.#hostBuffer, this.dataType, data, options);
|
|
202
213
|
}
|
|
203
|
-
const { startOffset, endOffset } = calculateOffsets(options, this.dataType, data);
|
|
204
|
-
const size = endOffset - startOffset;
|
|
205
214
|
this[$soul].device.queue.writeBuffer(gpuBuffer, startOffset, this.#hostBuffer, startOffset, size);
|
|
206
215
|
}
|
|
216
|
+
/**
|
|
217
|
+
* Returns the number of bytes to upload when writing to `[startOffset, endOffset)`.
|
|
218
|
+
* Writes that reach the end of the schema also cover the trailing padding (see {@link physicalSizeOf}).
|
|
219
|
+
* Other writes have to be 4-byte aligned already, since filling in the neighboring bytes
|
|
220
|
+
* from the host could overwrite data that was changed on the GPU.
|
|
221
|
+
*/
|
|
222
|
+
#alignedWriteSize(startOffset, endOffset) {
|
|
223
|
+
const paddedEndOffset = endOffset === sizeOf(this.dataType) ? physicalSizeOf(this.dataType) : endOffset;
|
|
224
|
+
const size = paddedEndOffset - startOffset;
|
|
225
|
+
if (startOffset % 4 !== 0 || size % 4 !== 0) {
|
|
226
|
+
throw new Error(`Cannot write to bytes ${startOffset}-${endOffset} of buffer '${getName(this) ?? '<unnamed>'}'. ` +
|
|
227
|
+
'WebGPU requires writes to start and end at a multiple of 4 bytes. ' +
|
|
228
|
+
'Align the range to 4 bytes, write the whole buffer, or use 4-byte elements (e.g. d.u32 instead of d.u16).');
|
|
229
|
+
}
|
|
230
|
+
return size;
|
|
231
|
+
}
|
|
207
232
|
/** @deprecated Use {@link patch} instead. */
|
|
208
233
|
writePartial(data) {
|
|
209
234
|
this.patch(convertPartialToPatch(this.dataType, data));
|
|
@@ -214,9 +239,19 @@ class TgpuBufferImpl {
|
|
|
214
239
|
patchArrayBuffer(this.#getMappedRange(), this.dataType, data);
|
|
215
240
|
}
|
|
216
241
|
else {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
242
|
+
// Every range is validated before the patch touches #hostBuffer, so a failing patch
|
|
243
|
+
// is neither uploaded halfway nor left behind in `arrayBuffer`
|
|
244
|
+
const instructions = getPatchInstructions(this.dataType, data, this.#hostBuffer, (start, end) => this.#alignedWriteSize(start, end));
|
|
245
|
+
for (const { data, gpuOffset, uploadSize } of instructions) {
|
|
246
|
+
if (uploadSize === data.byteLength) {
|
|
247
|
+
this[$soul].device.queue.writeBuffer(gpuBuffer, gpuOffset, data);
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
// Extending the write into the trailing padding (see physicalSizeOf)
|
|
251
|
+
const padded = new Uint8Array(uploadSize);
|
|
252
|
+
padded.set(data);
|
|
253
|
+
this[$soul].device.queue.writeBuffer(gpuBuffer, gpuOffset, padded);
|
|
254
|
+
}
|
|
220
255
|
}
|
|
221
256
|
}
|
|
222
257
|
}
|
|
@@ -238,7 +273,7 @@ class TgpuBufferImpl {
|
|
|
238
273
|
if (this.buffer.mapState === 'mapped') {
|
|
239
274
|
throw new Error('Cannot copy to a mapped buffer.');
|
|
240
275
|
}
|
|
241
|
-
const size =
|
|
276
|
+
const size = physicalSizeOf(this.dataType);
|
|
242
277
|
if (encoder) {
|
|
243
278
|
encoder[$internal].rawEncoder.copyBufferToBuffer(srcBuffer.buffer, 0, this.buffer, 0, size);
|
|
244
279
|
return;
|
|
@@ -258,14 +293,15 @@ class TgpuBufferImpl {
|
|
|
258
293
|
this.#unmapBuffer();
|
|
259
294
|
return res;
|
|
260
295
|
}
|
|
296
|
+
const size = physicalSizeOf(this.dataType);
|
|
261
297
|
const stagingBuffer = this[$soul].device.createBuffer({
|
|
262
|
-
size
|
|
298
|
+
size,
|
|
263
299
|
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ,
|
|
264
300
|
});
|
|
265
301
|
const commandEncoder = this[$soul].device.createCommandEncoder();
|
|
266
|
-
commandEncoder.copyBufferToBuffer(gpuBuffer, 0, stagingBuffer, 0,
|
|
302
|
+
commandEncoder.copyBufferToBuffer(gpuBuffer, 0, stagingBuffer, 0, size);
|
|
267
303
|
this[$soul].device.queue.submit([commandEncoder.finish()]);
|
|
268
|
-
await stagingBuffer.mapAsync(GPUMapMode.READ, 0,
|
|
304
|
+
await stagingBuffer.mapAsync(GPUMapMode.READ, 0, size);
|
|
269
305
|
const res = readFromArrayBuffer(stagingBuffer.getMappedRange(), this.dataType);
|
|
270
306
|
stagingBuffer.unmap();
|
|
271
307
|
stagingBuffer.destroy();
|
|
@@ -1,16 +1,19 @@
|
|
|
1
|
+
import { WeakMemo } from "../../memo.js";
|
|
1
2
|
import { $internal } from "../../shared/symbols.js";
|
|
2
3
|
import { isQuerySet } from "../querySet/querySet.js";
|
|
3
4
|
import { isGPUCanvasContext } from "../pipeline/typeGuards.js";
|
|
4
5
|
import { isTexture, isTextureView, } from "../texture/texture.js";
|
|
6
|
+
// Canvas contexts return the same texture within a frame, so its identity is enough to cache views
|
|
7
|
+
const defaultAttachmentViews = new WeakMemo((texture) => texture.createView());
|
|
5
8
|
export function unwrapAttachmentView(root, view) {
|
|
6
9
|
if (isTexture(view)) {
|
|
7
|
-
return root.unwrap(view)
|
|
10
|
+
return defaultAttachmentViews.getOrMake(root.unwrap(view));
|
|
8
11
|
}
|
|
9
12
|
if (isTextureView(view)) {
|
|
10
13
|
return root.unwrap(view);
|
|
11
14
|
}
|
|
12
15
|
if (isGPUCanvasContext(view)) {
|
|
13
|
-
return view.getCurrentTexture()
|
|
16
|
+
return defaultAttachmentViews.getOrMake(view.getCurrentTexture());
|
|
14
17
|
}
|
|
15
18
|
return view;
|
|
16
19
|
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type { PrimitiveOffsetInfo } from '../../data/offsetUtils.ts';
|
|
2
2
|
import type { AnyWgslData } from '../../data/wgslTypes.ts';
|
|
3
|
+
import type { InferInput } from '../../shared/repr.ts';
|
|
3
4
|
import { $internal } from '../../shared/symbols.ts';
|
|
4
5
|
import type { TgpuBindGroup, TgpuBindGroupLayout, TgpuLayoutEntry } from '../../tgpuBindGroupLayout.ts';
|
|
5
6
|
import type { IndirectFlag, TgpuBuffer } from '../buffer/buffer.ts';
|
|
7
|
+
import type { TgpuImmediateVar } from '../immediate/immediateVar.ts';
|
|
6
8
|
import { ComputeDrawState } from '../pipeline/drawState.ts';
|
|
7
9
|
import type { TgpuComputePipeline } from '../pipeline/computePipeline.ts';
|
|
8
10
|
import type { ExperimentalTgpuRoot } from '../root/rootTypes.ts';
|
|
@@ -41,6 +43,17 @@ export interface TgpuComputePass {
|
|
|
41
43
|
setBindGroup(bindGroup: TgpuBindGroup): void;
|
|
42
44
|
/** Associates a bind group with the given layout */
|
|
43
45
|
setBindGroup<Entries extends Record<string, TgpuLayoutEntry | null>>(bindGroupLayout: TgpuBindGroupLayout<Entries>, bindGroup: TgpuBindGroup<Entries> | GPUBindGroup): void;
|
|
46
|
+
/**
|
|
47
|
+
* Provides a value for the given immediate variable, used by subsequent dispatches.
|
|
48
|
+
* The value is captured (copied) at call time; mutating it afterwards has no
|
|
49
|
+
* effect until it is set again. Takes precedence over values held by the
|
|
50
|
+
* pipeline (`pipeline.with(immediate, value)`) and persists across pipeline
|
|
51
|
+
* switches until set again, like any other pass-level state.
|
|
52
|
+
*
|
|
53
|
+
* Passing an `ArrayBuffer` or typed array skips serialization entirely; the bytes
|
|
54
|
+
* are copied verbatim and the caller guarantees they match the schema's layout.
|
|
55
|
+
*/
|
|
56
|
+
setImmediates<T extends AnyWgslData>(immediate: TgpuImmediateVar<T>, value: InferInput<T> | ArrayBuffer | ArrayBufferView): void;
|
|
44
57
|
dispatchWorkgroups(x: number, y?: number, z?: number): void;
|
|
45
58
|
/**
|
|
46
59
|
* Dispatches compute workgroups using parameters read from a buffer.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { $internal } from "../../shared/symbols.js";
|
|
2
2
|
import { isGPUBuffer } from "../../types.js";
|
|
3
3
|
import { DISPATCH_INDIRECT_SIZE, resolveIndirectOffset } from "../pipeline/pipelineUtils.js";
|
|
4
|
-
import { ComputeDrawState, emitComputeDispatch, recordBindGroup,
|
|
4
|
+
import { ComputeDrawState, emitComputeDispatch, recordBindGroup, selectPipeline, } from "../pipeline/drawState.js";
|
|
5
5
|
import { unwrapTimestampWrites } from "./attachments.js";
|
|
6
6
|
// --------------
|
|
7
7
|
// Implementation
|
|
@@ -44,11 +44,14 @@ class TgpuComputePassImpl {
|
|
|
44
44
|
emitComputeDispatch(this.#root, internals, pipeline, emit);
|
|
45
45
|
}
|
|
46
46
|
setPipeline(pipeline) {
|
|
47
|
-
|
|
47
|
+
selectPipeline(this[$internal].state, pipeline);
|
|
48
48
|
}
|
|
49
49
|
setBindGroup(first, bindGroup) {
|
|
50
50
|
recordBindGroup(this[$internal].state, first, bindGroup);
|
|
51
51
|
}
|
|
52
|
+
setImmediates(immediate, value) {
|
|
53
|
+
this[$internal].state.immediates.set(immediate, value);
|
|
54
|
+
}
|
|
52
55
|
dispatchWorkgroups(x, y, z) {
|
|
53
56
|
this.#emit((rawPass) => rawPass.dispatchWorkgroups(x, y, z));
|
|
54
57
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { Disarray } from '../../data/dataTypes.ts';
|
|
2
2
|
import type { PrimitiveOffsetInfo } from '../../data/offsetUtils.ts';
|
|
3
|
-
import type { BaseData, WgslArray } from '../../data/wgslTypes.ts';
|
|
3
|
+
import type { AnyWgslData, BaseData, WgslArray } from '../../data/wgslTypes.ts';
|
|
4
|
+
import type { InferInput } from '../../shared/repr.ts';
|
|
4
5
|
import { $internal } from '../../shared/symbols.ts';
|
|
5
6
|
import type { TgpuBindGroup, TgpuBindGroupLayout, TgpuLayoutEntry } from '../../tgpuBindGroupLayout.ts';
|
|
6
7
|
import type { IndexFlag, IndirectFlag, TgpuBuffer, VertexFlag } from '../buffer/buffer.ts';
|
|
8
|
+
import type { TgpuImmediateVar } from '../immediate/immediateVar.ts';
|
|
7
9
|
import { RenderDrawState } from '../pipeline/drawState.ts';
|
|
8
10
|
import type { TgpuRenderPipeline } from '../pipeline/renderPipeline.ts';
|
|
9
11
|
import { type TgpuQuerySet } from '../querySet/querySet.ts';
|
|
@@ -58,6 +60,17 @@ export interface TgpuRenderCommands {
|
|
|
58
60
|
setVertexBuffer<TData extends WgslArray | Disarray>(vertexLayout: TgpuVertexLayout<TData>, buffer: (TgpuBuffer<TData> & VertexFlag) | GPUBuffer, offset?: number, size?: number): void;
|
|
59
61
|
/** Sets the current index buffer */
|
|
60
62
|
setIndexBuffer<TData extends WgslArray | Disarray>(buffer: (TgpuBuffer<TData> & IndexFlag) | GPUBuffer, indexFormat: GPUIndexFormat, offset?: number, size?: number): void;
|
|
63
|
+
/**
|
|
64
|
+
* Provides a value for the given immediate variable, used by subsequent draw calls.
|
|
65
|
+
* The value is captured (copied) at call time; mutating it afterwards has no
|
|
66
|
+
* effect until it is set again. Takes precedence over values held by the
|
|
67
|
+
* pipeline (`pipeline.with(immediate, value)`) and persists across pipeline
|
|
68
|
+
* switches until set again, like any other pass-level state.
|
|
69
|
+
*
|
|
70
|
+
* Passing an `ArrayBuffer` or typed array skips serialization entirely; the bytes
|
|
71
|
+
* are copied verbatim and the caller guarantees they match the schema's layout.
|
|
72
|
+
*/
|
|
73
|
+
setImmediates<T extends AnyWgslData>(immediate: TgpuImmediateVar<T>, value: InferInput<T> | ArrayBuffer | ArrayBufferView): void;
|
|
61
74
|
draw(vertexCount: number, instanceCount?: number, firstVertex?: number, firstInstance?: number): void;
|
|
62
75
|
drawIndexed(indexCount: number, instanceCount?: number, firstIndex?: number, baseVertex?: number, firstInstance?: number): void;
|
|
63
76
|
/**
|
|
@@ -108,9 +121,10 @@ export interface TgpuRenderPass extends TgpuRenderCommands {
|
|
|
108
121
|
endOcclusionQuery(): void;
|
|
109
122
|
/**
|
|
110
123
|
* Executes previously recorded {@link GPURenderBundle}s as part of this pass.
|
|
111
|
-
* As per the WebGPU spec, this resets the raw pass's pipeline, bind group
|
|
112
|
-
*
|
|
113
|
-
* re-applied on
|
|
124
|
+
* As per the WebGPU spec, this resets the raw pass's pipeline, bind group,
|
|
125
|
+
* vertex/index buffer and immediate data state. The state tracked by this
|
|
126
|
+
* typed pass (including values set via `setImmediates`) is re-applied on
|
|
127
|
+
* the next draw.
|
|
114
128
|
*/
|
|
115
129
|
executeBundles(bundles: Iterable<GPURenderBundle>): void;
|
|
116
130
|
/** Completes the recording of this render pass */
|
|
@@ -2,7 +2,7 @@ import { $internal } from "../../shared/symbols.js";
|
|
|
2
2
|
import { isGPUBuffer } from "../../types.js";
|
|
3
3
|
import { DRAW_INDEXED_INDIRECT_SIZE, DRAW_INDIRECT_SIZE, resolveIndirectOffset, } from "../pipeline/pipelineUtils.js";
|
|
4
4
|
import { isTexture, isTextureView } from "../texture/texture.js";
|
|
5
|
-
import { emitRenderDraw, recordBindGroup, RenderDrawState,
|
|
5
|
+
import { emitRenderDraw, recordBindGroup, RenderDrawState, selectPipeline, } from "../pipeline/drawState.js";
|
|
6
6
|
import { isQuerySet } from "../querySet/querySet.js";
|
|
7
7
|
import { unwrapAttachmentView, unwrapTimestampWrites, } from "./attachments.js";
|
|
8
8
|
// --------------
|
|
@@ -125,7 +125,7 @@ class TgpuRenderCommandsImpl {
|
|
|
125
125
|
emitRenderDraw(this.#root, internals, pipeline, usesIndexBuffer, emit);
|
|
126
126
|
}
|
|
127
127
|
setPipeline(pipeline) {
|
|
128
|
-
|
|
128
|
+
selectPipeline(this[$internal].state, pipeline);
|
|
129
129
|
}
|
|
130
130
|
setBindGroup(first, bindGroup) {
|
|
131
131
|
recordBindGroup(this[$internal].state, first, bindGroup);
|
|
@@ -140,6 +140,9 @@ class TgpuRenderCommandsImpl {
|
|
|
140
140
|
state.indexBuffer = { buffer, indexFormat, offsetBytes: offset, sizeBytes: size };
|
|
141
141
|
state.version++;
|
|
142
142
|
}
|
|
143
|
+
setImmediates(immediate, value) {
|
|
144
|
+
this[$internal].state.immediates.set(immediate, value);
|
|
145
|
+
}
|
|
143
146
|
draw(vertexCount, instanceCount, firstVertex, firstInstance) {
|
|
144
147
|
this.#emit(false, (rawPass) => rawPass.draw(vertexCount, instanceCount, firstVertex, firstInstance));
|
|
145
148
|
}
|
|
@@ -189,6 +192,7 @@ class TgpuRenderPassImpl extends TgpuRenderCommandsImpl {
|
|
|
189
192
|
const internals = this[$internal];
|
|
190
193
|
internals.rawPass.executeBundles(bundles);
|
|
191
194
|
internals.appliedVersion = undefined;
|
|
195
|
+
internals.state.immediates.invalidate();
|
|
192
196
|
}
|
|
193
197
|
end() {
|
|
194
198
|
this[$internal].rawPass.end();
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { type ResolvedSnippet } from '../../data/snippet.ts';
|
|
2
|
+
import { $internal, $resolve } from '../../shared/symbols.ts';
|
|
3
|
+
import type { ResolutionCtx, SelfResolvable } from '../../types.ts';
|
|
1
4
|
/**
|
|
2
5
|
* Extra declaration that shall be included in final WGSL code,
|
|
3
6
|
* when resolving objects that use it.
|
|
@@ -13,3 +16,11 @@ export interface TgpuDeclare {
|
|
|
13
16
|
* It was developed to ensure full compatibility of TypeGPU programs with current and future versions of WGSL.
|
|
14
17
|
*/
|
|
15
18
|
export declare function declare(declaration: string): TgpuDeclare;
|
|
19
|
+
export declare class TgpuDeclareImpl implements TgpuDeclare, SelfResolvable {
|
|
20
|
+
#private;
|
|
21
|
+
readonly [$internal] = true;
|
|
22
|
+
constructor(declaration: string);
|
|
23
|
+
$uses(dependencyMap: Record<string, unknown>): this;
|
|
24
|
+
[$resolve](ctx: ResolutionCtx): ResolvedSnippet;
|
|
25
|
+
toString(): string;
|
|
26
|
+
}
|
package/core/function/autoIO.js
CHANGED
|
@@ -39,7 +39,8 @@ export class AutoFragmentFn {
|
|
|
39
39
|
setName(impl, 'fragmentFn');
|
|
40
40
|
}
|
|
41
41
|
this.#core = createFnCore(impl, 'fragment');
|
|
42
|
-
this.autoIn = new AutoStruct({ ...builtinFragmentIn, ...varyings }, undefined, locations
|
|
42
|
+
this.autoIn = new AutoStruct({ ...builtinFragmentIn, ...varyings }, undefined, locations,
|
|
43
|
+
/* autoInterpolateIntegers */ true);
|
|
43
44
|
setName(this.autoIn, 'FragmentIn');
|
|
44
45
|
this.autoOut = new AutoStruct(builtinFragmentOut, vec4f);
|
|
45
46
|
setName(this.autoOut, 'FragmentOut');
|
|
@@ -68,7 +69,8 @@ export class AutoVertexFn {
|
|
|
68
69
|
this.#core = createFnCore(impl, 'vertex');
|
|
69
70
|
this.autoIn = new AutoStruct({ ...builtinVertexIn, ...attribs }, undefined, locations);
|
|
70
71
|
setName(this.autoIn, 'VertexIn');
|
|
71
|
-
this.autoOut = new AutoStruct(builtinVertexOut, undefined
|
|
72
|
+
this.autoOut = new AutoStruct(builtinVertexOut, undefined, undefined,
|
|
73
|
+
/* autoInterpolateIntegers */ true);
|
|
72
74
|
setName(this.autoOut, 'VertexOut');
|
|
73
75
|
}
|
|
74
76
|
toString() {
|
|
@@ -7,7 +7,12 @@ export type WithLocations<T extends Record<string, BaseData>> = {
|
|
|
7
7
|
export type IOLayoutToSchema<T> = T extends BaseData ? HasCustomLocation<T> extends true ? T : Decorate<T, Location<0>> : T extends Record<string, BaseData> ? WgslStruct<WithLocations<T>> : T extends {
|
|
8
8
|
type: 'void';
|
|
9
9
|
} ? void : never;
|
|
10
|
-
export declare function withLocations<T extends BaseData>(members: Record<string, T> | undefined, locations?: Record<string, number
|
|
10
|
+
export declare function withLocations<T extends BaseData>(members: Record<string, T> | undefined, locations?: Record<string, number>, autoInterpolateIntegers?: boolean): Record<string, BaseData>;
|
|
11
11
|
export declare function separateBuiltins(schema: Record<string, BaseData>, locations?: Record<string, number>): SeparatedEntryArgs;
|
|
12
12
|
export declare function separateAllAsPositional(schema: Record<string, BaseData>): SeparatedEntryArgs;
|
|
13
|
-
export declare function createIoSchema<T extends BaseData | Record<string, BaseData>>(layout: T, locations?: Record<string, number
|
|
13
|
+
export declare function createIoSchema<T extends BaseData | Record<string, BaseData>>(layout: T, locations?: Record<string, number>, autoInterpolateIntegers?: boolean): IOLayoutToSchema<T>;
|
|
14
|
+
/**
|
|
15
|
+
* WGSL requires integer inter-stage values to be flat interpolated. Interpolation is only
|
|
16
|
+
* inferred for shellless entry functions, so shells have to specify it explicitly.
|
|
17
|
+
*/
|
|
18
|
+
export declare function assertIntegerVaryingsInterpolated(layout: BaseData | Record<string, BaseData> | undefined, location: string): void;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { location, } from "../../data/attributes.js";
|
|
1
|
+
import { interpolate, location, } from "../../data/attributes.js";
|
|
2
2
|
import { isBuiltin } from "../../data/attributes.js";
|
|
3
3
|
import { getCustomLocation, isData } from "../../data/dataTypes.js";
|
|
4
4
|
import { INTERNAL_createStruct } from "../../data/struct.js";
|
|
5
|
-
import { isVoid } from "../../data/wgslTypes.js";
|
|
6
|
-
export function withLocations(members, locations = {}) {
|
|
5
|
+
import { isDecorated, isInteger, isIntegerVec, isInterpolateAttrib, isVoid, } from "../../data/wgslTypes.js";
|
|
6
|
+
export function withLocations(members, locations = {}, autoInterpolateIntegers = false) {
|
|
7
7
|
let nextLocation = 0;
|
|
8
8
|
const usedCustomLocations = new Set();
|
|
9
9
|
return Object.fromEntries(Object.entries(members ?? {})
|
|
@@ -15,7 +15,10 @@ export function withLocations(members, locations = {}) {
|
|
|
15
15
|
}
|
|
16
16
|
usedCustomLocations.add(customLocation);
|
|
17
17
|
}
|
|
18
|
-
return [
|
|
18
|
+
return [
|
|
19
|
+
key,
|
|
20
|
+
autoInterpolateIntegers ? withFlatInterpolationForInteger(member) : member,
|
|
21
|
+
];
|
|
19
22
|
})
|
|
20
23
|
.map(([key, member]) => {
|
|
21
24
|
if (isBuiltin(member)) {
|
|
@@ -57,15 +60,38 @@ export function separateAllAsPositional(schema) {
|
|
|
57
60
|
const positionalArgs = Object.entries(withLocs).map(([key, type]) => ({ schemaKey: key, type }));
|
|
58
61
|
return { dataSchema: undefined, positionalArgs };
|
|
59
62
|
}
|
|
60
|
-
export function createIoSchema(layout, locations = {}) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
63
|
+
export function createIoSchema(layout, locations = {}, autoInterpolateIntegers = false) {
|
|
64
|
+
if (isData(layout)) {
|
|
65
|
+
if (isVoid(layout) || isBuiltin(layout)) {
|
|
66
|
+
return layout;
|
|
67
|
+
}
|
|
68
|
+
return (getCustomLocation(layout) !== undefined ? layout : location(0, layout));
|
|
69
|
+
}
|
|
70
|
+
return INTERNAL_createStruct(withLocations(layout, locations, autoInterpolateIntegers),
|
|
71
|
+
/* isAbstruct */ false);
|
|
72
|
+
}
|
|
73
|
+
function needsFlatInterpolation(data) {
|
|
74
|
+
if (isBuiltin(data) || (isDecorated(data) && data.attribs.some(isInterpolateAttrib))) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
const inner = isDecorated(data) ? data.inner : data;
|
|
78
|
+
return isInteger(inner) || isIntegerVec(inner);
|
|
79
|
+
}
|
|
80
|
+
function withFlatInterpolationForInteger(data) {
|
|
81
|
+
return needsFlatInterpolation(data) ? interpolate('flat', data) : data;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* WGSL requires integer inter-stage values to be flat interpolated. Interpolation is only
|
|
85
|
+
* inferred for shellless entry functions, so shells have to specify it explicitly.
|
|
86
|
+
*/
|
|
87
|
+
export function assertIntegerVaryingsInterpolated(layout, location) {
|
|
88
|
+
if (layout === undefined || isData(layout)) {
|
|
89
|
+
// A single value is either a builtin or a fragment output, neither are varyings
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
for (const [key, member] of Object.entries(layout)) {
|
|
93
|
+
if (needsFlatInterpolation(member)) {
|
|
94
|
+
throw new Error(`Integer value "${key}" in ${location} requires flat interpolation. Wrap its schema in d.interpolate('flat', ...) or d.interpolate('flat, either', ...).`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
71
97
|
}
|
|
@@ -13,7 +13,7 @@ export type VertexOutToVarying<T> = OmitBuiltins<{
|
|
|
13
13
|
[K in keyof T]: InstanceToSchema<T[K]>;
|
|
14
14
|
}>;
|
|
15
15
|
type FragmentColorValue = Vec4f | Vec4i | Vec4u;
|
|
16
|
-
export type FragmentOutConstrained = IOLayout<FragmentColorValue | Decorated<FragmentColorValue,
|
|
16
|
+
export type FragmentOutConstrained = IOLayout<FragmentColorValue | Decorated<FragmentColorValue, Location[]> | AnyFragmentOutputBuiltin>;
|
|
17
17
|
/**
|
|
18
18
|
* Describes a fragment entry function signature (its arguments, return type and targets)
|
|
19
19
|
*/
|
|
@@ -3,7 +3,7 @@ import { $getNameForward, $internal, $resolve } from "../../shared/symbols.js";
|
|
|
3
3
|
import { addReturnTypeToExternals } from "../resolve/externals.js";
|
|
4
4
|
import { shaderStageSlot } from "../slot/internalSlots.js";
|
|
5
5
|
import { createFnCore } from "./fnCore.js";
|
|
6
|
-
import { createIoSchema, separateBuiltins } from "./ioSchema.js";
|
|
6
|
+
import { assertIntegerVaryingsInterpolated, createIoSchema, separateBuiltins, } from "./ioSchema.js";
|
|
7
7
|
import { stripTemplate } from "./templateUtils.js";
|
|
8
8
|
/**
|
|
9
9
|
* Creates a shell of a typed entry function for the fragment shader stage. Any function
|
|
@@ -55,6 +55,7 @@ function createFragmentFn(shell, implementation) {
|
|
|
55
55
|
return this;
|
|
56
56
|
},
|
|
57
57
|
[$resolve](ctx) {
|
|
58
|
+
assertIntegerVaryingsInterpolated(shell.in, `fragmentFn (${getName(this) ?? '<unnamed>'}) input`);
|
|
58
59
|
const entryInput = separateBuiltins(shell.in ?? {}, ctx.varyingLocations ?? {});
|
|
59
60
|
if (entryInput.dataSchema && isNamable(entryInput.dataSchema)) {
|
|
60
61
|
entryInput.dataSchema.$name(`${getName(this) ?? ''}_Input`);
|
|
@@ -2,7 +2,7 @@ import { getName, setName } from "../../shared/meta.js";
|
|
|
2
2
|
import { $getNameForward, $internal, $resolve } from "../../shared/symbols.js";
|
|
3
3
|
import { shaderStageSlot } from "../slot/internalSlots.js";
|
|
4
4
|
import { createFnCore } from "./fnCore.js";
|
|
5
|
-
import { createIoSchema, separateAllAsPositional } from "./ioSchema.js";
|
|
5
|
+
import { assertIntegerVaryingsInterpolated, createIoSchema, separateAllAsPositional, } from "./ioSchema.js";
|
|
6
6
|
import { stripTemplate } from "./templateUtils.js";
|
|
7
7
|
/**
|
|
8
8
|
* Creates a shell of a typed entry function for the vertex shader stage. Any function
|
|
@@ -50,6 +50,7 @@ function createVertexFn(shell, implementation) {
|
|
|
50
50
|
return this;
|
|
51
51
|
},
|
|
52
52
|
[$resolve](ctx) {
|
|
53
|
+
assertIntegerVaryingsInterpolated(shell.out, `vertexFn (${getName(this) ?? '<unnamed>'}) output`);
|
|
53
54
|
const outputWithLocation = createIoSchema(shell.out, ctx.varyingLocations).$name(`${getName(this) ?? ''}_Output`);
|
|
54
55
|
if (typeof implementation === 'string') {
|
|
55
56
|
core.setExternals('out', { Out: outputWithLocation });
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { type BaseData, type MatData, type ScalarData, type VecData, type WgslStruct } from '../../data/wgslTypes.ts';
|
|
2
|
+
import type { TgpuNamable } from '../../shared/meta.ts';
|
|
3
|
+
import type { InferGPU, InferInput } from '../../shared/repr.ts';
|
|
4
|
+
import type { TgpuSoul } from '../../shared/soul.ts';
|
|
5
|
+
import { $gpuValueOf, $internal, $soul } from '../../shared/symbols.ts';
|
|
6
|
+
export type ImmediateData = ScalarData | VecData | MatData | WgslStruct;
|
|
7
|
+
export interface TgpuImmediateVarSoul<TDataType extends BaseData = BaseData> extends TgpuSoul<'immediate-var'> {
|
|
8
|
+
readonly dataType: TDataType;
|
|
9
|
+
readonly defaultValue: InferInput<TDataType> | undefined;
|
|
10
|
+
}
|
|
11
|
+
export interface TgpuImmediateVar<TDataType extends BaseData = BaseData> extends TgpuNamable {
|
|
12
|
+
readonly [$internal]: true;
|
|
13
|
+
readonly [$soul]: TgpuImmediateVarSoul<TDataType>;
|
|
14
|
+
readonly resourceType: 'immediate-var';
|
|
15
|
+
readonly dataType: TDataType;
|
|
16
|
+
readonly defaultValue: InferInput<TDataType> | undefined;
|
|
17
|
+
readonly [$gpuValueOf]: InferGPU<TDataType>;
|
|
18
|
+
readonly $: InferGPU<TDataType>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Defines a variable in the 'immediate' address space, set from the CPU on a per-draw
|
|
22
|
+
* (or per-dispatch) basis without the overhead of a buffer.
|
|
23
|
+
*
|
|
24
|
+
* Only one immediate variable can be used in a single shader, and its size is limited
|
|
25
|
+
* by the device's `maxImmediateSize` limit. Requires the `immediate_address_space`
|
|
26
|
+
* WGSL language extension, check `root.enabledWgslLanguageFeatures` for support.
|
|
27
|
+
*
|
|
28
|
+
* @param dataType The schema of the held data's type. Cannot contain arrays, atomics or booleans.
|
|
29
|
+
* @param defaultValue The value used when no override is provided via `pipeline.with(immediate, value)`
|
|
30
|
+
* or `pass.setImmediates`. Captured (serialized) at creation time.
|
|
31
|
+
*/
|
|
32
|
+
export declare function immediateVar<TDataType extends ImmediateData>(dataType: TDataType, defaultValue?: InferInput<TDataType>): TgpuImmediateVar<TDataType>;
|
|
33
|
+
export declare function isImmediateVar(value: unknown): value is TgpuImmediateVar;
|
|
34
|
+
/**
|
|
35
|
+
* Validates that the given immediate variable can be used with the given root.
|
|
36
|
+
* @returns The size of the immediate data in bytes, to be passed as
|
|
37
|
+
* `immediateSize` to `device.createPipelineLayout`.
|
|
38
|
+
*/
|
|
39
|
+
export declare function validateImmediateUsage(immediate: TgpuImmediateVar, root: {
|
|
40
|
+
readonly enabledWgslLanguageFeatures: ReadonlySet<string>;
|
|
41
|
+
}): number;
|
|
42
|
+
/** Captured bytes of an immediate value, immutable once created */
|
|
43
|
+
export type ImmediateSnapshot = Uint8Array<ArrayBuffer>;
|
|
44
|
+
export declare function createImmediateSnapshot(immediate: TgpuImmediateVar, value: unknown): ImmediateSnapshot;
|
|
45
|
+
/** Captures pass overrides and tracks the last snapshot written to its encoder. */
|
|
46
|
+
export declare class ImmediatePassState {
|
|
47
|
+
#private;
|
|
48
|
+
set(immediate: TgpuImmediateVar, value: unknown): void;
|
|
49
|
+
invalidate(): void;
|
|
50
|
+
/** Pass overrides take precedence over pipeline values and the variable's default. */
|
|
51
|
+
write(pass: GPURenderPassEncoder | GPUComputePassEncoder | GPURenderBundleEncoder, immediate: TgpuImmediateVar, pipelineSnapshots: ReadonlyMap<TgpuImmediateVar, ImmediateSnapshot> | undefined, deduplicate: boolean): void;
|
|
52
|
+
}
|