Run GPU Code With Raw WebGL And GLSL

One WebGL fragment can turn a GLSL expression into a 32-bit hardware result.

The code below creates the canvas and context, compiles the shader pair, rasterizes two triangles, writes RGBA bytes, and reads them back. Direct browser calls expose the complete path from JavaScript to GPU execution.

Open the browser's Inspect panel, choose Console, and run each block in sequence.

Make One GPU Thread Return 32 Bits

The minimum path runs one GPU hardware thread and returns four RGBA bytes. That 32-bit result makes every stage easy to inspect.

The sequence starts with two browser operations:

  1. Create an invisible <canvas> HTML element.
  2. Call its getContext() method to acquire WebGL.
Shader compilation, triangle rasterization, and result readback then complete the loop.

Build the WebGL Context

A browser canvas owns the WebGL context:

The canvas starts at its default size of 300 by 150 pixels:

A 2x2 canvas keeps this first run compact:

Depth testing and antialiasing add graphics work that this GPGPU path does not need. The context options remove both and request high-performance, desynchronized execution:

A readable gl.getError() wrapper turns numeric failures into precise diagnostic names:

The Shader class compiles the GLSL pair, links the program, binds a four-vertex strip, and renders two triangles:

The complete run path now writes the RGBA value [0, 255, 127, 0] across a 16x16 viewport:

A later pass can consume the color attachment directly as a texture after a state swap. For inspection, readPixels() copies the 16x16 RGBA result into a byte array:

Keep GLSL 1.00 Precision Under Direct Control

The GLSL 1.00 preprocessor cuts floating-point literals below 1.0000001e-37 = pow(2, -123) * (1 + 0.0633825). Its decimal-literal path shrinks values below 1e-37 to zero and ignores the sign. The preprocessor causes that behavior before the GPU runs the shader; ANGLE's constant-union implementation shows the relevant translation path.

The next function runs dynamic shader source and returns floating-point values, raw bytes, and the corresponding bit string:

The dynamic runner can now execute the packing shader against a 1x1 target:

Desktop and laptop GPUs can write floating-point values to 8 color buffers at once. Smartphones generally retain the RGBA8888 path and its 32 output bits per shader thread. The final block creates a floating-point texture, attaches it to an offscreen framebuffer, runs GLSL, and reads four 32-bit channels at full desktop width: