Signatur
Beschreibung
createPipelineLayout() erzeugt ein explizites Pipeline-Layout. Es beschreibt die Schnittstelle zwischen Shader-Ressourcen und Pipeline: Das Array bindGroupLayouts ordnet jedem @group(n)-Index im WGSL-Shader ein GPUBindGroupLayout zu. Das Ergebnis übergibt man anschließend als layout-Eigenschaft an createRenderPipeline() oder createComputePipeline().
Alternativ kann man layout: "auto" verwenden; dann leitet WebGPU das Layout aus dem Shader ab. Das ist bequem, hat aber einen Nachteil: Automatisch erzeugte Bind-Group-Layouts sind an genau eine Pipeline gebunden, und Bind Groups lassen sich nicht zwischen Pipelines teilen. Ein explizites Layout lohnt sich daher immer, wenn mehrere Pipelines dieselben Bind Groups nutzen sollen (z. B. eine gemeinsame Kamera-/Szenen-Gruppe an @group(0)), oder wenn Ressourcen eingebunden werden, die der Shader aktuell gar nicht verwendet.
Die Methode arbeitet synchron und liefert sofort ein Objekt zurück. Validierungsfehler (etwa zu viele Bind Groups oder Überschreitung der Geräte-Limits) werfen keine Ausnahme, sondern erzeugen einen GPU-Validierungsfehler und ein ungültiges Layout. Solche Fehler fängt man mit pushErrorScope()/popErrorScope() oder dem uncapturederror-Ereignis ab.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $descriptor Pflicht | GPUPipelineLayoutDescriptor | Konfigurationsobjekt mit den folgenden Eigenschaften. | |
| $descriptor.bindGroupLayouts Pflicht | Array<GPUBindGroupLayout | null> | Liste der Bind-Group-Layouts; der Array-Index entspricht dem @group(n)-Index im Shader. Die Länge darf device.limits.maxBindGroups (mindestens 4) nicht überschreiten. Neuere Implementierungen erlauben null-Einträge für ungenutzte Gruppen. |
|
| $descriptor.label | string | "" | Optionaler Name zur Identifikation in Fehlermeldungen und Debugging-Werkzeugen. |
Rückgabewert
GPUPipelineLayout-Objekt, das als layout an createRenderPipeline(), createRenderPipelineAsync(), createComputePipeline() oder createComputePipelineAsync() übergeben wird.Beispiele
Compute-Pipeline mit explizitem Layout
const adapter = await navigator.gpu?.requestAdapter();
if (!adapter) throw new Error('WebGPU wird nicht unterstützt');
const device = await adapter.requestDevice();
const shader = 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) {
if (id.x < arrayLength(&data)) { data[id.x] *= 2.0; }
}`
});
// Layout der Gruppe 0 beschreiben
const bindGroupLayout = device.createBindGroupLayout({
label: 'Daten-Gruppe',
entries: [{
binding: 0,
visibility: GPUShaderStage.COMPUTE,
buffer: { type: 'storage' }
}]
});
// Pipeline-Layout: Index 0 -> @group(0)
const pipelineLayout = device.createPipelineLayout({
label: 'Verdopplungs-Layout',
bindGroupLayouts: [bindGroupLayout]
});
const pipeline = device.createComputePipeline({
layout: pipelineLayout,
compute: { module: shader, entryPoint: 'main' }
});
console.log(pipelineLayout.label);
Gemeinsame Bind Group für mehrere Render-Pipelines
// Annahme: device, shaderModule und format existieren bereits
const sceneLayout = device.createBindGroupLayout({
entries: [{
binding: 0,
visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
buffer: { type: 'uniform' }
}]
});
const materialLayout = device.createBindGroupLayout({
entries: [
{ binding: 0, visibility: GPUShaderStage.FRAGMENT, sampler: {} },
{ binding: 1, visibility: GPUShaderStage.FRAGMENT, texture: {} }
]
});
// Beide Pipelines teilen sich Gruppe 0 (Szene) und Gruppe 1 (Material)
const sharedLayout = device.createPipelineLayout({
label: 'Szene+Material',
bindGroupLayouts: [sceneLayout, materialLayout]
});
const makePipeline = (fragmentEntry) => device.createRenderPipeline({
layout: sharedLayout,
vertex: { module: shaderModule, entryPoint: 'vs_main' },
fragment: {
module: shaderModule,
entryPoint: fragmentEntry,
targets: [{ format }]
}
});
const opaquePipeline = makePipeline('fs_opaque');
const unlitPipeline = makePipeline('fs_unlit');
// Eine mit sceneLayout erstellte Bind Group funktioniert nun in beiden Pipelines.
Validierungsfehler abfangen
device.pushErrorScope('validation');
// Absichtlich zu viele Gruppen
const tooMany = Array.from(
{ length: device.limits.maxBindGroups + 1 },
() => device.createBindGroupLayout({ entries: [] })
);
device.createPipelineLayout({ bindGroupLayouts: tooMany });
const error = await device.popErrorScope();
console.log(error ? `Fehler: ${error.message}` : 'Layout gültig');
// Wichtig · Fallstricke
- Keine Ausnahmen: Ungültige Deskriptoren führen zu einem GPU-Validierungsfehler und einem ungültigen Objekt. Der Fehler zeigt sich oft erst beim Erstellen der Pipeline. Mit
pushErrorScope('validation')prüfen. - Index = Gruppennummer: Die Reihenfolge im Array
bindGroupLayoutsmuss zu den@group(n)-Angaben im Shader passen. Die Bindings des Shaders müssen in Typ undvisibilitymit den Layout-Einträgen übereinstimmen, sonst schlägt die Pipeline-Erstellung fehl. - Limits: Die Anzahl der Gruppen ist durch
device.limits.maxBindGroupsbegrenzt (Standard: 4). Auch die Gesamtzahl bestimmter Ressourcen pro Shaderstufe (z. B.maxStorageBuffersPerShaderStage) wird über alle Gruppen hinweg geprüft. "auto"vs. explizit: Bind Groups, die mitpipeline.getBindGroupLayout(n)aus einem"auto"-Layout erstellt wurden, sind nicht mit anderen Pipelines kompatibel. Für wiederverwendbare Ressourcen daher explizite Layouts nutzen.- Kompatibilität: WebGPU ist nur in sicheren Kontexten (HTTPS/localhost) verfügbar und noch nicht auf allen Plattformen aktiviert. Immer vorher
navigator.gpuund das Ergebnis vonrequestAdapter()prüfen.null-Einträge inbindGroupLayoutssind eine neuere Ergänzung der Spezifikation und werden nicht überall unterstützt.