Inspect Compiled GLSL Code in gpu.js

This guide explains how to inspect and extract the compiled OpenGL Shading Language (GLSL) source code generated by a gpu.js kernel. Accessing the underlying WebGL shader code allows developers to debug execution bottlenecks, troubleshoot precision and type issues, and gain a clearer understanding of how high-level JavaScript functions translate into raw GPU shaders.

Generating and Accessing GLSL

gpu.js compiles your JavaScript function into GLSL when the kernel is initialized and built. You can access this generated code directly via the built-in getGLSL() method on the kernel instance.

Because gpu.js compiles shaders lazily, you must either execute the kernel once with sample input arguments or explicitly build it before calling getGLSL().

Example: Using getGLSL()

const { GPU } = require('gpu.js');
const gpu = new GPU();

// Define a simple kernel
const multiplyMatrix = gpu.createKernel(function(a, b) {
  let sum = 0;
  for (let i = 0; i < 512; i++) {
    sum += a[this.thread.y][i] * b[i][this.thread.x];
  }
  return sum;
}).setOutput([512, 512]);

// Option 1: Explicitly build the kernel with mock inputs
multiplyMatrix.build([[1]], [[1]]);

// Option 2: Alternatively, run the kernel once to trigger compilation
// multiplyMatrix(matrixA, matrixB);

// Inspect the compiled GLSL fragment shader
const glslSource = multiplyMatrix.getGLSL();
console.log(glslSource);

Accessing Raw Shader Properties

If you need deeper inspection of the WebGL state beyond the output of getGLSL(), you can inspect the internal properties attached to the kernel object after execution or building:

// Access the internal compiled shader strings
console.log('--- Fragment Shader ---');
console.log(multiplyMatrix.compiledFragmentShader);

console.log('--- Vertex Shader ---');
console.log(multiplyMatrix.compiledVertexShader);

What to Look For in the Output

When examining the output GLSL, pay attention to the following sections:

  1. Precision Declarations: gpu.js sets default floating-point precision (typically precision highp float;). Verify if precision settings match your hardware capabilities.
  2. Uniforms and Textures: Matrix and array inputs are packed into WebGL textures (sampler2D). Look for uniforms prefixed with user_ to see how your JavaScript arguments were bound.
  3. Thread Mapping: The this.thread.x, this.thread.y, and this.thread.z coordinates are mapped through custom GLSL functions calculating texture coordinates to identify how indexing math is handled.