Dynamically Alter GPU.js Kernel Output Dimensions

In GPU.js, you can dynamically alter the output dimensions of an already compiled kernel without redefining the original kernel function. By utilizing the built-in setOutput() method on the kernel instance, developers can adjust 1D, 2D, or 3D execution bounds on the fly. This article explains how dynamic resizing works in GPU.js, how to implement it in code, and the performance trade-offs to keep in mind.

Changing Output Dimensions with setOutput()

When you create a kernel in GPU.js, you typically define the initial output size using the .setOutput() method during instantiation. However, this configuration is not permanently locked. You can call kernel.setOutput() at any point before executing the kernel with new arguments.

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

// 1. Create and compile the kernel with initial dimensions
const computeGrid = gpu.createKernel(function() {
  return this.thread.x + this.thread.y;
}).setOutput([512, 512]);

// Run with original dimensions (512x512)
let resultA = computeGrid();

// 2. Dynamically change the output dimensions to 1024x1024
computeGrid.setOutput([1024, 1024]);

// Run with updated dimensions
let resultB = computeGrid();

How It Works Under the Hood

When you modify the output dimensions, GPU.js handles several updates internally:

  1. Internal Constants Update: The thread boundaries accessible inside the kernel via this.output.x, this.output.y, and this.output.z update automatically to match the new array lengths.
  2. WebGL Viewport and Framebuffer Adjustment: Because GPU.js relies on WebGL textures to hold output data, resizing forces the underlying rendering context to update its viewport dimensions and reallocate appropriately sized texture buffers.
  3. No Full Kernel Recompilation: The underlying GLSL shader source code does not need to be fully parsed or re-transpiled from JavaScript. This makes resizing an existing kernel significantly faster than destroying it and creating a new one with gpu.createKernel().

Performance Considerations

While modifying output sizes on an existing kernel is more efficient than instantiating a new one, it is not completely free of overhead: