@luma.gl/engine 9.2.6 → 9.3.0-alpha.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/animation-loop/animation-loop.d.ts +11 -5
- package/dist/animation-loop/animation-loop.d.ts.map +1 -1
- package/dist/animation-loop/animation-loop.js +83 -47
- package/dist/animation-loop/animation-loop.js.map +1 -1
- package/dist/animation-loop/make-animation-loop.d.ts.map +1 -1
- package/dist/animation-loop/make-animation-loop.js +8 -1
- package/dist/animation-loop/make-animation-loop.js.map +1 -1
- package/dist/animation-loop/request-animation-frame.d.ts.map +1 -1
- package/dist/animation-loop/request-animation-frame.js +23 -6
- package/dist/animation-loop/request-animation-frame.js.map +1 -1
- package/dist/compute/computation.d.ts +3 -7
- package/dist/compute/computation.d.ts.map +1 -1
- package/dist/compute/computation.js +16 -13
- package/dist/compute/computation.js.map +1 -1
- package/dist/compute/swap.d.ts +2 -0
- package/dist/compute/swap.d.ts.map +1 -1
- package/dist/compute/swap.js +10 -5
- package/dist/compute/swap.js.map +1 -1
- package/dist/debug/debug-framebuffer.d.ts +9 -4
- package/dist/debug/debug-framebuffer.d.ts.map +1 -1
- package/dist/debug/debug-framebuffer.js +91 -45
- package/dist/debug/debug-framebuffer.js.map +1 -1
- package/dist/dist.dev.js +2767 -1344
- package/dist/dist.min.js +326 -211
- package/dist/dynamic-texture/dynamic-texture.d.ts +102 -0
- package/dist/dynamic-texture/dynamic-texture.d.ts.map +1 -0
- package/dist/dynamic-texture/dynamic-texture.js +558 -0
- package/dist/dynamic-texture/dynamic-texture.js.map +1 -0
- package/dist/dynamic-texture/texture-data.d.ts +144 -0
- package/dist/dynamic-texture/texture-data.d.ts.map +1 -0
- package/dist/dynamic-texture/texture-data.js +208 -0
- package/dist/dynamic-texture/texture-data.js.map +1 -0
- package/dist/geometries/cone-geometry.d.ts +3 -1
- package/dist/geometries/cone-geometry.d.ts.map +1 -1
- package/dist/geometries/cone-geometry.js.map +1 -1
- package/dist/geometries/cube-geometry.js +7 -7
- package/dist/geometries/cube-geometry.js.map +1 -1
- package/dist/geometries/cylinder-geometry.d.ts +2 -1
- package/dist/geometries/cylinder-geometry.d.ts.map +1 -1
- package/dist/geometries/cylinder-geometry.js.map +1 -1
- package/dist/geometries/ico-sphere-geometry.js +3 -1
- package/dist/geometries/ico-sphere-geometry.js.map +1 -1
- package/dist/geometry/gpu-geometry.d.ts.map +1 -1
- package/dist/geometry/gpu-geometry.js +11 -3
- package/dist/geometry/gpu-geometry.js.map +1 -1
- package/dist/index.cjs +2620 -1267
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +20 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -4
- package/dist/index.js.map +1 -1
- package/dist/material/material-factory.d.ts +73 -0
- package/dist/material/material-factory.d.ts.map +1 -0
- package/dist/material/material-factory.js +111 -0
- package/dist/material/material-factory.js.map +1 -0
- package/dist/material/material.d.ts +84 -0
- package/dist/material/material.d.ts.map +1 -0
- package/dist/material/material.js +176 -0
- package/dist/material/material.js.map +1 -0
- package/dist/model/model.d.ts +47 -16
- package/dist/model/model.d.ts.map +1 -1
- package/dist/model/model.js +148 -71
- package/dist/model/model.js.map +1 -1
- package/dist/model/split-uniforms-and-bindings.d.ts +4 -3
- package/dist/model/split-uniforms-and-bindings.d.ts.map +1 -1
- package/dist/model/split-uniforms-and-bindings.js +2 -2
- package/dist/model/split-uniforms-and-bindings.js.map +1 -1
- package/dist/models/billboard-texture-model.d.ts +8 -5
- package/dist/models/billboard-texture-model.d.ts.map +1 -1
- package/dist/models/billboard-texture-model.js +79 -25
- package/dist/models/billboard-texture-model.js.map +1 -1
- package/dist/models/billboard-texture-module.d.ts +1 -1
- package/dist/models/billboard-texture-module.js +1 -1
- package/dist/models/clip-space.js +7 -7
- package/dist/models/directional-light-model.d.ts +7 -0
- package/dist/models/directional-light-model.d.ts.map +1 -0
- package/dist/models/directional-light-model.js +23 -0
- package/dist/models/directional-light-model.js.map +1 -0
- package/dist/models/light-model-utils.d.ts +69 -0
- package/dist/models/light-model-utils.d.ts.map +1 -0
- package/dist/models/light-model-utils.js +395 -0
- package/dist/models/light-model-utils.js.map +1 -0
- package/dist/models/point-light-model.d.ts +7 -0
- package/dist/models/point-light-model.d.ts.map +1 -0
- package/dist/models/point-light-model.js +22 -0
- package/dist/models/point-light-model.js.map +1 -0
- package/dist/models/spot-light-model.d.ts +7 -0
- package/dist/models/spot-light-model.d.ts.map +1 -0
- package/dist/models/spot-light-model.js +23 -0
- package/dist/models/spot-light-model.js.map +1 -0
- package/dist/modules/picking/color-picking.d.ts +5 -9
- package/dist/modules/picking/color-picking.d.ts.map +1 -1
- package/dist/modules/picking/color-picking.js +122 -115
- package/dist/modules/picking/color-picking.js.map +1 -1
- package/dist/modules/picking/index-picking.d.ts +4 -4
- package/dist/modules/picking/index-picking.d.ts.map +1 -1
- package/dist/modules/picking/index-picking.js +36 -16
- package/dist/modules/picking/index-picking.js.map +1 -1
- package/dist/modules/picking/legacy-color-picking.d.ts +26 -0
- package/dist/modules/picking/legacy-color-picking.d.ts.map +1 -0
- package/dist/modules/picking/legacy-color-picking.js +7 -0
- package/dist/modules/picking/legacy-color-picking.js.map +1 -0
- package/dist/modules/picking/picking-manager.d.ts +29 -3
- package/dist/modules/picking/picking-manager.d.ts.map +1 -1
- package/dist/modules/picking/picking-manager.js +188 -41
- package/dist/modules/picking/picking-manager.js.map +1 -1
- package/dist/modules/picking/picking-uniforms.d.ts +13 -12
- package/dist/modules/picking/picking-uniforms.d.ts.map +1 -1
- package/dist/modules/picking/picking-uniforms.js +27 -14
- package/dist/modules/picking/picking-uniforms.js.map +1 -1
- package/dist/modules/picking/picking.d.ts +25 -0
- package/dist/modules/picking/picking.d.ts.map +1 -0
- package/dist/modules/picking/picking.js +18 -0
- package/dist/modules/picking/picking.js.map +1 -0
- package/dist/passes/get-fragment-shader.js +12 -27
- package/dist/passes/get-fragment-shader.js.map +1 -1
- package/dist/passes/shader-pass-renderer.d.ts +5 -7
- package/dist/passes/shader-pass-renderer.d.ts.map +1 -1
- package/dist/passes/shader-pass-renderer.js +16 -42
- package/dist/passes/shader-pass-renderer.js.map +1 -1
- package/dist/scenegraph/group-node.d.ts +5 -0
- package/dist/scenegraph/group-node.d.ts.map +1 -1
- package/dist/scenegraph/group-node.js +12 -0
- package/dist/scenegraph/group-node.js.map +1 -1
- package/dist/scenegraph/model-node.d.ts +2 -2
- package/dist/scenegraph/model-node.d.ts.map +1 -1
- package/dist/scenegraph/model-node.js.map +1 -1
- package/dist/scenegraph/scenegraph-node.d.ts +1 -1
- package/dist/scenegraph/scenegraph-node.d.ts.map +1 -1
- package/dist/scenegraph/scenegraph-node.js +23 -15
- package/dist/scenegraph/scenegraph-node.js.map +1 -1
- package/dist/shader-inputs.d.ts +9 -7
- package/dist/shader-inputs.d.ts.map +1 -1
- package/dist/shader-inputs.js +90 -13
- package/dist/shader-inputs.js.map +1 -1
- package/dist/utils/buffer-layout-order.d.ts.map +1 -1
- package/dist/utils/buffer-layout-order.js +12 -2
- package/dist/utils/buffer-layout-order.js.map +1 -1
- package/dist/utils/shader-module-utils.d.ts +7 -0
- package/dist/utils/shader-module-utils.d.ts.map +1 -0
- package/dist/utils/shader-module-utils.js +46 -0
- package/dist/utils/shader-module-utils.js.map +1 -0
- package/package.json +6 -6
- package/src/animation-loop/animation-loop.ts +89 -50
- package/src/animation-loop/make-animation-loop.ts +14 -5
- package/src/animation-loop/request-animation-frame.ts +32 -6
- package/src/compute/computation.ts +32 -17
- package/src/compute/swap.ts +13 -7
- package/src/debug/debug-framebuffer.ts +139 -61
- package/src/dynamic-texture/dynamic-texture.ts +730 -0
- package/src/dynamic-texture/texture-data.ts +336 -0
- package/src/{async-texture/texture-setters.ts.disabled → dynamic-texture/texture-data.ts.disabled} +1 -1
- package/src/geometries/cone-geometry.ts +6 -1
- package/src/geometries/cube-geometry.ts +7 -7
- package/src/geometries/cylinder-geometry.ts +5 -1
- package/src/geometries/ico-sphere-geometry.ts +3 -1
- package/src/geometry/gpu-geometry.ts +11 -3
- package/src/index.ts +38 -8
- package/src/material/material-factory.ts +157 -0
- package/src/material/material.ts +254 -0
- package/src/model/model.ts +196 -93
- package/src/model/split-uniforms-and-bindings.ts +8 -6
- package/src/models/billboard-texture-model.ts +90 -29
- package/src/models/billboard-texture-module.ts +1 -1
- package/src/models/clip-space.ts +7 -7
- package/src/models/directional-light-model.ts +32 -0
- package/src/models/light-model-utils.ts +587 -0
- package/src/models/point-light-model.ts +31 -0
- package/src/models/spot-light-model.ts +32 -0
- package/src/modules/picking/color-picking.ts +123 -122
- package/src/modules/picking/index-picking.ts +36 -16
- package/src/modules/picking/legacy-color-picking.ts +8 -0
- package/src/modules/picking/picking-manager.ts +252 -50
- package/src/modules/picking/picking-uniforms.ts +39 -24
- package/src/modules/picking/picking.ts +22 -0
- package/src/passes/get-fragment-shader.ts +12 -27
- package/src/passes/shader-pass-renderer.ts +25 -48
- package/src/scenegraph/group-node.ts +16 -0
- package/src/scenegraph/model-node.ts +2 -2
- package/src/scenegraph/scenegraph-node.ts +27 -16
- package/src/shader-inputs.ts +167 -26
- package/src/utils/buffer-layout-order.ts +18 -2
- package/src/utils/shader-module-utils.ts +65 -0
- package/dist/async-texture/async-texture.d.ts +0 -166
- package/dist/async-texture/async-texture.d.ts.map +0 -1
- package/dist/async-texture/async-texture.js +0 -386
- package/dist/async-texture/async-texture.js.map +0 -1
- package/dist/factories/pipeline-factory.d.ts +0 -37
- package/dist/factories/pipeline-factory.d.ts.map +0 -1
- package/dist/factories/pipeline-factory.js +0 -181
- package/dist/factories/pipeline-factory.js.map +0 -1
- package/dist/factories/shader-factory.d.ts +0 -22
- package/dist/factories/shader-factory.d.ts.map +0 -1
- package/dist/factories/shader-factory.js +0 -88
- package/dist/factories/shader-factory.js.map +0 -1
- package/src/async-texture/async-texture.ts +0 -551
- package/src/factories/pipeline-factory.ts +0 -224
- package/src/factories/shader-factory.ts +0 -103
package/src/model/model.ts
CHANGED
|
@@ -3,19 +3,18 @@
|
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
5
|
// A lot of imports, but then Model is where it all comes together...
|
|
6
|
-
import type
|
|
7
|
-
import type {
|
|
8
|
-
RenderPipelineProps,
|
|
9
|
-
RenderPipelineParameters,
|
|
10
|
-
BufferLayout,
|
|
11
|
-
Shader,
|
|
12
|
-
VertexArray,
|
|
13
|
-
TransformFeedback,
|
|
14
|
-
AttributeInfo,
|
|
15
|
-
Binding,
|
|
16
|
-
PrimitiveTopology
|
|
17
|
-
} from '@luma.gl/core';
|
|
6
|
+
import {type TypedArray} from '@math.gl/types';
|
|
18
7
|
import {
|
|
8
|
+
type RenderPipelineProps,
|
|
9
|
+
type RenderPipelineParameters,
|
|
10
|
+
type BufferLayout,
|
|
11
|
+
type Shader,
|
|
12
|
+
type VertexArray,
|
|
13
|
+
type TransformFeedback,
|
|
14
|
+
type AttributeInfo,
|
|
15
|
+
type Binding,
|
|
16
|
+
type BindingsByGroup,
|
|
17
|
+
type PrimitiveTopology,
|
|
19
18
|
Device,
|
|
20
19
|
DeviceFeature,
|
|
21
20
|
Buffer,
|
|
@@ -24,30 +23,37 @@ import {
|
|
|
24
23
|
Sampler,
|
|
25
24
|
RenderPipeline,
|
|
26
25
|
RenderPass,
|
|
26
|
+
PipelineFactory,
|
|
27
|
+
ShaderFactory,
|
|
27
28
|
UniformStore,
|
|
28
29
|
log,
|
|
29
|
-
|
|
30
|
-
getAttributeInfosFromLayouts
|
|
30
|
+
dataTypeDecoder,
|
|
31
|
+
getAttributeInfosFromLayouts,
|
|
32
|
+
normalizeBindingsByGroup
|
|
31
33
|
} from '@luma.gl/core';
|
|
32
34
|
|
|
33
|
-
import type {ShaderModule, PlatformInfo} from '@luma.gl/shadertools';
|
|
34
|
-
import {ShaderAssembler
|
|
35
|
+
import type {ShaderBindingDebugRow, ShaderModule, PlatformInfo} from '@luma.gl/shadertools';
|
|
36
|
+
import {ShaderAssembler} from '@luma.gl/shadertools';
|
|
35
37
|
|
|
36
38
|
import type {Geometry} from '../geometry/geometry';
|
|
37
39
|
import {GPUGeometry, makeGPUGeometry} from '../geometry/gpu-geometry';
|
|
38
|
-
import {PipelineFactory} from '../factories/pipeline-factory';
|
|
39
|
-
import {ShaderFactory} from '../factories/shader-factory';
|
|
40
40
|
import {getDebugTableForShaderLayout} from '../debug/debug-shader-layout';
|
|
41
41
|
import {debugFramebuffer} from '../debug/debug-framebuffer';
|
|
42
42
|
import {deepEqual} from '../utils/deep-equal';
|
|
43
43
|
import {BufferLayoutHelper} from '../utils/buffer-layout-helper';
|
|
44
44
|
import {sortedBufferLayoutByShaderSourceLocations} from '../utils/buffer-layout-order';
|
|
45
|
+
import {
|
|
46
|
+
mergeShaderModuleBindingsIntoLayout,
|
|
47
|
+
shaderModuleHasUniforms
|
|
48
|
+
} from '../utils/shader-module-utils';
|
|
45
49
|
import {uid} from '../utils/uid';
|
|
46
50
|
import {ShaderInputs} from '../shader-inputs';
|
|
47
|
-
import {
|
|
51
|
+
import {DynamicTexture} from '../dynamic-texture/dynamic-texture';
|
|
52
|
+
import {Material} from '../material/material';
|
|
48
53
|
|
|
49
54
|
const LOG_DRAW_PRIORITY = 2;
|
|
50
55
|
const LOG_DRAW_TIMEOUT = 10000;
|
|
56
|
+
const PIPELINE_INITIALIZATION_FAILED = 'render pipeline initialization failed';
|
|
51
57
|
|
|
52
58
|
export type ModelProps = Omit<RenderPipelineProps, 'vs' | 'fs' | 'bindings'> & {
|
|
53
59
|
source?: string;
|
|
@@ -62,8 +68,12 @@ export type ModelProps = Omit<RenderPipelineProps, 'vs' | 'fs' | 'bindings'> & {
|
|
|
62
68
|
|
|
63
69
|
/** Shader inputs, used to generated uniform buffers and bindings */
|
|
64
70
|
shaderInputs?: ShaderInputs;
|
|
71
|
+
/** Material-owned group-3 bindings */
|
|
72
|
+
material?: Material;
|
|
65
73
|
/** Bindings */
|
|
66
|
-
bindings?: Record<string, Binding |
|
|
74
|
+
bindings?: Record<string, Binding | DynamicTexture>;
|
|
75
|
+
/** WebGL-only uniforms */
|
|
76
|
+
uniforms?: Record<string, unknown>;
|
|
67
77
|
/** Parameters that are built into the pipeline */
|
|
68
78
|
parameters?: RenderPipelineParameters;
|
|
69
79
|
|
|
@@ -103,12 +113,19 @@ export type ModelProps = Omit<RenderPipelineProps, 'vs' | 'fs' | 'bindings'> & {
|
|
|
103
113
|
};
|
|
104
114
|
|
|
105
115
|
/**
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
116
|
+
* High level draw API for luma.gl.
|
|
117
|
+
*
|
|
118
|
+
* A `Model` encapsulates shaders, geometry attributes, bindings and render
|
|
119
|
+
* pipeline state into a single object. It automatically reuses and rebuilds
|
|
120
|
+
* pipelines as render parameters change and exposes convenient hooks for
|
|
121
|
+
* updating uniforms and attributes.
|
|
122
|
+
*
|
|
123
|
+
* Features:
|
|
124
|
+
* - Reuses and lazily recompiles {@link RenderPipeline | pipelines} as needed.
|
|
125
|
+
* - Integrates with `@luma.gl/shadertools` to assemble GLSL or WGSL from shader modules.
|
|
126
|
+
* - Manages geometry attributes and buffer bindings.
|
|
127
|
+
* - Accepts textures, samplers and uniform buffers as bindings, including `DynamicTexture`.
|
|
128
|
+
* - Provides detailed debug logging and optional shader source inspection.
|
|
112
129
|
*/
|
|
113
130
|
export class Model {
|
|
114
131
|
static defaultProps: Required<ModelProps> = {
|
|
@@ -125,6 +142,8 @@ export class Model {
|
|
|
125
142
|
indexBuffer: null,
|
|
126
143
|
attributes: {},
|
|
127
144
|
constantAttributes: {},
|
|
145
|
+
bindings: {},
|
|
146
|
+
uniforms: {},
|
|
128
147
|
varyings: [],
|
|
129
148
|
|
|
130
149
|
isInstanced: undefined!,
|
|
@@ -132,6 +151,7 @@ export class Model {
|
|
|
132
151
|
vertexCount: 0,
|
|
133
152
|
|
|
134
153
|
shaderInputs: undefined!,
|
|
154
|
+
material: undefined!,
|
|
135
155
|
pipelineFactory: undefined!,
|
|
136
156
|
shaderFactory: undefined!,
|
|
137
157
|
transformFeedback: undefined!,
|
|
@@ -141,16 +161,24 @@ export class Model {
|
|
|
141
161
|
disableWarnings: undefined!
|
|
142
162
|
};
|
|
143
163
|
|
|
164
|
+
/** Device that created this model */
|
|
144
165
|
readonly device: Device;
|
|
166
|
+
/** Application provided identifier */
|
|
145
167
|
readonly id: string;
|
|
168
|
+
/** WGSL shader source when using unified shader */
|
|
146
169
|
// @ts-expect-error assigned in function called from constructor
|
|
147
170
|
readonly source: string;
|
|
171
|
+
/** GLSL vertex shader source */
|
|
148
172
|
// @ts-expect-error assigned in function called from constructor
|
|
149
173
|
readonly vs: string;
|
|
174
|
+
/** GLSL fragment shader source */
|
|
150
175
|
// @ts-expect-error assigned in function called from constructor
|
|
151
176
|
readonly fs: string;
|
|
177
|
+
/** Factory used to create render pipelines */
|
|
152
178
|
readonly pipelineFactory: PipelineFactory;
|
|
179
|
+
/** Factory used to create shaders */
|
|
153
180
|
readonly shaderFactory: ShaderFactory;
|
|
181
|
+
/** User-supplied per-model data */
|
|
154
182
|
userData: {[key: string]: any} = {};
|
|
155
183
|
|
|
156
184
|
// Fixed properties (change can trigger pipeline rebuild)
|
|
@@ -179,7 +207,7 @@ export class Model {
|
|
|
179
207
|
/** Constant-valued attributes */
|
|
180
208
|
constantAttributes: Record<string, TypedArray> = {};
|
|
181
209
|
/** Bindings (textures, samplers, uniform buffers) */
|
|
182
|
-
bindings: Record<string, Binding |
|
|
210
|
+
bindings: Record<string, Binding | DynamicTexture> = {};
|
|
183
211
|
|
|
184
212
|
/**
|
|
185
213
|
* VertexArray
|
|
@@ -197,6 +225,7 @@ export class Model {
|
|
|
197
225
|
/** ShaderInputs instance */
|
|
198
226
|
// @ts-expect-error Assigned in function called by constructor
|
|
199
227
|
shaderInputs: ShaderInputs;
|
|
228
|
+
material: Material | null = null;
|
|
200
229
|
// @ts-expect-error Assigned in function called by constructor
|
|
201
230
|
_uniformStore: UniformStore;
|
|
202
231
|
|
|
@@ -210,6 +239,7 @@ export class Model {
|
|
|
210
239
|
|
|
211
240
|
/** "Time" of last draw. Monotonically increasing timestamp */
|
|
212
241
|
_lastDrawTimestamp: number = -1;
|
|
242
|
+
private _bindingTable: ShaderBindingDebugRow[] = [];
|
|
213
243
|
|
|
214
244
|
get [Symbol.toStringTag](): string {
|
|
215
245
|
return 'Model';
|
|
@@ -227,6 +257,8 @@ export class Model {
|
|
|
227
257
|
|
|
228
258
|
Object.assign(this.userData, props.userData);
|
|
229
259
|
|
|
260
|
+
this.material = props.material || null;
|
|
261
|
+
|
|
230
262
|
// Setup shader module inputs
|
|
231
263
|
const moduleMap = Object.fromEntries(
|
|
232
264
|
this.props.modules?.map(module => [module.name, module]) || []
|
|
@@ -246,6 +278,9 @@ export class Model {
|
|
|
246
278
|
// @ts-ignore shaderInputs is assigned in setShaderInputs above.
|
|
247
279
|
(this.props.modules?.length > 0 ? this.props.modules : this.shaderInputs?.getModules()) || [];
|
|
248
280
|
|
|
281
|
+
this.props.shaderLayout =
|
|
282
|
+
mergeShaderModuleBindingsIntoLayout(this.props.shaderLayout, modules) || null;
|
|
283
|
+
|
|
249
284
|
const isWebGPU = this.device.type === 'webgpu';
|
|
250
285
|
|
|
251
286
|
// WebGPU
|
|
@@ -253,7 +288,7 @@ export class Model {
|
|
|
253
288
|
// TODO - this is wrong, compile a single shader
|
|
254
289
|
if (isWebGPU && this.props.source) {
|
|
255
290
|
// WGSL
|
|
256
|
-
const {source, getUniforms} = this.props.shaderAssembler.assembleWGSLShader({
|
|
291
|
+
const {source, getUniforms, bindingTable} = this.props.shaderAssembler.assembleWGSLShader({
|
|
257
292
|
platformInfo,
|
|
258
293
|
...this.props,
|
|
259
294
|
modules
|
|
@@ -261,8 +296,16 @@ export class Model {
|
|
|
261
296
|
this.source = source;
|
|
262
297
|
// @ts-expect-error
|
|
263
298
|
this._getModuleUniforms = getUniforms;
|
|
299
|
+
this._bindingTable = bindingTable;
|
|
264
300
|
// Extract shader layout after modules have been added to WGSL source, to include any bindings added by modules
|
|
265
|
-
|
|
301
|
+
const inferredShaderLayout = (
|
|
302
|
+
device as Device & {getShaderLayout?: (source: string) => any}
|
|
303
|
+
).getShaderLayout?.(this.source);
|
|
304
|
+
this.props.shaderLayout =
|
|
305
|
+
mergeShaderModuleBindingsIntoLayout(
|
|
306
|
+
this.props.shaderLayout || inferredShaderLayout || null,
|
|
307
|
+
modules
|
|
308
|
+
) || null;
|
|
266
309
|
} else {
|
|
267
310
|
// GLSL
|
|
268
311
|
const {vs, fs, getUniforms} = this.props.shaderAssembler.assembleGLSLShaderPair({
|
|
@@ -275,6 +318,7 @@ export class Model {
|
|
|
275
318
|
this.fs = fs;
|
|
276
319
|
// @ts-expect-error
|
|
277
320
|
this._getModuleUniforms = getUniforms;
|
|
321
|
+
this._bindingTable = [];
|
|
278
322
|
}
|
|
279
323
|
|
|
280
324
|
this.vertexCount = this.props.vertexCount;
|
|
@@ -333,9 +377,6 @@ export class Model {
|
|
|
333
377
|
if (props.transformFeedback) {
|
|
334
378
|
this.transformFeedback = props.transformFeedback;
|
|
335
379
|
}
|
|
336
|
-
|
|
337
|
-
// Catch any access to non-standard props
|
|
338
|
-
Object.seal(this);
|
|
339
380
|
}
|
|
340
381
|
|
|
341
382
|
destroy(): void {
|
|
@@ -344,7 +385,7 @@ export class Model {
|
|
|
344
385
|
this.pipelineFactory.release(this.pipeline);
|
|
345
386
|
// Release the shaders
|
|
346
387
|
this.shaderFactory.release(this.pipeline.vs);
|
|
347
|
-
if (this.pipeline.fs) {
|
|
388
|
+
if (this.pipeline.fs && this.pipeline.fs !== this.pipeline.vs) {
|
|
348
389
|
this.shaderFactory.release(this.pipeline.fs);
|
|
349
390
|
}
|
|
350
391
|
this._uniformStore.destroy();
|
|
@@ -372,6 +413,12 @@ export class Model {
|
|
|
372
413
|
this._needsRedraw ||= reason;
|
|
373
414
|
}
|
|
374
415
|
|
|
416
|
+
/** Returns WGSL binding debug rows for the assembled shader. Returns an empty array for GLSL models. */
|
|
417
|
+
getBindingDebugTable(): readonly ShaderBindingDebugRow[] {
|
|
418
|
+
return this._bindingTable;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/** Update uniforms and pipeline state prior to drawing. */
|
|
375
422
|
predraw(): void {
|
|
376
423
|
// Update uniform buffers if needed
|
|
377
424
|
this.updateShaderInputs();
|
|
@@ -379,6 +426,11 @@ export class Model {
|
|
|
379
426
|
this.pipeline = this._updatePipeline();
|
|
380
427
|
}
|
|
381
428
|
|
|
429
|
+
/**
|
|
430
|
+
* Issue one draw call.
|
|
431
|
+
* @param renderPass - render pass to draw into
|
|
432
|
+
* @returns `true` if the draw call was executed, `false` if resources were not ready.
|
|
433
|
+
*/
|
|
382
434
|
draw(renderPass: RenderPass): boolean {
|
|
383
435
|
const loadingBinding = this._areBindingsLoading();
|
|
384
436
|
if (loadingBinding) {
|
|
@@ -394,6 +446,7 @@ export class Model {
|
|
|
394
446
|
}
|
|
395
447
|
|
|
396
448
|
let drawSuccess: boolean;
|
|
449
|
+
let pipelineErrored = this.pipeline.isErrored;
|
|
397
450
|
try {
|
|
398
451
|
renderPass.pushDebugGroup(`${this}.draw(${renderPass})`);
|
|
399
452
|
this._logDrawCallStart();
|
|
@@ -402,35 +455,45 @@ export class Model {
|
|
|
402
455
|
// TODO - inside RenderPass is likely the worst place to do this from performance perspective.
|
|
403
456
|
// Application can call Model.predraw() to avoid this.
|
|
404
457
|
this.pipeline = this._updatePipeline();
|
|
458
|
+
pipelineErrored = this.pipeline.isErrored;
|
|
405
459
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
460
|
+
if (pipelineErrored) {
|
|
461
|
+
log.info(
|
|
462
|
+
LOG_DRAW_PRIORITY,
|
|
463
|
+
`>>> DRAWING ABORTED ${this.id}: ${PIPELINE_INITIALIZATION_FAILED}`
|
|
464
|
+
)();
|
|
465
|
+
drawSuccess = false;
|
|
466
|
+
} else {
|
|
467
|
+
const syncBindings = this._getBindings();
|
|
468
|
+
const syncBindGroups = this._getBindGroups();
|
|
469
|
+
|
|
470
|
+
const {indexBuffer} = this.vertexArray;
|
|
471
|
+
const indexCount = indexBuffer
|
|
472
|
+
? indexBuffer.byteLength / (indexBuffer.indexType === 'uint32' ? 4 : 2)
|
|
473
|
+
: undefined;
|
|
474
|
+
|
|
475
|
+
drawSuccess = this.pipeline.draw({
|
|
476
|
+
renderPass,
|
|
477
|
+
vertexArray: this.vertexArray,
|
|
478
|
+
isInstanced: this.isInstanced,
|
|
479
|
+
vertexCount: this.vertexCount,
|
|
480
|
+
instanceCount: this.instanceCount,
|
|
481
|
+
indexCount,
|
|
482
|
+
transformFeedback: this.transformFeedback || undefined,
|
|
483
|
+
// Pipelines may be shared across models when caching is enabled, so bindings
|
|
484
|
+
// and WebGL uniforms must be supplied on every draw instead of being stored
|
|
485
|
+
// on the pipeline instance.
|
|
486
|
+
bindings: syncBindings,
|
|
487
|
+
bindGroups: syncBindGroups,
|
|
488
|
+
_bindGroupCacheKeys: this._getBindGroupCacheKeys(),
|
|
489
|
+
uniforms: this.props.uniforms,
|
|
490
|
+
// WebGL shares underlying cached pipelines even for models that have different parameters and topology,
|
|
491
|
+
// so we must provide our unique parameters to each draw
|
|
492
|
+
// (In WebGPU most parameters are encoded in the pipeline and cannot be changed per draw call)
|
|
493
|
+
parameters: this.parameters,
|
|
494
|
+
topology: this.topology
|
|
495
|
+
});
|
|
496
|
+
}
|
|
434
497
|
} finally {
|
|
435
498
|
renderPass.popDebugGroup();
|
|
436
499
|
this._logDrawCallEnd();
|
|
@@ -441,6 +504,8 @@ export class Model {
|
|
|
441
504
|
if (drawSuccess) {
|
|
442
505
|
this._lastDrawTimestamp = this.device.timestamp;
|
|
443
506
|
this._needsRedraw = false;
|
|
507
|
+
} else if (pipelineErrored) {
|
|
508
|
+
this._needsRedraw = PIPELINE_INITIALIZATION_FAILED;
|
|
444
509
|
} else {
|
|
445
510
|
this._needsRedraw = 'waiting for resource initialization';
|
|
446
511
|
}
|
|
@@ -549,21 +614,26 @@ export class Model {
|
|
|
549
614
|
/** Set the shader inputs */
|
|
550
615
|
setShaderInputs(shaderInputs: ShaderInputs): void {
|
|
551
616
|
this.shaderInputs = shaderInputs;
|
|
552
|
-
this._uniformStore = new UniformStore(this.shaderInputs.modules);
|
|
617
|
+
this._uniformStore = new UniformStore(this.device, this.shaderInputs.modules);
|
|
553
618
|
// Create uniform buffer bindings for all modules that actually have uniforms
|
|
554
619
|
for (const [moduleName, module] of Object.entries(this.shaderInputs.modules)) {
|
|
555
|
-
if (shaderModuleHasUniforms(module)) {
|
|
556
|
-
const uniformBuffer = this._uniformStore.getManagedUniformBuffer(
|
|
620
|
+
if (shaderModuleHasUniforms(module) && !this.material?.ownsModule(moduleName)) {
|
|
621
|
+
const uniformBuffer = this._uniformStore.getManagedUniformBuffer(moduleName);
|
|
557
622
|
this.bindings[`${moduleName}Uniforms`] = uniformBuffer;
|
|
558
623
|
}
|
|
559
624
|
}
|
|
560
625
|
this.setNeedsRedraw('shaderInputs');
|
|
561
626
|
}
|
|
562
627
|
|
|
628
|
+
setMaterial(material: Material | null): void {
|
|
629
|
+
this.material = material;
|
|
630
|
+
this.setNeedsRedraw('material');
|
|
631
|
+
}
|
|
632
|
+
|
|
563
633
|
/** Update uniform buffers from the model's shader inputs */
|
|
564
634
|
updateShaderInputs(): void {
|
|
565
635
|
this._uniformStore.setUniforms(this.shaderInputs.getUniformValues());
|
|
566
|
-
this.setBindings(this.shaderInputs.getBindingValues());
|
|
636
|
+
this.setBindings(this._getNonMaterialBindings(this.shaderInputs.getBindingValues()));
|
|
567
637
|
// TODO - this is already tracked through buffer/texture update times?
|
|
568
638
|
this.setNeedsRedraw('shaderInputs');
|
|
569
639
|
}
|
|
@@ -571,7 +641,7 @@ export class Model {
|
|
|
571
641
|
/**
|
|
572
642
|
* Sets bindings (textures, samplers, uniform buffers)
|
|
573
643
|
*/
|
|
574
|
-
setBindings(bindings: Record<string, Binding |
|
|
644
|
+
setBindings(bindings: Record<string, Binding | DynamicTexture>): void {
|
|
575
645
|
Object.assign(this.bindings, bindings);
|
|
576
646
|
this.setNeedsRedraw('bindings');
|
|
577
647
|
}
|
|
@@ -678,7 +748,12 @@ export class Model {
|
|
|
678
748
|
/** Check that bindings are loaded. Returns id of first binding that is still loading. */
|
|
679
749
|
_areBindingsLoading(): string | false {
|
|
680
750
|
for (const binding of Object.values(this.bindings)) {
|
|
681
|
-
if (binding instanceof
|
|
751
|
+
if (binding instanceof DynamicTexture && !binding.isReady) {
|
|
752
|
+
return binding.id;
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
for (const binding of Object.values(this.material?.bindings || {})) {
|
|
756
|
+
if (binding instanceof DynamicTexture && !binding.isReady) {
|
|
682
757
|
return binding.id;
|
|
683
758
|
}
|
|
684
759
|
}
|
|
@@ -690,7 +765,7 @@ export class Model {
|
|
|
690
765
|
const validBindings: Record<string, Binding> = {};
|
|
691
766
|
|
|
692
767
|
for (const [name, binding] of Object.entries(this.bindings)) {
|
|
693
|
-
if (binding instanceof
|
|
768
|
+
if (binding instanceof DynamicTexture) {
|
|
694
769
|
// Check that async textures are loaded
|
|
695
770
|
if (binding.isReady) {
|
|
696
771
|
validBindings[name] = binding.texture;
|
|
@@ -703,6 +778,32 @@ export class Model {
|
|
|
703
778
|
return validBindings;
|
|
704
779
|
}
|
|
705
780
|
|
|
781
|
+
_getBindGroups(): BindingsByGroup {
|
|
782
|
+
const shaderLayout = this.pipeline?.shaderLayout || this.props.shaderLayout || {bindings: []};
|
|
783
|
+
const bindGroups = shaderLayout.bindings.length
|
|
784
|
+
? normalizeBindingsByGroup(shaderLayout, this._getBindings())
|
|
785
|
+
: {0: this._getBindings()};
|
|
786
|
+
|
|
787
|
+
if (!this.material) {
|
|
788
|
+
return bindGroups;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
for (const [groupKey, groupBindings] of Object.entries(this.material.getBindingsByGroup())) {
|
|
792
|
+
const group = Number(groupKey);
|
|
793
|
+
bindGroups[group] = {
|
|
794
|
+
...(bindGroups[group] || {}),
|
|
795
|
+
...groupBindings
|
|
796
|
+
};
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
return bindGroups;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
_getBindGroupCacheKeys(): Partial<Record<number, object>> {
|
|
803
|
+
const bindGroupCacheKey = this.material?.getBindGroupCacheKey(3);
|
|
804
|
+
return bindGroupCacheKey ? {3: bindGroupCacheKey} : {};
|
|
805
|
+
}
|
|
806
|
+
|
|
706
807
|
/** Get the timestamp of the latest updated bound GPU memory resource (buffer/texture). */
|
|
707
808
|
_getBindingsUpdateTimestamp(): number {
|
|
708
809
|
let timestamp = 0;
|
|
@@ -711,7 +812,7 @@ export class Model {
|
|
|
711
812
|
timestamp = Math.max(timestamp, binding.texture.updateTimestamp);
|
|
712
813
|
} else if (binding instanceof Buffer || binding instanceof Texture) {
|
|
713
814
|
timestamp = Math.max(timestamp, binding.updateTimestamp);
|
|
714
|
-
} else if (binding instanceof
|
|
815
|
+
} else if (binding instanceof DynamicTexture) {
|
|
715
816
|
timestamp = binding.texture
|
|
716
817
|
? Math.max(timestamp, binding.texture.updateTimestamp)
|
|
717
818
|
: // The texture will become available in the future
|
|
@@ -720,7 +821,7 @@ export class Model {
|
|
|
720
821
|
timestamp = Math.max(timestamp, binding.buffer.updateTimestamp);
|
|
721
822
|
}
|
|
722
823
|
}
|
|
723
|
-
return timestamp;
|
|
824
|
+
return Math.max(timestamp, this.material?.getBindingsUpdateTimestamp() || 0);
|
|
724
825
|
}
|
|
725
826
|
|
|
726
827
|
/**
|
|
@@ -792,12 +893,11 @@ export class Model {
|
|
|
792
893
|
|
|
793
894
|
this.pipeline = this.pipelineFactory.createRenderPipeline({
|
|
794
895
|
...this.props,
|
|
896
|
+
bindings: undefined,
|
|
795
897
|
bufferLayout: this.bufferLayout,
|
|
796
898
|
topology: this.topology,
|
|
797
899
|
parameters: this.parameters,
|
|
798
|
-
|
|
799
|
-
// Should we expose a BindGroup abstraction?
|
|
800
|
-
bindings: this._getBindings(),
|
|
900
|
+
bindGroups: this._getBindGroups(),
|
|
801
901
|
vs,
|
|
802
902
|
fs
|
|
803
903
|
});
|
|
@@ -808,7 +908,9 @@ export class Model {
|
|
|
808
908
|
);
|
|
809
909
|
|
|
810
910
|
if (prevShaderVs) this.shaderFactory.release(prevShaderVs);
|
|
811
|
-
if (prevShaderFs
|
|
911
|
+
if (prevShaderFs && prevShaderFs !== prevShaderVs) {
|
|
912
|
+
this.shaderFactory.release(prevShaderFs);
|
|
913
|
+
}
|
|
812
914
|
}
|
|
813
915
|
return this.pipeline;
|
|
814
916
|
}
|
|
@@ -859,12 +961,11 @@ export class Model {
|
|
|
859
961
|
// } || (this._drawCount++ > 3 && this._drawCount % 60)) {
|
|
860
962
|
return;
|
|
861
963
|
}
|
|
862
|
-
// TODO - display framebuffer output in debug window
|
|
863
964
|
const framebuffer = renderPass.props.framebuffer;
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
}
|
|
965
|
+
debugFramebuffer(renderPass, framebuffer, {
|
|
966
|
+
id: framebuffer?.id || `${this.id}-framebuffer`,
|
|
967
|
+
minimap: true
|
|
968
|
+
});
|
|
868
969
|
}
|
|
869
970
|
|
|
870
971
|
_getAttributeDebugTable(): Record<string, Record<string, unknown>> {
|
|
@@ -896,15 +997,27 @@ export class Model {
|
|
|
896
997
|
|
|
897
998
|
// TODO - fix typing of luma data types
|
|
898
999
|
_getBufferOrConstantValues(attribute: Buffer | TypedArray, dataType: any): string {
|
|
899
|
-
const TypedArrayConstructor = getTypedArrayConstructor(dataType);
|
|
1000
|
+
const TypedArrayConstructor = dataTypeDecoder.getTypedArrayConstructor(dataType);
|
|
900
1001
|
const typedArray =
|
|
901
1002
|
attribute instanceof Buffer ? new TypedArrayConstructor(attribute.debugData) : attribute;
|
|
902
1003
|
return typedArray.toString();
|
|
903
1004
|
}
|
|
904
|
-
}
|
|
905
1005
|
|
|
906
|
-
|
|
907
|
-
|
|
1006
|
+
private _getNonMaterialBindings(
|
|
1007
|
+
bindings: Record<string, Binding | DynamicTexture>
|
|
1008
|
+
): Record<string, Binding | DynamicTexture> {
|
|
1009
|
+
if (!this.material) {
|
|
1010
|
+
return bindings;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
const filteredBindings: Record<string, Binding | DynamicTexture> = {};
|
|
1014
|
+
for (const [name, binding] of Object.entries(bindings)) {
|
|
1015
|
+
if (!this.material.ownsBinding(name)) {
|
|
1016
|
+
filteredBindings[name] = binding;
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
return filteredBindings;
|
|
1020
|
+
}
|
|
908
1021
|
}
|
|
909
1022
|
|
|
910
1023
|
// HELPERS
|
|
@@ -920,13 +1033,3 @@ export function getPlatformInfo(device: Device): PlatformInfo {
|
|
|
920
1033
|
features: device.features as unknown as Set<DeviceFeature>
|
|
921
1034
|
};
|
|
922
1035
|
}
|
|
923
|
-
|
|
924
|
-
/** Returns true if given object is empty, false otherwise. */
|
|
925
|
-
function isObjectEmpty(obj: object): boolean {
|
|
926
|
-
// @ts-ignore key is unused
|
|
927
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
928
|
-
for (const key in obj) {
|
|
929
|
-
return false;
|
|
930
|
-
}
|
|
931
|
-
return true;
|
|
932
|
-
}
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
|
-
import type {
|
|
5
|
+
import type {Binding, CompositeShaderType, UniformValue} from '@luma.gl/core';
|
|
6
|
+
import type {ShaderModuleUniformValue} from '@luma.gl/shadertools';
|
|
6
7
|
import {isNumericArray} from '@math.gl/types';
|
|
7
8
|
|
|
8
9
|
export function isUniformValue(value: unknown): value is UniformValue {
|
|
@@ -11,19 +12,20 @@ export function isUniformValue(value: unknown): value is UniformValue {
|
|
|
11
12
|
|
|
12
13
|
type UniformsAndBindings = {
|
|
13
14
|
bindings: Record<string, Binding>;
|
|
14
|
-
uniforms: Record<string,
|
|
15
|
+
uniforms: Record<string, ShaderModuleUniformValue>;
|
|
15
16
|
};
|
|
16
17
|
|
|
17
18
|
export function splitUniformsAndBindings(
|
|
18
|
-
uniforms: Record<string, Binding |
|
|
19
|
+
uniforms: Record<string, Binding | ShaderModuleUniformValue>,
|
|
20
|
+
uniformTypes: Readonly<Record<string, CompositeShaderType>> = {}
|
|
19
21
|
): UniformsAndBindings {
|
|
20
22
|
const result: UniformsAndBindings = {bindings: {}, uniforms: {}};
|
|
21
23
|
Object.keys(uniforms).forEach(name => {
|
|
22
24
|
const uniform = uniforms[name];
|
|
23
|
-
if (isUniformValue(uniform)) {
|
|
24
|
-
result.uniforms[name] = uniform;
|
|
25
|
+
if (Object.prototype.hasOwnProperty.call(uniformTypes, name) || isUniformValue(uniform)) {
|
|
26
|
+
result.uniforms[name] = uniform as ShaderModuleUniformValue;
|
|
25
27
|
} else {
|
|
26
|
-
result.bindings[name] = uniform;
|
|
28
|
+
result.bindings[name] = uniform as Binding;
|
|
27
29
|
}
|
|
28
30
|
});
|
|
29
31
|
|