From b532da00b562b2eeebb81f42368feca9234a0b75 Mon Sep 17 00:00:00 2001 From: Aleksander Katan Date: Wed, 1 Oct 2025 16:28:20 +0200 Subject: [PATCH 1/3] Support drawIndexed --- .../src/examples/tests/log-test/index.ts | 77 +++++++++++++------ .../src/core/pipeline/renderPipeline.ts | 5 ++ 2 files changed, 59 insertions(+), 23 deletions(-) diff --git a/apps/typegpu-docs/src/examples/tests/log-test/index.ts b/apps/typegpu-docs/src/examples/tests/log-test/index.ts index 80e9100eb..8b1fce816 100644 --- a/apps/typegpu-docs/src/examples/tests/log-test/index.ts +++ b/apps/typegpu-docs/src/examples/tests/log-test/index.ts @@ -12,6 +12,39 @@ const root = await tgpu.init({ }, }); +// setup for render tests +const presentationFormat = navigator.gpu.getPreferredCanvasFormat(); +const canvas = document.querySelector('canvas') as HTMLCanvasElement; + +const mainVertex = tgpu['~unstable'].vertexFn({ + in: { vertexIndex: d.builtin.vertexIndex }, + out: { pos: d.builtin.position }, +})((input) => { + const positions = [ + d.vec2f(0, 0.5), + d.vec2f(-0.5, -0.5), + d.vec2f(0.5, -0.5), + ]; + + return { pos: d.vec4f(positions[input.vertexIndex], 0, 1) }; +}); + +const mainFragment = tgpu['~unstable'].fragmentFn({ + in: { pos: d.builtin.position }, + out: d.vec4f, +})(({ pos }) => { + console.log('X:', pos.x, 'Y:', pos.y); + return d.vec4f(0.769, 0.392, 1.0, 1); +}); + +const context = canvas.getContext('webgpu') as GPUCanvasContext; + +context.configure({ + device: root.device, + format: presentationFormat, + alphaMode: 'premultiplied', +}); + // #region Example controls and cleanup export const controls = { @@ -152,29 +185,6 @@ export const controls = { }, 'Render pipeline': { onButtonClick: () => { - const mainVertex = tgpu['~unstable'].vertexFn({ - in: { vertexIndex: d.builtin.vertexIndex }, - out: { pos: d.builtin.position }, - })((input) => { - const positions = [ - d.vec2f(0, 0.5), - d.vec2f(-0.5, -0.5), - d.vec2f(0.5, -0.5), - ]; - - return { pos: d.vec4f(positions[input.vertexIndex], 0, 1) }; - }); - - const mainFragment = tgpu['~unstable'].fragmentFn({ - in: { pos: d.builtin.position }, - out: d.vec4f, - })(({ pos }) => { - console.log('X:', pos.x, 'Y:', pos.y); - return d.vec4f(0.769, 0.392, 1.0, 1); - }); - - const presentationFormat = navigator.gpu.getPreferredCanvasFormat(); - const canvas = document.querySelector('canvas') as HTMLCanvasElement; const context = canvas.getContext('webgpu') as GPUCanvasContext; context.configure({ @@ -198,6 +208,27 @@ export const controls = { .draw(3); }, }, + 'Draw indexed': { + onButtonClick: () => { + const pipeline = root['~unstable'] + .withVertex(mainVertex, {}) + .withFragment(mainFragment, { format: presentationFormat }) + .createPipeline(); + + const indexBuffer = root + .createBuffer(d.arrayOf(d.u32, 3), [0, 1, 2]) + .$usage('index'); + + pipeline + .withIndexBuffer(indexBuffer) + .withColorAttachment({ + view: context.getCurrentTexture().createView(), + clearValue: [0, 0, 0, 0], + loadOp: 'clear', + storeOp: 'store', + }).drawIndexed(3); + }, + }, 'Too many logs': { onButtonClick: () => prepareDispatch(root, (x) => { diff --git a/packages/typegpu/src/core/pipeline/renderPipeline.ts b/packages/typegpu/src/core/pipeline/renderPipeline.ts index 27aebe1ab..91d9d4054 100644 --- a/packages/typegpu/src/core/pipeline/renderPipeline.ts +++ b/packages/typegpu/src/core/pipeline/renderPipeline.ts @@ -595,6 +595,7 @@ class TgpuRenderPipelineImpl implements TgpuRenderPipeline { internals.priors.indexBuffer; const pass = this.setupRenderPass(); + const { logResources } = internals.core.unwrap(); const { branch } = internals.core.options; if (isGPUBuffer(buffer)) { @@ -618,6 +619,10 @@ class TgpuRenderPipelineImpl implements TgpuRenderPipeline { pass.end(); + if (logResources) { + logDataFromGPU(logResources); + } + internals.priors.performanceCallback ? triggerPerformanceCallback({ root: branch, From 95483422ef9495bb48c495ef03eade3d73e7ebf4 Mon Sep 17 00:00:00 2001 From: Aleksander Katan Date: Wed, 1 Oct 2025 16:28:40 +0200 Subject: [PATCH 2/3] Remove unnecessary test --- .../src/examples/tests/log-test/index.ts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/apps/typegpu-docs/src/examples/tests/log-test/index.ts b/apps/typegpu-docs/src/examples/tests/log-test/index.ts index 8b1fce816..b3e55c477 100644 --- a/apps/typegpu-docs/src/examples/tests/log-test/index.ts +++ b/apps/typegpu-docs/src/examples/tests/log-test/index.ts @@ -238,18 +238,6 @@ export const controls = { console.log('Log 3 from thread', x); }).dispatch(16), }, - 'Too much data': { - onButtonClick: () => { - try { - prepareDispatch(root, () => { - 'kernel'; - console.log(d.mat4x4f(), d.mat4x4f(), 1); - }).dispatch(); - } catch (err) { - console.log(err); - } - }, - }, }; export function onCleanup() { From ccf10f36a91eacc90f744b24365ef0b70a7a4e80 Mon Sep 17 00:00:00 2001 From: Aleksander Katan Date: Wed, 1 Oct 2025 16:31:19 +0200 Subject: [PATCH 3/3] Update tests --- .../src/examples/tests/log-test/index.ts | 1 - .../examples/individual/log-test.test.ts | 64 ++++++++++++++++++- 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/apps/typegpu-docs/src/examples/tests/log-test/index.ts b/apps/typegpu-docs/src/examples/tests/log-test/index.ts index b3e55c477..6dcd9fbd6 100644 --- a/apps/typegpu-docs/src/examples/tests/log-test/index.ts +++ b/apps/typegpu-docs/src/examples/tests/log-test/index.ts @@ -164,7 +164,6 @@ export const controls = { for (let i = 0; i < 100; i++) { indexUniform.write(i); test.dispatch(); - console.log(`dispatched ${i}`); } }, }, diff --git a/packages/typegpu/tests/examples/individual/log-test.test.ts b/packages/typegpu/tests/examples/individual/log-test.test.ts index 2af51104c..44214cdba 100644 --- a/packages/typegpu/tests/examples/individual/log-test.test.ts +++ b/packages/typegpu/tests/examples/individual/log-test.test.ts @@ -24,9 +24,10 @@ describe('console log example', () => { '100 dispatches', 'Varying size logs', 'Render pipeline', + 'Draw indexed', 'Too many logs', ], - expectedCalls: 11, + expectedCalls: 12, }, device); // the resolution variant for when 'shader-f16' is not enabled @@ -1301,6 +1302,67 @@ describe('console log example', () => { return vec4f(0.7689999938011169, 0.3919999897480011, 1, 1); } + struct mainVertex_Output_1 { + @builtin(position) pos: vec4f, + } + + struct mainVertex_Input_2 { + @builtin(vertex_index) vertexIndex: u32, + } + + @vertex fn mainVertex_0(input: mainVertex_Input_2) -> mainVertex_Output_1 { + var positions = array(vec2f(0, 0.5), vec2f(-0.5, -0.5), vec2f(0.5, -0.5)); + return mainVertex_Output_1(vec4f(positions[input.vertexIndex], 0, 1)); + } + + @group(0) @binding(0) var indexBuffer_5: atomic; + + struct SerializedLogData_7 { + id: u32, + serializedData: array, + } + + @group(0) @binding(1) var dataBuffer_6: array; + + var dataBlockIndex_8: u32; + + var dataByteIndex_9: u32; + + fn nextByteIndex_12() -> u32{ + let i = dataByteIndex_9; + dataByteIndex_9 = dataByteIndex_9 + 1u; + return i; + } + + fn serializeF32_11(n: f32) { + dataBuffer_6[dataBlockIndex_8].serializedData[nextByteIndex_12()] = bitcast(n); + } + + fn log1serializer_10(_arg_0: f32, _arg_1: f32) { + serializeF32_11(_arg_0); + serializeF32_11(_arg_1); + } + + fn log1_4(_arg_0: f32, _arg_1: f32) { + dataBlockIndex_8 = atomicAdd(&indexBuffer_5, 1); + if (dataBlockIndex_8 >= 40) { + return; + } + dataBuffer_6[dataBlockIndex_8].id = 1; + dataByteIndex_9 = 0; + + log1serializer_10(_arg_0, _arg_1); + } + + struct mainFragment_Input_13 { + @builtin(position) pos: vec4f, + } + + @fragment fn mainFragment_3(_arg_0: mainFragment_Input_13) -> @location(0) vec4f { + log1_4(_arg_0.pos.x, _arg_0.pos.y); + return vec4f(0.7689999938011169, 0.3919999897480011, 1, 1); + } + @group(0) @binding(0) var sizeUniform_1: vec3u; @group(0) @binding(1) var indexBuffer_4: atomic;