From 2bb558dd5b82243641a58527b813c5108c060374 Mon Sep 17 00:00:00 2001 From: Gregg Tavares Date: Mon, 1 Jul 2024 16:11:22 -0700 Subject: [PATCH] show/remove default properties of bindGroupLayoutDescriptor entries --- test/tests/data-byte-diagram-tests.js | 163 +++++++++++++++++- webgpu/lessons/resources/data-byte-diagram.js | 63 ++++++- .../resources/wgsl-offset-computer.html | 8 + 3 files changed, 226 insertions(+), 8 deletions(-) diff --git a/test/tests/data-byte-diagram-tests.js b/test/tests/data-byte-diagram-tests.js index c8f852c3..6713e959 100644 --- a/test/tests/data-byte-diagram-tests.js +++ b/test/tests/data-byte-diagram-tests.js @@ -158,7 +158,7 @@ describe('data-byte-diagram-tests', () => { describe('bind group layouts', () => { - it('handles storage textures', () => { + it('handles various types (no defaults)', () => { const shader = ` @group(0) @binding(2) var tex2d: texture_2d; @group(0) @binding(1) var texMS2d: texture_multisampled_2d; @@ -193,8 +193,151 @@ describe('data-byte-diagram-tests', () => { const defs = makeShaderDataDefinitions(shader); const js = makeBindGroupLayoutDescriptorsJS(defs, { compute: { entryPoint: 'cs' }, + }, { + keepDefaults: false, }); const expected = `[ + { + entries: [ + { + binding: 0, + visibility: GPUShaderStage.COMPUTE, + texture: { + sampleType: "depth", + }, + }, + { + binding: 1, + visibility: GPUShaderStage.COMPUTE, + texture: { + multisampled: true, + }, + }, + { + binding: 2, + visibility: GPUShaderStage.COMPUTE, + texture: {}, + }, + { + binding: 3, + visibility: GPUShaderStage.COMPUTE, + sampler: {}, + }, + { + binding: 4, + visibility: GPUShaderStage.COMPUTE, + sampler: { + type: "comparison", + }, + }, + { + binding: 5, + visibility: GPUShaderStage.COMPUTE, + externalTexture: {}, + }, + ], + }, + { + entries: [ + { + binding: 0, + visibility: GPUShaderStage.COMPUTE, + buffer: {}, + }, + { + binding: 1, + visibility: GPUShaderStage.COMPUTE, + buffer: { + type: "read-only-storage", + }, + }, + { + binding: 2, + visibility: GPUShaderStage.COMPUTE, + buffer: { + type: "read-only-storage", + }, + }, + { + binding: 3, + visibility: GPUShaderStage.COMPUTE, + buffer: { + type: "storage", + }, + }, + ], + }, + { + entries: [], + }, + { + entries: [ + { + binding: 0, + visibility: GPUShaderStage.COMPUTE, + storageTexture: { + access: "read-only", + format: "rgba8unorm", + }, + }, + { + binding: 1, + visibility: GPUShaderStage.COMPUTE, + storageTexture: { + format: "rgba32float", + }, + }, + { + binding: 2, + visibility: GPUShaderStage.COMPUTE, + storageTexture: { + access: "read-write", + format: "rgba16uint", + }, + }, + ], + }, +]`; + assertEqual(js, expected); + }); + + it('handles various types (with defaults)', () => { + const shader = ` + @group(0) @binding(2) var tex2d: texture_2d; + @group(0) @binding(1) var texMS2d: texture_multisampled_2d; + @group(0) @binding(0) var texDepth: texture_depth_2d; + @group(0) @binding(3) var samp: sampler; + @group(0) @binding(4) var sampC: sampler_comparison; + @group(0) @binding(5) var texExt: texture_external; + @group(1) @binding(0) var u: mat4x4f; + @group(1) @binding(1) var s: mat4x4f; + @group(1) @binding(2) var sr: mat4x4f; + @group(1) @binding(3) var srw: mat4x4f; + @group(3) @binding(0) var tsR: texture_storage_2d; + @group(3) @binding(1) var tsW: texture_storage_2d; + @group(3) @binding(2) var tsRW: texture_storage_2d; + @compute @workgroup_size(1) fn cs() { + _ = tex2d; + _ = texMS2d; + _ = texDepth; + _ = samp; + _ = sampC; + _ = texExt; + _ = u; + _ = s; + _ = sr; + _ = srw; + _ = tsR; + _ = tsW; + _ = tsRW; + } + `; + + const defs = makeShaderDataDefinitions(shader); + const js = makeBindGroupLayoutDescriptorsJS(defs, { + compute: { entryPoint: 'cs' }, + }, { keepDefaults: true }); + const expected = `[ { entries: [ { @@ -250,13 +393,19 @@ describe('data-byte-diagram-tests', () => { { binding: 0, visibility: GPUShaderStage.COMPUTE, - buffer: {}, + buffer: { + type: "uniform", + hasDynamicOffset: false, + minBindingSize: 0, + }, }, { binding: 1, visibility: GPUShaderStage.COMPUTE, buffer: { type: "read-only-storage", + hasDynamicOffset: false, + minBindingSize: 0, }, }, { @@ -264,6 +413,8 @@ describe('data-byte-diagram-tests', () => { visibility: GPUShaderStage.COMPUTE, buffer: { type: "read-only-storage", + hasDynamicOffset: false, + minBindingSize: 0, }, }, { @@ -271,6 +422,8 @@ describe('data-byte-diagram-tests', () => { visibility: GPUShaderStage.COMPUTE, buffer: { type: "storage", + hasDynamicOffset: false, + minBindingSize: 0, }, }, ], @@ -285,8 +438,8 @@ describe('data-byte-diagram-tests', () => { visibility: GPUShaderStage.COMPUTE, storageTexture: { access: "read-only", - format: "rgba8unorm", viewDimension: "2d", + format: "rgba8unorm", }, }, { @@ -294,8 +447,8 @@ describe('data-byte-diagram-tests', () => { visibility: GPUShaderStage.COMPUTE, storageTexture: { access: "write-only", - format: "rgba32float", viewDimension: "2d", + format: "rgba32float", }, }, { @@ -303,8 +456,8 @@ describe('data-byte-diagram-tests', () => { visibility: GPUShaderStage.COMPUTE, storageTexture: { access: "read-write", - format: "rgba16uint", viewDimension: "2d", + format: "rgba16uint", }, }, ], diff --git a/webgpu/lessons/resources/data-byte-diagram.js b/webgpu/lessons/resources/data-byte-diagram.js index 1bbbf70c..5d78fe88 100644 --- a/webgpu/lessons/resources/data-byte-diagram.js +++ b/webgpu/lessons/resources/data-byte-diagram.js @@ -369,8 +369,64 @@ return (key === 'visibility') : value; } -function bindGroupLayoutDescriptorsToString(bindGroupLayoutDescriptors) { -return JSON.stringify(bindGroupLayoutDescriptors, stringifyBindGroupLayoutDescriptor, 2) +const bindingEntryDefaults = { + buffer: { + type: 'uniform', + hasDynamicOffset: false, + minBindingSize: 0, + }, + sampler: { + type: 'filtering', + }, + texture: { + sampleType: 'float', + viewDimension: '2d', + multisampled: false, + }, + storageTexture: { + access: 'write-only', + viewDimension: '2d', + }, + externalTexture: {}, +}; + +function removeDefaultsFromBindGroupLayoutEntry(entry) { + return Object.fromEntries(Object.entries(entry).map(([k, v]) => { + const defaults = bindingEntryDefaults[k]; + if (defaults) { + v = Object.fromEntries(Object.entries(v).filter(([k, v]) => v !== defaults[k])); + } + return [k, v]; + })); +} + +function removeDefaults(bindGroupLayoutDescriptor) { + return { + ...bindGroupLayoutDescriptor, + entries: bindGroupLayoutDescriptor.entries.map(removeDefaultsFromBindGroupLayoutEntry), + }; +} + +function addDefaultsFromBindGroupLayoutEntry(entry) { + return Object.fromEntries(Object.entries(entry).map(([k, v]) => { + const defaults = bindingEntryDefaults[k]; + if (defaults) { + v = { ...defaults, ...v }; + } + return [k, v]; + })); +} + +function addDefaults(bindGroupLayoutDescriptor) { + return { + ...bindGroupLayoutDescriptor, + entries: bindGroupLayoutDescriptor.entries.map(addDefaultsFromBindGroupLayoutEntry), + }; +} + +function bindGroupLayoutDescriptorsToString(bindGroupLayoutDescriptors, options) { + const noDefaultsBindGroupLayoutDescriptors = bindGroupLayoutDescriptors.map(options.keepDefaults ? addDefaults : removeDefaults); + return JSON.stringify(noDefaultsBindGroupLayoutDescriptors, stringifyBindGroupLayoutDescriptor, 2) .replace(/"(\w+)":/g, '$1:') // "key": value -> key: value .replace(/(}|\]|"|\d|\w)\n/g, '$1,\n') // add trailing commas .replace(/"(GPUS.*?)"/g, '$1') // remove quotes from GPUShaderStage @@ -380,6 +436,7 @@ return JSON.stringify(bindGroupLayoutDescriptors, stringifyBindGroupLayoutDescri export function makeBindGroupLayoutDescriptorsJS( defs/*: ShaderDataDefinitions | ShaderDataDefinitions[]*/, desc/*: PipelineDescriptor*/, + options = {}, ) { - return bindGroupLayoutDescriptorsToString(makeBindGroupLayoutDescriptors(defs, desc)); + return bindGroupLayoutDescriptorsToString(makeBindGroupLayoutDescriptors(defs, desc), options); } diff --git a/webgpu/lessons/resources/wgsl-offset-computer.html b/webgpu/lessons/resources/wgsl-offset-computer.html index ba7e3993..ee716b44 100644 --- a/webgpu/lessons/resources/wgsl-offset-computer.html +++ b/webgpu/lessons/resources/wgsl-offset-computer.html @@ -247,6 +247,7 @@
+
@@ -411,6 +412,7 @@

WGSL Offset Computer

const flattenElem = document.querySelector('#flatten'); const numElementsElem = document.querySelector('#numElements'); const bindGroupLayoutsElem = document.querySelector('#bindGroupLayouts'); +const bindGroupLayoutDefaultsElem = document.querySelector('#bindGroupLayoutDefaults'); const helpElem = document.querySelector('#help'); const docsElem = document.querySelector('#docs'); const globals = {}; @@ -460,6 +462,7 @@

WGSL Offset Computer

flatten: flattenElem.checked, numElements: numElementsElem.value, bindGroupLayouts: bindGroupLayoutsElem.checked, + bindGroupLayoutsElem: bindGroupLayoutDefaultsElem.checked, }); compressor.compress(save, 1, function(bytes) { const hex = convertBytesToHex(bytes); @@ -515,6 +518,8 @@

WGSL Offset Computer

const js = makeBindGroupLayoutDescriptorsJS(defs, { vertex: { entryPoint: vsEntryPoints[0].name }, fragment: { entryPoint: fsEntryPoints[0].name }, + }, { + keepDefaults: bindGroupLayoutDefaultsElem.checked, }); epLines.push(`const bindGroupLayoutDescriptors = ${js};`); } else { @@ -531,6 +536,8 @@

WGSL Offset Computer

for (const {name} of csEntryPoints) { const js = makeBindGroupLayoutDescriptorsJS(defs, { compute: { entryPoint: name }, + }, { + keepDefaults: bindGroupLayoutDefaultsElem.checked, }); epLines.push(`const ${name}BindGroupLayoutDescriptors = ${js};`); } @@ -600,6 +607,7 @@

WGSL Offset Computer

styleElem.checked = true; } bindGroupLayoutsElem.checked = !(data.bindGroupLayouts === false); + bindGroupLayoutDefaultsElem.checked = !(data.bindGroupLayoutDefaults === false); editor.setValue(data.x); resolve(); },