Keyboard shortcuts

Press โ† or โ†’ to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Bind Groups & Buffers

WgpuLinkage exposes the bind groups, bindings, and buffers declared by a shader via uniform!, storage!, workgroup!, texture!, and sampler!.

Bind groups

Each @group(n) in WGSL corresponds to a BindGroupInfo. Access them by index or iterate:

#![allow(unused)]
fn main() {
let bg0: &BindGroupInfo = linkage.bind_group(0).expect("group 0 exists");
for (n, bg) in linkage.bind_groups() {
    println!("group {n}: {} bindings", bg.bindings.len());
}
}

BindGroupInfo carries:

  • The group index.
  • The list of bindings (@binding(i) entries) with their names, types, and visibility (see Per-binding Shader Stages).
  • A method to create the wgpu::BindGroupLayout.

Creating a bind group

The simplest path: WgpuLinkage::create_bind_group_named, which builds the bind group and caches the bind group layout for that group index:

#![allow(unused)]
fn main() {
let frame_bg = linkage.create_bind_group_named(0, &device, &[
    ("FRAME", frame_buffer.as_entire_binding()),
    ("COLOR_TEX", &color_texture_view),
    ("COLOR_SMP", &color_sampler),
])?;
}

Each entry is ("NAME", resource) where NAME is the binding name declared in the shader (the first argument to uniform!/storage!/texture!/ sampler!) and resource is a wgpu::BindingResource.

For more control, use BindGroupInfo::create directly:

#![allow(unused)]
fn main() {
let layout = bg0.create_layout(&device);
let bg = bg0.create(&device, &layout, &[
    frame_buffer.as_entire_binding(),
    &color_texture_view,
    &color_sampler,
]);
}

Resources must be supplied in binding-index order, matching the @binding(i) numbering in the generated WGSL.

create_named lets you supply resources by name regardless of order:

#![allow(unused)]
fn main() {
let bg = bg0.create_named("renderer", &device, &layout, &[
    ("FRAME", frame_buffer.as_entire_binding()),
    ("COLOR_TEX", &color_texture_view),
]);
}

Buffers

uniform! and storage! bindings produce a BufferDescriptorInfo entry that knows the buffer's WGSL size and usage. Find a buffer by its declared name:

#![allow(unused)]
fn main() {
let frame_buf_info = linkage.buffer("FRAME").expect("FRAME buffer exists");
let frame_buffer = frame_buf_info.create_buffer(&device);
}

BufferDescriptorInfo::create_buffer(device) returns a wgpu::Buffer sized per WGSL ยง14.4.1, with wgpu::BufferUsages derived from how the shader declares the binding (uniform vs storage, read-only vs read-write).

Workgroup variables

workgroup! bindings do not appear in bind groups โ€” they are workgroup-scoped storage. They do not need wgpu host-side resources.

Example: full bind group setup

#![allow(unused)]
fn main() {
let frame_info = linkage.buffer("FRAME").unwrap();
let frame_buffer = frame_info.create_buffer(&device);

let frame_bg = linkage.create_bind_group_named(0, &device, &[
    ("FRAME", frame_buffer.as_entire_binding()),
    ("ALBEDO", &albedo_view),
    ("SMP", &linear_sampler),
])?;
}

Layout caching

create_bind_group_named caches the wgpu::BindGroupLayout inside the WgpuLinkage so subsequent calls for the same group index return the cached layout. BindGroupInfo::create/create_named take an explicit layout, so you control whether to cache yourself.