@luma.gl/engine 9.0.0-alpha.9 → 9.0.0-beta.10

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.
Files changed (187) hide show
  1. package/LICENSE +3 -1
  2. package/dist/animation/key-frames.d.ts +1 -1
  3. package/dist/animation/key-frames.d.ts.map +1 -1
  4. package/dist/animation/key-frames.js +51 -72
  5. package/dist/animation/timeline.d.ts +8 -8
  6. package/dist/animation/timeline.d.ts.map +1 -1
  7. package/dist/animation/timeline.js +95 -131
  8. package/dist/animation-loop/animation-loop-template.d.ts +23 -0
  9. package/dist/animation-loop/animation-loop-template.d.ts.map +1 -0
  10. package/dist/animation-loop/animation-loop-template.js +21 -0
  11. package/dist/{lib → animation-loop}/animation-loop.d.ts +31 -23
  12. package/dist/animation-loop/animation-loop.d.ts.map +1 -0
  13. package/dist/animation-loop/animation-loop.js +442 -0
  14. package/dist/{lib → animation-loop}/animation-props.d.ts +4 -5
  15. package/dist/animation-loop/animation-props.d.ts.map +1 -0
  16. package/dist/animation-loop/animation-props.js +1 -0
  17. package/dist/animation-loop/make-animation-loop.d.ts +6 -0
  18. package/dist/animation-loop/make-animation-loop.d.ts.map +1 -0
  19. package/dist/animation-loop/make-animation-loop.js +32 -0
  20. package/dist/computation.d.ts +95 -0
  21. package/dist/computation.d.ts.map +1 -0
  22. package/dist/computation.js +248 -0
  23. package/dist/debug/copy-texture-to-image.d.ts +26 -0
  24. package/dist/debug/copy-texture-to-image.d.ts.map +1 -0
  25. package/dist/debug/copy-texture-to-image.js +43 -0
  26. package/dist/debug/debug-framebuffer.d.ts +11 -0
  27. package/dist/debug/debug-framebuffer.d.ts.map +1 -0
  28. package/dist/debug/debug-framebuffer.js +46 -0
  29. package/dist/debug/debug-shader-layout.d.ts +9 -0
  30. package/dist/debug/debug-shader-layout.d.ts.map +1 -0
  31. package/dist/debug/debug-shader-layout.js +27 -0
  32. package/dist/debug/pixel-data-utils.d.ts +24 -0
  33. package/dist/debug/pixel-data-utils.d.ts.map +1 -0
  34. package/dist/debug/pixel-data-utils.js +39 -0
  35. package/dist/dist.dev.js +9592 -0
  36. package/dist/dist.min.js +102 -0
  37. package/dist/geometries/cone-geometry.d.ts +2 -2
  38. package/dist/geometries/cone-geometry.d.ts.map +1 -1
  39. package/dist/geometries/cone-geometry.js +13 -18
  40. package/dist/geometries/cube-geometry.d.ts +2 -2
  41. package/dist/geometries/cube-geometry.d.ts.map +1 -1
  42. package/dist/geometries/cube-geometry.js +192 -57
  43. package/dist/geometries/cylinder-geometry.d.ts +2 -2
  44. package/dist/geometries/cylinder-geometry.d.ts.map +1 -1
  45. package/dist/geometries/cylinder-geometry.js +11 -15
  46. package/dist/geometries/ico-sphere-geometry.d.ts +2 -2
  47. package/dist/geometries/ico-sphere-geometry.d.ts.map +1 -1
  48. package/dist/geometries/ico-sphere-geometry.js +143 -171
  49. package/dist/geometries/plane-geometry.d.ts +2 -2
  50. package/dist/geometries/plane-geometry.d.ts.map +1 -1
  51. package/dist/geometries/plane-geometry.js +95 -122
  52. package/dist/geometries/sphere-geometry.d.ts +2 -2
  53. package/dist/geometries/sphere-geometry.d.ts.map +1 -1
  54. package/dist/geometries/sphere-geometry.js +78 -101
  55. package/dist/geometries/truncated-cone-geometry.d.ts +2 -4
  56. package/dist/geometries/truncated-cone-geometry.d.ts.map +1 -1
  57. package/dist/geometries/truncated-cone-geometry.js +100 -134
  58. package/dist/geometry/geometry-table.d.ts +2 -2
  59. package/dist/geometry/geometry-table.d.ts.map +1 -1
  60. package/dist/geometry/geometry-table.js +3 -1
  61. package/dist/geometry/geometry-utils.d.ts.map +1 -1
  62. package/dist/geometry/geometry-utils.js +35 -41
  63. package/dist/geometry/geometry.d.ts +43 -43
  64. package/dist/geometry/geometry.d.ts.map +1 -1
  65. package/dist/geometry/geometry.js +82 -139
  66. package/dist/geometry/gpu-geometry.d.ts +37 -0
  67. package/dist/geometry/gpu-geometry.d.ts.map +1 -0
  68. package/dist/geometry/gpu-geometry.js +90 -0
  69. package/dist/geometry/gpu-table.d.ts +1 -0
  70. package/dist/geometry/gpu-table.d.ts.map +1 -0
  71. package/dist/geometry/gpu-table.js +42 -0
  72. package/dist/index.cjs +3444 -0
  73. package/dist/index.cjs.map +7 -0
  74. package/dist/index.d.ts +43 -24
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.js +29 -15
  77. package/dist/lib/clip-space.d.ts +8 -0
  78. package/dist/lib/clip-space.d.ts.map +1 -1
  79. package/dist/lib/clip-space.js +43 -2
  80. package/dist/lib/pipeline-factory.d.ts +17 -51
  81. package/dist/lib/pipeline-factory.d.ts.map +1 -1
  82. package/dist/lib/pipeline-factory.js +84 -209
  83. package/dist/lib/shader-factory.d.ts +17 -0
  84. package/dist/lib/shader-factory.d.ts.map +1 -0
  85. package/dist/lib/shader-factory.js +46 -0
  86. package/dist/model/model.d.ts +219 -0
  87. package/dist/model/model.d.ts.map +1 -0
  88. package/dist/model/model.js +659 -0
  89. package/dist/scenegraph/group-node.d.ts +21 -0
  90. package/dist/scenegraph/group-node.d.ts.map +1 -0
  91. package/dist/scenegraph/group-node.js +84 -0
  92. package/dist/scenegraph/model-node.d.ts +18 -0
  93. package/dist/scenegraph/model-node.d.ts.map +1 -0
  94. package/dist/scenegraph/model-node.js +35 -0
  95. package/dist/scenegraph/scenegraph-node.d.ts +56 -0
  96. package/dist/scenegraph/scenegraph-node.d.ts.map +1 -0
  97. package/dist/scenegraph/scenegraph-node.js +153 -0
  98. package/dist/shader-inputs.d.ts +63 -0
  99. package/dist/shader-inputs.d.ts.map +1 -0
  100. package/dist/shader-inputs.js +107 -0
  101. package/dist/transform/buffer-transform.d.ts +35 -0
  102. package/dist/transform/buffer-transform.d.ts.map +1 -0
  103. package/dist/transform/buffer-transform.js +70 -0
  104. package/dist/transform/texture-transform.d.ts +57 -0
  105. package/dist/transform/texture-transform.d.ts.map +1 -0
  106. package/dist/transform/texture-transform.js +117 -0
  107. package/dist.min.js +25 -0
  108. package/package.json +24 -14
  109. package/src/animation/timeline.ts +35 -34
  110. package/src/animation-loop/animation-loop-template.ts +25 -0
  111. package/src/{lib → animation-loop}/animation-loop.ts +114 -93
  112. package/src/{lib → animation-loop}/animation-props.ts +2 -2
  113. package/src/animation-loop/make-animation-loop.ts +53 -0
  114. package/src/computation.ts +346 -0
  115. package/src/debug/copy-texture-to-image.ts +70 -0
  116. package/src/debug/debug-framebuffer.ts +70 -0
  117. package/src/debug/debug-shader-layout.ts +38 -0
  118. package/src/debug/pixel-data-utils.ts +54 -0
  119. package/src/geometries/cone-geometry.ts +1 -1
  120. package/src/geometries/cube-geometry.ts +62 -56
  121. package/src/geometries/cylinder-geometry.ts +2 -2
  122. package/src/geometries/ico-sphere-geometry.ts +6 -5
  123. package/src/geometries/plane-geometry.ts +5 -4
  124. package/src/geometries/sphere-geometry.ts +4 -3
  125. package/src/geometries/truncated-cone-geometry.ts +6 -14
  126. package/src/geometry/geometry-table.ts +10 -7
  127. package/src/geometry/geometry-utils.ts +19 -3
  128. package/src/geometry/geometry.ts +68 -110
  129. package/src/geometry/gpu-geometry.ts +132 -0
  130. package/src/geometry/gpu-table.ts +41 -0
  131. package/src/index.ts +37 -10
  132. package/src/lib/clip-space.ts +32 -34
  133. package/src/lib/pipeline-factory.ts +83 -193
  134. package/src/lib/shader-factory.ts +57 -0
  135. package/src/model/model.ts +835 -0
  136. package/src/scenegraph/group-node.ts +107 -0
  137. package/src/scenegraph/model-node.ts +50 -0
  138. package/src/scenegraph/scenegraph-node.ts +204 -0
  139. package/src/shader-inputs.ts +157 -0
  140. package/src/transform/buffer-transform.ts +102 -0
  141. package/src/transform/texture-transform.ts +168 -0
  142. package/dist/animation/key-frames.js.map +0 -1
  143. package/dist/animation/timeline.js.map +0 -1
  144. package/dist/bundle.d.ts +0 -2
  145. package/dist/bundle.d.ts.map +0 -1
  146. package/dist/bundle.js +0 -5
  147. package/dist/bundle.js.map +0 -1
  148. package/dist/geometries/cone-geometry.js.map +0 -1
  149. package/dist/geometries/cube-geometry.js.map +0 -1
  150. package/dist/geometries/cylinder-geometry.js.map +0 -1
  151. package/dist/geometries/ico-sphere-geometry.js.map +0 -1
  152. package/dist/geometries/plane-geometry.js.map +0 -1
  153. package/dist/geometries/sphere-geometry.js.map +0 -1
  154. package/dist/geometries/truncated-cone-geometry.js.map +0 -1
  155. package/dist/geometry/geometry-table.js.map +0 -1
  156. package/dist/geometry/geometry-utils.js.map +0 -1
  157. package/dist/geometry/geometry.js.map +0 -1
  158. package/dist/geometry/primitive-utils.d.ts +0 -1
  159. package/dist/geometry/primitive-utils.d.ts.map +0 -1
  160. package/dist/geometry/primitive-utils.js +0 -2
  161. package/dist/geometry/primitive-utils.js.map +0 -1
  162. package/dist/index.js.map +0 -1
  163. package/dist/lib/animation-loop.d.ts.map +0 -1
  164. package/dist/lib/animation-loop.js +0 -480
  165. package/dist/lib/animation-loop.js.map +0 -1
  166. package/dist/lib/animation-props.d.ts.map +0 -1
  167. package/dist/lib/animation-props.js +0 -2
  168. package/dist/lib/animation-props.js.map +0 -1
  169. package/dist/lib/clip-space.js.map +0 -1
  170. package/dist/lib/model-utils.d.ts +0 -5
  171. package/dist/lib/model-utils.d.ts.map +0 -1
  172. package/dist/lib/model-utils.js +0 -45
  173. package/dist/lib/model-utils.js.map +0 -1
  174. package/dist/lib/model.d.ts +0 -41
  175. package/dist/lib/model.d.ts.map +0 -1
  176. package/dist/lib/model.js +0 -182
  177. package/dist/lib/model.js.map +0 -1
  178. package/dist/lib/pipeline-factory.js.map +0 -1
  179. package/dist/lib/render-loop.d.ts +0 -14
  180. package/dist/lib/render-loop.d.ts.map +0 -1
  181. package/dist/lib/render-loop.js +0 -49
  182. package/dist/lib/render-loop.js.map +0 -1
  183. package/src/bundle.ts +0 -4
  184. package/src/geometry/primitive-utils.ts +0 -30
  185. package/src/lib/model-utils.ts +0 -124
  186. package/src/lib/model.ts +0 -183
  187. package/src/lib/render-loop.ts +0 -58
@@ -0,0 +1,346 @@
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import type {TypedArray} from '@luma.gl/core';
6
+ import type {DeviceFeature, ComputePipelineProps, Shader, Binding} from '@luma.gl/core';
7
+ import {Device, Buffer, ComputePipeline, ComputePass, UniformStore} from '@luma.gl/core';
8
+ import {log, uid, isNumberArray} from '@luma.gl/core';
9
+ import {getTypedArrayFromDataType} from '@luma.gl/core';
10
+ import type {ShaderModule, PlatformInfo} from '@luma.gl/shadertools';
11
+ import {ShaderAssembler, getShaderLayoutFromWGSL} from '@luma.gl/shadertools';
12
+ import {ShaderInputs} from './shader-inputs';
13
+ import {PipelineFactory} from './lib/pipeline-factory';
14
+ import {ShaderFactory} from './lib/shader-factory';
15
+ // import {getDebugTableForShaderLayout} from '../debug/debug-shader-layout';
16
+
17
+ const LOG_DRAW_PRIORITY = 2;
18
+ const LOG_DRAW_TIMEOUT = 10000;
19
+
20
+ export type ComputationProps = Omit<ComputePipelineProps, 'shader'> & {
21
+ source?: string;
22
+
23
+ /** shadertool shader modules (added to shader code) */
24
+ modules?: ShaderModule[];
25
+ /** Shadertool module defines (configures shader code)*/
26
+ defines?: Record<string, string | number | boolean>;
27
+ // TODO - injections, hooks etc?
28
+
29
+ /** Shader inputs, used to generated uniform buffers and bindings */
30
+ shaderInputs?: ShaderInputs;
31
+
32
+ /** Bindings */
33
+ bindings?: Record<string, Binding>;
34
+
35
+ /** Show shader source in browser? */
36
+ debugShaders?: 'never' | 'errors' | 'warnings' | 'always';
37
+
38
+ /** Factory used to create a {@link ComputePipeline}. Defaults to {@link Device} default factory. */
39
+ pipelineFactory?: PipelineFactory;
40
+ /** Factory used to create a {@link Shader}. Defaults to {@link Device} default factory. */
41
+ shaderFactory?: ShaderFactory;
42
+ /** Shader assembler. Defaults to the ShaderAssembler.getShaderAssembler() */
43
+ shaderAssembler?: ShaderAssembler;
44
+ };
45
+
46
+ /**
47
+ * v9 Model API
48
+ * A model
49
+ * - automatically reuses pipelines (programs) when possible
50
+ * - automatically rebuilds pipelines if necessary to accommodate changed settings
51
+ * shadertools integration
52
+ * - accepts modules and performs shader transpilation
53
+ */
54
+ export class Computation {
55
+ static defaultProps: Required<ComputationProps> = {
56
+ ...ComputePipeline.defaultProps,
57
+ id: 'unnamed',
58
+ handle: undefined,
59
+ userData: {},
60
+
61
+ source: '',
62
+ modules: [],
63
+ defines: {},
64
+
65
+ bindings: undefined!,
66
+ shaderInputs: undefined!,
67
+
68
+ pipelineFactory: undefined!,
69
+ shaderFactory: undefined!,
70
+ shaderAssembler: ShaderAssembler.getDefaultShaderAssembler(),
71
+
72
+ debugShaders: undefined
73
+ };
74
+
75
+ readonly device: Device;
76
+ readonly id: string;
77
+
78
+ readonly pipelineFactory: PipelineFactory;
79
+ readonly shaderFactory: ShaderFactory;
80
+
81
+ userData: {[key: string]: any} = {};
82
+
83
+ /** Bindings (textures, samplers, uniform buffers) */
84
+ bindings: Record<string, Binding> = {};
85
+
86
+ /** The underlying GPU "program". @note May be recreated if parameters change */
87
+ pipeline: ComputePipeline;
88
+ /** the underlying compiled compute shader */
89
+ shader: Shader;
90
+ source: string;
91
+
92
+ /** ShaderInputs instance */
93
+ shaderInputs: ShaderInputs;
94
+
95
+ _uniformStore: UniformStore;
96
+
97
+ _pipelineNeedsUpdate: string | false = 'newly created';
98
+
99
+ private _getModuleUniforms: (props?: Record<string, Record<string, any>>) => Record<string, any>;
100
+ private props: Required<ComputationProps>;
101
+
102
+ private _destroyed = false;
103
+
104
+ constructor(device: Device, props: ComputationProps) {
105
+ if (device.type !== 'webgpu') {
106
+ throw new Error('Computation is only supported in WebGPU');
107
+ }
108
+
109
+ this.props = {...Computation.defaultProps, ...props};
110
+ props = this.props;
111
+ this.id = props.id || uid('model');
112
+ this.device = device;
113
+
114
+ Object.assign(this.userData, props.userData);
115
+
116
+ // Setup shader module inputs
117
+ const moduleMap = Object.fromEntries(
118
+ this.props.modules?.map(module => [module.name, module]) || []
119
+ );
120
+ this.setShaderInputs(props.shaderInputs || new ShaderInputs(moduleMap));
121
+
122
+ // Support WGSL shader layout introspection
123
+ // TODO - Don't modify props!!
124
+ this.props.shaderLayout ||= getShaderLayoutFromWGSL(this.props.source);
125
+
126
+ // Setup shader assembler
127
+ const platformInfo = getPlatformInfo(device);
128
+
129
+ // Extract modules from shader inputs if not supplied
130
+ const modules =
131
+ (this.props.modules?.length > 0 ? this.props.modules : this.shaderInputs?.getModules()) || [];
132
+
133
+ this.pipelineFactory =
134
+ props.pipelineFactory || PipelineFactory.getDefaultPipelineFactory(this.device);
135
+ this.shaderFactory = props.shaderFactory || ShaderFactory.getDefaultShaderFactory(this.device);
136
+
137
+ const {source, getUniforms} = this.props.shaderAssembler.assembleShader({
138
+ platformInfo,
139
+ ...this.props,
140
+ modules
141
+ });
142
+
143
+ this.source = source;
144
+
145
+ this._getModuleUniforms = getUniforms;
146
+
147
+ // Create the pipeline
148
+ // @note order is important
149
+ this.pipeline = this._updatePipeline();
150
+
151
+ // Apply any dynamic settings that will not trigger pipeline change
152
+ if (props.bindings) {
153
+ this.setBindings(props.bindings);
154
+ }
155
+
156
+ // Catch any access to non-standard props
157
+ Object.seal(this);
158
+ }
159
+
160
+ destroy(): void {
161
+ if (this._destroyed) return;
162
+ this.pipelineFactory.release(this.pipeline);
163
+ this.shaderFactory.release(this.shader);
164
+ this._uniformStore.destroy();
165
+ this._destroyed = true;
166
+ }
167
+
168
+ // Draw call
169
+
170
+ predraw() {
171
+ // Update uniform buffers if needed
172
+ this.updateShaderInputs();
173
+ }
174
+
175
+ dispatch(computePass: ComputePass, x: number, y?: number, z?: number): void {
176
+ try {
177
+ this._logDrawCallStart();
178
+
179
+ // Check if the pipeline is invalidated
180
+ // TODO - this is likely the worst place to do this from performance perspective. Perhaps add a predraw()?
181
+ this.pipeline = this._updatePipeline();
182
+
183
+ // Set pipeline state, we may be sharing a pipeline so we need to set all state on every draw
184
+ // Any caching needs to be done inside the pipeline functions
185
+ this.pipeline.setBindings(this.bindings);
186
+ computePass.setPipeline(this.pipeline);
187
+ // @ts-expect-error
188
+ computePass.setBindings([]);
189
+
190
+ computePass.dispatch(x, y, z);
191
+ } finally {
192
+ this._logDrawCallEnd();
193
+ }
194
+ }
195
+
196
+ // Update fixed fields (can trigger pipeline rebuild)
197
+
198
+ // Update dynamic fields
199
+
200
+ /**
201
+ * Updates the vertex count (used in draw calls)
202
+ * @note Any attributes with stepMode=vertex need to be at least this big
203
+ */
204
+ setVertexCount(vertexCount: number): void {
205
+ // this.vertexCount = vertexCount;
206
+ }
207
+
208
+ /**
209
+ * Updates the instance count (used in draw calls)
210
+ * @note Any attributes with stepMode=instance need to be at least this big
211
+ */
212
+ setInstanceCount(instanceCount: number): void {
213
+ // this.instanceCount = instanceCount;
214
+ }
215
+
216
+ setShaderInputs(shaderInputs: ShaderInputs): void {
217
+ this.shaderInputs = shaderInputs;
218
+ this._uniformStore = new UniformStore(this.shaderInputs.modules);
219
+ // Create uniform buffer bindings for all modules
220
+ for (const moduleName of Object.keys(this.shaderInputs.modules)) {
221
+ const uniformBuffer = this._uniformStore.getManagedUniformBuffer(this.device, moduleName);
222
+ this.bindings[`${moduleName}Uniforms`] = uniformBuffer;
223
+ }
224
+ }
225
+
226
+ /**
227
+ * Updates shader module settings (which results in uniforms being set)
228
+ */
229
+ setShaderModuleProps(props: Record<string, any>): void {
230
+ const uniforms = this._getModuleUniforms(props);
231
+
232
+ // Extract textures & framebuffers set by the modules
233
+ // TODO better way to extract bindings
234
+ const keys = Object.keys(uniforms).filter(k => {
235
+ const uniform = uniforms[k];
236
+ return !isNumberArray(uniform) && typeof uniform !== 'number' && typeof uniform !== 'boolean';
237
+ });
238
+ const bindings: Record<string, Binding> = {};
239
+ for (const k of keys) {
240
+ bindings[k] = uniforms[k];
241
+ delete uniforms[k];
242
+ }
243
+ }
244
+
245
+ updateShaderInputs(): void {
246
+ this._uniformStore.setUniforms(this.shaderInputs.getUniformValues());
247
+ }
248
+
249
+ /**
250
+ * Sets bindings (textures, samplers, uniform buffers)
251
+ */
252
+ setBindings(bindings: Record<string, Binding>): void {
253
+ Object.assign(this.bindings, bindings);
254
+ }
255
+
256
+ _setPipelineNeedsUpdate(reason: string): void {
257
+ this._pipelineNeedsUpdate = this._pipelineNeedsUpdate || reason;
258
+ }
259
+
260
+ _updatePipeline(): ComputePipeline {
261
+ if (this._pipelineNeedsUpdate) {
262
+ let prevShader: Shader | null = null;
263
+ if (this.pipeline) {
264
+ log.log(
265
+ 1,
266
+ `Model ${this.id}: Recreating pipeline because "${this._pipelineNeedsUpdate}".`
267
+ )();
268
+ prevShader = this.shader;
269
+ }
270
+
271
+ this._pipelineNeedsUpdate = false;
272
+
273
+ this.shader = this.shaderFactory.createShader({
274
+ id: `${this.id}-fragment`,
275
+ stage: 'compute',
276
+ source: this.source,
277
+ debug: this.props.debugShaders
278
+ });
279
+
280
+ this.pipeline = this.pipelineFactory.createComputePipeline({
281
+ ...this.props,
282
+ shader: this.shader
283
+ });
284
+
285
+ if (prevShader) {
286
+ this.shaderFactory.release(prevShader);
287
+ }
288
+ }
289
+ return this.pipeline;
290
+ }
291
+
292
+ /** Throttle draw call logging */
293
+ _lastLogTime = 0;
294
+ _logOpen = false;
295
+
296
+ _logDrawCallStart(): void {
297
+ // IF level is 4 or higher, log every frame.
298
+ const logDrawTimeout = log.level > 3 ? 0 : LOG_DRAW_TIMEOUT;
299
+ if (log.level < 2 || Date.now() - this._lastLogTime < logDrawTimeout) {
300
+ return;
301
+ }
302
+
303
+ this._lastLogTime = Date.now();
304
+ this._logOpen = true;
305
+
306
+ log.group(LOG_DRAW_PRIORITY, `>>> DRAWING MODEL ${this.id}`, {collapsed: log.level <= 2})();
307
+ }
308
+
309
+ _logDrawCallEnd(): void {
310
+ if (this._logOpen) {
311
+ // const shaderLayoutTable = getDebugTableForShaderLayout(this.pipeline.props.shaderLayout, this.id);
312
+
313
+ // log.table(logLevel, attributeTable)();
314
+ // log.table(logLevel, uniformTable)();
315
+ // log.table(LOG_DRAW_PRIORITY, shaderLayoutTable)();
316
+
317
+ const uniformTable = this.shaderInputs.getDebugTable();
318
+ log.table(LOG_DRAW_PRIORITY, uniformTable)();
319
+
320
+ log.groupEnd(LOG_DRAW_PRIORITY)();
321
+ this._logOpen = false;
322
+ }
323
+ }
324
+
325
+ protected _drawCount = 0;
326
+
327
+ // TODO - fix typing of luma data types
328
+ _getBufferOrConstantValues(attribute: Buffer | TypedArray, dataType: any): string {
329
+ const TypedArrayConstructor = getTypedArrayFromDataType(dataType);
330
+ const typedArray =
331
+ attribute instanceof Buffer ? new TypedArrayConstructor(attribute.debugData) : attribute;
332
+ return typedArray.toString();
333
+ }
334
+ }
335
+
336
+ /** Create a shadertools platform info from the Device */
337
+ export function getPlatformInfo(device: Device): PlatformInfo {
338
+ return {
339
+ type: device.type,
340
+ shaderLanguage: device.info.shadingLanguage,
341
+ shaderLanguageVersion: device.info.shadingLanguageVersion as 100 | 300,
342
+ gpu: device.info.gpu,
343
+ // HACK - we pretend that the DeviceFeatures is a Set, it has a similar API
344
+ features: device.features as unknown as Set<DeviceFeature>
345
+ };
346
+ }
@@ -0,0 +1,70 @@
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {Texture, Framebuffer} from '@luma.gl/core';
6
+ import {flipRows, scalePixels} from './pixel-data-utils';
7
+
8
+ /**
9
+ * Options for copying texture pixels to image
10
+ * @todo - support gl.readBuffer
11
+ */
12
+ export type CopyTextureToImageOptions = {
13
+ sourceAttachment?: number;
14
+ targetMaxHeight?: number;
15
+ targetImage?: HTMLImageElement;
16
+ };
17
+
18
+ /**
19
+ * Reads pixels from a Framebuffer or Texture object into an HTML Image
20
+ * @todo - can we move this to @luma.gl/core?
21
+ * @param source
22
+ * @param options options passed to copyToDataUrl
23
+ * @returns
24
+ */
25
+ export function copyTextureToImage(
26
+ source: Texture | Framebuffer,
27
+ options?: CopyTextureToImageOptions
28
+ ): HTMLImageElement {
29
+ const dataUrl = copyTextureToDataUrl(source, options);
30
+ const targetImage: HTMLImageElement = options?.targetImage || new Image();
31
+ targetImage.src = dataUrl;
32
+
33
+ return targetImage;
34
+ }
35
+
36
+ /**
37
+ * Reads pixels from a Framebuffer or Texture object to a dataUrl
38
+ * @todo - can we move this to @luma.gl/core?
39
+ * @param source texture or framebuffer to read from
40
+ * @param options
41
+ */
42
+ export function copyTextureToDataUrl(
43
+ source: Texture | Framebuffer,
44
+ options: CopyTextureToImageOptions = {}
45
+ ): string {
46
+ const {sourceAttachment, targetMaxHeight = Number.MAX_SAFE_INTEGER} = options;
47
+
48
+ let data = source.device.readPixelsToArrayWebGL(source, {sourceAttachment});
49
+
50
+ // Scale down
51
+ let {width, height} = source;
52
+ while (height > targetMaxHeight) {
53
+ ({data, width, height} = scalePixels({data, width, height}));
54
+ }
55
+
56
+ // Flip to top down coordinate system
57
+ flipRows({data, width, height});
58
+
59
+ const canvas = document.createElement('canvas');
60
+ canvas.width = width;
61
+ canvas.height = height;
62
+ const context = canvas.getContext('2d');
63
+
64
+ // Copy the pixels to a 2D canvas
65
+ const imageData = context.createImageData(width, height);
66
+ imageData.data.set(data);
67
+ context.putImageData(imageData, 0, 0);
68
+
69
+ return canvas.toDataURL('image/png');
70
+ }
@@ -0,0 +1,70 @@
1
+ import type {Framebuffer, Texture} from '@luma.gl/core';
2
+ // import {copyTextureToImage} from '../debug/copy-texture-to-image';
3
+
4
+ /** Only works with 1st device? */
5
+ let canvas: HTMLCanvasElement | null = null;
6
+ let ctx: CanvasRenderingContext2D | null = null;
7
+ // let targetImage: HTMLImageElement | null = null;
8
+
9
+ /** Debug utility to draw FBO contents onto screen */
10
+ // eslint-disable-next-line
11
+ export function debugFramebuffer(
12
+ fbo: Framebuffer | Texture,
13
+ {
14
+ id,
15
+ minimap,
16
+ opaque,
17
+ top = '0',
18
+ left = '0',
19
+ rgbaScale = 1
20
+ }: {
21
+ id: string;
22
+ minimap?: boolean;
23
+ opaque?: boolean;
24
+ top?: string;
25
+ left?: string;
26
+ rgbaScale?: number;
27
+ }
28
+ ) {
29
+ if (!canvas) {
30
+ canvas = document.createElement('canvas');
31
+ canvas.id = id;
32
+ canvas.title = id;
33
+ canvas.style.zIndex = '100';
34
+ canvas.style.position = 'absolute';
35
+ canvas.style.top = top; // ⚠️
36
+ canvas.style.left = left; // ⚠️
37
+ canvas.style.border = 'blue 1px solid';
38
+ canvas.style.transform = 'scaleY(-1)';
39
+ document.body.appendChild(canvas);
40
+
41
+ ctx = canvas.getContext('2d');
42
+ // targetImage = new Image();
43
+ }
44
+
45
+ // const canvasHeight = (minimap ? 2 : 1) * fbo.height;
46
+ if (canvas.width !== fbo.width || canvas.height !== fbo.height) {
47
+ canvas.width = fbo.width / 2;
48
+ canvas.height = fbo.height / 2;
49
+ canvas.style.width = '400px';
50
+ canvas.style.height = '400px';
51
+ }
52
+
53
+ // const image = copyTextureToImage(fbo, {targetMaxHeight: 100, targetImage});
54
+ // ctx.drawImage(image, 0, 0);
55
+
56
+ const color = fbo.device.readPixelsToArrayWebGL(fbo);
57
+ const imageData = ctx.createImageData(fbo.width, fbo.height);
58
+ // Full map
59
+ const offset = 0;
60
+ // if (color.some((v) => v > 0)) {
61
+ // console.error('THERE IS NON-ZERO DATA IN THE FBO!');
62
+ // }
63
+ for (let i = 0; i < color.length; i += 4) {
64
+ imageData.data[offset + i + 0] = color[i + 0] * rgbaScale;
65
+ imageData.data[offset + i + 1] = color[i + 1] * rgbaScale;
66
+ imageData.data[offset + i + 2] = color[i + 2] * rgbaScale;
67
+ imageData.data[offset + i + 3] = opaque ? 255 : color[i + 3] * rgbaScale;
68
+ }
69
+ ctx.putImageData(imageData, 0, 0);
70
+ }
@@ -0,0 +1,38 @@
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import type {ShaderLayout} from '@luma.gl/core';
6
+
7
+ /**
8
+ * Extracts a table suitable for `console.table()` from a shader layout to assist in debugging.
9
+ * @param layout shader layout
10
+ * @param name app should provide the most meaningful name, usually the model or pipeline name / id.
11
+ * @returns
12
+ */
13
+ export function getDebugTableForShaderLayout(
14
+ layout: ShaderLayout,
15
+ name: string
16
+ ): Record<string, Record<string, string>> {
17
+ const table: Record<string, Record<string, string>> = {};
18
+
19
+ const header = 'Values'; // '`Shader Layout for ${name}`;
20
+
21
+ if (layout.attributes.length === 0 && !layout.varyings?.length) {
22
+ return {'No attributes or varyings': {[header]: 'N/A'}};
23
+ }
24
+
25
+ for (const attributeDeclaration of layout.attributes) {
26
+ if (attributeDeclaration) {
27
+ const glslDeclaration = `${attributeDeclaration.location} ${attributeDeclaration.name}: ${attributeDeclaration.type}`;
28
+ table[`in ${glslDeclaration}`] = {[header]: attributeDeclaration.stepMode || 'vertex'};
29
+ }
30
+ }
31
+
32
+ for (const varyingDeclaration of layout.varyings || []) {
33
+ const glslDeclaration = `${varyingDeclaration.location} ${varyingDeclaration.name}`;
34
+ table[`out ${glslDeclaration}`] = {[header]: JSON.stringify(varyingDeclaration.accessor)};
35
+ }
36
+
37
+ return table;
38
+ }
@@ -0,0 +1,54 @@
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {TypedArray} from '@luma.gl/core';
6
+
7
+ /**
8
+ * Flip rows (can be used on arrays returned from `Framebuffer.readPixels`)
9
+ * https: *stackoverflow.com/questions/41969562/
10
+ * how-can-i-flip-the-result-of-webglrenderingcontext-readpixels
11
+ * @param param0
12
+ */
13
+ export function flipRows(options: {
14
+ data: TypedArray;
15
+ width: number;
16
+ height: number;
17
+ bytesPerPixel?: number;
18
+ temp?: Uint8Array;
19
+ }): void {
20
+ const {data, width, height, bytesPerPixel = 4, temp} = options;
21
+ const bytesPerRow = width * bytesPerPixel;
22
+
23
+ // make a temp buffer to hold one row
24
+ const tempBuffer = temp || new Uint8Array(bytesPerRow);
25
+ for (let y = 0; y < height / 2; ++y) {
26
+ const topOffset = y * bytesPerRow;
27
+ const bottomOffset = (height - y - 1) * bytesPerRow;
28
+ // make copy of a row on the top half
29
+ tempBuffer.set(data.subarray(topOffset, topOffset + bytesPerRow));
30
+ // copy a row from the bottom half to the top
31
+ data.copyWithin(topOffset, bottomOffset, bottomOffset + bytesPerRow);
32
+ // copy the copy of the top half row to the bottom half
33
+ data.set(tempBuffer, bottomOffset);
34
+ }
35
+ }
36
+
37
+ export function scalePixels(options: {data: TypedArray; width: number; height: number}): {
38
+ data: Uint8Array;
39
+ width: number;
40
+ height: number;
41
+ } {
42
+ const {data, width, height} = options;
43
+ const newWidth = Math.round(width / 2);
44
+ const newHeight = Math.round(height / 2);
45
+ const newData = new Uint8Array(newWidth * newHeight * 4);
46
+ for (let y = 0; y < newHeight; y++) {
47
+ for (let x = 0; x < newWidth; x++) {
48
+ for (let c = 0; c < 4; c++) {
49
+ newData[(y * newWidth + x) * 4 + c] = data[(y * 2 * width + x * 2) * 4 + c];
50
+ }
51
+ }
52
+ }
53
+ return {data: newData, width: newWidth, height: newHeight};
54
+ }
@@ -1,4 +1,4 @@
1
- import {uid} from '@luma.gl/api';
1
+ import {uid} from '@luma.gl/core';
2
2
  import {TruncatedConeGeometry} from './truncated-cone-geometry';
3
3
 
4
4
  export type ConeGeometryProps = {