Skip to content

Commit

Permalink
chore(core): Clean up buffer map
Browse files Browse the repository at this point in the history
  • Loading branch information
ibgreen committed Aug 19, 2023
1 parent 69cbd2b commit 1152a0e
Show file tree
Hide file tree
Showing 17 changed files with 268 additions and 265 deletions.
34 changes: 28 additions & 6 deletions docs/api-guide/attributes.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
# Attributes

In traditional 3D graphics, the purpose of *attributes* is typically described
as providing vertex data to the GPU.
In traditional 3D graphics, the purpose of *GPU attributes* is typically to
provide vertex data to the GPU.

However, luma.gl favors thinking about a GPU as operating on "binary columnar tables".
- In such a mental model, attributes are "columnar binary arrays" with the same number of elements
that each contain one value for each row.
luma.gl favors thinking about a GPU as operating on "binary columnar tables". In this a mental model:
- attributes are "columnar binary arrays" with the same number of elements that each contain one value for each row.
- Each column is an array of either floating point values, or signed or unsigned integers.
- A row can use up either a single value, or represent a vector of 2, 3 or 4 elements.
- All rows in a column must be of the same format (single value or vector)

## Bindings

Attributes are binding points for buffers. The structure (memory layout and format of these buffers) must match the constraints imposed by the shader code,
and the structure of the provided data must also be communicated to the GPU.

In luma.gl attribute structure is described by two complementary concepts:

- `ShaderLayout` describes the static structure of attributes in a shader. This includes the "location" (the index of the attribute in the GPU's attribute bank), and the type of the attribute declared in the shader (float, int, uint, and number of components).
- `BufferMap` describes the dynamic structure of the attributes, i.e. the memory format and layout of the buffers that will be provided.


## VertexFormat

The format of a vertex attribute indicates how data from a vertex buffer
Expand Down Expand Up @@ -61,8 +71,20 @@ Each vertex data type can map to any WGSL scalar type of the same base type, reg
| 'sint32x4' | `sint32` | `i32` | `int`, `ivec2-4` |



## Backend Notes

When it comes to attributes, WebGL is significantly more flexible than WebGPU:
- Buffers with different structure ( a different `BufferMap`) can be provided without relinking the `RenderPipeline`
- Less restrictions on vertex formats (e.g. `unorm8x1`, `unorm8x3` are supported)
- Non-normalized integer attributes can be assigned to floating point GLSL shader variables (e.g. `vec4`).
- Constant attributes (attribute locations can be disabled in which case a constant value is read from the WebGLRenderingContext)
- It is possible to use buffers with more or fewer components than expected by the shader, and the missing values will be filled with `[0, 0, 0, 1]`.

Presumably, the additional restrictions in WebGPU allow for reduced run-time validation overhead and/or additional optimizations during shader compilation.

Note:
- 8 and 16 bit values only support 2 or 4 components. This is a WebGPU specific limitation that does not exist on WebGL, but is enforced for portability.
- WebGL: GLSL supports `bool` and `bvec*` but these are not portable to WebGPU and not included here.
- WebGL: GLSL types `double` and `dvec*` are not supported in any WebGL version
- WebGPU: WGSL `f64` (hypothetical double type) is not supported. Perhaps in a future extension?
- WebGPU: WGSL `f64` (hypothetical double type) is not supported. Perhaps in a future extension.
38 changes: 37 additions & 1 deletion docs/api-reference/core/buffer-mapping.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
# BufferMapping (type)

The bufferMapping type provides information about how the buffers the application is planning to bind map to the attributes.
The `BufferMapping` stores the dynamic structure of a render pipeline binding points.

It affects buffers bound with `Model.setAttributes()` or `RenderPipeline.setAttributes()`
`BufferMapping` affects buffers bound with `RenderPipeline.setAttributes()` or `Model.setAttributes()`. In particular, the names
of buffers are determined by the buffer mapping.

Normally the buffer names will match the attribute names, however for interleaved buffers the bufferMapping defines a new buffer name,
that then becomes valid in `RenderPipeline.setAttributes()` and `Model.setAttributes()`.

## Usage

The simplest use case is to provide a non-default vertex type:

Expand All @@ -15,11 +22,22 @@ The simplest use case is to provide a non-default vertex type:
],
```

```typescript
bufferMap: [
{name: 'instancePositions', format: 'float32x3'}
...
// RGBA colors can be efficiently encoded in 4 8bit bytes, instead of 4 32bit floats
{name: 'instanceColors': format: 'uint8normx4'},
],
```

A more advanced use case is interleaving: two attributes access the same buffer in an interleaved way.
Note that this introduces a new buffer name that can be referenced in `setAttributes()`

```typescript
bufferMap: [
{name: 'particles', attributes: [
// Note that strides are automatically calculated assuming a packed buffer.
{name: 'instancePositions'},
{name: 'instanceVelocities'}
]
Expand All @@ -31,3 +49,21 @@ calls will recognize that name and bind the provided buffer to all the interleav
attributes.
## Fields
Each row in the buffer mapping describes one buffer.
- `name: string` the name of the attribute and the buffer
- `format: VertexFormat` the format of the buffer's memory.
- `byteOffset?: number` the offset into the buffer (defaults to `0`)
- `byteStride?: number` the stride between elements in the buffer (default assumes a packed buffer)
- `attributes: InterleavedAttribute[]`
Interleaved Attribute Description
- `name: string` the name of the attribute and the buffer
- `format: VertexFormat` the format of the buffer's memory.
46 changes: 30 additions & 16 deletions docs/api-reference/core/shader-layout.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,28 @@
The luma.gl v9 API is currently in [public review](/docs/public-review) and may be subject to change.
:::

luma.gl defines the `ShaderLayout` type to collect a description of a (pair of) shaders.
A `ShaderLayout` is used when creating a `RenderPipeline` or `ComputePipeline`.
A `ShaderLayout` object describes the static structure a `RenderPipeline, "location" and structure of binding points of shaders,
including attributes, bindings (textures, samplers, uniform buffers), and uniforms (under WebGL) and also lets the application
assign a name to each binding point (typically matching the name used in the shader code).

The binding of data is performed in JavaScript on the CPU. For this to work,
a certain amount of metadata is needed in JavaScript that describes the layout of a
render or compute pipeline's specific shaders.
Note that a `ShaderLayout` only describes static data and it is typically complemented by a [`BufferMap`](), which contains
"dynamic" data such as the specific layout and structure of the buffers that will be provided to a `RenderPipeline`. The application
could choose to provide buffers with different vertex formats, strides, and offsets, without changing the shader.

Shader code contains declarations of attributes, uniform blocks, samplers etc in WGSL or GLSL code. After compilation and linking of fragment and vertex shaders into a pipeline, the resolved declarations collectively define the layout of the data that needs to be bound before the shader can execute on the GPU.
Shader code (WGSL and GLSL) contains declarations of attributes, uniform blocks, samplers etc, describing all required data inputs and outputs. After compilation and linking of fragment and vertex shaders into a pipeline, the resolved declarations collectively define the layout of the data that needs to be bound before the shader can execute on the GPU.

`ShaderLayout`s can be created manually by a programmer (by reading the shader code
and copying the relevant declarations).
As a preparation to a `RenderPipeline` `draw()` call, the GPU data
required by the pipeline's shaders must be bound on the CPU via luma.gl calls such as `setAttributes()`, `setIndexBuffer()`, `setBindings()` etc.
For these calls to work, the metadata in the `ShaderLayout` object is needed in JavaScript.

:::info
A default `ShaderLayout` is be extracted programmatically by the `RenderPipeline` in WebGL, but this is not yet possible in WebGPU. Therefore it is necessary to provide an explicit `layout` property to any `RenderPipeline` that is expected to run in WebGPU. This restriction may be lifted in the future.
:::
Note that `ShaderLayout`s are designed to be created manually by a programmer (who needs to make sure all relevant declarations in the shader code are described in the `ShaderLayout`).

Remarks:
- In WebGL, a default `ShaderLayout` is extracted automatically by the `RenderPipeline` in WebGL.
However this is not yet possible in WebGPU. Therefore it is necessary to provide an explicit `layout` property to any `RenderPipeline` that is expected to run in WebGPU. This restriction may be lifted in the future.
- It is not possible to automatically infer from a shader which attributes should have instanced step modes. The heuristic applied by luma.gl under WebGL is that any attribute which contains the string `instanced` will be assumed to have `stepMode='instance'`.
-
## Usage

```typescript
type ShaderLayout = {
Expand All @@ -28,7 +35,7 @@ type ShaderLayout = {
vertexPositions: {location: 2, format: 'float32x2', stepMode: 'vertex'}
],

bindings: {[bindingName: string]: BindingLayout};
bindings: {
projectionUniforms: {location: 0, type: 'uniforms'},
textureSampler: {location: 1, type: 'sampler'},
texture: {location: 2, type: 'texture'}
Expand Down Expand Up @@ -77,6 +84,11 @@ It contains fixed information about each attribute such as its location (the in
}
```

- `location: number` Compiled pipelines use small integer indices ("locations") to describe binding points (rather than string names). `ShaderLayout` assigns names to each attribute which allows applications to avoid keeping track of these location indices.
- `format: VertexFormat`
- `stepMode: 'vertex' | 'instance'` -


### bindings

Bindings cover textures, samplers and uniform buffers. location (index on the GPU)
Expand All @@ -90,12 +102,14 @@ and type are the key pieces of information that need to be provided.
}
```

- `location: number` Compiled pipelines use small integer indices ("locations") to describe binding points (rather than string names). `ShaderLayout` assigns names to each attribute which allows applications to avoid keeping track of these location indices.
- `type: 'texture' | 'sampler' | uniform'` The type of bind point (texture, sampler or uniform buffer). WebGPU requires separate bind points for textures and samplers.

### uniforms

And "free" uniforms (not part of a uniform buffer) are declared in this field.
### uniforms

:::caution
Uniforms are a WebGL-only concept, and it is strongly recommended to use uniform
buffers instead.
Uniforms are a WebGL-only concept. For portability it is recommended to use uniform buffers instead.
:::

Any top-level shader uniforms (not part of a uniform buffer) should be declared in this field.
2 changes: 1 addition & 1 deletion examples/showcase/instancing/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ export function pickInstance(
});

if (color[0] + color[1] + color[2] > 0) {
console.log('setting picking color', color);
// console.log('setting picking color', color);
model.updateModuleSettings({
pickingSelectedColor: color
});
Expand Down
169 changes: 0 additions & 169 deletions modules/api-tests/test/adapter/helpers/get-shader-layout.spec.ts

This file was deleted.

2 changes: 1 addition & 1 deletion modules/core/src/adapter/types/accessor.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// luma.gl, MIT license
import type {Buffer} from '../resources/buffer';
// import type {VertexFormat} from './vertex-formats';
// import type {VertexFormat} from './data-formats';

// ACCESSORS

Expand Down
Loading

0 comments on commit 1152a0e

Please sign in to comment.