Skip to content

(pipeline-layout …)

Composes an ordered list of (bind-group-layout …) into an explicit GPUPipelineLayout that a (render-pipeline …) or (compute-pipeline …) names as its :layout instead of auto-deriving its layout from the WGSL.

This is the only way to bind @group(0), @group(1), … to distinct explicit layouts, pinning per-group binding visibility and buffer-binding types that the shader alone doesn’t determine. Otherwise a pipeline states :layout auto, whose single implicit layout is inferred from shader usage.

(pipeline-layout :name pl :bind-group-layouts [bgl0 bgl1])
Key Type Required Description
:name symbol Yes Unique pipeline-layout name
:bind-group-layouts reference list Yes Declared (bind-group-layout …) names at @group 0, 1, … in order (at least one)
(shader-module :name mod :code """
@group(0) @binding(0) var<uniform> tint: vec4f;
@group(1) @binding(0) var<uniform> xform: vec4f;
@vertex fn vs() -> @builtin(position) vec4f { return vec4f(xform.xy, 0, 1); }
@fragment fn fs() -> @location(0) vec4f { return tint; }
""")
(buffer :name colorBuf :size 16 :usage [uniform copy-dst])
(buffer :name xformBuf :size 16 :usage [uniform copy-dst])
(bind-group-layout :name bglColor
(entry :binding 0 :visibility [fragment] (buffer :type uniform)))
(bind-group-layout :name bglXform
(entry :binding 0 :visibility [vertex] (buffer :type uniform)))
; @group(0) = bglColor, @group(1) = bglXform
(pipeline-layout :name pl :bind-group-layouts [bglColor bglXform])
(render-pipeline :name pipe :layout pl
(vertex :module mod :entry vs)
(fragment :module mod :entry fs
(target :format bgra8unorm)))
; Bind groups take their per-group layout from the pipeline:
(bind-group :name gColor :layout pipe :group 0
(entry :binding 0 :buffer colorBuf))
(bind-group :name gXform :layout pipe :group 1
(entry :binding 0 :buffer xformBuf))
  • :layout is one required key on both (render-pipeline …) and (compute-pipeline …), mirroring GPUPipelineDescriptorBase.layout, which is one required member. Its value is either auto or the name of a (pipeline-layout …), never both and never neither.
  • auto is read as the builtin wherever it appears, so a (pipeline-layout …) cannot claim that name. Declaring one is a located compile error.
  • A :bind-group-layouts entry must cross-reference a declared (bind-group-layout …); a dangling name is a not_cross_ref validation error.
  • Bind groups reference the pipeline (:layout pipe :group N), so each group resolves to pipeline.getBindGroupLayout(N), the matching entry of the explicit layout. This is equivalent across the browser runtime, native wgpu, and the --html export.
Rule Error
Name must be unique across every form kind located message, no code (see below)
:bind-group-layouts is required missing_required_key
:bind-group-layouts may not be empty vector_too_short
Each referenced bind-group-layout must exist not_cross_ref

A pipeline layout is its own cross-reference target: only a pipeline’s :layout names one. (A (bind-group …) names a render pipeline, a compute pipeline or a bind-group layout, which is why those three share a target group and collide as duplicate_cross_ref_target.) A pipeline-layout name that another form already uses, whatever its kind, is the compiler’s located message with no code: duplicate name 'pipe': already declared as a (pipeline-layout …) at line 3.

Maps to GPUPipelineLayout via:

const pl = device.createPipelineLayout({
bindGroupLayouts: [bgl0, bgl1], // @group 0, 1
});
const pipe = device.createRenderPipeline({ layout: pl, /* … */ });