Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions packages/typegpu/src/core/function/tgpuFn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,17 +145,17 @@ export function isTgpuFn<Args extends BaseData[] | [], Return extends BaseData>(
value: unknown,
): value is TgpuFn<(...args: Args) => Return> {
return (
isMarkedInternal(value) &&
(value as TgpuFn<(...args: Args) => Return>)?.resourceType === 'function'
(value as TgpuFn<(...args: Args) => Return>)?.resourceType === 'function' &&
isMarkedInternal(value)
);
}

export function isGenericFn<Callback extends AnyFn>(
value: unknown,
): value is TgpuGenericFn<Callback> {
return (
isMarkedInternal(value) &&
(value as TgpuGenericFn<Callback>)?.resourceType === 'generic-function'
(value as TgpuGenericFn<Callback>)?.resourceType === 'generic-function' &&
isMarkedInternal(value)
);
}

Expand Down
4 changes: 4 additions & 0 deletions packages/typegpu/src/core/resolve/externals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ function isResolvable(value: unknown) {
*/
export function mergeFunctionExternals(fnExternals: FnExternals): ExternalMap {
const base = fnExternals.pluginProvided ?? fnExternals.userProvided ?? {};
if (fnExternals.args === undefined && fnExternals.out === undefined) {
// Nothing to merge in, and consumers never mutate the map
return base;
}
// avoid calling any of the getters
const result: ExternalMap = Object.defineProperties({}, Object.getOwnPropertyDescriptors(base));
for (const flatExternal of [fnExternals.args, fnExternals.out].filter((e) => e !== undefined)) {
Expand Down
7 changes: 5 additions & 2 deletions packages/typegpu/src/core/resolve/namespace.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import type { ResolvedSnippet } from '../../data/snippet.ts';
import { bannedTokens, builtins, templateEnumerants } from '../../nameUtils.ts';
import { $internal } from '../../shared/symbols.ts';
import { ShelllessRepository } from '../../tgsl/shellless.ts';
import type { TgpuLazy, TgpuSlot } from '../slot/slotTypes.ts';

type SlotToValueMap = Map<TgpuSlot<unknown>, unknown>;

export interface NamespaceInternal {
/**
* Global identifiers taken by resolved items. Reserved WGSL words are checked separately,
* so that creating a namespace doesn't have to copy them.
*/
readonly takenGlobalIdentifiers: Set<string>;
readonly shelllessRepo: ShelllessRepository;
readonly strategy: 'random' | 'strict';
Expand Down Expand Up @@ -36,7 +39,7 @@ class NamespaceImpl implements Namespace {
constructor(strategy: 'random' | 'strict') {
this[$internal] = {
strategy,
takenGlobalIdentifiers: new Set([...bannedTokens, ...builtins, ...templateEnumerants]),
takenGlobalIdentifiers: new Set(),
shelllessRepo: new ShelllessRepository(),
memoizedResolves: new WeakMap(),
memoizedLazy: new WeakMap(),
Expand Down
23 changes: 14 additions & 9 deletions packages/typegpu/src/core/resolve/stitch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import type { ResolutionCtx } from '../../types.ts';

type ValueOrArray<T> = T | readonly T[];

function resolvePart(ctx: ResolutionCtx, part: Snippet | string | number) {
return isSnippet(part) ? ctx.resolveSnippet(part).value : part;
}

/**
* "The reverse of snipping"
* Injects resolved snippets into a template string.
Expand All @@ -14,21 +18,22 @@ export function stitch(
) {
const ctx = getResolutionCtx() as ResolutionCtx;

function resolveSnippet(maybeSnippet: Snippet | string | number) {
return isSnippet(maybeSnippet) ? ctx.resolveSnippet(maybeSnippet).value : maybeSnippet;
}

let result = '';
for (let i = 0; i < strings.length; ++i) {
result += strings[i];
const snippet = snippets[i];
if (Array.isArray(snippet)) {
result += snippet
.filter((s) => s !== undefined)
.map(resolveSnippet)
.join(', ');
// Joining the defined elements with ', '
let first = true;
for (const element of snippet) {
if (element === undefined) {
continue;
}
result += (first ? '' : ', ') + resolvePart(ctx, element);
first = false;
}
} else if (snippet) {
result += resolveSnippet(snippet as Snippet | string | number);
result += resolvePart(ctx, snippet as Snippet | string | number);
}
}
return result;
Expand Down
19 changes: 16 additions & 3 deletions packages/typegpu/src/core/texture/texture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -743,10 +743,15 @@ class TgpuFixedTextureViewImpl<T extends WgslTexture | WgslStorageTexture>
return this;
}

// Created once, since shader code can access a view many times
#valueProxy: Infer<T> | undefined;

get [$gpuValueOf](): Infer<T> {
if (this.#valueProxy) {
return this.#valueProxy;
}
const schema = this.schema;

return new Proxy(
this.#valueProxy = new Proxy(
{
[$internal]: true,
get [$ownSnippet]() {
Expand All @@ -758,6 +763,7 @@ class TgpuFixedTextureViewImpl<T extends WgslTexture | WgslStorageTexture>
},
valueProxyHandler,
) as unknown as Infer<T>;
return this.#valueProxy;
}

get $(): Infer<T> {
Expand Down Expand Up @@ -837,9 +843,15 @@ export class TgpuLaidOutTextureViewImpl<T extends WgslTexture | WgslStorageTextu
return snip(id, this.schema, /* origin */ 'handle');
}

// Created once, since shader code can access a view many times
#valueProxy: Infer<T> | undefined;

get [$gpuValueOf](): Infer<T> {
if (this.#valueProxy) {
return this.#valueProxy;
}
const schema = this.schema;
return new Proxy(
this.#valueProxy = new Proxy(
{
[$internal]: true,
get [$ownSnippet]() {
Expand All @@ -851,6 +863,7 @@ export class TgpuLaidOutTextureViewImpl<T extends WgslTexture | WgslStorageTextu
},
valueProxyHandler,
) as unknown as Infer<T>;
return this.#valueProxy;
}

get $(): Infer<T> {
Expand Down
6 changes: 3 additions & 3 deletions packages/typegpu/src/data/dataTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ export function isLooseData(data: unknown): data is AnyLooseData {
* isDisarray(d.vec3f) // false
*/
export function isDisarray(schema: unknown): schema is Disarray {
return isMarkedInternal(schema) && (schema as Disarray)?.type === 'disarray';
return (schema as Disarray)?.type === 'disarray' && isMarkedInternal(schema);
}

/**
Expand All @@ -193,11 +193,11 @@ export function isDisarray(schema: unknown): schema is Disarray {
* isUnstruct(d.vec3f) // false
*/
export function isUnstruct(schema: unknown): schema is Unstruct {
return isMarkedInternal(schema) && (schema as Unstruct)?.type === 'unstruct';
return (schema as Unstruct)?.type === 'unstruct' && isMarkedInternal(schema);
}

export function isLooseDecorated(value: unknown): value is LooseDecorated {
return isMarkedInternal(value) && (value as LooseDecorated)?.type === 'loose-decorated';
return (value as LooseDecorated)?.type === 'loose-decorated' && isMarkedInternal(value);
}

export function getCustomAlignment(data: wgsl.BaseData): number | undefined {
Expand Down
2 changes: 1 addition & 1 deletion packages/typegpu/src/data/vertexFormatData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ export type PackedData =
| unorm8x4_bgra;

export function isPackedData(value: unknown): value is PackedData {
return isMarkedInternal(value) && packedFormats.has((value as PackedData)?.type);
return packedFormats.has((value as PackedData)?.type) && isMarkedInternal(value);
}

type U32Data = U32 | Vec2u | Vec3u | Vec4u;
Expand Down
56 changes: 28 additions & 28 deletions packages/typegpu/src/data/wgslTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1554,7 +1554,7 @@ export type AnyWgslData =

export function isVecInstance(value: unknown): value is AnyVecInstance {
const v = value as AnyVecInstance | undefined;
return isMarkedInternal(v) && typeof v.kind === 'string' && v.kind.startsWith('vec');
return typeof v?.kind === 'string' && v.kind.startsWith('vec') && isMarkedInternal(v);
}

export function isVecBoolInstance(value: unknown): value is v2b | v3b | v4b {
Expand All @@ -1563,17 +1563,17 @@ export function isVecBoolInstance(value: unknown): value is v2b | v3b | v4b {

export function isVec2(value: unknown): value is Vec2f | Vec2h | Vec2i | Vec2u {
const v = value as AnyWgslData | undefined;
return isMarkedInternal(v) && typeof v.type === 'string' && v.type.startsWith('vec2');
return typeof v?.type === 'string' && v.type.startsWith('vec2') && isMarkedInternal(v);
}

export function isVec3(value: unknown): value is Vec3f | Vec3h | Vec3i | Vec3u {
const v = value as AnyWgslData | undefined;
return isMarkedInternal(v) && typeof v.type === 'string' && v.type.startsWith('vec3');
return typeof v?.type === 'string' && v.type.startsWith('vec3') && isMarkedInternal(v);
}

export function isVec4(value: unknown): value is Vec4f | Vec4h | Vec4i | Vec4u {
const v = value as AnyWgslData | undefined;
return isMarkedInternal(v) && typeof v.type === 'string' && v.type.startsWith('vec4');
return typeof v?.type === 'string' && v.type.startsWith('vec4') && isMarkedInternal(v);
}

export function isVec(
Expand Down Expand Up @@ -1604,20 +1604,20 @@ export function isVecBool(value: unknown): value is Vec2b | Vec3b | Vec4b {
export function isMatInstance(value: unknown): value is AnyMatInstance {
const v = value as AnyMatInstance | undefined;
return (
isMarkedInternal(v) && typeof v.kind?.startsWith === 'function' && v.kind.startsWith('mat')
typeof v?.kind?.startsWith === 'function' && v.kind.startsWith('mat') && isMarkedInternal(v)
);
}

export function isMat2x2f(value: unknown): value is Mat2x2f {
return isMarkedInternal(value) && (value as AnyWgslData)?.type === 'mat2x2f';
return (value as AnyWgslData)?.type === 'mat2x2f' && isMarkedInternal(value);
}

export function isMat3x3f(value: unknown): value is Mat3x3f {
return isMarkedInternal(value) && (value as AnyWgslData)?.type === 'mat3x3f';
return (value as AnyWgslData)?.type === 'mat3x3f' && isMarkedInternal(value);
}

export function isMat4x4f(value: unknown): value is Mat4x4f {
return isMarkedInternal(value) && (value as AnyWgslData)?.type === 'mat4x4f';
return (value as AnyWgslData)?.type === 'mat4x4f' && isMarkedInternal(value);
}

export function isMat(value: unknown): value is Mat2x2f | Mat3x3f | Mat4x4f {
Expand All @@ -1626,7 +1626,7 @@ export function isMat(value: unknown): value is Mat2x2f | Mat3x3f | Mat4x4f {

export function isInteger(value: unknown): value is AbstractInt | I32 | U32 {
return (
isMarkedInternal(value) && ['abstractInt', 'i32', 'u32'].includes((value as AnyWgslData)?.type)
['abstractInt', 'i32', 'u32'].includes((value as AnyWgslData)?.type) && isMarkedInternal(value)
);
}

Expand Down Expand Up @@ -1665,7 +1665,7 @@ export function isWgslData(value: unknown): value is AnyWgslData {
* isWgslArray(d.vec3f) // false
*/
export function isWgslArray(schema: unknown): schema is WgslArray {
return isMarkedInternal(schema) && (schema as WgslArray)?.type === 'array';
return (schema as WgslArray)?.type === 'array' && isMarkedInternal(schema);
}

/**
Expand All @@ -1681,7 +1681,7 @@ export function isWgslArray(schema: unknown): schema is WgslArray {
* isWgslStruct(d.vec3f) // false
*/
export function isWgslStruct(schema: unknown): schema is WgslStruct {
return isMarkedInternal(schema) && (schema as WgslStruct)?.type === 'struct';
return (schema as WgslStruct)?.type === 'struct' && isMarkedInternal(schema);
}

/**
Expand All @@ -1693,7 +1693,7 @@ export function isWgslStruct(schema: unknown): schema is WgslStruct {
* isPtr(d.f32) // false
*/
export function isPtr(schema: unknown): schema is Ptr {
return isMarkedInternal(schema) && (schema as Ptr)?.type === 'ptr';
return (schema as Ptr)?.type === 'ptr' && isMarkedInternal(schema);
}

/**
Expand All @@ -1704,44 +1704,44 @@ export function isPtr(schema: unknown): schema is Ptr {
* isAtomic(d.u32) // false
*/
export function isAtomic(schema: unknown): schema is Atomic {
return isMarkedInternal(schema) && (schema as Atomic)?.type === 'atomic';
return (schema as Atomic)?.type === 'atomic' && isMarkedInternal(schema);
}

export function isAlignAttrib<T extends number>(value: unknown): value is Align<T> {
return isMarkedInternal(value) && (value as Align<T>)?.type === '@align';
return (value as Align<T>)?.type === '@align' && isMarkedInternal(value);
}

export function isSizeAttrib<T extends number>(value: unknown): value is Size<T> {
return isMarkedInternal(value) && (value as Size<T>)?.type === '@size';
return (value as Size<T>)?.type === '@size' && isMarkedInternal(value);
}

export function isLocationAttrib<T extends number>(value: unknown): value is Location<T> {
return isMarkedInternal(value) && (value as Location<T>)?.type === '@location';
return (value as Location<T>)?.type === '@location' && isMarkedInternal(value);
}

export function isInterpolateAttrib<T extends InterpolationType>(
value: unknown,
): value is Interpolate<T> {
return isMarkedInternal(value) && (value as Interpolate<T>)?.type === '@interpolate';
return (value as Interpolate<T>)?.type === '@interpolate' && isMarkedInternal(value);
}
export function isBuiltinAttrib(value: unknown): value is Builtin<string> {
return isMarkedInternal(value) && (value as Builtin<string>)?.type === '@builtin';
return (value as Builtin<string>)?.type === '@builtin' && isMarkedInternal(value);
}

export function isInvariantAttrib(value: unknown): value is Invariant {
return isMarkedInternal(value) && (value as Invariant)?.type === '@invariant';
return (value as Invariant)?.type === '@invariant' && isMarkedInternal(value);
}

export function isDecorated(value: unknown): value is Decorated {
return isMarkedInternal(value) && (value as Decorated)?.type === 'decorated';
return (value as Decorated)?.type === 'decorated' && isMarkedInternal(value);
}

export function isAbstractFloat(value: unknown): value is AbstractFloat {
return isMarkedInternal(value) && (value as AbstractFloat).type === 'abstractFloat';
return (value as AbstractFloat)?.type === 'abstractFloat' && isMarkedInternal(value);
}

export function isAbstractInt(value: unknown): value is AbstractInt {
return isMarkedInternal(value) && (value as AbstractInt).type === 'abstractInt';
return (value as AbstractInt)?.type === 'abstractInt' && isMarkedInternal(value);
}

export function isAbstract(value: unknown): value is AbstractFloat | AbstractInt {
Expand All @@ -1753,11 +1753,11 @@ export function isConcrete(value: unknown): boolean {
}

export function isVoid(value: unknown): value is Void {
return isMarkedInternal(value) && (value as Void).type === 'void';
return (value as Void)?.type === 'void' && isMarkedInternal(value);
}

export function isBool(value: unknown): value is Bool {
return isMarkedInternal(value) && (value as Bool).type === 'bool';
return (value as Bool)?.type === 'bool' && isMarkedInternal(value);
}

export function isNumericSchema(
Expand All @@ -1766,22 +1766,22 @@ export function isNumericSchema(
const type = (schema as BaseData)?.type;

return (
isMarkedInternal(schema) &&
(type === 'abstractInt' ||
type === 'abstractFloat' ||
type === 'f32' ||
type === 'f16' ||
type === 'i32' ||
type === 'u32')
type === 'u32') &&
isMarkedInternal(schema)
);
}

export function isHalfPrecisionSchema(schema: unknown): schema is F16 | Vec2h | Vec3h | Vec4h {
const type = (schema as BaseData)?.type;

return (
isMarkedInternal(schema) &&
(type === 'f16' || type === 'vec2h' || type === 'vec3h' || type === 'vec4h')
(type === 'f16' || type === 'vec2h' || type === 'vec3h' || type === 'vec4h') &&
isMarkedInternal(schema)
);
}

Expand Down
Loading
Loading