Skip to content

Commit 3d59036

Browse files
fix: Fill missing slots in shellless entry functions (#2255)
1 parent 410b4d5 commit 3d59036

3 files changed

Lines changed: 120 additions & 3 deletions

File tree

apps/typegpu-docs/src/examples/tests/log-test/index.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import tgpu, { d, std } from 'typegpu';
1+
import tgpu, { d, std, type AutoVertexIn } from 'typegpu';
22
import { defineControls } from '../../common/defineControls.ts';
33

44
const root = await tgpu.init({
@@ -249,6 +249,32 @@ export const controls = defineControls({
249249
pipeline.withIndexBuffer(indexBuffer).withColorAttachment({ view: context }).drawIndexed(3);
250250
},
251251
},
252+
'Shellless entry': {
253+
onButtonClick: () => {
254+
const myLog = (n: number) => {
255+
'use gpu';
256+
console.log(n);
257+
};
258+
259+
const vs = ({ $vertexIndex }: AutoVertexIn<{}>) => {
260+
'use gpu';
261+
const positions = [d.vec2f(0, 0.5), d.vec2f(-0.5, -0.5), d.vec2f(0.5, -0.5)];
262+
myLog(6);
263+
return { $position: d.vec4f(positions[$vertexIndex], 0, 1) };
264+
};
265+
const fs = () => {
266+
'use gpu';
267+
myLog(7);
268+
return d.vec4f();
269+
};
270+
271+
const pipeline = root.createRenderPipeline({
272+
vertex: vs,
273+
fragment: fs,
274+
});
275+
pipeline.withColorAttachment({ view: context }).draw(3);
276+
},
277+
},
252278
'Too many logs': {
253279
onButtonClick: () =>
254280
root

packages/typegpu/src/core/function/autoIO.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { getName, setName } from '../../shared/meta.ts';
77
import type { InferGPU, InferGPURecord, InferRecord } from '../../shared/repr.ts';
88
import { $internal, $resolve } from '../../shared/symbols.ts';
99
import type { ResolutionCtx, SelfResolvable } from '../../types.ts';
10+
import { shaderStageSlot } from '../slot/internalSlots.ts';
1011
import { createFnCore, type FnCore } from './fnCore.ts';
1112
import type { BaseIOData } from './fnTypes.ts';
1213

@@ -85,7 +86,9 @@ export class AutoFragmentFn implements SelfResolvable {
8586
}
8687

8788
[$resolve](ctx: ResolutionCtx): ResolvedSnippet {
88-
return this.#core.resolve(ctx, [this.#autoIn], this.#autoOut);
89+
return ctx.withSlots([[shaderStageSlot, 'fragment']], () =>
90+
this.#core.resolve(ctx, [this.#autoIn], this.#autoOut),
91+
);
8992
}
9093
}
9194

@@ -129,7 +132,9 @@ export class AutoVertexFn implements SelfResolvable {
129132
}
130133

131134
[$resolve](ctx: ResolutionCtx): ResolvedSnippet {
132-
return this.#core.resolve(ctx, [this.#autoIn], this.#autoOut);
135+
return ctx.withSlots([[shaderStageSlot, 'vertex']], () =>
136+
this.#core.resolve(ctx, [this.#autoIn], this.#autoOut),
137+
);
133138
}
134139
}
135140

packages/typegpu/tests/tgsl/consoleLog.test.ts

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,92 @@ describe('wgslGenerator with console.log', () => {
223223
`);
224224
});
225225

226+
it('Works for shellless entry functions', ({ root }) => {
227+
const myLog = (n: number) => {
228+
'use gpu';
229+
console.log(n);
230+
};
231+
232+
const vs = () => {
233+
'use gpu';
234+
myLog(6);
235+
return { pos: d.vec4f() };
236+
};
237+
const fs = () => {
238+
'use gpu';
239+
myLog(7);
240+
return d.vec4f();
241+
};
242+
243+
const pipeline = root.createRenderPipeline({
244+
vertex: vs,
245+
fragment: fs,
246+
targets: { format: 'rg8unorm' },
247+
});
248+
249+
expect(tgpu.resolve([pipeline])).toMatchInlineSnapshot(`
250+
"fn myLog(n: i32) {
251+
/* console.log() */;
252+
}
253+
254+
struct VertexOut {
255+
@location(0) pos: vec4f,
256+
}
257+
258+
@vertex fn vs() -> VertexOut {
259+
myLog(6i);
260+
return VertexOut(vec4f());
261+
}
262+
263+
@group(0) @binding(0) var<storage, read_write> indexBuffer: atomic<u32>;
264+
265+
struct SerializedLogData {
266+
id: u32,
267+
serializedData: array<u32, 63>,
268+
}
269+
270+
@group(0) @binding(1) var<storage, read_write> dataBuffer: array<SerializedLogData, 64>;
271+
272+
var<private> dataBlockIndex: u32;
273+
274+
var<private> dataByteIndex: u32;
275+
276+
fn nextByteIndex() -> u32{
277+
let i = dataByteIndex;
278+
dataByteIndex = dataByteIndex + 1u;
279+
return i;
280+
}
281+
282+
fn serializeI32(n: i32) {
283+
dataBuffer[dataBlockIndex].serializedData[nextByteIndex()] = bitcast<u32>(n);
284+
}
285+
286+
fn log1serializer(_arg_0: i32) {
287+
serializeI32(_arg_0);
288+
}
289+
290+
fn log1(_arg_0: i32) {
291+
dataBlockIndex = atomicAdd(&indexBuffer, 1);
292+
if (dataBlockIndex >= 64) {
293+
return;
294+
}
295+
dataBuffer[dataBlockIndex].id = 1;
296+
dataByteIndex = 0;
297+
298+
log1serializer(_arg_0);
299+
}
300+
301+
fn myLog_1(n: i32) {
302+
log1(n);
303+
}
304+
305+
@fragment fn fs() -> @location(0) vec4f {
306+
myLog_1(7i);
307+
return vec4f();
308+
}"
309+
`);
310+
});
311+
226312
it('Parses a single console.log in a compute pipeline', ({ root }) => {
227313
const fn = tgpu.computeFn({
228314
workgroupSize: [1],

0 commit comments

Comments
 (0)