Skip to content

Commit

Permalink
feat(core): Break out Adapter class from Device
Browse files Browse the repository at this point in the history
  • Loading branch information
ibgreen committed Apr 28, 2024
1 parent 9163836 commit 8310f9a
Show file tree
Hide file tree
Showing 38 changed files with 442 additions and 374 deletions.
36 changes: 8 additions & 28 deletions docs/api-guide/gpu/gpu-initialization.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# GPU Initialization

## Adapter

An `Adapter` is a factory for `Device` instances for a specific backend (e.g. WebGPU or WebGL).

## Device

The [`Device`](/docs/api-reference/core/device) class provides luma.gl applications with access to the GPU.
Expand All @@ -22,31 +26,7 @@ A `CanvasContext` takes care of:
- canvas resizing
- device pixel ratio calculations

## Usage

Create a `Device` using the best available registered backend,
specifying an existing canvas to initialize the default `CanvasContext`.

```typescript
import {luma} from '@luma.gl/core';
import {WebGLDevice} from '@luma.gl/webgl';
import {WebGPUDevice} from '@luma.gl/webgpu';

luma.registerDevices([WebGLDevice]);
const device = luma.createDevice({canvas: ...});
```

Create a WebGL 2 device, auto creating a canvas.

```typescript
import {luma} from '@luma.gl/core';
import {WebGLDevice} from '@luma.gl/webgl';

luma.registerDevices([WebGLDevice]);
const webglDevice = luma.createDevice({type: 'webgl'});
```

## Registering Device Backends
## Registering Backend Adapters

The `@luma.gl/core` module defines abstract API interfaces such as `Device`, `Buffer` etc and is not usable on its own.

Expand All @@ -62,9 +42,9 @@ yarn add @luma.gl/webgpu

```typescript
import {luma} from '@luma.gl/core';
import {WebGPUDevice} from '@luma.gl/webgpu';
import {webgpuAdapter} from '@luma.gl/webgpu';

luma.registerDevices([WebGPUDevice]);
luma.registerAdapters([webgpuAdapter]);
const device = await luma.createDevice({type: 'webgpu', canvas: ...});
```

Expand All @@ -83,7 +63,7 @@ import {luma} from '@luma.gl/core';
import {WebGLDevice} from '@luma.gl/webgl';
import {WebGPUDevice} from '@luma.gl/webgpu';

luma.registerDevices([WebGLDevice, WebGPUDevice]);
luma.registerAdapters([WebGLDevice, WebGPUDevice]);

const webgpuDevice = luma.createDevice({type: 'best-available', canvas: ...});
```
6 changes: 6 additions & 0 deletions docs/api-reference/core/adapter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Adapter

An `Adapter` is a factory for `Device` instances for a specific backend (e.g. WebGPU or WebGL).

Adapters are normally not used directly, they are imported and passed to
methods like [`luma.createDevice`].
96 changes: 43 additions & 53 deletions docs/api-reference/core/luma.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
# luma


The [`luma`](/docs/api-reference/core/luma) namespace provides luma.gl applications
with the ability to register GPU Device backends and create `Device` class instances
using the registered backends.
with the ability to create `Device` class instances against GPU `Adapters` that bring
support for different GPU backends such as WebGPU and WebGL.

The returned [`Device`](/docs/api-reference/core/device) instances provides
The returned [`Device`](/docs/api-reference/core/device) instances provide
luma.gl applications with a complete GPU API.

## Device Registration
Expand All @@ -17,47 +16,48 @@ GPU API backend module (`@luma.gl/webgl` and/or `@luma.gl/webgpu`) and then regi

## Usage

To register a device backend, import the corresponding device backend module and then call `luma.registerDevices()`
Create a WebGL 2 context (throws if WebGL2 not supported)

```typescript
import {luma} from '@luma.gl/core';
import {WebGLDevice} from '@luma.gl/webgl';
luma.registerDevices([WebGLDevice]);
```
import {webgl2Adapter} from '@luma.gl/webgl';

It is possible to register more than one device to create an application
that can work in both WebGL and WebGPU environments.
const webgpuDevice = luma.createDevice({type: 'webgl', adapters: [webgl2Adapter], canvas: ...});
```

```typescript
import {luma} from '@luma.gl/core';
import {WebGLDevice} from '@luma.gl/webgl';
import {WebGPUDevice} from '@luma.gl/webgl';
luma.registerDevices([WebGLDevice, WebGPUDevice]);
const webgpuDevice = luma.createDevice({
type: 'best-available',
canvas: ...,
adapters: [webgl2Adapter, WebGPUDevice]
});
```

To pre-register a device backend, import the corresponding device backend module and then call `luma.registerAdapters()`

Register the WebGL backend, then create a WebGL2 context, auto creating a canvas

```typescript
import {luma} from '@luma.gl/core';
import {WebGLDevice} from '@luma.gl/webgl';

luma.registerDevices([WebGLDevice]);
import {webgl2Adapter} from '@luma.gl/webgl';
luma.registerAdapters([webgl2Adapter]);
const webglDevice = luma.createDevice({type: 'webgl', canvas: ...});
```

Create a WebGL 2 context (throws if WebGL2 not supported)
It is possible to register more than one device to create an application
that can work in both WebGL and WebGPU environments.

```typescript
import {luma} from '@luma.gl/core';
import {WebGLDevice} from '@luma.gl/webgl';

luma.registerDevices([WebGLDevice]);
const webgpuDevice = luma.createDevice({type: 'webgl', canvas: ...});
import {webgl2Adapter} from '@luma.gl/webgl';
import {webgpuDevice} from '@luma.gl/webgl';
luma.registerAdapters([webgl2Adapter, webgpuDevice]);
const device = luma.createDevice({type: 'best-available', canvas: ...});
```

## Registering Device Backends
## Registering Adapters

Install device modules
Install device modules and register adapters to access backends

```sh
yarn add @luma.gl/core
Expand All @@ -69,33 +69,23 @@ To create a WebGPU device:

```typescript
import {luma} from '@luma.gl/core';
import {WebGPUDevice} from '@luma.gl/webgpu';
import {webgpuAdapter} from '@luma.gl/webgpu';

luma.registerDevices([WebGPUDevice]);
luma.registerAdapters([webgpuAdapter]);
const device = await luma.createDevice({type: 'webgpu', canvas: ...});
```

Pre-register devices

```typescript
import {luma} from '@luma.gl/core';
import {WebGLDevice} from '@luma.gl/webgl';
import {WebGPUDevice} from '@luma.gl/webgpu';
import {webgl2Adapter} from '@luma.gl/webgl';
import {webgpuAdapter} from '@luma.gl/webgpu';

luma.registerDevices([WebGLDevice, WebGPUDevice]);
luma.registerAdapters([webgl2Adapter, webgpuAdapter]);
const webgpuDevice = luma.createDevice({type: 'best-available', canvas: ...});
```

Provide devices to createDevice

```typescript
const webgpuDevice = luma.createDevice({
type: 'best-available',
canvas: ...,
devices: [WebGLDevice, WebGPUDevice]
});
```

## Types

### `CreateDeviceProps`
Expand All @@ -107,7 +97,7 @@ type CreateDeviceProps = DeviceProps & {
/** Selects the type of device. `best-available` uses webgpu if available, then webgl. */
type?: 'webgl' | 'webgpu' | 'unknown' | 'best-available';
/** List of device types. Will also search any pre-registered device backends */
devices?: DeviceFactory[];
adapters?: Adapter[];
}
```
Expand All @@ -120,7 +110,7 @@ export type AttachDeviceProps = DeviceProps & {
/** Externally created WebGL context or WebGPU device */
handle: WebGL2RenderingContext | GPUDevice | null;
/** List of device types. Will also search any pre-registered device backends */
devices?: DeviceFactory[];
adapters?: Adapter[];
};
```

Expand All @@ -129,16 +119,16 @@ export type AttachDeviceProps = DeviceProps & {
### `luma.createDevice()`

```typescript
luma.createDevice({type, devices, ...deviceProps}: CreateDeviceProps);
luma.createDevice({type, adapters, ...deviceProps}: CreateDeviceProps);
```

To create a Device instance, the application calls `luma.createDevice()`.

- `type`: `'webgl' \| 'webgpu' \| 'best-available'`
- `devices`: list of `Device` backend classes. Can be omitted if `luma.registerDevices()` has been called.
- `adapters`: list of `Device` backend classes. Can be omitted if `luma.registerAdapters()` has been called.

Unless a device `type` is specified a `Device` will be created using the `'best-available'` adapter.
luma.gl favors WebGPU over WebGL devices, whenever WebGPU is available.
luma.gl favors WebGPU over WebGL adapters, whenever WebGPU is available.

Note: A device type is available if:
1. The backend module has been registered
Expand All @@ -147,29 +137,29 @@ Note: A device type is available if:
### `luma.attachDevice()`

```ts
luma.attachDevice({handle: WebGL2RenderingContext | GPUDevice, devices, ...}: AttachDeviceProps);
luma.attachDevice({handle: WebGL2RenderingContext | GPUDevice, adapters, ...}: AttachDeviceProps);
```

A luma.gl Device can be attached to an externally created `WebGL2RenderingContext` or `GPUDevice`.
This allows applications to use the luma.gl API to "interleave" rendering with other GPU libraries.

- `handle` - The externally created `WebGL2RenderingContext` or `GPUDevice` that should be attached to a luma `Device`.
- `devices` - list of `Device` backend classes. Can be omitted if `luma.registerDevices()` has been called.
- `adapters` - list of `Device` backend classes. Can be omitted if `luma.registerAdapters()` has been called.

Note that while you cannot directly attach a luma.gl `Device` to a WebGL 1 `WebGLRenderingContext`, you may be able to work around it using `luma.enforceWebGL2()`.

### `luma.registerDevices()`
### `luma.registerAdapters()`

```typescript
luma.registerDevices(devices?: (typeof Device)[]): void;
luma.registerAdapters(adapters?: (typeof Device)[]): void;
```

Registers one or more devices (device constructors) so that they can be used
to create `Device` instances against that GPU backend. The registered device types
Pre-registers one or more adapters so that they can be used
to create `Device` instances against those GPU backends. The registered adapters types
will be available to `luma.createDevice()` and `luma.attachDevice()` calls.

`luma.registerDevices()` enables separation of the application code that
registers GPU backends from the application code that creates devices,
`luma.registerAdapters()` enables separation of the application code that
registers GPU backends from the application code that creates adapters,
so that device types do not have to be provided at `Device` create or attach time.

### `luma.enforceWebGL2()`
Expand All @@ -191,4 +181,4 @@ Since WebGL2 is a essentially a superset of WebGL1, a library written for WebGL

## Remarks

- At least one backend must be imported and registered with `luma.registerDevices()` for `luma.createDevice()` or `luma.attachDevice()` calls to succeed (unless `Device` implementations are supplied to those calls).
- At least one backend must be imported and registered with `luma.registerAdapters()` for `luma.createDevice()` or `luma.attachDevice()` calls to succeed (unless `Device` implementations are supplied to those calls).
4 changes: 2 additions & 2 deletions examples/api/animation/index.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<!doctype html>
<script type="module">
import {luma} from '@luma.gl/core';
import {WebGLDevice} from '@luma.gl/webgl';
luma.registerDevices([WebGLDevice]);
import {webglAdaprter} from '@luma.gl/webgl';
luma.registerAdapters([webgl2Adapter]);

import AnimationLoopTemplate from './app.ts';
import {makeAnimationLoop} from '@luma.gl/engine';
Expand Down
4 changes: 2 additions & 2 deletions examples/api/cubemap/index.html
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<!doctype html>
<script type="module">
import {WebGLDevice} from '@luma.gl/webgl';
import {webgl2Adapter} from '@luma.gl/webgl';
// import {WebGPUDevice} from '@luma.gl/webgpu';
import {luma} from '@luma.gl/core';
import {makeAnimationLoop} from '@luma.gl/engine';
import AnimationLoopTemplate from './app.ts';

luma.registerDevices([WebGLDevice]);
luma.reagisterAdapters([webgl2Adapter]);
makeAnimationLoop(AnimationLoopTemplate).start();
</script>
<body>
Expand Down
4 changes: 2 additions & 2 deletions examples/api/texture-3d/index.html
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<!doctype html>
<script type="module">
import {WebGLDevice} from '@luma.gl/webgl';
import {webgl2Adapter} from '@luma.gl/webgl';
// import {WebGPUDevice} from '@luma.gl/webgpu';
import {luma} from '@luma.gl/core';
import {makeAnimationLoop} from '@luma.gl/engine';
import AnimationLoopTemplate from './app.ts';

luma.registerDevices([WebGLDevice]);
luma.reagisterAdapters([webgl2Adapter]);
makeAnimationLoop(AnimationLoopTemplate).start();
</script>
<body>
Expand Down
4 changes: 2 additions & 2 deletions examples/script/webgl/transform-feedback/index.html
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<!doctype html>
<script type="module">
import {WebGLDevice} from '@luma.gl/webgl';
import {webgl2Adapter} from '@luma.gl/webgl';
// import {WebGPUDevice} from '@luma.gl/webgpu';
import {luma} from '@luma.gl/core';
import {makeAnimationLoop} from '@luma.gl/engine';
import AnimationLoopTemplate from './app.ts';

luma.registerDevices([WebGLDevice]);
luma.reagisterAdapters([webgl2Adapter]);
makeAnimationLoop(AnimationLoopTemplate).start();
</script>
<body>
Expand Down
6 changes: 3 additions & 3 deletions examples/showcase/instancing/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
<script type="module">
import {luma} from '@luma.gl/core';
import {makeAnimationLoop} from '@luma.gl/engine';
import {WebGLDevice} from '@luma.gl/webgl';
import {WebGPUDevice} from '@luma.gl/webgpu';
import {webgl2Adapter} from '@luma.gl/webgl';
import {webgpuAdapter} from '@luma.gl/webgpu';
import AnimationLoopTemplate from './app.ts';
luma.registerDevices([/*WebGPUDevice, */WebGLDevice]);
luma.reagisterAdapters([/*webgpuAdapter, */ webgl2Adapter]);
makeAnimationLoop(AnimationLoopTemplate).start();
</script>
<body>
Expand Down
4 changes: 2 additions & 2 deletions examples/showcase/persistence/index.html
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<!doctype html>
<script type="module">
import {luma} from '@luma.gl/core';
import {WebGLDevice} from '@luma.gl/webgl';
import {webgl2Adapter} from '@luma.gl/webgl';
import {makeAnimationLoop} from '@luma.gl/engine';
import AppAnimationLoop from './app.ts';
luma.registerDevices([WebGLDevice]);
luma.reagisterAdapters([webgl2Adapter]);
const animationLoop = makeAnimationLoop(AppAnimationLoop);
animationLoop.start();
</script>
Expand Down
6 changes: 3 additions & 3 deletions examples/tutorials/hello-cube/index.html
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<!doctype html>
<script type="module">
import {WebGLDevice} from '@luma.gl/webgl';
import {WebGPUDevice} from '@luma.gl/webgpu';
import {webgl2Adapter} from '@luma.gl/webgl';
import {webgpuAdapter} from '@luma.gl/webgpu';
import {luma} from '@luma.gl/core';
import {makeAnimationLoop} from '@luma.gl/engine';
import AnimationLoopTemplate from './app.ts';

luma.registerDevices([WebGLDevice]);
luma.reagisterAdapters([webgl2Adapter]);
makeAnimationLoop(AnimationLoopTemplate).start();
</script>
<body>
Expand Down
6 changes: 3 additions & 3 deletions examples/tutorials/hello-gltf/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@
</head>
<script type="module">
import {luma} from '@luma.gl/core';
import {WebGLDevice} from '@luma.gl/webgl';
import {webgl2Adapter} from '@luma.gl/webgl';
// import {WebGPUDevice} from '@luma.gl/webgpu';
import {makeAnimationLoop} from '@luma.gl/engine';
import AnimationLoopTemplate from './app.ts';

luma.registerDevices([WebGLDevice]);
// luma.registerDevices([WebGLDevice, WebGPUDevice]);
luma.reagisterAdapters([webgl2Adapter]);
// luma.reagisterAdapters([webglDevice, webgpuDevice]);

const resolution = 2;
const device = luma.createDevice({width: resolution * window.innerWidth, height: resolution * window.innerHeight});
Expand Down

0 comments on commit 8310f9a

Please sign in to comment.