Start · Sprachen · JavaScript · Referenz · WebGL2RenderingContext.deleteSync()

WebGL2RenderingContext.deleteSync()

Methode

Löscht ein mit <code>fenceSync()</code> erzeugtes <code>WebGLSync</code>-Objekt und gibt die zugehörigen GPU-Ressourcen frei.

seit JavaScript WebGL 2.0 – Baseline: alle modernen Browser Kategorie: webapi

Signatur

WebGL2RenderingContext.prototype.deleteSync(sync)

Beschreibung

Die Methode deleteSync() des WebGL2RenderingContext markiert ein WebGLSync-Objekt zum Löschen. Solche Sync-Objekte (auch „Fences“ genannt) entstehen durch gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0). Mit ihnen lässt sich feststellen, ob die GPU alle bis dahin abgesetzten Befehle abgearbeitet hat.

Typische Anwendungsfälle sind das asynchrone Zurücklesen von Pixeldaten über Pixel Buffer Objects (PBO), das Streamen von Texturen und das Vermeiden von Pipeline-Stalls. Sobald ein Fence signalisiert wurde oder nicht mehr gebraucht wird, sollte man ihn mit deleteSync() löschen. Sonst sammeln sich mit jedem Frame weitere Sync-Objekte an.

Wenn noch jemand auf das Sync-Objekt wartet, etwa über clientWaitSync() oder waitSync(), wird es erst gelöscht, wenn kein Wartevorgang mehr daran hängt. Wird null übergeben, passiert nichts.

Parameter

Name Typ Default Beschreibung
$sync Pflicht WebGLSync | null Das zu löschende Sync-Objekt, das zuvor mit gl.fenceSync() erzeugt wurde. Bei null wird der Aufruf still ignoriert.

Rückgabewert

Typ
void
Beschreibung
Kein Rückgabewert (undefined).

Beispiele

Fence erzeugen, prüfen und löschen

const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl2');

gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);

// Fence nach den Zeichenbefehlen setzen
const sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);
gl.flush();

console.log(gl.isSync(sync)); // true

gl.deleteSync(sync);
console.log(gl.isSync(sync)); // false
true false

Asynchrones Zurücklesen per PBO mit Fence-Polling

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 status = gl.clientWaitSync(sync, 0, 0);
      if (status === gl.WAIT_FAILED) {
        gl.deleteSync(sync);
        gl.deleteBuffer(buf);
        reject(new Error('clientWaitSync fehlgeschlagen'));
      } else if (status === gl.TIMEOUT_EXPIRED) {
        requestAnimationFrame(poll);
      } else {
        // Fence ist signalisiert, wird also nicht mehr gebraucht
        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 pixels = await readPixelsAsync(gl, 0, 0, 1, 1);
console.log(pixels);
Uint8Array(4) [255, 0, 0, 255]

Aufräumen im Render-Loop, damit sich keine Fences ansammeln

const gl = document.createElement('canvas').getContext('webgl2');
let pendingSync = null;

const frame = () => {
  // Fence aus dem vorherigen Frame prüfen
  if (pendingSync) {
    const signaled = gl.getSyncParameter(pendingSync, gl.SYNC_STATUS) === gl.SIGNALED;
    if (signaled) {
      gl.deleteSync(pendingSync);
      pendingSync = null;
    }
  }

  gl.clear(gl.COLOR_BUFFER_BIT);

  if (!pendingSync) {
    pendingSync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);
  }
  requestAnimationFrame(frame);
};
requestAnimationFrame(frame);

// Wichtig · Fallstricke

  • Nur in WebGL 2: Die Methode gibt es im WebGL2RenderingContext, nicht im WebGLRenderingContext (WebGL 1). Prüfe also, ob canvas.getContext('webgl2') tatsächlich einen Kontext liefert. Alle modernen Browser unterstützen WebGL 2, Safari erst ab Version 15.
  • Speicherlecks: Wenn du pro Frame einen Fence mit fenceSync() anlegst und ihn nie löschst, sammeln sich Treiber-Ressourcen an. Rufe deleteSync() auf jedem Codepfad auf, auch bei Fehlern und Timeouts.
  • Nach dem Löschen: Ein gelöschtes Sync-Objekt darf nicht mehr an clientWaitSync(), waitSync() oder getSyncParameter() übergeben werden. Das erzeugt INVALID_VALUE bzw. INVALID_OPERATION. isSync() liefert danach false. Setze deine Referenz am besten gleich auf null.
  • Kontextverlust: Nach einem webglcontextlost-Event sind alle Sync-Objekte ungültig. deleteSync() ist dann wirkungslos.
  • Browser signalisieren einen Fence frühestens, nachdem die Kontrolle an die Ereignisschleife zurückgegeben wurde. Synchrones Warten in einer Schleife bringt daher nichts. Frage den Status stattdessen über requestAnimationFrame oder setTimeout ab.