@luma.gl/engine 9.1.9 → 9.2.0-alpha.2
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/README.md +5 -0
- package/dist/animation-loop/animation-loop.d.ts +12 -12
- package/dist/animation-loop/animation-loop.d.ts.map +1 -1
- package/dist/animation-loop/animation-loop.js +26 -62
- package/dist/animation-loop/animation-loop.js.map +1 -1
- package/dist/animation-loop/animation-props.d.ts +3 -4
- package/dist/animation-loop/animation-props.d.ts.map +1 -1
- package/dist/animation-loop/make-animation-loop.d.ts +4 -1
- package/dist/animation-loop/make-animation-loop.d.ts.map +1 -1
- package/dist/animation-loop/make-animation-loop.js +39 -7
- package/dist/animation-loop/make-animation-loop.js.map +1 -1
- package/dist/async-texture/async-texture.d.ts +106 -2
- package/dist/async-texture/async-texture.d.ts.map +1 -1
- package/dist/async-texture/async-texture.js +281 -13
- package/dist/async-texture/async-texture.js.map +1 -1
- package/dist/compute/computation.d.ts +1 -1
- package/dist/compute/computation.d.ts.map +1 -1
- package/dist/compute/computation.js +2 -2
- package/dist/compute/computation.js.map +1 -1
- package/dist/compute/swap.d.ts.map +1 -1
- package/dist/compute/swap.js +6 -2
- package/dist/compute/swap.js.map +1 -1
- package/dist/compute/texture-transform.d.ts.map +1 -1
- package/dist/compute/texture-transform.js +4 -2
- package/dist/compute/texture-transform.js.map +1 -1
- package/dist/debug/copy-texture-to-image.d.ts +23 -1
- package/dist/debug/copy-texture-to-image.d.ts.map +1 -1
- package/dist/debug/copy-texture-to-image.js +37 -1
- package/dist/debug/copy-texture-to-image.js.map +1 -1
- package/dist/dist.dev.js +566 -232
- package/dist/dist.min.js +26 -26
- package/dist/factories/pipeline-factory.d.ts +11 -1
- package/dist/factories/pipeline-factory.d.ts.map +1 -1
- package/dist/factories/pipeline-factory.js +107 -25
- package/dist/factories/pipeline-factory.js.map +1 -1
- package/dist/factories/shader-factory.d.ts +5 -1
- package/dist/factories/shader-factory.d.ts.map +1 -1
- package/dist/factories/shader-factory.js +40 -6
- package/dist/factories/shader-factory.js.map +1 -1
- package/dist/geometries/cube-geometry.d.ts +3 -3
- package/dist/geometries/cube-geometry.d.ts.map +1 -1
- package/dist/geometry/geometry.d.ts.map +1 -1
- package/dist/geometry/geometry.js +3 -2
- package/dist/geometry/geometry.js.map +1 -1
- package/dist/index.cjs +581 -251
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/model/model.d.ts +4 -25
- package/dist/model/model.d.ts.map +1 -1
- package/dist/model/model.js +26 -71
- package/dist/model/model.js.map +1 -1
- package/dist/models/billboard-texture-model.d.ts.map +1 -1
- package/dist/models/billboard-texture-model.js +6 -4
- package/dist/models/billboard-texture-model.js.map +1 -1
- package/dist/modules/picking/legacy-picking-manager.d.ts +1 -1
- package/dist/modules/picking/legacy-picking-manager.d.ts.map +1 -1
- package/dist/modules/picking/legacy-picking-manager.js +1 -1
- package/dist/modules/picking/legacy-picking-manager.js.map +1 -1
- package/dist/modules/picking/picking-manager.d.ts +2 -2
- package/dist/modules/picking/picking-manager.d.ts.map +1 -1
- package/dist/modules/picking/picking-manager.js +2 -2
- package/dist/modules/picking/picking-manager.js.map +1 -1
- package/dist/passes/get-fragment-shader.js +2 -2
- package/dist/passes/shader-pass-renderer.d.ts +4 -4
- package/dist/passes/shader-pass-renderer.d.ts.map +1 -1
- package/dist/passes/shader-pass-renderer.js +15 -5
- package/dist/passes/shader-pass-renderer.js.map +1 -1
- package/dist/shader-inputs.js +1 -1
- package/dist/shader-inputs.js.map +1 -1
- package/dist/utils/buffer-layout-helper.d.ts +12 -0
- package/dist/utils/buffer-layout-helper.d.ts.map +1 -0
- package/dist/utils/buffer-layout-helper.js +41 -0
- package/dist/utils/buffer-layout-helper.js.map +1 -0
- package/dist/utils/buffer-layout-order.d.ts +3 -0
- package/dist/utils/buffer-layout-order.d.ts.map +1 -0
- package/dist/utils/buffer-layout-order.js +16 -0
- package/dist/utils/buffer-layout-order.js.map +1 -0
- package/package.json +4 -4
- package/src/animation-loop/animation-loop.ts +31 -71
- package/src/animation-loop/animation-props.ts +3 -5
- package/src/animation-loop/make-animation-loop.ts +41 -9
- package/src/async-texture/async-texture.ts +386 -23
- package/src/async-texture/texture-setters.ts.disabled +296 -0
- package/src/compute/computation.ts +3 -3
- package/src/compute/swap.ts +7 -2
- package/src/compute/texture-transform.ts +4 -2
- package/src/debug/copy-texture-to-image.ts +52 -2
- package/src/factories/pipeline-factory.ts +122 -26
- package/src/factories/shader-factory.ts +43 -7
- package/src/geometry/geometry.ts +3 -2
- package/src/index.ts +12 -0
- package/src/model/model.ts +31 -86
- package/src/models/billboard-texture-model.ts +6 -4
- package/src/modules/picking/legacy-picking-manager.ts +2 -2
- package/src/modules/picking/picking-manager.ts +3 -3
- package/src/passes/get-fragment-shader.ts +2 -2
- package/src/passes/shader-pass-renderer.ts +18 -8
- package/src/shader-inputs.ts +1 -1
- package/src/utils/buffer-layout-helper.ts +51 -0
- package/src/utils/buffer-layout-order.ts +26 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
|
-
import {Device, Shader, ShaderProps} from '@luma.gl/core';
|
|
5
|
+
import {Device, Shader, ShaderProps, log} from '@luma.gl/core';
|
|
6
6
|
|
|
7
7
|
/** Manages a cached pool of Shaders for reuse. */
|
|
8
8
|
export class ShaderFactory {
|
|
@@ -10,22 +10,39 @@ export class ShaderFactory {
|
|
|
10
10
|
|
|
11
11
|
/** Returns the default ShaderFactory for the given {@link Device}, creating one if necessary. */
|
|
12
12
|
static getDefaultShaderFactory(device: Device): ShaderFactory {
|
|
13
|
-
device._lumaData
|
|
14
|
-
return device._lumaData
|
|
13
|
+
device._lumaData['defaultShaderFactory'] ||= new ShaderFactory(device);
|
|
14
|
+
return device._lumaData['defaultShaderFactory'] as ShaderFactory;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
public readonly device: Device;
|
|
18
|
+
readonly cachingEnabled: boolean;
|
|
18
19
|
readonly destroyPolicy: 'unused' | 'never';
|
|
20
|
+
readonly debug: boolean;
|
|
21
|
+
|
|
19
22
|
private readonly _cache: Record<string, {shader: Shader; useCount: number}> = {};
|
|
20
23
|
|
|
24
|
+
get [Symbol.toStringTag](): string {
|
|
25
|
+
return 'ShaderFactory';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
toString(): string {
|
|
29
|
+
return `${this[Symbol.toStringTag]}(${this.device.id})`;
|
|
30
|
+
}
|
|
31
|
+
|
|
21
32
|
/** @internal */
|
|
22
33
|
constructor(device: Device) {
|
|
23
34
|
this.device = device;
|
|
24
|
-
this.
|
|
35
|
+
this.cachingEnabled = device.props._cacheShaders;
|
|
36
|
+
this.destroyPolicy = device.props._cacheDestroyPolicy;
|
|
37
|
+
this.debug = true; // device.props.debugFactories;
|
|
25
38
|
}
|
|
26
39
|
|
|
27
40
|
/** Requests a {@link Shader} from the cache, creating a new Shader only if necessary. */
|
|
28
41
|
createShader(props: ShaderProps): Shader {
|
|
42
|
+
if (!this.cachingEnabled) {
|
|
43
|
+
return this.device.createShader(props);
|
|
44
|
+
}
|
|
45
|
+
|
|
29
46
|
const key = this._hashShader(props);
|
|
30
47
|
|
|
31
48
|
let cacheEntry = this._cache[key];
|
|
@@ -34,15 +51,27 @@ export class ShaderFactory {
|
|
|
34
51
|
...props,
|
|
35
52
|
id: props.id ? `${props.id}-cached` : undefined
|
|
36
53
|
});
|
|
37
|
-
this._cache[key] = cacheEntry = {shader, useCount:
|
|
54
|
+
this._cache[key] = cacheEntry = {shader, useCount: 1};
|
|
55
|
+
if (this.debug) {
|
|
56
|
+
log.warn(`${this}: Created new shader ${shader.id}`)();
|
|
57
|
+
}
|
|
58
|
+
} else {
|
|
59
|
+
cacheEntry.useCount++;
|
|
60
|
+
if (this.debug) {
|
|
61
|
+
log.warn(`${this}: Reusing shader ${cacheEntry.shader.id} count=${cacheEntry.useCount}`)();
|
|
62
|
+
}
|
|
38
63
|
}
|
|
39
64
|
|
|
40
|
-
cacheEntry.useCount++;
|
|
41
65
|
return cacheEntry.shader;
|
|
42
66
|
}
|
|
43
67
|
|
|
44
68
|
/** Releases a previously-requested {@link Shader}, destroying it if no users remain. */
|
|
45
69
|
release(shader: Shader): void {
|
|
70
|
+
if (!this.cachingEnabled) {
|
|
71
|
+
shader.destroy();
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
46
75
|
const key = this._hashShader(shader);
|
|
47
76
|
const cacheEntry = this._cache[key];
|
|
48
77
|
if (cacheEntry) {
|
|
@@ -51,14 +80,21 @@ export class ShaderFactory {
|
|
|
51
80
|
if (this.destroyPolicy === 'unused') {
|
|
52
81
|
delete this._cache[key];
|
|
53
82
|
cacheEntry.shader.destroy();
|
|
83
|
+
if (this.debug) {
|
|
84
|
+
log.warn(`${this}: Releasing shader ${shader.id}, destroyed`)();
|
|
85
|
+
}
|
|
54
86
|
}
|
|
87
|
+
} else if (cacheEntry.useCount < 0) {
|
|
88
|
+
throw new Error(`ShaderFactory: Shader ${shader.id} released too many times`);
|
|
89
|
+
} else if (this.debug) {
|
|
90
|
+
log.warn(`${this}: Releasing shader ${shader.id} count=${cacheEntry.useCount}`)();
|
|
55
91
|
}
|
|
56
92
|
}
|
|
57
93
|
}
|
|
58
94
|
|
|
59
95
|
// PRIVATE
|
|
60
96
|
|
|
61
|
-
|
|
97
|
+
protected _hashShader(value: Shader | ShaderProps): string {
|
|
62
98
|
return `${value.stage}:${value.source}`;
|
|
63
99
|
}
|
|
64
100
|
}
|
package/src/geometry/geometry.ts
CHANGED
|
@@ -86,9 +86,9 @@ export class Geometry {
|
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
if (this.indices && this.indices
|
|
89
|
+
if (this.indices && this.indices['isIndexed'] !== undefined) {
|
|
90
90
|
this.indices = Object.assign({}, this.indices);
|
|
91
|
-
delete this.indices
|
|
91
|
+
delete this.indices['isIndexed'];
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
this.vertexCount = vertexCount || this._calculateVertexCount(this.attributes, this.indices);
|
|
@@ -103,6 +103,7 @@ export class Geometry {
|
|
|
103
103
|
* TODO Geometry types are a mess
|
|
104
104
|
*/
|
|
105
105
|
getAttributes(): GeometryAttributes {
|
|
106
|
+
// @ts-ignore
|
|
106
107
|
return this.indices ? {indices: this.indices, ...this.attributes} : this.attributes;
|
|
107
108
|
}
|
|
108
109
|
|
package/src/index.ts
CHANGED
|
@@ -80,6 +80,18 @@ export {SwapFramebuffers} from './compute/swap';
|
|
|
80
80
|
export type {ComputationProps} from './compute/computation';
|
|
81
81
|
export {Computation} from './compute/computation';
|
|
82
82
|
|
|
83
|
+
export type {
|
|
84
|
+
TextureCubeFace,
|
|
85
|
+
TextureImageData,
|
|
86
|
+
TextureData,
|
|
87
|
+
Texture1DData,
|
|
88
|
+
Texture2DData,
|
|
89
|
+
Texture3DData,
|
|
90
|
+
TextureCubeData,
|
|
91
|
+
TextureArrayData,
|
|
92
|
+
TextureCubeArrayData
|
|
93
|
+
} from './async-texture/async-texture';
|
|
94
|
+
|
|
83
95
|
export type {AsyncTextureProps} from './async-texture/async-texture';
|
|
84
96
|
export {AsyncTexture} from './async-texture/async-texture';
|
|
85
97
|
|
package/src/model/model.ts
CHANGED
|
@@ -13,7 +13,6 @@ import type {
|
|
|
13
13
|
TransformFeedback,
|
|
14
14
|
AttributeInfo,
|
|
15
15
|
Binding,
|
|
16
|
-
UniformValue,
|
|
17
16
|
PrimitiveTopology
|
|
18
17
|
} from '@luma.gl/core';
|
|
19
18
|
import {
|
|
@@ -27,10 +26,8 @@ import {
|
|
|
27
26
|
RenderPass,
|
|
28
27
|
UniformStore,
|
|
29
28
|
log,
|
|
30
|
-
|
|
31
|
-
getAttributeInfosFromLayouts
|
|
32
|
-
_BufferLayoutHelper,
|
|
33
|
-
sortedBufferLayoutByShaderSourceLocations
|
|
29
|
+
getTypedArrayConstructor,
|
|
30
|
+
getAttributeInfosFromLayouts
|
|
34
31
|
} from '@luma.gl/core';
|
|
35
32
|
|
|
36
33
|
import type {ShaderModule, PlatformInfo} from '@luma.gl/shadertools';
|
|
@@ -43,25 +40,24 @@ import {ShaderFactory} from '../factories/shader-factory';
|
|
|
43
40
|
import {getDebugTableForShaderLayout} from '../debug/debug-shader-layout';
|
|
44
41
|
import {debugFramebuffer} from '../debug/debug-framebuffer';
|
|
45
42
|
import {deepEqual} from '../utils/deep-equal';
|
|
43
|
+
import {BufferLayoutHelper} from '../utils/buffer-layout-helper';
|
|
44
|
+
import {sortedBufferLayoutByShaderSourceLocations} from '../utils/buffer-layout-order';
|
|
46
45
|
import {uid} from '../utils/uid';
|
|
47
46
|
import {ShaderInputs} from '../shader-inputs';
|
|
48
|
-
// import type {AsyncTextureProps} from '../async-texture/async-texture';
|
|
49
47
|
import {AsyncTexture} from '../async-texture/async-texture';
|
|
50
48
|
|
|
51
|
-
import {splitUniformsAndBindings} from './split-uniforms-and-bindings';
|
|
52
|
-
|
|
53
49
|
const LOG_DRAW_PRIORITY = 2;
|
|
54
50
|
const LOG_DRAW_TIMEOUT = 10000;
|
|
55
51
|
|
|
56
52
|
export type ModelProps = Omit<RenderPipelineProps, 'vs' | 'fs' | 'bindings'> & {
|
|
57
53
|
source?: string;
|
|
58
|
-
vs
|
|
59
|
-
fs
|
|
54
|
+
vs?: string | null;
|
|
55
|
+
fs?: string | null;
|
|
60
56
|
|
|
61
57
|
/** shadertool shader modules (added to shader code) */
|
|
62
58
|
modules?: ShaderModule[];
|
|
63
59
|
/** Shadertool module defines (configures shader code)*/
|
|
64
|
-
defines?: Record<string,
|
|
60
|
+
defines?: Record<string, boolean>;
|
|
65
61
|
// TODO - injections, hooks etc?
|
|
66
62
|
|
|
67
63
|
/** Shader inputs, used to generated uniform buffers and bindings */
|
|
@@ -95,9 +91,6 @@ export type ModelProps = Omit<RenderPipelineProps, 'vs' | 'fs' | 'bindings'> & {
|
|
|
95
91
|
|
|
96
92
|
transformFeedback?: TransformFeedback;
|
|
97
93
|
|
|
98
|
-
/** Mapped uniforms for shadertool modules */
|
|
99
|
-
moduleSettings?: Record<string, Record<string, any>>;
|
|
100
|
-
|
|
101
94
|
/** Show shader source in browser? */
|
|
102
95
|
debugShaders?: 'never' | 'errors' | 'warnings' | 'always';
|
|
103
96
|
|
|
@@ -128,7 +121,6 @@ export class Model {
|
|
|
128
121
|
userData: {},
|
|
129
122
|
defines: {},
|
|
130
123
|
modules: [],
|
|
131
|
-
moduleSettings: undefined!,
|
|
132
124
|
geometry: null,
|
|
133
125
|
indexBuffer: null,
|
|
134
126
|
attributes: {},
|
|
@@ -188,8 +180,6 @@ export class Model {
|
|
|
188
180
|
constantAttributes: Record<string, TypedArray> = {};
|
|
189
181
|
/** Bindings (textures, samplers, uniform buffers) */
|
|
190
182
|
bindings: Record<string, Binding | AsyncTexture> = {};
|
|
191
|
-
/** Sets uniforms @deprecated Use uniform buffers and setBindings() for portability*/
|
|
192
|
-
uniforms: Record<string, UniformValue> = {};
|
|
193
183
|
|
|
194
184
|
/**
|
|
195
185
|
* VertexArray
|
|
@@ -212,7 +202,6 @@ export class Model {
|
|
|
212
202
|
|
|
213
203
|
_attributeInfos: Record<string, AttributeInfo> = {};
|
|
214
204
|
_gpuGeometry: GPUGeometry | null = null;
|
|
215
|
-
private _getModuleUniforms: (props?: Record<string, Record<string, any>>) => Record<string, any>;
|
|
216
205
|
private props: Required<ModelProps>;
|
|
217
206
|
|
|
218
207
|
_pipelineNeedsUpdate: string | false = 'newly created';
|
|
@@ -309,7 +298,8 @@ export class Model {
|
|
|
309
298
|
this.pipeline = this._updatePipeline();
|
|
310
299
|
|
|
311
300
|
this.vertexArray = device.createVertexArray({
|
|
312
|
-
|
|
301
|
+
shaderLayout: this.pipeline.shaderLayout,
|
|
302
|
+
bufferLayout: this.pipeline.bufferLayout
|
|
313
303
|
});
|
|
314
304
|
|
|
315
305
|
// Now we can apply geometry attributes
|
|
@@ -340,13 +330,6 @@ export class Model {
|
|
|
340
330
|
if (props.bindings) {
|
|
341
331
|
this.setBindings(props.bindings);
|
|
342
332
|
}
|
|
343
|
-
if (props.uniforms) {
|
|
344
|
-
this.setUniformsWebGL(props.uniforms);
|
|
345
|
-
}
|
|
346
|
-
if (props.moduleSettings) {
|
|
347
|
-
// log.warn('Model.props.moduleSettings is deprecated. Use Model.shaderInputs.setProps()')();
|
|
348
|
-
this.updateModuleSettingsWebGL(props.moduleSettings);
|
|
349
|
-
}
|
|
350
333
|
if (props.transformFeedback) {
|
|
351
334
|
this.transformFeedback = props.transformFeedback;
|
|
352
335
|
}
|
|
@@ -356,16 +339,19 @@ export class Model {
|
|
|
356
339
|
}
|
|
357
340
|
|
|
358
341
|
destroy(): void {
|
|
359
|
-
if (this._destroyed)
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
this.shaderFactory.release(this.pipeline.
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
342
|
+
if (!this._destroyed) {
|
|
343
|
+
// Release pipeline before we destroy the shaders used by the pipeline
|
|
344
|
+
this.pipelineFactory.release(this.pipeline);
|
|
345
|
+
// Release the shaders
|
|
346
|
+
this.shaderFactory.release(this.pipeline.vs);
|
|
347
|
+
if (this.pipeline.fs) {
|
|
348
|
+
this.shaderFactory.release(this.pipeline.fs);
|
|
349
|
+
}
|
|
350
|
+
this._uniformStore.destroy();
|
|
351
|
+
// TODO - mark resource as managed and destroyIfManaged() ?
|
|
352
|
+
this._gpuGeometry?.destroy();
|
|
353
|
+
this._destroyed = true;
|
|
354
|
+
}
|
|
369
355
|
}
|
|
370
356
|
|
|
371
357
|
// Draw call
|
|
@@ -425,9 +411,6 @@ export class Model {
|
|
|
425
411
|
this.pipeline.setBindings(syncBindings, {
|
|
426
412
|
disableWarnings: this.props.disableWarnings
|
|
427
413
|
});
|
|
428
|
-
if (!isObjectEmpty(this.uniforms)) {
|
|
429
|
-
this.pipeline.setUniformsWebGL(this.uniforms);
|
|
430
|
-
}
|
|
431
414
|
|
|
432
415
|
const {indexBuffer} = this.vertexArray;
|
|
433
416
|
const indexCount = indexBuffer
|
|
@@ -476,7 +459,7 @@ export class Model {
|
|
|
476
459
|
const gpuGeometry = geometry && makeGPUGeometry(this.device, geometry);
|
|
477
460
|
if (gpuGeometry) {
|
|
478
461
|
this.setTopology(gpuGeometry.topology || 'triangle-list');
|
|
479
|
-
const bufferLayoutHelper = new
|
|
462
|
+
const bufferLayoutHelper = new BufferLayoutHelper(this.bufferLayout);
|
|
480
463
|
this.bufferLayout = bufferLayoutHelper.mergeBufferLayouts(
|
|
481
464
|
gpuGeometry.bufferLayout,
|
|
482
465
|
this.bufferLayout
|
|
@@ -504,7 +487,7 @@ export class Model {
|
|
|
504
487
|
* @note Triggers a pipeline rebuild / pipeline cache fetch
|
|
505
488
|
*/
|
|
506
489
|
setBufferLayout(bufferLayout: BufferLayout[]): void {
|
|
507
|
-
const bufferLayoutHelper = new
|
|
490
|
+
const bufferLayoutHelper = new BufferLayoutHelper(this.bufferLayout);
|
|
508
491
|
this.bufferLayout = this._gpuGeometry
|
|
509
492
|
? bufferLayoutHelper.mergeBufferLayouts(bufferLayout, this._gpuGeometry.bufferLayout)
|
|
510
493
|
: bufferLayout;
|
|
@@ -516,7 +499,8 @@ export class Model {
|
|
|
516
499
|
// vertex array needs to be updated if we update buffer layout,
|
|
517
500
|
// but not if we update parameters
|
|
518
501
|
this.vertexArray = this.device.createVertexArray({
|
|
519
|
-
|
|
502
|
+
shaderLayout: this.pipeline.shaderLayout,
|
|
503
|
+
bufferLayout: this.pipeline.bufferLayout
|
|
520
504
|
});
|
|
521
505
|
|
|
522
506
|
// Reapply geometry attributes to the new vertex array
|
|
@@ -615,7 +599,7 @@ export class Model {
|
|
|
615
599
|
*/
|
|
616
600
|
setAttributes(buffers: Record<string, Buffer>, options?: {disableWarnings?: boolean}): void {
|
|
617
601
|
const disableWarnings = options?.disableWarnings ?? this.props.disableWarnings;
|
|
618
|
-
if (buffers
|
|
602
|
+
if (buffers['indices']) {
|
|
619
603
|
log.warn(
|
|
620
604
|
`Model:${this.id} setAttributes() - indexBuffer should be set using setIndexBuffer()`
|
|
621
605
|
)();
|
|
@@ -627,7 +611,7 @@ export class Model {
|
|
|
627
611
|
this.pipeline.shaderLayout,
|
|
628
612
|
this.bufferLayout
|
|
629
613
|
);
|
|
630
|
-
const bufferLayoutHelper = new
|
|
614
|
+
const bufferLayoutHelper = new BufferLayoutHelper(this.bufferLayout);
|
|
631
615
|
|
|
632
616
|
// Check if all buffers have a layout
|
|
633
617
|
for (const [bufferName, buffer] of Object.entries(buffers)) {
|
|
@@ -689,42 +673,7 @@ export class Model {
|
|
|
689
673
|
this.setNeedsRedraw('constants');
|
|
690
674
|
}
|
|
691
675
|
|
|
692
|
-
//
|
|
693
|
-
|
|
694
|
-
/**
|
|
695
|
-
* Sets individual uniforms
|
|
696
|
-
* @deprecated WebGL only, use uniform buffers for portability
|
|
697
|
-
* @param uniforms
|
|
698
|
-
*/
|
|
699
|
-
setUniforms(uniforms: Record<string, UniformValue>): void {
|
|
700
|
-
this.setUniformsWebGL(uniforms);
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
/**
|
|
704
|
-
* Sets individual uniforms
|
|
705
|
-
* @deprecated WebGL only, use uniform buffers for portability
|
|
706
|
-
* @param uniforms
|
|
707
|
-
*/
|
|
708
|
-
setUniformsWebGL(uniforms: Record<string, UniformValue>): void {
|
|
709
|
-
if (!isObjectEmpty(uniforms)) {
|
|
710
|
-
this.pipeline.setUniformsWebGL(uniforms);
|
|
711
|
-
Object.assign(this.uniforms, uniforms);
|
|
712
|
-
}
|
|
713
|
-
this.setNeedsRedraw('uniforms');
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
/**
|
|
717
|
-
* @deprecated Updates shader module settings (which results in uniforms being set)
|
|
718
|
-
*/
|
|
719
|
-
updateModuleSettingsWebGL(props: Record<string, any>): void {
|
|
720
|
-
// log.warn('Model.updateModuleSettings is deprecated. Use Model.shaderInputs.setProps()')();
|
|
721
|
-
const {bindings, uniforms} = splitUniformsAndBindings(this._getModuleUniforms(props));
|
|
722
|
-
Object.assign(this.bindings, bindings);
|
|
723
|
-
Object.assign(this.uniforms, uniforms);
|
|
724
|
-
this.setNeedsRedraw('moduleSettings');
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
// Internal methods
|
|
676
|
+
// INTERNAL METHODS
|
|
728
677
|
|
|
729
678
|
/** Check that bindings are loaded. Returns id of first binding that is still loading. */
|
|
730
679
|
_areBindingsLoading(): string | false {
|
|
@@ -890,10 +839,6 @@ export class Model {
|
|
|
890
839
|
log.table(LOG_DRAW_PRIORITY, shaderLayoutTable)();
|
|
891
840
|
|
|
892
841
|
const uniformTable = this.shaderInputs.getDebugTable();
|
|
893
|
-
// Add any global uniforms
|
|
894
|
-
for (const [name, value] of Object.entries(this.uniforms)) {
|
|
895
|
-
uniformTable[name] = {value};
|
|
896
|
-
}
|
|
897
842
|
log.table(LOG_DRAW_PRIORITY, uniformTable)();
|
|
898
843
|
|
|
899
844
|
const attributeTable = this._getAttributeDebugTable();
|
|
@@ -940,7 +885,7 @@ export class Model {
|
|
|
940
885
|
indexBuffer.indexType === 'uint32'
|
|
941
886
|
? new Uint32Array(indexBuffer.debugData)
|
|
942
887
|
: new Uint16Array(indexBuffer.debugData);
|
|
943
|
-
table
|
|
888
|
+
table['indices'] = {
|
|
944
889
|
name: 'indices',
|
|
945
890
|
type: indexBuffer.indexType,
|
|
946
891
|
values: values.toString()
|
|
@@ -951,7 +896,7 @@ export class Model {
|
|
|
951
896
|
|
|
952
897
|
// TODO - fix typing of luma data types
|
|
953
898
|
_getBufferOrConstantValues(attribute: Buffer | TypedArray, dataType: any): string {
|
|
954
|
-
const TypedArrayConstructor =
|
|
899
|
+
const TypedArrayConstructor = getTypedArrayConstructor(dataType);
|
|
955
900
|
const typedArray =
|
|
956
901
|
attribute instanceof Buffer ? new TypedArrayConstructor(attribute.debugData) : attribute;
|
|
957
902
|
return typedArray.toString();
|
|
@@ -11,7 +11,7 @@ const BACKGROUND_FS_WGSL = /* wgsl */ `\
|
|
|
11
11
|
@group(0) @binding(1) var backgroundTextureSampler: sampler;
|
|
12
12
|
|
|
13
13
|
fn billboardTexture_getTextureUV(coordinates: vec2<f32>) -> vec2<f32> {
|
|
14
|
-
let iTexSize: vec2<u32> = textureDimensions(backgroundTexture, 0)
|
|
14
|
+
let iTexSize: vec2<u32> = textureDimensions(backgroundTexture, 0);
|
|
15
15
|
let texSize: vec2<f32> = vec2<f32>(f32(iTexSize.x), f32(iTexSize.y));
|
|
16
16
|
var position: vec2<f32> = coordinates.xy / texSize;
|
|
17
17
|
return position;
|
|
@@ -32,7 +32,7 @@ uniform sampler2D backgroundTexture;
|
|
|
32
32
|
out vec4 fragColor;
|
|
33
33
|
|
|
34
34
|
vec2 billboardTexture_getTextureUV() {
|
|
35
|
-
ivec2 iTexSize =
|
|
35
|
+
ivec2 iTexSize = textureSize(backgroundTexture, 0);
|
|
36
36
|
vec2 texSize = vec2(float(iTexSize.x), float(iTexSize.y));
|
|
37
37
|
vec2 position = gl_FragCoord.xy / texSize;
|
|
38
38
|
return position;
|
|
@@ -67,14 +67,13 @@ export class BackgroundTextureModel extends ClipSpace {
|
|
|
67
67
|
fs: BACKGROUND_FS,
|
|
68
68
|
parameters: {
|
|
69
69
|
depthWriteEnabled: false,
|
|
70
|
-
depthCompare: 'always',
|
|
71
70
|
...(props.blend
|
|
72
71
|
? {
|
|
73
72
|
blend: true,
|
|
74
73
|
blendColorOperation: 'add',
|
|
75
74
|
blendAlphaOperation: 'add',
|
|
76
75
|
blendColorSrcFactor: 'one',
|
|
77
|
-
blendColorDstFactor: 'one-minus-src
|
|
76
|
+
blendColorDstFactor: 'one-minus-src',
|
|
78
77
|
blendAlphaSrcFactor: 'one',
|
|
79
78
|
blendAlphaDstFactor: 'one-minus-src-alpha'
|
|
80
79
|
}
|
|
@@ -82,6 +81,9 @@ export class BackgroundTextureModel extends ClipSpace {
|
|
|
82
81
|
}
|
|
83
82
|
});
|
|
84
83
|
|
|
84
|
+
if (!props.backgroundTexture) {
|
|
85
|
+
throw new Error('BackgroundTextureModel requires a backgroundTexture prop');
|
|
86
|
+
}
|
|
85
87
|
this.setTexture(props.backgroundTexture);
|
|
86
88
|
}
|
|
87
89
|
|
|
@@ -42,7 +42,7 @@ export class LegacyPickingManager {
|
|
|
42
42
|
/** Prepare for rendering picking colors */
|
|
43
43
|
beginRenderPass() {
|
|
44
44
|
const framebuffer = this.getFramebuffer();
|
|
45
|
-
framebuffer.resize(this.device.getCanvasContext().
|
|
45
|
+
framebuffer.resize(this.device.getCanvasContext().getDevicePixelSize());
|
|
46
46
|
|
|
47
47
|
this.shaderInputs.setProps({picking: {isActive: true}});
|
|
48
48
|
|
|
@@ -90,7 +90,7 @@ export class LegacyPickingManager {
|
|
|
90
90
|
* Get pick position in device pixel range
|
|
91
91
|
* use the center pixel location in device pixel range
|
|
92
92
|
*/
|
|
93
|
-
getPickPosition(mousePosition: number
|
|
93
|
+
getPickPosition(mousePosition: [number, number]): [number, number] {
|
|
94
94
|
const devicePixels = this.device.getCanvasContext().cssToDevicePixels(mousePosition);
|
|
95
95
|
const pickX = devicePixels.x + Math.floor(devicePixels.width / 2);
|
|
96
96
|
const pickY = devicePixels.y + Math.floor(devicePixels.height / 2);
|
|
@@ -67,7 +67,7 @@ export class PickingManager {
|
|
|
67
67
|
/** Prepare for rendering picking colors */
|
|
68
68
|
beginRenderPass() {
|
|
69
69
|
const framebuffer = this.getFramebuffer();
|
|
70
|
-
framebuffer.resize(this.device.getDefaultCanvasContext().
|
|
70
|
+
framebuffer.resize(this.device.getDefaultCanvasContext().getDevicePixelSize());
|
|
71
71
|
|
|
72
72
|
this.props.shaderInputs?.setProps({picking: {isActive: true}});
|
|
73
73
|
|
|
@@ -80,7 +80,7 @@ export class PickingManager {
|
|
|
80
80
|
return pickingPass;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
|
|
83
|
+
async updatePickInfo(mousePosition: [number, number]): Promise<PickInfo | null> {
|
|
84
84
|
const framebuffer = this.getFramebuffer();
|
|
85
85
|
|
|
86
86
|
// use the center pixel location in device pixel range
|
|
@@ -128,7 +128,7 @@ export class PickingManager {
|
|
|
128
128
|
* Get pick position in device pixel range
|
|
129
129
|
* use the center pixel location in device pixel range
|
|
130
130
|
*/
|
|
131
|
-
getPickPosition(mousePosition: number
|
|
131
|
+
getPickPosition(mousePosition: [number, number]): [number, number] {
|
|
132
132
|
const devicePixels = this.device.getDefaultCanvasContext().cssToDevicePixels(mousePosition);
|
|
133
133
|
const pickX = devicePixels.x + Math.floor(devicePixels.width / 2);
|
|
134
134
|
const pickY = devicePixels.y + Math.floor(devicePixels.height / 2);
|
|
@@ -37,11 +37,11 @@ export function getFragmentShaderForRenderPass(options: {
|
|
|
37
37
|
function getFilterShaderWGSL(func: string) {
|
|
38
38
|
return /* wgsl */ `\
|
|
39
39
|
// Binding 0:1 is reserved for shader passes
|
|
40
|
-
@group(0) @binding(0) var<uniform> brightnessContrast : brightnessContrastUniforms;
|
|
40
|
+
// @group(0) @binding(0) var<uniform> brightnessContrast : brightnessContrastUniforms;
|
|
41
41
|
@group(0) @binding(1) var texture: texture_2d<f32>;
|
|
42
42
|
@group(0) @binding(2) var sampler: sampler;
|
|
43
43
|
|
|
44
|
-
struct FragmentInputs
|
|
44
|
+
struct FragmentInputs {
|
|
45
45
|
@location(0) fragUV: vec2f,
|
|
46
46
|
@location(1) fragPosition: vec4f,
|
|
47
47
|
@location(2) fragCoordinate: vec4f
|
|
@@ -44,9 +44,9 @@ export class ShaderPassRenderer {
|
|
|
44
44
|
);
|
|
45
45
|
this.shaderInputs = props.shaderInputs || new ShaderInputs(modules);
|
|
46
46
|
|
|
47
|
-
const size = device.getCanvasContext().
|
|
47
|
+
const size = device.getCanvasContext().getDrawingBufferSize();
|
|
48
48
|
this.swapFramebuffers = new SwapFramebuffers(device, {
|
|
49
|
-
colorAttachments: [
|
|
49
|
+
colorAttachments: [device.preferredColorFormat],
|
|
50
50
|
width: size[0],
|
|
51
51
|
height: size[1]
|
|
52
52
|
});
|
|
@@ -99,7 +99,7 @@ void main() {
|
|
|
99
99
|
// this.props.passes.forEach(pass => pass.resize(width, height));
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
renderToScreen(options: {sourceTexture: AsyncTexture; uniforms
|
|
102
|
+
renderToScreen(options: {sourceTexture: AsyncTexture; uniforms?: any; bindings?: any}): boolean {
|
|
103
103
|
// Run the shader passes and generate an output texture
|
|
104
104
|
const outputTexture = this.renderToTexture(options);
|
|
105
105
|
if (!outputTexture) {
|
|
@@ -107,7 +107,16 @@ void main() {
|
|
|
107
107
|
return false;
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
const
|
|
110
|
+
const framebuffer = this.device
|
|
111
|
+
.getDefaultCanvasContext()
|
|
112
|
+
// @ts-expect-error TODO - remove after republish
|
|
113
|
+
.getCurrentFramebuffer({depthStencilAttachment: false});
|
|
114
|
+
const renderPass = this.device.beginRenderPass({
|
|
115
|
+
id: 'shader-pass-renderer-to-screen',
|
|
116
|
+
framebuffer,
|
|
117
|
+
clearColor: [0, 0, 0, 1],
|
|
118
|
+
clearDepth: 1
|
|
119
|
+
});
|
|
111
120
|
this.clipSpace.setBindings({sourceTexture: outputTexture});
|
|
112
121
|
this.clipSpace.draw(renderPass);
|
|
113
122
|
renderPass.end();
|
|
@@ -119,8 +128,8 @@ void main() {
|
|
|
119
128
|
*/
|
|
120
129
|
renderToTexture(options: {
|
|
121
130
|
sourceTexture: AsyncTexture;
|
|
122
|
-
uniforms
|
|
123
|
-
bindings
|
|
131
|
+
uniforms?: any;
|
|
132
|
+
bindings?: any;
|
|
124
133
|
}): Texture | null {
|
|
125
134
|
const {sourceTexture} = options;
|
|
126
135
|
if (!sourceTexture.isReady) {
|
|
@@ -134,6 +143,7 @@ void main() {
|
|
|
134
143
|
|
|
135
144
|
// Clear the current texture before we begin
|
|
136
145
|
const clearTexturePass = this.device.beginRenderPass({
|
|
146
|
+
id: 'shader-pass-renderer-clear-texture',
|
|
137
147
|
framebuffer: this.swapFramebuffers.current,
|
|
138
148
|
clearColor: [0, 0, 0, 1]
|
|
139
149
|
});
|
|
@@ -163,6 +173,7 @@ void main() {
|
|
|
163
173
|
};
|
|
164
174
|
|
|
165
175
|
const renderPass = this.device.beginRenderPass({
|
|
176
|
+
id: 'shader-pass-renderer-run-pass',
|
|
166
177
|
framebuffer: this.swapFramebuffers.next,
|
|
167
178
|
clearColor: [0, 0, 0, 1],
|
|
168
179
|
clearDepth: 1
|
|
@@ -226,8 +237,7 @@ class SubPassRenderer {
|
|
|
226
237
|
fs,
|
|
227
238
|
modules: [shaderPass],
|
|
228
239
|
parameters: {
|
|
229
|
-
depthWriteEnabled: false
|
|
230
|
-
depthCompare: 'always'
|
|
240
|
+
depthWriteEnabled: false
|
|
231
241
|
}
|
|
232
242
|
});
|
|
233
243
|
}
|
package/src/shader-inputs.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import type {Binding, UniformValue} from '@luma.gl/core';
|
|
6
6
|
import {log} from '@luma.gl/core';
|
|
7
|
-
// import type {
|
|
7
|
+
// import type {VariableShaderType, UniformValue, UniformFormat, UniformInfoDevice, Texture, Sampler} from '@luma.gl/core';
|
|
8
8
|
import {getShaderModuleDependencies, ShaderModule} from '@luma.gl/shadertools';
|
|
9
9
|
import {splitUniformsAndBindings} from './model/split-uniforms-and-bindings';
|
|
10
10
|
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// luma.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
import {log, type BufferLayout} from '@luma.gl/core';
|
|
6
|
+
|
|
7
|
+
/** BufferLayoutHelper is a helper class that should not be used directly by applications */
|
|
8
|
+
export class BufferLayoutHelper {
|
|
9
|
+
bufferLayouts: BufferLayout[];
|
|
10
|
+
|
|
11
|
+
constructor(bufferLayouts: BufferLayout[]) {
|
|
12
|
+
this.bufferLayouts = bufferLayouts;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
getBufferLayout(name: string): BufferLayout | null {
|
|
16
|
+
return this.bufferLayouts.find(layout => layout.name === name) || null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Get attribute names from a BufferLayout */
|
|
20
|
+
getAttributeNamesForBuffer(bufferLayout: BufferLayout): string[] {
|
|
21
|
+
return bufferLayout.attributes
|
|
22
|
+
? bufferLayout.attributes?.map(layout => layout.attribute)
|
|
23
|
+
: [bufferLayout.name];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
mergeBufferLayouts(
|
|
27
|
+
bufferLayouts1: BufferLayout[],
|
|
28
|
+
bufferLayouts2: BufferLayout[]
|
|
29
|
+
): BufferLayout[] {
|
|
30
|
+
const mergedLayouts = [...bufferLayouts1];
|
|
31
|
+
for (const attribute of bufferLayouts2) {
|
|
32
|
+
const index = mergedLayouts.findIndex(attribute2 => attribute2.name === attribute.name);
|
|
33
|
+
if (index < 0) {
|
|
34
|
+
mergedLayouts.push(attribute);
|
|
35
|
+
} else {
|
|
36
|
+
mergedLayouts[index] = attribute;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return mergedLayouts;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
getBufferIndex(bufferName: string): number {
|
|
43
|
+
const bufferIndex = this.bufferLayouts.findIndex(layout => layout.name === bufferName);
|
|
44
|
+
|
|
45
|
+
if (bufferIndex === -1) {
|
|
46
|
+
log.warn(`BufferLayout: Missing buffer for "${bufferName}".`)();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return bufferIndex;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// luma.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
import {type BufferLayout, type ShaderLayout} from '@luma.gl/core';
|
|
6
|
+
|
|
7
|
+
export function sortedBufferLayoutByShaderSourceLocations(
|
|
8
|
+
shaderLayout: ShaderLayout,
|
|
9
|
+
bufferLayout: BufferLayout[]
|
|
10
|
+
): BufferLayout[] {
|
|
11
|
+
const shaderLayoutMap = Object.fromEntries(
|
|
12
|
+
shaderLayout.attributes.map(attr => [attr.name, attr.location])
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
const sortedLayout = bufferLayout.slice();
|
|
16
|
+
sortedLayout.sort((a, b) => {
|
|
17
|
+
const attributeNamesA = a.attributes ? a.attributes.map(attr => attr.attribute) : [a.name];
|
|
18
|
+
const attributeNamesB = b.attributes ? b.attributes.map(attr => attr.attribute) : [b.name];
|
|
19
|
+
const minLocationA = Math.min(...attributeNamesA.map(name => shaderLayoutMap[name]));
|
|
20
|
+
const minLocationB = Math.min(...attributeNamesB.map(name => shaderLayoutMap[name]));
|
|
21
|
+
|
|
22
|
+
return minLocationA - minLocationB;
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
return sortedLayout;
|
|
26
|
+
}
|