(bind-group-layout …)
Defines the layout of a bind group explicitly, specifying what resource can be bound at each binding index and which shader stages may access it. Use it instead of inferring the layout from a pipeline’s auto-layout.
Compose one or more of these into an explicit
(pipeline-layout …) to bind @group(0),
@group(1), … to distinct layouts, or name one directly as a
(bind-group …)’s :layout.
Syntax
Section titled “Syntax”(bind-group-layout :name layoutName (entry :binding 0 :visibility [vertex fragment] (buffer :type uniform)) (entry :binding 1 :visibility [fragment] (sampler :type filtering)) (entry :binding 2 :visibility [fragment] (texture :sample-type float)) (entry :binding 3 :visibility [compute] (storage-texture :format rgba8unorm)))Keys & Sub-forms
Section titled “Keys & Sub-forms”| Key / Sub-form | Type | Required | Default | Description |
|---|---|---|---|---|
:name |
symbol | Yes | - | Layout name |
(entry …) |
sub-form | No | - | Binding layout entries, one per slot |
A layout with no (entry …) children is legal and describes an empty group, the
same as WebGPU’s empty entries list.
(entry …) entries
Section titled “(entry …) entries”Each (entry …) sub-form describes a single binding slot:
| Key / Sub-form | Type | Required | Description |
|---|---|---|---|
:binding |
number | Yes | Binding index (0-based, up to 255) |
:visibility |
array | Yes | Shader stages that can access |
| resource sub-form | sub-form | Yes | Exactly one of (buffer …), (sampler …), (texture …), (storage-texture …) |
Exactly one resource per entry, as GPUBindGroupLayoutEntry says: none is
positional_missing and two is positional_too_many, both located, rather than
a binding kind chosen for you.
:visibility
Section titled “:visibility”Array of shader stages:
| Value | Description |
|---|---|
vertex |
Vertex shader |
fragment |
Fragment shader |
compute |
Compute shader |
Any other spelling is a not_member error naming the three that are allowed.
(buffer …)
Section titled “(buffer …)”Buffer binding layout:
| Key | Type | Required | Description |
|---|---|---|---|
:type |
symbol | No (uniform) |
How the buffer is exposed to WGSL |
| Type | WGSL |
|---|---|
uniform |
var<uniform> (read-only, size-limited) |
storage |
var<storage, read_write> |
read-only-storage |
var<storage, read> |
(sampler …)
Section titled “(sampler …)”| Key | Type | Default | Description |
|---|---|---|---|
:type |
symbol | filtering |
filtering, non-filtering, or comparison |
comparison corresponds to WGSL’s sampler_comparison; pair it with a
(sampler … :compare …) for shadow mapping.
(texture …)
Section titled “(texture …)”Sampled-texture binding layout:
| Key | Type | Default | Description |
|---|---|---|---|
:sample-type |
symbol | float |
float, unfilterable-float, depth, sint, uint |
:view-dimension |
symbol | 2d |
View dimension (see the table below) |
:multisampled |
boolean | false |
Whether the binding is a multisampled texture |
(storage-texture …)
Section titled “(storage-texture …)”| Key | Type | Default | Description |
|---|---|---|---|
:format |
symbol | required | Texel format; WebGPU requires a storage-capable one, e.g. rgba8unorm |
:access |
symbol | write-only |
write-only, read-only, or read-write |
:view-dimension |
symbol | 2d |
View dimension (see the table below) |
:view-dimension values
Section titled “:view-dimension values”:view-dimension is spelled the way the WebGPU spec spells it, the same
spellings (texture-view …) takes:
| Value | GPUTextureViewDimension |
|---|---|
1d |
One-dimensional view (texture_1d) |
2d |
Two-dimensional view (texture_2d), the default |
2d-array |
Array of 2d layers (texture_2d_array) |
cube |
Cube map, six 2d layers (texture_cube) |
cube-array |
Array of cube maps (texture_cube_array) |
3d |
Volume view (texture_3d) |
The digit-leading spellings lex as numbers with a unit in SJON (the
S-expression source format PNGine compiles), and the schema matches them on that
parsed pair, so they are written bare, unquoted. A plain integer is a
wrong_underlying error.
Examples
Section titled “Examples”Uniform Buffer Layout
Section titled “Uniform Buffer Layout”(bind-group-layout :name uniformLayout (entry :binding 0 :visibility [vertex fragment] (buffer :type uniform)))Multiple Uniforms
Section titled “Multiple Uniforms”(bind-group-layout :name sceneLayout (entry :binding 0 :visibility [vertex fragment] (buffer :type uniform)) (entry :binding 1 :visibility [fragment] (buffer :type uniform)) (entry :binding 2 :visibility [vertex fragment] (buffer :type uniform)))Compute Storage Layout
Section titled “Compute Storage Layout”(bind-group-layout :name computeLayout (entry :binding 0 :visibility [compute] (buffer :type read-only-storage)) (entry :binding 1 :visibility [compute] (buffer :type storage)))Texture, Sampler and Storage Texture
Section titled “Texture, Sampler and Storage Texture”(bind-group-layout :name imageLayout (entry :binding 0 :visibility [fragment] (sampler :type filtering)) (entry :binding 1 :visibility [fragment] (texture :sample-type float)) (entry :binding 2 :visibility [compute] (storage-texture :format rgba8unorm :access write-only :view-dimension 2d)))Array and Cube Views
Section titled “Array and Cube Views”(bind-group-layout :name arrayLayout (entry :binding 0 :visibility [fragment] (texture :sample-type float :view-dimension 2d-array)) (entry :binding 1 :visibility [fragment] (texture :sample-type float :view-dimension cube)))Shadow Map Layout
Section titled “Shadow Map Layout”(bind-group-layout :name shadowLayout (entry :binding 0 :visibility [fragment] (sampler :type comparison)) (entry :binding 1 :visibility [fragment] (texture :sample-type depth)))Validation Rules
Section titled “Validation Rules”| Rule | Error |
|---|---|
| Name must be unique across every form kind | duplicate_cross_ref_target |
Each entry requires :binding and :visibility |
missing_required_key |
| Each entry must carry exactly one resource sub-form | positional_missing / positional_too_many |
(buffer …) requires :type |
missing_required_key |
(storage-texture …) requires :format |
missing_required_key |
:visibility takes only vertex, fragment, compute |
not_member |
:view-dimension takes a spec spelling, not an integer |
wrong_underlying |
A bind-group layout, a render pipeline and a compute pipeline share one
cross-reference target group, because a (bind-group …) may name any of them, so
a name collision between two of those kinds is a duplicate_cross_ref_target.
Across unrelated kinds the compiler reports it instead, with a located message
and no code: duplicate name 'x': already declared as a (buffer …) at line N.
The entry types must match the WGSL binding they front, or WebGPU rejects the pipeline; the native renderer reports that as a nonzero exit rather than a blank frame.
WebGPU Mapping
Section titled “WebGPU Mapping”Maps to GPUBindGroupLayout via:
device.createBindGroupLayout({ entries: [ { binding: 0, visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT, buffer: { type: 'uniform' } }, { binding: 1, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: 'float', viewDimension: '2d' } } ]});:visibility becomes the ORed GPUShaderStage mask (vertex 0x1, fragment
0x2, compute 0x4). Each resource sub-form’s enum values are the WebGPU
spellings, passed through verbatim.
Related
Section titled “Related”(pipeline-layout …)- Compose layouts into a pipeline layout(bind-group …)- Create bind groups using this layout(buffer …)- Buffer resources(texture …)- Texture resources(sampler …)- Sampler resources