From a97d31f2ebb717b4f7b403a9d6f127f9543b2e2c Mon Sep 17 00:00:00 2001 From: Aleksander Katan <56294622+aleksanderkatan@users.noreply.github.com> Date: Tue, 21 Apr 2026 16:33:40 +0200 Subject: [PATCH 1/3] Handle implicit pointers --- packages/typegpu/src/data/dataTypes.ts | 2 + .../src/tgsl/consoleLog/logGenerator.ts | 38 +++++++---- .../typegpu/tests/tgsl/consoleLog.test.ts | 66 +++++++++++++++++++ 3 files changed, 93 insertions(+), 13 deletions(-) diff --git a/packages/typegpu/src/data/dataTypes.ts b/packages/typegpu/src/data/dataTypes.ts index 5cac3ebd0a..fa08821955 100644 --- a/packages/typegpu/src/data/dataTypes.ts +++ b/packages/typegpu/src/data/dataTypes.ts @@ -145,6 +145,8 @@ export function undecorate(data: BaseData): BaseData { return data; } +export function unptr(data: BaseData): BaseData; +export function unptr(data: BaseData | UnknownData): BaseData | UnknownData; export function unptr(data: BaseData | UnknownData): BaseData | UnknownData { if (wgsl.isPtr(data)) { return data.inner; diff --git a/packages/typegpu/src/tgsl/consoleLog/logGenerator.ts b/packages/typegpu/src/tgsl/consoleLog/logGenerator.ts index 889d2da43b..4cb6790a3c 100644 --- a/packages/typegpu/src/tgsl/consoleLog/logGenerator.ts +++ b/packages/typegpu/src/tgsl/consoleLog/logGenerator.ts @@ -4,7 +4,7 @@ import type { TgpuRoot } from '../../core/root/rootTypes.ts'; import { shaderStageSlot } from '../../core/slot/internalSlots.ts'; import { arrayOf } from '../../data/array.ts'; import { atomic } from '../../data/atomic.ts'; -import { UnknownData } from '../../data/dataTypes.ts'; +import { UnknownData, unptr } from '../../data/dataTypes.ts'; import { u32 } from '../../data/numeric.ts'; import { snip, type Snippet } from '../../data/snippet.ts'; import { struct } from '../../data/struct.ts'; @@ -16,7 +16,8 @@ import { type WgslArray, } from '../../data/wgslTypes.ts'; import { $internal } from '../../shared/symbols.ts'; -import { concretizeSnippets, type GenerationCtx } from '../generationHelpers.ts'; +import { convertToCommonType } from '../conversion.ts'; +import { concretizeSnippet, type GenerationCtx } from '../generationHelpers.ts'; import { createLoggingFunction } from './serializers.ts'; import { type LogGenerator, @@ -87,30 +88,41 @@ export class LogGeneratorImpl implements LogGenerator { return fallbackSnippet; } - const concreteArgs = concretizeSnippets(args); const id = this.#firstUnusedId++; - const nonStringArgs = concreteArgs.filter((e) => e.dataType !== UnknownData); + const concreteArgsWithStrings = args + .map((arg) => + typeof arg.dataType === 'symbol' + ? arg + : convertToCommonType(ctx, [arg], [unptr(arg.dataType)])?.[0], + ) + .filter((arg) => !!arg) + .map(concretizeSnippet); + + const concreteArgs = concreteArgsWithStrings.filter((arg) => typeof arg.dataType !== 'symbol'); const logFn = createLoggingFunction( id, - nonStringArgs.map((e) => e.dataType as AnyWgslData), + concreteArgs.map((e) => e.dataType as AnyWgslData), this.#dataBuffer, this.#indexBuffer, this.#options, ); - const argTypes = concreteArgs.map((e) => - e.dataType === UnknownData ? (e.value as string) : (e.dataType as AnyWgslData), - ); - - this.#logIdToMeta.set(id, { op: op as SupportedLogOps, argTypes }); - - return snip( - stitch`${ctx.resolve(logFn).value}(${nonStringArgs})`, + const functionSnippet = snip( + stitch`${ctx.resolve(logFn).value}(${concreteArgs})`, Void, /* origin */ 'runtime', ); + + this.#logIdToMeta.set(id, { + op: op as SupportedLogOps, + argTypes: concreteArgsWithStrings.map((e) => + e?.dataType === UnknownData ? (e?.value as string) : (e?.dataType as AnyWgslData), + ), + }); + + return functionSnippet; } get logResources(): LogResources | undefined { diff --git a/packages/typegpu/tests/tgsl/consoleLog.test.ts b/packages/typegpu/tests/tgsl/consoleLog.test.ts index c3fe5c7189..f452dd5f2a 100644 --- a/packages/typegpu/tests/tgsl/consoleLog.test.ts +++ b/packages/typegpu/tests/tgsl/consoleLog.test.ts @@ -682,6 +682,72 @@ describe('wgslGenerator with console.log', () => { expect(consoleWarnSpy).toHaveBeenCalledWith("Unsupported log method 'trace'."); expect(consoleWarnSpy).toHaveBeenCalledTimes(1); }); + + it('works with implicit pointers', ({ root }) => { + const myUniform = root.createUniform(d.vec2f); + const myPipeline = root.createGuardedComputePipeline((x) => { + 'use gpu'; + const v = myUniform.$; + console.log(v); + }); + + expect(tgpu.resolve([myPipeline.pipeline])).toMatchInlineSnapshot(` + "@group(0) @binding(0) var sizeUniform: vec3u; + + @group(0) @binding(1) var myUniform: vec2f; + + @group(0) @binding(2) var indexBuffer: atomic; + + struct SerializedLogData { + id: u32, + serializedData: array, + } + + @group(0) @binding(3) var dataBuffer: array; + + var dataBlockIndex: u32; + + var dataByteIndex: u32; + + fn nextByteIndex() -> u32 { + let i = dataByteIndex; + dataByteIndex = dataByteIndex + 1u; + return i; + } + + fn serializeVec2f(v: vec2f) { + dataBuffer[dataBlockIndex].serializedData[nextByteIndex()] = bitcast(v.x); + dataBuffer[dataBlockIndex].serializedData[nextByteIndex()] = bitcast(v.y); + } + + fn log1serializer(_arg_0: vec2f) { + serializeVec2f(_arg_0); + } + + fn log1(_arg_0: vec2f) { + dataBlockIndex = atomicAdd(&indexBuffer, 1); + if (dataBlockIndex >= 64) { + return; + } + dataBuffer[dataBlockIndex].id = 1; + dataByteIndex = 0; + + log1serializer(_arg_0); + } + + fn wrappedCallback(x: u32, _arg_1: u32, _arg_2: u32) { + let v = (&myUniform); + log1((*v)); + } + + @compute @workgroup_size(256, 1, 1) fn mainCompute(@builtin(global_invocation_id) id: vec3u) { + if (any(id >= sizeUniform)) { + return; + } + wrappedCallback(id.x, id.y, id.z); + }" + `); + }); }); describe('deserializeAndStringify', () => { From 24a238c24551432423f5b5c3c7c33902c19f6d30 Mon Sep 17 00:00:00 2001 From: Aleksander Katan <56294622+aleksanderkatan@users.noreply.github.com> Date: Wed, 22 Apr 2026 13:05:05 +0200 Subject: [PATCH 2/3] Add an invariant --- .../src/tgsl/consoleLog/logGenerator.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/packages/typegpu/src/tgsl/consoleLog/logGenerator.ts b/packages/typegpu/src/tgsl/consoleLog/logGenerator.ts index 4cb6790a3c..a8035decbe 100644 --- a/packages/typegpu/src/tgsl/consoleLog/logGenerator.ts +++ b/packages/typegpu/src/tgsl/consoleLog/logGenerator.ts @@ -15,6 +15,7 @@ import { Void, type WgslArray, } from '../../data/wgslTypes.ts'; +import { invariant } from '../../errors.ts'; import { $internal } from '../../shared/symbols.ts'; import { convertToCommonType } from '../conversion.ts'; import { concretizeSnippet, type GenerationCtx } from '../generationHelpers.ts'; @@ -91,12 +92,17 @@ export class LogGeneratorImpl implements LogGenerator { const id = this.#firstUnusedId++; const concreteArgsWithStrings = args - .map((arg) => - typeof arg.dataType === 'symbol' - ? arg - : convertToCommonType(ctx, [arg], [unptr(arg.dataType)])?.[0], - ) - .filter((arg) => !!arg) + .map((arg) => { + if (typeof arg.dataType === 'symbol') { + return arg; + } + const converted = convertToCommonType(ctx, [arg], [unptr(arg.dataType)])?.[0]; + invariant( + converted, + `Internal error. Expected type ${arg.dataType} to be convertible to ${unptr(arg.dataType)}`, + ); + return converted; + }) .map(concretizeSnippet); const concreteArgs = concreteArgsWithStrings.filter((arg) => typeof arg.dataType !== 'symbol'); From e3dd457a98e92f9a6801392e62acc34b10d6feed Mon Sep 17 00:00:00 2001 From: Aleksander Katan <56294622+aleksanderkatan@users.noreply.github.com> Date: Wed, 22 Apr 2026 13:06:08 +0200 Subject: [PATCH 3/3] Lint --- packages/typegpu/src/tgsl/wgslGenerator.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/typegpu/src/tgsl/wgslGenerator.ts b/packages/typegpu/src/tgsl/wgslGenerator.ts index 7c7c06d7c8..053c43e643 100644 --- a/packages/typegpu/src/tgsl/wgslGenerator.ts +++ b/packages/typegpu/src/tgsl/wgslGenerator.ts @@ -772,10 +772,7 @@ ${this.ctx.pre}}`; ); } // Taking care of abstract numerics and implicit pointers - accessed = structType.provideProp( - key, - unptr(concretize(expr.dataType)) as wgsl.BaseData, - ); + accessed = structType.provideProp(key, unptr(concretize(expr.dataType))); } return [accessed.prop, expr];