feat(docs): Another docs pass (#1621)

This commit is contained in:
Ib Green 2022-02-10 13:52:09 -08:00 committed by GitHub
parent 00a2cb5b30
commit 7f2b7c76ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 873 additions and 866 deletions

View File

@ -4,11 +4,14 @@
The luma.gl API is designed to expose the capabilities of the GPU and shader programming to web applications.
Naturally, core responsibilities for any GPU library:
Core responsibilities for any GPU library are:
- GPU resource management (create and destroy GPU resources like Buffers, Textures etc)
- GPU Bindings (making attribute buffers, uniform buffers, textures, samplers etc available to GPU shaders.
- GPU resource management (create and destroy Buffers, Textures etc)
- GPU binding management (make attribute buffers, uniforms, textures, samplers available to GPU shaders).
- Shader execution (draw, compute)
Together with features like:
- Shader composition
- Cross platform support: backwards compatibility with WebGL 2 (WebGL on a "best effort" basis).

View File

@ -1,33 +1,30 @@
# Bindings
A key responsibility of luma.gl is to make it easy for the application to
set up data so that it can be accessed by shader code running on the GPU.
luma.gl offers support for setting up ("binding") data required by the GPU during shader execution, including:
- attribute buffers
- bindings (uniform buffers, textures, samplers, ...)
- uniforms
The terminology used to describe GPU bindings can vary somewhat between APIs and frameworks.
luma.gl attempts to roughly follow WebGPU / WGLSL conventions. The following terms are used:
## Background
- **layouts** - metadata for various shader connection points
- **attribute layout** - actual values for attributes
- **attribute buffers** - actual values for attributes
- **binding layout** - actual values for attributes
- **bindings** - actual values for
A key responsibility of any GPU framework is to make enable the application to
set up (or "bind") data so that it can be accessed by shader code running on the GPU.
## ShaderLayout
Shaders contain declarations of external inputs such as attributes, uniform blocks, samplers etc.
Collectively, these inputs define data that the CPU (the application) needs to be provide to the GPU
(typically by "binding" data to the right "locations").
## Shader Layout
Shader code (whether in WGSL or GLSL) contains declarations of attributes,
uniform blocks, samplers etc.
Collectively, these define the data that needs to be bound before the
shader can execute on the GPU. And since the bindings are performed on the CPU,
a certain amount of metadata is needed in JavaScript to describe what data
a specific shader or pair of shaders expects.
luma.gl needs a certain amount of metadata describing what bindings a specific shader (or pair of vertex and fragment shaders) expects.
luma.gl defines the `ShaderLayout` type to collect a description of a (pair of) shaders. A `ShaderLayout`
is required when creating a `RenderPipeline` or `ComputePipeline`.
luma.gl expects this metadata to be conform to the `ShaderLayout` type, and a `ShaderLayout`-conforming object
is required when creating a `RenderPipeline` or `ComputePipeline`.
Note that while `ShaderLayout`s must be created manually for WebGPU devices,
luma.gl can generate them automatically on WebGL devices (using WebGL program introspection APIs).
Shaders expose numeric bindings, however in applications, named bindings tend to be more convenient.
Shaders expose numeric bindings, however in applications, named bindings tend to be more convenient,
and the ShaderLayout does include information on both names, locations and formats.
Note: `ShaderLayout`s can be created manually (by reading the shader code),
or be automatically generated by parsing shader source code or using e.g. the WebGL program introspection APIs.
```typescript
type ShaderLayout = {
@ -37,7 +34,7 @@ type ShaderLayout = {
{name: 'vertexPositions', location: 2, format: 'float32x2', stepMode: 'vertex'}
},
bindings?: {
bindings: {
{name: 'projectionUniforms', location: 0, type: 'uniforms'},
{name: 'textureSampler', location: 1, type: 'sampler'},
{name: 'texture', location: 2, type: 'texture'}
@ -51,7 +48,7 @@ device.createRenderPipeline({
});
```
### Attributes
### Attribute Layout
```typescript
const shaderLayout: ShaderLayout = {
@ -66,26 +63,30 @@ const shaderLayout: ShaderLayout = {
### Buffer Mapping
Buffer mappings are an optional mechanism enabling more sophisticated GPU buffer layouts,
offering control of GPU buffer offsets, strides, interleaving etc.
For many use cases, supplying a single, "canonically" formatted buffer per attribute is sufficient.
However, sometimes an application may want to use more sophisticated GPU buffer layouts,
controlling GPU buffer offsets, strides, interleaving etc.
Note that buffer layouts are static and need to be defined when a pipeline is created, and all
buffers subsequently supplied to that pipeline need to conform to the buffer mapping.
Buffer mapping is an optional feature enabling custom buffer layouts and buffer interleaving.
The bufferMap field in the example below specifies that
Note that buffer mappings need to be defined when a pipeline is created,
and all buffers subsequently supplied to that pipeline need to conform to the buffer mapping.
Example: The `bufferMap` field in the example below specifies that both the
`instancePositions` and `instanceVelocities` attributes should be read from a single,
interleaved buffer. In this example, since no strides are provided, supplied buffers are assumed to be "packed",
with alternating "position" and "velocity" values with no padding in between.
```typescript
const shaderLayout: ShaderLayout = {
attributes: [
{name: 'instancePositions', location: 0, format: 'float32x2', stepMode: 'instance'},
{name: 'instanceVelocities', location: 1, format: 'float32x2', stepMode: 'instance'},
{name: 'vertexPositions', location: 2, format: 'float32x2', stepMode: 'vertex'}
],
...
};
device.createRenderPipeline({
shaderLayout,
shaderLayout: {
attributes: [
{name: 'instancePositions', location: 0, format: 'float32x2', stepMode: 'instance'},
{name: 'instanceVelocities', location: 1, format: 'float32x2', stepMode: 'instance'},
{name: 'vertexPositions', location: 2, format: 'float32x2', stepMode: 'vertex'}
],
...
},
// We want to use "non-standard" buffers: two attributes interleaved in same buffer
bufferMap: [
{name: 'particles', attributes: [
@ -93,7 +94,9 @@ device.createRenderPipeline({
{name: 'instanceVelocities'}
]
],
attributes: {},
attributes: {
particles: device.createBuffer(...)
},
bindings: {}
});
```
@ -102,14 +105,37 @@ device.createRenderPipeline({
```typescript
new Model(device, {
attributeLayout:
instancePositions: {location: 0, format: 'float32x2', stepMode: 'instance'},
instanceVelocities: {location: 1, format: 'float32x2', stepMode: 'instance'},
vertexPositions: {location: 2, format: 'float32x2', stepMode: 'vertex'}
};
})
shaderLayout: {
attributes: {
instancePositions: {location: 0, format: 'float32x2', stepMode: 'instance'},
instanceVelocities: {location: 1, format: 'float32x2', stepMode: 'instance'},
vertexPositions: {location: 2, format: 'float32x2', stepMode: 'vertex'}
}
}
});
```
## Types
### `ShaderLayout`
```typescript
export type ShaderLayout = {
attributes: AttributeLayout[];
bindings: BindingLayout[];
}
```
### `AttributeLayout`
- name = `string`
- location - `number`
- format - `VertexFormat`
- stepMode - `'vertex' \| 'instance'`
## Advanced Example
WGSL vertex shader
```rust
@ -147,93 +173,3 @@ fn main([[location(0)]] fragUV: vec2<f32>,
return textureSample(myTexture, mySampler, fragUV) * fragPosition;
}
```
# Accessors
"Buffer accessor objects" (or "accessor objects", or just "accessors" for short) are used to describe the structure of data contained in WebGL buffers (for more information see [`Buffers`](/docs/api-reference/webgl/buffer)).
When using `Buffer`s as input to shader programs, applications must tell WebGL how the data in the buffer is formatted, so that the GPU knows how to access buffers' memory. To enable applications to specify how the buffer memory should be accessed, luma.gl APIs that set attribute buffers accept buffer "accessor objects".
## Accessor Object Fields
This is an overview of the object accessor fields that are available to applications to define format descriptions. These objects can contain the following fields, this is an excerpt from [`Accessor`](/docs/api-reference/webgl/accessor).
| Property | Auto Deduced | Default | Comment |
| ----------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- |
| `buffer` | No | An accessor can optionally reference a specific buffer. Multiple accessors can point to the same buffer, providing different views or "slices" of the buffer's memory. |
| `offset` | No | `0` | Byte offset to start of data in buffer |
| `stride` | No | `0` | Extra bytes between each successive data element |
| `type` | Yes | `GL.FLOAT` | Low level data type (`GL.BYTE`, `GL.SHORT`, ...) |
| `size` | Yes | `1` | Components per element (`1`-`4`) |
| `divisor` | Yes | `0` | Enables/disables instancing |
| `normalize` | N/A | `false` | Normalize integers to [-1,1], or [0,1] if unsigned |
| `integer` | N/A | `false` | Disable conversion of integer values to floats **WebGL 2** |
## Combining Accessors with Buffers
When setting attributes (e.g. using `Model.setProps({attributes: {attributeName: value, ...}}))`, each attribute value needs to contain both a buffer (a handle to the raw data uploaded to the GPU) and an accessor (describing how that data should be accessed).
luma.gl provides three methods to specify attribute values so that both a buffer and an accessor are provided:
- As a two-element array: `[buffer, accessor]`.
- As an accessor, in which case the accessor object's `buffer` field should be set to the matching `Buffer`.
- As a `Buffer`, in which case the `Buffer` objects `accessor` field should be set to the mathing `Accessor`.
All three methods have their uses: the first option gives the applications full freedom to dynamically select combinations of buffers and accessors, the second option is often the natural choice when working with interleaved buffers (see below), and the last choice is often the most convenient when just setting up an ad-hoc buffer for immediate use, as the accessor can be stored directly on the buffer, avoiding the need to manage separate objects.
## Accessor Class vs Accessor Objects
luma.gl provides the [`Accessor`](/docs/api-reference/webgl/accessor) helper class to help you work with accessor objects. For instance, the `Accessor` class supports merging of partial accessor objects, see below.
Note that it is not necessary to use the `Accessor` class, as plain old JavaScript objects with the appropriate fields are also accepted by the various APIs that accept accessors. Use the style that works best for your application.
### "Partial" Accessors
luma.gl allows "partial" accessors to be created, and later combined. Usually many accessor fields can be left undefined (e.g. because defaults are sufficient, or because accessor auto-deduction has already deduced the information, see below).
Partial accessors will be created automatically by `Program` when shaders are compiled and linked, and also by `Buffer` objects when they are created. Any application supplied accessors fields will then be merged in (override) these auto-deduceted fields, that can add any fine-tuning or override of parameters.
### Accessor Auto Deduction
luma.gl attempts to "auto deduce" as much accessor information as it can, for instance luma.gl can extract fields like `type` and `size` after shaders have been compiled.
This relieves applications from having to respecify the same thing multiple times. For instance if the application has already declared an attribute as `in vec2 size` in the vertex shader, it does not need to specify `size:2, type: GL.FLOAT` again in the accessor, when it sets the buffer in JavaScript, since this information will have been auto-deduced.
In many cases, when buffers are not shared between attributes (i.e. interleaved) and default behavior is desired, luma.gl applications often do not need to specify any `Accessor` at all.
### Merging (Resolving) Accessors
The `Accessor` API allows for accessors to be merged (or "resolved") into a new `Accessor`. Accessor mmerging is mainly used internally in luma.gl to implement support for partial accessors and accessor auto deduction, but can be used by applications if necessary.
### Data Interleaving
Using the`stride` and `offset` fields in accessor objects, it is possible to interleave two arrays so that the first two elements of one array are next to each other, then the next two elements etc.
```
const interleavedBuffer = new Buffer(gl, accessor: {stride: 12 + 4}}); // Creates a partial accessor with `stride` in buffer.
vertexArray.setAttributes({
// These accessors are merged with the `interleavedBuffer` accessor and any
// auto-deduced accessors
POSITIONS: new Accessor({offset: 0, buffer: interleavedBuffer})
COLORS: new Accessor({offset: 12, buffer: interleavedBuffer})
})
```
For more information see the article about attributes.
### Using Different Size in Buffers and Shaders
It is possible to use different size memory attributes than specified by the GLSL shader code, by specifying a different size in the accessor compared to the GLSL shader variable declaration. Extra components in the Buffer memory will be ignored, missing components will be filled in from `(0.0, 0.0, 0.0, 1.0)`
> Be aware that the headless gl integration does not support this feature due to limitations in headless gl.
### glTF Format Accessors
[glTF formatted files](https://www.khronos.org/gltf/). glTF files contain two JSON object arrays ("bufferViews" and "accessors") that describe how raw memory buffers are organized and should be interpreted.
The `Accessor` and `Buffer` class APIs have intentionally been designed to be a close representation when converting "accessors" and "bufferViews" stored in glTF files. Each glTF `accessor` can be mapped to a luma.gl `Accessor` and each glTF `bufferView` can be mapped to a luma.gl `Buffer`.
`For more details see [glTF mapping]().`

View File

@ -1,27 +1,43 @@
# Device and CanvasContext
The `Device` class initializes, instruments a WebGL contexts.
The `Device` API is similar to the WebGPU `GPUDevice` class.
- Instrument an externally-created context with the same options as `createGLContext`. This performs WebGL 2 polyfilling (which is required for higher-level luma.gl classes) as well as optional state tracking and debug context creation.
- Polyfill a WebGL context integrating available extensions.
The [`Device`](../api-reference/device) class provides access to the GPU.
An luma.gl application first obtains a `Device` provides the
application with facilities for creating GPU resources
(such as `Buffer` and `Texture` objects), query GPU capabilities etc.
While a `Device` can be used on its own to perform computations on the GPU,
at least one `CanvasContext` is required for rendering to the screen.
Each `CanvasContext` provides a connection between a `Device` and an `HTMLCanvasElement` (or `OffscreenCanvas`).
## Installing adapters
The `@luma.gl/api` module is not usable on its own. A device adapter module must
be imported (it self registers on import).
The `@luma.gl/api` module defines abstract API interfaces such as `Device`, `Buffer` etc and is not usable on its own.
One or more device "adapter" modules (`@luma.gl/webgl` and `@luma.gl/webgpu`) must be also be imported,
and the actual resources returned to the application will be created by the adapter.
Create a WebGPU device:
```sh
yarn add @luma.gl/api
yarn add @luma.gl/webgpu
```
```typescript
import {luma} from '@luma.gl/api';
import '@luma.gl/webgpu';
import '@luma.gl/webgpu'; // Note: self registers on import
const device = await luma.createDevice({type: 'webgpu', canvas: ...});
```
It is possible to register more than one device adapter to create an application
that can work in both WebGL and WebGPU environments.
that can work in both WebGL and WebGPU environments. To create a `Device` using
the best available adapter (WebGPU, WebGL 2 and WebGL in that order).
```sh
yarn add @luma.gl/api
yarn add @luma.gl/webgl
yarn add @luma.gl/webgpu
```
```typescript
import {luma} from '@luma.gl/api';
@ -36,70 +52,26 @@ const webgpuDevice = luma.createDevice({type: 'best-available', canvas: ...});
Create a WebGL2 or WebGL context, auto creating a canvas
```typescript
import {Device} from '@luma.gl/gltools';
const device = new Device(); // Prefers WebGL 2 but falls back to WebGL 1
import {luma} from '@luma.gl/api';
import '@luma.gl/webgl';
const webgpuDevice = luma.createDevice({type: 'webgl', canvas: ...});
```
Create a WebGL 2 context (throws if WebGL2 not supported)
```typescript
import {Device} from '@luma.gl/gltools';
const device = createGLContext({
webgl1: false,
});
import {luma} from '@luma.gl/api';
import '@luma.gl/webgl';
const webgpuDevice = luma.createDevice({type: 'webgl2', canvas: ...});
```
Attaching a Device to an externally created WebGLRendering context instruments it
so that it works with other luma.gl classes.
```typescript
import {Device} from '@luma.gl/gltools';
import {Model} from '@luma.gl/engine';
const device = Device.attach(gl); // "instruments" the external context
// Instrumentation ensures the context works with higher-level classes.
const model = new Model(gl, options);
```
Attaching a device to a WebGL1 context adds WebGL2 "polyfills" to the WebGLRendering context
extends that context with a subset of WebGL2 APIs that are available via WebGL extensions.
```typescript
const gl = canvas.createContext('webgl'); // A WebGL 1 context
const device = Device.attach(gl);
// Can now use a subset of WebGL2 APIs on
const vao = device.gl.createVertexArray();
```
# CanvasContext
> This class is still experimental
A `CanvasContext` holds a connection between the GPU `Device` and an HTML `canvas` into which it can render.
A `CanvasContext` handles the following responsibilities:
- manages the "swap chain" (provides fresh texture view every frame on WebGPU)
- manages canvas resizing
- manages device pixel ratio
- can look up canvas elements in DOM, or create a new canvas elements if needed
Note that:
- A `WebGPUDevice` can have multiple associated `CanvasContext` instances, or none, if only used for compute.
- A `WebGLDevice` always has exactly one `CanvasContext` (and can thus only render into a single canvas). This is due to fundamental limitations of the WebGL API.
## CanvasContextProps
| Property | Type |
| --- | --- |
| `canvas?` | HTMLCanvasElement \| OffscreenCanvas \| string |
| `width?` | number |
| `height?` | number |
| `useDevicePixels?` | boolean \| number |
| `autoResize?` | boolean |
Remarks:
- `useDevicePixels` can accept a custom ratio (Number), instead of `true` or `false`. This allows rendering to a much smaller or higher resolutions. When using high value (usually more than device pixel ratio), it is possible it can get clamped down, this happens due to system memory limitation, in such cases a warning will be logged to the browser console. For additional details check device pixels [`document`](<(/docs/api-reference/gltools/device-pixels)>).
## CanvasContext
A [`CanvasContext`](../api-reference/canvas-context) holds a connection between
the GPU `Device` and an HTML or offscreen `canvas` into which it can render.
A `CanvasContext` takes care of:
- providing a fresh framebuffer every render frame, set up to render into the canvas' swap chain.
- canvas resizing
- device pixel ratio considerations

View File

@ -1,39 +1,13 @@
# Parameters
# GPU Parameters
luma.gl provides a unified API for controlling GPU parameters providing control of GPU pipeline features such as culling, depth and stencil buffers, blending, clipping etc.
A number of parameters are set when certain GPU objects are created, and cannot be changed without creating a new object.
| Parameter "Type" | Comments |
| ---------------- | ------------------------------------------------------------------------------------------------------------- |
| `RenderPipeline` constructor | `RenderPipeline` is created. |
| `RenderPass` constructor | Render targets, clear colors etc. To vary these parameters, additional RenderPasses would need to be created. |
| `RenderPass` method | (`viewport`, `scissor` and `blendConstant`) can be changed dynamically between draw calls in the same RenderPass. |
Note that there are certain types of parameters affecting GPU operation that are not handled by
| Parameters | Comments |
| ------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `Sampler` | How to sample from textures is controlled by `Sampler` objects. |
| `Framebuffer` | luma.gl uses Framebuffer objects to collect render targets and also certain per-render-target settings, such as clearColors. |
## Dynamic Parameters
The only parameters that can be changed at any time are viewport parameters, blend constant and stencil reference.
| Parameter | Description | Values |
| ------------------ | ---------------------------------------------------------------------------------------------- | --------------------------- | -------------- |
| `viewport` | Specifying viewport size | `number` (**`0xffffffff`**) |
| `scissor` | Specifyi | `number` (**`0xffffffff`**) | `gl.frontFace` |
| `blendConstant` | Sets color referenced by pipeline targets using blend factors `constant`, `one-minus-constant` |
| `stencilReference` | |
## Usage
To set up depth testing
```typescript
const value = device.createPipeline({
const value = device.createRenderPipeline({
parameters: {
depthWriteEnabled: true,
depthCompare: 'less-equal'
@ -41,7 +15,7 @@ const value = device.createPipeline({
```
```typescript
const value = device.createPipeline({
const value = device.createRenderPipeline({
parameters: {
depthWriteEnabled: true,
depthCompare: 'less-equal'
@ -54,11 +28,12 @@ const value = device.createPipeline({
]
});
const device.createFramebuffer({
const framebuffer = device.createFramebuffer({
colorAttachments: {clearColor: [1, 0, 0]},
})
const device.createRenderPass({
framebuffer,
parameters: {
}
@ -71,11 +46,13 @@ renderPass.setParameters({viewport: MINI_MAP})
renderPass.draw();
```
## Parameters by GPU Pipeline Stages
## GPU Pipeline Overview
Parameters control the GPU pipeline and can be GPU Pipeline Stages
Describes luma.gl setting names and values
0. Vertex Fetch (buffers)
1. Vertex Shader
2. Primitive assembly (`topology`)
3. Rasterization (multisampling parameters)
@ -84,54 +61,84 @@ Describes luma.gl setting names and values
6. Depth test and write (depth parameters)
7. Output merging, controlled by `Framebuffer`
## Parameter Mutability
### Primitive Assembly Parameters (RenderPipeline)
Most luma.gl parameters are stored on the `RenderPipeline` or `RenderPass` classes which are either fully or partially immutable, meaning that parameters are fixed when these objects are created, and cannot be changed without creating new resources. The following table summarizes the situation:
Note: `topology` must be specified on a `RenderPipeline` to describe the layout of vertex buffers.
| Parameter Mutability | Examples | Constraint |
| --------------------------------- | ------------------------------------------------- | ----------------------------------------------------------------------- |
| Dynamic `RenderPass` parameters | `viewport`, `scissor`, `blendConstant` | Can be freely changed between draw calls. |
| Fixed `RenderPass` parameters | `clearColors`, `discard`, `depthClearValue`... | Can not be changed. A new `RenderPass` must be created. |
| Fixed `RenderPipeline` parameters | `cullMode`, `frontFace`, `depthWriteEnabled`, ... | Can not be changed. A new `RenderPipeline` must be created. |
### Rasterization Parameters (RenderPipeline)
## Dynamic RenderPass Parameters
The only parameters that can be changed at any time (using `renderPass.setParameters()`) are viewport size, scissor rectangle, and blend constant
| Parameter | Type | Description |
| --------------- | ----------- | ----------------------------------------------------------------------------------- |
| `viewport` | `number[6]` | Specifying viewport size |
| `scissor` | `number[4]` | Specifying scissor rect |
| `blendConstant` | `number[4]` | Sets color for pipeline targets w/ blend factors `constant` or `one-minus-constant` |
## Fixed RenderPass Parameters
A `RenderPass` holds parameters specifying how color and depth / stencil attachments should be cleared (clear colors, values), discarded etc.
Note that there is no explicit `clear` function in the luma.gl v9 API. Instead attachments are cleared when a `RenderPass` is created (begins),
`createRenderPass({framebuffer, parameters})`
| Parameter | Type | Description |
| -------------------- | ------------- | -------------------------------------------------------------------------------------------------- |
| `clearColors?` | `number[4][]` | If not supplied, loads the value from the attached texture (less performant) |
| `discard?` | `boolean[]` | If `true`, does not store the result in the attached texture |
| `depthClearValue?` | `number` | Typically set to `0`. If not supplied, loads the value from the attached texture (less performant) |
| `depthDiscard?` | `boolean` | If `true`, does not store the result in the attached texture |
| `depthReadonly?` | `boolean` | If `true`, indicated depth component is readonly |
| `stencilClearValue?` | `number` | Typically set to `0`. If not supplied, loads the value from the attached texture (less performant) |
| `stencilDiscard?` | `boolean` | If `true`, does not store the result in the attached texture |
| `stencilReadonly?` | `boolean` | If `true`, indicated stencil component is readonly |
## RenderPipeline Parameters
### Culling Assembly
These parameters control the primitive assembly stage (which happens before fragment shader runs).
| Function | How to set | Description | Values | WebGL counterpart |
| ----------- | ------------------------------------- | --------------------------------- | ------ | ----------------- |
| `cullMode` | Which face to cull | **`'none'`**, `'front'`, `'back'` |
| `frontFace` | Which triangle winding order is front | **`ccw`**, `cw` |
Notes:
## Multisample Parameters (RenderPipeline)
- `topology` must be specified on a `RenderPipeline` to describe the layout of vertex buffers.
- `stripIndexFormat` must be specified on the `RenderPipeline` to define sub-list separators.
| Function | Description | Values |
| ------------------------ | ----------- | ---------- |
| `sampleCount` | | 1 |
| `sampleMask` | | 0xFFFFFFFF |
| `alphaToCoverageEnabled` | | false |
| Function | Type / Values | Description |
| ----------- | --------------------------------- | ------------------------------------- |
| `cullMode` | **`'none'`**, `'front'`, `'back'` | Which face to cull |
| `frontFace` | **`ccw`**, `cw` | Which triangle winding order is front |
### Blending
### Multisampling
| Parameter | How to set | Description |
| ---------------- | -------------------------------------- | ----------- |
| `blendColor` | `RenderPass.setParameters()` |
| `blendEquation` | `createRenderPipeline({targets: ...})` |
| `blendOperation` | `createRenderPipeline({targets}).` |
| `blendSrcFactor` | `createRenderPipeline({targets}).` |
| `blendDstFactor` | `createRenderPipeline({targets}).` |
[color_blending]: https://csawesome.runestone.academy/runestone/books/published/learnwebgl2/12_advanced_rendering/05_color_blending.html
| Function | Description | Values |
| ------------------------ | ----------- | ------------ |
| `sampleCount` | | `1` |
| `sampleMask` | | `0xFFFFFFFF` |
| `alphaToCoverageEnabled` | | `false` |
### Stencil Test (RenderPipeline)
After the fragment shader runs, optional stencil tests are performed, with resulting operations on the the stencil buffer.
| Function | Description | Values |
| --------------------------- | ------------------------ | -------------------------------------- | ------------------------------ | ---------------- |
| `stencilReadMask` | `createRenderPipeline()` | Binary mask for reading stencil values | `number` (**`0xffffffff`**) |
| `stencilWriteMask` | `createRenderPipeline()` | Binary mask for writing stencil values | `number` (**`0xffffffff`**) | `gl.frontFace` |
| `stencilCompare` | `createRenderPipeline()` | How the mask is compared | **`always`**, `not-equal`, ... | `gl.stencilFunc` |
| `stencilPassOperation` | `createRenderPipeline()` | | **`'keep'`** | `gl.stencilOp` |
| `stencilDepthFailOperation` | `createRenderPipeline()` | | **`'keep'`** | `gl.stencilOp` |
| `stencilFailOperation` | `createRenderPipeline()` | | **`'keep'`** | `gl.stencilOp` |
| Function | Type | Default | Description |
| --------------------------- | ------------------ | ------------------ | -------------------------------------- |
| `stencilReadMask` | `number` | (**`0xffffffff`**) | Binary mask for reading stencil values |
| `stencilWriteMask` | `number` | (**`0xffffffff`**) | Binary mask for writing stencil values |
| `stencilCompare` | `StencilCompare` | **`always`** | How the mask is compared |
| `stencilPassOperation` | `StencilOperation` | **`'keep'`** | |
| `stencilDepthFailOperation` | `StencilOperation` | **`'keep'`** | |
| `stencilFailOperation` | `StencilOperation` | **`'keep'`** | |
#### Stencil Test Functions
#### Stencil Test
| `stencilCompare` Value | Description |
| ---------------------- | ---------------------------------------- |
@ -144,7 +151,7 @@ After the fragment shader runs, optional stencil tests are performed, with resul
| `'notequal'` | Pass if (ref & mask) != (stencil & mask) |
| `'gequal'` | Pass if (ref & mask) >= (stencil & mask) |
#### Stencil Operations (RenderPipeline)
#### Stencil Operations
| `stencil<>Operation` | Description |
| -------------------- | -------------------------------------------------------------- |
@ -168,7 +175,7 @@ Remarks:
- By using binary masks, an 8 bit stencil buffer can effectively contain 8 separate masks or stencils
- The luma.gl API currently does not support setting stencil operations separately for front and back faces.
## Depth Test Parameters (RenderPipeline)
### Depth Test Parameters
After the GPU completes stencil tests, depth tests and writes are performed. These can be controlled by the following parameters:
@ -183,11 +190,69 @@ After the GPU completes stencil tests, depth tests and writes are performed. The
- **Depth Bias** - Sometimes referred to as "polygon offset". Adds small offset to fragment depth values (by factor × DZ + r × units). Usually used as a heuristic to avoid z-fighting, but can also be used for effects like applying decals to surfaces, and for rendering solids with highlighted edges. The semantics of polygon offsets are loosely specified by the WebGL standard and results can thus be driver dependent.
### Color Targets
## Render Targets (Framebuffers)
A `RenderPipeline` requires information about each color attachments:
### Clear Color
| Target setting | Type | Default | Description |
| ---------------------- | --------------- | --------- | ---------------------------------------------------------- |
| `format` | `TextureFormat` | N/A | |
| `writeMask?` | `number` | ALL = 0xF | RED = 0x1, GREEN = 0x2, BLUE = 0x4, ALPHA = 0x8, ALL = 0xF |
| `colorBlendOperation?` | BlendOperation | `'add'` | |
| `colorBlendSrcFactor?` | BlendEquation | `'one'` | |
| `colorBlendDstFactor?` | BlendEquation | `'zero'` | |
| `alphaBlendOperation?` | BlendOperation | `'add'` | |
| `alphaBlendSrcFactor?` | BlendEquation | `'one'` | |
| `alphaBlendDstFactor?` | BlendEquation | `'zero'` | |
| Function | Sets parameters |
| ---------- | -------------------------------------- |
| clearColor | `createRenderPass({colorAttachments})` |
### Blending
Blending mixes the source color and the target color:
- The two colors are first multiplied with chosen factors (controlled by "blend function" parameters).
- The two colors are then either added, subtracted, or the min or max color is used per the "blend operation" parameter.
The default blending settings do not perform any visual "blending" but simply overwrites the destination color with the source color by:
- multiplying the src color with 1
- multiplying the destination color with 0
- using the `'add'` blend operation.
The following link provides more information on [color blending][color_blending].
[color_blending]: https://csawesome.runestone.academy/runestone/books/published/learnwebgl2/12_advanced_rendering/05_color_blending.html
- `blendColor` The constant blend color referenced by `constant` and `one-minus-constant` can be changed at any time with with `RenderPass.setParameters({})`.
| BlendOperation | Output color | Visual effect |
| -------------------- | ------------------------------- | ----------------------------------------------------------------------- |
| `'add'` | source + destination | Incrementally brighten as multiple elements render on top of each other |
| `'subtract'` | source - destination | - |
| `'reverse-subtract'` | destination - source | - |
| `'min'` | minimum of source + destination | - |
| `'max'` | maximum of source + destination | Ensure brightest color is preserved |
| BlendFunction | All colors multiplied with |
| ----------------------- | ------------------------------------------------------ |
| `'zero'` | `[0,0,0,0]` |
| `'one'` | `[1,1,1,1]` |
| `'src'` | RBGAsrc |
| `'one-minus-src'` | 1 - RGBAsrc |
| `'src-alpha'` | AAAAsrc |
| `'one-minus-src-alpha'` | 1 - AAAAsrc |
| `'dst'` | RBGAdst |
| `'one-minus-dst'` | 1 - RBGAdst |
| `'dst-alpha'` | AAAAdest |
| `'one-minus-dst-alpha'` | 1 - AAAAdst |
| `'src-alpha-saturated'` | [min(AS, 1 - AD), min(AS, 1 - AD), min(AS, 1 - AD), 1] |
| `'constant'` | RGBAconstant |
| `'one-minus-constant'` | 1- RGBAconstant |
## Remarks
Note that there are certain types of parameters affecting GPU operation that are not handled by the main parameter system:
| Parameters | Comments |
| ------------- | ------------------------------------------------------------------------- |
| `Sampler` | Describes how to sample from textures is controlled by `Sampler` objects. |
| `Framebuffer` | luma.gl uses Framebuffer objects specify collections of render targets. |

View File

@ -2,9 +2,37 @@
> Proposed luma.gl v9 API. Open for comments.
The v9 API represents a break with the luma.gl v8 API, which was designed around providing a set of classes explicitly designed for working with the WebGL2 API.
The proposed luma.gl v9 API does represents a break with the v8 API. The new v9 API is optimized around WebGPU and TypeScript, while the v8 API design focused on providing a set of classes optimized for working with the WebGL2 API, and predated TypeScript introduction.
While there are breaking changes, the "spirit" and concepts of the classic luma.gl API have carried forward from the v8 API to the v9 API, and programmers should find themselves comfortably working on the same abstraction level as before with essentially the same classes, such as `Model`, `AnimationLoop`, `Buffer`, `Texture` etc.
While the v9 API has been modernized, the "spirit" and concepts of the classic luma.gl API have been carried forward from the v8 API to the v9 API. The abstraction level has not changed, and while some constants and names etc will need to be updated, programmers should find themselves comfortably working on with essentially the same classes in luma.gl v9, as they did in v8 without having to re-learn the API (e.g. `Model`, `AnimationLoop`, `Buffer`, `Texture` etc).
## Why a major breaking change?
The three major reasons why the v9 API are making breaking changes are to take full advantage of WebGPU, TypeScript and to improve long-term maintainability.
### A "WebGPU-first" API
Adding WebGPU support was top priority for luma.gl v9. Keeping the existing WebGL2-centric API and providing a WebGPU implementation of it was an option, but ultimately that did not make sense. The WebGPU API itself is quite different from WebGL (it was designed to avoid performance overhead induced by WebGL APIs), and WebGPU is clearly the future of WebGPU compute in the browser (WebGL is no longer evolving). It seems doubtful that luma.gl would be able to remain relevant if it remained optimized for WebGL.
### A "TypeScript-first" API
As luma.gl continued to adopt TypeScript it become clear that TypeScript enables a number simpler, more intuitive API constructions. One example is that in TypeScript we can now safely specify that an argument must be one of a few specific strings. By using string values in types, we don't need to introduce enumerations or key-value object constants. As an example the `Sampler` `minFilter` property is now specified as either `'linear'` or `'nearest'`, rather than `GL.LINEAR` or `GL.NEAREST`. The move to simpler interface mechanisms like string constant values also allowed us to align string constants with the WebGPU standard, avoiding the need to define additional mappings on top of the WebGPU API.
### Improved Maintainability
Another reason for breaking changes is the removal and restructuring of legacy code. The luma.gl API had grown quite large. It exposed all the functionality offered by WebGL2, however many WebGL 2 functions were rarely used. luma.gl contained a lot of code for mutating WebGL resources, which would not work when applications ran on WebGPU, since WebGPU classes are immutable. Some core maintainers have moved on, so we took the opportunity to cut out some legacy code to make sure the code base remains accessible and easy to understand for the community. The new WebGPU compatible API provided the just the lens we needed to decide which particular pieces of functionality could be cut.
Note tha in luma.gl v9, the v8 classes are still available (they have been moved into the `gltools` module, which is now considered deprecated) but the plan is to remove it completely in v10.
## v9 vs v8 API highlighs
- The v9 API is now abstract, specified in terms of TypeScript interfaces, such as `Buffer`, `Texture` etc.
-
- The `Device` class provides the interface implement these interfaces using the corresponding implementation API.
- Reading and writing buffers is now an async operation. While WebGL does not support async reads and writes on MacOS, the API is still async to ensure portability.
- Uniform buffers are now the standard way for the application to specify uniforms. Uniform buffers are "emulated" under WebGL.
- The v9 API no longer accepts/returns `GL` constants, but instead uses the corresponding string values from the WebGPU standard (mapping those transparently under WebGL).
- The parameter API has been updated to more closely match the WebGPU API. Also parameters are built into pipelines and not as easy to change in a draw call.
But there are a number of important differences, more on that below.
@ -22,41 +50,6 @@ GPUCommandBuffer and GPURenderBundle are containers for user-recorded commands.
GPUs execute commands encoded in GPUCommandBuffers by feeding data through a pipeline, which is a mix of fixed-function and programmable stages. Programmable stages execute shaders, which are special programs designed to run on GPU hardware. Most of the state of a pipeline is defined by a GPURenderPipeline or a GPUComputePipeline object. The state not included in these pipeline objects is set during encoding with commands, such as beginRenderPass() or setBlendColor().
## Why a major breaking change?
There a couple of reasons why we decided to make breaking changes in the v9 API:
### A "WebGPU-first" API
Making luma.gl work both on WebGPU and WebGL was the top priority for luma.gl v9. Naturally, we initially considered keeping the existing WebGL2-centric API and providing a WebGPU implementation of it, but ultimately that did not make sense.
- The imminent completion of the WebGPU standard and launch of WebGPU support in the Chrome browser.
- Announcements that no further evolution of the WebGL standard is taking place.
- WebGPU essentially exposes the latest next-gen GPU APIs (Vulkan, Metal, DX12) in the browser. A primary characteristic of these APIs is that they are designed to ensure GPU usage can be optimized "to the bone" (by e.g. minimization CPU-side validation overhead, enabling multi-threading etc) and wrapping WebGPU APIs under a backwards-compatible WebGL-centric API does not make much sense.
- It made sense to make a breaking change now, and introduce
### A "TypeScript-first" API
Both luma.gl and the most of the surrounding vis.gl code base has now been migrated to TypeScript. While we have added TypeScript types to the v8 API, it has become clear that TypeScript enables us to provide cleaner, more intuitive APIs.
One example is that in TypeScript we can now safely specify that an argument must be one of a few specific strings. By using string values in types, we don't need to introduce lots of enumerations or exports, and the code becomes easier to debug as the string parameters are self explaining, typescript will catch any misspelled string inputs. As an example the `Sampler` `minFilter` property is now specified as either `'linear'` or `'nearest'`, rather than `GL.LINEAR` or `GL.NEAREST`.
This move to string constant values also allowed us to align string constants with the WebGPU standard.
### Community Maintainability
Another major reason is that the luma.gl API had grown quite large as it exposed all the functionality offered by WebGL2. However as the some core maintainers have moved on, and luma.gl is increasingly becomes a community project, we want to make sure the code base is accessible and easy to understand. The new WebGPU compatible API provided the just the lens we needed to decide if a piece of functionality could be cut.
For now we have kept all the old functionality (it has been moved into the `gltools` module which is now considered deprecated).
## v9 vs v8 API
- The API is now abstract, specified in terms of TypeScript interfaces, such as `Buffer`, `Texture` etc. A `Device` class provides concrete classes that implement these interfaces using the corresponding implementation API.
- Reading and writing buffers is now an async operation. While WebGL does not support async reads and writes on MacOS, the API is still async to ensure portability.
- Uniform buffers are now the standard way for the application to specify uniforms. Uniform buffers are "emulated" under WebGL.
- The v9 API no longer accepts/returns `GL` constants, but instead uses the corresponding string values from the WebGPU standard (mapping those transparently under WebGL).
- The parameter API has been updated to more closely match the WebGPU API. Also parameters are built into pipelines and not as easy to change in a draw call.
## Get Started
```js

View File

@ -243,3 +243,244 @@ GPU State Management can be quite complicated.
* Reading values from WebGL can be very slow if it requires a GPU roundtrip. To get around this, luma.gl reads values once, caches them and tracks them as they are changed through luma functions. The cached values can get out of sync if the context is shared outside of luma.gl.
* luma.gl's state management enables "conflict-free" programming, so that even when setting global state, one part of the code does not need to worry about whether other parts are changing the global state.
* Note that to fully support the conflict-free model and detect changes done e.g. in other WebGL libraries, luma.gl needs to hook into the WebGL context to track state changes.
----
## v8 to v9 API Mapping
- Parameters are set on `Pipeline`/`Program` creation. They can not be modified, or passed in draw calls.
- Parameters can only be set, not queried. luma.gl longer provides a way to query parameters.
| WebGL Function | luma.gl parameter counterparts |
| --------- | ---------------------------------- |
| [polygonOffset](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/polygonOffset) | `depthBias`, `depthBiasSlopeScale` |
| [depthRange](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/depthRange) | N/A |
| [clearDepth](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/clearDepth) | |
## Depth testing
To set up depth testing
```js
const value = model.setParameters({
depthWriteEnabled: true,
depthCompare: 'less-equal'
});
```
## Parameters
Describes luma.gl setting names and values
### Rasterization Parameters
These parameters control the rasterization stage (which happens before fragment shader runs).
| Function | Description | Values | WebGL counterpart |
| --------- | ---------------------------------- | --- | --- |
| `cullMode` | Which face to cull | **`'none'`**, `'front'`, `'back'` | [`gl.cullFace`](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/cullFace) |
| `frontFace` | Which triangle winding order is front | **`ccw`**, `cw` | [`gl.frontFace`](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/frontFace) |
| `depthBias` | Small depth offset for polygons | `float` | `gl.polygonOffset` |
| `depthBiasSlopeScale` | Small depth factor for polygons | `float` | `gl.polygonOffset` |
| `depthBiasClamp` | Max depth offset for polygons | `float` |
- **Depth Bias** - Sometimes referred to as "polygon offset". Adds small offset to fragment depth values (by factor × DZ + r × units). Usually used as a heuristic to avoid z-fighting, but can also be used for effects like applying decals to surfaces, and for rendering solids with highlighted edges. The semantics of polygon offsets are loosely specified by the WebGL standard and results can thus be driver dependent.
## Stencil Parameters
After the fragment shader runs, optional stencil tests are performed, with resulting operations on the the stencil buffer.
| Function | Description | Values |
| --------- | ---------------------------------- | --- |
| `stencilReadMask` | Binary mask for reading stencil values | `number` (**`0xffffffff`**) |
| `stencilWriteMask` | Binary mask for writing stencil values | `number` (**`0xffffffff`**) | `gl.frontFace` |
| `stencilCompare` | How the mask is compared | **`always`**, `not-equal`, ... | `gl.stencilFunc` |
| `stencilPassOperation` | | **`'keep'`** | `gl.stencilOp` |
| `stencilDepthFailOperation` | | **`'keep'`** | `gl.stencilOp` |
| `stencilFailOperation` | | **`'keep'`** | `gl.stencilOp` |
Action when the stencil test fails
* stencil test fail action,
* depth test fail action,
* pass action
Remarks:
- By using binary masks, an 8 bit stencil buffer can effectively contain 8 separate masks or stencils
- The luma.gl API currently does not support setting stencil operations separately for front and back faces.
| WebGL Function | WebGL Parameters | luma.gl v9 counterpart |
| -------- | -------------- |
| [`clearStencil`](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/clearStencil) | `GL.STENCIL_CLEAR_VALUE` | |
| [`stencilMask`](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/stencilMask) | [`GL.STENCIL_WRITEMASK`] | `stencilWriteMask` |
| [`stencilFunc`](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/stencilFunc) | [`GL.STENCIL_FUNC`, `GL.STENCIL_REF`, `GL.STENCIL_VALUE_MASK`] | `stencilCompare`, `stencilReadMask` |
| [`stencilOp`](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/stencilOp) | `GL.STENCIL_FAIL`, `GL.STENCIL_PASS_DEPTH_FAIL`, `GL.STENCIL_PASS_DEPTH_PASS` | `stencilPassOperation`, `stencilFailDepth
| [`stencilOpSeparate`](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/stencilOpSeparate) | [`GL.STENCIL_FAIL`, `GL.STENCIL_FAIL_DEPTH_FAIL`, `GL.STENCIL_FAIL_DEPTH_PASS`, `GL.STENCIL_BACK_FAIL`, `GL.STENCIL_BACK_FAIL_DEPTH_FAIL`, `GL.STENCIL_BACK_FAIL_DEPTH_PASS`]| N/A |
- In WebGL, setting any value will enable stencil testing (i.e. enable `GL.STENCIL_TEST`).
| Parameter | Type | Default | Description |
| --------------------------------- | --------- | ------------ | ----------------------- |
| `GL.STENCIL_TEST` | GLboolean | `false` | Enables stencil testing |
| `GL.STENCIL_CLEAR_VALUE` | GLint | `0` | Sets index used when stencil buffer is cleared. |
| `GL.STENCIL_WRITEMASK` | GLuint | `0xFFFFFFFF` | Sets bit mask enabling writing of individual bits in the stencil planes |
| `GL.STENCIL_BACK_WRITEMASK` | GLuint | `0xFFFFFFFF` | Sets bit mask enabling writing of individual bits in the stencil planes |
| `GL.STENCIL_FUNC` | GLenum | `GL.ALWAYS` | |
| `GL.STENCIL_REF` | GLint | `0` | |
| `GL.STENCIL_VALUE_MASK` | GLuint | `0xFFFFFFFF` | Sets bit mask |
| `GL.STENCIL_BACK_FUNC` | GLenum | `GL.ALWAYS` | |
| `GL.STENCIL_BACK_REF` | GLint | `0` | |
| `GL.STENCIL_BACK_VALUE_MASK` | GLuint | `0xFFFFFFFF` | Sets bit mask enabling writing of individual bits in the stencil planes |
| `GL.STENCIL_FAIL` | GLenum | `GL.KEEP` | stencil test fail action |
| `GL.STENCIL_PASS_DEPTH_FAIL` | GLenum | `GL.KEEP` | depth test fail action |
| `GL.STENCIL_PASS_DEPTH_PASS` | GLenum | `GL.KEEP` | depth test pass action |
| `GL.STENCIL_BACK_FAIL` | GLenum | `GL.KEEP` | stencil test fail action, back |
| `GL.STENCIL_BACK_PASS_DEPTH_FAIL` | GLenum | `GL.KEEP` | depth test fail action, back |
| `GL.STENCIL_BACK_PASS_DEPTH_PASS` | GLenum | `GL.KEEP` | depth test pass action, back |
### Blending
| Function style | Sets parameter(s) |
| --------------------- | ---------------------- |
| [blendColor](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/blendColor) | `GL.BLEND_COLOR` |
| [blendEquation](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/blendEquation) | [`GL.BLEND_EQUATION_RGB`, `GL.BLEND_EQUATION_ALPHA`] |
| [blendFunc](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/blendFunc) | [`GL.BLEND_SRC_RGB`, `GL.BLEND_SRC_ALPHA`] |
| [blendFuncSeparate](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/blendFuncSeparate) | [`GL.BLEND_SRC_RGB`, `GL.BLEND_SRC_ALPHA`, `GL.BLEND_DST_RGB`, `GL.BLEND_DST_ALPHA`] |
| Parameter | Type | Default | Description |
| ------------------------- | --------------- | --------------- | -------- |
| `GL.BLEND` | GLboolean | `false` | Blending enabled |
| `GL.BLEND_COLOR` | Float32Array(4) | `[0, 0, 0, 0]` | |
| `GL.BLEND_EQUATION_RGB` | GLenum | `GL.FUNC_ADD` | |
| `GL.BLEND_EQUATION_ALPHA` | GLenum | `GL.FUNC_ADD` | |
| `GL.BLEND_SRC_RGB` | GLenum | `GL.ONE` | srcRgb |
| `GL.BLEND_SRC_ALPHA` | GLenum | `GL.ZERO` | srcAlpha |
| `GL.BLEND_DST_RGB` | GLenum | `GL.ONE` | dstRgb |
| `GL.BLEND_DST_ALPHA` | GLenum | `GL.ZERO` | dstAlpha |
### Clear Color
| Function | Sets parameters |
| --------- | ---------------------------------- |
| [clearColor](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/clearColor) | GL.COLOR_CLEAR_VALUE |
| Parameter | Type | Default | Description |
| ---------------------- | --------------- | -------- | -------- |
| `GL.COLOR_CLEAR_VALUE` | new Float32Array(4) | [0, 0, 0, 0] | . |
### Color Mask
| Function | Sets parameters |
| --------- | ---------------------------------- |
| [colorMask](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/colorMask) | GL.COLOR_WRITEMASK |
| Parameter | Type | Default | Description |
| ---------------------- | --------------- | -------- | -------- |
| `GL.COLOR_WRITEMASK` | [GLboolean, GLboolean, GLboolean, GLboolean] | [true, true, true, true] | . |
### Dithering
| Parameter | Type | Default | Description |
| ---------------------- | --------------- | -------- | -------- |
| `GL.DITHER` | GLboolean | `true` | Enable dithering of color components before they get written to the color buffer |
* Note: Dithering is driver dependent and typically has a stronger effect when the color components have a lower number of bits.
### PolygonOffset
Add small offset to fragment depth values (by factor × DZ + r × units)
Useful for rendering hidden-line images, for applying decals to surfaces,
and for rendering solids with highlighted edges.
| Function | Sets parameters |
| --------- | ---------------------------------- |
| [polygonOffset](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/polygonOffset) | [GL.POLYGON_OFFSET_FACTOR, GL.POLYGON_OFFSET_UNITS] |
| Parameter | Type | Default | Description |
| -------------------------- | ------------- | -------- | ----------------------- |
| `GL.POLYGON_OFFSET_FILL` | GLboolean | `false` | . |
| `GL.POLYGON_OFFSET_FACTOR` | GLfloat | `0` | . |
| `GL.POLYGON_OFFSET_UNITS` | GLfloat | `0` | . |
* Note: The semantics of polygon offsets are loosely specified by the WebGL standard and results can thus be driver dependent.
### Rasterization (WebGL 2)
Primitives are discarded immediately before the rasterization stage, but after the optional transform feedback stage. `gl.clear()` commands are ignored.
| Parameter | Type | Default | Description |
| ----------------------------------- | ------------- | -------- | ----------------------- |
| `GL.RASTERIZER_DISCARD` | GLboolean | `false` | Disable rasterization |
### Sampling
Specify multisample coverage parameters
| Function | Sets parameters |
| --------- | ---------------------------------- |
| [sampleCoverage](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/sampleCoverage) | [`GL.SAMPLE_COVERAGE_VALUE`, `GL.SAMPLE_COVERAGE_INVERT`] |
| Parameter | Type | Default | Description |
| ---------------------------------- | ------------- | -------- | ----------------------- |
| `GL_SAMPLE_COVERAGE` | GLboolean | `false` | Activates the computation of a temporary coverage value determined by the alpha value. |
| `GL_SAMPLE_ALPHA_TO_COVERAGE` | GLboolean | `false` | Activates ANDing the fragment's coverage with the temporary coverage value |
| `GL.SAMPLE_COVERAGE_VALUE` | GLfloat | 1.0 | |
| `GL.SAMPLE_COVERAGE_INVERT` | GLboolean | `false` | |
### Scissor Test
Settings for scissor test and scissor box.
| Function | Sets parameters |
| --------- | ---------------------------------- |
| [scissor](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/scissor) | `GL.SCISSOR_BOX` |
| scissorTest | GL.SCISSOR_TEST |
| Parameter | Type | Default | Description |
| ---------------------------------- | ------------- | -------- | ----------------------- |
| `GL.SCISSOR_TEST` | GLboolean | `false` |
| `GL.SCISSOR_BOX` | Int32Array(4) | [null, null, null, null]), // TBD |
## Viewport
Specifies the transformation from normalized device coordinates to
window/framebuffer coordinates. The maximum supported value, is defined by the
`GL.MAX_VIEWPORT_DIMS` limit.
| Function | Parameters |
| ------------ | -------------- |
| [viewport](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/viewport) | `GL.VIEWPORT` |
| Parameter | Type | Default | Description |
| ---------------------------------- | ------------- | --------- | ----------------------- |
| `GL.VIEWPORT` | Int32Array(4) | [...] TBD | Viewport |
Example:
```js
// Set viewport to maximum supported size
const maxViewport = getLimits(gl)[GL.MAX_VIEWPORT_DIMS];
setState(gl, {
viewport: [0, 0, maxViewport[0], maxViewport[1]]
});
```

View File

@ -2,6 +2,10 @@
This pages collects notes on some of the notable differences between WebGPU and WebGL. This is not intended to be a complete list but is essentially a set of author's notes, included because they may be useful to understanding why some of the breaking changes in the luma.gl v9 API were made, and provide more detail on the differences between the WebGPU and WebGL implementations.
- The imminent completion of the WebGPU standard and launch of WebGPU support in the Chrome browser.
- Announcements that no further evolution of the WebGL standard is taking place.
- WebGPU essentially exposes the latest next-gen GPU APIs (Vulkan, Metal, DX12) in the browser. A primary characteristic of these APIs is that they are designed to ensure GPU usage can be optimized "to the bone" (by e.g. minimization CPU-side validation overhead, enabling multi-threading etc) and wrapping WebGPU APIs under a backwards-compatible WebGL-centric API does not make much sense.
**Decision: Convert luma.gl into a "WebGPU first" API**
## Background

View File

@ -12,6 +12,25 @@ a `CanvasContext` handles the following responsibilities:
- manages canvas resizing
- manages device pixel ratio
## Usage
Use a device's default canvas context:
```typescript
const renderPass = device.beginRenderPass({
framebuffer: device.canvasContext.getFramebuffer()
});
```
Create additional canvas contexts (WebGPU only):
```typescript
const canvasContext2 = device.createCanvasContext({canvas: ...});
const renderPass = device.beginRenderPass({
framebuffer: canvasContext2.getFramebuffer()
});
```
## Types
### `CanvasContextProps`
@ -67,5 +86,4 @@ canvasContext.resize(options)
## Remarks
- Note that a WebGPU `Device` can have multiple associated `CanvasContext` instances (or none, if only used for compute). However a WebGL `Device` always has exactly one `CanvasContext` and can only render into that single canvas. (This is a fundamental limitation of the WebGL API.)
- `useDevicePixels` can accept a custom ratio (Number), instead of `true` or `false`. This allows rendering to a much smaller or higher resolutions. When using high value (usually more than device pixel ratio), it is possible it can get clamped down, this happens due to system memory limitation, in such cases a warning will be logged to the browser console. For additional details check device pixels [`document`](<(/docs/api-reference/gltools/device-pixels)>).

View File

@ -0,0 +1,179 @@
# AnimationLoop
> Proposed luma.gl v9 API. Open for comments.
An optional helper class to manage the applications render loop,
`AnimationLoop` provides a number of conveniences related to
initialization of a `Device` and update of per-frame animation parameters.
## Usage
```typescript
import {AnimationLoop} from `@luma.gl/engine`;
```
Autocreates a canvas/context
```js
import {AnimationLoop, ClipSpace} from '@luma.gl/engine';
class AppAnimationLoop extends AnimationLoop {
onInitialize({gl}) {
// Keys in the object returned here will be available in onRender
this.clipSpaceQuad = new ClipSpace({gl, fs: FRAGMENT_SHADER});
}
onRender({tick}) {
// Tick is autoupdated by AnimationLoop
this.clipSpaceQuad.setUniforms({uTime: tick * 0.01});
this.clipSpaceQuad.draw();
}
});
new AppAnimationLoop().start();
```
Use a canvas in the existing DOM through its HTML id
```js
new AppAnimationLoop({canvas: 'my-canvas'}).start();
```
## Types
### `AnimationLoopProps`
| Parameter | Type | Description |
| -------------------------------- | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `device?` | `Device` | If supplied, will render into this external context instead of creating a new one. |
| `glOptions`=`{}` (object) | | Options to create the WebGLContext with. See [createGLContext](/docs/api-reference/gltools/context). |
| `onCreateContext?` | (callback) | function without parameters that returns a `WebGLRenderingContext`. This callback will be called exactly once, after page load completes. |
| `onInitialize` | (callback) | if supplied, will be called once after first `start()` has been called, after page load completes and a context has been created. |
| `onRender?` | (callback) | Called on every animation frame. |
| `onFinalize?` | (callback) | Called once when animation is stopped. Can be used to delete objects or free any resources created during `onInitialize`. |
| `onError?` | (callback) | Called when an error is about to be thrown. |
| `autoResizeViewport`=`true` | `boolean` | If true, calls `gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight)` each frame before `onRender` is called. Set to false to control viewport size. |
| `autoResizeDrawingBuffer`=`true` | `boolean` | If true, checks the canvas size every frame and updates the drawing buffer size if needed. |
| `useDevicePixels` | `boolean \| number` | Whether to use `window.devicePixelRatio` as a multiplier, e.g. in `autoResizeDrawingBuffer` etc. Refer to `Experimental API` section below for more use cases of this prop. |
### `AnimationProps`
The callbacks `onInitialize`, `onRender` and `onFinalize` that the app supplies to the `AnimationLoop`, will be called with an object containing named parameters:
| Parameter | Type | Description |
| ----------------- | ---------------------------------------- | ----------------------------------------------------------------------------------- |
| `animationLoop` | `AnimationLoop` | The calling `AnimationLoop` instance |
| `device` | `Device` | This `AnimationLoop`'s gl context. |
| `canvas` | `HTMLCanvasElement` or `OffscreenCanvas` | The canvas associated with this context. |
| `aspect` | `number` | The canvas aspect ratio (width/height) to update projection matrices |
| `width` | | The drawing buffer width, in "device" pixels (can be different from canvas.width). |
| `height` | | The drawing buffer height, in "device" pixels (can be different from canvas.width). |
| `useDevicePixels` | `boolean` | Boolean indicating if canvas is utilizes full resolution of Retina/ |
| `needsRedraw` | `String` | Redraw flag (will be automatically set if drawingBuffer resizes) |
| `time` | `Number` | Milliseconds since `AnimationLoop` was created (monotonic). |
| `tick` | `Number` | Counter that updates for every frame rendered (monotonic). |
| `renderPass` | `RenderPass` | Availabel if `createFrameBuffer: true` was passed to the constructor. |
| `_mousePosition` | `[x, y]` or `null` | (**experimental**) Current mouse position over the canvas. |
| `_timeline` | `Timeline` | (**experimental**) `Timeline` object tracking the animation timeline and channels. |
## Methods
### constructor(props : Object)
```js
new AnimationLoop({
onCreateContext,
onInitialize,
onFinalize,
onRender,
autoResizeViewport,
autoResizeDrawingBuffer
});
```
### start([options : Object]) : AnimationLoop
Restarts the animation
`animationLoop.start(options)`
- `options`=`{}` (object) - Options to create the WebGLContext with. See [createGLContext](/docs/api-reference/gltools/context).
### stop() : AnimationLoop
Stops the animation
`animationLoop.stop()`
### waitForRender() : Promise
Returns a promise which resolves in the next frame after rendering and the `onRender` callback have completed.
```js
const loop = await animationLoop.waitForRender()
// can now read pixels from webgl context
loop.gl.readPixels(...)
```
### redraw() : AnimationLoop
Immediately invokes a redraw (call `onRender` with updated animation props). Only use if the canvas must be updated synchronously.
### setNeedsRedraw(reason : String) : AnimationLoop
`animationLoop.setNeedsRedraw(reason)`
- `reason` (`String`) - A human readable string giving a hint as to why redraw was needed (e.g. "geometry changed").
If set, the value will be provided as the `needsRedraw` field to the `onRender` callback.
Notes:
- `onRender` will be called for each animation frame regardless of whether this flag is set, and the redraw reason is automatically cleared.
- If called multiple times, the `reason` provided in the first call will be remembered.
- `AnimationLoop` automatically sets this flag if the WebGL context's drawing buffer size changes.
### setProps(props : Object) : AnimationLoop
`animationLoop.setProps({...props})`
- `props.autoResizeViewport` - Call `gl.viewport` before each call to `onRender()`
- `props.autoResizeDrawingBuffer` - Update the drawing buffer size to match the canvas size before each call to `onRender()`
- `props.useDevicePixels` - Whether to use `window.devicePixelRatio` as a multiplier, e.g. in `autoResizeDrawingBuffer` etc.
### attachTimeline(timeline: Timeline): void
Attach an `Timeline` object to the animation loop. Allows time produced for animations to be paused, played, etc. See `Timeline` documentation for more info.
### detachTimeline(): void
Detach the currently attached timeline from the animation loop.
### toDataURL(): string
Returns returns a `Promise` that resolves to the data URL of the canvas once drawing operations are complete for the current frame. The data URL can be used as the `src` for an HTML image element.
`animationLoop.toDataURL()`
### isContextLost(): boolean
Returns the current state of the WebGL context used by the animation loop.
### Frame timers
- The animation loop tracks GPU and CPU render time of each frame the in member properties `cpuTime` and `gpuTime`. If `gpuTime` is set to `-1`, then the timing for the last frame was invalid and should not be used (this rare and might occur, for example, if the GPU was throttled mid-frame).
## Experimental API (`useDevicePixels`)
`useDevicePixels` can accept a custom ratio (Number), instead of `true` or `false`. This allows rendering to a much smaller or higher resolutions. When using high value (usually more than device pixel ratio), it is possible it can get clamped down, this happens due to system memory limitation, in such cases a warning will be logged to the browser console. For additional details check device pixels [`document`](<(/docs/api-reference/gltools/device-pixels)>).
## Remarks
- You can instantiate multiple `AnimationLoop` classes in parallel, rendering into the same or different `WebGLRenderingContext`s.
- Works both in browser and under Node.js.
- All `AnimationLoop` methods can be chained.
- Postpones context creation until the page (i.e. all HTML) has been loaded. At this time it is safe to specify canvas ids when calling [`createGLContext`](/docs/api-reference/gltools/context).
- The supplied callback function must return a WebGLRenderingContext or an error will be thrown.
- This callback registration function should not be called if a `WebGLRenderingContext` was supplied to the AnimationLoop constructor.
- When running in the browser, this class uses [`requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame)
- [WebGL Fundamentals](https://webglfundamentals.org/webgl/lessons/webgl-anti-patterns.html#drawingbuffer) contains excellent information on the subtleties of the how the WebGL context's drawing buffer and the HTML canvas interact.

View File

@ -2,12 +2,13 @@
> Proposed luma.gl v9 API. Open for comments.
The `Model` is the primary class for most luma.gl applications.
The `Model` class brings together and orchestrates the different functions needed
to perform draw calls, including:
A `Model` brings together a range of different luma.gl functions in one class. It holds all the data necessary to perform draw calls:
- **shaders** (via a [`Program`](/docs/api-reference/webgl/program) instance)
- **shader module dependency injection and shader transpilation**
- **render pipeline creation** -
- **bindings** these can reference uniforms and textures.
- **uniforms**
- **attributes** (holds a [`Mesh`] or a [`Geometry`](/docs/api-reference/engine/geometry) instance, plus any additional attributes for instanced rendering)
The `Model` class integrates with the `@luma.gl/shadertools` shader module system: [see `Shader Assembly`](/docs/api-reference/shadertools/assemble-shaders).
@ -20,17 +21,23 @@ TBD
## Usage
```typescript
import {Model} from `@luma.gl/engine`;
```
### Provide attribute data using Geometry object
Create model object by passing shaders, uniforms, geometry and render it by passing updated uniforms.
```typescript
// construct the model.
const model = new Model(device, {
const model = new Model(device, {
vs: VERTEX_SHADER,
fs: FRAGMENT_SHADER,
uniforms: {uSampler: texture},
geometry: geometryObject,
bindings: {
uSampler: texture
},
})
// and on each frame update any uniforms (typically matrices) and call render.
@ -116,82 +123,80 @@ model.setVertexArray(vertexArray2);
model.draw({...});
```
## Properties
## Types
| Property | Type | Description |
| ------------- | ------------------------ | --------------------------------------------------------------------------------------- |
| `vs` | `Shader` \| _string_ | A vertex shader object, or source as a string. |
| `fs` | `Shader` \| _string_ | A fragment shader object, or source as a string. |
| `layout` | `ShaderLayout` | Describes how shader attributes and bindings are laid out. |
| `modules` | | shader modules to be applied (shadertools). |
| `pipeline` | | pre created program to use, when provided, vs, ps and modules are not used. |
| `topology?` | | `'point-list'`, `'line-list'`, `'line-strip'`, `'triangle-list'` or `'triangle-strip'`, |
| `parameters?` | RenderPipelineParameters | |
### ModelProps
- `programManager` | | `ProgramManager` to use for program creation and caching. |
- `varyings` | (WebGL 2) | An array of vertex shader output variables, that needs to be recorded (used in TransformFeedback flow). |
- `bufferMode` | (WebGL 2) | Mode to be used when recording vertex shader outputs (used in TransformFeedback flow). Default value is `gl.SEPARATE_ATTRIBS`. |
- `transpileToGLSL100` | | Transpile vertex and fragment shaders to GLSL 1.0. |
| Property | Type | Description |
| -------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `vs` | `Shader` \| _string_ | A vertex shader object, or source as a string. |
| `fs` | `Shader` \| _string_ | A fragment shader object, or source as a string. |
| `modules` | | shader modules to be applied (shadertools). |
| `programManager` | | `ProgramManager` to use for program creation and caching. |
| `varyings` | (WebGL 2) | An array of vertex shader output variables, that needs to be recorded (used in TransformFeedback flow). |
| `bufferMode` | (WebGL 2) | Mode to be used when recording vertex shader outputs (used in TransformFeedback flow). Default value is `GL.SEPARATE_ATTRIBS`. |
| `transpileToGLSL100` | | Transpile vertex and fragment shaders to GLSL 1.0. |
`ModelProps` passes through `RenderPipelineProps`
| Property | Type | Description |
| ------------- | -------------------------- | --------------------------------------------------------------------------------------- |
| `layout` | `ShaderLayout` | Describes how shader attributes and bindings are laid out. |
| `topology?` | | `'point-list'`, `'line-list'`, `'line-strip'`, `'triangle-list'` or `'triangle-strip'`, |
| `parameters?` | `RenderPipelineParameters` | |
| Property | Type | Description |
| ----------------- | ------------------------ | ------------------------------------------------------------------- |
| `vertexCount?` | `number` | |
| `instanceCount?` | `number` | |
| `moduleSettings?` | `Record<string, any>` | any values required by shader modules (will be mapped to uniforms). |
| `uniforms?` | `Record<string, any>` | any non-binding uniform values |
| `bindings?` | `Record<string, any>` | |
| `buffers?` | `Record<string, Buffer>` | |
## Properties
### moduleSettings: object
### renderPipeline: RenderPipeline
any uniforms needed by shader modules.
### uniforms: object
uniform values to be used for drawing.
### onBeforeRender
function to be called before every time this model is drawn.
### onAfterRender
function to be called after every time this model is drawn.
Get model's `Program` instance
## Methods
### Model(device: Device, props: ModelProps)
### constructor(device: Device, props: ModelProps)
The constructor for the Model class. Use this to create a new Model.
### destroy()
### destroy(): void
Free WebGL resources associated with this model
Free GPU resources associated with this model immediately, instead of waiting for garbage collection.
### isAnimated(): boolean
Returns `true` if the model is animated (i.e. needs to be redrawn every frame).
### getProgram(): Program
Get model's `Program` instance
### getUniforms(): object
Returns map of currently stored uniforms
### setUniforms(uniforms: object); this
### setUniforms(uniforms: object): void
Stores named uniforms {key, value}
### updateModuleSettings(moduleSettings: object); this
### updateModuleSettings(moduleSettings: object): void
### draw(options: object): boolean
### draw(options: DrawOptions): boolean
Renders the model with provided uniforms, attributes and samplers
```typescript
model.draw({
renderPass,
moduleSettings = null,
uniforms = {},
attributes = {},
samplers = {},
parameters = {},
settings,
framebuffer = null,
vertexArray = null,
transformFeedback = null
});
@ -212,18 +217,3 @@ The remaining draw options are passed directly to `Program.draw()`:
- `framebuffer`=`null` (`Framebuffer`) - if provided, renders into the supplied framebuffer, otherwise renders to the default framebuffer.
- `transformFeedback` - an instance `TranformFeedback` object, that gets activated for this rendering.
- `vertexArray` - an instance of `VertexArray` object, that holds required buffer bindings for vertex shader inputs.
### transform(options: object); this
Renders the model with provided uniforms, and samplers. Calls `Program.draw()` with rasterization turned off.
- `discard`=`true` (Boolean) - Turns off rasterization
- `feedbackBuffers`=`null` (Object) - Optional map of feedback buffers. A `TransformFeedback` object will be created, initialized with these buffers, and passed to `Model.draw`.
- `unbindModels`=`[]` (Model[]) - Array of models whose VertexAttributes will be temporarily unbound during the transform feeback to avoid triggering a possible [Khronos/Chrome bug](https://github.com/KhronosGroup/WebGL/issues/2346).
.
```typescript
model.transform({
discard: false
});
```

View File

@ -0,0 +1,26 @@
# CommandEncoder
> Proposed luma.gl v9 API. Open for comments.
A command encoder offering GPU memory copying operations.
## Types
### `CommandEncoderProps`
| Property | Type | Description |
| ------------- | -------------------------------- | ---------------------------------------------------------------------------- |
| N/A | | |
## Members
- `device`: `Device` - holds a reference to the `Device` that created this `CommandEncoder`.
- `handle`: `unknown` - holds the underlying WebGL or WebGPU shader object
- `props`: `CommandEncoderProps` - holds a copy of the `CommandEncoderProps` used to create this `CommandEncoder`.
## Methods
### `constructor(props: CommandEncoderProps)`
`CommandEncoder` is an abstract class and cannot be instantiated directly. Create with `device.beginCommandEncoder(...)`.

View File

@ -2,16 +2,17 @@
> Proposed luma.gl v9 API. Open for comments.
A configuration for compute.
> WebGPU only
A pass on which to run computations with compute pipelines.
## Types
### `BufferProps`
| Property | Type | Description |
| ------------- | -------------------------------- | ---------------------------------------------------------------------------- |
| `parameters?` | `Parameters` | GPU pipeline parameters |
### `ComputePassProps`
| Property | Type | Description |
| -------- | ---- | ----------- |
| N/A | | |
## Members

View File

@ -1,38 +1,51 @@
# Upgrade Guide
## Upgrading from v8.X to v9.0 (Forward-Looking Changes)
## Upgrading from v8.X to v9.0
luma.gl v9 needs major API changes to be able to incorporate WebGPU in a natural way.
WebGPU is a more performant API and it does not make sense to try to hide it under a legacy API.
luma.gl v9 introduces major API changes driven primarily by the addition of WebGPU support.
The motivations for the breaking changes are described separately.
Development of luma.gl v9.0 is still ongoing however a number of expected changes are already clear:
While the API changes are fairly extensive, they typically will not require the structure of applications to change.
An application should still be "instantly recognizable" as luma.gl application whether written towards the v8 or v9+ API.
- APIs will no longer accept `WebGLRenderingContext` directly. All APIs will require a `Device`.
- Parameters can no longer be set on the context.
- `clear` can no longer be called directly. Clear colors must be set on framebuffers.
- Uniform buffers are required, at least if WebGPU support is desired.
### Module-level changes
### Deprecations
v9.0 deprecates a range of APIs as part of preparations for WebGPU support in v9.0.
v8.7 deprecates a range of APIs as part of preparations for WebGPU support in v9.0.
- `@luma.gl/gltools` module is deprecated.
- The module still exists, but is now just re-exporting the functions which have been moved to `@luma.gl/webgl`.
- `@luma.gl/gltools` module is now deprecated.
- The module still exists, but is no longer dedicated to WebGL context functionality.
- now just re-exporting the functions which have been moved to `@luma.gl/webgl`.
- In v9.0 the `@luma.gl/gltools` module will be removed, and the context functions will be replaced by the new experimental `WebGLDevice` class.
- `@luma.gl/core` module is being trimmed.
- WebGL module re-exports are deprecated and should be imported directly from `@luma.gl/webgl`.
- `@luma.gl/core` module is "in transition":
- in v9, the core module still exports the deprecated v8 classes from `@luma.gl/gltools` (so that applications can gradually start moving to the v10 API).
- in v10, the core module will be completely updated and instead export the new v9+ API.
- WebGL class exports are deprecated and should be imported directly from `@luma.gl/gltools`.
- gltools module re-exports are deprecated and should be imported directly from `@luma.gl/webgl`.
- `@luma.gl/constants` module is no longer recommended.
- The luma.gl API is moving towards using WebGPU-style string constants instead of numeric enums, which works very well with the strict typescript typings. This means that WebGL-style numeric constants are being phased out of the luma.gl API.
Required changes:
- N/A
- `@luma.gl/constants` module remains but is no longer needed by applications:
- WebGL-style numeric constants (`GL.` constants) are no longer used in the public v9 API.
- Instead, the luma.gl v9 API uses string constants (strictly typed, of course).
Recommended changes:
- Change imports from `@luma.gl/gltools` to `@luma.gl/webgl`.
- Change imports from `@luma.gl/core` to `@luma.gl/webgl`.
- Gradually revise use of `@luma.gl/constants` and start adopting string constants.
### Feature-level changes
A long list of changes, some required to make the API portable between WebGPU and WebGL, and many to accommodate the limitations of the more locked-down WebGPU API.
- APIs no longer accept `WebGLRenderingContext` directly. APIs now require a `Device`.
- WebGL classes such as Buffer, Texture2D etc can no longer be imported and instantiated with `new Buffer(gl, props)`. Instead they must be created via a device `device.createBuffer(props)`.
- `Program` is now called `RenderPipeline`.
- Parameters can no longer be set on the WebGL context. They must be set on a `RenderPipeline`.
- `RenderPipeline` parameters cannot be changed after creation (though the `Model` class will create new `RenderPipeline` instances if parameters change).
- Some parameters are set on `RenderPass`.
- Constant attributes are no longer supported.
- `clear` can no longer be called directly. Instead attachments are cleared when a `RenderPass` is created and clear colors must be specified in `beginRenderPass`.
- Uniform buffers are required to run under WebGPU.
---
## Upgrading from v8.4 to v8.5
### Transpilation

View File

@ -4,48 +4,35 @@
Target Date: Q1, 2022
The v9.0 release adds WebGPU support and a refreshed luma.gl API.
The changes under the hood are quite extensive, and many APIs have been changed to align more closely with WebGPU conventions and concepts. However all legacy v8 APIs are still available,
so luma.gl v9 should remain reasonably compatible with luma.gl v8 applications, with some caveats.
Please consult the upgrade guide before upgrading your applications.
The v9.0 release brings WebGPU support and a modernized luma.gl API. Adoption of the new API will require applications to be updated.
While the luma.gl documentation has been overhauled to focus on the new API,
the legacy API documentation is still available.
The deprecation status of a class or API is noted at the top of each page.
All legacy v8 APIs are still available, so it should be possible to first migrate luma.gl v8 applications to luma.gl v9 without any modifications and then gradually start updating the application to the v9 API.
luma.gl v9 has also been updated with more rigorous typescript typings.
While the stronger types may trigger some new warnings during the upgrade process, the hope is that this will ultimately
save developers time and surprises by
automatically highlighting incorrect API usage during the upgrade process.
The luma.gl documentation focuses on the new v9 API, however legacy v8 API documentation is still included.
luma.gl v9 is now written in TypeScript from the ground up and is more rigorously typed.
#### `@luma.gl/api` (new module)
- The new cross-platform luma.gl API is exposed through the new `@luma.gl/api` module. Applications written against this API can run on both WebGPU and WebGL2 devices.
- The heart of the new cross-platform luma.gl API is the portable `Device` API that is exposed through the new `@luma.gl/api` module.
- Applications written against `@luma.gl/api` can run on both WebGPU, WebGL2 and WebGL devices.
#### `@luma.gl/engine`
#### `@luma.gl/engine` (breaking changes)
- The classes and APIs in the `@luma.gl/engine` module (`Model`, `AnimationLoop` etc) are now fully portable and work on both WebGPU and WebGL.
- The `@luma.gl/engine` module still exports th classic luma.gl classes such as `Model` and `AnimationLoop`.
- However all engine classes are now implemented on top of `@luma.gl/api`, allowing them to work portably on both WebGPU and WebGL.
- For backwards compatibility, the `WebGLRenderingContext`-dependent versions have been moved to `@luma.gl/gltools`
#### `@luma.gl/webgpu` (new module)
- Provides a WebGPU implementation of the luma.gl API (`@luma.gl/api`). Importing this module enables the application to create `Device`s of type `'webgpu'` (requires a browser that supports WebGPU).
- Provides a WebGPU implementation of the luma.gl API (`@luma.gl/api`).
- Importing this module enables the application to create `Device`s of type `'webgpu'` (when run in a browser that supports WebGPU API).
#### `@luma.gl/webgl`
#### `@luma.gl/webgl` (breaking changes)
- Provides a WebGL / WebGL 2 implementation of the luma.gl API (`@luma.gl/api`). Importing this module enables the application to create `Device`s of type `'webgpu'`.
- The webgl module has been deeply refactored and reorganized to make it smaller and more maintainable.
#### `@luma.gl/core`
- The core module still re-exports the classic luma.gl v8 API (from `@luma.gl/gltools`), to avoid breaking existing applications.
- Applications that want to start using the v9 API should import directly from `@luma.gl/engine` and `@luma.gl/api`.
#### `@luma.gl/gltools` (deprecated)
- The `@luma.gl/gltools` module is now deprecated. It now exports all legacy WebGL APIs and is no longer dedicate to just WebGL context-related utilities.
- The "classic" WebGL classes from luma.gl v8 can now be imported directly from this module.
- The old WebGL dependent `@luma.gl/engine` classes can still be imported from this module.
- The WebGL context related APIs exported by this module in v8 are now simple wrappers for the `WebGLDevice` class.
- Provides a WebGL / WebGL 2 implementation of the luma.gl API (`@luma.gl/api`).
- Importing this module enables the application to create `Device`s of type `'webgl2'` or `'webgl'`.
- The legacy v8 WebGL classes have been moved to `@luma.gl/gltools`
#### `@luma.gl/shadertools`
@ -55,7 +42,19 @@ automatically highlighting incorrect API usage during the upgrade process.
- `makeDebugContext()` from `@luma.gl/debug` is deprecated. Khronos WebGL developer tools no longer need to be bundled, they are now dynamically loaded when WebGL devices are created with `luma.createDevice({debug: true, type: 'webgl'})`.
- Debugging:the [Khronos WebGL developer tools](https://github.com/KhronosGroup/WebGLDeveloperTools) no longer need to be bundled. They are now automatically loaded from CDN when WebGL devices are created with `luma.createDevice({debug: true, type: 'webgl'})`
- Debugging: [Spector.js](https://spector.babylonjs.com/) is pre-integrated. If a `WebGLDevice` is created with `spector: true`, the Spector.js library will be dynamically loaded from CDN, the device canvas will be "captured", and luma.gl API metadata will exposed to the Spector UI.
- Debugging: [Spector.js](https://spector.babylonjs.com/) is pre-integrated. If a `WebGLDevice` is created with `spector: true`, the Spector.js library will be dynamically loaded from CDN, the device canvas will be "captured". Also information about luma.gl objects associated with WebGL handles will be displayed in the Spector UI.
#### `@luma.gl/core` ("deprecated")
- The core module still re-exports the classic luma.gl v8 API (from `@luma.gl/gltools`), to avoid breaking existing applications.
- Applications that want to start using the v9 API should import directly from `@luma.gl/engine` and `@luma.gl/api`.
#### `@luma.gl/gltools` (deprecated)
- The `@luma.gl/gltools` module is now deprecated. It now exports all legacy WebGL APIs and is no longer dedicate to just WebGL context-related utilities.
- The legacy v8 WebGL classes from luma.gl v8 can now be imported directly from this module.
- The legacy v8 WebGL-dependent `@luma.gl/engine` classes can still be imported from this module.
- The WebGL context related APIs exported by this module in v8 are now simple wrappers for the `WebGLDevice` class.
## Version 8.5

View File

@ -1,188 +0,0 @@
# Legacy Parameters (TODO delete)
| WebGL Function | WebGL Parameters | luma.gl v9 counterpart |
| -------- | -------------- |
| [`clearStencil`](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/clearStencil) | `GL.STENCIL_CLEAR_VALUE` | |
| [`stencilMask`](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/stencilMask) | [`GL.STENCIL_WRITEMASK`] | `stencilWriteMask` |
| [`stencilFunc`](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/stencilFunc) | [`GL.STENCIL_FUNC`, `GL.STENCIL_REF`, `GL.STENCIL_VALUE_MASK`] | `stencilCompare`, `stencilReadMask` |
| [`stencilOp`](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/stencilOp) | `GL.STENCIL_FAIL`, `GL.STENCIL_PASS_DEPTH_FAIL`, `GL.STENCIL_PASS_DEPTH_PASS` | `stencilPassOperation`, `stencilFailDepth
| [`stencilOpSeparate`](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/stencilOpSeparate) | [`GL.STENCIL_FAIL`, `GL.STENCIL_FAIL_DEPTH_FAIL`, `GL.STENCIL_FAIL_DEPTH_PASS`, `GL.STENCIL_BACK_FAIL`, `GL.STENCIL_BACK_FAIL_DEPTH_FAIL`, `GL.STENCIL_BACK_FAIL_DEPTH_PASS`]| N/A |
- In WebGL, setting any value will enable stencil testing (i.e. enable `GL.STENCIL_TEST`).
| Parameter | Type | Default | Description |
| --------------------------------- | --------- | ------------ | ----------------------- |
| `GL.STENCIL_TEST` | GLboolean | `false` | Enables stencil testing |
| `GL.STENCIL_CLEAR_VALUE` | GLint | `0` | Sets index used when stencil buffer is cleared. |
| `GL.STENCIL_WRITEMASK` | GLuint | `0xFFFFFFFF` | Sets bit mask enabling writing of individual bits in the stencil planes |
| `GL.STENCIL_BACK_WRITEMASK` | GLuint | `0xFFFFFFFF` | Sets bit mask enabling writing of individual bits in the stencil planes |
| `GL.STENCIL_FUNC` | GLenum | `GL.ALWAYS` | |
| `GL.STENCIL_REF` | GLint | `0` | |
| `GL.STENCIL_VALUE_MASK` | GLuint | `0xFFFFFFFF` | Sets bit mask |
| `GL.STENCIL_BACK_FUNC` | GLenum | `GL.ALWAYS` | |
| `GL.STENCIL_BACK_REF` | GLint | `0` | |
| `GL.STENCIL_BACK_VALUE_MASK` | GLuint | `0xFFFFFFFF` | Sets bit mask enabling writing of individual bits in the stencil planes |
| `GL.STENCIL_FAIL` | GLenum | `GL.KEEP` | stencil test fail action |
| `GL.STENCIL_PASS_DEPTH_FAIL` | GLenum | `GL.KEEP` | depth test fail action |
| `GL.STENCIL_PASS_DEPTH_PASS` | GLenum | `GL.KEEP` | depth test pass action |
| `GL.STENCIL_BACK_FAIL` | GLenum | `GL.KEEP` | stencil test fail action, back |
| `GL.STENCIL_BACK_PASS_DEPTH_FAIL` | GLenum | `GL.KEEP` | depth test fail action, back |
| `GL.STENCIL_BACK_PASS_DEPTH_PASS` | GLenum | `GL.KEEP` | depth test pass action, back |
## Depth Test Parameters
After stencil tests, depth tests and writes are done, controlled by the following parameters:
| Function | Description | Values | WebGL counterpart |
| --------- | ---------------------------------- | --- | --- |
| `depthWriteEnabled` | Whether depth buffer is updated | `boolean` **`true`** | `gl.depthMask` |
| `depthCompare` | If and how depth testing is done | **`always`**, `less-equal`, ... | `gl.depthFunc` |
### Blending
| Function style | Sets parameter(s) |
| --------------------- | ---------------------- |
| [blendColor](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/blendColor) | `GL.BLEND_COLOR` |
| [blendEquation](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/blendEquation) | [`GL.BLEND_EQUATION_RGB`, `GL.BLEND_EQUATION_ALPHA`] |
| [blendFunc](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/blendFunc) | [`GL.BLEND_SRC_RGB`, `GL.BLEND_SRC_ALPHA`] |
| [blendFuncSeparate](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/blendFuncSeparate) | [`GL.BLEND_SRC_RGB`, `GL.BLEND_SRC_ALPHA`, `GL.BLEND_DST_RGB`, `GL.BLEND_DST_ALPHA`] |
| Parameter | Type | Default | Description |
| ------------------------- | --------------- | --------------- | -------- |
| `GL.BLEND` | GLboolean | `false` | Blending enabled |
| `GL.BLEND_COLOR` | Float32Array(4) | `[0, 0, 0, 0]` | |
| `GL.BLEND_EQUATION_RGB` | GLenum | `GL.FUNC_ADD` | |
| `GL.BLEND_EQUATION_ALPHA` | GLenum | `GL.FUNC_ADD` | |
| `GL.BLEND_SRC_RGB` | GLenum | `GL.ONE` | srcRgb |
| `GL.BLEND_SRC_ALPHA` | GLenum | `GL.ZERO` | srcAlpha |
| `GL.BLEND_DST_RGB` | GLenum | `GL.ONE` | dstRgb |
| `GL.BLEND_DST_ALPHA` | GLenum | `GL.ZERO` | dstAlpha |
### Clear Color
| Function | Sets parameters |
| --------- | ---------------------------------- |
| [clearColor](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/clearColor) | GL.COLOR_CLEAR_VALUE |
| Parameter | Type | Default | Description |
| ---------------------- | --------------- | -------- | -------- |
| `GL.COLOR_CLEAR_VALUE` | new Float32Array(4) | [0, 0, 0, 0] | . |
### Color Mask
| Function | Sets parameters |
| --------- | ---------------------------------- |
| [colorMask](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/colorMask) | GL.COLOR_WRITEMASK |
| Parameter | Type | Default | Description |
| ---------------------- | --------------- | -------- | -------- |
| `GL.COLOR_WRITEMASK` | [GLboolean, GLboolean, GLboolean, GLboolean] | [true, true, true, true] | . |
### Dithering
| Parameter | Type | Default | Description |
| ---------------------- | --------------- | -------- | -------- |
| `GL.DITHER` | GLboolean | `true` | Enable dithering of color components before they get written to the color buffer |
* Note: Dithering is driver dependent and typically has a stronger effect when the color components have a lower number of bits.
### PolygonOffset
Add small offset to fragment depth values (by factor × DZ + r × units)
Useful for rendering hidden-line images, for applying decals to surfaces,
and for rendering solids with highlighted edges.
| Function | Sets parameters |
| --------- | ---------------------------------- |
| [polygonOffset](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/polygonOffset) | [GL.POLYGON_OFFSET_FACTOR, GL.POLYGON_OFFSET_UNITS] |
| Parameter | Type | Default | Description |
| -------------------------- | ------------- | -------- | ----------------------- |
| `GL.POLYGON_OFFSET_FILL` | GLboolean | `false` | . |
| `GL.POLYGON_OFFSET_FACTOR` | GLfloat | `0` | . |
| `GL.POLYGON_OFFSET_UNITS` | GLfloat | `0` | . |
* Note: The semantics of polygon offsets are loosely specified by the WebGL standard and results can thus be driver dependent.
### Rasterization (WebGL 2)
Primitives are discarded immediately before the rasterization stage, but after the optional transform feedback stage. `gl.clear()` commands are ignored.
| Parameter | Type | Default | Description |
| ----------------------------------- | ------------- | -------- | ----------------------- |
| `GL.RASTERIZER_DISCARD` | GLboolean | `false` | Disable rasterization |
### Sampling
Specify multisample coverage parameters
| Function | Sets parameters |
| --------- | ---------------------------------- |
| [sampleCoverage](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/sampleCoverage) | [`GL.SAMPLE_COVERAGE_VALUE`, `GL.SAMPLE_COVERAGE_INVERT`] |
| Parameter | Type | Default | Description |
| ---------------------------------- | ------------- | -------- | ----------------------- |
| `GL_SAMPLE_COVERAGE` | GLboolean | `false` | Activates the computation of a temporary coverage value determined by the alpha value. |
| `GL_SAMPLE_ALPHA_TO_COVERAGE` | GLboolean | `false` | Activates ANDing the fragment's coverage with the temporary coverage value |
| `GL.SAMPLE_COVERAGE_VALUE` | GLfloat | 1.0 | |
| `GL.SAMPLE_COVERAGE_INVERT` | GLboolean | `false` | |
### Scissor Test
Settings for scissor test and scissor box.
| Function | Sets parameters |
| --------- | ---------------------------------- |
| [scissor](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/scissor) | `GL.SCISSOR_BOX` |
| scissorTest | GL.SCISSOR_TEST |
| Parameter | Type | Default | Description |
| ---------------------------------- | ------------- | -------- | ----------------------- |
| `GL.SCISSOR_TEST` | GLboolean | `false` |
| `GL.SCISSOR_BOX` | Int32Array(4) | [null, null, null, null]), // TBD |
## Viewport
Specifies the transformation from normalized device coordinates to
window/framebuffer coordinates. The maximum supported value, is defined by the
`GL.MAX_VIEWPORT_DIMS` limit.
| Function | Parameters |
| ------------ | -------------- |
| [viewport](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/viewport) | `GL.VIEWPORT` |
| Parameter | Type | Default | Description |
| ---------------------------------- | ------------- | --------- | ----------------------- |
| `GL.VIEWPORT` | Int32Array(4) | [...] TBD | Viewport |
Example:
```js
// Set viewport to maximum supported size
const maxViewport = getLimits(gl)[GL.MAX_VIEWPORT_DIMS];
setState(gl, {
viewport: [0, 0, maxViewport[0], maxViewport[1]]
});
```
## Remarks
GPU State Management can be quite complicated.
* A large part of the WebGL API is devoted to parameters. When reading, querying individual values using GL constants is the norm, and when writing, special purpose functions are provided for most parameters. luma.gl supports both forms for both reading and writing parameters.
* Reading values from WebGL can be very slow if it requires a GPU roundtrip. To get around this, luma.gl reads values once, caches them and tracks them as they are changed through luma functions. The cached values can get out of sync if the context is shared outside of luma.gl.
* luma.gl's state management enables "conflict-free" programming, so that even when setting global state, one part of the code does not need to worry about whether other parts are changing the global state.
* Note that to fully support the conflict-free model and detect changes done e.g. in other WebGL libraries, luma.gl needs to hook into the WebGL context to track state changes.

View File

@ -1,245 +0,0 @@
## v8 to v9 API Mapping
- Parameters are set on `Pipeline`/`Program` creation. They can not be modified, or passed in draw calls.
- Parameters can only be set, not queried. luma.gl longer provides a way to query parameters.
| WebGL Function | luma.gl parameter counterparts |
| --------- | ---------------------------------- |
| [polygonOffset](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/polygonOffset) | `depthBias`, `depthBiasSlopeScale` |
| [depthRange](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/depthRange) | N/A |
| [clearDepth](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/clearDepth) | |
## Depth testing
To set up depth testing
```js
const value = model.setParameters({
depthWriteEnabled: true,
depthCompare: 'less-equal'
});
```
## Parameters
Describes luma.gl setting names and values
### Rasterization Parameters
These parameters control the rasterization stage (which happens before fragment shader runs).
| Function | Description | Values | WebGL counterpart |
| --------- | ---------------------------------- | --- | --- |
| `cullMode` | Which face to cull | **`'none'`**, `'front'`, `'back'` | [`gl.cullFace`](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/cullFace) |
| `frontFace` | Which triangle winding order is front | **`ccw`**, `cw` | [`gl.frontFace`](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/frontFace) |
| `depthBias` | Small depth offset for polygons | `float` | `gl.polygonOffset` |
| `depthBiasSlopeScale` | Small depth factor for polygons | `float` | `gl.polygonOffset` |
| `depthBiasClamp` | Max depth offset for polygons | `float` |
- **Depth Bias** - Sometimes referred to as "polygon offset". Adds small offset to fragment depth values (by factor × DZ + r × units). Usually used as a heuristic to avoid z-fighting, but can also be used for effects like applying decals to surfaces, and for rendering solids with highlighted edges. The semantics of polygon offsets are loosely specified by the WebGL standard and results can thus be driver dependent.
## Stencil Parameters
After the fragment shader runs, optional stencil tests are performed, with resulting operations on the the stencil buffer.
| Function | Description | Values |
| --------- | ---------------------------------- | --- |
| `stencilReadMask` | Binary mask for reading stencil values | `number` (**`0xffffffff`**) |
| `stencilWriteMask` | Binary mask for writing stencil values | `number` (**`0xffffffff`**) | `gl.frontFace` |
| `stencilCompare` | How the mask is compared | **`always`**, `not-equal`, ... | `gl.stencilFunc` |
| `stencilPassOperation` | | **`'keep'`** | `gl.stencilOp` |
| `stencilDepthFailOperation` | | **`'keep'`** | `gl.stencilOp` |
| `stencilFailOperation` | | **`'keep'`** | `gl.stencilOp` |
Action when the stencil test fails
* stencil test fail action,
* depth test fail action,
* pass action
Remarks:
- By using binary masks, an 8 bit stencil buffer can effectively contain 8 separate masks or stencils
- The luma.gl API currently does not support setting stencil operations separately for front and back faces.
| WebGL Function | WebGL Parameters | luma.gl v9 counterpart |
| -------- | -------------- |
| [`clearStencil`](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/clearStencil) | `GL.STENCIL_CLEAR_VALUE` | |
| [`stencilMask`](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/stencilMask) | [`GL.STENCIL_WRITEMASK`] | `stencilWriteMask` |
| [`stencilFunc`](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/stencilFunc) | [`GL.STENCIL_FUNC`, `GL.STENCIL_REF`, `GL.STENCIL_VALUE_MASK`] | `stencilCompare`, `stencilReadMask` |
| [`stencilOp`](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/stencilOp) | `GL.STENCIL_FAIL`, `GL.STENCIL_PASS_DEPTH_FAIL`, `GL.STENCIL_PASS_DEPTH_PASS` | `stencilPassOperation`, `stencilFailDepth
| [`stencilOpSeparate`](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/stencilOpSeparate) | [`GL.STENCIL_FAIL`, `GL.STENCIL_FAIL_DEPTH_FAIL`, `GL.STENCIL_FAIL_DEPTH_PASS`, `GL.STENCIL_BACK_FAIL`, `GL.STENCIL_BACK_FAIL_DEPTH_FAIL`, `GL.STENCIL_BACK_FAIL_DEPTH_PASS`]| N/A |
- In WebGL, setting any value will enable stencil testing (i.e. enable `GL.STENCIL_TEST`).
| Parameter | Type | Default | Description |
| --------------------------------- | --------- | ------------ | ----------------------- |
| `GL.STENCIL_TEST` | GLboolean | `false` | Enables stencil testing |
| `GL.STENCIL_CLEAR_VALUE` | GLint | `0` | Sets index used when stencil buffer is cleared. |
| `GL.STENCIL_WRITEMASK` | GLuint | `0xFFFFFFFF` | Sets bit mask enabling writing of individual bits in the stencil planes |
| `GL.STENCIL_BACK_WRITEMASK` | GLuint | `0xFFFFFFFF` | Sets bit mask enabling writing of individual bits in the stencil planes |
| `GL.STENCIL_FUNC` | GLenum | `GL.ALWAYS` | |
| `GL.STENCIL_REF` | GLint | `0` | |
| `GL.STENCIL_VALUE_MASK` | GLuint | `0xFFFFFFFF` | Sets bit mask |
| `GL.STENCIL_BACK_FUNC` | GLenum | `GL.ALWAYS` | |
| `GL.STENCIL_BACK_REF` | GLint | `0` | |
| `GL.STENCIL_BACK_VALUE_MASK` | GLuint | `0xFFFFFFFF` | Sets bit mask enabling writing of individual bits in the stencil planes |
| `GL.STENCIL_FAIL` | GLenum | `GL.KEEP` | stencil test fail action |
| `GL.STENCIL_PASS_DEPTH_FAIL` | GLenum | `GL.KEEP` | depth test fail action |
| `GL.STENCIL_PASS_DEPTH_PASS` | GLenum | `GL.KEEP` | depth test pass action |
| `GL.STENCIL_BACK_FAIL` | GLenum | `GL.KEEP` | stencil test fail action, back |
| `GL.STENCIL_BACK_PASS_DEPTH_FAIL` | GLenum | `GL.KEEP` | depth test fail action, back |
| `GL.STENCIL_BACK_PASS_DEPTH_PASS` | GLenum | `GL.KEEP` | depth test pass action, back |
### Blending
| Function style | Sets parameter(s) |
| --------------------- | ---------------------- |
| [blendColor](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/blendColor) | `GL.BLEND_COLOR` |
| [blendEquation](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/blendEquation) | [`GL.BLEND_EQUATION_RGB`, `GL.BLEND_EQUATION_ALPHA`] |
| [blendFunc](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/blendFunc) | [`GL.BLEND_SRC_RGB`, `GL.BLEND_SRC_ALPHA`] |
| [blendFuncSeparate](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/blendFuncSeparate) | [`GL.BLEND_SRC_RGB`, `GL.BLEND_SRC_ALPHA`, `GL.BLEND_DST_RGB`, `GL.BLEND_DST_ALPHA`] |
| Parameter | Type | Default | Description |
| ------------------------- | --------------- | --------------- | -------- |
| `GL.BLEND` | GLboolean | `false` | Blending enabled |
| `GL.BLEND_COLOR` | Float32Array(4) | `[0, 0, 0, 0]` | |
| `GL.BLEND_EQUATION_RGB` | GLenum | `GL.FUNC_ADD` | |
| `GL.BLEND_EQUATION_ALPHA` | GLenum | `GL.FUNC_ADD` | |
| `GL.BLEND_SRC_RGB` | GLenum | `GL.ONE` | srcRgb |
| `GL.BLEND_SRC_ALPHA` | GLenum | `GL.ZERO` | srcAlpha |
| `GL.BLEND_DST_RGB` | GLenum | `GL.ONE` | dstRgb |
| `GL.BLEND_DST_ALPHA` | GLenum | `GL.ZERO` | dstAlpha |
### Clear Color
| Function | Sets parameters |
| --------- | ---------------------------------- |
| [clearColor](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/clearColor) | GL.COLOR_CLEAR_VALUE |
| Parameter | Type | Default | Description |
| ---------------------- | --------------- | -------- | -------- |
| `GL.COLOR_CLEAR_VALUE` | new Float32Array(4) | [0, 0, 0, 0] | . |
### Color Mask
| Function | Sets parameters |
| --------- | ---------------------------------- |
| [colorMask](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/colorMask) | GL.COLOR_WRITEMASK |
| Parameter | Type | Default | Description |
| ---------------------- | --------------- | -------- | -------- |
| `GL.COLOR_WRITEMASK` | [GLboolean, GLboolean, GLboolean, GLboolean] | [true, true, true, true] | . |
### Dithering
| Parameter | Type | Default | Description |
| ---------------------- | --------------- | -------- | -------- |
| `GL.DITHER` | GLboolean | `true` | Enable dithering of color components before they get written to the color buffer |
* Note: Dithering is driver dependent and typically has a stronger effect when the color components have a lower number of bits.
### PolygonOffset
Add small offset to fragment depth values (by factor × DZ + r × units)
Useful for rendering hidden-line images, for applying decals to surfaces,
and for rendering solids with highlighted edges.
| Function | Sets parameters |
| --------- | ---------------------------------- |
| [polygonOffset](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/polygonOffset) | [GL.POLYGON_OFFSET_FACTOR, GL.POLYGON_OFFSET_UNITS] |
| Parameter | Type | Default | Description |
| -------------------------- | ------------- | -------- | ----------------------- |
| `GL.POLYGON_OFFSET_FILL` | GLboolean | `false` | . |
| `GL.POLYGON_OFFSET_FACTOR` | GLfloat | `0` | . |
| `GL.POLYGON_OFFSET_UNITS` | GLfloat | `0` | . |
* Note: The semantics of polygon offsets are loosely specified by the WebGL standard and results can thus be driver dependent.
### Rasterization (WebGL 2)
Primitives are discarded immediately before the rasterization stage, but after the optional transform feedback stage. `gl.clear()` commands are ignored.
| Parameter | Type | Default | Description |
| ----------------------------------- | ------------- | -------- | ----------------------- |
| `GL.RASTERIZER_DISCARD` | GLboolean | `false` | Disable rasterization |
### Sampling
Specify multisample coverage parameters
| Function | Sets parameters |
| --------- | ---------------------------------- |
| [sampleCoverage](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/sampleCoverage) | [`GL.SAMPLE_COVERAGE_VALUE`, `GL.SAMPLE_COVERAGE_INVERT`] |
| Parameter | Type | Default | Description |
| ---------------------------------- | ------------- | -------- | ----------------------- |
| `GL_SAMPLE_COVERAGE` | GLboolean | `false` | Activates the computation of a temporary coverage value determined by the alpha value. |
| `GL_SAMPLE_ALPHA_TO_COVERAGE` | GLboolean | `false` | Activates ANDing the fragment's coverage with the temporary coverage value |
| `GL.SAMPLE_COVERAGE_VALUE` | GLfloat | 1.0 | |
| `GL.SAMPLE_COVERAGE_INVERT` | GLboolean | `false` | |
### Scissor Test
Settings for scissor test and scissor box.
| Function | Sets parameters |
| --------- | ---------------------------------- |
| [scissor](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/scissor) | `GL.SCISSOR_BOX` |
| scissorTest | GL.SCISSOR_TEST |
| Parameter | Type | Default | Description |
| ---------------------------------- | ------------- | -------- | ----------------------- |
| `GL.SCISSOR_TEST` | GLboolean | `false` |
| `GL.SCISSOR_BOX` | Int32Array(4) | [null, null, null, null]), // TBD |
## Viewport
Specifies the transformation from normalized device coordinates to
window/framebuffer coordinates. The maximum supported value, is defined by the
`GL.MAX_VIEWPORT_DIMS` limit.
| Function | Parameters |
| ------------ | -------------- |
| [viewport](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/viewport) | `GL.VIEWPORT` |
| Parameter | Type | Default | Description |
| ---------------------------------- | ------------- | --------- | ----------------------- |
| `GL.VIEWPORT` | Int32Array(4) | [...] TBD | Viewport |
Example:
```js
// Set viewport to maximum supported size
const maxViewport = getLimits(gl)[GL.MAX_VIEWPORT_DIMS];
setState(gl, {
viewport: [0, 0, maxViewport[0], maxViewport[1]]
});
```
## Remarks
GPU State Management can be quite complicated.
* A large part of the WebGL API is devoted to parameters. When reading, querying individual values using GL constants is the norm, and when writing, special purpose functions are provided for most parameters. luma.gl supports both forms for both reading and writing parameters.
* Reading values from WebGL can be very slow if it requires a GPU roundtrip. To get around this, luma.gl reads values once, caches them and tracks them as they are changed through luma functions. The cached values can get out of sync if the context is shared outside of luma.gl.
* luma.gl's state management enables "conflict-free" programming, so that even when setting global state, one part of the code does not need to worry about whether other parts are changing the global state.
* Note that to fully support the conflict-free model and detect changes done e.g. in other WebGL libraries, luma.gl needs to hook into the WebGL context to track state changes.