UNPKG

typegpu

Version:

A thin layer between JS and WebGPU/WGSL that improves development experience and allows for faster iteration.

217 lines (216 loc) 8.72 kB
import { stitch } from "../core/resolve/stitch.js"; import { isWgslExternalTexture, isWgslTexture, } from "../data/texture.js"; import { dualImpl, MissingCpuImplError } from "../core/function/dualImpl.js"; import { f32, i32, u32 } from "../data/numeric.js"; import { vec2u, vec3u, vec4f, vec4i, vec4u } from "../data/vector.js"; import { Void, } from "../data/wgslTypes.js"; import { getTextureFormatInfo, } from "../core/texture/textureFormats.js"; function compactSnippetArgs(args) { return args.filter((arg) => arg !== undefined); } function sampleCpu(_texture, _sampler, _coords, _offsetOrArrayIndex, _maybeOffset) { throw new MissingCpuImplError('Texture sampling relies on GPU resources and cannot be executed outside of a draw call'); } export const textureSample = dualImpl({ name: 'textureSample', normalImpl: sampleCpu, codegenImpl: (ctx, args) => ctx.gen.emitCall('textureSample', [], compactSnippetArgs(args)), signature: (...args) => { const isDepth = args[0].type.startsWith('texture_depth'); return { argTypes: args, returnType: isDepth ? f32 : vec4f, }; }, sideEffects: false, }); function sampleBiasCpu(_texture, _sampler, _coords, _biasOrArrayIndex, _biasOrOffset, _maybeOffset) { throw new MissingCpuImplError('Texture sampling with bias relies on GPU resources and cannot be executed outside of a draw call'); } export const textureSampleBias = dualImpl({ name: 'textureSampleBias', normalImpl: sampleBiasCpu, codegenImpl: (ctx, args) => ctx.gen.emitCall('textureSampleBias', [], compactSnippetArgs(args)), signature: (...args) => ({ argTypes: args, returnType: vec4f, }), sideEffects: false, }); function sampleLevelCpu(_texture, _sampler, _coords, _level, _offsetOrArrayIndex, _maybeOffset) { throw new MissingCpuImplError('Texture sampling relies on GPU resources and cannot be executed outside of a draw call'); } export const textureSampleLevel = dualImpl({ name: 'textureSampleLevel', normalImpl: sampleLevelCpu, codegenImpl: (ctx, args) => ctx.gen.emitCall('textureSampleLevel', [], compactSnippetArgs(args)), signature: (...args) => { const isDepth = args[0].type.startsWith('texture_depth'); return { argTypes: args, returnType: isDepth ? f32 : vec4f, }; }, sideEffects: false, }); function textureLoadCpu(_texture, _coords, _levelOrArrayIndex) { throw new MissingCpuImplError('`textureLoad` relies on GPU resources and cannot be executed outside of a draw call'); } export const textureLoad = dualImpl({ name: 'textureLoad', normalImpl: textureLoadCpu, codegenImpl: (ctx, args) => ctx.gen.emitCall('textureLoad', [], compactSnippetArgs(args)), signature: (...args) => { const texture = args[0]; if (isWgslTexture(texture)) { const isDepth = texture.type.startsWith('texture_depth'); const sampleType = texture.sampleType; return { argTypes: args, returnType: isDepth ? f32 : sampleType.type === 'f32' ? vec4f : sampleType.type === 'u32' ? vec4u : vec4i, }; } if (isWgslExternalTexture(texture)) { return { argTypes: args, returnType: vec4f, }; } const format = texture.format; const dataType = getTextureFormatInfo(format).vectorType; return { argTypes: args, returnType: dataType, }; }, sideEffects: false, }); function textureStoreCpu(_texture, _coords, _arrayIndexOrValue, _maybeValue) { throw new MissingCpuImplError('`textureStore` relies on GPU resources and cannot be executed outside of a draw call'); } export const textureStore = dualImpl({ name: 'textureStore', normalImpl: textureStoreCpu, codegenImpl: (_ctx, args) => stitch `textureStore(${args})`, signature: (...args) => ({ argTypes: args, returnType: Void }), sideEffects: true, }); function textureDimensionsCpu(_texture, _level) { throw new MissingCpuImplError('`textureDimensions` relies on GPU resources and cannot be executed outside of a draw call'); } export const textureDimensions = dualImpl({ name: 'textureDimensions', normalImpl: textureDimensionsCpu, codegenImpl: (ctx, args) => ctx.gen.emitCall('textureDimensions', [], compactSnippetArgs(args)), signature: (...args) => { const dim = args[0].dimension; if (dim === '1d') { return { argTypes: args, returnType: u32, }; } if (dim === '3d') { return { argTypes: args, returnType: vec3u, }; } return { argTypes: args, returnType: vec2u, }; }, sideEffects: false, }); export const textureGatherCpu = (..._args) => { throw new Error('Texture gather relies on GPU resources and cannot be executed outside of a draw call'); }; const sampleTypeToVecType = { f32: vec4f, i32: vec4i, u32: vec4u, }; export const textureGather = dualImpl({ name: 'textureGather', normalImpl: textureGatherCpu, codegenImpl: (_ctx, args) => stitch `textureGather(${args})`, signature: (...args) => { if (args[0].type.startsWith('texture')) { const [texture, sampler, coords, _, ...rest] = args; const isArrayTexture = texture.type === 'texture_depth_2d_array' || texture.type === 'texture_depth_cube_array'; const argTypes = isArrayTexture ? [texture, sampler, coords, [u32, i32], ...rest] : args; return { argTypes: argTypes, returnType: vec4f }; } const [_, texture, sampler, coords, ...rest] = args; const isArrayTexture = texture.type === 'texture_2d_array' || texture.type === 'texture_cube_array'; const argTypes = isArrayTexture ? [[u32, i32], texture, sampler, coords, [u32, i32], ...rest] : [[u32, i32], texture, sampler, coords, ...rest]; return { argTypes: argTypes, returnType: sampleTypeToVecType[texture.sampleType.type], }; }, sideEffects: false, }); function textureSampleCompareCpu(_texture, _sampler, _coords, _depthRefOrArrayIndex, _depthRefOrOffset, _maybeOffset) { throw new MissingCpuImplError('Texture comparison sampling relies on GPU resources and cannot be executed outside of a draw call'); } export const textureSampleCompare = dualImpl({ name: 'textureSampleCompare', normalImpl: textureSampleCompareCpu, codegenImpl: (_ctx, args) => stitch `textureSampleCompare(${args})`, signature: (...args) => ({ argTypes: args, returnType: f32, }), sideEffects: false, }); function textureSampleCompareLevelCpu(_texture, _sampler, _coords, _depthRefOrArrayIndex, _depthRefOrOffset, _maybeOffset) { throw new MissingCpuImplError('Texture comparison sampling with level relies on GPU resources and cannot be executed outside of a draw call'); } export const textureSampleCompareLevel = dualImpl({ name: 'textureSampleCompareLevel', normalImpl: textureSampleCompareLevelCpu, codegenImpl: (ctx, args) => stitch `textureSampleCompareLevel(${args})`, signature: (...args) => ({ argTypes: args, returnType: f32, }), sideEffects: false, }); function textureSampleBaseClampToEdgeCpu(_texture, _sampler, _coords) { throw new MissingCpuImplError('Texture sampling with base clamp to edge is not supported outside of GPU mode.'); } function sampleGradCpu(_texture, _sampler, _coords, _ddxOrArrayIndex, _ddyOrDdx, _offsetOrDdy, _maybeOffset) { throw new MissingCpuImplError('Texture sampling with gradients relies on GPU resources and cannot be executed outside of a draw call'); } export const textureSampleGrad = dualImpl({ name: 'textureSampleGrad', normalImpl: sampleGradCpu, codegenImpl: (_ctx, args) => stitch `textureSampleGrad(${args})`, signature: (...args) => ({ argTypes: args, returnType: vec4f, }), sideEffects: false, }); export const textureSampleBaseClampToEdge = dualImpl({ name: 'textureSampleBaseClampToEdge', normalImpl: textureSampleBaseClampToEdgeCpu, codegenImpl: (_ctx, args) => stitch `textureSampleBaseClampToEdge(${args})`, signature: (...args) => ({ argTypes: args, returnType: vec4f, }), sideEffects: false, });