GPU Evaluators
@luma.gl/gpgpu has two evaluator layers:
GPUDataEvaluatorruns one lazy transform over one fixed-widthGPUDatachunk orGPUDataView.GPUVectorEvaluatorapplies one lazyGPUDataEvaluatortransform independently to every orderedGPUDatachunk in aGPUVector.
There is no GPUTable evaluator input path. Streaming code should pass an incoming
GPUData chunk or borrowed GPUDataView directly to GPUDataEvaluator operations, or wrap a GPUVector
with GPUVectorEvaluator when the same transform should preserve every existing
chunk boundary.
Usage
One incoming GPUData
import {GPUDataEvaluator, add} from '@luma.gl/gpgpu';
const offset = GPUDataEvaluator.fromConstant([1, 2, 3]);
const translatedChunk = add(incomingGPUData, offset);
const translatedVector = await translatedChunk.evaluate(device);
One GPUVector
import {GPUDataEvaluator, GPUVectorEvaluator, add} from '@luma.gl/gpgpu';
const offset = GPUDataEvaluator.fromConstant([1, 2, 3]);
const translatedVector = GPUVectorEvaluator.fromGPUVector(vector).mapGPUData(data =>
add(data, offset)
);
const outputVector = await translatedVector.evaluate(device);
GPUVectorEvaluator preserves vector.data[] order and chunk boundaries. It does
not combine streaming batches or pack buffers implicitly.
Interleaved attribute input
import {add} from '@luma.gl/gpgpu';
import {makeGPUDataViewFromAttribute} from '@luma.gl/gpgpu/gpu-data';
const positions = makeGPUDataViewFromAttribute({
buffer: interleavedBuffer,
bufferLayout,
attributeName: 'positions',
length: instanceCount
});
const translatedPositions = add(positions, [10, 0, 0]);
const packedOutput = await translatedPositions.evaluate(device);
Input views retain their offset and stride, so multiple attributes may borrow
the same interleaved buffer. Operation results use newly materialized packed
outputs by default. Call setTargetBuffer() before evaluation to direct an
operation result into an existing buffer range.
Evaluate into an existing buffer
import {cleanEvaluate, fround, GPUDataEvaluator} from '@luma.gl/gpgpu';
const source = GPUDataEvaluator.fromArray(new Float64Array(values), {size: 3});
const splitPositions = fround(source);
splitPositions.setTargetBuffer({
buffer: attributeBuffer,
byteOffset: destinationByteOffset
});
await cleanEvaluate(device, splitPositions);
The target is borrowed. Evaluation writes directly into attributeBuffer and
does not allocate or copy through a separate output buffer. cleanEvaluate()
recycles unreferenced owned dependency buffers, but preserves the borrowed root
target. Calling splitPositions.destroy() is not required to release the target
and never destroys attributeBuffer.
GPUDataEvaluator
GPUDataEvaluator describes a 2D row layout backed by CPU values, one borrowed
GPUData chunk, borrowed GPUDataView, another GPUDataEvaluator, or a lazy Operation output. Each
row contains size scalar elements of the same numeric type.
GPUDataEvaluatorProps
| Property | Type | Description |
|---|---|---|
id? | string | Optional debug name used by toString(). |
type | SignedDataType | Scalar element type, such as 'float32' or 'uint32'. |
size | number | Number of scalar elements in each row. |
offset? | number | Byte offset to the first element of the first row. Defaults to 0. |
stride? | number | Byte distance between adjacent rows. Defaults to ValueType.BYTES_PER_ELEMENT * size. |
normalized? | boolean | Whether integer values are normalized when exposed as vertex formats. |
value? | TypedArray | CPU-side data for the evaluator. |
buffer? | Buffer | DynamicBuffer | Borrowed GPU buffer backing this evaluator. |
gpuData? | GPUData | Borrowed fixed-width GPUData chunk backing this evaluator. |
format? | GPUVectorFormat | Optional memory format preserved for GPUVector interop. |
source? | Operation | GPUDataEvaluator | null | Lazy source for this evaluator. |
isConstant? | boolean | Whether every row shares the same value. Defaults to false. |
length? | number | Row count. Optional when isConstant is true or value is provided. |
Static Methods
GPUDataEvaluator.fromArray(value, props?): GPUDataEvaluator
Creates one evaluator from a typed array or numeric array. Plain JavaScript
arrays use props.type or 'float32' by default. Float64Array inputs are
reinterpreted as uint32 pairs for GPU-oriented operations such as fround().
GPUDataEvaluator.fromConstant(value, type?): GPUDataEvaluator
Creates one constant evaluator with a shared row value. A scalar becomes a
one-element row, and an array becomes a row with value.length elements.
GPUDataEvaluator.fromGPUData(data, options?): GPUDataEvaluator
Creates one evaluator view over a fixed-width GPUData chunk. The input
must have a fixed-width GPUData.format and matching rowByteLength. Strided
rows are preserved. The evaluator borrows data.buffer and does not destroy it.
GPUDataEvaluator.fromGPUDataView(view, options?): GPUDataEvaluator
Creates an evaluator over a borrowed fixed-width GPUDataView, preserving its
format, length, byte offset, and byte stride. Existing operations accept views
directly through GPUDataEvaluatorInput.
CPU, WebGL, and WebGPU support strided 32-bit component formats. Other formats remain subject to backend capabilities; unsupported WebGPU storage types fail explicitly rather than being repacked. Offsets and strides must be aligned to the stored scalar component width.
Methods
setTargetBuffer(target: GPUDataEvaluatorTargetBuffer): void
Assigns borrowed storage for the next evaluation of a deferred operation
output. This method is only valid before evaluation and on an evaluator whose
source is an Operation.
| Property | Type | Description |
|---|---|---|
buffer | Buffer | Borrowed buffer that receives the operation output. |
byteOffset? | number | Byte offset of the first output row. Defaults to 0. |
byteStride? | number | Byte distance between adjacent output rows. Defaults to the operation output's current packed stride. Backend layout restrictions still apply. |
setTargetBuffer() records the target without changing the evaluator's logical
layout. When evaluation begins, the target replaces the normal pooled output
allocation and offset, stride, and byteLength are updated to describe the
physical target layout. The target buffer must belong to the evaluation device
and be large enough for the resulting range.
The evaluator borrows the assigned buffer. Evaluating or destroying the evaluator never transfers ownership of or destroys that buffer.
evaluate(device: Device, options?): Promise<GPUVector>
Materializes one single-chunk GPUVector on the provided device. Lazy
dependencies are evaluated before the operation handler writes the output.
evaluateSync(device: Device, options?): GPUVector
Materializes one single-chunk GPUVector synchronously. This is useful for
call sites that must stay synchronous, but it is stricter than evaluate():
- backend lookup must already be resolved
- dependencies are evaluated recursively without awaiting
- any required CPU value must already be available
If those conditions are not met, evaluateSync() throws.
readValue(startRow?: number, endRow?: number): Promise<TypedArray>
Reads evaluator contents back to the CPU. This is intended for debugging or inspection and may be slower than staying on the GPU.
destroy(): void
Releases cached GPU storage owned by this evaluator and prevents future
evaluation. Borrowed buffers supplied through the constructor,
fromGPUData(), fromGPUDataView(), or setTargetBuffer() are not destroyed.
GPUVectorEvaluator
GPUVectorEvaluator is the official GPUVector path. It wraps ordered
GPUDataEvaluator chunks and materializes one output GPUVector with the same
chunk boundaries.
Static Methods
GPUVectorEvaluator.fromGPUVector(vector): GPUVectorEvaluator
Creates one chunk-preserving evaluator over a fixed-width GPUVector. The
vector must have at least one GPUData chunk and must not be interleaved.
GPUVectorEvaluator.fromGPUDataEvaluators(evaluators, options?): GPUVectorEvaluator
Creates one vector evaluator from already-built ordered chunk evaluators.
Methods
mapGPUData(transform): GPUVectorEvaluator
Applies one lazy GPUDataEvaluator transform independently to each preserved
chunk. Use this for row-local streaming transforms that should not repack source
batches.
evaluate(device: Device, options?): Promise<GPUVector>
Materializes every chunk evaluator and returns one GPUVector with preserved
chunk order and boundaries.
evaluateSync(device: Device, options?): GPUVector
Synchronously materializes every chunk evaluator and returns one GPUVector
with preserved chunk order and boundaries. This has the same synchronous
requirements as GPUDataEvaluator.evaluateSync().
destroy(): void
Releases cached GPU resources owned through child GPUDataEvaluator instances.
Remarks
- Leaf operations accept
GPUDataEvaluator,GPUData, orGPUDataView, notGPUVector. - Use
GPUVectorEvaluator.fromGPUVector(vector).mapGPUData(...)for vector-wide transforms that should preserve streaming chunks. GPUDataEvaluatoroperation outputs own their automatically allocated backing resource. Outputs configured withsetTargetBuffer()borrow their backing resource instead.- Borrowed
GPUDatachunks are not destroyed byGPUDataEvaluator.destroy(). - Borrowed
GPUDataViewbuffers are not destroyed byGPUDataEvaluator.destroy(). - Target buffers assigned with
GPUDataEvaluator.setTargetBuffer()are not destroyed or recycled by the evaluator. - Synchronous evaluation is intended for already-prepared graphs where backend registration and any required CPU values are available up front.