Start · Sprachen · JavaScript · Referenz · WebGLRenderingContext.linkProgram()

WebGLRenderingContext.linkProgram()

Methode

Verknüpft die angehängten Vertex- und Fragment-Shader eines <code>WebGLProgram</code> zu einem ausführbaren GPU-Programm.

seit JavaScript Baseline: alle Browser (WebGL 1) Kategorie: webapi

Signatur

WebGLRenderingContext.prototype.linkProgram(program)

Beschreibung

linkProgram() ist der letzte Schritt beim Erzeugen eines Shader-Programms in WebGL. Zuerst kompilierst du die Shader mit compileShader(), dann hängst du sie mit attachShader() an ein WebGLProgram. Danach bringt linkProgram() die beiden Shader zusammen: Die varying-Variablen des Vertex-Shaders werden den passenden Eingaben des Fragment-Shaders zugeordnet, Attribut- und Uniform-Positionen werden vergeben und der Maschinencode für die GPU wird erzeugt.

Die Methode gibt nichts zurück und löst bei einem Linkfehler keine Ausnahme aus. Ob das Linken geklappt hat, fragst du mit gl.getProgramParameter(program, gl.LINK_STATUS) ab. Die Fehlermeldung des Treibers bekommst du über gl.getProgramInfoLog(program).

Attribut-Positionen, die du mit bindAttribLocation() festlegst, gelten erst nach dem nächsten linkProgram()-Aufruf. Auch die Positionen von Uniforms und Attributen solltest du erst nach dem Linken abfragen, zum Beispiel mit getUniformLocation() und getAttribLocation(). Wird ein Programm, das gerade in Benutzung ist, neu gelinkt, gilt das neue Ergebnis nur, wenn das Linken erfolgreich war.

Parameter

Name Typ Default Beschreibung
$program Pflicht WebGLProgram Das Programm, das gelinkt werden soll. Es muss mit gl.createProgram() erzeugt worden sein, und es müssen ein Vertex- und ein Fragment-Shader angehängt sein.

Rückgabewert

Typ
void
Beschreibung
Kein Rückgabewert (undefined). Den Erfolg prüfst du mit getProgramParameter(program, gl.LINK_STATUS).

Beispiele

Shader kompilieren, anhängen und Programm linken

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

const vsSource = `
  attribute vec2 aPosition;
  void main() {
    gl_Position = vec4(aPosition, 0.0, 1.0);
  }`;

const fsSource = `
  precision mediump float;
  uniform vec4 uColor;
  void main() {
    gl_FragColor = uColor;
  }`;

const compile = (type, source) => {
  const shader = gl.createShader(type);
  gl.shaderSource(shader, source);
  gl.compileShader(shader);
  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
    throw new Error(gl.getShaderInfoLog(shader));
  }
  return shader;
};

const program = gl.createProgram();
gl.attachShader(program, compile(gl.VERTEX_SHADER, vsSource));
gl.attachShader(program, compile(gl.FRAGMENT_SHADER, fsSource));
gl.linkProgram(program);

console.log('Gelinkt:', gl.getProgramParameter(program, gl.LINK_STATUS));
Gelinkt: true

Wiederverwendbare Hilfsfunktion mit Fehlerbehandlung

const createProgram = (gl, vertexShader, fragmentShader) => {
  const program = gl.createProgram();
  gl.attachShader(program, vertexShader);
  gl.attachShader(program, fragmentShader);
  gl.linkProgram(program);

  if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
    const log = gl.getProgramInfoLog(program);
    gl.deleteProgram(program);
    throw new Error(`Programm konnte nicht gelinkt werden: ${log}`);
  }

  // Shader werden nach dem Linken nicht mehr gebraucht
  gl.detachShader(program, vertexShader);
  gl.detachShader(program, fragmentShader);
  gl.deleteShader(vertexShader);
  gl.deleteShader(fragmentShader);

  return program;
};

Attribut-Position vor dem Linken festlegen

// Annahme: gl, vertexShader und fragmentShader sind vorhanden
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);

// Muss VOR linkProgram() aufgerufen werden
gl.bindAttribLocation(program, 0, 'aPosition');
gl.linkProgram(program);

if (gl.getProgramParameter(program, gl.LINK_STATUS)) {
  gl.useProgram(program);
  console.log(gl.getAttribLocation(program, 'aPosition'));
  const uColor = gl.getUniformLocation(program, 'uColor');
  gl.uniform4f(uColor, 1.0, 0.5, 0.0, 1.0);
}

// Wichtig · Fallstricke

  • Keine Ausnahme bei Fehlern: Wenn das Linken fehlschlägt, bleibt das stumm. Prüfe immer LINK_STATUS und gib getProgramInfoLog() aus. Häufige Ursachen sind varying-Variablen, deren Namen oder Typen in den beiden Shadern nicht zusammenpassen, ein fehlender Shader oder zu viele Uniforms oder Attribute für die Hardware.
  • Performance: In vielen Browsern blockiert linkProgram() nicht sofort. Erst die anschließende Abfrage von LINK_STATUS wartet, bis das Linken fertig ist. Mit der Erweiterung KHR_parallel_shader_compile kannst du COMPLETION_STATUS_KHR abfragen, ohne den Hauptthread zu blockieren. So lassen sich viele Programme parallel vorbereiten.
  • Wird ein Programm neu gelinkt, gehen alle Uniform-Werte verloren. Außerdem werden vorher abgefragte WebGLUniformLocation-Objekte ungültig.
  • Ist program kein gültiges WebGLProgram, entsteht der Fehler INVALID_VALUE oder INVALID_OPERATION. Den kannst du mit gl.getError() auslesen.
  • Die Methode gibt es auch in WebGL2RenderingContext. Sie wird von allen modernen Browsern unterstützt.