Signatur
Beschreibung
fenceSync() setzt eine Synchronisationsmarke (Fence) in die Befehlswarteschlange der GPU. Die Fence wird signalisiert, sobald alle vor ihr abgesetzten GL-Befehle vollständig von der GPU ausgeführt wurden. So lässt sich feststellen, wann asynchrone Arbeit wie Rendern, Transform Feedback oder ein readPixels() in einen Pixel-Buffer-Objekt (PBO) wirklich fertig ist.
Der typische Anwendungsfall ist das nicht blockierende Zurücklesen von GPU-Daten: Man startet readPixels() in einen PIXEL_PACK_BUFFER, setzt direkt danach eine Fence und fragt in späteren Frames mit clientWaitSync() (Timeout 0) oder getSyncParameter() ab, ob die Fence signalisiert ist. Erst dann ruft man getBufferSubData() auf – ohne die Render-Pipeline anzuhalten.
In WebGL 2 ist als condition ausschließlich gl.SYNC_GPU_COMMANDS_COMPLETE und als flags ausschließlich 0 zulässig. Das zurückgegebene Objekt sollte nach Gebrauch mit deleteSync() freigegeben werden.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $condition Pflicht | GLenum | Bedingung, bei der die Fence signalisiert wird. Einziger gültiger Wert: gl.SYNC_GPU_COMMANDS_COMPLETE. |
|
| $flags Pflicht | GLbitfield | 0 | Bitmaske für Verhaltensoptionen. Muss in WebGL 2 immer 0 sein. |
Rückgabewert
WebGLSync-Objekt, oder null, wenn ein Fehler auftritt (z. B. ungültige Argumente oder verlorener Kontext).Beispiele
Fence setzen und Status abfragen
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl2');
gl.clearColor(0, 0, 1, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
// Fence nach den Befehlen einfügen
const sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);
gl.flush(); // sicherstellen, dass die Fence an die GPU übergeben wird
const status = gl.getSyncParameter(sync, gl.SYNC_STATUS);
console.log(status === gl.SIGNALED ? 'fertig' : 'noch in Arbeit');
Nicht blockierendes readPixels über PBO
const readPixelsAsync = (gl, x, y, w, h) => {
const buf = gl.createBuffer();
gl.bindBuffer(gl.PIXEL_PACK_BUFFER, buf);
gl.bufferData(gl.PIXEL_PACK_BUFFER, w * h * 4, gl.STREAM_READ);
gl.readPixels(x, y, w, h, gl.RGBA, gl.UNSIGNED_BYTE, 0);
gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);
const sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);
gl.flush();
return new Promise((resolve, reject) => {
const poll = () => {
const res = gl.clientWaitSync(sync, 0, 0);
if (res === gl.WAIT_FAILED) {
gl.deleteSync(sync);
reject(new Error('clientWaitSync fehlgeschlagen'));
} else if (res === gl.TIMEOUT_EXPIRED) {
requestAnimationFrame(poll); // später erneut prüfen
} else {
gl.deleteSync(sync);
const data = new Uint8Array(w * h * 4);
gl.bindBuffer(gl.PIXEL_PACK_BUFFER, buf);
gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, data);
gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);
gl.deleteBuffer(buf);
resolve(data);
}
};
poll();
});
};
const gl = document.createElement('canvas').getContext('webgl2');
gl.clearColor(1, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
const pixel = await readPixelsAsync(gl, 0, 0, 1, 1);
console.log(pixel);
Fence auf der GPU-Seite abwarten (waitSync)
const gl = document.createElement('canvas').getContext('webgl2');
const sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);
// Die GPU wartet, bevor nachfolgende Befehle ausgeführt werden – blockiert JS nicht
gl.waitSync(sync, 0, gl.TIMEOUT_IGNORED);
gl.deleteSync(sync);
console.log(gl.getError() === gl.NO_ERROR);
// Wichtig · Fallstricke
- Nur WebGL 2: In einem WebGL-1-Kontext gibt es
fenceSync()nicht. Wird von allen aktuellen Browsern mit WebGL-2-Unterstützung angeboten (Chrome, Edge, Firefox, Safari 15+). - Ungültige Argumente: Andere Werte als
SYNC_GPU_COMMANDS_COMPLETEbzw.0erzeugenINVALID_ENUMbzw.INVALID_VALUE, und es wirdnullzurückgegeben. - Flush nicht vergessen: Ohne
gl.flush()(oder das FlagSYNC_FLUSH_COMMANDS_BITbeiclientWaitSync()) wird die Fence unter Umständen nie signalisiert. - Status erst im nächsten Task: Browser aktualisieren den Sync-Status laut Spezifikation frühestens, nachdem die aktuelle Aufgabe an die Event-Loop zurückgegeben wurde. Aktives Warten in einer Schleife funktioniert daher nicht – stattdessen per
requestAnimationFrameodersetTimeouterneut prüfen. - Timeouts:
clientWaitSync()erlaubt nur Timeouts bisMAX_CLIENT_WAIT_TIMEOUT_WEBGL(oft 0); blockierendes Warten im Hauptthread ist praktisch nicht möglich. - Ressourcen: Nicht mehr benötigte Fences mit
deleteSync()freigeben, um Speicherlecks zu vermeiden.