Signatur
Beschreibung
WebGLQuery gehört zur WebGL-2-API (WebGL2RenderingContext) und steht für ein Abfrageobjekt auf der GPU. Die GPU arbeitet unabhängig von JavaScript. Mit einer Abfrage sammelt man während bestimmter Zeichenbefehle Informationen und liest das Ergebnis später aus, ohne dass die Render-Pipeline blockiert.
Die Schnittstelle hat weder eigene Eigenschaften noch eigene Methoden. Erzeugt wird ein Objekt mit gl.createQuery(), benutzt wird es über Methoden des Kontexts:
gl.beginQuery(target, query)/gl.endQuery(target)– legen fest, welche Befehle ausgewertet werdengl.getQueryParameter(query, pname)– mitgl.QUERY_RESULT_AVAILABLEprüfen, ob das Ergebnis schon da ist, und dann mitgl.QUERY_RESULTauslesengl.getQuery(target, gl.CURRENT_QUERY)– liefert die aktive Abfrage für ein Zielgl.isQuery(query)undgl.deleteQuery(query)– prüfen bzw. geben frei
Mögliche Ziele (target) sind gl.ANY_SAMPLES_PASSED, gl.ANY_SAMPLES_PASSED_CONSERVATIVE (beide für die Verdeckungsprüfung, englisch Occlusion Culling) und gl.TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN. Mit der Erweiterung EXT_disjoint_timer_query_webgl2 kommen GPU-Zeitmessungen hinzu (TIME_ELAPSED_EXT, TIMESTAMP_EXT).
Typische Einsatzfälle: Man zeichnet vorab eine einfache Hülle (Bounding Box), um verdeckte Objekte nicht aufwendig rendern zu müssen. Man misst die GPU-Zeit einzelner Render-Durchgänge. Oder man zählt die Ausgaben von Transform Feedback, etwa bei Partikelsystemen.
Rückgabewert
gl.createQuery() zurückgegeben. Das Objekt ist undurchsichtig (opak), es wird nur als Argument an Kontext-Methoden weitergereicht.Beispiele
Abfrage erzeugen und Verdeckung prüfen (Occlusion Query)
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl2');
if (!gl) throw new Error('WebGL 2 wird nicht unterstützt');
const query = gl.createQuery();
console.log(query instanceof WebGLQuery); // true
// Alle Zeichenbefehle zwischen begin und end werden ausgewertet
gl.beginQuery(gl.ANY_SAMPLES_PASSED_CONSERVATIVE, query);
// z. B. eine vereinfachte Bounding Box zeichnen:
// gl.drawArrays(gl.TRIANGLES, 0, 36);
gl.endQuery(gl.ANY_SAMPLES_PASSED_CONSERVATIVE);
console.log(gl.isQuery(query));
Ergebnis asynchron in späteren Frames abholen
const gl = document.createElement('canvas').getContext('webgl2');
const query = gl.createQuery();
gl.beginQuery(gl.ANY_SAMPLES_PASSED, query);
gl.clear(gl.COLOR_BUFFER_BIT); // hier stünden die Zeichenbefehle
gl.endQuery(gl.ANY_SAMPLES_PASSED);
const poll = () => {
const available = gl.getQueryParameter(query, gl.QUERY_RESULT_AVAILABLE);
if (!available) {
requestAnimationFrame(poll); // nicht blockieren, im nächsten Frame erneut prüfen
return;
}
const visible = gl.getQueryParameter(query, gl.QUERY_RESULT);
console.log('Objekt sichtbar:', Boolean(visible));
gl.deleteQuery(query);
};
requestAnimationFrame(poll);
GPU-Zeit messen mit EXT_disjoint_timer_query_webgl2
const gl = document.createElement('canvas').getContext('webgl2');
const ext = gl.getExtension('EXT_disjoint_timer_query_webgl2');
if (!ext) {
console.log('Timer-Queries nicht verfügbar');
} else {
const timer = gl.createQuery();
gl.beginQuery(ext.TIME_ELAPSED_EXT, timer);
gl.clear(gl.COLOR_BUFFER_BIT); // zu messender Render-Durchgang
gl.endQuery(ext.TIME_ELAPSED_EXT);
const check = () => {
const available = gl.getQueryParameter(timer, gl.QUERY_RESULT_AVAILABLE);
const disjoint = gl.getParameter(ext.GPU_DISJOINT_EXT);
if (available && !disjoint) {
const ns = gl.getQueryParameter(timer, gl.QUERY_RESULT);
console.log(`GPU-Zeit: ${(ns / 1e6).toFixed(3)} ms`);
gl.deleteQuery(timer);
} else if (disjoint) {
console.log('Messung ungültig (disjoint), bitte verwerfen');
gl.deleteQuery(timer);
} else {
requestAnimationFrame(check);
}
};
requestAnimationFrame(check);
}
Geschriebene Primitive bei Transform Feedback zählen
const gl = document.createElement('canvas').getContext('webgl2');
const countQuery = gl.createQuery();
gl.beginQuery(gl.TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, countQuery);
// gl.beginTransformFeedback(gl.POINTS);
// gl.drawArrays(gl.POINTS, 0, particleCount);
// gl.endTransformFeedback();
gl.endQuery(gl.TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
setTimeout(() => {
if (gl.getQueryParameter(countQuery, gl.QUERY_RESULT_AVAILABLE)) {
console.log('Primitive:', gl.getQueryParameter(countQuery, gl.QUERY_RESULT));
}
}, 100);