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

WebGL2RenderingContext.endQuery()

Methode

Beendet die aktive Abfrage für das angegebene Ziel, die vorher mit <code>beginQuery()</code> gestartet wurde. Das Ergebnis kann danach asynchron abgerufen werden.

seit JavaScript WebGL 2 – Baseline: alle modernen Browser (seit 20 Kategorie: webapi

Signatur

WebGL2RenderingContext.prototype.endQuery(target)

Beschreibung

Mit endQuery() beendest du eine GPU-Abfrage (WebGLQuery), die du vorher mit beginQuery() für dasselbe Ziel gestartet hast. Alle Zeichenbefehle zwischen den beiden Aufrufen fließen in das Ergebnis ein. Typische Einsatzfälle sind Occlusion Queries (Wurde von einem Objekt überhaupt etwas gezeichnet?) und Transform-Feedback-Abfragen (Wie viele Primitive wurden geschrieben?).

Das Ergebnis steht nicht sofort bereit, weil die GPU asynchron zur CPU arbeitet. Du fragst es mit gl.getQueryParameter(query, gl.QUERY_RESULT_AVAILABLE) ab und liest es erst dann mit gl.QUERY_RESULT. In WebGL wird ein Ergebnis frühestens im nächsten Frame verfügbar, also nachdem die Steuerung wieder an die Ereignisschleife des Browsers zurückgegeben wurde.

Pro Ziel kann immer nur eine Abfrage aktiv sein. ANY_SAMPLES_PASSED und ANY_SAMPLES_PASSED_CONSERVATIVE belegen dabei denselben Slot. Beide Aufrufe müssen also paarweise und mit demselben Ziel erfolgen.

Parameter

Name Typ Default Beschreibung
$target Pflicht GLenum Das Abfrageziel, dessen aktive Abfrage beendet werden soll: gl.ANY_SAMPLES_PASSED (Occlusion Query), gl.ANY_SAMPLES_PASSED_CONSERVATIVE (ungenauere, dafür schnellere Occlusion Query) oder gl.TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN. Mit der Erweiterung EXT_disjoint_timer_query_webgl2 kommt noch ext.TIME_ELAPSED_EXT dazu.

Rückgabewert

Typ
void
Beschreibung
Kein Rückgabewert (undefined). Das Ergebnis liest du später mit getQueryParameter() aus.

Beispiele

Einfache Occlusion Query

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

const query = gl.createQuery();

gl.beginQuery(gl.ANY_SAMPLES_PASSED, query);
// Hier z. B. eine Bounding-Box des Objekts zeichnen
// gl.drawArrays(gl.TRIANGLES, 0, 36);
gl.endQuery(gl.ANY_SAMPLES_PASSED);

console.log(gl.isQuery(query));
true

Ergebnis asynchron im nächsten Frame abfragen

const gl = document.querySelector('canvas').getContext('webgl2');
const query = gl.createQuery();

gl.beginQuery(gl.ANY_SAMPLES_PASSED_CONSERVATIVE, query);
// gl.drawElements(...) – Testgeometrie zeichnen
gl.endQuery(gl.ANY_SAMPLES_PASSED_CONSERVATIVE);

const poll = () => {
  const available = gl.getQueryParameter(query, gl.QUERY_RESULT_AVAILABLE);
  if (!available) {
    requestAnimationFrame(poll);
    return;
  }
  const visible = gl.getQueryParameter(query, gl.QUERY_RESULT);
  console.log(visible ? 'Objekt sichtbar' : 'Objekt verdeckt');
  gl.deleteQuery(query);
};
requestAnimationFrame(poll);
Objekt sichtbar

GPU-Zeitmessung mit EXT_disjoint_timer_query_webgl2

const gl = document.querySelector('canvas').getContext('webgl2');
const ext = gl.getExtension('EXT_disjoint_timer_query_webgl2');

if (ext) {
  const query = gl.createQuery();
  gl.beginQuery(ext.TIME_ELAPSED_EXT, query);
  // Aufwendige Zeichenbefehle ...
  gl.endQuery(ext.TIME_ELAPSED_EXT);

  const check = () => {
    const ready = gl.getQueryParameter(query, gl.QUERY_RESULT_AVAILABLE);
    const disjoint = gl.getParameter(ext.GPU_DISJOINT_EXT);
    if (ready && !disjoint) {
      const ns = gl.getQueryParameter(query, gl.QUERY_RESULT);
      console.log(`GPU-Zeit: ${(ns / 1e6).toFixed(2)} ms`);
    } else if (!ready) {
      requestAnimationFrame(check);
    }
  };
  requestAnimationFrame(check);
} else {
  console.log('Timer-Queries nicht verfügbar');
}
GPU-Zeit: 1.37 ms

// Wichtig · Fallstricke

  • Ist für target keine Abfrage aktiv, entsteht der Fehler gl.INVALID_OPERATION. Bei einem ungültigen Ziel ist es gl.INVALID_ENUM. Beide kannst du mit gl.getError() prüfen.
  • Lies QUERY_RESULT nicht im selben Frame aus. WebGL meldet das Ergebnis frühestens nach Rückkehr in die Ereignisschleife als verfügbar. Aktives Warten in einer Schleife blockiert den Browser.
  • Occlusion-Ergebnisse sind boolesch (true/false) und keine Anzahl von Samples.
  • Timer-Queries stehen wegen Timing-Angriffen (Spectre) in vielen Browsern nicht oder nur mit verringerter Genauigkeit zur Verfügung. Prüfe außerdem immer GPU_DISJOINT_EXT.
  • Die Methode gibt es nur in WebGL 2. In WebGL 1 steht Vergleichbares höchstens über Erweiterungen wie EXT_disjoint_timer_query zur Verfügung.