Skip to content
Merged
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
6 changes: 3 additions & 3 deletions apps/typegpu-docs/src/content/docs/fundamentals/utils.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ compute.dispatch();
// "[GPU] Call number 2"
```

Currently supported data types for logging include scalars, vectors, matrices, structs, and fixed-size arrays.

Under the hood, TypeGPU translates `console.log` to a series of serializing functions that write the logged arguments to a buffer that is read and deserialized after every draw/dispatch call.

The buffer is of fixed size, which may limit the total amount of information that can be logged; if the buffer overflows, additional logs are dropped.
Expand Down Expand Up @@ -193,8 +195,6 @@ There are some limitations (some of which we intend to alleviate in the future):
- `console.log` only works when used in TGSL, when calling or resolving a TypeGPU pipeline.
Otherwise, for example when using `tgpu.resolve` on a WGSL template, logs are ignored.
- `console.log` only works in fragment and compute shaders.
This is due to [WebGPU limitation](https://www.w3.org/TR/WGSL/#address-space) that does not allow modifying buffers during the vertex shader stage.
- TypeGPU needs to handle every logged data type individually.
Currently, we only support scalar, vector and matrix types.
This is due to a [WebGPU limitation](https://www.w3.org/TR/WGSL/#address-space) that does not allow modifying buffers during the vertex shader stage.
- `console.log` currently does not support template literals and string substitutions.
- Other `console` methods like `clear` or `warn` are not yet supported.
36 changes: 31 additions & 5 deletions apps/typegpu-docs/src/examples/tests/log-test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ export const controls = {
onButtonClick: () =>
prepareDispatch(root, () => {
'kernel';
console.log(d.u32(1), d.vec3u(2, 3, 4), d.u32(5), d.u32(6));
console.log(1, d.vec3u(2, 3, 4), 5, 6);
}).dispatch(),
},
'String literals': {
onButtonClick: () =>
prepareDispatch(root, () => {
'kernel';
console.log(d.u32(2), 'plus', d.u32(3), 'equals', d.u32(5));
console.log(2, 'plus', 3, 'equals', 5);
}).dispatch(),
},
'Two logs': {
Expand Down Expand Up @@ -88,6 +88,32 @@ export const controls = {
}
}).dispatch(),
},
'Compound types': {
onButtonClick: () => {
const SimpleStruct = d.struct({ vec: d.vec3u, num: d.u32 });
const ComplexStruct = d.struct({ nested: SimpleStruct, bool: d.bool });
const SimpleArray = d.arrayOf(d.u32, 2);
const ComplexArray = d.arrayOf(SimpleArray, 3);

prepareDispatch(root, () => {
'kernel';
const simpleStruct = SimpleStruct({ vec: d.vec3u(1, 2, 3), num: 4 });
console.log(simpleStruct);

const complexStruct = ComplexStruct({
nested: simpleStruct,
bool: true,
});
console.log(complexStruct);

const simpleArray = SimpleArray([1, 2]);
console.log(simpleArray);

const complexArray = ComplexArray([[3, 4], [5, 6], [7, 8]]);
console.log(complexArray);
}).dispatch();
},
},
'Two threads': {
onButtonClick: () =>
prepareDispatch(root, (x) => {
Expand Down Expand Up @@ -115,7 +141,7 @@ export const controls = {
const test = prepareDispatch(root, () => {
'kernel';
for (let i = d.u32(); i < logCountUniform.$; i++) {
console.log('Log index', d.u32(i) + 1, 'out of', logCountUniform.$);
console.log('Log index', i + 1, 'out of', logCountUniform.$);
}
});
logCountUniform.write(3);
Expand Down Expand Up @@ -143,7 +169,7 @@ export const controls = {
in: { pos: d.builtin.position },
out: d.vec4f,
})(({ pos }) => {
console.log('X:', d.u32(pos.x), 'Y:', d.u32(pos.y));
console.log('X:', pos.x, 'Y:', pos.y);
return d.vec4f(0.769, 0.392, 1.0, 1);
});

Expand Down Expand Up @@ -186,7 +212,7 @@ export const controls = {
try {
prepareDispatch(root, () => {
'kernel';
console.log(d.vec3u(), d.vec3u(), d.vec3u());
console.log(d.mat4x4f(), d.mat4x4f(), 1);
}).dispatch();
} catch (err) {
console.log(err);
Expand Down
6 changes: 5 additions & 1 deletion packages/typegpu/src/data/alignmentOf.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { safeStringify } from '../shared/stringify.ts';
import {
type AnyData,
getCustomAlignment,
Expand All @@ -12,26 +13,29 @@ import {
isWgslArray,
isWgslStruct,
} from './wgslTypes.ts';
import { safeStringify } from '../shared/safeStringify.ts';

const knownAlignmentMap: Record<string, number> = {
f32: 4,
f16: 2,
i32: 4,
u32: 4,
bool: 4,
u16: 2,
vec2f: 8,
vec2h: 4,
vec2i: 8,
vec2u: 8,
vec2b: 8,
vec3f: 16,
vec3h: 8,
vec3i: 16,
vec3u: 16,
vec3b: 16,
vec4f: 16,
vec4h: 8,
vec4i: 16,
vec4u: 16,
vec4b: 16,
mat2x2f: 8,
mat3x3f: 16,
mat4x4f: 16,
Expand Down
2 changes: 1 addition & 1 deletion packages/typegpu/src/resolutionCtx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import {
import { provideCtx, topLevelState } from './execMode.ts';
import { naturalsExcept } from './shared/generators.ts';
import type { Infer } from './shared/repr.ts';
import { safeStringify } from './shared/safeStringify.ts';
import { safeStringify } from './shared/stringify.ts';
import { $internal, $providing, $resolve } from './shared/symbols.ts';
import {
bindGroupLayout,
Expand Down
13 changes: 0 additions & 13 deletions packages/typegpu/src/shared/safeStringify.ts

This file was deleted.

35 changes: 35 additions & 0 deletions packages/typegpu/src/shared/stringify.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { isMatInstance, isVecInstance } from '../data/wgslTypes.ts';

export function safeStringify(item: unknown): string {
const asString = String(item);
if (asString !== '[object Object]') {
return asString;
}

try {
return JSON.stringify(item);
} catch (error) {
console.error('Error parsing JSON:', error);
return '<invalid json>';
}
}

export function niceStringify(item: unknown): string {
if (isVecInstance(item) || isMatInstance(item)) {
return item.toString();
}

if (Array.isArray(item)) {
return `[${item.map(niceStringify).join(', ')}]`;
}

if (item && typeof item === 'object') {
return `{ ${
Object.entries(item).map(([key, value]) =>
`${key}: ${niceStringify(value)}`
).join(', ')
} }`;
}

return String(item);
}
6 changes: 3 additions & 3 deletions packages/typegpu/src/std/atomic.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { createDualImpl } from '../core/function/dualImpl.ts';
import { stitch } from '../core/resolve/stitch.ts';
import { snip, type Snippet } from '../data/snippet.ts';
import { i32, u32 } from '../data/numeric.ts';
import { snip, type Snippet } from '../data/snippet.ts';
import {
type AnyWgslData,
type atomicI32,
type atomicU32,
isWgslData,
Void,
} from '../data/wgslTypes.ts';
import { createDualImpl } from '../core/function/dualImpl.ts';
import { safeStringify } from '../shared/safeStringify.ts';
import { safeStringify } from '../shared/stringify.ts';
type AnyAtomic = atomicI32 | atomicU32;

export const workgroupBarrier = createDualImpl(
Expand Down
2 changes: 1 addition & 1 deletion packages/typegpu/src/tgpuBindGroupLayout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ import {
import type { TgpuNamable } from './shared/meta.ts';
import { getName, setName } from './shared/meta.ts';
import type { Infer, MemIdentity } from './shared/repr.ts';
import { safeStringify } from './shared/safeStringify.ts';
import { safeStringify } from './shared/stringify.ts';
import { $gpuValueOf, $internal } from './shared/symbols.ts';
import type {
Default,
Expand Down
Loading