diff --git a/packages/typegpu/package.json b/packages/typegpu/package.json index 96fb1978b4..bdd852f151 100644 --- a/packages/typegpu/package.json +++ b/packages/typegpu/package.json @@ -24,6 +24,9 @@ }, "type": "module", "sideEffects": false, + "imports": { + "#shaderbit": "./src/shaderbit/index.ts" + }, "exports": { "./package.json": "./package.json", ".": { diff --git a/packages/typegpu/src/core/buffer/bufferShorthand.ts b/packages/typegpu/src/core/buffer/bufferShorthand.ts index 3f86942dcf..4375ec7bba 100644 --- a/packages/typegpu/src/core/buffer/bufferShorthand.ts +++ b/packages/typegpu/src/core/buffer/bufferShorthand.ts @@ -1,4 +1,4 @@ -import type { ResolvedSnippet } from '../../data/snippet.ts'; +import type { ResolvedSnippet } from '../../tgsl/snippet.ts'; import type { BaseData } from '../../data/wgslTypes.ts'; import type { StorageFlag } from '../../extension.ts'; import { getName, setName, type TgpuNamable } from '../../shared/meta.ts'; diff --git a/packages/typegpu/src/core/buffer/bufferUsage.ts b/packages/typegpu/src/core/buffer/bufferUsage.ts index 24f28dcbca..15f4cd42fa 100644 --- a/packages/typegpu/src/core/buffer/bufferUsage.ts +++ b/packages/typegpu/src/core/buffer/bufferUsage.ts @@ -1,5 +1,5 @@ import { schemaCallWrapper } from '../../data/schemaCallWrapper.ts'; -import { type ResolvedSnippet, snip } from '../../data/snippet.ts'; +import { type ResolvedSnippet, snip } from '../../tgsl/snippet.ts'; import { type AnyWgslData, type BaseData, isNaturallyEphemeral } from '../../data/wgslTypes.ts'; import { IllegalBufferAccessError } from '../../errors.ts'; import { getExecMode, inCodegenMode, isInsideTgpuFn } from '../../execMode.ts'; diff --git a/packages/typegpu/src/core/constant/tgpuConstant.ts b/packages/typegpu/src/core/constant/tgpuConstant.ts index 4efbf7bef7..0afac41ca3 100644 --- a/packages/typegpu/src/core/constant/tgpuConstant.ts +++ b/packages/typegpu/src/core/constant/tgpuConstant.ts @@ -1,5 +1,5 @@ import { isData, type AnyData } from '../../data/dataTypes.ts'; -import { type ResolvedSnippet, snip } from '../../data/snippet.ts'; +import { type ResolvedSnippet, snip } from '../../tgsl/snippet.ts'; import { type AnyWgslData, type BaseData, diff --git a/packages/typegpu/src/core/declare/tgpuDeclare.ts b/packages/typegpu/src/core/declare/tgpuDeclare.ts index 9fda1b99ca..6a7b4accf8 100644 --- a/packages/typegpu/src/core/declare/tgpuDeclare.ts +++ b/packages/typegpu/src/core/declare/tgpuDeclare.ts @@ -1,4 +1,4 @@ -import { type ResolvedSnippet, snip } from '../../data/snippet.ts'; +import { type ResolvedSnippet, snip } from '../../tgsl/snippet.ts'; import { Void } from '../../data/wgslTypes.ts'; import { $internal, $resolve } from '../../shared/symbols.ts'; import type { ResolutionCtx, SelfResolvable } from '../../types.ts'; diff --git a/packages/typegpu/src/core/function/autoIO.ts b/packages/typegpu/src/core/function/autoIO.ts index 6feece51d5..d6c18d5cb9 100644 --- a/packages/typegpu/src/core/function/autoIO.ts +++ b/packages/typegpu/src/core/function/autoIO.ts @@ -1,6 +1,6 @@ import { builtin, type OmitBuiltins } from '../../builtin.ts'; import { AutoStruct } from '../../data/autoStruct.ts'; -import type { ResolvedSnippet } from '../../data/snippet.ts'; +import type { ResolvedSnippet } from '../../tgsl/snippet.ts'; import { vec4f } from '../../data/vector.ts'; import type { FormatToWGSLType } from '../../data/vertexFormatData.ts'; import type { BaseData, v4f } from '../../data/wgslTypes.ts'; diff --git a/packages/typegpu/src/core/function/createCallableSchema.ts b/packages/typegpu/src/core/function/createCallableSchema.ts index 970c950fa8..92f93cb6ff 100644 --- a/packages/typegpu/src/core/function/createCallableSchema.ts +++ b/packages/typegpu/src/core/function/createCallableSchema.ts @@ -1,4 +1,4 @@ -import { type MapValueToSnippet, type ResolvedSnippet, snip } from '../../data/snippet.ts'; +import { type MapValueToSnippet, type ResolvedSnippet, snip } from '../../tgsl/snippet.ts'; import { type BaseData, isPtr } from '../../data/wgslTypes.ts'; import { setName } from '../../shared/meta.ts'; import { $gpuCallable } from '../../shared/symbols.ts'; diff --git a/packages/typegpu/src/core/function/dualImpl.ts b/packages/typegpu/src/core/function/dualImpl.ts index 4f54ac49be..44c4fde149 100644 --- a/packages/typegpu/src/core/function/dualImpl.ts +++ b/packages/typegpu/src/core/function/dualImpl.ts @@ -1,4 +1,4 @@ -import { type MapValueToSnippet, snip } from '../../data/snippet.ts'; +import { type MapValueToSnippet, snip } from '../../tgsl/snippet.ts'; import { setName } from '../../shared/meta.ts'; import { $gpuCallable } from '../../shared/symbols.ts'; import { tryConvertSnippet } from '../../tgsl/conversion.ts'; diff --git a/packages/typegpu/src/core/function/entryInputRouter.ts b/packages/typegpu/src/core/function/entryInputRouter.ts index 8ba6669372..0f4082b9af 100644 --- a/packages/typegpu/src/core/function/entryInputRouter.ts +++ b/packages/typegpu/src/core/function/entryInputRouter.ts @@ -1,5 +1,5 @@ import { undecorate } from '../../data/dataTypes.ts'; -import { snip, type Snippet } from '../../data/snippet.ts'; +import { snip, type Snippet } from '../../tgsl/snippet.ts'; import { $internal, $repr } from '../../shared/symbols.ts'; import { type BaseData, isWgslStruct } from '../../data/wgslTypes.ts'; diff --git a/packages/typegpu/src/core/function/fnCore.ts b/packages/typegpu/src/core/function/fnCore.ts index 66429067e5..aa986d0e0e 100644 --- a/packages/typegpu/src/core/function/fnCore.ts +++ b/packages/typegpu/src/core/function/fnCore.ts @@ -1,6 +1,6 @@ import { getAttributesString } from '../../data/attributes.ts'; import { undecorate } from '../../data/dataTypes.ts'; -import { type ResolvedSnippet, snip } from '../../data/snippet.ts'; +import { type ResolvedSnippet, snip } from '../../tgsl/snippet.ts'; import { type BaseData, isWgslData, isWgslStruct, Void } from '../../data/wgslTypes.ts'; import { MissingLinksError } from '../../errors.ts'; import { getMetaData, getName } from '../../shared/meta.ts'; diff --git a/packages/typegpu/src/core/function/shelllessImpl.ts b/packages/typegpu/src/core/function/shelllessImpl.ts index 23b60bdde1..256c27af30 100644 --- a/packages/typegpu/src/core/function/shelllessImpl.ts +++ b/packages/typegpu/src/core/function/shelllessImpl.ts @@ -1,4 +1,4 @@ -import type { ResolvedSnippet } from '../../data/snippet.ts'; +import type { ResolvedSnippet } from '../../tgsl/snippet.ts'; import type { BaseData } from '../../data/wgslTypes.ts'; import { getName } from '../../shared/meta.ts'; import { $getNameForward, $internal, $resolve } from '../../shared/symbols.ts'; diff --git a/packages/typegpu/src/core/function/tgpuComputeFn.ts b/packages/typegpu/src/core/function/tgpuComputeFn.ts index 6f48cbe643..eeb6b7f85b 100644 --- a/packages/typegpu/src/core/function/tgpuComputeFn.ts +++ b/packages/typegpu/src/core/function/tgpuComputeFn.ts @@ -1,5 +1,5 @@ import type { AnyComputeBuiltin } from '../../builtin.ts'; -import type { ResolvedSnippet } from '../../data/snippet.ts'; +import type { ResolvedSnippet } from '../../tgsl/snippet.ts'; import { Void } from '../../data/wgslTypes.ts'; import { getName, setName, type TgpuNamable } from '../../shared/meta.ts'; import { $getNameForward, $internal, $resolve } from '../../shared/symbols.ts'; diff --git a/packages/typegpu/src/core/function/tgpuFn.ts b/packages/typegpu/src/core/function/tgpuFn.ts index 65ea52de65..882b4613aa 100644 --- a/packages/typegpu/src/core/function/tgpuFn.ts +++ b/packages/typegpu/src/core/function/tgpuFn.ts @@ -1,4 +1,4 @@ -import type { ResolvedSnippet } from '../../data/snippet.ts'; +import type { ResolvedSnippet } from '../../tgsl/snippet.ts'; import { schemaCallWrapper } from '../../data/schemaCallWrapper.ts'; import { type BaseData, Void } from '../../data/wgslTypes.ts'; import { ExecutionError } from '../../errors.ts'; diff --git a/packages/typegpu/src/core/function/tgpuFragmentFn.ts b/packages/typegpu/src/core/function/tgpuFragmentFn.ts index 631617bcdc..23602e94db 100644 --- a/packages/typegpu/src/core/function/tgpuFragmentFn.ts +++ b/packages/typegpu/src/core/function/tgpuFragmentFn.ts @@ -5,7 +5,7 @@ import type { } from '../../builtin.ts'; import type { UndecorateRecord } from '../../data/dataTypes.ts'; import type { InstanceToSchema } from '../../data/instanceToSchema.ts'; -import type { ResolvedSnippet } from '../../data/snippet.ts'; +import type { ResolvedSnippet } from '../../tgsl/snippet.ts'; import type { BaseData, Decorated, diff --git a/packages/typegpu/src/core/function/tgpuVertexFn.ts b/packages/typegpu/src/core/function/tgpuVertexFn.ts index a261634b3d..3d3db97fe9 100644 --- a/packages/typegpu/src/core/function/tgpuVertexFn.ts +++ b/packages/typegpu/src/core/function/tgpuVertexFn.ts @@ -1,6 +1,6 @@ import type { AnyVertexInputBuiltin, AnyVertexOutputBuiltin, OmitBuiltins } from '../../builtin.ts'; import type { UndecorateRecord } from '../../data/dataTypes.ts'; -import type { ResolvedSnippet } from '../../data/snippet.ts'; +import type { ResolvedSnippet } from '../../tgsl/snippet.ts'; import type { BaseData, Decorated, Interpolate, Location } from '../../data/wgslTypes.ts'; import { getName, setName, type TgpuNamable } from '../../shared/meta.ts'; import { $getNameForward, $internal, $resolve } from '../../shared/symbols.ts'; diff --git a/packages/typegpu/src/core/pipeline/computePipeline.ts b/packages/typegpu/src/core/pipeline/computePipeline.ts index 48f6499742..1f5d8f02c4 100644 --- a/packages/typegpu/src/core/pipeline/computePipeline.ts +++ b/packages/typegpu/src/core/pipeline/computePipeline.ts @@ -1,6 +1,6 @@ import type { AnyComputeBuiltin } from '../../builtin.ts'; import type { TgpuQuerySet } from '../../core/querySet/querySet.ts'; -import { type ResolvedSnippet, snip } from '../../data/snippet.ts'; +import { type ResolvedSnippet, snip } from '../../tgsl/snippet.ts'; import type { AnyWgslData } from '../../data/wgslTypes.ts'; import { Void } from '../../data/wgslTypes.ts'; import { applyBindGroups } from './applyPipelineState.ts'; diff --git a/packages/typegpu/src/core/pipeline/renderPipeline.ts b/packages/typegpu/src/core/pipeline/renderPipeline.ts index d558aeb8d8..e349dee2a8 100644 --- a/packages/typegpu/src/core/pipeline/renderPipeline.ts +++ b/packages/typegpu/src/core/pipeline/renderPipeline.ts @@ -4,7 +4,7 @@ import type { TgpuQuerySet } from '../../core/querySet/querySet.ts'; import { isBuiltin } from '../../data/attributes.ts'; import { type Disarray, getCustomLocation, type UndecorateRecord } from '../../data/dataTypes.ts'; import { sizeOf } from '../../data/sizeOf.ts'; -import { type ResolvedSnippet, snip } from '../../data/snippet.ts'; +import { type ResolvedSnippet, snip } from '../../tgsl/snippet.ts'; import type { WgslTexture, WgslTextureDepth2d, diff --git a/packages/typegpu/src/core/rawCodeSnippet/tgpuRawCodeSnippet.ts b/packages/typegpu/src/core/rawCodeSnippet/tgpuRawCodeSnippet.ts index 573b6aa4e8..a6d18b1b5f 100644 --- a/packages/typegpu/src/core/rawCodeSnippet/tgpuRawCodeSnippet.ts +++ b/packages/typegpu/src/core/rawCodeSnippet/tgpuRawCodeSnippet.ts @@ -1,5 +1,5 @@ import type { AnyData } from '../../data/dataTypes.ts'; -import { type Origin, type ResolvedSnippet, snip } from '../../data/snippet.ts'; +import { type Origin, type ResolvedSnippet, snip } from '../../tgsl/snippet.ts'; import type { BaseData } from '../../data/wgslTypes.ts'; import { inCodegenMode } from '../../execMode.ts'; import type { InferGPU } from '../../shared/repr.ts'; diff --git a/packages/typegpu/src/core/resolve/namespace.ts b/packages/typegpu/src/core/resolve/namespace.ts index f112cd4fb0..b65b70835a 100644 --- a/packages/typegpu/src/core/resolve/namespace.ts +++ b/packages/typegpu/src/core/resolve/namespace.ts @@ -1,4 +1,4 @@ -import type { ResolvedSnippet } from '../../data/snippet.ts'; +import type { ResolvedSnippet } from '../../tgsl/snippet.ts'; import { type NameRegistry, RandomNameRegistry, StrictNameRegistry } from '../../nameRegistry.ts'; import { getName } from '../../shared/meta.ts'; import { $internal } from '../../shared/symbols.ts'; diff --git a/packages/typegpu/src/core/resolve/stitch.ts b/packages/typegpu/src/core/resolve/stitch.ts index 912c81d93a..d48d1e9c3a 100644 --- a/packages/typegpu/src/core/resolve/stitch.ts +++ b/packages/typegpu/src/core/resolve/stitch.ts @@ -1,4 +1,4 @@ -import { isSnippet, type Snippet } from '../../data/snippet.ts'; +import { isSnippet, type Snippet } from '../../tgsl/snippet.ts'; import { getResolutionCtx } from '../../execMode.ts'; import type { ResolutionCtx } from '../../types.ts'; diff --git a/packages/typegpu/src/core/resolve/tgpuResolve.ts b/packages/typegpu/src/core/resolve/tgpuResolve.ts index ab3aae7e08..bb8592231a 100644 --- a/packages/typegpu/src/core/resolve/tgpuResolve.ts +++ b/packages/typegpu/src/core/resolve/tgpuResolve.ts @@ -1,4 +1,4 @@ -import { type ResolvedSnippet, snip } from '../../data/snippet.ts'; +import { type ResolvedSnippet, snip } from '../../tgsl/snippet.ts'; import { Void } from '../../data/wgslTypes.ts'; import { type ResolutionResult, resolve as resolveImpl } from '../../resolutionCtx.ts'; import { $internal, $resolve } from '../../shared/symbols.ts'; diff --git a/packages/typegpu/src/core/sampler/sampler.ts b/packages/typegpu/src/core/sampler/sampler.ts index 4daaf1c917..27668ce52e 100644 --- a/packages/typegpu/src/core/sampler/sampler.ts +++ b/packages/typegpu/src/core/sampler/sampler.ts @@ -1,5 +1,5 @@ import type { WgslComparisonSamplerProps, WgslSamplerProps } from '../../data/sampler.ts'; -import { type ResolvedSnippet, snip } from '../../data/snippet.ts'; +import { type ResolvedSnippet, snip } from '../../tgsl/snippet.ts'; import type { TgpuNamable } from '../../shared/meta.ts'; import { getName, setName } from '../../shared/meta.ts'; import type { Infer } from '../../shared/repr.ts'; diff --git a/packages/typegpu/src/core/slot/accessor.ts b/packages/typegpu/src/core/slot/accessor.ts index 96b611f6bd..f6b3976641 100644 --- a/packages/typegpu/src/core/slot/accessor.ts +++ b/packages/typegpu/src/core/slot/accessor.ts @@ -1,6 +1,6 @@ import { type AnyData, isData } from '../../data/dataTypes.ts'; import { schemaCallWrapper } from '../../data/schemaCallWrapper.ts'; -import { isSnippet, type ResolvedSnippet, snip } from '../../data/snippet.ts'; +import { isSnippet, type ResolvedSnippet, snip } from '../../tgsl/snippet.ts'; import type { BaseData } from '../../data/wgslTypes.ts'; import { getResolutionCtx, inCodegenMode } from '../../execMode.ts'; import { getName, hasTinyestMetadata, setName } from '../../shared/meta.ts'; diff --git a/packages/typegpu/src/core/texture/externalTexture.ts b/packages/typegpu/src/core/texture/externalTexture.ts index c9d457c48b..868e6a3f6f 100644 --- a/packages/typegpu/src/core/texture/externalTexture.ts +++ b/packages/typegpu/src/core/texture/externalTexture.ts @@ -5,7 +5,7 @@ import { textureExternal, type WgslExternalTexture } from '../../data/texture.ts import { valueProxyHandler } from '../valueProxyUtils.ts'; import { inCodegenMode } from '../../execMode.ts'; import type { ResolutionCtx, SelfResolvable } from '../../types.ts'; -import { type ResolvedSnippet, snip } from '../../data/snippet.ts'; +import { type ResolvedSnippet, snip } from '../../tgsl/snippet.ts'; import type { Infer } from '../../shared/repr.ts'; // ---------- diff --git a/packages/typegpu/src/core/texture/texture.ts b/packages/typegpu/src/core/texture/texture.ts index 27923995d6..da66fe80a0 100644 --- a/packages/typegpu/src/core/texture/texture.ts +++ b/packages/typegpu/src/core/texture/texture.ts @@ -7,7 +7,7 @@ import { type WgslTextureProps, } from '../../data/texture.ts'; import { inCodegenMode } from '../../execMode.ts'; -import { type ResolvedSnippet, snip } from '../../data/snippet.ts'; +import { type ResolvedSnippet, snip } from '../../tgsl/snippet.ts'; import type { F32, Vec4f, Vec4i, Vec4u } from '../../data/wgslTypes.ts'; import type { TgpuNamable } from '../../shared/meta.ts'; import { getName, setName } from '../../shared/meta.ts'; diff --git a/packages/typegpu/src/core/unroll/tgpuUnroll.ts b/packages/typegpu/src/core/unroll/tgpuUnroll.ts index 0a1756824b..9d640ee066 100644 --- a/packages/typegpu/src/core/unroll/tgpuUnroll.ts +++ b/packages/typegpu/src/core/unroll/tgpuUnroll.ts @@ -2,7 +2,7 @@ import { stitch } from '../resolve/stitch.ts'; import { $gpuCallable, $internal, $resolve } from '../../../src/shared/symbols.ts'; import { setName } from '../../../src/shared/meta.ts'; import type { DualFn } from '../../../src/types.ts'; -import { type ResolvedSnippet, snip, type Snippet } from '../../../src/data/snippet.ts'; +import { type ResolvedSnippet, snip, type Snippet } from '../../tgsl/snippet.ts'; import type { ResolutionCtx, SelfResolvable } from '../../../src/types.ts'; import type { BaseData } from '../../data/wgslTypes.ts'; diff --git a/packages/typegpu/src/core/valueProxyUtils.ts b/packages/typegpu/src/core/valueProxyUtils.ts index ad401ea46e..8e308bd34b 100644 --- a/packages/typegpu/src/core/valueProxyUtils.ts +++ b/packages/typegpu/src/core/valueProxyUtils.ts @@ -1,4 +1,4 @@ -import type { Snippet } from '../data/snippet.ts'; +import type { Snippet } from '../tgsl/snippet.ts'; import { getGPUValue } from '../getGPUValue.ts'; import { $internal, $ownSnippet, $resolve } from '../shared/symbols.ts'; import { accessIndex } from '../tgsl/accessIndex.ts'; diff --git a/packages/typegpu/src/core/variable/tgpuVariable.ts b/packages/typegpu/src/core/variable/tgpuVariable.ts index 2f34a523bd..5b321c8f05 100644 --- a/packages/typegpu/src/core/variable/tgpuVariable.ts +++ b/packages/typegpu/src/core/variable/tgpuVariable.ts @@ -1,5 +1,5 @@ import type { AnyData } from '../../data/dataTypes.ts'; -import { type ResolvedSnippet, snip } from '../../data/snippet.ts'; +import { type ResolvedSnippet, snip } from '../../tgsl/snippet.ts'; import { type BaseData, isNaturallyEphemeral } from '../../data/wgslTypes.ts'; import { IllegalVarAccessError } from '../../errors.ts'; import { getExecMode, isInsideTgpuFn } from '../../execMode.ts'; diff --git a/packages/typegpu/src/data/autoStruct.ts b/packages/typegpu/src/data/autoStruct.ts index 647d13b79c..5831c43363 100644 --- a/packages/typegpu/src/data/autoStruct.ts +++ b/packages/typegpu/src/data/autoStruct.ts @@ -3,7 +3,7 @@ import { isValidProp } from '../nameRegistry.ts'; import { getName, setName } from '../shared/meta.ts'; import { $internal, $repr, $resolve } from '../shared/symbols.ts'; import type { ResolutionCtx, SelfResolvable } from '../types.ts'; -import type { ResolvedSnippet } from './snippet.ts'; +import type { ResolvedSnippet } from '../tgsl/snippet.ts'; import type { BaseData, WgslStruct } from './wgslTypes.ts'; /** diff --git a/packages/typegpu/src/data/dataTypes.ts b/packages/typegpu/src/data/dataTypes.ts index 5cac3ebd0a..1597cdb059 100644 --- a/packages/typegpu/src/data/dataTypes.ts +++ b/packages/typegpu/src/data/dataTypes.ts @@ -27,7 +27,7 @@ import { $internal } from '../shared/symbols.ts'; import type { Prettify } from '../shared/utilityTypes.ts'; import { vertexFormats } from '../shared/vertexFormat.ts'; import type { WgslExternalTexture, WgslStorageTexture, WgslTexture } from './texture.ts'; -import type { Snippet } from './snippet.ts'; +import type { Snippet } from '../tgsl/snippet.ts'; import type { PackedData } from './vertexFormatData.ts'; import * as wgsl from './wgslTypes.ts'; import type { WgslComparisonSampler, WgslSampler } from './sampler.ts'; @@ -145,13 +145,6 @@ export function undecorate(data: BaseData): BaseData { return data; } -export function unptr(data: BaseData | UnknownData): BaseData | UnknownData { - if (wgsl.isPtr(data)) { - return data.inner; - } - return data; -} - const looseTypeLiterals = ['unstruct', 'disarray', 'loose-decorated', ...vertexFormats] as const; export type LooseTypeLiteral = (typeof looseTypeLiterals)[number]; @@ -233,9 +226,6 @@ export type AnyConcreteData = Exclude< | WgslComparisonSampler >; -export const UnknownData = Symbol('UNKNOWN'); -export type UnknownData = typeof UnknownData; - export class InfixDispatch { readonly name: string; readonly lhs: Snippet; diff --git a/packages/typegpu/src/data/matrix.ts b/packages/typegpu/src/data/matrix.ts index b2fd9b3717..7f223635ed 100644 --- a/packages/typegpu/src/data/matrix.ts +++ b/packages/typegpu/src/data/matrix.ts @@ -7,7 +7,7 @@ import { $internal, $resolve } from '../shared/symbols.ts'; import { numericLiteralToSnippet } from '../tgsl/generationHelpers.ts'; import type { ResolutionCtx, SelfResolvable } from '../types.ts'; import { f32 } from './numeric.ts'; -import { type ResolvedSnippet } from './snippet.ts'; +import { type ResolvedSnippet } from '../tgsl/snippet.ts'; import { vec2f, vec3f, vec4f } from './vector.ts'; import { type BaseData, diff --git a/packages/typegpu/src/data/ptr.ts b/packages/typegpu/src/data/ptr.ts index ed1e76eade..b1170bafc8 100644 --- a/packages/typegpu/src/data/ptr.ts +++ b/packages/typegpu/src/data/ptr.ts @@ -1,5 +1,5 @@ import { $internal } from '../shared/symbols.ts'; -import { type Origin, type OriginToPtrParams, originToPtrParams } from './snippet.ts'; +import { type Origin, type OriginToPtrParams, originToPtrParams } from '../tgsl/snippet.ts'; import type { Access, AddressSpace, BaseData, Ptr, StorableData } from './wgslTypes.ts'; export function ptrFn(inner: T): Ptr<'function', T, 'read-write'> { diff --git a/packages/typegpu/src/data/ref.ts b/packages/typegpu/src/data/ref.ts index cd30969bbb..f92785eebd 100644 --- a/packages/typegpu/src/data/ref.ts +++ b/packages/typegpu/src/data/ref.ts @@ -1,12 +1,12 @@ import { stitch } from '../core/resolve/stitch.ts'; import { WgslTypeError } from '../errors.ts'; +import { isPtrType, type PtrBit } from '../shaderbit/typeBits.ts'; import { setName } from '../shared/meta.ts'; import { $gpuCallable, $internal, $ownSnippet, $resolve } from '../shared/symbols.ts'; import type { DualFn, SelfResolvable } from '../types.ts'; -import { UnknownData } from './dataTypes.ts'; import { createPtrFromOrigin, explicitFrom } from './ptr.ts'; -import { type ResolvedSnippet, snip, type Snippet } from './snippet.ts'; -import { isNaturallyEphemeral, isPtr, type Ptr, type StorableData } from './wgslTypes.ts'; +import { type ResolvedSnippet, snip, type Snippet, UnknownData } from '../tgsl/snippet.ts'; +import { isNaturallyEphemeral, isPtr, type StorableData } from './wgslTypes.ts'; // ---------- // Public API @@ -143,9 +143,9 @@ export class RefOperator implements SelfResolvable { readonly [$internal]: true; readonly snippet: Snippet; - readonly #ptrType: Ptr | undefined; + readonly #ptrType: PtrBit | undefined; - constructor(snippet: Snippet, ptrType: Ptr | undefined) { + constructor(snippet: Snippet, ptrType: PtrBit | undefined) { this[$internal] = true; this.snippet = snippet; this.#ptrType = ptrType; @@ -167,7 +167,7 @@ export class RefOperator implements SelfResolvable { } export function derefSnippet(snippet: Snippet): Snippet { - if (!isPtr(snippet.dataType)) { + if (!isPtrType(snippet.dataType)) { return snippet; } diff --git a/packages/typegpu/src/data/schemaCallWrapper.ts b/packages/typegpu/src/data/schemaCallWrapper.ts index 1cbf7b65f5..ff8efb1a26 100644 --- a/packages/typegpu/src/data/schemaCallWrapper.ts +++ b/packages/typegpu/src/data/schemaCallWrapper.ts @@ -1,6 +1,6 @@ import { $cast, $gpuCallable } from '../shared/symbols.ts'; import { type GPUCallable, hasCast, isGPUCallable, type ResolutionCtx } from '../types.ts'; -import type { Snippet } from './snippet.ts'; +import type { Snippet } from '../tgsl/snippet.ts'; import type { BaseData } from './wgslTypes.ts'; /** diff --git a/packages/typegpu/src/data/vectorImpl.ts b/packages/typegpu/src/data/vectorImpl.ts index abb714d267..bf5d26c356 100644 --- a/packages/typegpu/src/data/vectorImpl.ts +++ b/packages/typegpu/src/data/vectorImpl.ts @@ -2,7 +2,7 @@ import { $internal, $resolve } from '../shared/symbols.ts'; import { numericLiteralToSnippet } from '../tgsl/generationHelpers.ts'; import type { ResolutionCtx, SelfResolvable } from '../types.ts'; import { bool, f16, f32, i32, u32 } from './numeric.ts'; -import { type ResolvedSnippet } from './snippet.ts'; +import { type ResolvedSnippet } from '../tgsl/snippet.ts'; import { WORKAROUND_getSchema, type BaseData, type VecKind } from './wgslTypes.ts'; type ElementSchema = BaseData & ((v?: S) => S); diff --git a/packages/typegpu/src/data/vertexFormatData.ts b/packages/typegpu/src/data/vertexFormatData.ts index 5a4a8c517d..5d5280d9e7 100644 --- a/packages/typegpu/src/data/vertexFormatData.ts +++ b/packages/typegpu/src/data/vertexFormatData.ts @@ -6,7 +6,7 @@ import { f32, i32, u32 } from './numeric.ts'; import { vec2f, vec2i, vec2u, vec3f, vec3i, vec3u, vec4f, vec4i, vec4u } from './vector.ts'; import type { WithCast } from '../types.ts'; import { schemaCallWrapper, schemaCallWrapperGPU } from './schemaCallWrapper.ts'; -import type { Snippet } from './snippet.ts'; +import type { Snippet } from '../tgsl/snippet.ts'; import type { BaseData, F16, diff --git a/packages/typegpu/src/resolutionCtx.ts b/packages/typegpu/src/resolutionCtx.ts index 5b3daa0067..b7ec2ee00a 100644 --- a/packages/typegpu/src/resolutionCtx.ts +++ b/packages/typegpu/src/resolutionCtx.ts @@ -15,7 +15,7 @@ import { import { getAttributesString } from './data/attributes.ts'; import { isData, undecorate, UnknownData } from './data/dataTypes.ts'; import { bool } from './data/numeric.ts'; -import { type ResolvedSnippet, snip, type Snippet } from './data/snippet.ts'; +import { type ResolvedSnippet, snip, type Snippet } from './tgsl/snippet.ts'; import { type BaseData, isPtr, isWgslArray, isWgslStruct, Void } from './data/wgslTypes.ts'; import { invariant, MissingSlotValueError, ResolutionError, WgslTypeError } from './errors.ts'; import { provideCtx, topLevelState } from './execMode.ts'; diff --git a/packages/typegpu/src/shaderbit/compound.ts b/packages/typegpu/src/shaderbit/compound.ts new file mode 100644 index 0000000000..5b2993bfc3 --- /dev/null +++ b/packages/typegpu/src/shaderbit/compound.ts @@ -0,0 +1,18 @@ +export interface CompoundBit { + '~shaderbit:wgsl': { + reduce(): T; + }; +} + +export type ReducibleTo = CompoundBit | T; + +export function isCompoundBit(bit: unknown): bit is CompoundBit { + return !!(bit as CompoundBit)['~shaderbit:wgsl']; +} + +export function reduceIfCompound(bit: ReducibleTo): T { + if (isCompoundBit(bit)) { + return bit['~shaderbit:wgsl'].reduce(); + } + return bit as T; +} diff --git a/packages/typegpu/src/shaderbit/index.ts b/packages/typegpu/src/shaderbit/index.ts new file mode 100644 index 0000000000..6bcd9e5173 --- /dev/null +++ b/packages/typegpu/src/shaderbit/index.ts @@ -0,0 +1,2 @@ +export * from './typeBits.ts'; +export * from './compound.ts'; diff --git a/packages/typegpu/src/shaderbit/typeBits.ts b/packages/typegpu/src/shaderbit/typeBits.ts new file mode 100644 index 0000000000..83e8c6b7aa --- /dev/null +++ b/packages/typegpu/src/shaderbit/typeBits.ts @@ -0,0 +1,178 @@ +// Decorated types don't exist on the level of type bits, they're a property of struct fields and function arguments instead, +// which simplifies their handling a lot in the type system. + +export interface AttributeBit { + readonly name: string; + readonly params: (string | number)[][]; +} + +export interface StructPropertyBit< + TType extends TypeBit = TypeBit, + TAttribs extends AttributeBit[] = AttributeBit[], +> { + readonly type: TType; + readonly attribs: TAttribs; +} + +export interface StructBit { + readonly kind: 'struct'; + readonly fields: Record; +} + +export interface ArrayBit { + readonly kind: 'array'; + readonly elem: TypeBit; + readonly count: number; +} + +export interface PtrBit { + readonly kind: 'ptr'; + readonly inner: TypeBit; +} + +export type TypeBit = + | 'abstractInt' + | 'abstractFloat' + | 'bool' + | 'f32' + | 'f16' + | 'i32' + | 'u32' + | 'vec2f' + | 'vec2h' + | 'vec2i' + | 'vec2u' + | 'vec2b' + | 'vec3f' + | 'vec3h' + | 'vec3i' + | 'vec3u' + | 'vec3b' + | 'vec4f' + | 'vec4h' + | 'vec4i' + | 'vec4u' + | 'vec4b' + | 'mat2x2f' + | 'mat3x3f' + | 'mat4x4f' + | StructBit + | ArrayBit + | PtrBit; + +export function isVectorType(type: TypeBit): boolean { + return ( + type === 'vec2f' || + type === 'vec2h' || + type === 'vec2i' || + type === 'vec2u' || + type === 'vec2b' || + type === 'vec3f' || + type === 'vec3h' || + type === 'vec3i' || + type === 'vec3u' || + type === 'vec3b' || + type === 'vec4f' || + type === 'vec4h' || + type === 'vec4i' || + type === 'vec4u' || + type === 'vec4b' + ); +} + +export function areTypesEqual(a: TypeBit, b: TypeBit): boolean { + if (a === b) return true; + if (typeof a === 'string' || typeof b === 'string') return a === b; + if (a.kind !== b.kind) return false; + if (a.kind === 'struct') { + return areStructTypesEqual(a as StructBit, b as StructBit); + } + if (a.kind === 'array') { + const aArray = a as ArrayBit; + const bArray = b as ArrayBit; + return areTypesEqual(aArray.elem, bArray.elem) && aArray.count === bArray.count; + } + return false; +} + +export function getVectorElementCount(type: TypeBit): number { + switch (type) { + case 'vec2f': + case 'vec2h': + case 'vec2i': + case 'vec2u': + case 'vec2b': + return 2; + case 'vec3f': + case 'vec3h': + case 'vec3i': + case 'vec3u': + case 'vec3b': + return 3; + case 'vec4f': + case 'vec4h': + case 'vec4i': + case 'vec4u': + case 'vec4b': + return 4; + default: + return 1; + } + return 1; +} + +export function isPtrType(type: unknown): type is PtrBit { + return (type as PtrBit)?.kind === 'ptr'; +} + +export function isNumericType( + type: unknown, +): type is 'abstractInt' | 'abstractFloat' | 'f32' | 'f16' | 'i32' | 'u32' { + return ( + type === 'abstractInt' || + type === 'abstractFloat' || + type === 'f32' || + type === 'f16' || + type === 'i32' || + type === 'u32' + ); +} + +export function getVectorPrimitive( + type: TypeBit, +): 'f32' | 'f16' | 'i32' | 'u32' | 'bool' | undefined { + switch (type) { + case 'vec2f': + case 'vec3f': + case 'vec4f': + return 'f32'; + case 'vec2h': + case 'vec3h': + case 'vec4h': + return 'f16'; + case 'vec2i': + case 'vec3i': + case 'vec4i': + return 'i32'; + case 'vec2u': + case 'vec3u': + case 'vec4u': + return 'u32'; + case 'vec2b': + case 'vec3b': + case 'vec4b': + return 'bool'; + default: + return undefined; + } +} + +function areStructTypesEqual(a: StructBit, b: StructBit): boolean { + if (Object.keys(a.fields).length !== Object.keys(b.fields).length) return false; + for (const [name, aField] of Object.entries(a.fields)) { + const bField = b.fields[name]; + // TODO: Compare attributes as well + if (!bField || !areTypesEqual(aField.type, bField.type)) return false; + } + return true; +} diff --git a/packages/typegpu/src/std/boolean.ts b/packages/typegpu/src/std/boolean.ts index bcb74ff623..2f31344666 100644 --- a/packages/typegpu/src/std/boolean.ts +++ b/packages/typegpu/src/std/boolean.ts @@ -1,7 +1,7 @@ import { dualImpl } from '../core/function/dualImpl.ts'; import { stitch } from '../core/resolve/stitch.ts'; import { bool, f32 } from '../data/numeric.ts'; -import { isSnippetNumeric, snip } from '../data/snippet.ts'; +import { isSnippetNumeric, snip } from '../tgsl/snippet.ts'; import { vec2b, vec3b, vec4b } from '../data/vector.ts'; import { VectorOps } from '../data/vectorOps.ts'; import { diff --git a/packages/typegpu/src/std/numeric.ts b/packages/typegpu/src/std/numeric.ts index ed60310628..9ab836e4ea 100644 --- a/packages/typegpu/src/std/numeric.ts +++ b/packages/typegpu/src/std/numeric.ts @@ -3,7 +3,7 @@ import { stitch } from '../core/resolve/stitch.ts'; import { mat2x2f, mat3x3f, mat4x4f } from '../data/matrix.ts'; import { smoothstepScalar } from '../data/numberOps.ts'; import { abstractFloat, abstractInt, f16, f32, i32, u32 } from '../data/numeric.ts'; -import type { Snippet } from '../data/snippet.ts'; +import type { Snippet } from '../tgsl/snippet.ts'; import { abstruct } from '../data/struct.ts'; import { vec2f, diff --git a/packages/typegpu/src/tgsl/accessIndex.ts b/packages/typegpu/src/tgsl/accessIndex.ts index 6dd00045e5..943922af55 100644 --- a/packages/typegpu/src/tgsl/accessIndex.ts +++ b/packages/typegpu/src/tgsl/accessIndex.ts @@ -1,7 +1,7 @@ import { stitch } from '../core/resolve/stitch.ts'; import { isDisarray, MatrixColumnsAccess, UnknownData } from '../data/dataTypes.ts'; import { derefSnippet } from '../data/ref.ts'; -import { isEphemeralSnippet, type Origin, snip, type Snippet } from '../data/snippet.ts'; +import { isEphemeralSnippet, type Origin, snip, type Snippet } from './snippet.ts'; import { vec2f, vec3f, vec4f } from '../data/vector.ts'; import { type BaseData, diff --git a/packages/typegpu/src/tgsl/accessProp.ts b/packages/typegpu/src/tgsl/accessProp.ts index b264a154ba..f91c0c18f6 100644 --- a/packages/typegpu/src/tgsl/accessProp.ts +++ b/packages/typegpu/src/tgsl/accessProp.ts @@ -10,7 +10,7 @@ import { } from '../data/dataTypes.ts'; import { abstractInt, bool, f16, f32, i32, u32 } from '../data/numeric.ts'; import { derefSnippet } from '../data/ref.ts'; -import { isEphemeralSnippet, snip, type Snippet } from '../data/snippet.ts'; +import { isEphemeralSnippet, snip, type Snippet } from './snippet.ts'; import { vec2b, vec2f, diff --git a/packages/typegpu/src/tgsl/consoleLog/logGenerator.ts b/packages/typegpu/src/tgsl/consoleLog/logGenerator.ts index 889d2da43b..5f1b2d7c36 100644 --- a/packages/typegpu/src/tgsl/consoleLog/logGenerator.ts +++ b/packages/typegpu/src/tgsl/consoleLog/logGenerator.ts @@ -6,7 +6,7 @@ import { arrayOf } from '../../data/array.ts'; import { atomic } from '../../data/atomic.ts'; import { UnknownData } from '../../data/dataTypes.ts'; import { u32 } from '../../data/numeric.ts'; -import { snip, type Snippet } from '../../data/snippet.ts'; +import { snip, type Snippet } from '../snippet.ts'; import { struct } from '../../data/struct.ts'; import { type AnyWgslData, diff --git a/packages/typegpu/src/tgsl/consoleLog/types.ts b/packages/typegpu/src/tgsl/consoleLog/types.ts index f694bd3387..6457e6b7d9 100644 --- a/packages/typegpu/src/tgsl/consoleLog/types.ts +++ b/packages/typegpu/src/tgsl/consoleLog/types.ts @@ -1,5 +1,5 @@ import type { TgpuMutable } from '../../core/buffer/bufferShorthand.ts'; -import type { Snippet } from '../../data/snippet.ts'; +import type { Snippet } from '../snippet.ts'; import type { AnyWgslData, Atomic, U32, WgslArray, WgslStruct } from '../../data/wgslTypes.ts'; import type { GenerationCtx } from '../generationHelpers.ts'; diff --git a/packages/typegpu/src/tgsl/conversion.ts b/packages/typegpu/src/tgsl/conversion.ts index 0d8ae68163..75487ba313 100644 --- a/packages/typegpu/src/tgsl/conversion.ts +++ b/packages/typegpu/src/tgsl/conversion.ts @@ -1,17 +1,23 @@ +import { + areTypesEqual, + getVectorElementCount, + getVectorPrimitive, + isPtrType, + isVectorType, + type StructBit, + type TypeBit, +} from '#shaderbit'; import { stitch } from '../core/resolve/stitch.ts'; import { UnknownData } from '../data/dataTypes.ts'; -import { undecorate } from '../data/dataTypes.ts'; import { derefSnippet, RefOperator } from '../data/ref.ts'; import { schemaCallWrapperGPU } from '../data/schemaCallWrapper.ts'; -import { snip, type Snippet } from '../data/snippet.ts'; +import { snip, type Snippet } from './snippet.ts'; import { - type AnyWgslData, type BaseData, type F16, type F32, type I32, isMat, - isPtr, isVec, type Ptr, type U32, @@ -26,7 +32,7 @@ import type { ResolutionCtx } from '../types.ts'; type ConversionAction = 'ref' | 'deref' | 'cast' | 'none'; type ConversionRankInfo = - | { rank: number; action: 'cast'; targetType: BaseData } + | { rank: number; action: 'cast'; targetType: TypeBit } | { rank: number; action: Exclude }; const INFINITE_RANK: ConversionRankInfo = { @@ -34,41 +40,38 @@ const INFINITE_RANK: ConversionRankInfo = { action: 'none', }; -function getAutoConversionRank(src: BaseData, dest: BaseData): ConversionRankInfo { - const trueSrc = undecorate(src); - const trueDst = undecorate(dest); - - if (trueSrc.type === trueDst.type) { +function getAutoConversionRank(src: TypeBit, dst: TypeBit): ConversionRankInfo { + if (areTypesEqual(src, dst)) { return { rank: 0, action: 'none' }; } - if (trueSrc.type === 'abstractFloat') { - if (trueDst.type === 'f32') return { rank: 1, action: 'none' }; - if (trueDst.type === 'f16') return { rank: 2, action: 'none' }; + if (src === 'abstractFloat') { + if (dst === 'f32') return { rank: 1, action: 'none' }; + if (dst === 'f16') return { rank: 2, action: 'none' }; } - if (trueSrc.type === 'abstractInt') { - if (trueDst.type === 'i32') return { rank: 3, action: 'none' }; - if (trueDst.type === 'u32') return { rank: 4, action: 'none' }; - if (trueDst.type === 'abstractFloat') return { rank: 5, action: 'none' }; - if (trueDst.type === 'f32') return { rank: 6, action: 'none' }; - if (trueDst.type === 'f16') return { rank: 7, action: 'none' }; + if (src === 'abstractInt') { + if (dst === 'i32') return { rank: 3, action: 'none' }; + if (dst === 'u32') return { rank: 4, action: 'none' }; + if (dst === 'abstractFloat') return { rank: 5, action: 'none' }; + if (dst === 'f32') return { rank: 6, action: 'none' }; + if (dst === 'f16') return { rank: 7, action: 'none' }; } if ( - isVec(trueSrc) && - isVec(trueDst) && + isVectorType(src) && + isVectorType(dst) && // Same length vectors - trueSrc.type[3] === trueDst.type[3] + getVectorElementCount(src) === getVectorElementCount(dst) ) { - return getAutoConversionRank(trueSrc.primitive, trueDst.primitive); + return getAutoConversionRank(getVectorPrimitive(src)!, getVectorPrimitive(dst)!); } if ( - isMat(trueSrc) && - isMat(trueDst) && + isMat(src) && + isMat(dst) && // Same dimensions - trueSrc.type[3] === trueDst.type[3] + src.type[3] === dst.type[3] ) { // Matrix conversion rank depends only on component type (always f32 for now) return { rank: 0, action: 'none' }; @@ -77,23 +80,17 @@ function getAutoConversionRank(src: BaseData, dest: BaseData): ConversionRankInf return INFINITE_RANK; } -function getImplicitConversionRank(src: BaseData, dest: BaseData): ConversionRankInfo { - const trueSrc = undecorate(src); - const trueDst = undecorate(dest); - +function getImplicitConversionRank(src: TypeBit, dst: TypeBit): ConversionRankInfo { if ( - isPtr(trueSrc) && + isPtrType(src) && // Only dereferencing implicit pointers, otherwise we'd have a types mismatch between TS and WGSL - trueSrc.implicit && - getAutoConversionRank(trueSrc.inner, trueDst).rank < Number.POSITIVE_INFINITY + src.implicit && + getAutoConversionRank(src.inner, dst).rank < Number.POSITIVE_INFINITY ) { return { rank: 0, action: 'deref' }; } - if ( - isPtr(trueDst) && - getAutoConversionRank(trueSrc, trueDst.inner).rank < Number.POSITIVE_INFINITY - ) { + if (isPtrType(dst) && getAutoConversionRank(src, dst.inner).rank < Number.POSITIVE_INFINITY) { return { rank: 1, action: 'ref' }; } @@ -106,9 +103,9 @@ function getImplicitConversionRank(src: BaseData, dest: BaseData): ConversionRan } as const; type PrimitiveType = keyof typeof primitivePreference; - if (trueSrc.type in primitivePreference && trueDst.type in primitivePreference) { - const srcType = trueSrc.type as PrimitiveType; - const destType = trueDst.type as PrimitiveType; + if (src.type in primitivePreference && dst.type in primitivePreference) { + const srcType = src.type as PrimitiveType; + const destType = dst.type as PrimitiveType; if (srcType !== destType) { const srcPref = primitivePreference[srcType]; @@ -116,16 +113,16 @@ function getImplicitConversionRank(src: BaseData, dest: BaseData): ConversionRan const rank = destPref < srcPref ? 10 : 20; - return { rank: rank, action: 'cast', targetType: trueDst }; + return { rank: rank, action: 'cast', targetType: dst }; } } - if (trueSrc.type === 'abstractFloat') { - if (trueDst.type === 'u32') { - return { rank: 2, action: 'cast', targetType: trueDst }; + if (src === 'abstractFloat') { + if (dst === 'u32') { + return { rank: 2, action: 'cast', targetType: dst }; } - if (trueDst.type === 'i32') { - return { rank: 1, action: 'cast', targetType: trueDst }; + if (dst === 'i32') { + return { rank: 1, action: 'cast', targetType: dst }; } } @@ -133,8 +130,8 @@ function getImplicitConversionRank(src: BaseData, dest: BaseData): ConversionRan } function getConversionRank( - src: BaseData, - dest: BaseData, + src: TypeBit, + dest: TypeBit, allowImplicit: boolean, ): ConversionRankInfo { const autoRank = getAutoConversionRank(src, dest); @@ -154,17 +151,17 @@ export type ConversionResultAction = { }; export type ConversionResult = { - targetType: BaseData; + targetType: TypeBit; actions: ConversionResultAction[]; hasImplicitConversions?: boolean; }; function findBestType( - types: BaseData[], - uniqueTypes: BaseData[], + types: TypeBit[], + uniqueTypes: TypeBit[], allowImplicit: boolean, ): ConversionResult | undefined { - let bestResult: { type: BaseData; details: ConversionRankInfo[]; sum: number } | undefined; + let bestResult: { type: TypeBit; details: ConversionRankInfo[]; sum: number } | undefined; for (const targetType of uniqueTypes) { const details: ConversionRankInfo[] = []; @@ -200,12 +197,12 @@ function findBestType( } export function getBestConversion( - types: BaseData[], - targetTypes?: BaseData[], + types: TypeBit[], + targetTypes?: TypeBit[], ): ConversionResult | undefined { if (types.length === 0) return undefined; - const uniqueTargetTypes = [...new Set((targetTypes || types).map(undecorate))]; + const uniqueTargetTypes = [...new Set(targetTypes || types)]; const explicitResult = findBestType(types, uniqueTargetTypes, false); if (explicitResult) { @@ -224,7 +221,7 @@ function applyActionToSnippet( ctx: ResolutionCtx, snippet: Snippet, action: ConversionResultAction, - targetType: BaseData, + targetType: TypeBit, ): Snippet { if (action.action === 'none') { return snip( @@ -271,7 +268,7 @@ export function unify( export function convertToCommonType( ctx: ResolutionCtx, values: T, - restrictTo?: BaseData[], + restrictTo?: TypeBit[], verbose = true, ): T | undefined { const types = values.map((value) => value.dataType); @@ -286,7 +283,7 @@ export function convertToCommonType( ); } - const conversion = getBestConversion(types as BaseData[], restrictTo); + const conversion = getBestConversion(types as TypeBit[], restrictTo); if (!conversion) { return undefined; } @@ -295,7 +292,7 @@ export function convertToCommonType( console.warn( `Implicit conversions from [\n${values .map((v) => ` ${v.value}: ${safeStringify(v.dataType)}`) - .join(',\n')}\n] to ${conversion.targetType.type} are supported, but not recommended. + .join(',\n')}\n] to ${conversion.targetType} are supported, but not recommended. Consider using explicit conversions instead.`, ); } @@ -310,7 +307,7 @@ Consider using explicit conversions instead.`, export function tryConvertSnippet( ctx: ResolutionCtx, snippet: Snippet, - targetDataTypes: BaseData | BaseData[], + targetDataTypes: TypeBit | TypeBit[], verbose = true, ): Snippet { const targets = Array.isArray(targetDataTypes) ? targetDataTypes : [targetDataTypes]; @@ -318,7 +315,7 @@ export function tryConvertSnippet( const { value, dataType, origin } = snippet; if (targets.length === 1) { - const target = targets[0] as AnyWgslData; + const target = targets[0] as TypeBit; if (target === dataType) { return snip(value, target, origin); @@ -338,22 +335,22 @@ export function tryConvertSnippet( throw new WgslTypeError( `Cannot convert value of type '${String( dataType, - )}' to any of the target types: [${targets.map((t) => t.type).join(', ')}]`, + )}' to any of the target types: [${targets.join(', ')}]`, ); } export function convertStructValues( ctx: ResolutionCtx, - structType: WgslStruct, + structType: StructBit, values: Record, ): Snippet[] { - return Object.entries(structType.propTypes).map(([key, targetType]) => { + return Object.entries(structType.fields).map(([key, prop]) => { const val = values[key]; if (!val) { throw new Error(`Missing property ${key}`); } - const converted = convertToCommonType(ctx, [val], [targetType]); + const converted = convertToCommonType(ctx, [val], [prop.type]); return converted?.[0] ?? val; }); } diff --git a/packages/typegpu/src/tgsl/forOfUtils.ts b/packages/typegpu/src/tgsl/forOfUtils.ts index bd35368b90..ea2c7c9d4d 100644 --- a/packages/typegpu/src/tgsl/forOfUtils.ts +++ b/packages/typegpu/src/tgsl/forOfUtils.ts @@ -1,5 +1,5 @@ import { UnknownData } from '../data/dataTypes.ts'; -import { isEphemeralSnippet, snip, type Snippet } from '../data/snippet.ts'; +import { isEphemeralSnippet, snip, type Snippet } from './snippet.ts'; import { stitch } from '../core/resolve/stitch.ts'; import * as wgsl from '../data/wgslTypes.ts'; import { i32, u32 } from '../data/numeric.ts'; diff --git a/packages/typegpu/src/tgsl/generationHelpers.ts b/packages/typegpu/src/tgsl/generationHelpers.ts index d4900b86e7..dc46f05f8d 100644 --- a/packages/typegpu/src/tgsl/generationHelpers.ts +++ b/packages/typegpu/src/tgsl/generationHelpers.ts @@ -7,7 +7,7 @@ import { type ResolvedSnippet, snip, type Snippet, -} from '../data/snippet.ts'; +} from './snippet.ts'; import { type AnyWgslData, type BaseData, diff --git a/packages/typegpu/src/tgsl/shaderGenerator.ts b/packages/typegpu/src/tgsl/shaderGenerator.ts index e482b03cc8..fc888ce345 100644 --- a/packages/typegpu/src/tgsl/shaderGenerator.ts +++ b/packages/typegpu/src/tgsl/shaderGenerator.ts @@ -1,7 +1,7 @@ import type { Block } from 'tinyest'; import type { BaseData } from '../data/wgslTypes.ts'; import type { GenerationCtx } from './generationHelpers.ts'; -import type { ResolvedSnippet, Snippet } from '../data/snippet.ts'; +import type { ResolvedSnippet, Snippet } from './snippet.ts'; /** * **NOTE: This is an unstable API and may change in the future.** diff --git a/packages/typegpu/src/tgsl/shaderGenerator_members.ts b/packages/typegpu/src/tgsl/shaderGenerator_members.ts index a33ac92b24..5107cba1da 100644 --- a/packages/typegpu/src/tgsl/shaderGenerator_members.ts +++ b/packages/typegpu/src/tgsl/shaderGenerator_members.ts @@ -2,3 +2,4 @@ export { UnknownData } from '../data/dataTypes.ts'; // types export type { ResolutionCtx } from '../types.ts'; +./snippet.ts./snippet.ts diff --git a/packages/typegpu/src/tgsl/shellless.ts b/packages/typegpu/src/tgsl/shellless.ts index 8ff5ab48b6..3c2cb47c79 100644 --- a/packages/typegpu/src/tgsl/shellless.ts +++ b/packages/typegpu/src/tgsl/shellless.ts @@ -1,7 +1,7 @@ import { createShelllessImpl, type ShelllessImpl } from '../core/function/shelllessImpl.ts'; import { UnknownData } from '../data/dataTypes.ts'; import { RefOperator } from '../data/ref.ts'; -import type { Snippet } from '../data/snippet.ts'; +import type { Snippet } from './snippet.ts'; import { type BaseData, isPtr, isWgslArray, isWgslStruct } from '../data/wgslTypes.ts'; import { WgslTypeError } from '../errors.ts'; import { getMetaData, getName } from '../shared/meta.ts'; diff --git a/packages/typegpu/src/data/snippet.ts b/packages/typegpu/src/tgsl/snippet.ts similarity index 74% rename from packages/typegpu/src/data/snippet.ts rename to packages/typegpu/src/tgsl/snippet.ts index fe658ef99d..7650d861bf 100644 --- a/packages/typegpu/src/data/snippet.ts +++ b/packages/typegpu/src/tgsl/snippet.ts @@ -1,7 +1,22 @@ -import { undecorate } from './dataTypes.ts'; -import type { UnknownData } from './dataTypes.ts'; +// TODO: Move to packages/typegpu/src/tgsl/, since snippets have more to do with code-gen than schema definitions. +import { isNumericType, type TypeBit } from '#shaderbit'; import { DEV } from '../shared/env.ts'; -import { type BaseData, isNumericSchema } from './wgslTypes.ts'; + +export const UnknownData = Symbol('UNKNOWN'); +export type UnknownData = typeof UnknownData; + +export interface PtrImplicitBit { + readonly kind: 'ptr-implicit'; + readonly inner: SnippetType; +} + +export function isPtrImplicitType(data: SnippetType): data is PtrImplicitBit { + return (data as PtrImplicitBit)?.kind === 'ptr-implicit'; +} + +type UsageDeterminedType = { kind: 'usage-determined-type' }; + +export type SnippetType = TypeBit | PtrImplicitBit | UsageDeterminedType | UnknownData; export type Origin = | 'uniform' @@ -70,7 +85,7 @@ export interface Snippet { * The type that `value` is assignable to (not necessary exactly inferred as). * E.g. `1.1` is assignable to `f32`, but `1.1` itself is an abstract float */ - readonly dataType: BaseData | UnknownData; + readonly dataType: SnippetType; readonly origin: Origin; } @@ -80,7 +95,7 @@ export interface ResolvedSnippet { * The type that `value` is assignable to (not necessary exactly inferred as). * E.g. `1.1` is assignable to `f32`, but `1.1` itself is an abstract float */ - readonly dataType: BaseData; + readonly dataType: Exclude; readonly origin: Origin; } @@ -88,10 +103,10 @@ export type MapValueToSnippet = { [K in keyof T]: Snippet }; class SnippetImpl implements Snippet { readonly value: unknown; - readonly dataType: BaseData | UnknownData; + readonly dataType: SnippetType; readonly origin: Origin; - constructor(value: unknown, dataType: BaseData | UnknownData, origin: Origin) { + constructor(value: unknown, dataType: SnippetType, origin: Origin) { this.value = value; this.dataType = dataType; this.origin = origin; @@ -103,14 +118,18 @@ export function isSnippet(value: unknown): value is Snippet { } export function isSnippetNumeric(snippet: Snippet) { - return isNumericSchema(snippet.dataType); + return isNumericType(snippet.dataType); } -export function snip(value: string, dataType: BaseData, origin: Origin): ResolvedSnippet; -export function snip(value: unknown, dataType: BaseData | UnknownData, origin: Origin): Snippet; +export function snip( + value: string, + dataType: Exclude, + origin: Origin, +): ResolvedSnippet; +export function snip(value: unknown, dataType: SnippetType, origin: Origin): Snippet; export function snip( value: unknown, - dataType: BaseData | UnknownData, + dataType: SnippetType, origin: Origin, ): Snippet | ResolvedSnippet { if (DEV && isSnippet(value)) { @@ -118,10 +137,5 @@ export function snip( throw new Error('Cannot nest snippets'); } - return new SnippetImpl( - value, - // We don't care about attributes in snippet land, so we discard that information. - undecorate(dataType as BaseData), - origin, - ); + return new SnippetImpl(value, dataType, origin); } diff --git a/packages/typegpu/src/tgsl/snippetTypeUtils.ts b/packages/typegpu/src/tgsl/snippetTypeUtils.ts new file mode 100644 index 0000000000..1abd89ceb7 --- /dev/null +++ b/packages/typegpu/src/tgsl/snippetTypeUtils.ts @@ -0,0 +1,9 @@ +import { isPtrType } from '#shaderbit'; +import { isPtrImplicitType, type SnippetType } from './snippet.ts'; + +export function unptr(data: SnippetType): SnippetType { + if (isPtrType(data) || isPtrImplicitType(data)) { + return data.inner; + } + return data; +} diff --git a/packages/typegpu/src/tgsl/wgslGenerator.ts b/packages/typegpu/src/tgsl/wgslGenerator.ts index 7c7c06d7c8..75c4f82837 100644 --- a/packages/typegpu/src/tgsl/wgslGenerator.ts +++ b/packages/typegpu/src/tgsl/wgslGenerator.ts @@ -1,14 +1,7 @@ import * as tinyest from 'tinyest'; import { stitch } from '../core/resolve/stitch.ts'; import { arrayOf } from '../data/array.ts'; -import { - type AnyData, - ConsoleLog, - InfixDispatch, - isLooseData, - UnknownData, - unptr, -} from '../data/dataTypes.ts'; +import { type AnyData, ConsoleLog, InfixDispatch, isLooseData } from '../data/dataTypes.ts'; import { bool, i32, u32 } from '../data/numeric.ts'; import { vec2u, vec3u, vec4u } from '../data/vector.ts'; import { @@ -18,8 +11,10 @@ import { type Origin, type ResolvedSnippet, snip, + UnknownData, type Snippet, -} from '../data/snippet.ts'; +} from './snippet.ts'; +import { unptr } from './snippetTypeUtils.ts'; import * as wgsl from '../data/wgslTypes.ts'; import { invariant, ResolutionError, WgslTypeError } from '../errors.ts'; import { getName } from '../shared/meta.ts'; diff --git a/packages/typegpu/src/types.ts b/packages/typegpu/src/types.ts index 1c92f8a43f..fd583a7f19 100644 --- a/packages/typegpu/src/types.ts +++ b/packages/typegpu/src/types.ts @@ -29,7 +29,7 @@ import type { TgpuExternalTexture } from './core/texture/externalTexture.ts'; import type { TgpuTexture, TgpuTextureView } from './core/texture/texture.ts'; import type { TgpuVar } from './core/variable/tgpuVariable.ts'; import { type AnyData, UnknownData } from './data/dataTypes.ts'; -import type { MapValueToSnippet, ResolvedSnippet, Snippet } from './data/snippet.ts'; +import type { MapValueToSnippet, ResolvedSnippet, Snippet } from './tgsl/snippet.ts'; import { type AnyMatInstance, type AnyVecInstance, diff --git a/packages/typegpu/tests/resolve.test.ts b/packages/typegpu/tests/resolve.test.ts index 254730def2..900e584fcf 100644 --- a/packages/typegpu/tests/resolve.test.ts +++ b/packages/typegpu/tests/resolve.test.ts @@ -4,7 +4,7 @@ import { setName } from '../src/shared/meta.ts'; import { $gpuValueOf, $internal, $ownSnippet, $resolve } from '../src/shared/symbols.ts'; import type { ResolutionCtx } from '../src/types.ts'; import { it } from 'typegpu-testing-utility'; -import { snip } from '../src/data/snippet.ts'; +import { snip } from '../src/tgsl/snippet.ts'; describe('tgpu resolve', () => { it('should resolve an external struct', () => { diff --git a/packages/typegpu/tests/tgsl/conversion.test.ts b/packages/typegpu/tests/tgsl/conversion.test.ts index ee72863801..b8ad19ec85 100644 --- a/packages/typegpu/tests/tgsl/conversion.test.ts +++ b/packages/typegpu/tests/tgsl/conversion.test.ts @@ -1,7 +1,7 @@ import { afterAll, beforeAll, describe, expect } from 'vitest'; import { abstractFloat, abstractInt } from '../../src/data/numeric.ts'; import * as d from '../../src/data/index.ts'; -import { snip, type Snippet } from '../../src/data/snippet.ts'; +import { snip, type Snippet } from '../../src/tgsl/snippet.ts'; import { convertStructValues, convertToCommonType, diff --git a/packages/typegpu/tests/tgsl/generationHelpers.test.ts b/packages/typegpu/tests/tgsl/generationHelpers.test.ts index 9a51b702c3..c9a424404a 100644 --- a/packages/typegpu/tests/tgsl/generationHelpers.test.ts +++ b/packages/typegpu/tests/tgsl/generationHelpers.test.ts @@ -1,14 +1,14 @@ import { afterEach, beforeEach, describe, expect, it } from 'vitest'; import { arrayOf } from '../../src/data/array.ts'; import { mat2x2f, mat3x3f, mat4x4f } from '../../src/data/matrix.ts'; -import { abstractFloat, abstractInt, bool, f16, f32, i32, u32 } from '../../src/data/numeric.ts'; +import { bool, f16, f32, i32, u32 } from '../../src/data/numeric.ts'; import { struct } from '../../src/data/struct.ts'; import { vec2f, vec2i, vec3f, vec3i, vec4f, vec4h } from '../../src/data/vector.ts'; import { coerceToSnippet, numericLiteralToSnippet } from '../../src/tgsl/generationHelpers.ts'; import { accessIndex } from '../../src/tgsl/accessIndex.ts'; import { accessProp } from '../../src/tgsl/accessProp.ts'; import { UnknownData } from '../../src/data/dataTypes.ts'; -import { snip } from '../../src/data/snippet.ts'; +import { snip } from '../../src/tgsl/snippet.ts'; import { INTERNAL_setCtx } from '../../src/execMode.ts'; import { ResolutionCtxImpl } from '../../src/resolutionCtx.ts'; import { namespace } from '../../src/core/resolve/namespace.ts'; @@ -27,27 +27,31 @@ describe('generationHelpers', () => { describe('numericLiteralToSnippet', () => { it('should convert numeric literals to correct snippets', () => { - expect(numericLiteralToSnippet(1)).toEqual(snip(1, abstractInt, /* origin */ 'constant')); + expect(numericLiteralToSnippet(1)).toEqual(snip(1, 'abstractInt', /* origin */ 'constant')); expect(numericLiteralToSnippet(1.1)).toEqual( - snip(1.1, abstractFloat, /* origin */ 'constant'), + snip(1.1, 'abstractFloat', /* origin */ 'constant'), ); expect(numericLiteralToSnippet(1e10)).toEqual( - snip(1e10, abstractInt, /* origin */ 'constant'), + snip(1e10, 'abstractInt', /* origin */ 'constant'), ); expect(numericLiteralToSnippet(0.5)).toEqual( - snip(0.5, abstractFloat, /* origin */ 'constant'), + snip(0.5, 'abstractFloat', /* origin */ 'constant'), ); - expect(numericLiteralToSnippet(-45)).toEqual(snip(-45, abstractInt, /* origin */ 'constant')); + expect(numericLiteralToSnippet(-45)).toEqual( + snip(-45, 'abstractInt', /* origin */ 'constant'), + ); expect(numericLiteralToSnippet(0x1a)).toEqual( - snip(0x1a, abstractInt, /* origin */ 'constant'), + snip(0x1a, 'abstractInt', /* origin */ 'constant'), ); - expect(numericLiteralToSnippet(0b101)).toEqual(snip(5, abstractInt, /* origin */ 'constant')); + expect(numericLiteralToSnippet(0b101)).toEqual( + snip(5, 'abstractInt', /* origin */ 'constant'), + ); }); }); @@ -116,7 +120,7 @@ describe('generationHelpers', () => { }); it('returns undefined otherwise', () => { - const target = snip('foo', f32, /* origin */ 'runtime'); + const target = snip('foo', 'f32', /* origin */ 'runtime'); expect(accessIndex(target, index)).toBe(undefined); }); }); @@ -125,15 +129,15 @@ describe('generationHelpers', () => { const arr = arrayOf(f32, 2); it('coerces JS numbers', () => { - expect(coerceToSnippet(1)).toEqual(snip(1, abstractInt, /* origin */ 'constant')); - expect(coerceToSnippet(2.5)).toEqual(snip(2.5, abstractFloat, /* origin */ 'constant')); - expect(coerceToSnippet(-10)).toEqual(snip(-10, abstractInt, /* origin */ 'constant')); - expect(coerceToSnippet(0.0)).toEqual(snip(0, abstractInt, /* origin */ 'constant')); + expect(coerceToSnippet(1)).toEqual(snip(1, 'abstractInt', /* origin */ 'constant')); + expect(coerceToSnippet(2.5)).toEqual(snip(2.5, 'abstractFloat', /* origin */ 'constant')); + expect(coerceToSnippet(-10)).toEqual(snip(-10, 'abstractInt', /* origin */ 'constant')); + expect(coerceToSnippet(0.0)).toEqual(snip(0, 'abstractInt', /* origin */ 'constant')); }); it('coerces JS booleans', () => { - expect(coerceToSnippet(true)).toEqual(snip(true, bool, /* origin */ 'constant')); - expect(coerceToSnippet(false)).toEqual(snip(false, bool, /* origin */ 'constant')); + expect(coerceToSnippet(true)).toEqual(snip(true, 'bool', /* origin */ 'constant')); + expect(coerceToSnippet(false)).toEqual(snip(false, 'bool', /* origin */ 'constant')); }); it(`coerces schemas to UnknownData (as they're not instance types)`, () => { diff --git a/packages/typegpu/tests/tgsl/memberAccess.test.ts b/packages/typegpu/tests/tgsl/memberAccess.test.ts index dfa33a9f34..3a8fee685c 100644 --- a/packages/typegpu/tests/tgsl/memberAccess.test.ts +++ b/packages/typegpu/tests/tgsl/memberAccess.test.ts @@ -1,7 +1,7 @@ import { describe } from 'vitest'; import { it } from 'typegpu-testing-utility'; import { expectSnippetOf } from '../utils/parseResolved.ts'; -import { snip } from '../../src/data/snippet.ts'; +import { snip } from '../../src/tgsl/snippet.ts'; import tgpu, { d } from '../../src/index.js'; describe('Member Access', () => { diff --git a/packages/typegpu/tests/tgsl/wgslGenerator.test.ts b/packages/typegpu/tests/tgsl/wgslGenerator.test.ts index 62c96fe428..0c2d81dcba 100644 --- a/packages/typegpu/tests/tgsl/wgslGenerator.test.ts +++ b/packages/typegpu/tests/tgsl/wgslGenerator.test.ts @@ -3,7 +3,7 @@ import { beforeEach, describe, expect, vi } from 'vitest'; import { namespace } from '../../src/core/resolve/namespace.ts'; import * as d from '../../src/data/index.ts'; import { abstractFloat, abstractInt } from '../../src/data/numeric.ts'; -import { snip } from '../../src/data/snippet.ts'; +import { snip } from '../../src/tgsl/snippet.ts'; import { Void, type WgslArray } from '../../src/data/wgslTypes.ts'; import { provideCtx } from '../../src/execMode.ts'; import tgpu from '../../src/index.js'; @@ -1067,7 +1067,7 @@ describe('wgslGenerator', () => { provideCtx(ctx, () => { ctx[$internal].itemStateStack.pushFunctionScope( 'normal', - [snip('idx', d.u32, /* origin */ 'runtime')], + [snip('idx', 'u32', /* origin */ 'runtime')], {}, d.f32, (astInfo.externals as () => Record)() ?? {}, diff --git a/packages/typegpu/tests/utils/parseResolved.ts b/packages/typegpu/tests/utils/parseResolved.ts index b798ff9f8c..ffd2d94df8 100644 --- a/packages/typegpu/tests/utils/parseResolved.ts +++ b/packages/typegpu/tests/utils/parseResolved.ts @@ -1,13 +1,13 @@ import type * as tinyest from 'tinyest'; import { type Assertion, expect } from 'vitest'; -import type { BaseData } from '../../src/data/index.ts'; +import type { TypeBit } from '#shaderbit'; import type { UnknownData } from '../../src/data/dataTypes.ts'; import { ResolutionCtxImpl } from '../../src/resolutionCtx.ts'; import { provideCtx } from '../../src/execMode.ts'; import { getMetaData } from '../../src/shared/meta.ts'; import wgslGenerator from '../../src/tgsl/wgslGenerator.ts'; import { namespace } from '../../src/core/resolve/namespace.ts'; -import type { Snippet } from '../../src/data/snippet.ts'; +import type { Snippet } from '../../src/tgsl/snippet.ts'; import { $internal } from '../../src/shared/symbols.ts'; import { CodegenState } from '../../src/types.ts'; @@ -64,6 +64,6 @@ export function expectSnippetOf(cb: () => unknown): Assertion { return expect(extractSnippetFromFn(cb)); } -export function expectDataTypeOf(cb: () => unknown): Assertion { - return expect(extractSnippetFromFn(cb).dataType); +export function expectDataTypeOf(cb: () => unknown): Assertion { + return expect(extractSnippetFromFn(cb).dataType); }