Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions docs/api-reference/tables/gpu-data.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ order, offsets, formats, row stride, and optional `stepMode`.
| `format` | `GPUVectorFormat \| GPUDataStructFields` | `undefined` | A scalar/list format string or an inline record of named fixed-width field formats. |
| `layout` | `wgsl-storage \| packed` | `wgsl-storage` | Physical packing rules for an inline struct format. Invalid with a scalar/list format. |
| `length` | `number` | Required | Number of logical rows in this chunk. |
| `valueLength` | `number` | `length` | Number of fixed rows or flattened vertex-list element values. |
| `valueLength` | `number` | Derived from `format` | Number of fixed rows, or flattened variable-list/fixed-size-list element values. |
| `stride` | `number` | Derived from `format` | Number of scalar values represented by one fixed row or flattened element. |
| `byteOffset` | `number` | `0` | Byte offset of the first logical row in this chunk's buffer. Most adapters use `0` because chunks own their uploaded buffers. |
| `byteStride` | `number` | Derived from `format` | Bytes between adjacent fixed rows or flattened elements. |
Expand All @@ -130,14 +130,31 @@ order, offsets, formats, row stride, and optional `stepMode`.
| `type` | `unknown` | Deprecated adapter-owned logical metadata. |
| `dataType` | `unknown` | Deprecated adapter-owned logical metadata. |
| `length` | `number` | Number of logical rows in this chunk. |
| `valueLength` | `number` | Number of fixed rows or flattened vertex-list element values. |
| `valueLength` | `number` | Number of fixed rows, or flattened variable-list/fixed-size-list element values. |
| `stride` | `number` | Number of scalar values represented by one fixed row or flattened element. |
| `byteOffset` | `number` | Byte offset of the first logical row. |
| `byteStride` | `number` | Bytes between adjacent fixed rows or flattened elements. |
| `rowByteLength` | `number` | Bytes occupied by one fixed row or flattened element payload. |
| `readbackMetadata` | `unknown` | Optional producer-owned metadata. |
| `ownsBuffer` | `boolean` | Whether this data range currently owns its backing buffer. |

Fixed-size storage lists preserve table rows independently from flattened scalar
coordinates:

```ts
const embeddings = new GPUData({
buffer,
format: 'fixed-size-list<float32,768>',
length: 1000,
ownsBuffer: true
});

embeddings.length; // 1000 logical table rows
embeddings.valueLength; // 768000 Float32 elements
embeddings.rowByteLength; // 3072 bytes
embeddings.byteStride; // 3072 bytes, unless rows are explicitly padded
```

## Methods

### `getChild(name): GPUDataView | null`
Expand Down
20 changes: 18 additions & 2 deletions docs/api-reference/tables/gpu-schema.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ For the required and optional `GPUVector` inputs accepted by a model, see

```ts
import type {VertexFormat} from '@luma.gl/core';
import type {GPUVectorFormat, VertexList} from '@luma.gl/tables';
import type {FixedSizeList, GPUVectorFormat, VertexList} from '@luma.gl/tables';

export type GPUTypeMap = Record<string, GPUVectorFormat>;

export type GPUField<
Name extends string = string,
Format extends VertexFormat | VertexList<VertexFormat> = GPUVectorFormat
Format extends GPUVectorFormat = GPUVectorFormat
> = {
name: Name;
format?: Format;
Expand Down Expand Up @@ -68,6 +68,20 @@ type PathTable = {
};
```

Fixed-size storage values retain their row cardinality in the column format:

```ts
type EmbeddingTable = {
embedding: FixedSizeList<'float32', 768>;
sourceId: 'uint32';
embeddingValidity: 'uint32';
};
```

Every column has the same logical table row count. The embedding allocation
contains 768 Float32 elements per row; its source IDs and optional GPU-validity
mask remain independently owned, ordinary row-aligned Uint32 columns.

## Semantics

`GPUSchema` describes selected GPU-facing columns, not necessarily every source
Expand All @@ -79,6 +93,8 @@ path.

- fixed vectors use core `VertexFormat` strings such as `float32x3`;
- variable-length vertex lists use `vertex-list<format>`;
- variable-length non-vertex values use `value-list<format>`;
- fixed-size storage values use `fixed-size-list<format,size>`;
- shader values remain in `ShaderLayout`, such as `vec3<f32>` or `vec4<f32>`.

Compatibility between `GPUField.format` and shader values is checked separately
Expand Down
3 changes: 3 additions & 0 deletions docs/api-reference/tables/gpu-table-lifecycle.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ Packing mutates the table in place. It rebuilds `batches[]` and table-level
removed batches. Borrowed external buffers are not destroyed.
Indexed tables are rejected because packed index buffers would need their
batch-local vertex indices rebased.
Nullable chunks and chunks carrying producer-owned readback metadata are also
rejected rather than silently losing source validity or adapter reconstruction
information. Non-null fixed-size-list columns can still be packed explicitly.

### Ownership Rules

Expand Down
4 changes: 3 additions & 1 deletion docs/api-reference/tables/gpu-table.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,9 @@ This means `table.schema.fields` may contain names absent from

Explicitly merges adjacent physical batches. Constants survive unchanged and do not
participate in copies. Indexed and variable-length restrictions still apply to the
varying data being packed.
varying data being packed. Columns carrying null bitmaps or producer-owned
readback metadata are rejected until a metadata-preserving packing contract is
available; ordinary non-null fixed-size-list storage columns remain packable.

### `addBatch(batch): this`

Expand Down
67 changes: 58 additions & 9 deletions docs/api-reference/tables/gpu-vector-format.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,15 @@ import type {VertexFormat} from '@luma.gl/core';
export type VertexList<Format extends VertexFormat = VertexFormat> =
`vertex-list<${Format}>`;

export type GPUVectorFormat = VertexFormat | VertexList;
export type ValueList<Format extends VertexFormat = VertexFormat> =
`value-list<${Format}>`;

export type FixedSizeList<
Format extends VertexFormat = VertexFormat,
Size extends number = number
> = `fixed-size-list<${Format},${Size}>`;

export type GPUVectorFormat = VertexFormat | VertexList | ValueList | FixedSizeList;

export type GPUDataFormat = GPUVectorFormat | GPUDataStructFormat;
```
Expand Down Expand Up @@ -54,8 +62,25 @@ per-vertex element values. The format inside the angle brackets describes one
flattened element. Offset buffers, row ranges, closed-path flags, text glyph
maps, and similar topology metadata are adapter-owned.

Generic `list<format>` is intentionally reserved for a possible future
non-vertex offset-list type.
Variable-length non-vertex values use `value-list<format>`. For example,
`value-list<uint8>` stores flattened UTF-8 bytes with producer-owned row offsets.

Fixed-size storage values keep their logical row width in the format itself:

```ts
'fixed-size-list<float32,384>'
'fixed-size-list<float32,768>'
'fixed-size-list<float32,1536>'
```

`fixed-size-list<float32,768>` describes 768 stored Float32 values in each table
row. It does **not** describe a vertex attribute, a WGSL `vec768<f32>`, or a
new Arrow-owned GPU type. `GPUData.length` and `GPUVector.length` remain logical
row counts; `valueLength` counts the flattened elements. The default row
`byteStride` and `rowByteLength` are `768 * 4`, while an explicit larger
`byteStride` preserves physical row padding.

Generic `list<format>` remains intentionally reserved.

`GPUDataStructFormat` is an object rather than another format string because it
contains named field formats, offsets, and row-stride metadata. It remains a
Expand All @@ -67,7 +92,7 @@ format of one logical vector.

### `getGPUVectorFormatInfo(format): GPUVectorFormatInfo`

Decodes a fixed or `vertex-list<...>` format string.
Decodes fixed scalar/vector, variable-list, or fixed-size-list storage formats.

```ts
const info = getGPUVectorFormatInfo('vertex-list<float32x3>');
Expand All @@ -77,17 +102,35 @@ info.vertexList; // true
info.components; // 3
info.byteLength; // 12
info.primitiveType; // 'f32'

const embedding = getGPUVectorFormatInfo('fixed-size-list<float32,768>');

embedding.elementFormat; // 'float32'
embedding.fixedSizeList; // true
embedding.listSize; // 768
embedding.elementByteLength; // 4
embedding.byteLength; // 3072 bytes per logical row
```

### `getGPUVectorElementFormat(format): VertexFormat`

Returns the fixed element format. For fixed vectors this is the input format; for
vertex lists this is the format inside `vertex-list<...>`.
Returns the fixed element format. For scalar/vector formats this is the input;
for variable and fixed-size lists it is the element format inside the brackets.

### `isVertexListGPUVectorFormat(format): boolean`

Returns true for `vertex-list<...>` formats.

### `isValueListGPUVectorFormat(format): boolean`

Returns true for variable-length non-vertex `value-list<...>` formats.

### `isFixedSizeListGPUVectorFormat(format): boolean`

Returns true for canonical `fixed-size-list<format,size>` formats. Sizes are
positive integers; whitespace, leading zeros, missing sizes, and unsupported
element formats are rejected.

### `isGPUVectorFormatCompatibleWithShaderType(format, shaderType): boolean`

Checks whether the memory format can feed one shader attribute type.
Expand All @@ -101,6 +144,7 @@ Examples:
| `uint32x2` | `vec2<u32>` | yes | Unsigned integer primitive type matches. |
| `sint32x2` | `vec2<u32>` | no | Signedness mismatch. |
| `float32x3` | `vec4<f32>` | no | Component count mismatch. |
| `fixed-size-list<float32,768>` | `vec4<f32>` | no | Fixed-size lists are storage columns, not vertex attributes. |

## Buffer Layouts

Expand Down Expand Up @@ -136,9 +180,10 @@ const positions = new GPUVector({
});
```

`vertex-list<...>` vectors do not synthesize generic vertex-buffer layouts.
Path, text, polygon, and geometry adapters must either expand them into
renderable fixed vectors or bind them through an explicit storage/offset path.
`vertex-list<...>`, `value-list<...>`, and `fixed-size-list<...>` vectors do not
synthesize generic vertex-buffer layouts. Path, text, polygon, geometry, and
embedding adapters must either expand compatible values into renderable fixed
vectors or bind them explicitly through storage.

## Arrow Mapping

Expand All @@ -151,5 +196,9 @@ renderable fixed vectors or bind them through an explicit storage/offset path.
| `List<FixedSizeList<Float32, 3>>` path coordinates | `vertex-list<float32x3>` |
| `List<FixedSizeList<Uint8, 4>>` vertex colors | `vertex-list<unorm8x4>` |

Short fixed-size lists preserve their existing vertex-attribute mappings.
Fixed-size-list GPU formats can describe wider caller-created table storage
without inventing unsupported vertex formats such as `float32x768`.

Arrow data types remain adapter/readback metadata. Table core uses
`GPUVectorFormat`.
28 changes: 27 additions & 1 deletion docs/api-reference/tables/gpu-vector.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ When the input starts as Apache Arrow, prefer
| `type` | `unknown` | Deprecated adapter-owned logical metadata. |
| `dataType` | `unknown` | Deprecated adapter-owned logical metadata. |
| `length` | `number` | Aggregate logical row count. |
| `valueLength` | `number` | Aggregate fixed-row or flattened vertex-list element count. |
| `valueLength` | `number` | Aggregate scalar-row count, flattened variable-list count, or fixed-size-list element count. |
| `stride` | `number` | Number of scalar values represented by one fixed row or flattened element. |
| `byteOffset` | `number` | Compatibility metadata for the first row when this vector has one chunk. |
| `byteStride` | `number` | Bytes between adjacent fixed rows or flattened elements. |
Expand Down Expand Up @@ -101,3 +101,29 @@ For `vertex-list<...>` vectors, `length` remains the source row count and
`valueLength` is the flattened element count. `byteStride` and `rowByteLength`
describe one flattened element, not one source row. Offsets and other
variable-length metadata are adapter-owned.

For `fixed-size-list<float32,768>` vectors, `length` remains the number of table
rows while `valueLength` is `length * 768`. Each `GPUData` chunk stores one
complete fixed-size-list row per `byteStride`; `rowByteLength` describes its
meaningful payload and may be smaller than a padded physical stride. These
columns are storage-only unless an application explicitly expands them into
shader-compatible attributes. When binding a packed column through generic
WebGPU table shader/computation helpers, its `byteOffset` must satisfy the
device's `minStorageBufferOffsetAlignment`; consumers that align bindings
internally may support additional suballocation offsets.

```ts
import {GPUVector, type FixedSizeList} from '@luma.gl/tables';

const embeddings = new GPUVector<FixedSizeList<'float32', 768>>({
type: 'buffer',
name: 'embedding',
buffer: embeddingBuffer,
format: 'fixed-size-list<float32,768>',
length: rowCount
});

embeddings.length; // Logical source rows.
embeddings.valueLength; // Flattened Float32 embedding coordinates.
embeddings.data; // Original caller-owned GPUData batch chunks.
```
9 changes: 8 additions & 1 deletion modules/tables/src/engine/gpu-table-computation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {Computation, type ComputationProps} from '@luma.gl/engine';
import {DynamicBuffer} from '@luma.gl/engine';
import type {GPUData} from '../table/gpu-data';
import type {GPUVector} from '../table/gpu-vector';
import {isFixedSizeListGPUVectorFormat} from '../table/gpu-vector-format';

/** Metadata supplied to one GPU table computation batch dispatch. */
export type GPUTableComputationBatch = {
Expand Down Expand Up @@ -160,10 +161,16 @@ function getBatchVectorBindings(
}

function getGPUDataBinding(data: GPUData): Binding {
const fixedSizeListByteLength =
data.format && isFixedSizeListGPUVectorFormat(data.format)
? data.length === 0
? 0
: (data.length - 1) * data.byteStride + data.rowByteLength
: undefined;
return {
buffer: getGPUDataBuffer(data),
offset: data.byteOffset,
size: data.length * data.byteStride
size: data.valueByteLength ?? fixedSizeListByteLength ?? data.length * data.byteStride
};
}

Expand Down
10 changes: 8 additions & 2 deletions modules/tables/src/engine/gpu-table-shader-bindings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
import {GPUConstant} from '../table/gpu-constant';
import type {GPUData} from '../table/gpu-data';
import type {GPUTable} from '../table/gpu-table';
import {getGPUVectorFormatInfo} from '../table/gpu-vector-format';
import {getGPUVectorFormatInfo, isFixedSizeListGPUVectorFormat} from '../table/gpu-vector-format';

type GPUBuffer = Buffer | DynamicBuffer;

Expand Down Expand Up @@ -530,10 +530,16 @@ function getShaderAttributeBufferLayout(
}

function getGPUDataBinding(data: GPUData): Binding {
const fixedSizeListByteLength =
data.format && isFixedSizeListGPUVectorFormat(data.format)
? data.length === 0
? 0
: (data.length - 1) * data.byteStride + data.rowByteLength
: undefined;
return {
buffer: data.buffer instanceof DynamicBuffer ? data.buffer.buffer : data.buffer,
offset: data.byteOffset,
size: data.valueByteLength ?? data.valueLength * data.byteStride
size: data.valueByteLength ?? fixedSizeListByteLength ?? data.valueLength * data.byteStride
};
}

Expand Down
2 changes: 2 additions & 0 deletions modules/tables/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,11 @@ export {
export {
getGPUVectorElementFormat,
getGPUVectorFormatInfo,
isFixedSizeListGPUVectorFormat,
isGPUVectorFormatCompatibleWithShaderType,
isValueListGPUVectorFormat,
isVertexListGPUVectorFormat,
type FixedSizeList,
type GPUVectorFormat,
type GPUVectorFormatInfo,
type ValueList,
Expand Down
3 changes: 3 additions & 0 deletions modules/tables/src/table/gpu-constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ export class GPUConstant<T extends VertexFormat = VertexFormat> {

constructor({format, value}: GPUConstantProps<T>) {
const formatInfo = getGPUVectorFormatInfo(format);
if (formatInfo.fixedSizeList) {
throw new Error('GPUConstant cannot represent fixed-size-list storage columns');
}
const expectedConstructor = getGPUConstantTypedArrayConstructor(format);
if (value.constructor !== expectedConstructor) {
throw new Error(
Expand Down
Loading