Start · Sprachen · JavaScript · Referenz · GPUDevice.createBindGroup()

GPUDevice.createBindGroup()

Methode

Erstellt eine <code>GPUBindGroup</code>, die konkrete Ressourcen (Puffer, Texturen, Sampler) an die Slots eines <code>GPUBindGroupLayout</code> bindet, damit Shader darauf zugreifen können.

seit JavaScript WebGPU – Chrome/Edge 113+, Safari 26+, Firefox 141 Kategorie: webapi

Signatur

GPUDevice.prototype.createBindGroup(descriptor)

Beschreibung

createBindGroup() verbindet echte GPU-Ressourcen mit den @group/@binding-Deklarationen eines WGSL-Shaders. Das zugrunde liegende GPUBindGroupLayout legt fest, welche Art von Ressource an welchem Binding-Index erwartet wird. Die Bind Group liefert dann die konkreten Objekte, also etwa einen bestimmten Uniform-Puffer oder eine bestimmte Textur-Ansicht.

Gebraucht wird die Methode immer dann, wenn ein Render- oder Compute-Pipeline Daten lesen oder schreiben soll: Uniforms (Kameramatrizen, Zeit), Storage-Puffer (Partikel, Rechenergebnisse), Texturen und Sampler. Die fertige Bind Group wird während eines Durchlaufs mit passEncoder.setBindGroup(index, bindGroup) gesetzt.

Das Layout kann explizit mit device.createBindGroupLayout() erstellt werden oder bei Pipelines mit layout: "auto" über pipeline.getBindGroupLayout(index) abgefragt werden. Bind Groups sind unveränderlich. Den Inhalt eines gebundenen Puffers darfst du jederzeit ändern (z. B. mit queue.writeBuffer()). Willst du aber eine andere Ressource binden, brauchst du eine neue Bind Group.

Parameter

Name Typ Default Beschreibung
$descriptor Pflicht GPUBindGroupDescriptor Konfigurationsobjekt mit folgenden Eigenschaften:
  • layout (GPUBindGroupLayout, Pflicht): das Layout, dem die Einträge entsprechen müssen.
  • entries (Array<GPUBindGroupEntry>, Pflicht): pro Binding ein Objekt { binding, resource }.
  • label (string, optional): Name für Fehlermeldungen und Debugging-Werkzeuge.
$descriptor.entries[].binding Pflicht number Binding-Index. Er muss zu einem Eintrag im Layout und zu @binding(n) im WGSL-Code passen.
$descriptor.entries[].resource Pflicht GPUBufferBinding | GPUTextureView | GPUSampler | GPUExternalTexture | GPUBuffer Die zu bindende Ressource. Puffer werden als { buffer, offset?, size? } übergeben (offset ist standardmäßig 0, size standardmäßig der Rest des Puffers). In neueren Implementierungen darfst du auch direkt einen GPUBuffer übergeben.

Rückgabewert

Typ
GPUBindGroup
Beschreibung
Eine neue, unveränderliche GPUBindGroup. Ist der Deskriptor ungültig, bekommst du trotzdem ein Objekt zurück. Es ist dann aber ungültig, und es wird ein Validierungsfehler gemeldet (keine Ausnahme!).

Beispiele

Uniform-Puffer an eine Render-Pipeline binden

const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();

const shader = device.createShaderModule({
  code: `
    struct U { color: vec4f };
    @group(0) @binding(0) var<uniform> u: U;
    @vertex fn vs(@builtin(vertex_index) i: u32) -> @builtin(position) vec4f {
      let p = array(vec2f(0, 0.5), vec2f(-0.5, -0.5), vec2f(0.5, -0.5));
      return vec4f(p[i], 0, 1);
    }
    @fragment fn fs() -> @location(0) vec4f { return u.color; }
  `
});

const pipeline = device.createRenderPipeline({
  layout: 'auto',
  vertex: { module: shader, entryPoint: 'vs' },
  fragment: { module: shader, entryPoint: 'fs', targets: [{ format: navigator.gpu.getPreferredCanvasFormat() }] }
});

const uniformBuffer = device.createBuffer({
  size: 16,
  usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
});
device.queue.writeBuffer(uniformBuffer, 0, new Float32Array([1, 0.4, 0, 1]));

const bindGroup = device.createBindGroup({
  label: 'Farb-Uniforms',
  layout: pipeline.getBindGroupLayout(0),
  entries: [{ binding: 0, resource: { buffer: uniformBuffer } }]
});

console.log(bindGroup.label);
// Später im Render-Pass: pass.setBindGroup(0, bindGroup);
Farb-Uniforms

Explizites Layout mit Storage-Puffern für einen Compute-Shader

const device = await (await navigator.gpu.requestAdapter()).requestDevice();

const layout = device.createBindGroupLayout({
  entries: [
    { binding: 0, visibility: GPUShaderStage.COMPUTE, buffer: { type: 'read-only-storage' } },
    { binding: 1, visibility: GPUShaderStage.COMPUTE, buffer: { type: 'storage' } }
  ]
});

const input = device.createBuffer({ size: 1024, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST });
const output = device.createBuffer({ size: 1024, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC });

const bindGroup = device.createBindGroup({
  layout,
  entries: [
    { binding: 0, resource: { buffer: input } },
    // Nur die zweite Hälfte des Puffers binden (Offset muss 256-Byte-ausgerichtet sein)
    { binding: 1, resource: { buffer: output, offset: 256, size: 768 } }
  ]
});

const pipeline = device.createComputePipeline({
  layout: device.createPipelineLayout({ bindGroupLayouts: [layout] }),
  compute: {
    module: device.createShaderModule({ code: `
      @group(0) @binding(0) var<storage, read> a: array<f32>;
      @group(0) @binding(1) var<storage, read_write> b: array<f32>;
      @compute @workgroup_size(64) fn main(@builtin(global_invocation_id) id: vec3u) {
        if (id.x < arrayLength(&b)) { b[id.x] = a[id.x] * 2.0; }
      }` }),
    entryPoint: 'main'
  }
});

const encoder = device.createCommandEncoder();
const pass = encoder.beginComputePass();
pass.setPipeline(pipeline);
pass.setBindGroup(0, bindGroup);
pass.dispatchWorkgroups(4);
pass.end();
device.queue.submit([encoder.finish()]);

Textur und Sampler binden, Validierungsfehler abfangen

const device = await (await navigator.gpu.requestAdapter()).requestDevice();

const layout = device.createBindGroupLayout({
  entries: [
    { binding: 0, visibility: GPUShaderStage.FRAGMENT, sampler: {} },
    { binding: 1, visibility: GPUShaderStage.FRAGMENT, texture: {} }
  ]
});

const texture = device.createTexture({
  size: [256, 256],
  format: 'rgba8unorm',
  usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST
});
const sampler = device.createSampler({ magFilter: 'linear', minFilter: 'linear' });

device.pushErrorScope('validation');
const bindGroup = device.createBindGroup({
  label: 'Material',
  layout,
  entries: [
    { binding: 0, resource: sampler },
    { binding: 1, resource: texture.createView() }
  ]
});
const error = await device.popErrorScope();
console.log(error ? `Fehler: ${error.message}` : 'Bind Group gültig');
Bind Group gültig