Signatur
Beschreibung
Mit getActiveUniformBlockParameter() fragst du Metadaten zu einem Uniform-Block (in GLSL ES 3.00: uniform Name { ... };) ab, nachdem das Programm erfolgreich gelinkt wurde. Den benötigten Block-Index ermittelst du vorher mit getUniformBlockIndex().
Am häufigsten wird die Methode genutzt, um mit gl.UNIFORM_BLOCK_DATA_SIZE die exakte Byte-Größe des Blocks zu erfahren. Genau so groß muss der Uniform Buffer Object (UBO) sein, den du mit bufferData() anlegst und mit bindBufferBase() oder bindBufferRange() an einen Binding-Punkt hängst. Da der Treiber die Größe inklusive Padding nach dem std140-Layout berechnet, ist das zuverlässiger als eigenes Nachrechnen.
Weitere Abfragen verraten, wie viele Uniforms der Block enthält (UNIFORM_BLOCK_ACTIVE_UNIFORMS) und welche Indizes sie haben (UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES). Zusammen mit getActiveUniforms() und UNIFORM_OFFSET kannst du damit die Byte-Offsets einzelner Felder im Puffer ermitteln. Außerdem lässt sich prüfen, ob der Block im Vertex- oder Fragment-Shader tatsächlich verwendet wird.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $program Pflicht | WebGLProgram | Das erfolgreich gelinkte Programm, das den Uniform-Block enthält. | |
| $uniformBlockIndex Pflicht | GLuint (number) | Index des Uniform-Blocks, meist ermittelt mit gl.getUniformBlockIndex(program, name). |
|
| $pname Pflicht | GLenum (number) | Welche Information abgefragt wird:
|
Rückgabewert
pname ab: eine Zahl (GLuint), ein boolean oder ein Uint32Array mit Uniform-Indizes. Bei einem Fehler (z. B. ungültigem Index) gibt die Methode null zurück und setzt einen GL-Fehler.Beispiele
UBO in passender Größe anlegen
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl2');
const vsSource = `#version 300 es
uniform Camera {
mat4 view;
mat4 projection;
vec3 position;
};
in vec4 aPos;
void main() { gl_Position = projection * view * aPos + vec4(position, 0.0); }`;
const fsSource = `#version 300 es
precision highp float;
out vec4 color;
void main() { color = vec4(1.0); }`;
const compile = (type, src) => {
const s = gl.createShader(type);
gl.shaderSource(s, src);
gl.compileShader(s);
return s;
};
const program = gl.createProgram();
gl.attachShader(program, compile(gl.VERTEX_SHADER, vsSource));
gl.attachShader(program, compile(gl.FRAGMENT_SHADER, fsSource));
gl.linkProgram(program);
const blockIndex = gl.getUniformBlockIndex(program, 'Camera');
const size = gl.getActiveUniformBlockParameter(
program, blockIndex, gl.UNIFORM_BLOCK_DATA_SIZE
);
console.log('Blockgröße in Bytes:', size);
// Puffer exakt in der geforderten Größe anlegen und binden
const ubo = gl.createBuffer();
gl.bindBuffer(gl.UNIFORM_BUFFER, ubo);
gl.bufferData(gl.UNIFORM_BUFFER, size, gl.DYNAMIC_DRAW);
gl.uniformBlockBinding(program, blockIndex, 0);
gl.bindBufferBase(gl.UNIFORM_BUFFER, 0, ubo);
Offsets der Block-Uniforms ermitteln
// Setzt program und blockIndex aus dem vorigen Beispiel voraus
const indices = gl.getActiveUniformBlockParameter(
program, blockIndex, gl.UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES
);
const offsets = gl.getActiveUniforms(program, indices, gl.UNIFORM_OFFSET);
indices.forEach((idx, i) => {
const info = gl.getActiveUniform(program, idx);
console.log(`${info.name}: Offset ${offsets[i]}`);
});
Binding-Punkt und Shader-Nutzung prüfen
const describeBlock = (gl, program, name) => {
const idx = gl.getUniformBlockIndex(program, name);
if (idx === gl.INVALID_INDEX) return null;
const q = (p) => gl.getActiveUniformBlockParameter(program, idx, p);
return {
binding: q(gl.UNIFORM_BLOCK_BINDING),
uniforms: q(gl.UNIFORM_BLOCK_ACTIVE_UNIFORMS),
inVertex: q(gl.UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER),
inFragment: q(gl.UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER)
};
};
console.log(describeBlock(gl, program, 'Camera'));
// Wichtig · Fallstricke
- Das Programm muss erfolgreich gelinkt sein. Prüfe das vorher mit
gl.getProgramParameter(program, gl.LINK_STATUS). - Prüfe den Rückgabewert von
getUniformBlockIndex()gegengl.INVALID_INDEX. Ein ungültiger Index führt zuINVALID_VALUEund der Rückgabewert istnull. - Der GLSL-Compiler entfernt Blöcke, die nicht verwendet werden. Solche Blöcke sind dann nicht „aktiv“ und lassen sich nicht abfragen.
- Verlass dich bei der Puffergröße auf
UNIFORM_BLOCK_DATA_SIZEstatt auf eigene Rechnungen: Durch dasstd140-Padding wird etwa einvec3auf 16 Bytes aufgerundet. - Bei
bindBufferRange()muss der Offset ein Vielfaches vongl.getParameter(gl.UNIFORM_BUFFER_OFFSET_ALIGNMENT)sein. - Die Methode gibt es nur im
WebGL2RenderingContext, im WebGL 1 gibt es sie nicht. Alle aktuellen Browser unterstützen WebGL 2, Safari seit Version 15. - Jeder Aufruf kann die GPU-Pipeline synchronisieren. Frag die Werte deshalb einmal nach dem Linken ab und speichere sie zwischen, statt sie in jedem Frame neu abzufragen.