Description
Motivation
Today GPUBindGroupLayout
and GPUPipelineLayout
are the most complicated part of the API. How about we add some defaults to them?
Namely it would change this sample code:
const bindGroupLayout = device.createBindGroupLayout({
bindings: [
{binding: 0, visibility: GPUShaderStage.COMPUTE, type: "storage-buffer"},
{binding: 1, visibility: GPUShaderStage.COMPUTE, type: "storage-buffer"},
{binding: 2, visibility: GPUShaderStage.COMPUTE, type: "storage-buffer"}
]
});
const bindGroup = device.createBindGroup({
layout: bindGroupLayout,
bindings: [
{binding: 0, resource: {buffer: gpuBufferFirstMatrix}},
{binding: 1, resource: {buffer: gpuBufferSecondMatrix}},
{binding: 2, resource: {buffer: resultMatrixBuffer}}
]
});
const computeShaderCode = `#version 450
layout(std430, set = 0, binding = 0) readonly buffer FirstMatrix {
} firstMatrix;
layout(std430, set = 0, binding = 1) readonly buffer SecondMatrix {
} secondMatrix;
layout(std430, set = 0, binding = 2) buffer ResultMatrix {
} resultMatrix;`;
const computePipeline = device.createComputePipeline({
layout: device.createPipelineLayout({
bindGroupLayouts: [bindGroupLayout]
}),
computeStage: {
module: device.createShaderModule({code: theCode}),
entryPoint: "main"
}
});
into
const bindGroup = device.createBindGroup({
bindings: [
{binding: 0, resource: {buffer: gpuBufferFirstMatrix}},
{binding: 1, resource: {buffer: gpuBufferSecondMatrix}},
{binding: 2, resource: {buffer: resultMatrixBuffer}}
]
});
const computeShaderCode = `#version 450
layout(std430, set = 0, binding = 0) readonly buffer FirstMatrix {
} firstMatrix;
layout(std430, set = 0, binding = 1) readonly buffer SecondMatrix {
} secondMatrix;
layout(std430, set = 0, binding = 2) buffer ResultMatrix {
} resultMatrix;`;
const computePipeline = device.createComputePipeline({
computeStage: {
module: device.createShaderModule({code: theCode}),
entryPoint: "main"
}
});
which is much easier to understand for people getting started with WebGPU, and almost 50% less code to type for experienced WebGPU developers hacking with the API.
How would this work
It makes the layout
member of GPUPipelineDescriptorBase
and GPUBindGroupDescriptor
optional and if not present deduces them using the following algorithms.
For GPUBindGroupDescriptor
it implicitly creates a GPUBindGroupLayout
that one binding (with the same binding
number) for each binding in the GPUBindGroupDescriptor
. visibility
is always all the stage and other member are set like so (if not described, they get their default value):
- If the
resource
is aGPUSampler
,type
is"sampler"
- If the
resource
is aGPUTextureView
, if the texture has not exactly one of theSAMPLED
andSTORAGE
usages, an error is produced.type
is"sampled-texture"
if the texture has theSAMPLED
usage,"storage-texture"
otherwise.textureDimension
is set to the texture view dimension of the view, andtextureComponentType
set to the component type of the texture's format. If the texture has asampleCount
larger than 1,multisampled
is set sotrue
. - If the
resource
is aGPUBufferBinding
, if the buffer has not exactly one of theUNIFORM
andSTORAGE
usages, an error is produced.type
is"uniform-buffer"
if the buffer has theUNIFORM
usage,"storage-buffer"
otherwise.
For GPUComputePipeline
and GPURenderPipeline
we would deduce an implicit GPUPipelineLayout
that has implicit GPUBindGroupLayouts
for each set used by the pipeline. visibility
is set to all shader stages. Then for each binding of the shader modules of the pipeline a binding is inserted in the correct GPUBindGroupLayout
with the matching binding
like the following (members not mentioned get their default value):
- For sampler bindings in the shadermodule,
type
is set to"sampler"
. - For uniform buffer bindings,
type
is set to"uniform-buffer"
. - For storage buffer bindings,
type
is set to"storage-buffer"
. - For texture bindings, if the texture (SPIRV-ism) has the Sampled bit set to 0,
type
is set tostorage-texture
,sampled-texture
otherwise.textureViewDimension
is set to match the texture binding declaration, as ismultisampled
andtextureComponentType
.
Note that for render pipeline this would also require checking no two bindings conflict.