Signatur
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
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));
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);
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');
}
// Wichtig · Fallstricke
- Ist für
targetkeine Abfrage aktiv, entsteht der Fehlergl.INVALID_OPERATION. Bei einem ungültigen Ziel ist esgl.INVALID_ENUM. Beide kannst du mitgl.getError()prüfen. - Lies
QUERY_RESULTnicht 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_queryzur Verfügung.