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

WebGL2RenderingContext.getActiveUniformBlockParameter()

Methode

Liefert Informationen über einen aktiven Uniform-Block eines gelinkten <code>WebGLProgram</code>, z. B. Datengröße, Binding-Punkt oder Anzahl der enthaltenen Uniforms.

seit JavaScript WebGL 2.0, Baseline: alle modernen Browser (seit 2 Kategorie: webapi

Signatur

WebGL2RenderingContext.prototype.getActiveUniformBlockParameter(program, uniformBlockIndex, pname)

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:
  • gl.UNIFORM_BLOCK_BINDING: zugewiesener Binding-Punkt (GLuint)
  • gl.UNIFORM_BLOCK_DATA_SIZE: Mindestgröße des Puffers in Bytes (GLuint)
  • gl.UNIFORM_BLOCK_ACTIVE_UNIFORMS: Anzahl der aktiven Uniforms im Block (GLuint)
  • gl.UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES: Indizes der aktiven Uniforms (Uint32Array)
  • gl.UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER: Wird der Block im Vertex-Shader verwendet? (GLboolean)
  • gl.UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER: Wird der Block im Fragment-Shader verwendet? (GLboolean)

Rückgabewert

Typ
number | boolean | Uint32Array | null
Beschreibung
Hängt von 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);
Blockgröße in Bytes: 144

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]}`);
});
view: Offset 0 projection: Offset 64 position: Offset 128

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'));
{ binding: 0, uniforms: 3, inVertex: true, inFragment: false }

// 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() gegen gl.INVALID_INDEX. Ein ungültiger Index führt zu INVALID_VALUE und der Rückgabewert ist null.
  • 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_SIZE statt auf eigene Rechnungen: Durch das std140-Padding wird etwa ein vec3 auf 16 Bytes aufgerundet.
  • Bei bindBufferRange() muss der Offset ein Vielfaches von gl.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.