Signatur
Beschreibung
Eine GPUQueue ist die Befehlswarteschlange eines GPUDevice. Man erzeugt sie nicht selbst, sondern greift über device.queue darauf zu. Jedes Gerät hat genau eine Standard-Queue. Alles, was die GPU tatsächlich ausführen soll, landet früher oder später in dieser Queue: fertig kodierte GPUCommandBuffer-Objekte, Datenuploads in Puffer und Texturen sowie Kopien aus Bildquellen.
Die wichtigsten Methoden:
submit(commandBuffers): Übergibt ein Array von Befehlspuffern (erzeugt mitGPUCommandEncoder.finish()) an die GPU zur Ausführung.writeBuffer(buffer, bufferOffset, data, dataOffset?, size?): Schreibt Daten aus einemArrayBuffer,TypedArrayoderDataViewin einenGPUBuffer. Der Puffer braucht dafür das Usage-FlagGPUBufferUsage.COPY_DST.writeTexture(destination, data, dataLayout, size): Schreibt Rohdaten in eineGPUTexture.copyExternalImageToTexture(source, destination, copySize): Kopiert einImageBitmap,HTMLCanvasElement,HTMLVideoElement,VideoFrameo. Ä. in eine Textur.onSubmittedWorkDone(): Gibt einPromise<undefined>zurück, das erfüllt wird, sobald die GPU alle bis dahin übergebene Arbeit erledigt hat.label: Ein frei wählbarer Name. Er taucht in Fehlermeldungen und Debug-Werkzeugen auf.
Alle Methoden arbeiten asynchron gegenüber der GPU. Der Aufruf kehrt sofort zurück, und die eigentliche Arbeit läuft später auf der Grafikkarte. Die Reihenfolge bleibt dabei erhalten: Ein writeBuffer() vor einem submit() ist garantiert sichtbar, wenn die übergebenen Befehle laufen. Deshalb eignen sich writeBuffer() und writeTexture() gut für häufige, kleine Aktualisierungen wie Uniforms pro Frame. Ein manuelles Mappen von Staging-Puffern ist dafür nicht nötig.
Rückgabewert
submit(), writeBuffer(), writeTexture() und copyExternalImageToTexture() geben undefined zurück. onSubmittedWorkDone() gibt ein Promise<undefined> zurück.Beispiele
Queue holen und einen Render-Pass übergeben
const adapter = await navigator.gpu?.requestAdapter();
if (!adapter) throw new Error('WebGPU nicht verfügbar');
const device = await adapter.requestDevice();
const queue = device.queue; // keine Instanziierung – kommt vom Gerät
queue.label = 'Haupt-Queue';
const canvas = document.querySelector('canvas');
const context = canvas.getContext('webgpu');
context.configure({ device, format: navigator.gpu.getPreferredCanvasFormat() });
const encoder = device.createCommandEncoder();
const pass = encoder.beginRenderPass({
colorAttachments: [{
view: context.getCurrentTexture().createView(),
clearValue: { r: 0.1, g: 0.2, b: 0.4, a: 1 },
loadOp: 'clear',
storeOp: 'store'
}]
});
pass.end();
queue.submit([encoder.finish()]);
console.log(queue.label);
Uniform-Puffer pro Frame mit writeBuffer aktualisieren
const uniformBuffer = device.createBuffer({
size: 16, // 4 × float32
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
});
const frame = (time) => {
const uniforms = new Float32Array([time / 1000, canvas.width, canvas.height, 0]);
device.queue.writeBuffer(uniformBuffer, 0, uniforms);
// ... Befehle kodieren, die uniformBuffer nutzen, dann:
// device.queue.submit([encoder.finish()]);
requestAnimationFrame(frame);
};
requestAnimationFrame(frame);
Bild in eine Textur laden
const response = await fetch('/img/logo.png');
const bitmap = await createImageBitmap(await response.blob());
const texture = device.createTexture({
size: [bitmap.width, bitmap.height],
format: 'rgba8unorm',
usage: GPUTextureUsage.TEXTURE_BINDING |
GPUTextureUsage.COPY_DST |
GPUTextureUsage.RENDER_ATTACHMENT
});
device.queue.copyExternalImageToTexture(
{ source: bitmap, flipY: true },
{ texture },
[bitmap.width, bitmap.height]
);
console.log('Textur:', texture.width, 'x', texture.height);
Auf das Ende der GPU-Arbeit warten (Compute-Ergebnis messen)
const start = performance.now();
const encoder = device.createCommandEncoder();
const pass = encoder.beginComputePass();
pass.setPipeline(computePipeline);
pass.setBindGroup(0, bindGroup);
pass.dispatchWorkgroups(64);
pass.end();
device.queue.submit([encoder.finish()]);
await device.queue.onSubmittedWorkDone();
console.log(`GPU fertig nach ${(performance.now() - start).toFixed(1)} ms`);