Skip to content

Nodes and Handles

A node is the value returned by v.pass().

const A = v.pass(kernel, { input, output });

Every buffer-like binding on a node gets a handle with the same name.

A.input;
A.output;

You can use handles when one pass consumes data from another pass, to make the dependency requirement clear:

const A = v.pass(doubleKernel, { input, output: mid });
const B = v.pass(offsetKernel, { input: A.output, output: result });
v.run(B);

Running B also runs A, because B depends on A.output.

This is Volten’s graph model: handles connect nodes into a dependency graph, and v.run(B) runs the work needed to produce B.

Handles are created for in-place bindings too.

const A = v.pass(kernel, { data });
const B = v.pass(kernel, { data: A.data });
const C = v.pass(kernel, { data: B.data });
v.run(C);

This lets you chain work in a way that improves the readability of the dependency chain, as well as letting you created more complex GPU compute execution dependency graphs

Declared outputs matter when reading a node.

const kernel = new Kernel(`...`, {
outputs: ['result']
});
const node = v.pass(kernel, { input, result });
const output = await v.read(node);

If you choose to not declare outputs on your kernel, you can alternatively read a specific buffer or handle:

const data = await v.read(node.data);