Start · Sprachen · JavaScript · Referenz · GPUBindGroupLayout

GPUBindGroupLayout

Schnittstelle

Beschreibt als Vorlage, welche GPU-Ressourcen (Buffer, Texturen, Sampler) an welchen Bindings und Shader-Stufen eine <code>GPUBindGroup</code> bereitstellen muss.

seit JavaScript Chrome/Edge 113+, Firefox 141+ (Windows), Safari 2 Kategorie: webapi

Signatur

interface GPUBindGroupLayout

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);
Kamera-Layout

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);
true

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);
true

// 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 ein GPUPipelineLayout verwenden.
  • Shader und Layout müssen übereinstimmen: binding, Ressourcentyp und visibility müssen zu den @group/@binding-Deklarationen in WGSL passen. Sonst schlägt die Pipeline-Erstellung fehl. Die Fehler kommen asynchron, deshalb lohnen sich device.pushErrorScope("validation") und aussagekräftige label-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 maxUniformBuffersPerShaderStage oder maxBindGroups (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.gpu prüfen, ob WebGPU vorhanden ist.