Signatur
Beschreibung
Ein GPUBindGroupLayout gehört zur WebGPU-API und legt die Struktur einer Gruppe zusammengehöriger Ressourcen fest. Dazu gehört, welcher Binding-Index welchen Ressourcentyp enthält (Uniform-/Storage-Buffer, Textur, Sampler, Storage-Textur, externe Textur) und in welchen Shader-Stufen (VERTEX, FRAGMENT, COMPUTE) er sichtbar ist. Die Ressourcen selbst enthält das Layout nicht. Es ist nur der „Bauplan“, nach dem später mit GPUDevice.createBindGroup() konkrete GPUBindGroup-Objekte entstehen.
Ein Layout bekommt man auf zwei Wegen: explizit über GPUDevice.createBindGroupLayout(descriptor) oder implizit über pipeline.getBindGroupLayout(index), wenn die Pipeline mit layout: "auto" erstellt wurde. Explizite Layouts lassen sich über ein GPUPipelineLayout in mehreren Pipelines verwenden. Dann kann dieselbe Bind Group mit verschiedenen Pipelines genutzt werden, was bei vielen Materialien oder Render-Durchläufen wichtig ist.
Die Schnittstelle selbst ist schlank. Sie hat nur die Eigenschaft label, einen frei wählbaren Namen für Fehlermeldungen und Debugging-Werkzeuge. Einen öffentlichen Konstruktor gibt es nicht.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $descriptor.label | string | "" | Optionaler Name für Debugging und Fehlermeldungen (Parameter von createBindGroupLayout()). |
| $descriptor.entries Pflicht | Array<GPUBindGroupLayoutEntry> | Liste der Bindings. Jeder Eintrag hat binding (Index), visibility (Bitmaske aus GPUShaderStage) und genau eines der Objekte buffer, sampler, texture, storageTexture oder externalTexture. |
|
| $entry.buffer | { type?: "uniform"|"storage"|"read-only-storage", hasDynamicOffset?: boolean, minBindingSize?: number } | { type: "uniform" } | Beschreibt ein Buffer-Binding. Mit hasDynamicOffset sind dynamische Offsets in setBindGroup() möglich. |
| $entry.texture | { sampleType?: string, viewDimension?: string, multisampled?: boolean } | { sampleType: "float", viewDimension: "2d" } | Beschreibt ein Textur-Binding, das im Shader gesampelt wird. |
| $entry.sampler | { type?: "filtering"|"non-filtering"|"comparison" } | { type: "filtering" } | Beschreibt ein Sampler-Binding. |
| $entry.storageTexture | { access?: string, format: GPUTextureFormat, viewDimension?: string } | Beschreibt eine Storage-Textur (z. B. access: "write-only"). |
Beispiele
Layout explizit erstellen und Bind Group ableiten
const adapter = await navigator.gpu?.requestAdapter();
if (!adapter) throw new Error('WebGPU nicht verfügbar');
const device = await adapter.requestDevice();
// Layout: Uniform-Buffer für Vertex- und Fragment-Shader
const bindGroupLayout = device.createBindGroupLayout({
label: 'Kamera-Layout',
entries: [
{
binding: 0,
visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
buffer: { type: 'uniform' }
}
]
});
const uniformBuffer = device.createBuffer({
size: 64, // 4x4-Matrix aus float32
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
});
const bindGroup = device.createBindGroup({
layout: bindGroupLayout,
entries: [{ binding: 0, resource: { buffer: uniformBuffer } }]
});
console.log(bindGroupLayout.label);
Layout mit Textur und Sampler für ein Material
const materialLayout = device.createBindGroupLayout({
label: 'Material-Layout',
entries: [
{ binding: 0, visibility: GPUShaderStage.FRAGMENT, sampler: { type: 'filtering' } },
{ binding: 1, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: 'float' } }
]
});
// Pipeline-Layout: Gruppe 0 = Kamera, Gruppe 1 = Material
const pipelineLayout = device.createPipelineLayout({
bindGroupLayouts: [bindGroupLayout, materialLayout]
});
// WGSL-Gegenstück:
// @group(1) @binding(0) var mySampler: sampler;
// @group(1) @binding(1) var myTexture: texture_2d<f32>;
console.log(pipelineLayout instanceof GPUPipelineLayout);
Implizites Layout einer Compute-Pipeline abfragen
const module = device.createShaderModule({
code: `
@group(0) @binding(0) var<storage, read_write> data: array<f32>;
@compute @workgroup_size(64)
fn main(@builtin(global_invocation_id) id: vec3u) {
data[id.x] = data[id.x] * 2.0;
}
`
});
const pipeline = device.createComputePipeline({
layout: 'auto',
compute: { module, entryPoint: 'main' }
});
// Layout aus dem Shader ableiten lassen
const layout = pipeline.getBindGroupLayout(0);
const storageBuffer = device.createBuffer({
size: 256 * 4,
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST
});
const bindGroup = device.createBindGroup({
layout,
entries: [{ binding: 0, resource: { buffer: storageBuffer } }]
});
console.log(layout instanceof GPUBindGroupLayout);
// Wichtig · Fallstricke
- Automatische Layouts lassen sich nicht teilen: Ein mit
layout: "auto"erzeugtes Layout passt nur zu genau der Pipeline, aus der es stammt. Wird eine damit erstellte Bind Group mit einer anderen Pipeline verwendet, entsteht ein Validierungsfehler, selbst wenn die Struktur identisch ist. Wer eine Bind Group in mehreren Pipelines nutzen will, sollte explizite Layouts und einGPUPipelineLayoutverwenden. - Shader und Layout müssen übereinstimmen:
binding, Ressourcentyp undvisibilitymüssen zu den@group/@binding-Deklarationen in WGSL passen. Sonst schlägt die Pipeline-Erstellung fehl. Die Fehler kommen asynchron, deshalb lohnen sichdevice.pushErrorScope("validation")und aussagekräftigelabel-Werte. - Nicht in jeder Stufe erlaubt: Storage-Buffer mit
type: "storage"und beschreibbare Storage-Texturen sind im Vertex-Shader nicht zulässig. - Geräte-Grenzwerte: Die Zahl der Bindings pro Stufe ist begrenzt, z. B. durch
maxUniformBuffersPerShaderStageodermaxBindGroups(standardmäßig 4). - Browser-Unterstützung: WebGPU steht nur in sicheren Kontexten zur Verfügung und ist noch nicht auf allen Plattformen vollständig umgesetzt. Vorher mit
navigator.gpuprüfen, ob WebGPU vorhanden ist.