typegpu 0.11.9 → 0.12.1
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/bin.mjs +28 -6
- package/builtin.d.ts +51 -53
- package/builtin.js +30 -34
- package/common/fullScreenTriangle.d.ts +2 -10
- package/common/fullScreenTriangle.js +20 -28
- package/common/index.d.ts +2 -9
- package/common/index.js +3 -12
- package/common/writeSoA.d.ts +11 -12
- package/common/writeSoA.js +88 -76
- package/core/buffer/buffer.d.ts +79 -62
- package/core/buffer/buffer.js +283 -205
- package/core/buffer/bufferBinding.d.ts +71 -0
- package/core/buffer/bufferBinding.js +154 -0
- package/core/buffer/bufferUsage.d.ts +14 -45
- package/core/buffer/bufferUsage.js +1 -171
- package/core/buffer/laidOutBuffer.d.ts +25 -0
- package/core/buffer/laidOutBuffer.js +55 -0
- package/core/commandEncoder/attachments.d.ts +125 -0
- package/core/commandEncoder/attachments.js +29 -0
- package/core/commandEncoder/commandEncoder.d.ts +53 -0
- package/core/commandEncoder/commandEncoder.js +56 -0
- package/core/commandEncoder/computePass.d.ts +58 -0
- package/core/commandEncoder/computePass.js +63 -0
- package/core/commandEncoder/renderPass.d.ts +121 -0
- package/core/commandEncoder/renderPass.js +196 -0
- package/core/constant/tgpuConstant.d.ts +26 -26
- package/core/constant/tgpuConstant.js +76 -65
- package/core/declare/tgpuDeclare.d.ts +3 -6
- package/core/declare/tgpuDeclare.js +36 -36
- package/core/function/autoIO.d.ts +61 -33
- package/core/function/autoIO.js +68 -73
- package/core/function/comptime.d.ts +11 -13
- package/core/function/comptime.js +60 -52
- package/core/function/createCallableSchema.d.ts +16 -0
- package/core/function/createCallableSchema.js +50 -40
- package/core/function/dualImpl.d.ts +44 -0
- package/core/function/dualImpl.js +71 -50
- package/core/function/entryInputRouter.d.ts +26 -0
- package/core/function/entryInputRouter.js +31 -33
- package/core/function/extractArgs.d.ts +38 -0
- package/core/function/extractArgs.js +202 -200
- package/core/function/fnCore.d.ts +44 -5
- package/core/function/fnCore.js +148 -93
- package/core/function/fnTypes.d.ts +31 -29
- package/core/function/fnTypes.js +1 -0
- package/core/function/ioSchema.d.ts +12 -10
- package/core/function/ioSchema.js +65 -47
- package/core/function/shelllessImpl.d.ts +9 -12
- package/core/function/shelllessImpl.js +17 -22
- package/core/function/templateUtils.d.ts +2 -0
- package/core/function/templateUtils.js +9 -8
- package/core/function/tgpuComputeFn.d.ts +26 -28
- package/core/function/tgpuComputeFn.js +47 -48
- package/core/function/tgpuFn.d.ts +34 -37
- package/core/function/tgpuFn.js +179 -153
- package/core/function/tgpuFragmentFn.d.ts +52 -53
- package/core/function/tgpuFragmentFn.js +63 -56
- package/core/function/tgpuVertexFn.d.ts +36 -39
- package/core/function/tgpuVertexFn.js +56 -53
- package/core/pipeline/computePipeline.d.ts +141 -53
- package/core/pipeline/computePipeline.js +291 -225
- package/core/pipeline/connectAttachmentToShader.d.ts +4 -0
- package/core/pipeline/connectAttachmentToShader.js +25 -22
- package/core/pipeline/connectTargetsToShader.d.ts +3 -0
- package/core/pipeline/connectTargetsToShader.js +29 -27
- package/core/pipeline/drawState.d.ts +52 -0
- package/core/pipeline/drawState.js +225 -0
- package/core/pipeline/performanceTracker.d.ts +14 -0
- package/core/pipeline/performanceTracker.js +34 -0
- package/core/pipeline/pipelineUtils.d.ts +18 -0
- package/core/pipeline/pipelineUtils.js +54 -25
- package/core/pipeline/priors.d.ts +1 -0
- package/core/pipeline/priors.js +12 -0
- package/core/pipeline/renderPipeline.d.ts +246 -261
- package/core/pipeline/renderPipeline.js +487 -480
- package/core/pipeline/timeable.d.ts +28 -18
- package/core/pipeline/timeable.js +90 -52
- package/core/pipeline/typeGuards.d.ts +17 -0
- package/core/pipeline/typeGuards.js +52 -22
- package/core/pipeline/webgpuLimitations.d.ts +10 -0
- package/core/pipeline/webgpuLimitations.js +81 -0
- package/core/querySet/querySet.d.ts +26 -21
- package/core/querySet/querySet.js +127 -103
- package/core/rawCodeSnippet/tgpuRawCodeSnippet.d.ts +13 -18
- package/core/rawCodeSnippet/tgpuRawCodeSnippet.js +89 -90
- package/core/resolve/externals.d.ts +25 -8
- package/core/resolve/externals.js +78 -54
- package/core/resolve/namespace.d.ts +22 -25
- package/core/resolve/namespace.js +16 -21
- package/core/resolve/resolvableString.d.ts +7 -0
- package/core/resolve/resolvableString.js +13 -0
- package/core/resolve/resolveData.d.ts +10 -0
- package/core/resolve/resolveData.js +162 -121
- package/core/resolve/stitch.d.ts +8 -0
- package/core/resolve/stitch.js +23 -21
- package/core/resolve/tgpuResolve.d.ts +55 -53
- package/core/resolve/tgpuResolve.js +106 -53
- package/core/root/configurableImpl.d.ts +10 -0
- package/core/root/configurableImpl.js +17 -19
- package/core/root/init.d.ts +76 -38
- package/core/root/init.js +346 -455
- package/core/root/rootTypes.d.ts +461 -636
- package/core/root/rootTypes.js +1 -0
- package/core/sampler/sampler.d.ts +50 -31
- package/core/sampler/sampler.js +120 -113
- package/core/simulate/tgpuSimulate.d.ts +9 -12
- package/core/simulate/tgpuSimulate.js +68 -71
- package/core/slot/accessor.d.ts +36 -13
- package/core/slot/accessor.js +138 -91
- package/core/slot/internalSlots.d.ts +2 -0
- package/core/slot/internalSlots.js +1 -6
- package/core/slot/lazy.d.ts +2 -6
- package/core/slot/lazy.js +71 -39
- package/core/slot/slot.d.ts +2 -6
- package/core/slot/slot.js +45 -38
- package/core/slot/slotTypes.d.ts +78 -80
- package/core/slot/slotTypes.js +11 -16
- package/core/texture/externalTexture.d.ts +20 -11
- package/core/texture/externalTexture.js +46 -46
- package/core/texture/texture.d.ts +152 -97
- package/core/texture/texture.js +407 -314
- package/core/texture/textureFormats.d.ts +42 -23
- package/core/texture/textureFormats.js +104 -75
- package/core/texture/textureProps.d.ts +7 -10
- package/core/texture/textureProps.js +1 -0
- package/core/texture/textureUtils.d.ts +8 -0
- package/core/texture/textureUtils.js +185 -179
- package/core/texture/usageExtension.d.ts +21 -18
- package/core/texture/usageExtension.js +13 -17
- package/core/unroll/tgpuUnroll.d.ts +20 -19
- package/core/unroll/tgpuUnroll.js +82 -91
- package/core/valueProxyUtils.d.ts +3 -0
- package/core/valueProxyUtils.js +52 -41
- package/core/variable/tgpuVariable.d.ts +26 -27
- package/core/variable/tgpuVariable.js +93 -96
- package/core/vertexLayout/connectAttributesToShader.d.ts +9 -0
- package/core/vertexLayout/connectAttributesToShader.js +61 -56
- package/core/vertexLayout/vertexAttribute.d.ts +21 -17
- package/core/vertexLayout/vertexAttribute.js +1 -0
- package/core/vertexLayout/vertexLayout.d.ts +24 -18
- package/core/vertexLayout/vertexLayout.js +130 -99
- package/core/whitespaces.d.ts +2 -0
- package/core/whitespaces.js +16 -0
- package/data/alignIO.d.ts +7 -0
- package/data/alignIO.js +13 -13
- package/data/alignmentOf.d.ts +5 -8
- package/data/alignmentOf.js +90 -75
- package/data/array.d.ts +17 -9
- package/data/array.js +57 -40
- package/data/atomic.d.ts +2 -7
- package/data/atomic.js +26 -23
- package/data/attributes.d.ts +19 -21
- package/data/attributes.js +192 -132
- package/data/autoStruct.d.ts +36 -3
- package/data/autoStruct.js +84 -81
- package/data/compiledIO.d.ts +5 -0
- package/data/compiledIO.js +231 -215
- package/data/dataIO.d.ts +13 -11
- package/data/dataIO.js +643 -589
- package/data/dataTypes.d.ts +83 -65
- package/data/dataTypes.js +66 -68
- package/data/deepEqual.d.ts +2 -7
- package/data/deepEqual.js +80 -55
- package/data/disarray.d.ts +6 -10
- package/data/disarray.js +52 -46
- package/data/float16Conversion.d.ts +4 -0
- package/data/float16Conversion.js +7 -0
- package/data/generalizeFn.d.ts +25 -0
- package/data/generalizeFn.js +89 -0
- package/data/getLongestContiguousPrefix.d.ts +4 -8
- package/data/getLongestContiguousPrefix.js +6 -11
- package/data/index.d.ts +30 -31
- package/data/index.js +39 -172
- package/data/instanceToSchema.d.ts +24 -27
- package/data/instanceToSchema.js +1 -0
- package/data/isContiguous.d.ts +4 -8
- package/data/isContiguous.js +6 -11
- package/data/matrix.d.ts +21 -21
- package/data/matrix.js +513 -505
- package/data/numberOps.d.ts +5 -0
- package/data/numberOps.js +21 -21
- package/data/numeric.d.ts +21 -12
- package/data/numeric.js +287 -197
- package/data/offsetUtils.d.ts +9 -13
- package/data/offsetUtils.js +204 -144
- package/data/offsets.d.ts +8 -0
- package/data/offsets.js +33 -33
- package/data/partialIO.d.ts +13 -8
- package/data/partialIO.js +124 -113
- package/data/ptr.d.ts +12 -12
- package/data/ptr.js +42 -44
- package/data/ref.d.ts +40 -27
- package/data/ref.js +125 -95
- package/data/sampler.d.ts +99 -101
- package/data/sampler.js +17 -21
- package/data/schemaCallWrapper.d.ts +19 -0
- package/data/schemaCallWrapper.js +31 -26
- package/data/schemaMemoryLayout.d.ts +8 -0
- package/data/schemaMemoryLayout.js +213 -185
- package/data/sizeOf.d.ts +4 -8
- package/data/sizeOf.js +6 -11
- package/data/snippet.d.ts +96 -20
- package/data/snippet.js +75 -86
- package/data/struct.d.ts +4 -7
- package/data/struct.js +51 -39
- package/data/texture.d.ts +253 -250
- package/data/texture.js +238 -200
- package/data/unstruct.d.ts +2 -7
- package/data/unstruct.js +43 -37
- package/data/vector.d.ts +33 -21
- package/data/vector.js +234 -221
- package/data/vectorImpl.d.ts +231 -0
- package/data/vectorImpl.js +563 -515
- package/data/vectorOps.d.ts +25 -0
- package/data/vectorOps.js +118 -669
- package/data/vertexFormatData.d.ts +181 -184
- package/data/vertexFormatData.js +104 -106
- package/data/wgslTypes.d.ts +665 -600
- package/data/wgslTypes.js +220 -198
- package/errors.d.ts +50 -24
- package/errors.js +146 -126
- package/execMode.d.ts +16 -0
- package/execMode.js +47 -40
- package/extension.d.ts +13 -8
- package/extension.js +10 -16
- package/getGPUValue.d.ts +1 -0
- package/getGPUValue.js +2 -7
- package/index.d.ts +28 -68
- package/index.js +8 -28
- package/indexNamedExports.d.ts +69 -42
- package/indexNamedExports.js +25 -0
- package/internal.d.ts +16 -0
- package/internal.js +12 -0
- package/mathUtils.d.ts +5 -0
- package/mathUtils.js +7 -11
- package/memo.d.ts +11 -0
- package/memo.js +20 -22
- package/minify.d.ts +5 -0
- package/minify.js +93 -0
- package/nameUtils.d.ts +29 -0
- package/nameUtils.js +427 -394
- package/package.json +5 -1
- package/resolutionCtx.d.ts +162 -22
- package/resolutionCtx.js +911 -629
- package/serial/registry.d.ts +15 -0
- package/serial/registry.js +106 -0
- package/serial/restore.d.ts +49 -0
- package/serial/restore.js +68 -0
- package/serial/schema.d.ts +58 -0
- package/serial/schema.js +209 -0
- package/serial/types.d.ts +5 -0
- package/serial/types.js +1 -0
- package/shared/env.d.ts +9 -0
- package/shared/env.js +9 -12
- package/shared/generators.d.ts +4 -0
- package/shared/generators.js +10 -12
- package/shared/meta.d.ts +29 -14
- package/shared/meta.js +71 -55
- package/shared/normalizeMetadata.d.ts +32 -27
- package/shared/normalizeMetadata.js +23 -36
- package/shared/repr.d.ts +73 -55
- package/shared/repr.js +1 -0
- package/shared/soul.d.ts +17 -0
- package/shared/soul.js +1 -0
- package/shared/stringify.d.ts +2 -0
- package/shared/stringify.js +29 -20
- package/shared/symbols.d.ts +26 -20
- package/shared/symbols.js +79 -79
- package/shared/tseynit.d.ts +2 -0
- package/shared/tseynit.js +160 -75
- package/shared/utilityTypes.d.ts +30 -14
- package/shared/utilityTypes.js +2 -6
- package/shared/vertexFormat.d.ts +41 -43
- package/shared/vertexFormat.js +59 -62
- package/std/array.d.ts +2 -7
- package/std/array.js +18 -23
- package/std/atomic.d.ts +14 -18
- package/std/atomic.js +96 -95
- package/std/bitcast.d.ts +193 -10
- package/std/bitcast.js +309 -39
- package/std/boolean.d.ts +19 -33
- package/std/boolean.js +296 -292
- package/std/copy.d.ts +2 -7
- package/std/copy.js +27 -24
- package/std/derivative.d.ts +11 -15
- package/std/derivative.js +56 -79
- package/std/discard.d.ts +1 -6
- package/std/discard.js +7 -14
- package/std/environment.d.ts +19 -14
- package/std/environment.js +71 -51
- package/std/extensions.d.ts +2 -8
- package/std/extensions.js +10 -11
- package/std/index.d.ts +20 -24
- package/std/index.js +32 -187
- package/std/matrix.d.ts +6 -12
- package/std/matrix.js +60 -69
- package/std/numeric.d.ts +150 -146
- package/std/numeric.js +771 -727
- package/std/operators.d.ts +19 -27
- package/std/operators.js +195 -194
- package/std/packing.d.ts +5 -11
- package/std/packing.js +67 -75
- package/std/range.d.ts +6 -11
- package/std/range.js +48 -36
- package/std/subgroup.d.ts +33 -37
- package/std/subgroup.js +180 -217
- package/std/texture.d.ts +70 -38
- package/std/texture.js +176 -172
- package/taskQueue.d.ts +6 -0
- package/taskQueue.js +30 -0
- package/tgpu.d.ts +16 -0
- package/tgpu.js +17 -44
- package/tgpuBindGroupLayout.d.ts +132 -152
- package/tgpuBindGroupLayout.js +346 -268
- package/tgpuLogger.d.ts +34 -0
- package/tgpuLogger.js +64 -0
- package/tgpuUnstable.d.ts +16 -22
- package/tgpuUnstable.js +13 -35
- package/tgsl/accessIndex.d.ts +2 -0
- package/tgsl/accessIndex.js +76 -33
- package/tgsl/accessProp.d.ts +2 -0
- package/tgsl/accessProp.js +142 -101
- package/tgsl/accessStructProp.d.ts +5 -0
- package/tgsl/accessStructProp.js +13 -15
- package/tgsl/consoleLog/deserializers.d.ts +13 -0
- package/tgsl/consoleLog/deserializers.js +119 -103
- package/tgsl/consoleLog/logGenerator.d.ts +21 -0
- package/tgsl/consoleLog/logGenerator.js +85 -80
- package/tgsl/consoleLog/serializers.d.ts +21 -0
- package/tgsl/consoleLog/serializers.js +119 -100
- package/tgsl/consoleLog/types.d.ts +40 -39
- package/tgsl/consoleLog/types.js +1 -0
- package/tgsl/conversion.d.ts +33 -0
- package/tgsl/conversion.js +271 -216
- package/tgsl/forOfUtils.d.ts +15 -0
- package/tgsl/forOfUtils.js +85 -70
- package/tgsl/generationHelpers.d.ts +22 -39
- package/tgsl/generationHelpers.js +85 -58
- package/tgsl/infixDispatch.d.ts +70 -0
- package/tgsl/infixDispatch.js +48 -46
- package/tgsl/jsPolyfills.d.ts +16 -19
- package/tgsl/jsPolyfills.js +44 -42
- package/tgsl/makeDereferenceable.d.ts +48 -0
- package/tgsl/makeDereferenceable.js +86 -0
- package/tgsl/makeResolvable.d.ts +22 -0
- package/tgsl/makeResolvable.js +33 -0
- package/tgsl/shaderGenerator.d.ts +77 -17
- package/tgsl/shaderGenerator.js +1 -0
- package/tgsl/shellless.d.ts +6 -9
- package/tgsl/shellless.js +73 -43
- package/tgsl/wgslGenerator.d.ts +66 -59
- package/tgsl/wgslGenerator.js +1345 -760
- package/types.d.ts +287 -222
- package/types.js +61 -44
- package/unwrapper.d.ts +31 -26
- package/unwrapper.js +1 -0
- package/wgslExtensions.d.ts +3 -5
- package/wgslExtensions.js +12 -16
- package/_virtual/rolldown_runtime.js +0 -13
- package/core/buffer/bufferShorthand.d.ts +0 -50
- package/core/buffer/bufferShorthand.js +0 -55
- package/core/pipeline/applyPipelineState.js +0 -37
- package/core/pipeline/limitsOverflow.js +0 -13
- package/package.js +0 -5
- package/tgsl/shaderGenerator_members.d.ts +0 -33
- package/tgsl/shaderGenerator_members.js +0 -12
package/core/texture/texture.js
CHANGED
|
@@ -1,322 +1,415 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getName, setName } from "../../shared/meta.js";
|
|
3
|
-
import { snip } from "../../data/snippet.js";
|
|
1
|
+
import { isWgslStorageTexture, textureDescriptorToSchema, } from "../../data/texture.js";
|
|
4
2
|
import { inCodegenMode } from "../../execMode.js";
|
|
3
|
+
import { snip } from "../../data/snippet.js";
|
|
4
|
+
import { getName, setName } from "../../shared/meta.js";
|
|
5
|
+
import { getTextureFormatInfo, } from "./textureFormats.js";
|
|
6
|
+
import { $gpuValueOf, $internal, $ownSnippet, $repr, $resolve, $soul, } from "../../shared/symbols.js";
|
|
5
7
|
import { valueProxyHandler } from "../valueProxyUtils.js";
|
|
6
|
-
import { isWgslStorageTexture, textureDescriptorToSchema } from "../../data/texture.js";
|
|
7
|
-
import { getTextureFormatInfo } from "./textureFormats.js";
|
|
8
8
|
import { generateTextureMipmaps, getImageSourceDimensions, resampleImage } from "./textureUtils.js";
|
|
9
|
-
|
|
10
|
-
//#region src/core/texture/texture.ts
|
|
9
|
+
import { logger } from "../../tgpuLogger.js";
|
|
11
10
|
function getDescriptorForProps(props) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
return {
|
|
12
|
+
dimension: (props.dimension ?? '2d'),
|
|
13
|
+
sampleType: getTextureFormatInfo(props.format).channelType,
|
|
14
|
+
multisampled: !((props.sampleCount ?? 1) === 1),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export function INTERNAL_createTexture(props, root, rawTexture) {
|
|
18
|
+
return new TgpuTextureImpl(props, root, rawTexture);
|
|
19
|
+
}
|
|
20
|
+
export function isTexture(value) {
|
|
21
|
+
return value?.resourceType === 'texture' && !!value[$internal];
|
|
22
|
+
}
|
|
23
|
+
export function isTextureView(value) {
|
|
24
|
+
return (value?.resourceType === 'texture-view' &&
|
|
25
|
+
!!value[$internal]);
|
|
26
|
+
}
|
|
27
|
+
// --------------
|
|
28
|
+
// Implementation
|
|
29
|
+
// --------------
|
|
30
|
+
class TgpuTextureImpl {
|
|
31
|
+
[$internal];
|
|
32
|
+
[$soul];
|
|
33
|
+
resourceType = 'texture';
|
|
34
|
+
usableAsSampled = false;
|
|
35
|
+
usableAsStorage = false;
|
|
36
|
+
usableAsRender = false;
|
|
37
|
+
#formatInfo;
|
|
38
|
+
#destroyed = false;
|
|
39
|
+
#ownTexture;
|
|
40
|
+
constructor(props, root, rawTexture) {
|
|
41
|
+
this.#ownTexture = rawTexture === undefined;
|
|
42
|
+
this[$soul] = {
|
|
43
|
+
type: 'texture',
|
|
44
|
+
device: root.device,
|
|
45
|
+
props,
|
|
46
|
+
flags: GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC,
|
|
47
|
+
flagsOverridden: false,
|
|
48
|
+
usages: [],
|
|
49
|
+
raw: rawTexture,
|
|
50
|
+
label: undefined,
|
|
51
|
+
};
|
|
52
|
+
this.#formatInfo = getTextureFormatInfo(props.format);
|
|
53
|
+
this[$internal] = {
|
|
54
|
+
root,
|
|
55
|
+
materialize: () => {
|
|
56
|
+
if (this.#destroyed) {
|
|
57
|
+
throw new Error('This texture has been destroyed');
|
|
58
|
+
}
|
|
59
|
+
const soul = this[$soul];
|
|
60
|
+
if (!soul.raw) {
|
|
61
|
+
const props = soul.props;
|
|
62
|
+
soul.raw = soul.device.createTexture({
|
|
63
|
+
label: getName(this) ?? '<unnamed>',
|
|
64
|
+
format: props.format,
|
|
65
|
+
// The WebGPU types accept only mutable arrays, which is too loosely typed
|
|
66
|
+
size: props.size,
|
|
67
|
+
usage: soul.flags,
|
|
68
|
+
dimension: props.dimension ?? '2d',
|
|
69
|
+
viewFormats: props.viewFormats ?? [],
|
|
70
|
+
mipLevelCount: props.mipLevelCount ?? 1,
|
|
71
|
+
sampleCount: props.sampleCount ?? 1,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
return soul.raw;
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
get props() {
|
|
79
|
+
return this[$soul].props;
|
|
80
|
+
}
|
|
81
|
+
$name(label) {
|
|
82
|
+
setName(this, label);
|
|
83
|
+
return this;
|
|
84
|
+
}
|
|
85
|
+
$usage(...usages) {
|
|
86
|
+
const soul = this[$soul];
|
|
87
|
+
if (soul.flagsOverridden) {
|
|
88
|
+
throw new Error('Cannot call $usage() after $overrideFlags().');
|
|
89
|
+
}
|
|
90
|
+
const hasStorage = usages.includes('storage');
|
|
91
|
+
const hasSampled = usages.includes('sampled');
|
|
92
|
+
const hasRender = usages.includes('render');
|
|
93
|
+
const hasTransient = usages.includes('transient');
|
|
94
|
+
const bindingFlags = (hasSampled ? GPUTextureUsage.TEXTURE_BINDING : 0) |
|
|
95
|
+
(hasStorage ? GPUTextureUsage.STORAGE_BINDING : 0);
|
|
96
|
+
const transientFlags = GPUTextureUsage.TRANSIENT_ATTACHMENT | GPUTextureUsage.RENDER_ATTACHMENT;
|
|
97
|
+
const nextFlags = soul.flags | bindingFlags | (hasRender ? GPUTextureUsage.RENDER_ATTACHMENT : 0);
|
|
98
|
+
const hasTransientUsage = hasTransient || !!(soul.flags & GPUTextureUsage.TRANSIENT_ATTACHMENT);
|
|
99
|
+
const hasSampledOrStorageUsage = !!(nextFlags &
|
|
100
|
+
(GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.STORAGE_BINDING));
|
|
101
|
+
if (hasTransientUsage && hasSampledOrStorageUsage) {
|
|
102
|
+
throw new Error("Transient texture usage cannot be combined with 'sampled' or 'storage'.");
|
|
103
|
+
}
|
|
104
|
+
soul.flags = hasTransient ? transientFlags : nextFlags;
|
|
105
|
+
this.usableAsStorage ||= hasStorage;
|
|
106
|
+
this.usableAsSampled ||= hasSampled;
|
|
107
|
+
this.usableAsRender ||= hasRender || hasTransient;
|
|
108
|
+
for (const usage of usages) {
|
|
109
|
+
if (!soul.usages.includes(usage)) {
|
|
110
|
+
soul.usages.push(usage);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return this;
|
|
114
|
+
}
|
|
115
|
+
$overrideFlags(flags) {
|
|
116
|
+
const soul = this[$soul];
|
|
117
|
+
soul.flags = flags;
|
|
118
|
+
soul.flagsOverridden = true;
|
|
119
|
+
this.usableAsSampled = true;
|
|
120
|
+
this.usableAsStorage = true;
|
|
121
|
+
this.usableAsRender = true;
|
|
122
|
+
return this;
|
|
123
|
+
}
|
|
124
|
+
createView(schema, viewDescriptor) {
|
|
125
|
+
if (schema === 'render') {
|
|
126
|
+
return new TgpuTextureRenderViewImpl(this, viewDescriptor);
|
|
127
|
+
}
|
|
128
|
+
return new TgpuFixedTextureViewImpl(schema ?? textureDescriptorToSchema(getDescriptorForProps(this.props)), this, viewDescriptor);
|
|
129
|
+
}
|
|
130
|
+
#clearMipLevel(mip = 0) {
|
|
131
|
+
const scale = 2 ** mip;
|
|
132
|
+
const [width, height, depth] = [
|
|
133
|
+
Math.max(1, Math.floor((this.props.size[0] ?? 1) / scale)),
|
|
134
|
+
Math.max(1, Math.floor((this.props.size[1] ?? 1) / scale)),
|
|
135
|
+
Math.max(1, Math.floor((this.props.size[2] ?? 1) / scale)),
|
|
136
|
+
];
|
|
137
|
+
const texelSize = this.#formatInfo.texelSize;
|
|
138
|
+
if (texelSize === 'non-copyable') {
|
|
139
|
+
throw new Error(`Cannot clear texture with format '${this.props.format}': this format does not support copy operations.`);
|
|
140
|
+
}
|
|
141
|
+
this[$soul].device.queue.writeTexture({ texture: this[$internal].materialize(), mipLevel: mip }, new Uint8Array(width * height * depth * texelSize), { bytesPerRow: texelSize * width, rowsPerImage: height }, [width, height, depth]);
|
|
142
|
+
}
|
|
143
|
+
clear(mipLevel = 'all') {
|
|
144
|
+
if (mipLevel === 'all') {
|
|
145
|
+
const mipLevels = this.props.mipLevelCount ?? 1;
|
|
146
|
+
for (let i = 0; i < mipLevels; i++) {
|
|
147
|
+
this.#clearMipLevel(i);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
this.#clearMipLevel(mipLevel);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
generateMipmaps(baseMipLevel = 0, mipLevels) {
|
|
155
|
+
if (!this.usableAsRender) {
|
|
156
|
+
throw new Error("generateMipmaps called without specifying 'render' usage. Add it via the $usage('render') method.");
|
|
157
|
+
}
|
|
158
|
+
const actualMipLevels = mipLevels ?? (this.props.mipLevelCount ?? 1) - baseMipLevel;
|
|
159
|
+
if (actualMipLevels <= 1) {
|
|
160
|
+
logger.warn('suspicious', `generateMipmaps is a no-op: would generate ${actualMipLevels} mip levels (base: ${baseMipLevel}, total: ${this.props.mipLevelCount ?? 1})`);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
if (baseMipLevel >= (this.props.mipLevelCount ?? 1)) {
|
|
164
|
+
throw new Error(`Base mip level ${baseMipLevel} is out of range. Texture has ${this.props.mipLevelCount ?? 1} mip levels.`);
|
|
165
|
+
}
|
|
166
|
+
generateTextureMipmaps(this[$soul].device, this[$internal].materialize(), baseMipLevel, actualMipLevels);
|
|
167
|
+
}
|
|
168
|
+
write(source, optionsOrMipLevel = 0) {
|
|
169
|
+
if (source instanceof ArrayBuffer || ArrayBuffer.isView(source)) {
|
|
170
|
+
this.#writeBufferData(source, typeof optionsOrMipLevel === 'number' ? optionsOrMipLevel : 0);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
if (!this.usableAsRender) {
|
|
174
|
+
throw new Error("texture.write(...) with image sources requires 'render' usage. Add it via the $usage('render') method.");
|
|
175
|
+
}
|
|
176
|
+
const options = typeof optionsOrMipLevel === 'number' ? undefined : optionsOrMipLevel;
|
|
177
|
+
const dimension = this.props.dimension ?? '2d';
|
|
178
|
+
const isArray = Array.isArray(source);
|
|
179
|
+
if (!isArray) {
|
|
180
|
+
this.#writeSingleLayer(source, dimension === '3d' ? 0 : undefined, options);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const layerCount = this.props.size[2] ?? 1;
|
|
184
|
+
if (source.length > layerCount) {
|
|
185
|
+
logger.warn('suspicious', `Too many image sources provided. Expected ${layerCount} layers, got ${source.length}. Extra sources will be ignored.`);
|
|
186
|
+
}
|
|
187
|
+
for (let layer = 0; layer < Math.min(source.length, layerCount); layer++) {
|
|
188
|
+
const bitmap = source[layer];
|
|
189
|
+
if (bitmap) {
|
|
190
|
+
this.#writeSingleLayer(bitmap, layer, options);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
#writeBufferData(source, mipLevel) {
|
|
195
|
+
const mipWidth = Math.max(1, this.props.size[0] >> mipLevel);
|
|
196
|
+
const mipHeight = Math.max(1, (this.props.size[1] ?? 1) >> mipLevel);
|
|
197
|
+
const mipDepth = Math.max(1, (this.props.size[2] ?? 1) >> mipLevel);
|
|
198
|
+
const texelSize = this.#formatInfo.texelSize;
|
|
199
|
+
if (texelSize === 'non-copyable') {
|
|
200
|
+
throw new Error(`Cannot write to texture with format '${this.props.format}': this format does not support copy operations.`);
|
|
201
|
+
}
|
|
202
|
+
const expectedSize = mipWidth * mipHeight * mipDepth * texelSize;
|
|
203
|
+
const actualSize = source.byteLength ?? source.byteLength;
|
|
204
|
+
if (actualSize !== expectedSize) {
|
|
205
|
+
throw new Error(`Buffer size mismatch. Expected ${expectedSize} bytes for mip level ${mipLevel}, got ${actualSize} bytes.`);
|
|
206
|
+
}
|
|
207
|
+
this[$soul].device.queue.writeTexture({
|
|
208
|
+
texture: this[$internal].materialize(),
|
|
209
|
+
mipLevel,
|
|
210
|
+
}, 'buffer' in source ? source.buffer : source, {
|
|
211
|
+
bytesPerRow: texelSize * mipWidth,
|
|
212
|
+
rowsPerImage: mipHeight,
|
|
213
|
+
}, [mipWidth, mipHeight, mipDepth]);
|
|
214
|
+
}
|
|
215
|
+
#writeSingleLayer(source, layer, options) {
|
|
216
|
+
const targetWidth = this.props.size[0];
|
|
217
|
+
const targetHeight = this.props.size[1] ?? 1;
|
|
218
|
+
const { width: sourceWidth, height: sourceHeight } = getImageSourceDimensions(source);
|
|
219
|
+
const needsResampling = sourceWidth !== targetWidth || sourceHeight !== targetHeight;
|
|
220
|
+
if (needsResampling) {
|
|
221
|
+
if (options?.fit !== 'stretch') {
|
|
222
|
+
throw new Error(`Texture write source size ${sourceWidth}x${sourceHeight} does not match target size ${targetWidth}x${targetHeight}. Pass fit: 'stretch' to resize explicitly.`);
|
|
223
|
+
}
|
|
224
|
+
resampleImage(this[$soul].device, this[$internal].materialize(), source, layer);
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
this[$soul].device.queue.copyExternalImageToTexture({ source }, {
|
|
228
|
+
texture: this[$internal].materialize(),
|
|
229
|
+
...(layer !== undefined && { origin: { x: 0, y: 0, z: layer } }),
|
|
230
|
+
}, layer !== undefined ? [targetWidth, targetHeight, 1] : this.props.size);
|
|
231
|
+
}
|
|
232
|
+
copyFrom(source) {
|
|
233
|
+
if (source.props.format !== this.props.format) {
|
|
234
|
+
throw new Error(`Texture format mismatch. Source texture has format ${source.props.format}, target texture has format ${this.props.format}`);
|
|
235
|
+
}
|
|
236
|
+
if (source.props.size[0] !== this.props.size[0] ||
|
|
237
|
+
(source.props.size[1] ?? 1) !== (this.props.size[1] ?? 1) ||
|
|
238
|
+
(source.props.size[2] ?? 1) !== (this.props.size[2] ?? 1)) {
|
|
239
|
+
throw new Error(`Texture size mismatch. Source texture has size ${source.props.size.join('x')}, target texture has size ${this.props.size.join('x')}`);
|
|
240
|
+
}
|
|
241
|
+
const commandEncoder = this[$soul].device.createCommandEncoder();
|
|
242
|
+
commandEncoder.copyTextureToTexture({ texture: source[$internal].materialize() }, { texture: this[$internal].materialize() }, source.props.size);
|
|
243
|
+
this[$soul].device.queue.submit([commandEncoder.finish()]);
|
|
244
|
+
}
|
|
245
|
+
toString() {
|
|
246
|
+
return `${this.resourceType}:${getName(this) ?? '<unnamed>'}`;
|
|
247
|
+
}
|
|
248
|
+
get destroyed() {
|
|
249
|
+
return this.#destroyed;
|
|
250
|
+
}
|
|
251
|
+
destroy() {
|
|
252
|
+
if (this.#destroyed) {
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
this.#destroyed = true;
|
|
256
|
+
if (this.#ownTexture) {
|
|
257
|
+
this[$soul].raw?.destroy();
|
|
258
|
+
}
|
|
259
|
+
}
|
|
17
260
|
}
|
|
18
|
-
|
|
19
|
-
|
|
261
|
+
class TgpuFixedTextureViewImpl {
|
|
262
|
+
[$internal];
|
|
263
|
+
[$soul];
|
|
264
|
+
resourceType = 'texture-view';
|
|
265
|
+
constructor(schema, baseTexture, descriptor) {
|
|
266
|
+
this[$soul] = {
|
|
267
|
+
type: 'texture-view',
|
|
268
|
+
texture: baseTexture,
|
|
269
|
+
schema,
|
|
270
|
+
descriptor,
|
|
271
|
+
raw: undefined,
|
|
272
|
+
label: undefined,
|
|
273
|
+
};
|
|
274
|
+
this[$internal] = {
|
|
275
|
+
unwrap: () => {
|
|
276
|
+
const soul = this[$soul];
|
|
277
|
+
if (!soul.raw) {
|
|
278
|
+
const schema = soul.schema;
|
|
279
|
+
const format = isWgslStorageTexture(schema) ? schema.format : soul.texture.props.format;
|
|
280
|
+
soul.raw = soul.texture[$internal].materialize().createView({
|
|
281
|
+
...soul.descriptor,
|
|
282
|
+
label: getName(this) ?? '<unnamed>',
|
|
283
|
+
format: soul.descriptor?.format ?? format,
|
|
284
|
+
dimension: schema.dimension,
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
return soul.raw;
|
|
288
|
+
},
|
|
289
|
+
format: descriptor?.format ??
|
|
290
|
+
(isWgslStorageTexture(schema) ? schema.format : baseTexture.props.format),
|
|
291
|
+
aspect: descriptor?.aspect,
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
get schema() {
|
|
295
|
+
return this[$soul].schema;
|
|
296
|
+
}
|
|
297
|
+
$name(label) {
|
|
298
|
+
setName(this, label);
|
|
299
|
+
if (this[$soul].raw) {
|
|
300
|
+
this[$soul].raw.label = label;
|
|
301
|
+
}
|
|
302
|
+
return this;
|
|
303
|
+
}
|
|
304
|
+
get [$gpuValueOf]() {
|
|
305
|
+
const schema = this.schema;
|
|
306
|
+
return new Proxy({
|
|
307
|
+
[$internal]: true,
|
|
308
|
+
get [$ownSnippet]() {
|
|
309
|
+
return snip(this, schema, /* origin */ 'handle', false);
|
|
310
|
+
},
|
|
311
|
+
[$resolve]: (ctx) => ctx.resolve(this),
|
|
312
|
+
toString: () => `${this.toString()}.$`,
|
|
313
|
+
}, valueProxyHandler);
|
|
314
|
+
}
|
|
315
|
+
get $() {
|
|
316
|
+
if (inCodegenMode()) {
|
|
317
|
+
return this[$gpuValueOf];
|
|
318
|
+
}
|
|
319
|
+
throw new Error('Direct access to texture view values is possible only as part of a compute dispatch or draw call. Try .read() or .write() instead');
|
|
320
|
+
}
|
|
321
|
+
get size() {
|
|
322
|
+
return this[$soul].texture.props.size;
|
|
323
|
+
}
|
|
324
|
+
toString() {
|
|
325
|
+
return `textureView:${getName(this) ?? '<unnamed>'}`;
|
|
326
|
+
}
|
|
327
|
+
[$resolve](ctx) {
|
|
328
|
+
const id = ctx.makeUniqueIdentifier(getName(this), 'global');
|
|
329
|
+
const { group, binding } = ctx.allocateFixedEntry(isWgslStorageTexture(this.schema)
|
|
330
|
+
? {
|
|
331
|
+
storageTexture: this.schema,
|
|
332
|
+
}
|
|
333
|
+
: {
|
|
334
|
+
texture: this.schema,
|
|
335
|
+
sampleType: this[$soul].descriptor?.sampleType ?? this.schema.bindingSampleType[0],
|
|
336
|
+
}, this);
|
|
337
|
+
return ctx.gen.declareGlobalVar({
|
|
338
|
+
group,
|
|
339
|
+
binding,
|
|
340
|
+
id,
|
|
341
|
+
dataType: this.schema,
|
|
342
|
+
scope: 'handle',
|
|
343
|
+
init: undefined,
|
|
344
|
+
});
|
|
345
|
+
}
|
|
20
346
|
}
|
|
21
|
-
|
|
22
|
-
|
|
347
|
+
export class TgpuLaidOutTextureViewImpl {
|
|
348
|
+
[$internal] = { unwrap: undefined };
|
|
349
|
+
resourceType = 'texture-view';
|
|
350
|
+
#membership;
|
|
351
|
+
schema;
|
|
352
|
+
constructor(schema, membership) {
|
|
353
|
+
this.schema = schema;
|
|
354
|
+
this.#membership = membership;
|
|
355
|
+
setName(this, membership.key);
|
|
356
|
+
}
|
|
357
|
+
toString() {
|
|
358
|
+
return `textureView:${getName(this) ?? '<unnamed>'}`;
|
|
359
|
+
}
|
|
360
|
+
[$resolve](ctx) {
|
|
361
|
+
const id = ctx.makeUniqueIdentifier(getName(this), 'global');
|
|
362
|
+
const group = ctx.allocateLayoutEntry(this.#membership.layout);
|
|
363
|
+
ctx.addDeclaration(`@group(${group}) @binding(${this.#membership.idx}) var ${id}: ${ctx.resolve(this.schema).value};`, id);
|
|
364
|
+
return snip(id, this.schema, /* origin */ 'handle');
|
|
365
|
+
}
|
|
366
|
+
get [$gpuValueOf]() {
|
|
367
|
+
const schema = this.schema;
|
|
368
|
+
return new Proxy({
|
|
369
|
+
[$internal]: true,
|
|
370
|
+
get [$ownSnippet]() {
|
|
371
|
+
return snip(this, schema, /* origin */ 'handle', false);
|
|
372
|
+
},
|
|
373
|
+
[$resolve]: (ctx) => ctx.resolve(this),
|
|
374
|
+
toString: () => `${this.toString()}.$`,
|
|
375
|
+
}, valueProxyHandler);
|
|
376
|
+
}
|
|
377
|
+
get $() {
|
|
378
|
+
if (inCodegenMode()) {
|
|
379
|
+
return this[$gpuValueOf];
|
|
380
|
+
}
|
|
381
|
+
throw new Error(`Accessed view '${getName(this) ?? '<unnamed>'}' outside of codegen mode. Direct access to texture views values is possible only as part of a compute dispatch or draw call. Try .read() or .write() instead`);
|
|
382
|
+
}
|
|
383
|
+
$name(label) {
|
|
384
|
+
setName(this, label);
|
|
385
|
+
return this;
|
|
386
|
+
}
|
|
23
387
|
}
|
|
24
|
-
|
|
25
|
-
|
|
388
|
+
export class TgpuTextureRenderViewImpl {
|
|
389
|
+
[$internal];
|
|
390
|
+
[$soul];
|
|
391
|
+
resourceType = 'texture-view';
|
|
392
|
+
constructor(baseTexture, descriptor = {}) {
|
|
393
|
+
this[$soul] = {
|
|
394
|
+
type: 'texture-view',
|
|
395
|
+
texture: baseTexture,
|
|
396
|
+
schema: 'render',
|
|
397
|
+
descriptor,
|
|
398
|
+
raw: undefined,
|
|
399
|
+
label: undefined,
|
|
400
|
+
};
|
|
401
|
+
this[$internal] = {
|
|
402
|
+
unwrap: () => {
|
|
403
|
+
return baseTexture[$internal].materialize().createView({
|
|
404
|
+
label: getName(this) ?? '<unnamed>',
|
|
405
|
+
...this.descriptor,
|
|
406
|
+
});
|
|
407
|
+
},
|
|
408
|
+
format: descriptor.format ?? baseTexture.props.format,
|
|
409
|
+
aspect: descriptor.aspect,
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
get descriptor() {
|
|
413
|
+
return this[$soul].descriptor ?? {};
|
|
414
|
+
}
|
|
26
415
|
}
|
|
27
|
-
var TgpuTextureImpl = class {
|
|
28
|
-
[$internal];
|
|
29
|
-
resourceType = "texture";
|
|
30
|
-
props;
|
|
31
|
-
usableAsSampled = false;
|
|
32
|
-
usableAsStorage = false;
|
|
33
|
-
usableAsRender = false;
|
|
34
|
-
#formatInfo;
|
|
35
|
-
#destroyed = false;
|
|
36
|
-
#flags = GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC;
|
|
37
|
-
#texture = null;
|
|
38
|
-
#branch;
|
|
39
|
-
constructor(props, branch) {
|
|
40
|
-
this.props = props;
|
|
41
|
-
const format = props.format;
|
|
42
|
-
this.#branch = branch;
|
|
43
|
-
this.#formatInfo = getTextureFormatInfo(format);
|
|
44
|
-
this[$internal] = { unwrap: () => {
|
|
45
|
-
if (this.#destroyed) throw new Error("This texture has been destroyed");
|
|
46
|
-
if (!this.#texture) this.#texture = branch.device.createTexture({
|
|
47
|
-
label: getName(this) ?? "<unnamed>",
|
|
48
|
-
format: props.format,
|
|
49
|
-
size: props.size,
|
|
50
|
-
usage: this.#flags,
|
|
51
|
-
dimension: props.dimension ?? "2d",
|
|
52
|
-
viewFormats: props.viewFormats ?? [],
|
|
53
|
-
mipLevelCount: props.mipLevelCount ?? 1,
|
|
54
|
-
sampleCount: props.sampleCount ?? 1
|
|
55
|
-
});
|
|
56
|
-
return this.#texture;
|
|
57
|
-
} };
|
|
58
|
-
}
|
|
59
|
-
$name(label) {
|
|
60
|
-
setName(this, label);
|
|
61
|
-
return this;
|
|
62
|
-
}
|
|
63
|
-
$usage(...usages) {
|
|
64
|
-
const hasStorage = usages.includes("storage");
|
|
65
|
-
const hasSampled = usages.includes("sampled");
|
|
66
|
-
const hasRender = usages.includes("render");
|
|
67
|
-
this.#flags |= hasSampled ? GPUTextureUsage.TEXTURE_BINDING : 0;
|
|
68
|
-
this.#flags |= hasStorage ? GPUTextureUsage.STORAGE_BINDING : 0;
|
|
69
|
-
this.#flags |= hasRender ? GPUTextureUsage.RENDER_ATTACHMENT : 0;
|
|
70
|
-
this.usableAsStorage ||= hasStorage;
|
|
71
|
-
this.usableAsSampled ||= hasSampled;
|
|
72
|
-
this.usableAsRender ||= hasRender;
|
|
73
|
-
return this;
|
|
74
|
-
}
|
|
75
|
-
createView(schema, viewDescriptor) {
|
|
76
|
-
if (schema === "render") return new TgpuTextureRenderViewImpl(this, viewDescriptor);
|
|
77
|
-
return new TgpuFixedTextureViewImpl(schema ?? textureDescriptorToSchema(getDescriptorForProps(this.props)), this, viewDescriptor);
|
|
78
|
-
}
|
|
79
|
-
#clearMipLevel(mip = 0) {
|
|
80
|
-
const scale = 2 ** mip;
|
|
81
|
-
const [width, height, depth] = [
|
|
82
|
-
Math.max(1, Math.floor((this.props.size[0] ?? 1) / scale)),
|
|
83
|
-
Math.max(1, Math.floor((this.props.size[1] ?? 1) / scale)),
|
|
84
|
-
Math.max(1, Math.floor((this.props.size[2] ?? 1) / scale))
|
|
85
|
-
];
|
|
86
|
-
const texelSize = this.#formatInfo.texelSize;
|
|
87
|
-
if (texelSize === "non-copyable") throw new Error(`Cannot clear texture with format '${this.props.format}': this format does not support copy operations.`);
|
|
88
|
-
this.#branch.device.queue.writeTexture({
|
|
89
|
-
texture: this[$internal].unwrap(),
|
|
90
|
-
mipLevel: mip
|
|
91
|
-
}, new Uint8Array(width * height * depth * texelSize), {
|
|
92
|
-
bytesPerRow: texelSize * width,
|
|
93
|
-
rowsPerImage: height
|
|
94
|
-
}, [
|
|
95
|
-
width,
|
|
96
|
-
height,
|
|
97
|
-
depth
|
|
98
|
-
]);
|
|
99
|
-
}
|
|
100
|
-
clear(mipLevel = "all") {
|
|
101
|
-
if (mipLevel === "all") {
|
|
102
|
-
const mipLevels = this.props.mipLevelCount ?? 1;
|
|
103
|
-
for (let i = 0; i < mipLevels; i++) this.#clearMipLevel(i);
|
|
104
|
-
} else this.#clearMipLevel(mipLevel);
|
|
105
|
-
}
|
|
106
|
-
generateMipmaps(baseMipLevel = 0, mipLevels) {
|
|
107
|
-
if (!this.usableAsRender) throw new Error("generateMipmaps called without specifying 'render' usage. Add it via the $usage('render') method.");
|
|
108
|
-
const actualMipLevels = mipLevels ?? (this.props.mipLevelCount ?? 1) - baseMipLevel;
|
|
109
|
-
if (actualMipLevels <= 1) {
|
|
110
|
-
console.warn(`generateMipmaps is a no-op: would generate ${actualMipLevels} mip levels (base: ${baseMipLevel}, total: ${this.props.mipLevelCount ?? 1})`);
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
if (baseMipLevel >= (this.props.mipLevelCount ?? 1)) throw new Error(`Base mip level ${baseMipLevel} is out of range. Texture has ${this.props.mipLevelCount ?? 1} mip levels.`);
|
|
114
|
-
generateTextureMipmaps(this.#branch.device, this[$internal].unwrap(), baseMipLevel, actualMipLevels);
|
|
115
|
-
}
|
|
116
|
-
write(source, mipLevel = 0) {
|
|
117
|
-
if (source instanceof ArrayBuffer || ArrayBuffer.isView(source)) {
|
|
118
|
-
this.#writeBufferData(source, mipLevel);
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
const dimension = this.props.dimension ?? "2d";
|
|
122
|
-
if (!Array.isArray(source)) {
|
|
123
|
-
this.#writeSingleLayer(source, dimension === "3d" ? 0 : void 0);
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
const layerCount = this.props.size[2] ?? 1;
|
|
127
|
-
if (source.length > layerCount) console.warn(`Too many image sources provided. Expected ${layerCount} layers, got ${source.length}. Extra sources will be ignored.`);
|
|
128
|
-
for (let layer = 0; layer < Math.min(source.length, layerCount); layer++) {
|
|
129
|
-
const bitmap = source[layer];
|
|
130
|
-
if (bitmap) this.#writeSingleLayer(bitmap, layer);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
#writeBufferData(source, mipLevel) {
|
|
134
|
-
const mipWidth = Math.max(1, this.props.size[0] >> mipLevel);
|
|
135
|
-
const mipHeight = Math.max(1, (this.props.size[1] ?? 1) >> mipLevel);
|
|
136
|
-
const mipDepth = Math.max(1, (this.props.size[2] ?? 1) >> mipLevel);
|
|
137
|
-
const texelSize = this.#formatInfo.texelSize;
|
|
138
|
-
if (texelSize === "non-copyable") throw new Error(`Cannot write to texture with format '${this.props.format}': this format does not support copy operations.`);
|
|
139
|
-
const expectedSize = mipWidth * mipHeight * mipDepth * texelSize;
|
|
140
|
-
const actualSize = source.byteLength ?? source.byteLength;
|
|
141
|
-
if (actualSize !== expectedSize) throw new Error(`Buffer size mismatch. Expected ${expectedSize} bytes for mip level ${mipLevel}, got ${actualSize} bytes.`);
|
|
142
|
-
this.#branch.device.queue.writeTexture({
|
|
143
|
-
texture: this[$internal].unwrap(),
|
|
144
|
-
mipLevel
|
|
145
|
-
}, "buffer" in source ? source.buffer : source, {
|
|
146
|
-
bytesPerRow: texelSize * mipWidth,
|
|
147
|
-
rowsPerImage: mipHeight
|
|
148
|
-
}, [
|
|
149
|
-
mipWidth,
|
|
150
|
-
mipHeight,
|
|
151
|
-
mipDepth
|
|
152
|
-
]);
|
|
153
|
-
}
|
|
154
|
-
#writeSingleLayer(source, layer) {
|
|
155
|
-
const targetWidth = this.props.size[0];
|
|
156
|
-
const targetHeight = this.props.size[1] ?? 1;
|
|
157
|
-
const { width: sourceWidth, height: sourceHeight } = getImageSourceDimensions(source);
|
|
158
|
-
if (sourceWidth !== targetWidth || sourceHeight !== targetHeight) {
|
|
159
|
-
resampleImage(this.#branch.device, this[$internal].unwrap(), source, layer);
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
this.#branch.device.queue.copyExternalImageToTexture({ source }, {
|
|
163
|
-
texture: this[$internal].unwrap(),
|
|
164
|
-
...layer !== void 0 && { origin: {
|
|
165
|
-
x: 0,
|
|
166
|
-
y: 0,
|
|
167
|
-
z: layer
|
|
168
|
-
} }
|
|
169
|
-
}, layer !== void 0 ? [
|
|
170
|
-
targetWidth,
|
|
171
|
-
targetHeight,
|
|
172
|
-
1
|
|
173
|
-
] : this.props.size);
|
|
174
|
-
}
|
|
175
|
-
copyFrom(source) {
|
|
176
|
-
if (source.props.format !== this.props.format) throw new Error(`Texture format mismatch. Source texture has format ${source.props.format}, target texture has format ${this.props.format}`);
|
|
177
|
-
if (source.props.size[0] !== this.props.size[0] || (source.props.size[1] ?? 1) !== (this.props.size[1] ?? 1) || (source.props.size[2] ?? 1) !== (this.props.size[2] ?? 1)) throw new Error(`Texture size mismatch. Source texture has size ${source.props.size.join("x")}, target texture has size ${this.props.size.join("x")}`);
|
|
178
|
-
const commandEncoder = this.#branch.device.createCommandEncoder();
|
|
179
|
-
commandEncoder.copyTextureToTexture({ texture: source[$internal].unwrap() }, { texture: this[$internal].unwrap() }, source.props.size);
|
|
180
|
-
this.#branch.device.queue.submit([commandEncoder.finish()]);
|
|
181
|
-
}
|
|
182
|
-
toString() {
|
|
183
|
-
return `${this.resourceType}:${getName(this) ?? "<unnamed>"}`;
|
|
184
|
-
}
|
|
185
|
-
get destroyed() {
|
|
186
|
-
return this.#destroyed;
|
|
187
|
-
}
|
|
188
|
-
destroy() {
|
|
189
|
-
if (this.#destroyed) return;
|
|
190
|
-
this.#destroyed = true;
|
|
191
|
-
this.#texture?.destroy();
|
|
192
|
-
}
|
|
193
|
-
};
|
|
194
|
-
var TgpuFixedTextureViewImpl = class {
|
|
195
|
-
[$internal];
|
|
196
|
-
resourceType = "texture-view";
|
|
197
|
-
schema;
|
|
198
|
-
#baseTexture;
|
|
199
|
-
#view;
|
|
200
|
-
#descriptor;
|
|
201
|
-
constructor(schema, baseTexture, descriptor) {
|
|
202
|
-
this.schema = schema;
|
|
203
|
-
this.#baseTexture = baseTexture;
|
|
204
|
-
this.#descriptor = descriptor;
|
|
205
|
-
this[$internal] = { unwrap: () => {
|
|
206
|
-
if (!this.#view) {
|
|
207
|
-
const schema$1 = this.schema;
|
|
208
|
-
const format = isWgslStorageTexture(schema$1) ? schema$1.format : this.#baseTexture.props.format;
|
|
209
|
-
this.#view = this.#baseTexture[$internal].unwrap().createView({
|
|
210
|
-
...this.#descriptor,
|
|
211
|
-
label: getName(this) ?? "<unnamed>",
|
|
212
|
-
format: this.#descriptor?.format ?? format,
|
|
213
|
-
dimension: schema$1.dimension
|
|
214
|
-
});
|
|
215
|
-
}
|
|
216
|
-
return this.#view;
|
|
217
|
-
} };
|
|
218
|
-
}
|
|
219
|
-
$name(label) {
|
|
220
|
-
setName(this, label);
|
|
221
|
-
if (this.#view) this.#view.label = label;
|
|
222
|
-
return this;
|
|
223
|
-
}
|
|
224
|
-
get [$gpuValueOf]() {
|
|
225
|
-
const schema = this.schema;
|
|
226
|
-
return new Proxy({
|
|
227
|
-
[$internal]: true,
|
|
228
|
-
get [$ownSnippet]() {
|
|
229
|
-
return snip(this, schema, "handle");
|
|
230
|
-
},
|
|
231
|
-
[$resolve]: (ctx) => ctx.resolve(this),
|
|
232
|
-
toString: () => `${this.toString()}.$`
|
|
233
|
-
}, valueProxyHandler);
|
|
234
|
-
}
|
|
235
|
-
get $() {
|
|
236
|
-
if (inCodegenMode()) return this[$gpuValueOf];
|
|
237
|
-
throw new Error("Direct access to texture view values is possible only as part of a compute dispatch or draw call. Try .read() or .write() instead");
|
|
238
|
-
}
|
|
239
|
-
get value() {
|
|
240
|
-
return this.$;
|
|
241
|
-
}
|
|
242
|
-
get size() {
|
|
243
|
-
return this.#baseTexture.props.size;
|
|
244
|
-
}
|
|
245
|
-
toString() {
|
|
246
|
-
return `textureView:${getName(this) ?? "<unnamed>"}`;
|
|
247
|
-
}
|
|
248
|
-
[$resolve](ctx) {
|
|
249
|
-
const id = ctx.makeUniqueIdentifier(getName(this), "global");
|
|
250
|
-
const { group, binding } = ctx.allocateFixedEntry(isWgslStorageTexture(this.schema) ? { storageTexture: this.schema } : {
|
|
251
|
-
texture: this.schema,
|
|
252
|
-
sampleType: this.#descriptor?.sampleType ?? this.schema.bindingSampleType[0]
|
|
253
|
-
}, this);
|
|
254
|
-
return ctx.gen.declareGlobalVar({
|
|
255
|
-
group,
|
|
256
|
-
binding,
|
|
257
|
-
id,
|
|
258
|
-
dataType: this.schema,
|
|
259
|
-
scope: "handle",
|
|
260
|
-
init: void 0
|
|
261
|
-
});
|
|
262
|
-
}
|
|
263
|
-
};
|
|
264
|
-
var TgpuLaidOutTextureViewImpl = class {
|
|
265
|
-
[$internal] = { unwrap: void 0 };
|
|
266
|
-
resourceType = "texture-view";
|
|
267
|
-
#membership;
|
|
268
|
-
schema;
|
|
269
|
-
constructor(schema, membership) {
|
|
270
|
-
this.schema = schema;
|
|
271
|
-
this.#membership = membership;
|
|
272
|
-
setName(this, membership.key);
|
|
273
|
-
}
|
|
274
|
-
toString() {
|
|
275
|
-
return `textureView:${getName(this) ?? "<unnamed>"}`;
|
|
276
|
-
}
|
|
277
|
-
[$resolve](ctx) {
|
|
278
|
-
const id = ctx.makeUniqueIdentifier(getName(this), "global");
|
|
279
|
-
const group = ctx.allocateLayoutEntry(this.#membership.layout);
|
|
280
|
-
ctx.addDeclaration(`@group(${group}) @binding(${this.#membership.idx}) var ${id}: ${ctx.resolve(this.schema).value};`);
|
|
281
|
-
return snip(id, this.schema, "handle");
|
|
282
|
-
}
|
|
283
|
-
get [$gpuValueOf]() {
|
|
284
|
-
const schema = this.schema;
|
|
285
|
-
return new Proxy({
|
|
286
|
-
[$internal]: true,
|
|
287
|
-
get [$ownSnippet]() {
|
|
288
|
-
return snip(this, schema, "handle");
|
|
289
|
-
},
|
|
290
|
-
[$resolve]: (ctx) => ctx.resolve(this),
|
|
291
|
-
toString: () => `${this.toString()}.$`
|
|
292
|
-
}, valueProxyHandler);
|
|
293
|
-
}
|
|
294
|
-
get $() {
|
|
295
|
-
if (inCodegenMode()) return this[$gpuValueOf];
|
|
296
|
-
throw new Error(`Accessed view '${getName(this) ?? "<unnamed>"}' outside of codegen mode. Direct access to texture views values is possible only as part of a compute dispatch or draw call. Try .read() or .write() instead`);
|
|
297
|
-
}
|
|
298
|
-
get value() {
|
|
299
|
-
return this.$;
|
|
300
|
-
}
|
|
301
|
-
$name(label) {
|
|
302
|
-
setName(this, label);
|
|
303
|
-
return this;
|
|
304
|
-
}
|
|
305
|
-
};
|
|
306
|
-
var TgpuTextureRenderViewImpl = class {
|
|
307
|
-
[$internal];
|
|
308
|
-
resourceType = "texture-view";
|
|
309
|
-
descriptor;
|
|
310
|
-
constructor(baseTexture, descriptor = {}) {
|
|
311
|
-
this.descriptor = descriptor;
|
|
312
|
-
this[$internal] = { unwrap: () => {
|
|
313
|
-
return baseTexture[$internal].unwrap().createView({
|
|
314
|
-
label: getName(this) ?? "<unnamed>",
|
|
315
|
-
...this.descriptor
|
|
316
|
-
});
|
|
317
|
-
} };
|
|
318
|
-
}
|
|
319
|
-
};
|
|
320
|
-
|
|
321
|
-
//#endregion
|
|
322
|
-
export { INTERNAL_createTexture, TgpuLaidOutTextureViewImpl, isTexture, isTextureView };
|