@luma.gl/core 9.2.5 → 9.3.0-alpha.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.
- package/dist/adapter/canvas-context.d.ts +6 -162
- package/dist/adapter/canvas-context.d.ts.map +1 -1
- package/dist/adapter/canvas-context.js +5 -419
- package/dist/adapter/canvas-context.js.map +1 -1
- package/dist/adapter/canvas-observer.d.ts +32 -0
- package/dist/adapter/canvas-observer.d.ts.map +1 -0
- package/dist/adapter/canvas-observer.js +90 -0
- package/dist/adapter/canvas-observer.js.map +1 -0
- package/dist/adapter/canvas-surface.d.ts +150 -0
- package/dist/adapter/canvas-surface.d.ts.map +1 -0
- package/dist/adapter/canvas-surface.js +392 -0
- package/dist/adapter/canvas-surface.js.map +1 -0
- package/dist/adapter/device.d.ts +81 -16
- package/dist/adapter/device.d.ts.map +1 -1
- package/dist/adapter/device.js +196 -10
- package/dist/adapter/device.js.map +1 -1
- package/dist/adapter/luma.js +1 -1
- package/dist/adapter/luma.js.map +1 -1
- package/dist/adapter/presentation-context.d.ts +11 -0
- package/dist/adapter/presentation-context.d.ts.map +1 -0
- package/dist/adapter/presentation-context.js +12 -0
- package/dist/adapter/presentation-context.js.map +1 -0
- package/dist/adapter/resources/buffer.d.ts +5 -5
- package/dist/adapter/resources/buffer.d.ts.map +1 -1
- package/dist/adapter/resources/buffer.js +18 -7
- package/dist/adapter/resources/buffer.js.map +1 -1
- package/dist/adapter/resources/command-buffer.d.ts +3 -1
- package/dist/adapter/resources/command-buffer.d.ts.map +1 -1
- package/dist/adapter/resources/command-buffer.js +3 -1
- package/dist/adapter/resources/command-buffer.js.map +1 -1
- package/dist/adapter/resources/command-encoder.d.ts +30 -7
- package/dist/adapter/resources/command-encoder.d.ts.map +1 -1
- package/dist/adapter/resources/command-encoder.js +68 -2
- package/dist/adapter/resources/command-encoder.js.map +1 -1
- package/dist/adapter/resources/compute-pipeline.d.ts +2 -2
- package/dist/adapter/resources/compute-pipeline.d.ts.map +1 -1
- package/dist/adapter/resources/fence.d.ts +16 -0
- package/dist/adapter/resources/fence.d.ts.map +1 -0
- package/dist/adapter/resources/fence.js +17 -0
- package/dist/adapter/resources/fence.js.map +1 -0
- package/dist/adapter/resources/framebuffer.d.ts +1 -1
- package/dist/adapter/resources/framebuffer.d.ts.map +1 -1
- package/dist/adapter/resources/framebuffer.js +15 -12
- package/dist/adapter/resources/framebuffer.js.map +1 -1
- package/dist/adapter/resources/query-set.d.ts +17 -1
- package/dist/adapter/resources/query-set.d.ts.map +1 -1
- package/dist/adapter/resources/query-set.js.map +1 -1
- package/dist/adapter/resources/render-pipeline.d.ts +28 -10
- package/dist/adapter/resources/render-pipeline.d.ts.map +1 -1
- package/dist/adapter/resources/render-pipeline.js +21 -2
- package/dist/adapter/resources/render-pipeline.js.map +1 -1
- package/dist/adapter/resources/resource.d.ts +13 -0
- package/dist/adapter/resources/resource.d.ts.map +1 -1
- package/dist/adapter/resources/resource.js +243 -14
- package/dist/adapter/resources/resource.js.map +1 -1
- package/dist/adapter/resources/shader.js +27 -25
- package/dist/adapter/resources/shader.js.map +1 -1
- package/dist/adapter/resources/shared-render-pipeline.d.ts +22 -0
- package/dist/adapter/resources/shared-render-pipeline.d.ts.map +1 -0
- package/dist/adapter/resources/shared-render-pipeline.js +25 -0
- package/dist/adapter/resources/shared-render-pipeline.js.map +1 -0
- package/dist/adapter/resources/texture-view.d.ts +1 -1
- package/dist/adapter/resources/texture-view.d.ts.map +1 -1
- package/dist/adapter/resources/texture.d.ts +168 -28
- package/dist/adapter/resources/texture.d.ts.map +1 -1
- package/dist/adapter/resources/texture.js +284 -25
- package/dist/adapter/resources/texture.js.map +1 -1
- package/dist/adapter/types/attachments.d.ts +1 -1
- package/dist/adapter/types/attachments.d.ts.map +1 -1
- package/dist/adapter/types/buffer-layout.d.ts +1 -1
- package/dist/adapter/types/buffer-layout.d.ts.map +1 -1
- package/dist/adapter/types/parameters.d.ts +3 -1
- package/dist/adapter/types/parameters.d.ts.map +1 -1
- package/dist/adapter/types/parameters.js +1 -0
- package/dist/adapter/types/parameters.js.map +1 -1
- package/dist/adapter/types/shader-layout.d.ts +10 -6
- package/dist/adapter/types/shader-layout.d.ts.map +1 -1
- package/dist/adapter/types/uniforms.d.ts +6 -0
- package/dist/adapter/types/uniforms.d.ts.map +1 -1
- package/dist/adapter-utils/bind-groups.d.ts +9 -0
- package/dist/adapter-utils/bind-groups.d.ts.map +1 -0
- package/dist/adapter-utils/bind-groups.js +41 -0
- package/dist/adapter-utils/bind-groups.js.map +1 -0
- package/dist/adapter-utils/format-compiler-log.d.ts.map +1 -1
- package/dist/adapter-utils/format-compiler-log.js +23 -15
- package/dist/adapter-utils/format-compiler-log.js.map +1 -1
- package/dist/adapter-utils/get-attribute-from-layouts.d.ts +2 -2
- package/dist/adapter-utils/get-attribute-from-layouts.d.ts.map +1 -1
- package/dist/adapter-utils/get-attribute-from-layouts.js +6 -6
- package/dist/adapter-utils/get-attribute-from-layouts.js.map +1 -1
- package/dist/dist.dev.js +2692 -645
- package/dist/dist.min.js +10 -9
- package/dist/factories/bind-group-factory.d.ts +20 -0
- package/dist/factories/bind-group-factory.d.ts.map +1 -0
- package/dist/factories/bind-group-factory.js +79 -0
- package/dist/factories/bind-group-factory.js.map +1 -0
- package/dist/factories/core-module-state.d.ts +7 -0
- package/dist/factories/core-module-state.d.ts.map +1 -0
- package/dist/{shadertypes/data-types/shader-types.js → factories/core-module-state.js} +1 -1
- package/dist/factories/core-module-state.js.map +1 -0
- package/dist/factories/pipeline-factory.d.ts +54 -0
- package/dist/factories/pipeline-factory.d.ts.map +1 -0
- package/dist/factories/pipeline-factory.js +270 -0
- package/dist/factories/pipeline-factory.js.map +1 -0
- package/dist/factories/shader-factory.d.ts +20 -0
- package/dist/factories/shader-factory.d.ts.map +1 -0
- package/dist/factories/shader-factory.js +84 -0
- package/dist/factories/shader-factory.js.map +1 -0
- package/dist/index.cjs +2427 -554
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +30 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -7
- package/dist/index.js.map +1 -1
- package/dist/portable/shader-block-writer.d.ts +51 -0
- package/dist/portable/shader-block-writer.d.ts.map +1 -0
- package/dist/portable/shader-block-writer.js +185 -0
- package/dist/portable/shader-block-writer.js.map +1 -0
- package/dist/portable/uniform-block.d.ts +1 -1
- package/dist/portable/uniform-block.d.ts.map +1 -1
- package/dist/portable/uniform-store.d.ts +55 -24
- package/dist/portable/uniform-store.d.ts.map +1 -1
- package/dist/portable/uniform-store.js +73 -25
- package/dist/portable/uniform-store.js.map +1 -1
- package/dist/shadertypes/data-types/data-type-decoder.d.ts +20 -0
- package/dist/shadertypes/data-types/data-type-decoder.d.ts.map +1 -0
- package/dist/shadertypes/data-types/data-type-decoder.js +79 -0
- package/dist/shadertypes/data-types/data-type-decoder.js.map +1 -0
- package/dist/shadertypes/data-types/data-types.d.ts +31 -12
- package/dist/shadertypes/data-types/data-types.d.ts.map +1 -1
- package/dist/shadertypes/data-types/decode-data-types.d.ts.map +1 -1
- package/dist/shadertypes/data-types/decode-data-types.js +2 -1
- package/dist/shadertypes/data-types/decode-data-types.js.map +1 -1
- package/dist/{image-utils → shadertypes/image-types}/image-types.d.ts +0 -6
- package/dist/shadertypes/image-types/image-types.d.ts.map +1 -0
- package/dist/shadertypes/image-types/image-types.js.map +1 -0
- package/dist/shadertypes/shader-types/shader-block-layout.d.ts +72 -0
- package/dist/shadertypes/shader-types/shader-block-layout.d.ts.map +1 -0
- package/dist/shadertypes/shader-types/shader-block-layout.js +209 -0
- package/dist/shadertypes/shader-types/shader-block-layout.js.map +1 -0
- package/dist/shadertypes/shader-types/shader-type-decoder.d.ts +41 -0
- package/dist/shadertypes/shader-types/shader-type-decoder.d.ts.map +1 -0
- package/dist/shadertypes/{data-types/decode-shader-types.js → shader-types/shader-type-decoder.js} +43 -4
- package/dist/shadertypes/shader-types/shader-type-decoder.js.map +1 -0
- package/dist/shadertypes/shader-types/shader-types.d.ts +101 -0
- package/dist/shadertypes/shader-types/shader-types.d.ts.map +1 -0
- package/dist/shadertypes/shader-types/shader-types.js +30 -0
- package/dist/shadertypes/shader-types/shader-types.js.map +1 -0
- package/dist/shadertypes/texture-types/pixel-utils.d.ts.map +1 -0
- package/dist/shadertypes/{textures → texture-types}/pixel-utils.js +4 -4
- package/dist/shadertypes/texture-types/pixel-utils.js.map +1 -0
- package/dist/shadertypes/texture-types/texture-format-decoder.d.ts +36 -0
- package/dist/shadertypes/texture-types/texture-format-decoder.d.ts.map +1 -0
- package/dist/shadertypes/{textures → texture-types}/texture-format-decoder.js +109 -37
- package/dist/shadertypes/texture-types/texture-format-decoder.js.map +1 -0
- package/dist/shadertypes/texture-types/texture-format-generics.d.ts +34 -0
- package/dist/shadertypes/texture-types/texture-format-generics.d.ts.map +1 -0
- package/dist/shadertypes/texture-types/texture-format-generics.js.map +1 -0
- package/dist/shadertypes/texture-types/texture-format-table.d.ts.map +1 -0
- package/dist/shadertypes/{textures → texture-types}/texture-format-table.js +10 -9
- package/dist/shadertypes/texture-types/texture-format-table.js.map +1 -0
- package/dist/shadertypes/{textures → texture-types}/texture-formats.d.ts +51 -17
- package/dist/shadertypes/texture-types/texture-formats.d.ts.map +1 -0
- package/dist/shadertypes/{textures → texture-types}/texture-formats.js +1 -0
- package/dist/shadertypes/texture-types/texture-formats.js.map +1 -0
- package/dist/shadertypes/texture-types/texture-layout.d.ts +5 -0
- package/dist/shadertypes/texture-types/texture-layout.d.ts.map +1 -0
- package/dist/shadertypes/texture-types/texture-layout.js +41 -0
- package/dist/shadertypes/texture-types/texture-layout.js.map +1 -0
- package/dist/shadertypes/vertex-types/vertex-format-decoder.d.ts +24 -0
- package/dist/shadertypes/vertex-types/vertex-format-decoder.d.ts.map +1 -0
- package/dist/shadertypes/vertex-types/vertex-format-decoder.js +106 -0
- package/dist/shadertypes/vertex-types/vertex-format-decoder.js.map +1 -0
- package/dist/shadertypes/vertex-types/vertex-formats.d.ts +50 -0
- package/dist/shadertypes/vertex-types/vertex-formats.d.ts.map +1 -0
- package/dist/shadertypes/vertex-types/vertex-formats.js.map +1 -0
- package/dist/utils/array-equal.d.ts +1 -1
- package/dist/utils/array-equal.d.ts.map +1 -1
- package/dist/utils/array-equal.js +15 -9
- package/dist/utils/array-equal.js.map +1 -1
- package/dist/utils/assert.d.ts +5 -0
- package/dist/utils/assert.d.ts.map +1 -0
- package/dist/utils/assert.js +17 -0
- package/dist/utils/assert.js.map +1 -0
- package/dist/utils/stats-manager.d.ts.map +1 -1
- package/dist/utils/stats-manager.js +61 -1
- package/dist/utils/stats-manager.js.map +1 -1
- package/package.json +6 -6
- package/src/adapter/canvas-context.ts +7 -556
- package/src/adapter/canvas-observer.ts +130 -0
- package/src/adapter/canvas-surface.ts +521 -0
- package/src/adapter/device.ts +312 -24
- package/src/adapter/presentation-context.ts +16 -0
- package/src/adapter/resources/buffer.ts +19 -9
- package/src/adapter/resources/command-buffer.ts +4 -2
- package/src/adapter/resources/command-encoder.ts +101 -10
- package/src/adapter/resources/compute-pipeline.ts +2 -2
- package/src/adapter/resources/fence.ts +32 -0
- package/src/adapter/resources/framebuffer.ts +16 -13
- package/src/adapter/resources/query-set.ts +17 -1
- package/src/adapter/resources/render-pipeline.ts +52 -16
- package/src/adapter/resources/resource.ts +289 -14
- package/src/adapter/resources/shader.ts +28 -28
- package/src/adapter/resources/shared-render-pipeline.ts +40 -0
- package/src/adapter/resources/texture-view.ts +1 -1
- package/src/adapter/resources/texture.ts +427 -49
- package/src/adapter/types/attachments.ts +1 -1
- package/src/adapter/types/buffer-layout.ts +1 -1
- package/src/adapter/types/parameters.ts +4 -1
- package/src/adapter/types/shader-layout.ts +15 -9
- package/src/adapter/types/uniforms.ts +12 -0
- package/src/adapter-utils/bind-groups.ts +71 -0
- package/src/adapter-utils/format-compiler-log.ts +23 -15
- package/src/adapter-utils/get-attribute-from-layouts.ts +8 -11
- package/src/factories/bind-group-factory.ts +139 -0
- package/src/factories/core-module-state.ts +11 -0
- package/src/factories/pipeline-factory.ts +328 -0
- package/src/factories/shader-factory.ts +103 -0
- package/src/index.ts +70 -26
- package/src/portable/shader-block-writer.ts +254 -0
- package/src/portable/uniform-block.ts +1 -1
- package/src/portable/uniform-store.ts +98 -40
- package/src/shadertypes/data-types/data-type-decoder.ts +105 -0
- package/src/shadertypes/data-types/data-types.ts +100 -48
- package/src/shadertypes/data-types/decode-data-types.ts +2 -1
- package/src/{image-utils → shadertypes/image-types}/image-types.ts +0 -7
- package/src/shadertypes/shader-types/shader-block-layout.ts +340 -0
- package/src/shadertypes/{data-types/decode-shader-types.ts → shader-types/shader-type-decoder.ts} +88 -14
- package/src/shadertypes/shader-types/shader-types.ts +207 -0
- package/src/shadertypes/{textures → texture-types}/pixel-utils.ts +4 -4
- package/src/shadertypes/{textures → texture-types}/texture-format-decoder.ts +166 -45
- package/src/shadertypes/{textures → texture-types}/texture-format-generics.ts +42 -48
- package/src/shadertypes/{textures → texture-types}/texture-format-table.ts +10 -9
- package/src/shadertypes/{textures → texture-types}/texture-formats.ts +73 -17
- package/src/shadertypes/texture-types/texture-layout.ts +60 -0
- package/src/shadertypes/vertex-types/vertex-format-decoder.ts +131 -0
- package/src/shadertypes/vertex-types/vertex-formats.ts +183 -0
- package/src/utils/array-equal.ts +21 -9
- package/src/utils/assert.ts +18 -0
- package/src/utils/stats-manager.ts +76 -2
- package/dist/image-utils/image-types.d.ts.map +0 -1
- package/dist/image-utils/image-types.js.map +0 -1
- package/dist/portable/uniform-buffer-layout.d.ts +0 -28
- package/dist/portable/uniform-buffer-layout.d.ts.map +0 -1
- package/dist/portable/uniform-buffer-layout.js +0 -96
- package/dist/portable/uniform-buffer-layout.js.map +0 -1
- package/dist/shadertypes/data-types/decode-shader-types.d.ts +0 -17
- package/dist/shadertypes/data-types/decode-shader-types.d.ts.map +0 -1
- package/dist/shadertypes/data-types/decode-shader-types.js.map +0 -1
- package/dist/shadertypes/data-types/shader-types.d.ts +0 -45
- package/dist/shadertypes/data-types/shader-types.d.ts.map +0 -1
- package/dist/shadertypes/data-types/shader-types.js.map +0 -1
- package/dist/shadertypes/textures/pixel-utils.d.ts.map +0 -1
- package/dist/shadertypes/textures/pixel-utils.js.map +0 -1
- package/dist/shadertypes/textures/texture-format-decoder.d.ts +0 -18
- package/dist/shadertypes/textures/texture-format-decoder.d.ts.map +0 -1
- package/dist/shadertypes/textures/texture-format-decoder.js.map +0 -1
- package/dist/shadertypes/textures/texture-format-generics.d.ts +0 -33
- package/dist/shadertypes/textures/texture-format-generics.d.ts.map +0 -1
- package/dist/shadertypes/textures/texture-format-generics.js.map +0 -1
- package/dist/shadertypes/textures/texture-format-table.d.ts.map +0 -1
- package/dist/shadertypes/textures/texture-format-table.js.map +0 -1
- package/dist/shadertypes/textures/texture-formats.d.ts.map +0 -1
- package/dist/shadertypes/textures/texture-formats.js.map +0 -1
- package/dist/shadertypes/vertex-arrays/decode-vertex-format.d.ts +0 -18
- package/dist/shadertypes/vertex-arrays/decode-vertex-format.d.ts.map +0 -1
- package/dist/shadertypes/vertex-arrays/decode-vertex-format.js +0 -100
- package/dist/shadertypes/vertex-arrays/decode-vertex-format.js.map +0 -1
- package/dist/shadertypes/vertex-arrays/vertex-formats.d.ts +0 -27
- package/dist/shadertypes/vertex-arrays/vertex-formats.d.ts.map +0 -1
- package/dist/shadertypes/vertex-arrays/vertex-formats.js.map +0 -1
- package/src/portable/uniform-buffer-layout.ts +0 -118
- package/src/shadertypes/data-types/shader-types.ts +0 -87
- package/src/shadertypes/vertex-arrays/decode-vertex-format.ts +0 -124
- package/src/shadertypes/vertex-arrays/vertex-formats.ts +0 -91
- /package/dist/{image-utils → shadertypes/image-types}/image-types.js +0 -0
- /package/dist/shadertypes/{textures → texture-types}/pixel-utils.d.ts +0 -0
- /package/dist/shadertypes/{textures → texture-types}/texture-format-generics.js +0 -0
- /package/dist/shadertypes/{textures → texture-types}/texture-format-table.d.ts +0 -0
- /package/dist/shadertypes/{vertex-arrays → vertex-types}/vertex-formats.js +0 -0
package/dist/dist.dev.js
CHANGED
|
@@ -43,39 +43,51 @@ var __exports__ = (() => {
|
|
|
43
43
|
DeviceFeatures: () => DeviceFeatures,
|
|
44
44
|
DeviceLimits: () => DeviceLimits,
|
|
45
45
|
ExternalTexture: () => ExternalTexture,
|
|
46
|
+
Fence: () => Fence,
|
|
46
47
|
Framebuffer: () => Framebuffer,
|
|
48
|
+
PipelineFactory: () => PipelineFactory,
|
|
47
49
|
PipelineLayout: () => PipelineLayout,
|
|
50
|
+
PresentationContext: () => PresentationContext,
|
|
48
51
|
QuerySet: () => QuerySet,
|
|
49
52
|
RenderPass: () => RenderPass,
|
|
50
53
|
RenderPipeline: () => RenderPipeline,
|
|
51
54
|
Resource: () => Resource,
|
|
52
55
|
Sampler: () => Sampler,
|
|
53
56
|
Shader: () => Shader,
|
|
57
|
+
ShaderBlockWriter: () => ShaderBlockWriter,
|
|
58
|
+
ShaderFactory: () => ShaderFactory,
|
|
59
|
+
SharedRenderPipeline: () => SharedRenderPipeline,
|
|
54
60
|
Texture: () => Texture,
|
|
55
|
-
TextureFormatDecoder: () => TextureFormatDecoder,
|
|
56
61
|
TextureView: () => TextureView,
|
|
57
62
|
TransformFeedback: () => TransformFeedback,
|
|
58
63
|
UniformBlock: () => UniformBlock,
|
|
59
|
-
UniformBufferLayout: () => UniformBufferLayout,
|
|
60
64
|
UniformStore: () => UniformStore,
|
|
61
65
|
VertexArray: () => VertexArray,
|
|
66
|
+
_getDefaultBindGroupFactory: () => _getDefaultBindGroupFactory,
|
|
62
67
|
_getTextureFormatDefinition: () => getTextureFormatDefinition,
|
|
63
68
|
_getTextureFormatTable: () => getTextureFormatTable,
|
|
69
|
+
assert: () => assert2,
|
|
70
|
+
assertDefined: () => assertDefined,
|
|
71
|
+
dataTypeDecoder: () => dataTypeDecoder,
|
|
72
|
+
flattenBindingsByGroup: () => flattenBindingsByGroup,
|
|
64
73
|
getAttributeInfosFromLayouts: () => getAttributeInfosFromLayouts,
|
|
65
74
|
getAttributeShaderTypeInfo: () => getAttributeShaderTypeInfo,
|
|
66
|
-
|
|
67
|
-
getDataTypeInfo: () => getDataTypeInfo,
|
|
68
|
-
getNormalizedDataType: () => getNormalizedDataType,
|
|
75
|
+
getExternalImageSize: () => getExternalImageSize,
|
|
69
76
|
getScratchArray: () => getScratchArray,
|
|
77
|
+
getShaderLayoutBinding: () => getShaderLayoutBinding,
|
|
78
|
+
getTextureImageView: () => getTextureImageView,
|
|
70
79
|
getTypedArrayConstructor: () => getTypedArrayConstructor,
|
|
71
80
|
getVariableShaderTypeInfo: () => getVariableShaderTypeInfo,
|
|
72
|
-
|
|
73
|
-
getVertexFormatInfo: () => getVertexFormatInfo,
|
|
81
|
+
isExternalImage: () => isExternalImage,
|
|
74
82
|
log: () => log,
|
|
75
83
|
luma: () => luma,
|
|
76
|
-
|
|
84
|
+
makeShaderBlockLayout: () => makeShaderBlockLayout,
|
|
85
|
+
normalizeBindingsByGroup: () => normalizeBindingsByGroup,
|
|
77
86
|
readPixel: () => readPixel,
|
|
87
|
+
setTextureImageData: () => setTextureImageData,
|
|
88
|
+
shaderTypeDecoder: () => shaderTypeDecoder,
|
|
78
89
|
textureFormatDecoder: () => textureFormatDecoder,
|
|
90
|
+
vertexFormatDecoder: () => vertexFormatDecoder,
|
|
79
91
|
writePixel: () => writePixel
|
|
80
92
|
});
|
|
81
93
|
|
|
@@ -273,6 +285,24 @@ var __exports__ = (() => {
|
|
|
273
285
|
};
|
|
274
286
|
|
|
275
287
|
// src/utils/stats-manager.ts
|
|
288
|
+
var GPU_TIME_AND_MEMORY_STATS = "GPU Time and Memory";
|
|
289
|
+
var GPU_TIME_AND_MEMORY_STAT_ORDER = [
|
|
290
|
+
"Adapter",
|
|
291
|
+
"GPU",
|
|
292
|
+
"GPU Type",
|
|
293
|
+
"GPU Backend",
|
|
294
|
+
"Frame Rate",
|
|
295
|
+
"CPU Time",
|
|
296
|
+
"GPU Time",
|
|
297
|
+
"GPU Memory",
|
|
298
|
+
"Buffer Memory",
|
|
299
|
+
"Texture Memory",
|
|
300
|
+
"Referenced Buffer Memory",
|
|
301
|
+
"Referenced Texture Memory",
|
|
302
|
+
"Swap Chain Texture"
|
|
303
|
+
];
|
|
304
|
+
var ORDERED_STATS_CACHE = /* @__PURE__ */ new WeakMap();
|
|
305
|
+
var ORDERED_STAT_NAME_SET_CACHE = /* @__PURE__ */ new WeakMap();
|
|
276
306
|
var StatsManager = class {
|
|
277
307
|
stats = /* @__PURE__ */ new Map();
|
|
278
308
|
getStats(name2) {
|
|
@@ -282,10 +312,50 @@ var __exports__ = (() => {
|
|
|
282
312
|
if (!this.stats.has(name2)) {
|
|
283
313
|
this.stats.set(name2, new Stats({ id: name2 }));
|
|
284
314
|
}
|
|
285
|
-
|
|
315
|
+
const stats = this.stats.get(name2);
|
|
316
|
+
if (name2 === GPU_TIME_AND_MEMORY_STATS) {
|
|
317
|
+
initializeStats(stats, GPU_TIME_AND_MEMORY_STAT_ORDER);
|
|
318
|
+
}
|
|
319
|
+
return stats;
|
|
286
320
|
}
|
|
287
321
|
};
|
|
288
322
|
var lumaStats = new StatsManager();
|
|
323
|
+
function initializeStats(stats, orderedStatNames) {
|
|
324
|
+
const statsMap = stats.stats;
|
|
325
|
+
let addedOrderedStat = false;
|
|
326
|
+
for (const statName of orderedStatNames) {
|
|
327
|
+
if (!statsMap[statName]) {
|
|
328
|
+
stats.get(statName);
|
|
329
|
+
addedOrderedStat = true;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
const statCount = Object.keys(statsMap).length;
|
|
333
|
+
const cachedStats = ORDERED_STATS_CACHE.get(stats);
|
|
334
|
+
if (!addedOrderedStat && cachedStats?.orderedStatNames === orderedStatNames && cachedStats.statCount === statCount) {
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
const reorderedStats = {};
|
|
338
|
+
let orderedStatNamesSet = ORDERED_STAT_NAME_SET_CACHE.get(orderedStatNames);
|
|
339
|
+
if (!orderedStatNamesSet) {
|
|
340
|
+
orderedStatNamesSet = new Set(orderedStatNames);
|
|
341
|
+
ORDERED_STAT_NAME_SET_CACHE.set(orderedStatNames, orderedStatNamesSet);
|
|
342
|
+
}
|
|
343
|
+
for (const statName of orderedStatNames) {
|
|
344
|
+
if (statsMap[statName]) {
|
|
345
|
+
reorderedStats[statName] = statsMap[statName];
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
for (const [statName, stat] of Object.entries(statsMap)) {
|
|
349
|
+
if (!orderedStatNamesSet.has(statName)) {
|
|
350
|
+
reorderedStats[statName] = stat;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
for (const statName of Object.keys(statsMap)) {
|
|
354
|
+
delete statsMap[statName];
|
|
355
|
+
}
|
|
356
|
+
Object.assign(statsMap, reorderedStats);
|
|
357
|
+
ORDERED_STATS_CACHE.set(stats, { orderedStatNames, statCount });
|
|
358
|
+
}
|
|
289
359
|
|
|
290
360
|
// ../../node_modules/@probe.gl/env/dist/lib/globals.js
|
|
291
361
|
var window_ = globalThis;
|
|
@@ -317,7 +387,139 @@ var __exports__ = (() => {
|
|
|
317
387
|
}
|
|
318
388
|
|
|
319
389
|
// ../../node_modules/@probe.gl/env/dist/index.js
|
|
320
|
-
var VERSION = true ? "4.1.
|
|
390
|
+
var VERSION = true ? "4.1.1" : "untranspiled source";
|
|
391
|
+
|
|
392
|
+
// ../../node_modules/@probe.gl/log/dist/utils/assert.js
|
|
393
|
+
function assert(condition, message) {
|
|
394
|
+
if (!condition) {
|
|
395
|
+
throw new Error(message || "Assertion failed");
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// ../../node_modules/@probe.gl/log/dist/loggers/log-utils.js
|
|
400
|
+
function normalizeLogLevel(logLevel) {
|
|
401
|
+
if (!logLevel) {
|
|
402
|
+
return 0;
|
|
403
|
+
}
|
|
404
|
+
let resolvedLevel;
|
|
405
|
+
switch (typeof logLevel) {
|
|
406
|
+
case "number":
|
|
407
|
+
resolvedLevel = logLevel;
|
|
408
|
+
break;
|
|
409
|
+
case "object":
|
|
410
|
+
resolvedLevel = logLevel.logLevel || logLevel.priority || 0;
|
|
411
|
+
break;
|
|
412
|
+
default:
|
|
413
|
+
return 0;
|
|
414
|
+
}
|
|
415
|
+
assert(Number.isFinite(resolvedLevel) && resolvedLevel >= 0);
|
|
416
|
+
return resolvedLevel;
|
|
417
|
+
}
|
|
418
|
+
function normalizeArguments(opts) {
|
|
419
|
+
const { logLevel, message } = opts;
|
|
420
|
+
opts.logLevel = normalizeLogLevel(logLevel);
|
|
421
|
+
const args = opts.args ? Array.from(opts.args) : [];
|
|
422
|
+
while (args.length && args.shift() !== message) {
|
|
423
|
+
}
|
|
424
|
+
switch (typeof logLevel) {
|
|
425
|
+
case "string":
|
|
426
|
+
case "function":
|
|
427
|
+
if (message !== void 0) {
|
|
428
|
+
args.unshift(message);
|
|
429
|
+
}
|
|
430
|
+
opts.message = logLevel;
|
|
431
|
+
break;
|
|
432
|
+
case "object":
|
|
433
|
+
Object.assign(opts, logLevel);
|
|
434
|
+
break;
|
|
435
|
+
default:
|
|
436
|
+
}
|
|
437
|
+
if (typeof opts.message === "function") {
|
|
438
|
+
opts.message = opts.message();
|
|
439
|
+
}
|
|
440
|
+
const messageType = typeof opts.message;
|
|
441
|
+
assert(messageType === "string" || messageType === "object");
|
|
442
|
+
return Object.assign(opts, { args }, opts.opts);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// ../../node_modules/@probe.gl/log/dist/loggers/base-log.js
|
|
446
|
+
var noop = () => {
|
|
447
|
+
};
|
|
448
|
+
var BaseLog = class {
|
|
449
|
+
constructor({ level = 0 } = {}) {
|
|
450
|
+
this.userData = {};
|
|
451
|
+
this._onceCache = /* @__PURE__ */ new Set();
|
|
452
|
+
this._level = level;
|
|
453
|
+
}
|
|
454
|
+
set level(newLevel) {
|
|
455
|
+
this.setLevel(newLevel);
|
|
456
|
+
}
|
|
457
|
+
get level() {
|
|
458
|
+
return this.getLevel();
|
|
459
|
+
}
|
|
460
|
+
setLevel(level) {
|
|
461
|
+
this._level = level;
|
|
462
|
+
return this;
|
|
463
|
+
}
|
|
464
|
+
getLevel() {
|
|
465
|
+
return this._level;
|
|
466
|
+
}
|
|
467
|
+
// Unconditional logging
|
|
468
|
+
warn(message, ...args) {
|
|
469
|
+
return this._log("warn", 0, message, args, { once: true });
|
|
470
|
+
}
|
|
471
|
+
error(message, ...args) {
|
|
472
|
+
return this._log("error", 0, message, args);
|
|
473
|
+
}
|
|
474
|
+
// Conditional logging
|
|
475
|
+
log(logLevel, message, ...args) {
|
|
476
|
+
return this._log("log", logLevel, message, args);
|
|
477
|
+
}
|
|
478
|
+
info(logLevel, message, ...args) {
|
|
479
|
+
return this._log("info", logLevel, message, args);
|
|
480
|
+
}
|
|
481
|
+
once(logLevel, message, ...args) {
|
|
482
|
+
return this._log("once", logLevel, message, args, { once: true });
|
|
483
|
+
}
|
|
484
|
+
_log(type, logLevel, message, args, options = {}) {
|
|
485
|
+
const normalized = normalizeArguments({
|
|
486
|
+
logLevel,
|
|
487
|
+
message,
|
|
488
|
+
args: this._buildArgs(logLevel, message, args),
|
|
489
|
+
opts: options
|
|
490
|
+
});
|
|
491
|
+
return this._createLogFunction(type, normalized, options);
|
|
492
|
+
}
|
|
493
|
+
_buildArgs(logLevel, message, args) {
|
|
494
|
+
return [logLevel, message, ...args];
|
|
495
|
+
}
|
|
496
|
+
_createLogFunction(type, normalized, options) {
|
|
497
|
+
if (!this._shouldLog(normalized.logLevel)) {
|
|
498
|
+
return noop;
|
|
499
|
+
}
|
|
500
|
+
const tag = this._getOnceTag(options.tag ?? normalized.tag ?? normalized.message);
|
|
501
|
+
if ((options.once || normalized.once) && tag !== void 0) {
|
|
502
|
+
if (this._onceCache.has(tag)) {
|
|
503
|
+
return noop;
|
|
504
|
+
}
|
|
505
|
+
this._onceCache.add(tag);
|
|
506
|
+
}
|
|
507
|
+
return this._emit(type, normalized);
|
|
508
|
+
}
|
|
509
|
+
_shouldLog(logLevel) {
|
|
510
|
+
return this.getLevel() >= normalizeLogLevel(logLevel);
|
|
511
|
+
}
|
|
512
|
+
_getOnceTag(tag) {
|
|
513
|
+
if (tag === void 0) {
|
|
514
|
+
return void 0;
|
|
515
|
+
}
|
|
516
|
+
try {
|
|
517
|
+
return typeof tag === "string" ? tag : String(tag);
|
|
518
|
+
} catch {
|
|
519
|
+
return void 0;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
};
|
|
321
523
|
|
|
322
524
|
// ../../node_modules/@probe.gl/log/dist/utils/local-storage.js
|
|
323
525
|
function getStorage(type) {
|
|
@@ -436,13 +638,6 @@ var __exports__ = (() => {
|
|
|
436
638
|
}
|
|
437
639
|
}
|
|
438
640
|
|
|
439
|
-
// ../../node_modules/@probe.gl/log/dist/utils/assert.js
|
|
440
|
-
function assert(condition, message) {
|
|
441
|
-
if (!condition) {
|
|
442
|
-
throw new Error(message || "Assertion failed");
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
|
|
446
641
|
// ../../node_modules/@probe.gl/log/dist/utils/hi-res-timestamp.js
|
|
447
642
|
function getHiResTimestamp2() {
|
|
448
643
|
let timestamp;
|
|
@@ -457,7 +652,7 @@ var __exports__ = (() => {
|
|
|
457
652
|
return timestamp;
|
|
458
653
|
}
|
|
459
654
|
|
|
460
|
-
// ../../node_modules/@probe.gl/log/dist/log.js
|
|
655
|
+
// ../../node_modules/@probe.gl/log/dist/loggers/probe-log.js
|
|
461
656
|
var originalConsole = {
|
|
462
657
|
debug: isBrowser() ? console.debug || console.log : console.log,
|
|
463
658
|
log: console.log,
|
|
@@ -469,12 +664,9 @@ var __exports__ = (() => {
|
|
|
469
664
|
enabled: true,
|
|
470
665
|
level: 0
|
|
471
666
|
};
|
|
472
|
-
|
|
473
|
-
}
|
|
474
|
-
var cache = {};
|
|
475
|
-
var ONCE = { once: true };
|
|
476
|
-
var Log = class {
|
|
667
|
+
var ProbeLog = class extends BaseLog {
|
|
477
668
|
constructor({ id } = { id: "" }) {
|
|
669
|
+
super({ level: 0 });
|
|
478
670
|
this.VERSION = VERSION;
|
|
479
671
|
this._startTs = getHiResTimestamp2();
|
|
480
672
|
this._deltaTs = getHiResTimestamp2();
|
|
@@ -482,22 +674,16 @@ var __exports__ = (() => {
|
|
|
482
674
|
this.LOG_THROTTLE_TIMEOUT = 0;
|
|
483
675
|
this.id = id;
|
|
484
676
|
this.userData = {};
|
|
485
|
-
this._storage = new LocalStorage(`__probe-${this.id}__`, DEFAULT_LOG_CONFIGURATION);
|
|
677
|
+
this._storage = new LocalStorage(`__probe-${this.id}__`, { [this.id]: DEFAULT_LOG_CONFIGURATION });
|
|
486
678
|
this.timeStamp(`${this.id} started`);
|
|
487
679
|
autobind(this);
|
|
488
680
|
Object.seal(this);
|
|
489
681
|
}
|
|
490
|
-
set level(newLevel) {
|
|
491
|
-
this.setLevel(newLevel);
|
|
492
|
-
}
|
|
493
|
-
get level() {
|
|
494
|
-
return this.getLevel();
|
|
495
|
-
}
|
|
496
682
|
isEnabled() {
|
|
497
|
-
return this.
|
|
683
|
+
return this._getConfiguration().enabled;
|
|
498
684
|
}
|
|
499
685
|
getLevel() {
|
|
500
|
-
return this.
|
|
686
|
+
return this._getConfiguration().level;
|
|
501
687
|
}
|
|
502
688
|
/** @return milliseconds, with fractions */
|
|
503
689
|
getTotal() {
|
|
@@ -521,20 +707,20 @@ var __exports__ = (() => {
|
|
|
521
707
|
}
|
|
522
708
|
// Configure
|
|
523
709
|
enable(enabled = true) {
|
|
524
|
-
this.
|
|
710
|
+
this._updateConfiguration({ enabled });
|
|
525
711
|
return this;
|
|
526
712
|
}
|
|
527
713
|
setLevel(level) {
|
|
528
|
-
this.
|
|
714
|
+
this._updateConfiguration({ level });
|
|
529
715
|
return this;
|
|
530
716
|
}
|
|
531
717
|
/** return the current status of the setting */
|
|
532
718
|
get(setting) {
|
|
533
|
-
return this.
|
|
719
|
+
return this._getConfiguration()[setting];
|
|
534
720
|
}
|
|
535
721
|
// update the status of the setting
|
|
536
722
|
set(setting, value) {
|
|
537
|
-
this.
|
|
723
|
+
this._updateConfiguration({ [setting]: value });
|
|
538
724
|
}
|
|
539
725
|
/** Logs the current settings as a table */
|
|
540
726
|
settings() {
|
|
@@ -550,11 +736,16 @@ var __exports__ = (() => {
|
|
|
550
736
|
throw new Error(message || "Assertion failed");
|
|
551
737
|
}
|
|
552
738
|
}
|
|
553
|
-
warn(message) {
|
|
554
|
-
return this.
|
|
739
|
+
warn(message, ...args) {
|
|
740
|
+
return this._log("warn", 0, message, args, {
|
|
741
|
+
method: originalConsole.warn,
|
|
742
|
+
once: true
|
|
743
|
+
});
|
|
555
744
|
}
|
|
556
|
-
error(message) {
|
|
557
|
-
return this.
|
|
745
|
+
error(message, ...args) {
|
|
746
|
+
return this._log("error", 0, message, args, {
|
|
747
|
+
method: originalConsole.error
|
|
748
|
+
});
|
|
558
749
|
}
|
|
559
750
|
/** Print a deprecation warning */
|
|
560
751
|
deprecated(oldUsage, newUsage) {
|
|
@@ -564,50 +755,63 @@ var __exports__ = (() => {
|
|
|
564
755
|
removed(oldUsage, newUsage) {
|
|
565
756
|
return this.error(`\`${oldUsage}\` has been removed. Use \`${newUsage}\` instead`);
|
|
566
757
|
}
|
|
567
|
-
probe(logLevel, message) {
|
|
568
|
-
return this.
|
|
758
|
+
probe(logLevel, message, ...args) {
|
|
759
|
+
return this._log("log", logLevel, message, args, {
|
|
760
|
+
method: originalConsole.log,
|
|
569
761
|
time: true,
|
|
570
762
|
once: true
|
|
571
763
|
});
|
|
572
764
|
}
|
|
573
|
-
log(logLevel, message) {
|
|
574
|
-
return this.
|
|
765
|
+
log(logLevel, message, ...args) {
|
|
766
|
+
return this._log("log", logLevel, message, args, {
|
|
767
|
+
method: originalConsole.debug
|
|
768
|
+
});
|
|
575
769
|
}
|
|
576
|
-
info(logLevel, message) {
|
|
577
|
-
return this.
|
|
770
|
+
info(logLevel, message, ...args) {
|
|
771
|
+
return this._log("info", logLevel, message, args, { method: console.info });
|
|
578
772
|
}
|
|
579
|
-
once(logLevel, message) {
|
|
580
|
-
return this.
|
|
773
|
+
once(logLevel, message, ...args) {
|
|
774
|
+
return this._log("once", logLevel, message, args, {
|
|
775
|
+
method: originalConsole.debug || originalConsole.info,
|
|
776
|
+
once: true
|
|
777
|
+
});
|
|
581
778
|
}
|
|
582
779
|
/** Logs an object as a table */
|
|
583
780
|
table(logLevel, table, columns) {
|
|
584
781
|
if (table) {
|
|
585
|
-
return this.
|
|
782
|
+
return this._log("table", logLevel, table, columns && [columns] || [], {
|
|
783
|
+
method: console.table || noop,
|
|
586
784
|
tag: getTableHeader(table)
|
|
587
785
|
});
|
|
588
786
|
}
|
|
589
787
|
return noop;
|
|
590
788
|
}
|
|
591
789
|
time(logLevel, message) {
|
|
592
|
-
return this.
|
|
790
|
+
return this._log("time", logLevel, message, [], {
|
|
791
|
+
method: console.time ? console.time : console.info
|
|
792
|
+
});
|
|
593
793
|
}
|
|
594
794
|
timeEnd(logLevel, message) {
|
|
595
|
-
return this.
|
|
795
|
+
return this._log("time", logLevel, message, [], {
|
|
796
|
+
method: console.timeEnd ? console.timeEnd : console.info
|
|
797
|
+
});
|
|
596
798
|
}
|
|
597
799
|
timeStamp(logLevel, message) {
|
|
598
|
-
return this.
|
|
800
|
+
return this._log("time", logLevel, message, [], {
|
|
801
|
+
method: console.timeStamp || noop
|
|
802
|
+
});
|
|
599
803
|
}
|
|
600
804
|
group(logLevel, message, opts = { collapsed: false }) {
|
|
601
|
-
const
|
|
602
|
-
|
|
603
|
-
options.method = (collapsed ? console.groupCollapsed : console.group) || console.info;
|
|
604
|
-
return this._getLogFunction(options);
|
|
805
|
+
const method = (opts.collapsed ? console.groupCollapsed : console.group) || console.info;
|
|
806
|
+
return this._log("group", logLevel, message, [], { method });
|
|
605
807
|
}
|
|
606
808
|
groupCollapsed(logLevel, message, opts = {}) {
|
|
607
809
|
return this.group(logLevel, message, Object.assign({}, opts, { collapsed: true }));
|
|
608
810
|
}
|
|
609
811
|
groupEnd(logLevel) {
|
|
610
|
-
return this.
|
|
812
|
+
return this._log("groupEnd", logLevel, "", [], {
|
|
813
|
+
method: console.groupEnd || noop
|
|
814
|
+
});
|
|
611
815
|
}
|
|
612
816
|
// EXPERIMENTAL
|
|
613
817
|
withGroup(logLevel, message, func) {
|
|
@@ -623,78 +827,34 @@ var __exports__ = (() => {
|
|
|
623
827
|
console.trace();
|
|
624
828
|
}
|
|
625
829
|
}
|
|
626
|
-
// PRIVATE METHODS
|
|
627
|
-
/** Deduces log level from a variety of arguments */
|
|
628
830
|
_shouldLog(logLevel) {
|
|
629
|
-
return this.isEnabled() &&
|
|
630
|
-
}
|
|
631
|
-
_getLogFunction(logLevel, message, method, args, opts) {
|
|
632
|
-
if (this._shouldLog(logLevel)) {
|
|
633
|
-
opts = normalizeArguments({ logLevel, message, args, opts });
|
|
634
|
-
method = method || opts.method;
|
|
635
|
-
assert(method);
|
|
636
|
-
opts.total = this.getTotal();
|
|
637
|
-
opts.delta = this.getDelta();
|
|
638
|
-
this._deltaTs = getHiResTimestamp2();
|
|
639
|
-
const tag = opts.tag || opts.message;
|
|
640
|
-
if (opts.once && tag) {
|
|
641
|
-
if (!cache[tag]) {
|
|
642
|
-
cache[tag] = getHiResTimestamp2();
|
|
643
|
-
} else {
|
|
644
|
-
return noop;
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
message = decorateMessage(this.id, opts.message, opts);
|
|
648
|
-
return method.bind(console, message, ...opts.args);
|
|
649
|
-
}
|
|
650
|
-
return noop;
|
|
831
|
+
return this.isEnabled() && super._shouldLog(logLevel);
|
|
651
832
|
}
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
case "number":
|
|
661
|
-
resolvedLevel = logLevel;
|
|
662
|
-
break;
|
|
663
|
-
case "object":
|
|
664
|
-
resolvedLevel = logLevel.logLevel || logLevel.priority || 0;
|
|
665
|
-
break;
|
|
666
|
-
default:
|
|
667
|
-
return 0;
|
|
668
|
-
}
|
|
669
|
-
assert(Number.isFinite(resolvedLevel) && resolvedLevel >= 0);
|
|
670
|
-
return resolvedLevel;
|
|
671
|
-
}
|
|
672
|
-
function normalizeArguments(opts) {
|
|
673
|
-
const { logLevel, message } = opts;
|
|
674
|
-
opts.logLevel = normalizeLogLevel(logLevel);
|
|
675
|
-
const args = opts.args ? Array.from(opts.args) : [];
|
|
676
|
-
while (args.length && args.shift() !== message) {
|
|
833
|
+
_emit(_type, normalized) {
|
|
834
|
+
const method = normalized.method;
|
|
835
|
+
assert(method);
|
|
836
|
+
normalized.total = this.getTotal();
|
|
837
|
+
normalized.delta = this.getDelta();
|
|
838
|
+
this._deltaTs = getHiResTimestamp2();
|
|
839
|
+
const message = decorateMessage(this.id, normalized.message, normalized);
|
|
840
|
+
return method.bind(console, message, ...normalized.args);
|
|
677
841
|
}
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
}
|
|
684
|
-
opts.message = logLevel;
|
|
685
|
-
break;
|
|
686
|
-
case "object":
|
|
687
|
-
Object.assign(opts, logLevel);
|
|
688
|
-
break;
|
|
689
|
-
default:
|
|
842
|
+
_getConfiguration() {
|
|
843
|
+
if (!this._storage.config[this.id]) {
|
|
844
|
+
this._updateConfiguration(DEFAULT_LOG_CONFIGURATION);
|
|
845
|
+
}
|
|
846
|
+
return this._storage.config[this.id];
|
|
690
847
|
}
|
|
691
|
-
|
|
692
|
-
|
|
848
|
+
_updateConfiguration(configuration) {
|
|
849
|
+
const currentConfiguration = this._storage.config[this.id] || {
|
|
850
|
+
...DEFAULT_LOG_CONFIGURATION
|
|
851
|
+
};
|
|
852
|
+
this._storage.setConfiguration({
|
|
853
|
+
[this.id]: { ...currentConfiguration, ...configuration }
|
|
854
|
+
});
|
|
693
855
|
}
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
return Object.assign(opts, { args }, opts.opts);
|
|
697
|
-
}
|
|
856
|
+
};
|
|
857
|
+
ProbeLog.VERSION = VERSION;
|
|
698
858
|
function decorateMessage(id, message, opts) {
|
|
699
859
|
if (typeof message === "string") {
|
|
700
860
|
const time = opts.time ? leftPad(formatTime(opts.total)) : "";
|
|
@@ -716,10 +876,10 @@ var __exports__ = (() => {
|
|
|
716
876
|
globalThis.probe = {};
|
|
717
877
|
|
|
718
878
|
// ../../node_modules/@probe.gl/log/dist/index.js
|
|
719
|
-
var dist_default = new
|
|
879
|
+
var dist_default = new ProbeLog({ id: "@probe.gl/log" });
|
|
720
880
|
|
|
721
881
|
// src/utils/log.ts
|
|
722
|
-
var log = new
|
|
882
|
+
var log = new ProbeLog({ id: "luma.gl" });
|
|
723
883
|
|
|
724
884
|
// src/utils/uid.ts
|
|
725
885
|
var uidCounters = {};
|
|
@@ -730,19 +890,75 @@ var __exports__ = (() => {
|
|
|
730
890
|
}
|
|
731
891
|
|
|
732
892
|
// src/adapter/resources/resource.ts
|
|
893
|
+
var CPU_HOTSPOT_PROFILER_MODULE = "cpu-hotspot-profiler";
|
|
894
|
+
var RESOURCE_COUNTS_STATS = "GPU Resource Counts";
|
|
895
|
+
var LEGACY_RESOURCE_COUNTS_STATS = "Resource Counts";
|
|
896
|
+
var GPU_TIME_AND_MEMORY_STATS2 = "GPU Time and Memory";
|
|
897
|
+
var BASE_RESOURCE_COUNT_ORDER = [
|
|
898
|
+
"Resources",
|
|
899
|
+
"Buffers",
|
|
900
|
+
"Textures",
|
|
901
|
+
"Samplers",
|
|
902
|
+
"TextureViews",
|
|
903
|
+
"Framebuffers",
|
|
904
|
+
"QuerySets",
|
|
905
|
+
"Shaders",
|
|
906
|
+
"RenderPipelines",
|
|
907
|
+
"ComputePipelines",
|
|
908
|
+
"PipelineLayouts",
|
|
909
|
+
"VertexArrays",
|
|
910
|
+
"RenderPasss",
|
|
911
|
+
"ComputePasss",
|
|
912
|
+
"CommandEncoders",
|
|
913
|
+
"CommandBuffers"
|
|
914
|
+
];
|
|
915
|
+
var WEBGL_RESOURCE_COUNT_ORDER = [
|
|
916
|
+
"Resources",
|
|
917
|
+
"Buffers",
|
|
918
|
+
"Textures",
|
|
919
|
+
"Samplers",
|
|
920
|
+
"TextureViews",
|
|
921
|
+
"Framebuffers",
|
|
922
|
+
"QuerySets",
|
|
923
|
+
"Shaders",
|
|
924
|
+
"RenderPipelines",
|
|
925
|
+
"SharedRenderPipelines",
|
|
926
|
+
"ComputePipelines",
|
|
927
|
+
"PipelineLayouts",
|
|
928
|
+
"VertexArrays",
|
|
929
|
+
"RenderPasss",
|
|
930
|
+
"ComputePasss",
|
|
931
|
+
"CommandEncoders",
|
|
932
|
+
"CommandBuffers"
|
|
933
|
+
];
|
|
934
|
+
var BASE_RESOURCE_COUNT_STAT_ORDER = BASE_RESOURCE_COUNT_ORDER.flatMap((resourceType) => [
|
|
935
|
+
`${resourceType} Created`,
|
|
936
|
+
`${resourceType} Active`
|
|
937
|
+
]);
|
|
938
|
+
var WEBGL_RESOURCE_COUNT_STAT_ORDER = WEBGL_RESOURCE_COUNT_ORDER.flatMap((resourceType) => [
|
|
939
|
+
`${resourceType} Created`,
|
|
940
|
+
`${resourceType} Active`
|
|
941
|
+
]);
|
|
942
|
+
var ORDERED_STATS_CACHE2 = /* @__PURE__ */ new WeakMap();
|
|
943
|
+
var ORDERED_STAT_NAME_SET_CACHE2 = /* @__PURE__ */ new WeakMap();
|
|
733
944
|
var Resource = class {
|
|
734
945
|
toString() {
|
|
735
946
|
return `${this[Symbol.toStringTag] || this.constructor.name}:"${this.id}"`;
|
|
736
947
|
}
|
|
737
948
|
/** props.id, for debugging. */
|
|
738
949
|
id;
|
|
950
|
+
/** The props that this resource was created with */
|
|
739
951
|
props;
|
|
952
|
+
/** User data object, reserved for the application */
|
|
740
953
|
userData = {};
|
|
954
|
+
/** The device that this resource is associated with - TODO can we remove this dup? */
|
|
741
955
|
_device;
|
|
742
956
|
/** Whether this resource has been destroyed */
|
|
743
957
|
destroyed = false;
|
|
744
958
|
/** For resources that allocate GPU memory */
|
|
745
959
|
allocatedBytes = 0;
|
|
960
|
+
/** Stats bucket currently holding the tracked allocation */
|
|
961
|
+
allocatedBytesName = null;
|
|
746
962
|
/** Attached resources will be destroyed when this resource is destroyed. Tracks auto-created "sub" resources. */
|
|
747
963
|
_attachedResources = /* @__PURE__ */ new Set();
|
|
748
964
|
/**
|
|
@@ -764,6 +980,9 @@ var __exports__ = (() => {
|
|
|
764
980
|
* destroy can be called on any resource to release it before it is garbage collected.
|
|
765
981
|
*/
|
|
766
982
|
destroy() {
|
|
983
|
+
if (this.destroyed) {
|
|
984
|
+
return;
|
|
985
|
+
}
|
|
767
986
|
this.destroyResource();
|
|
768
987
|
}
|
|
769
988
|
/** @deprecated Use destroy() */
|
|
@@ -802,7 +1021,7 @@ var __exports__ = (() => {
|
|
|
802
1021
|
}
|
|
803
1022
|
/** Destroy all owned resources. Make sure the resources are no longer needed before calling. */
|
|
804
1023
|
destroyAttachedResources() {
|
|
805
|
-
for (const resource of
|
|
1024
|
+
for (const resource of this._attachedResources) {
|
|
806
1025
|
resource.destroy();
|
|
807
1026
|
}
|
|
808
1027
|
this._attachedResources = /* @__PURE__ */ new Set();
|
|
@@ -810,37 +1029,107 @@ var __exports__ = (() => {
|
|
|
810
1029
|
// PROTECTED METHODS
|
|
811
1030
|
/** Perform all destroy steps. Can be called by derived resources when overriding destroy() */
|
|
812
1031
|
destroyResource() {
|
|
1032
|
+
if (this.destroyed) {
|
|
1033
|
+
return;
|
|
1034
|
+
}
|
|
813
1035
|
this.destroyAttachedResources();
|
|
814
1036
|
this.removeStats();
|
|
815
1037
|
this.destroyed = true;
|
|
816
1038
|
}
|
|
817
1039
|
/** Called by .destroy() to track object destruction. Subclass must call if overriding destroy() */
|
|
818
1040
|
removeStats() {
|
|
819
|
-
const
|
|
820
|
-
const
|
|
821
|
-
|
|
1041
|
+
const profiler = getCpuHotspotProfiler(this._device);
|
|
1042
|
+
const startTime = profiler ? getTimestamp() : 0;
|
|
1043
|
+
const statsObjects = [
|
|
1044
|
+
this._device.statsManager.getStats(RESOURCE_COUNTS_STATS),
|
|
1045
|
+
this._device.statsManager.getStats(LEGACY_RESOURCE_COUNTS_STATS)
|
|
1046
|
+
];
|
|
1047
|
+
const orderedStatNames = getResourceCountStatOrder(this._device);
|
|
1048
|
+
for (const stats of statsObjects) {
|
|
1049
|
+
initializeStats2(stats, orderedStatNames);
|
|
1050
|
+
}
|
|
1051
|
+
const name2 = this.getStatsName();
|
|
1052
|
+
for (const stats of statsObjects) {
|
|
1053
|
+
stats.get("Resources Active").decrementCount();
|
|
1054
|
+
stats.get(`${name2}s Active`).decrementCount();
|
|
1055
|
+
}
|
|
1056
|
+
if (profiler) {
|
|
1057
|
+
profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
|
|
1058
|
+
profiler.statsBookkeepingTimeMs = (profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
|
|
1059
|
+
}
|
|
822
1060
|
}
|
|
823
1061
|
/** Called by subclass to track memory allocations */
|
|
824
|
-
trackAllocatedMemory(bytes, name2 = this
|
|
825
|
-
const
|
|
1062
|
+
trackAllocatedMemory(bytes, name2 = this.getStatsName()) {
|
|
1063
|
+
const profiler = getCpuHotspotProfiler(this._device);
|
|
1064
|
+
const startTime = profiler ? getTimestamp() : 0;
|
|
1065
|
+
const stats = this._device.statsManager.getStats(GPU_TIME_AND_MEMORY_STATS2);
|
|
1066
|
+
if (this.allocatedBytes > 0 && this.allocatedBytesName) {
|
|
1067
|
+
stats.get("GPU Memory").subtractCount(this.allocatedBytes);
|
|
1068
|
+
stats.get(`${this.allocatedBytesName} Memory`).subtractCount(this.allocatedBytes);
|
|
1069
|
+
}
|
|
826
1070
|
stats.get("GPU Memory").addCount(bytes);
|
|
827
1071
|
stats.get(`${name2} Memory`).addCount(bytes);
|
|
1072
|
+
if (profiler) {
|
|
1073
|
+
profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
|
|
1074
|
+
profiler.statsBookkeepingTimeMs = (profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
|
|
1075
|
+
}
|
|
828
1076
|
this.allocatedBytes = bytes;
|
|
1077
|
+
this.allocatedBytesName = name2;
|
|
1078
|
+
}
|
|
1079
|
+
/** Called by subclass to track handle-backed memory allocations separately from owned allocations */
|
|
1080
|
+
trackReferencedMemory(bytes, name2 = this.getStatsName()) {
|
|
1081
|
+
this.trackAllocatedMemory(bytes, `Referenced ${name2}`);
|
|
829
1082
|
}
|
|
830
1083
|
/** Called by subclass to track memory deallocations */
|
|
831
|
-
trackDeallocatedMemory(name2 = this
|
|
832
|
-
|
|
1084
|
+
trackDeallocatedMemory(name2 = this.getStatsName()) {
|
|
1085
|
+
if (this.allocatedBytes === 0) {
|
|
1086
|
+
this.allocatedBytesName = null;
|
|
1087
|
+
return;
|
|
1088
|
+
}
|
|
1089
|
+
const profiler = getCpuHotspotProfiler(this._device);
|
|
1090
|
+
const startTime = profiler ? getTimestamp() : 0;
|
|
1091
|
+
const stats = this._device.statsManager.getStats(GPU_TIME_AND_MEMORY_STATS2);
|
|
833
1092
|
stats.get("GPU Memory").subtractCount(this.allocatedBytes);
|
|
834
|
-
stats.get(`${name2} Memory`).subtractCount(this.allocatedBytes);
|
|
1093
|
+
stats.get(`${this.allocatedBytesName || name2} Memory`).subtractCount(this.allocatedBytes);
|
|
1094
|
+
if (profiler) {
|
|
1095
|
+
profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
|
|
1096
|
+
profiler.statsBookkeepingTimeMs = (profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
|
|
1097
|
+
}
|
|
835
1098
|
this.allocatedBytes = 0;
|
|
1099
|
+
this.allocatedBytesName = null;
|
|
1100
|
+
}
|
|
1101
|
+
/** Called by subclass to deallocate handle-backed memory tracked via trackReferencedMemory() */
|
|
1102
|
+
trackDeallocatedReferencedMemory(name2 = this.getStatsName()) {
|
|
1103
|
+
this.trackDeallocatedMemory(`Referenced ${name2}`);
|
|
836
1104
|
}
|
|
837
1105
|
/** Called by resource constructor to track object creation */
|
|
838
1106
|
addStats() {
|
|
839
|
-
const
|
|
840
|
-
const
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
1107
|
+
const name2 = this.getStatsName();
|
|
1108
|
+
const profiler = getCpuHotspotProfiler(this._device);
|
|
1109
|
+
const startTime = profiler ? getTimestamp() : 0;
|
|
1110
|
+
const statsObjects = [
|
|
1111
|
+
this._device.statsManager.getStats(RESOURCE_COUNTS_STATS),
|
|
1112
|
+
this._device.statsManager.getStats(LEGACY_RESOURCE_COUNTS_STATS)
|
|
1113
|
+
];
|
|
1114
|
+
const orderedStatNames = getResourceCountStatOrder(this._device);
|
|
1115
|
+
for (const stats of statsObjects) {
|
|
1116
|
+
initializeStats2(stats, orderedStatNames);
|
|
1117
|
+
}
|
|
1118
|
+
for (const stats of statsObjects) {
|
|
1119
|
+
stats.get("Resources Created").incrementCount();
|
|
1120
|
+
stats.get("Resources Active").incrementCount();
|
|
1121
|
+
stats.get(`${name2}s Created`).incrementCount();
|
|
1122
|
+
stats.get(`${name2}s Active`).incrementCount();
|
|
1123
|
+
}
|
|
1124
|
+
if (profiler) {
|
|
1125
|
+
profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
|
|
1126
|
+
profiler.statsBookkeepingTimeMs = (profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
|
|
1127
|
+
}
|
|
1128
|
+
recordTransientCanvasResourceCreate(this._device, name2);
|
|
1129
|
+
}
|
|
1130
|
+
/** Canonical resource name used for stats buckets. */
|
|
1131
|
+
getStatsName() {
|
|
1132
|
+
return getCanonicalResourceName(this);
|
|
844
1133
|
}
|
|
845
1134
|
};
|
|
846
1135
|
/** Default properties for resource */
|
|
@@ -858,6 +1147,96 @@ var __exports__ = (() => {
|
|
|
858
1147
|
}
|
|
859
1148
|
return mergedProps;
|
|
860
1149
|
}
|
|
1150
|
+
function initializeStats2(stats, orderedStatNames) {
|
|
1151
|
+
const statsMap = stats.stats;
|
|
1152
|
+
let addedOrderedStat = false;
|
|
1153
|
+
for (const statName of orderedStatNames) {
|
|
1154
|
+
if (!statsMap[statName]) {
|
|
1155
|
+
stats.get(statName);
|
|
1156
|
+
addedOrderedStat = true;
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
const statCount = Object.keys(statsMap).length;
|
|
1160
|
+
const cachedStats = ORDERED_STATS_CACHE2.get(stats);
|
|
1161
|
+
if (!addedOrderedStat && cachedStats?.orderedStatNames === orderedStatNames && cachedStats.statCount === statCount) {
|
|
1162
|
+
return;
|
|
1163
|
+
}
|
|
1164
|
+
const reorderedStats = {};
|
|
1165
|
+
let orderedStatNamesSet = ORDERED_STAT_NAME_SET_CACHE2.get(orderedStatNames);
|
|
1166
|
+
if (!orderedStatNamesSet) {
|
|
1167
|
+
orderedStatNamesSet = new Set(orderedStatNames);
|
|
1168
|
+
ORDERED_STAT_NAME_SET_CACHE2.set(orderedStatNames, orderedStatNamesSet);
|
|
1169
|
+
}
|
|
1170
|
+
for (const statName of orderedStatNames) {
|
|
1171
|
+
if (statsMap[statName]) {
|
|
1172
|
+
reorderedStats[statName] = statsMap[statName];
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
for (const [statName, stat] of Object.entries(statsMap)) {
|
|
1176
|
+
if (!orderedStatNamesSet.has(statName)) {
|
|
1177
|
+
reorderedStats[statName] = stat;
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
for (const statName of Object.keys(statsMap)) {
|
|
1181
|
+
delete statsMap[statName];
|
|
1182
|
+
}
|
|
1183
|
+
Object.assign(statsMap, reorderedStats);
|
|
1184
|
+
ORDERED_STATS_CACHE2.set(stats, { orderedStatNames, statCount });
|
|
1185
|
+
}
|
|
1186
|
+
function getResourceCountStatOrder(device) {
|
|
1187
|
+
return device.type === "webgl" ? WEBGL_RESOURCE_COUNT_STAT_ORDER : BASE_RESOURCE_COUNT_STAT_ORDER;
|
|
1188
|
+
}
|
|
1189
|
+
function getCpuHotspotProfiler(device) {
|
|
1190
|
+
const profiler = device.userData[CPU_HOTSPOT_PROFILER_MODULE];
|
|
1191
|
+
return profiler?.enabled ? profiler : null;
|
|
1192
|
+
}
|
|
1193
|
+
function getTimestamp() {
|
|
1194
|
+
return globalThis.performance?.now?.() ?? Date.now();
|
|
1195
|
+
}
|
|
1196
|
+
function recordTransientCanvasResourceCreate(device, name2) {
|
|
1197
|
+
const profiler = getCpuHotspotProfiler(device);
|
|
1198
|
+
if (!profiler || !profiler.activeDefaultFramebufferAcquireDepth) {
|
|
1199
|
+
return;
|
|
1200
|
+
}
|
|
1201
|
+
profiler.transientCanvasResourceCreates = (profiler.transientCanvasResourceCreates || 0) + 1;
|
|
1202
|
+
switch (name2) {
|
|
1203
|
+
case "Texture":
|
|
1204
|
+
profiler.transientCanvasTextureCreates = (profiler.transientCanvasTextureCreates || 0) + 1;
|
|
1205
|
+
break;
|
|
1206
|
+
case "TextureView":
|
|
1207
|
+
profiler.transientCanvasTextureViewCreates = (profiler.transientCanvasTextureViewCreates || 0) + 1;
|
|
1208
|
+
break;
|
|
1209
|
+
case "Sampler":
|
|
1210
|
+
profiler.transientCanvasSamplerCreates = (profiler.transientCanvasSamplerCreates || 0) + 1;
|
|
1211
|
+
break;
|
|
1212
|
+
case "Framebuffer":
|
|
1213
|
+
profiler.transientCanvasFramebufferCreates = (profiler.transientCanvasFramebufferCreates || 0) + 1;
|
|
1214
|
+
break;
|
|
1215
|
+
default:
|
|
1216
|
+
break;
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
function getCanonicalResourceName(resource) {
|
|
1220
|
+
let prototype = Object.getPrototypeOf(resource);
|
|
1221
|
+
while (prototype) {
|
|
1222
|
+
const parentPrototype = Object.getPrototypeOf(prototype);
|
|
1223
|
+
if (!parentPrototype || parentPrototype === Resource.prototype) {
|
|
1224
|
+
return getPrototypeToStringTag(prototype) || resource[Symbol.toStringTag] || resource.constructor.name;
|
|
1225
|
+
}
|
|
1226
|
+
prototype = parentPrototype;
|
|
1227
|
+
}
|
|
1228
|
+
return resource[Symbol.toStringTag] || resource.constructor.name;
|
|
1229
|
+
}
|
|
1230
|
+
function getPrototypeToStringTag(prototype) {
|
|
1231
|
+
const descriptor = Object.getOwnPropertyDescriptor(prototype, Symbol.toStringTag);
|
|
1232
|
+
if (typeof descriptor?.get === "function") {
|
|
1233
|
+
return descriptor.get.call(prototype);
|
|
1234
|
+
}
|
|
1235
|
+
if (typeof descriptor?.value === "string") {
|
|
1236
|
+
return descriptor.value;
|
|
1237
|
+
}
|
|
1238
|
+
return null;
|
|
1239
|
+
}
|
|
861
1240
|
|
|
862
1241
|
// src/adapter/resources/buffer.ts
|
|
863
1242
|
var _Buffer = class extends Resource {
|
|
@@ -866,7 +1245,7 @@ var __exports__ = (() => {
|
|
|
866
1245
|
}
|
|
867
1246
|
/** The usage with which this buffer was created */
|
|
868
1247
|
usage;
|
|
869
|
-
/** For index buffers, whether indices are 16 or 32 bit */
|
|
1248
|
+
/** For index buffers, whether indices are 8, 16 or 32 bit. Note: uint8 indices are automatically converted to uint16 for WebGPU compatibility */
|
|
870
1249
|
indexType;
|
|
871
1250
|
/** "Time" of last update, can be used to check if redraw is needed */
|
|
872
1251
|
updateTimestamp;
|
|
@@ -877,6 +1256,8 @@ var __exports__ = (() => {
|
|
|
877
1256
|
deducedProps.indexType = "uint32";
|
|
878
1257
|
} else if (props.data instanceof Uint16Array) {
|
|
879
1258
|
deducedProps.indexType = "uint16";
|
|
1259
|
+
} else if (props.data instanceof Uint8Array) {
|
|
1260
|
+
deducedProps.indexType = "uint8";
|
|
880
1261
|
}
|
|
881
1262
|
}
|
|
882
1263
|
delete deducedProps.data;
|
|
@@ -895,18 +1276,26 @@ var __exports__ = (() => {
|
|
|
895
1276
|
/** A partial CPU-side copy of the data in this buffer, for debugging purposes */
|
|
896
1277
|
debugData = new ArrayBuffer(0);
|
|
897
1278
|
/** This doesn't handle partial non-zero offset updates correctly */
|
|
898
|
-
_setDebugData(data,
|
|
899
|
-
|
|
1279
|
+
_setDebugData(data, _byteOffset, byteLength) {
|
|
1280
|
+
let arrayBufferView = null;
|
|
1281
|
+
let arrayBuffer2;
|
|
1282
|
+
if (ArrayBuffer.isView(data)) {
|
|
1283
|
+
arrayBufferView = data;
|
|
1284
|
+
arrayBuffer2 = data.buffer;
|
|
1285
|
+
} else {
|
|
1286
|
+
arrayBuffer2 = data;
|
|
1287
|
+
}
|
|
900
1288
|
const debugDataLength = Math.min(
|
|
901
1289
|
data ? data.byteLength : byteLength,
|
|
902
1290
|
_Buffer.DEBUG_DATA_MAX_LENGTH
|
|
903
1291
|
);
|
|
904
1292
|
if (arrayBuffer2 === null) {
|
|
905
1293
|
this.debugData = new ArrayBuffer(debugDataLength);
|
|
906
|
-
} else if (byteOffset === 0 && byteLength === arrayBuffer2.byteLength) {
|
|
907
|
-
this.debugData = arrayBuffer2.slice(0, debugDataLength);
|
|
908
1294
|
} else {
|
|
909
|
-
|
|
1295
|
+
const sourceByteOffset = Math.min(arrayBufferView?.byteOffset || 0, arrayBuffer2.byteLength);
|
|
1296
|
+
const availableByteLength = Math.max(0, arrayBuffer2.byteLength - sourceByteOffset);
|
|
1297
|
+
const copyByteLength = Math.min(debugDataLength, availableByteLength);
|
|
1298
|
+
this.debugData = new Uint8Array(arrayBuffer2, sourceByteOffset, copyByteLength).slice().buffer;
|
|
910
1299
|
}
|
|
911
1300
|
}
|
|
912
1301
|
};
|
|
@@ -940,61 +1329,73 @@ var __exports__ = (() => {
|
|
|
940
1329
|
onMapped: void 0
|
|
941
1330
|
});
|
|
942
1331
|
|
|
943
|
-
// src/shadertypes/data-types/
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
signedType,
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
case "sint8":
|
|
964
|
-
return "snorm8";
|
|
965
|
-
case "uint16":
|
|
966
|
-
return "unorm16";
|
|
967
|
-
case "sint16":
|
|
968
|
-
return "snorm16";
|
|
969
|
-
default:
|
|
970
|
-
return dataType;
|
|
1332
|
+
// src/shadertypes/data-types/data-type-decoder.ts
|
|
1333
|
+
var DataTypeDecoder = class {
|
|
1334
|
+
/**
|
|
1335
|
+
* Gets info about a data type constant (signed or normalized)
|
|
1336
|
+
* @returns underlying primitive / signed types, byte length, normalization, integer, signed flags
|
|
1337
|
+
*/
|
|
1338
|
+
getDataTypeInfo(type) {
|
|
1339
|
+
const [signedType, primitiveType, byteLength] = NORMALIZED_TYPE_MAP[type];
|
|
1340
|
+
const normalized = type.includes("norm");
|
|
1341
|
+
const integer = !normalized && !type.startsWith("float");
|
|
1342
|
+
const signed = type.startsWith("s");
|
|
1343
|
+
return {
|
|
1344
|
+
signedType,
|
|
1345
|
+
primitiveType,
|
|
1346
|
+
byteLength,
|
|
1347
|
+
normalized,
|
|
1348
|
+
integer,
|
|
1349
|
+
signed
|
|
1350
|
+
// TODO - add webglOnly flag
|
|
1351
|
+
};
|
|
971
1352
|
}
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
1353
|
+
/** Build a vertex format from a signed data type and a component */
|
|
1354
|
+
getNormalizedDataType(signedDataType) {
|
|
1355
|
+
const dataType = signedDataType;
|
|
1356
|
+
switch (dataType) {
|
|
1357
|
+
case "uint8":
|
|
1358
|
+
return "unorm8";
|
|
1359
|
+
case "sint8":
|
|
1360
|
+
return "snorm8";
|
|
1361
|
+
case "uint16":
|
|
1362
|
+
return "unorm16";
|
|
1363
|
+
case "sint16":
|
|
1364
|
+
return "snorm16";
|
|
1365
|
+
default:
|
|
1366
|
+
return dataType;
|
|
1367
|
+
}
|
|
981
1368
|
}
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
1369
|
+
/** Align offset to 1, 2 or 4 elements (4, 8 or 16 bytes) */
|
|
1370
|
+
alignTo(size, count) {
|
|
1371
|
+
switch (count) {
|
|
1372
|
+
case 1:
|
|
1373
|
+
return size;
|
|
1374
|
+
case 2:
|
|
1375
|
+
return size + size % 2;
|
|
1376
|
+
default:
|
|
1377
|
+
return size + (4 - size % 4) % 4;
|
|
1378
|
+
}
|
|
987
1379
|
}
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
1380
|
+
/** Returns the VariableShaderType that corresponds to a typed array */
|
|
1381
|
+
getDataType(arrayOrType) {
|
|
1382
|
+
const Constructor = ArrayBuffer.isView(arrayOrType) ? arrayOrType.constructor : arrayOrType;
|
|
1383
|
+
if (Constructor === Uint8ClampedArray) {
|
|
1384
|
+
return "uint8";
|
|
1385
|
+
}
|
|
1386
|
+
const info = Object.values(NORMALIZED_TYPE_MAP).find((entry) => Constructor === entry[4]);
|
|
1387
|
+
if (!info) {
|
|
1388
|
+
throw new Error(Constructor.name);
|
|
1389
|
+
}
|
|
1390
|
+
return info[0];
|
|
991
1391
|
}
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
}
|
|
1392
|
+
/** Returns the TypedArray that corresponds to a shader data type */
|
|
1393
|
+
getTypedArrayConstructor(type) {
|
|
1394
|
+
const [, , , , Constructor] = NORMALIZED_TYPE_MAP[type];
|
|
1395
|
+
return Constructor;
|
|
1396
|
+
}
|
|
1397
|
+
};
|
|
1398
|
+
var dataTypeDecoder = new DataTypeDecoder();
|
|
998
1399
|
var NORMALIZED_TYPE_MAP = {
|
|
999
1400
|
uint8: ["uint8", "u32", 1, false, Uint8Array],
|
|
1000
1401
|
sint8: ["sint8", "i32", 1, false, Int8Array],
|
|
@@ -1010,87 +1411,99 @@ var __exports__ = (() => {
|
|
|
1010
1411
|
sint32: ["sint32", "i32", 4, false, Int32Array]
|
|
1011
1412
|
};
|
|
1012
1413
|
|
|
1013
|
-
// src/shadertypes/vertex-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
type
|
|
1026
|
-
components
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
case "unorm8":
|
|
1041
|
-
if (components === 1) {
|
|
1042
|
-
return "unorm8";
|
|
1043
|
-
}
|
|
1044
|
-
if (components === 3) {
|
|
1045
|
-
return "unorm8x3-webgl";
|
|
1046
|
-
}
|
|
1047
|
-
return `${dataType}x${components}`;
|
|
1048
|
-
case "snorm8":
|
|
1049
|
-
case "uint8":
|
|
1050
|
-
case "sint8":
|
|
1051
|
-
case "uint16":
|
|
1052
|
-
case "sint16":
|
|
1053
|
-
case "unorm16":
|
|
1054
|
-
case "snorm16":
|
|
1055
|
-
case "float16":
|
|
1056
|
-
if (components === 1 || components === 3) {
|
|
1057
|
-
throw new Error(`size: ${components}`);
|
|
1058
|
-
}
|
|
1059
|
-
return `${dataType}x${components}`;
|
|
1060
|
-
default:
|
|
1061
|
-
return components === 1 ? dataType : `${dataType}x${components}`;
|
|
1414
|
+
// src/shadertypes/vertex-types/vertex-format-decoder.ts
|
|
1415
|
+
var VertexFormatDecoder = class {
|
|
1416
|
+
/**
|
|
1417
|
+
* Decodes a vertex format, returning type, components, byte length and flags (integer, signed, normalized)
|
|
1418
|
+
*/
|
|
1419
|
+
getVertexFormatInfo(format) {
|
|
1420
|
+
let webglOnly;
|
|
1421
|
+
if (format.endsWith("-webgl")) {
|
|
1422
|
+
format.replace("-webgl", "");
|
|
1423
|
+
webglOnly = true;
|
|
1424
|
+
}
|
|
1425
|
+
const [type_, count] = format.split("x");
|
|
1426
|
+
const type = type_;
|
|
1427
|
+
const components = count ? parseInt(count) : 1;
|
|
1428
|
+
const decodedType = dataTypeDecoder.getDataTypeInfo(type);
|
|
1429
|
+
const result = {
|
|
1430
|
+
type,
|
|
1431
|
+
components,
|
|
1432
|
+
byteLength: decodedType.byteLength * components,
|
|
1433
|
+
integer: decodedType.integer,
|
|
1434
|
+
signed: decodedType.signed,
|
|
1435
|
+
normalized: decodedType.normalized
|
|
1436
|
+
};
|
|
1437
|
+
if (webglOnly) {
|
|
1438
|
+
result.webglOnly = true;
|
|
1439
|
+
}
|
|
1440
|
+
return result;
|
|
1062
1441
|
}
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1442
|
+
/** Build a vertex format from a signed data type and a component */
|
|
1443
|
+
makeVertexFormat(signedDataType, components, normalized) {
|
|
1444
|
+
const dataType = normalized ? dataTypeDecoder.getNormalizedDataType(signedDataType) : signedDataType;
|
|
1445
|
+
switch (dataType) {
|
|
1446
|
+
case "unorm8":
|
|
1447
|
+
if (components === 1) {
|
|
1448
|
+
return "unorm8";
|
|
1449
|
+
}
|
|
1450
|
+
if (components === 3) {
|
|
1451
|
+
return "unorm8x3-webgl";
|
|
1452
|
+
}
|
|
1453
|
+
return `${dataType}x${components}`;
|
|
1454
|
+
case "snorm8":
|
|
1455
|
+
case "uint8":
|
|
1456
|
+
case "sint8":
|
|
1457
|
+
case "uint16":
|
|
1458
|
+
case "sint16":
|
|
1459
|
+
case "unorm16":
|
|
1460
|
+
case "snorm16":
|
|
1461
|
+
case "float16":
|
|
1462
|
+
if (components === 1 || components === 3) {
|
|
1463
|
+
throw new Error(`size: ${components}`);
|
|
1464
|
+
}
|
|
1465
|
+
return `${dataType}x${components}`;
|
|
1466
|
+
default:
|
|
1467
|
+
return components === 1 ? dataType : `${dataType}x${components}`;
|
|
1468
|
+
}
|
|
1067
1469
|
}
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
vertexType = "float32";
|
|
1077
|
-
break;
|
|
1078
|
-
case "i32":
|
|
1079
|
-
vertexType = "sint32";
|
|
1080
|
-
break;
|
|
1081
|
-
case "u32":
|
|
1082
|
-
vertexType = "uint32";
|
|
1083
|
-
break;
|
|
1084
|
-
case "f16":
|
|
1085
|
-
return opts.components <= 2 ? "float16x2" : "float16x4";
|
|
1470
|
+
/** Get the vertex format for an attribute with TypedArray and size */
|
|
1471
|
+
getVertexFormatFromAttribute(typedArray, size, normalized) {
|
|
1472
|
+
if (!size || size > 4) {
|
|
1473
|
+
throw new Error(`size ${size}`);
|
|
1474
|
+
}
|
|
1475
|
+
const components = size;
|
|
1476
|
+
const signedDataType = dataTypeDecoder.getDataType(typedArray);
|
|
1477
|
+
return this.makeVertexFormat(signedDataType, components, normalized);
|
|
1086
1478
|
}
|
|
1087
|
-
|
|
1088
|
-
|
|
1479
|
+
/**
|
|
1480
|
+
* Return a "default" vertex format for a certain shader data type
|
|
1481
|
+
* The simplest vertex format that matches the shader attribute's data type
|
|
1482
|
+
*/
|
|
1483
|
+
getCompatibleVertexFormat(opts) {
|
|
1484
|
+
let vertexType;
|
|
1485
|
+
switch (opts.primitiveType) {
|
|
1486
|
+
case "f32":
|
|
1487
|
+
vertexType = "float32";
|
|
1488
|
+
break;
|
|
1489
|
+
case "i32":
|
|
1490
|
+
vertexType = "sint32";
|
|
1491
|
+
break;
|
|
1492
|
+
case "u32":
|
|
1493
|
+
vertexType = "uint32";
|
|
1494
|
+
break;
|
|
1495
|
+
case "f16":
|
|
1496
|
+
return opts.components <= 2 ? "float16x2" : "float16x4";
|
|
1497
|
+
}
|
|
1498
|
+
if (opts.components === 1) {
|
|
1499
|
+
return vertexType;
|
|
1500
|
+
}
|
|
1501
|
+
return `${vertexType}x${opts.components}`;
|
|
1089
1502
|
}
|
|
1090
|
-
|
|
1091
|
-
|
|
1503
|
+
};
|
|
1504
|
+
var vertexFormatDecoder = new VertexFormatDecoder();
|
|
1092
1505
|
|
|
1093
|
-
// src/shadertypes/
|
|
1506
|
+
// src/shadertypes/texture-types/texture-format-table.ts
|
|
1094
1507
|
var texture_compression_bc = "texture-compression-bc";
|
|
1095
1508
|
var texture_compression_astc = "texture-compression-astc";
|
|
1096
1509
|
var texture_compression_etc2 = "texture-compression-etc2";
|
|
@@ -1101,6 +1514,7 @@ var __exports__ = (() => {
|
|
|
1101
1514
|
var float16_renderable = "float16-renderable-webgl";
|
|
1102
1515
|
var rgb9e5ufloat_renderable = "rgb9e5ufloat-renderable-webgl";
|
|
1103
1516
|
var snorm8_renderable = "snorm8-renderable-webgl";
|
|
1517
|
+
var norm16_webgl = "norm16-webgl";
|
|
1104
1518
|
var norm16_renderable = "norm16-renderable-webgl";
|
|
1105
1519
|
var snorm16_renderable = "snorm16-renderable-webgl";
|
|
1106
1520
|
var float32_filterable = "float32-filterable";
|
|
@@ -1134,16 +1548,16 @@ var __exports__ = (() => {
|
|
|
1134
1548
|
"rgba8sint": {},
|
|
1135
1549
|
"bgra8unorm": {},
|
|
1136
1550
|
"bgra8unorm-srgb": {},
|
|
1137
|
-
"r16unorm": { f: norm16_renderable },
|
|
1138
|
-
"rg16unorm": { render: norm16_renderable },
|
|
1139
|
-
"rgb16unorm-webgl": { f:
|
|
1551
|
+
"r16unorm": { f: norm16_webgl, render: norm16_renderable },
|
|
1552
|
+
"rg16unorm": { f: norm16_webgl, render: norm16_renderable },
|
|
1553
|
+
"rgb16unorm-webgl": { f: norm16_webgl, render: false },
|
|
1140
1554
|
// rgb not renderable
|
|
1141
|
-
"rgba16unorm": { render: norm16_renderable },
|
|
1142
|
-
"r16snorm": { f: snorm16_renderable },
|
|
1143
|
-
"rg16snorm": { render: snorm16_renderable },
|
|
1144
|
-
"rgb16snorm-webgl": { f:
|
|
1555
|
+
"rgba16unorm": { f: norm16_webgl, render: norm16_renderable },
|
|
1556
|
+
"r16snorm": { f: norm16_webgl, render: snorm16_renderable },
|
|
1557
|
+
"rg16snorm": { f: norm16_webgl, render: snorm16_renderable },
|
|
1558
|
+
"rgb16snorm-webgl": { f: norm16_webgl, render: false },
|
|
1145
1559
|
// rgb not renderable
|
|
1146
|
-
"rgba16snorm": { render: snorm16_renderable },
|
|
1560
|
+
"rgba16snorm": { f: norm16_webgl, render: snorm16_renderable },
|
|
1147
1561
|
"r16uint": {},
|
|
1148
1562
|
"rg16uint": {},
|
|
1149
1563
|
"rgba16uint": {},
|
|
@@ -1246,7 +1660,7 @@ var __exports__ = (() => {
|
|
|
1246
1660
|
// WEBGL_compressed_texture_pvrtc
|
|
1247
1661
|
"pvrtc-rgb4unorm-webgl": { f: texture_compression_pvrtc_webgl },
|
|
1248
1662
|
"pvrtc-rgba4unorm-webgl": { f: texture_compression_pvrtc_webgl },
|
|
1249
|
-
"pvrtc-
|
|
1663
|
+
"pvrtc-rgb2unorm-webgl": { f: texture_compression_pvrtc_webgl },
|
|
1250
1664
|
"pvrtc-rgba2unorm-webgl": { f: texture_compression_pvrtc_webgl },
|
|
1251
1665
|
// WEBGL_compressed_texture_etc1
|
|
1252
1666
|
"etc1-rbg-unorm-webgl": { f: texture_compression_etc1_webgl },
|
|
@@ -1260,7 +1674,10 @@ var __exports__ = (() => {
|
|
|
1260
1674
|
...TEXTURE_FORMAT_COMPRESSED_TABLE
|
|
1261
1675
|
};
|
|
1262
1676
|
|
|
1263
|
-
// src/shadertypes/
|
|
1677
|
+
// src/shadertypes/texture-types/texture-format-decoder.ts
|
|
1678
|
+
var RGB_FORMAT_REGEX = /^(r|rg|rgb|rgba|bgra)([0-9]*)([a-z]*)(-srgb)?(-webgl)?$/;
|
|
1679
|
+
var COLOR_FORMAT_PREFIXES = ["rgb", "rgba", "bgra"];
|
|
1680
|
+
var DEPTH_FORMAT_PREFIXES = ["depth", "stencil"];
|
|
1264
1681
|
var COMPRESSED_TEXTURE_FORMAT_PREFIXES = [
|
|
1265
1682
|
"bc1",
|
|
1266
1683
|
"bc2",
|
|
@@ -1276,49 +1693,83 @@ var __exports__ = (() => {
|
|
|
1276
1693
|
"astc",
|
|
1277
1694
|
"pvrtc"
|
|
1278
1695
|
];
|
|
1279
|
-
var RGB_FORMAT_REGEX = /^(r|rg|rgb|rgba|bgra)([0-9]*)([a-z]*)(-srgb)?(-webgl)?$/;
|
|
1280
1696
|
var TextureFormatDecoder = class {
|
|
1281
|
-
/** Returns information about a texture format, e.g. attatchment type, components, byte length and flags (integer, signed, normalized) */
|
|
1282
|
-
getInfo(format) {
|
|
1283
|
-
return getTextureFormatInfo(format);
|
|
1284
|
-
}
|
|
1285
1697
|
/** Checks if a texture format is color */
|
|
1286
1698
|
isColor(format) {
|
|
1287
|
-
return
|
|
1699
|
+
return COLOR_FORMAT_PREFIXES.some((prefix) => format.startsWith(prefix));
|
|
1288
1700
|
}
|
|
1289
1701
|
/** Checks if a texture format is depth or stencil */
|
|
1290
1702
|
isDepthStencil(format) {
|
|
1291
|
-
return
|
|
1703
|
+
return DEPTH_FORMAT_PREFIXES.some((prefix) => format.startsWith(prefix));
|
|
1292
1704
|
}
|
|
1293
1705
|
/** Checks if a texture format is compressed */
|
|
1294
1706
|
isCompressed(format) {
|
|
1295
1707
|
return COMPRESSED_TEXTURE_FORMAT_PREFIXES.some((prefix) => format.startsWith(prefix));
|
|
1296
1708
|
}
|
|
1297
|
-
/**
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1709
|
+
/** Returns information about a texture format, e.g. attachment type, components, byte length and flags (integer, signed, normalized) */
|
|
1710
|
+
getInfo(format) {
|
|
1711
|
+
return getTextureFormatInfo(format);
|
|
1712
|
+
}
|
|
1713
|
+
/** "static" capabilities of a texture format. @note Needs to be adjusted against current device */
|
|
1301
1714
|
getCapabilities(format) {
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
filter: info.filter ?? true,
|
|
1308
|
-
blend: info.blend ?? true,
|
|
1309
|
-
store: info.store ?? true
|
|
1310
|
-
};
|
|
1311
|
-
const formatInfo = getTextureFormatInfo(format);
|
|
1312
|
-
const isDepthStencil = format.startsWith("depth") || format.startsWith("stencil");
|
|
1313
|
-
const isSigned = formatInfo?.signed;
|
|
1314
|
-
const isInteger = formatInfo?.integer;
|
|
1315
|
-
const isWebGLSpecific = formatInfo?.webgl;
|
|
1316
|
-
formatCapabilities.render &&= !isSigned;
|
|
1317
|
-
formatCapabilities.filter &&= !isDepthStencil && !isSigned && !isInteger && !isWebGLSpecific;
|
|
1318
|
-
return formatCapabilities;
|
|
1715
|
+
return getTextureFormatCapabilities(format);
|
|
1716
|
+
}
|
|
1717
|
+
/** Computes the memory layout for a texture, in particular including row byte alignment */
|
|
1718
|
+
computeMemoryLayout(opts) {
|
|
1719
|
+
return computeTextureMemoryLayout(opts);
|
|
1319
1720
|
}
|
|
1320
1721
|
};
|
|
1321
1722
|
var textureFormatDecoder = new TextureFormatDecoder();
|
|
1723
|
+
function computeTextureMemoryLayout({
|
|
1724
|
+
format,
|
|
1725
|
+
width,
|
|
1726
|
+
height,
|
|
1727
|
+
depth,
|
|
1728
|
+
byteAlignment
|
|
1729
|
+
}) {
|
|
1730
|
+
const formatInfo = textureFormatDecoder.getInfo(format);
|
|
1731
|
+
const {
|
|
1732
|
+
bytesPerPixel,
|
|
1733
|
+
bytesPerBlock = bytesPerPixel,
|
|
1734
|
+
blockWidth = 1,
|
|
1735
|
+
blockHeight = 1,
|
|
1736
|
+
compressed = false
|
|
1737
|
+
} = formatInfo;
|
|
1738
|
+
const blockColumns = compressed ? Math.ceil(width / blockWidth) : width;
|
|
1739
|
+
const blockRows = compressed ? Math.ceil(height / blockHeight) : height;
|
|
1740
|
+
const unpaddedBytesPerRow = blockColumns * bytesPerBlock;
|
|
1741
|
+
const bytesPerRow = Math.ceil(unpaddedBytesPerRow / byteAlignment) * byteAlignment;
|
|
1742
|
+
const rowsPerImage = blockRows;
|
|
1743
|
+
const byteLength = bytesPerRow * rowsPerImage * depth;
|
|
1744
|
+
return {
|
|
1745
|
+
bytesPerPixel,
|
|
1746
|
+
bytesPerRow,
|
|
1747
|
+
rowsPerImage,
|
|
1748
|
+
depthOrArrayLayers: depth,
|
|
1749
|
+
bytesPerImage: bytesPerRow * rowsPerImage,
|
|
1750
|
+
byteLength
|
|
1751
|
+
};
|
|
1752
|
+
}
|
|
1753
|
+
function getTextureFormatCapabilities(format) {
|
|
1754
|
+
const info = getTextureFormatDefinition(format);
|
|
1755
|
+
const formatCapabilities = {
|
|
1756
|
+
format,
|
|
1757
|
+
create: info.f ?? true,
|
|
1758
|
+
render: info.render ?? true,
|
|
1759
|
+
filter: info.filter ?? true,
|
|
1760
|
+
blend: info.blend ?? true,
|
|
1761
|
+
store: info.store ?? true
|
|
1762
|
+
};
|
|
1763
|
+
const formatInfo = getTextureFormatInfo(format);
|
|
1764
|
+
const isDepthStencil = format.startsWith("depth") || format.startsWith("stencil");
|
|
1765
|
+
const isSigned = formatInfo?.signed;
|
|
1766
|
+
const isInteger = formatInfo?.integer;
|
|
1767
|
+
const isWebGLSpecific = formatInfo?.webgl;
|
|
1768
|
+
const isCompressed = Boolean(formatInfo?.compressed);
|
|
1769
|
+
formatCapabilities.render &&= !isDepthStencil && !isCompressed;
|
|
1770
|
+
formatCapabilities.filter &&= !isDepthStencil && !isSigned && !isInteger && !isWebGLSpecific;
|
|
1771
|
+
return formatCapabilities;
|
|
1772
|
+
}
|
|
1322
1773
|
function getTextureFormatInfo(format) {
|
|
1323
1774
|
let formatInfo = getTextureFormatInfoUsingTable(format);
|
|
1324
1775
|
if (textureFormatDecoder.isCompressed(format)) {
|
|
@@ -1327,19 +1778,20 @@ var __exports__ = (() => {
|
|
|
1327
1778
|
formatInfo.bytesPerPixel = 1;
|
|
1328
1779
|
formatInfo.srgb = false;
|
|
1329
1780
|
formatInfo.compressed = true;
|
|
1781
|
+
formatInfo.bytesPerBlock = getCompressedTextureBlockByteLength(format);
|
|
1330
1782
|
const blockSize = getCompressedTextureBlockSize(format);
|
|
1331
1783
|
if (blockSize) {
|
|
1332
1784
|
formatInfo.blockWidth = blockSize.blockWidth;
|
|
1333
1785
|
formatInfo.blockHeight = blockSize.blockHeight;
|
|
1334
1786
|
}
|
|
1335
1787
|
}
|
|
1336
|
-
const matches = RGB_FORMAT_REGEX.exec(format);
|
|
1788
|
+
const matches = !formatInfo.packed ? RGB_FORMAT_REGEX.exec(format) : null;
|
|
1337
1789
|
if (matches) {
|
|
1338
1790
|
const [, channels, length, type, srgb, suffix] = matches;
|
|
1339
1791
|
const dataType = `${type}${length}`;
|
|
1340
|
-
const decodedType = getDataTypeInfo(dataType);
|
|
1792
|
+
const decodedType = dataTypeDecoder.getDataTypeInfo(dataType);
|
|
1341
1793
|
const bits = decodedType.byteLength * 8;
|
|
1342
|
-
const components = channels
|
|
1794
|
+
const components = channels?.length ?? 1;
|
|
1343
1795
|
const bitsPerChannel = [
|
|
1344
1796
|
bits,
|
|
1345
1797
|
components >= 2 ? bits : 0,
|
|
@@ -1356,7 +1808,7 @@ var __exports__ = (() => {
|
|
|
1356
1808
|
signed: decodedType.signed,
|
|
1357
1809
|
normalized: decodedType.normalized,
|
|
1358
1810
|
bitsPerChannel,
|
|
1359
|
-
bytesPerPixel: decodedType.byteLength *
|
|
1811
|
+
bytesPerPixel: decodedType.byteLength * components,
|
|
1360
1812
|
packed: formatInfo.packed,
|
|
1361
1813
|
srgb: formatInfo.srgb
|
|
1362
1814
|
};
|
|
@@ -1412,10 +1864,31 @@ var __exports__ = (() => {
|
|
|
1412
1864
|
const [, blockWidth, blockHeight] = matches;
|
|
1413
1865
|
return { blockWidth: Number(blockWidth), blockHeight: Number(blockHeight) };
|
|
1414
1866
|
}
|
|
1867
|
+
if (format.startsWith("bc") || format.startsWith("etc1") || format.startsWith("etc2") || format.startsWith("eac") || format.startsWith("atc")) {
|
|
1868
|
+
return { blockWidth: 4, blockHeight: 4 };
|
|
1869
|
+
}
|
|
1870
|
+
if (format.startsWith("pvrtc-rgb4") || format.startsWith("pvrtc-rgba4")) {
|
|
1871
|
+
return { blockWidth: 4, blockHeight: 4 };
|
|
1872
|
+
}
|
|
1873
|
+
if (format.startsWith("pvrtc-rgb2") || format.startsWith("pvrtc-rgba2")) {
|
|
1874
|
+
return { blockWidth: 8, blockHeight: 4 };
|
|
1875
|
+
}
|
|
1415
1876
|
return null;
|
|
1416
1877
|
}
|
|
1878
|
+
function getCompressedTextureBlockByteLength(format) {
|
|
1879
|
+
if (format.startsWith("bc1") || format.startsWith("bc4") || format.startsWith("etc1") || format.startsWith("etc2-rgb8") || format.startsWith("etc2-rgb8a1") || format.startsWith("eac-r11") || format === "atc-rgb-unorm-webgl") {
|
|
1880
|
+
return 8;
|
|
1881
|
+
}
|
|
1882
|
+
if (format.startsWith("bc2") || format.startsWith("bc3") || format.startsWith("bc5") || format.startsWith("bc6h") || format.startsWith("bc7") || format.startsWith("etc2-rgba8") || format.startsWith("eac-rg11") || format.startsWith("astc") || format === "atc-rgba-unorm-webgl" || format === "atc-rgbai-unorm-webgl") {
|
|
1883
|
+
return 16;
|
|
1884
|
+
}
|
|
1885
|
+
if (format.startsWith("pvrtc")) {
|
|
1886
|
+
return 8;
|
|
1887
|
+
}
|
|
1888
|
+
return 16;
|
|
1889
|
+
}
|
|
1417
1890
|
|
|
1418
|
-
// src/image-
|
|
1891
|
+
// src/shadertypes/image-types/image-types.ts
|
|
1419
1892
|
function isExternalImage(data) {
|
|
1420
1893
|
return typeof ImageData !== "undefined" && data instanceof ImageData || typeof ImageBitmap !== "undefined" && data instanceof ImageBitmap || typeof HTMLImageElement !== "undefined" && data instanceof HTMLImageElement || typeof HTMLVideoElement !== "undefined" && data instanceof HTMLVideoElement || typeof VideoFrame !== "undefined" && data instanceof VideoFrame || typeof HTMLCanvasElement !== "undefined" && data instanceof HTMLCanvasElement || typeof OffscreenCanvas !== "undefined" && data instanceof OffscreenCanvas;
|
|
1421
1894
|
}
|
|
@@ -1438,6 +1911,52 @@ var __exports__ = (() => {
|
|
|
1438
1911
|
// src/adapter/device.ts
|
|
1439
1912
|
var DeviceLimits = class {
|
|
1440
1913
|
};
|
|
1914
|
+
function formatErrorLogArguments(context, args) {
|
|
1915
|
+
const formattedContext = formatErrorLogValue(context);
|
|
1916
|
+
const formattedArgs = args.map(formatErrorLogValue).filter((arg) => arg !== void 0);
|
|
1917
|
+
return [formattedContext, ...formattedArgs].filter((arg) => arg !== void 0);
|
|
1918
|
+
}
|
|
1919
|
+
function formatErrorLogValue(value) {
|
|
1920
|
+
if (value === void 0) {
|
|
1921
|
+
return void 0;
|
|
1922
|
+
}
|
|
1923
|
+
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
1924
|
+
return value;
|
|
1925
|
+
}
|
|
1926
|
+
if (value instanceof Error) {
|
|
1927
|
+
return value.message;
|
|
1928
|
+
}
|
|
1929
|
+
if (Array.isArray(value)) {
|
|
1930
|
+
return value.map(formatErrorLogValue);
|
|
1931
|
+
}
|
|
1932
|
+
if (typeof value === "object") {
|
|
1933
|
+
if (hasCustomToString(value)) {
|
|
1934
|
+
const stringValue = String(value);
|
|
1935
|
+
if (stringValue !== "[object Object]") {
|
|
1936
|
+
return stringValue;
|
|
1937
|
+
}
|
|
1938
|
+
}
|
|
1939
|
+
if (looksLikeGPUCompilationMessage(value)) {
|
|
1940
|
+
return formatGPUCompilationMessage(value);
|
|
1941
|
+
}
|
|
1942
|
+
return value.constructor?.name || "Object";
|
|
1943
|
+
}
|
|
1944
|
+
return String(value);
|
|
1945
|
+
}
|
|
1946
|
+
function hasCustomToString(value) {
|
|
1947
|
+
return "toString" in value && typeof value.toString === "function" && value.toString !== Object.prototype.toString;
|
|
1948
|
+
}
|
|
1949
|
+
function looksLikeGPUCompilationMessage(value) {
|
|
1950
|
+
return "message" in value && "type" in value;
|
|
1951
|
+
}
|
|
1952
|
+
function formatGPUCompilationMessage(value) {
|
|
1953
|
+
const type = typeof value.type === "string" ? value.type : "message";
|
|
1954
|
+
const message = typeof value.message === "string" ? value.message : "";
|
|
1955
|
+
const lineNum = typeof value.lineNum === "number" ? value.lineNum : null;
|
|
1956
|
+
const linePos = typeof value.linePos === "number" ? value.linePos : null;
|
|
1957
|
+
const location = lineNum !== null && linePos !== null ? ` @ ${lineNum}:${linePos}` : lineNum !== null ? ` @ ${lineNum}` : "";
|
|
1958
|
+
return `${type}${location}: ${message}`.trim();
|
|
1959
|
+
}
|
|
1441
1960
|
var DeviceFeatures = class {
|
|
1442
1961
|
features;
|
|
1443
1962
|
disabledFeatures;
|
|
@@ -1467,19 +1986,24 @@ var __exports__ = (() => {
|
|
|
1467
1986
|
userData = {};
|
|
1468
1987
|
/** stats */
|
|
1469
1988
|
statsManager = lumaStats;
|
|
1989
|
+
/** Internal per-device factory storage */
|
|
1990
|
+
_factories = {};
|
|
1470
1991
|
/** An abstract timestamp used for change tracking */
|
|
1471
1992
|
timestamp = 0;
|
|
1472
1993
|
/** True if this device has been reused during device creation (app has multiple references) */
|
|
1473
1994
|
_reused = false;
|
|
1474
1995
|
/** Used by other luma.gl modules to store data on the device */
|
|
1475
|
-
|
|
1996
|
+
_moduleData = {};
|
|
1476
1997
|
_textureCaps = {};
|
|
1998
|
+
/** Internal timestamp query set used when GPU timing collection is enabled for this device. */
|
|
1999
|
+
_debugGPUTimeQuery = null;
|
|
1477
2000
|
constructor(props) {
|
|
1478
2001
|
this.props = { ..._Device.defaultProps, ...props };
|
|
1479
2002
|
this.id = this.props.id || uid(this[Symbol.toStringTag].toLowerCase());
|
|
1480
2003
|
}
|
|
2004
|
+
// TODO - just expose the shadertypes decoders?
|
|
1481
2005
|
getVertexFormatInfo(format) {
|
|
1482
|
-
return getVertexFormatInfo(format);
|
|
2006
|
+
return vertexFormatDecoder.getVertexFormatInfo(format);
|
|
1483
2007
|
}
|
|
1484
2008
|
isVertexFormatSupported(format) {
|
|
1485
2009
|
return true;
|
|
@@ -1527,6 +2051,16 @@ var __exports__ = (() => {
|
|
|
1527
2051
|
isTextureFormatCompressed(format) {
|
|
1528
2052
|
return textureFormatDecoder.isCompressed(format);
|
|
1529
2053
|
}
|
|
2054
|
+
/** Returns the compressed texture formats that can be created and sampled on this device */
|
|
2055
|
+
getSupportedCompressedTextureFormats() {
|
|
2056
|
+
const supportedFormats = [];
|
|
2057
|
+
for (const format of Object.keys(getTextureFormatTable())) {
|
|
2058
|
+
if (this.isTextureFormatCompressed(format) && this.isTextureFormatSupported(format)) {
|
|
2059
|
+
supportedFormats.push(format);
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
return supportedFormats;
|
|
2063
|
+
}
|
|
1530
2064
|
// DEBUG METHODS
|
|
1531
2065
|
pushDebugGroup(groupLabel) {
|
|
1532
2066
|
this.commandEncoder.pushDebugGroup(groupLabel);
|
|
@@ -1569,7 +2103,13 @@ var __exports__ = (() => {
|
|
|
1569
2103
|
reportError(error, context, ...args) {
|
|
1570
2104
|
const isHandled = this.props.onError(error, context);
|
|
1571
2105
|
if (!isHandled) {
|
|
1572
|
-
|
|
2106
|
+
const logArguments = formatErrorLogArguments(context, args);
|
|
2107
|
+
return log.error(
|
|
2108
|
+
this.type === "webgl" ? "%cWebGL" : "%cWebGPU",
|
|
2109
|
+
"color: white; background: red; padding: 2px 6px; border-radius: 3px;",
|
|
2110
|
+
error.message,
|
|
2111
|
+
...logArguments
|
|
2112
|
+
);
|
|
1573
2113
|
}
|
|
1574
2114
|
return () => {
|
|
1575
2115
|
};
|
|
@@ -1591,6 +2131,10 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1591
2131
|
}
|
|
1592
2132
|
return this.canvasContext;
|
|
1593
2133
|
}
|
|
2134
|
+
/** Create a fence sync object */
|
|
2135
|
+
createFence() {
|
|
2136
|
+
throw new Error("createFence() not implemented");
|
|
2137
|
+
}
|
|
1594
2138
|
/** Create a RenderPass using the default CommandEncoder */
|
|
1595
2139
|
beginRenderPass(props) {
|
|
1596
2140
|
return this.commandEncoder.beginRenderPass(props);
|
|
@@ -1599,6 +2143,78 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1599
2143
|
beginComputePass(props) {
|
|
1600
2144
|
return this.commandEncoder.beginComputePass(props);
|
|
1601
2145
|
}
|
|
2146
|
+
/**
|
|
2147
|
+
* Generate mipmaps for a WebGPU texture.
|
|
2148
|
+
* WebGPU textures must be created up front with the required mip count, usage flags, and a format that supports the chosen generation path.
|
|
2149
|
+
* WebGL uses `Texture.generateMipmapsWebGL()` directly because the backend manages mip generation on the texture object itself.
|
|
2150
|
+
*/
|
|
2151
|
+
generateMipmapsWebGPU(_texture) {
|
|
2152
|
+
throw new Error("not implemented");
|
|
2153
|
+
}
|
|
2154
|
+
/** Internal helper for creating a shareable WebGL render-pipeline implementation. */
|
|
2155
|
+
_createSharedRenderPipelineWebGL(_props) {
|
|
2156
|
+
throw new Error("_createSharedRenderPipelineWebGL() not implemented");
|
|
2157
|
+
}
|
|
2158
|
+
/** Internal WebGPU-only helper for retrieving the native bind-group layout for a pipeline group. */
|
|
2159
|
+
_createBindGroupLayoutWebGPU(_pipeline, _group) {
|
|
2160
|
+
throw new Error("_createBindGroupLayoutWebGPU() not implemented");
|
|
2161
|
+
}
|
|
2162
|
+
/** Internal WebGPU-only helper for creating a native bind group. */
|
|
2163
|
+
_createBindGroupWebGPU(_bindGroupLayout, _shaderLayout, _bindings, _group) {
|
|
2164
|
+
throw new Error("_createBindGroupWebGPU() not implemented");
|
|
2165
|
+
}
|
|
2166
|
+
/**
|
|
2167
|
+
* Internal helper that returns `true` when timestamp-query GPU timing should be
|
|
2168
|
+
* collected for this device.
|
|
2169
|
+
*/
|
|
2170
|
+
_supportsDebugGPUTime() {
|
|
2171
|
+
return this.features.has("timestamp-query") && Boolean(this.props.debug || this.props.debugGPUTime);
|
|
2172
|
+
}
|
|
2173
|
+
/**
|
|
2174
|
+
* Internal helper that enables device-managed GPU timing collection on the
|
|
2175
|
+
* default command encoder. Reuses the existing query set if timing is already enabled.
|
|
2176
|
+
*
|
|
2177
|
+
* @param queryCount - Number of timestamp slots reserved for profiled passes.
|
|
2178
|
+
* @returns The device-managed timestamp QuerySet, or `null` when timing is not supported or could not be enabled.
|
|
2179
|
+
*/
|
|
2180
|
+
_enableDebugGPUTime(queryCount = 256) {
|
|
2181
|
+
if (!this._supportsDebugGPUTime()) {
|
|
2182
|
+
return null;
|
|
2183
|
+
}
|
|
2184
|
+
if (this._debugGPUTimeQuery) {
|
|
2185
|
+
return this._debugGPUTimeQuery;
|
|
2186
|
+
}
|
|
2187
|
+
try {
|
|
2188
|
+
this._debugGPUTimeQuery = this.createQuerySet({ type: "timestamp", count: queryCount });
|
|
2189
|
+
this.commandEncoder = this.createCommandEncoder({
|
|
2190
|
+
id: this.commandEncoder.props.id,
|
|
2191
|
+
timeProfilingQuerySet: this._debugGPUTimeQuery
|
|
2192
|
+
});
|
|
2193
|
+
} catch {
|
|
2194
|
+
this._debugGPUTimeQuery = null;
|
|
2195
|
+
}
|
|
2196
|
+
return this._debugGPUTimeQuery;
|
|
2197
|
+
}
|
|
2198
|
+
/**
|
|
2199
|
+
* Internal helper that disables device-managed GPU timing collection and restores
|
|
2200
|
+
* the default command encoder to an unprofiled state.
|
|
2201
|
+
*/
|
|
2202
|
+
_disableDebugGPUTime() {
|
|
2203
|
+
if (!this._debugGPUTimeQuery) {
|
|
2204
|
+
return;
|
|
2205
|
+
}
|
|
2206
|
+
if (this.commandEncoder.getTimeProfilingQuerySet() === this._debugGPUTimeQuery) {
|
|
2207
|
+
this.commandEncoder = this.createCommandEncoder({
|
|
2208
|
+
id: this.commandEncoder.props.id
|
|
2209
|
+
});
|
|
2210
|
+
}
|
|
2211
|
+
this._debugGPUTimeQuery.destroy();
|
|
2212
|
+
this._debugGPUTimeQuery = null;
|
|
2213
|
+
}
|
|
2214
|
+
/** Internal helper that returns `true` when device-managed GPU timing is currently active. */
|
|
2215
|
+
_isDebugGPUTimeEnabled() {
|
|
2216
|
+
return this._debugGPUTimeQuery !== null;
|
|
2217
|
+
}
|
|
1602
2218
|
// DEPRECATED METHODS
|
|
1603
2219
|
/** @deprecated Use getDefaultCanvasContext() */
|
|
1604
2220
|
getCanvasContext() {
|
|
@@ -1634,6 +2250,12 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1634
2250
|
resetWebGL() {
|
|
1635
2251
|
throw new Error("not implemented");
|
|
1636
2252
|
}
|
|
2253
|
+
// INTERNAL LUMA.GL METHODS
|
|
2254
|
+
getModuleData(moduleName) {
|
|
2255
|
+
this._moduleData[moduleName] ||= {};
|
|
2256
|
+
return this._moduleData[moduleName];
|
|
2257
|
+
}
|
|
2258
|
+
// INTERNAL HELPERS
|
|
1637
2259
|
// IMPLEMENTATION
|
|
1638
2260
|
/** Helper to get the canvas context props */
|
|
1639
2261
|
static _getCanvasContextProps(props) {
|
|
@@ -1665,6 +2287,9 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1665
2287
|
newProps.indexType = "uint32";
|
|
1666
2288
|
} else if (props.data instanceof Uint16Array) {
|
|
1667
2289
|
newProps.indexType = "uint16";
|
|
2290
|
+
} else if (props.data instanceof Uint8Array) {
|
|
2291
|
+
newProps.data = new Uint16Array(props.data);
|
|
2292
|
+
newProps.indexType = "uint16";
|
|
1668
2293
|
}
|
|
1669
2294
|
}
|
|
1670
2295
|
if (!newProps.indexType) {
|
|
@@ -1697,7 +2322,8 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1697
2322
|
onVisibilityChange: (context) => log.log(1, `${context} Visibility changed ${context.isVisible}`)(),
|
|
1698
2323
|
onDevicePixelRatioChange: (context, info) => log.log(1, `${context} DPR changed ${info.oldRatio} => ${context.devicePixelRatio}`)(),
|
|
1699
2324
|
// Debug flags
|
|
1700
|
-
debug:
|
|
2325
|
+
debug: getDefaultDebugValue(),
|
|
2326
|
+
debugGPUTime: false,
|
|
1701
2327
|
debugShaders: log.get("debug-shaders") || void 0,
|
|
1702
2328
|
debugFramebuffers: Boolean(log.get("debug-framebuffers")),
|
|
1703
2329
|
debugFactories: Boolean(log.get("debug-factories")),
|
|
@@ -1708,9 +2334,11 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1708
2334
|
// Experimental
|
|
1709
2335
|
_reuseDevices: false,
|
|
1710
2336
|
_requestMaxLimits: true,
|
|
1711
|
-
_cacheShaders:
|
|
1712
|
-
|
|
1713
|
-
|
|
2337
|
+
_cacheShaders: true,
|
|
2338
|
+
_destroyShaders: false,
|
|
2339
|
+
_cachePipelines: true,
|
|
2340
|
+
_sharePipelines: true,
|
|
2341
|
+
_destroyPipelines: false,
|
|
1714
2342
|
// TODO - Change these after confirming things work as expected
|
|
1715
2343
|
_initializeFeatures: true,
|
|
1716
2344
|
_disabledFeatures: {
|
|
@@ -1719,6 +2347,25 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1719
2347
|
// INTERNAL
|
|
1720
2348
|
_handle: void 0
|
|
1721
2349
|
});
|
|
2350
|
+
function _getDefaultDebugValue(logDebugValue, nodeEnv) {
|
|
2351
|
+
if (logDebugValue !== void 0 && logDebugValue !== null) {
|
|
2352
|
+
return Boolean(logDebugValue);
|
|
2353
|
+
}
|
|
2354
|
+
if (nodeEnv !== void 0) {
|
|
2355
|
+
return nodeEnv !== "production";
|
|
2356
|
+
}
|
|
2357
|
+
return false;
|
|
2358
|
+
}
|
|
2359
|
+
function getDefaultDebugValue() {
|
|
2360
|
+
return _getDefaultDebugValue(log.get("debug"), getNodeEnv());
|
|
2361
|
+
}
|
|
2362
|
+
function getNodeEnv() {
|
|
2363
|
+
const processObject = globalThis.process;
|
|
2364
|
+
if (!processObject?.env) {
|
|
2365
|
+
return void 0;
|
|
2366
|
+
}
|
|
2367
|
+
return processObject.env["NODE_ENV"];
|
|
2368
|
+
}
|
|
1722
2369
|
|
|
1723
2370
|
// src/adapter/luma.ts
|
|
1724
2371
|
var STARTUP_MESSAGE = "set luma.log.level=1 (or higher) to trace rendering";
|
|
@@ -1896,6 +2543,100 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1896
2543
|
return pageLoadPromise;
|
|
1897
2544
|
}
|
|
1898
2545
|
|
|
2546
|
+
// src/adapter/canvas-observer.ts
|
|
2547
|
+
var CanvasObserver = class {
|
|
2548
|
+
props;
|
|
2549
|
+
_resizeObserver;
|
|
2550
|
+
_intersectionObserver;
|
|
2551
|
+
_observeDevicePixelRatioTimeout = null;
|
|
2552
|
+
_observeDevicePixelRatioMediaQuery = null;
|
|
2553
|
+
_handleDevicePixelRatioChange = () => this._refreshDevicePixelRatio();
|
|
2554
|
+
_trackPositionInterval = null;
|
|
2555
|
+
_started = false;
|
|
2556
|
+
get started() {
|
|
2557
|
+
return this._started;
|
|
2558
|
+
}
|
|
2559
|
+
constructor(props) {
|
|
2560
|
+
this.props = props;
|
|
2561
|
+
}
|
|
2562
|
+
start() {
|
|
2563
|
+
if (this._started || !this.props.canvas) {
|
|
2564
|
+
return;
|
|
2565
|
+
}
|
|
2566
|
+
this._started = true;
|
|
2567
|
+
this._intersectionObserver ||= new IntersectionObserver(
|
|
2568
|
+
(entries) => this.props.onIntersection(entries)
|
|
2569
|
+
);
|
|
2570
|
+
this._resizeObserver ||= new ResizeObserver((entries) => this.props.onResize(entries));
|
|
2571
|
+
this._intersectionObserver.observe(this.props.canvas);
|
|
2572
|
+
try {
|
|
2573
|
+
this._resizeObserver.observe(this.props.canvas, { box: "device-pixel-content-box" });
|
|
2574
|
+
} catch {
|
|
2575
|
+
this._resizeObserver.observe(this.props.canvas, { box: "content-box" });
|
|
2576
|
+
}
|
|
2577
|
+
this._observeDevicePixelRatioTimeout = setTimeout(() => this._refreshDevicePixelRatio(), 0);
|
|
2578
|
+
if (this.props.trackPosition) {
|
|
2579
|
+
this._trackPosition();
|
|
2580
|
+
}
|
|
2581
|
+
}
|
|
2582
|
+
stop() {
|
|
2583
|
+
if (!this._started) {
|
|
2584
|
+
return;
|
|
2585
|
+
}
|
|
2586
|
+
this._started = false;
|
|
2587
|
+
if (this._observeDevicePixelRatioTimeout) {
|
|
2588
|
+
clearTimeout(this._observeDevicePixelRatioTimeout);
|
|
2589
|
+
this._observeDevicePixelRatioTimeout = null;
|
|
2590
|
+
}
|
|
2591
|
+
if (this._observeDevicePixelRatioMediaQuery) {
|
|
2592
|
+
this._observeDevicePixelRatioMediaQuery.removeEventListener(
|
|
2593
|
+
"change",
|
|
2594
|
+
this._handleDevicePixelRatioChange
|
|
2595
|
+
);
|
|
2596
|
+
this._observeDevicePixelRatioMediaQuery = null;
|
|
2597
|
+
}
|
|
2598
|
+
if (this._trackPositionInterval) {
|
|
2599
|
+
clearInterval(this._trackPositionInterval);
|
|
2600
|
+
this._trackPositionInterval = null;
|
|
2601
|
+
}
|
|
2602
|
+
this._resizeObserver?.disconnect();
|
|
2603
|
+
this._intersectionObserver?.disconnect();
|
|
2604
|
+
}
|
|
2605
|
+
_refreshDevicePixelRatio() {
|
|
2606
|
+
if (!this._started) {
|
|
2607
|
+
return;
|
|
2608
|
+
}
|
|
2609
|
+
this.props.onDevicePixelRatioChange();
|
|
2610
|
+
this._observeDevicePixelRatioMediaQuery?.removeEventListener(
|
|
2611
|
+
"change",
|
|
2612
|
+
this._handleDevicePixelRatioChange
|
|
2613
|
+
);
|
|
2614
|
+
this._observeDevicePixelRatioMediaQuery = matchMedia(
|
|
2615
|
+
`(resolution: ${window.devicePixelRatio}dppx)`
|
|
2616
|
+
);
|
|
2617
|
+
this._observeDevicePixelRatioMediaQuery.addEventListener(
|
|
2618
|
+
"change",
|
|
2619
|
+
this._handleDevicePixelRatioChange,
|
|
2620
|
+
{ once: true }
|
|
2621
|
+
);
|
|
2622
|
+
}
|
|
2623
|
+
_trackPosition(intervalMs = 100) {
|
|
2624
|
+
if (this._trackPositionInterval) {
|
|
2625
|
+
return;
|
|
2626
|
+
}
|
|
2627
|
+
this._trackPositionInterval = setInterval(() => {
|
|
2628
|
+
if (!this._started) {
|
|
2629
|
+
if (this._trackPositionInterval) {
|
|
2630
|
+
clearInterval(this._trackPositionInterval);
|
|
2631
|
+
this._trackPositionInterval = null;
|
|
2632
|
+
}
|
|
2633
|
+
} else {
|
|
2634
|
+
this.props.onPositionChange();
|
|
2635
|
+
}
|
|
2636
|
+
}, intervalMs);
|
|
2637
|
+
}
|
|
2638
|
+
};
|
|
2639
|
+
|
|
1899
2640
|
// src/utils/promise-utils.ts
|
|
1900
2641
|
function withResolvers() {
|
|
1901
2642
|
let resolve;
|
|
@@ -1907,8 +2648,21 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1907
2648
|
return { promise, resolve, reject };
|
|
1908
2649
|
}
|
|
1909
2650
|
|
|
1910
|
-
// src/
|
|
1911
|
-
|
|
2651
|
+
// src/utils/assert.ts
|
|
2652
|
+
function assert2(condition, message) {
|
|
2653
|
+
if (!condition) {
|
|
2654
|
+
const error = new Error(message ?? "luma.gl assertion failed.");
|
|
2655
|
+
Error.captureStackTrace?.(error, assert2);
|
|
2656
|
+
throw error;
|
|
2657
|
+
}
|
|
2658
|
+
}
|
|
2659
|
+
function assertDefined(value, message) {
|
|
2660
|
+
assert2(value, message);
|
|
2661
|
+
return value;
|
|
2662
|
+
}
|
|
2663
|
+
|
|
2664
|
+
// src/adapter/canvas-surface.ts
|
|
2665
|
+
var _CanvasSurface = class {
|
|
1912
2666
|
static isHTMLCanvas(canvas) {
|
|
1913
2667
|
return typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement;
|
|
1914
2668
|
}
|
|
@@ -1942,16 +2696,20 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1942
2696
|
drawingBufferWidth;
|
|
1943
2697
|
/** Height of drawing buffer: automatically tracks this.pixelHeight if props.autoResize is true */
|
|
1944
2698
|
drawingBufferHeight;
|
|
2699
|
+
/** Resolves when the canvas is initialized, i.e. when the ResizeObserver has updated the pixel size */
|
|
1945
2700
|
_initializedResolvers = withResolvers();
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
_position;
|
|
2701
|
+
_canvasObserver;
|
|
2702
|
+
/** Position of the canvas in the document, updated by a timer */
|
|
2703
|
+
_position = [0, 0];
|
|
2704
|
+
/** Whether this canvas context has been destroyed */
|
|
1949
2705
|
destroyed = false;
|
|
2706
|
+
/** Whether the drawing buffer size needs to be resized (deferred resizing to avoid flicker) */
|
|
2707
|
+
_needsDrawingBufferResize = true;
|
|
1950
2708
|
toString() {
|
|
1951
2709
|
return `${this[Symbol.toStringTag]}(${this.id})`;
|
|
1952
2710
|
}
|
|
1953
2711
|
constructor(props) {
|
|
1954
|
-
this.props = { ...
|
|
2712
|
+
this.props = { ..._CanvasSurface.defaultProps, ...props };
|
|
1955
2713
|
props = this.props;
|
|
1956
2714
|
this.initialized = this._initializedResolvers.promise;
|
|
1957
2715
|
if (!isBrowser()) {
|
|
@@ -1963,11 +2721,11 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1963
2721
|
} else {
|
|
1964
2722
|
this.canvas = props.canvas;
|
|
1965
2723
|
}
|
|
1966
|
-
if (
|
|
2724
|
+
if (_CanvasSurface.isHTMLCanvas(this.canvas)) {
|
|
1967
2725
|
this.id = props.id || this.canvas.id;
|
|
1968
2726
|
this.type = "html-canvas";
|
|
1969
2727
|
this.htmlCanvas = this.canvas;
|
|
1970
|
-
} else if (
|
|
2728
|
+
} else if (_CanvasSurface.isOffscreenCanvas(this.canvas)) {
|
|
1971
2729
|
this.id = props.id || "offscreen-canvas";
|
|
1972
2730
|
this.type = "offscreen-canvas";
|
|
1973
2731
|
this.offscreenCanvas = this.canvas;
|
|
@@ -1983,25 +2741,21 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1983
2741
|
this.drawingBufferHeight = this.canvas.height;
|
|
1984
2742
|
this.devicePixelRatio = globalThis.devicePixelRatio || 1;
|
|
1985
2743
|
this._position = [0, 0];
|
|
1986
|
-
|
|
1987
|
-
this.
|
|
1988
|
-
|
|
1989
|
-
)
|
|
1990
|
-
this.
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
} catch {
|
|
1995
|
-
this._resizeObserver.observe(this.canvas, { box: "content-box" });
|
|
1996
|
-
}
|
|
1997
|
-
setTimeout(() => this._observeDevicePixelRatio(), 0);
|
|
1998
|
-
if (this.props.trackPosition) {
|
|
1999
|
-
this._trackPosition();
|
|
2000
|
-
}
|
|
2001
|
-
}
|
|
2744
|
+
this._canvasObserver = new CanvasObserver({
|
|
2745
|
+
canvas: this.htmlCanvas,
|
|
2746
|
+
trackPosition: this.props.trackPosition,
|
|
2747
|
+
onResize: (entries) => this._handleResize(entries),
|
|
2748
|
+
onIntersection: (entries) => this._handleIntersection(entries),
|
|
2749
|
+
onDevicePixelRatioChange: () => this._observeDevicePixelRatio(),
|
|
2750
|
+
onPositionChange: () => this.updatePosition()
|
|
2751
|
+
});
|
|
2002
2752
|
}
|
|
2003
2753
|
destroy() {
|
|
2004
|
-
this.destroyed
|
|
2754
|
+
if (!this.destroyed) {
|
|
2755
|
+
this.destroyed = true;
|
|
2756
|
+
this._stopObservers();
|
|
2757
|
+
this.device = null;
|
|
2758
|
+
}
|
|
2005
2759
|
}
|
|
2006
2760
|
setProps(props) {
|
|
2007
2761
|
if ("useDevicePixels" in props) {
|
|
@@ -2010,55 +2764,41 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2010
2764
|
}
|
|
2011
2765
|
return this;
|
|
2012
2766
|
}
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
*/
|
|
2767
|
+
/** Returns a framebuffer with properly resized current 'swap chain' textures */
|
|
2768
|
+
getCurrentFramebuffer(options) {
|
|
2769
|
+
this._resizeDrawingBufferIfNeeded();
|
|
2770
|
+
return this._getCurrentFramebuffer(options);
|
|
2771
|
+
}
|
|
2019
2772
|
getCSSSize() {
|
|
2020
2773
|
return [this.cssWidth, this.cssHeight];
|
|
2021
2774
|
}
|
|
2022
2775
|
getPosition() {
|
|
2023
2776
|
return this._position;
|
|
2024
2777
|
}
|
|
2025
|
-
/**
|
|
2026
|
-
* Returns the size covered by the canvas in actual device pixels.
|
|
2027
|
-
* @note This can be different from the 'CSS' size of a canvas due to DPR scaling, and rounding to integer pixels
|
|
2028
|
-
* @note This is independent of the canvas' internal drawing buffer size (.width, .height).
|
|
2029
|
-
*/
|
|
2030
2778
|
getDevicePixelSize() {
|
|
2031
2779
|
return [this.devicePixelWidth, this.devicePixelHeight];
|
|
2032
2780
|
}
|
|
2033
|
-
/** Get the drawing buffer size (number of pixels GPU is rendering into, can be different from CSS size) */
|
|
2034
2781
|
getDrawingBufferSize() {
|
|
2035
2782
|
return [this.drawingBufferWidth, this.drawingBufferHeight];
|
|
2036
2783
|
}
|
|
2037
|
-
/** Returns the biggest allowed framebuffer size. @todo Allow the application to limit this? */
|
|
2038
2784
|
getMaxDrawingBufferSize() {
|
|
2039
2785
|
const maxTextureDimension = this.device.limits.maxTextureDimension2D;
|
|
2040
2786
|
return [maxTextureDimension, maxTextureDimension];
|
|
2041
2787
|
}
|
|
2042
|
-
/** Update the canvas drawing buffer size. Called automatically if props.autoResize is true. */
|
|
2043
2788
|
setDrawingBufferSize(width, height) {
|
|
2044
|
-
|
|
2045
|
-
|
|
2789
|
+
width = Math.floor(width);
|
|
2790
|
+
height = Math.floor(height);
|
|
2791
|
+
if (this.drawingBufferWidth === width && this.drawingBufferHeight === height) {
|
|
2792
|
+
return;
|
|
2793
|
+
}
|
|
2046
2794
|
this.drawingBufferWidth = width;
|
|
2047
2795
|
this.drawingBufferHeight = height;
|
|
2796
|
+
this._needsDrawingBufferResize = true;
|
|
2048
2797
|
}
|
|
2049
|
-
/**
|
|
2050
|
-
* Returns the current DPR (number of physical pixels per CSS pixel), if props.useDevicePixels is true
|
|
2051
|
-
* @note This can be a fractional (non-integer) number, e.g. when the user zooms in the browser.
|
|
2052
|
-
* @note This function handles the non-HTML canvas cases
|
|
2053
|
-
*/
|
|
2054
2798
|
getDevicePixelRatio() {
|
|
2055
|
-
const
|
|
2056
|
-
return
|
|
2799
|
+
const devicePixelRatio2 = typeof window !== "undefined" && window.devicePixelRatio;
|
|
2800
|
+
return devicePixelRatio2 || 1;
|
|
2057
2801
|
}
|
|
2058
|
-
// DEPRECATED METHODS
|
|
2059
|
-
/**
|
|
2060
|
-
* Maps CSS pixel position to device pixel position
|
|
2061
|
-
*/
|
|
2062
2802
|
cssToDevicePixels(cssPixel, yInvert = true) {
|
|
2063
2803
|
const ratio = this.cssToDeviceRatio();
|
|
2064
2804
|
const [width, height] = this.getDrawingBufferSize();
|
|
@@ -2068,10 +2808,10 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2068
2808
|
getPixelSize() {
|
|
2069
2809
|
return this.getDevicePixelSize();
|
|
2070
2810
|
}
|
|
2071
|
-
/** @deprecated
|
|
2811
|
+
/** @deprecated Use the current drawing buffer size for projection setup. */
|
|
2072
2812
|
getAspect() {
|
|
2073
|
-
const [width, height] = this.
|
|
2074
|
-
return width / height;
|
|
2813
|
+
const [width, height] = this.getDrawingBufferSize();
|
|
2814
|
+
return width > 0 && height > 0 ? width / height : 1;
|
|
2075
2815
|
}
|
|
2076
2816
|
/** @deprecated Returns multiplier need to convert CSS size to Device size */
|
|
2077
2817
|
cssToDeviceRatio() {
|
|
@@ -2087,18 +2827,40 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2087
2827
|
resize(size) {
|
|
2088
2828
|
this.setDrawingBufferSize(size.width, size.height);
|
|
2089
2829
|
}
|
|
2090
|
-
// IMPLEMENTATION
|
|
2091
|
-
/**
|
|
2092
|
-
* Allows subclass constructor to override the canvas id for auto created canvases.
|
|
2093
|
-
* This can really help when debugging DOM in apps that create multiple devices
|
|
2094
|
-
*/
|
|
2095
2830
|
_setAutoCreatedCanvasId(id) {
|
|
2096
2831
|
if (this.htmlCanvas?.id === "lumagl-auto-created-canvas") {
|
|
2097
2832
|
this.htmlCanvas.id = id;
|
|
2098
2833
|
}
|
|
2099
2834
|
}
|
|
2100
|
-
/**
|
|
2835
|
+
/**
|
|
2836
|
+
* Starts DOM observation after the derived context and its device are fully initialized.
|
|
2837
|
+
*
|
|
2838
|
+
* `CanvasSurface` construction runs before subclasses can assign `this.device`, and the
|
|
2839
|
+
* default WebGL canvas context is created before `WebGLDevice` has initialized `limits`,
|
|
2840
|
+
* `features`, and the rest of its runtime state. Deferring observer startup avoids early
|
|
2841
|
+
* `ResizeObserver` and DPR callbacks running against a partially initialized device.
|
|
2842
|
+
*/
|
|
2843
|
+
_startObservers() {
|
|
2844
|
+
if (this.destroyed) {
|
|
2845
|
+
return;
|
|
2846
|
+
}
|
|
2847
|
+
this._canvasObserver.start();
|
|
2848
|
+
}
|
|
2849
|
+
/**
|
|
2850
|
+
* Stops all DOM observation and timers associated with a canvas surface.
|
|
2851
|
+
*
|
|
2852
|
+
* This pairs with `_startObservers()` so teardown uses the same lifecycle whether a context is
|
|
2853
|
+
* explicitly destroyed, abandoned during device reuse, or temporarily has not started observing
|
|
2854
|
+
* yet. Centralizing shutdown here keeps resize/DPR/position watchers from surviving past the
|
|
2855
|
+
* lifetime of the owning device.
|
|
2856
|
+
*/
|
|
2857
|
+
_stopObservers() {
|
|
2858
|
+
this._canvasObserver.stop();
|
|
2859
|
+
}
|
|
2101
2860
|
_handleIntersection(entries) {
|
|
2861
|
+
if (this.destroyed) {
|
|
2862
|
+
return;
|
|
2863
|
+
}
|
|
2102
2864
|
const entry = entries.find((entry_) => entry_.target === this.canvas);
|
|
2103
2865
|
if (!entry) {
|
|
2104
2866
|
return;
|
|
@@ -2109,21 +2871,20 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2109
2871
|
this.device.props.onVisibilityChange(this);
|
|
2110
2872
|
}
|
|
2111
2873
|
}
|
|
2112
|
-
/**
|
|
2113
|
-
* Reacts to an observed resize by using the most accurate pixel size information the browser can provide
|
|
2114
|
-
* @see https://web.dev/articles/device-pixel-content-box
|
|
2115
|
-
* @see https://webgpufundamentals.org/webgpu/lessons/webgpu-resizing-the-canvas.html
|
|
2116
|
-
*/
|
|
2117
2874
|
_handleResize(entries) {
|
|
2875
|
+
if (this.destroyed) {
|
|
2876
|
+
return;
|
|
2877
|
+
}
|
|
2118
2878
|
const entry = entries.find((entry_) => entry_.target === this.canvas);
|
|
2119
2879
|
if (!entry) {
|
|
2120
2880
|
return;
|
|
2121
2881
|
}
|
|
2122
|
-
|
|
2123
|
-
this.
|
|
2882
|
+
const contentBoxSize = assertDefined(entry.contentBoxSize?.[0]);
|
|
2883
|
+
this.cssWidth = contentBoxSize.inlineSize;
|
|
2884
|
+
this.cssHeight = contentBoxSize.blockSize;
|
|
2124
2885
|
const oldPixelSize = this.getDevicePixelSize();
|
|
2125
|
-
const devicePixelWidth = entry.devicePixelContentBoxSize?.[0]
|
|
2126
|
-
const devicePixelHeight = entry.devicePixelContentBoxSize?.[0]
|
|
2886
|
+
const devicePixelWidth = entry.devicePixelContentBoxSize?.[0]?.inlineSize || contentBoxSize.inlineSize * devicePixelRatio;
|
|
2887
|
+
const devicePixelHeight = entry.devicePixelContentBoxSize?.[0]?.blockSize || contentBoxSize.blockSize * devicePixelRatio;
|
|
2127
2888
|
const [maxDevicePixelWidth, maxDevicePixelHeight] = this.getMaxDrawingBufferSize();
|
|
2128
2889
|
this.devicePixelWidth = Math.max(1, Math.min(devicePixelWidth, maxDevicePixelWidth));
|
|
2129
2890
|
this.devicePixelHeight = Math.max(1, Math.min(devicePixelHeight, maxDevicePixelHeight));
|
|
@@ -2133,47 +2894,47 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2133
2894
|
_updateDrawingBufferSize() {
|
|
2134
2895
|
if (this.props.autoResize) {
|
|
2135
2896
|
if (typeof this.props.useDevicePixels === "number") {
|
|
2136
|
-
const
|
|
2137
|
-
this.setDrawingBufferSize(
|
|
2897
|
+
const devicePixelRatio2 = this.props.useDevicePixels;
|
|
2898
|
+
this.setDrawingBufferSize(
|
|
2899
|
+
this.cssWidth * devicePixelRatio2,
|
|
2900
|
+
this.cssHeight * devicePixelRatio2
|
|
2901
|
+
);
|
|
2138
2902
|
} else if (this.props.useDevicePixels) {
|
|
2139
2903
|
this.setDrawingBufferSize(this.devicePixelWidth, this.devicePixelHeight);
|
|
2140
2904
|
} else {
|
|
2141
2905
|
this.setDrawingBufferSize(this.cssWidth, this.cssHeight);
|
|
2142
2906
|
}
|
|
2143
|
-
this._updateDevice();
|
|
2144
2907
|
}
|
|
2145
2908
|
this._initializedResolvers.resolve();
|
|
2146
2909
|
this.isInitialized = true;
|
|
2147
2910
|
this.updatePosition();
|
|
2148
2911
|
}
|
|
2149
|
-
|
|
2912
|
+
_resizeDrawingBufferIfNeeded() {
|
|
2913
|
+
if (this._needsDrawingBufferResize) {
|
|
2914
|
+
this._needsDrawingBufferResize = false;
|
|
2915
|
+
const sizeChanged = this.drawingBufferWidth !== this.canvas.width || this.drawingBufferHeight !== this.canvas.height;
|
|
2916
|
+
if (sizeChanged) {
|
|
2917
|
+
this.canvas.width = this.drawingBufferWidth;
|
|
2918
|
+
this.canvas.height = this.drawingBufferHeight;
|
|
2919
|
+
this._configureDevice();
|
|
2920
|
+
}
|
|
2921
|
+
}
|
|
2922
|
+
}
|
|
2150
2923
|
_observeDevicePixelRatio() {
|
|
2924
|
+
if (this.destroyed || !this._canvasObserver.started) {
|
|
2925
|
+
return;
|
|
2926
|
+
}
|
|
2151
2927
|
const oldRatio = this.devicePixelRatio;
|
|
2152
2928
|
this.devicePixelRatio = window.devicePixelRatio;
|
|
2153
2929
|
this.updatePosition();
|
|
2154
|
-
this.device.props.onDevicePixelRatioChange(this, {
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
() => this._observeDevicePixelRatio(),
|
|
2158
|
-
{ once: true }
|
|
2159
|
-
);
|
|
2160
|
-
}
|
|
2161
|
-
/** Start tracking positions with a timer */
|
|
2162
|
-
_trackPosition(intervalMs = 100) {
|
|
2163
|
-
const intervalId = setInterval(() => {
|
|
2164
|
-
if (this.destroyed) {
|
|
2165
|
-
clearInterval(intervalId);
|
|
2166
|
-
} else {
|
|
2167
|
-
this.updatePosition();
|
|
2168
|
-
}
|
|
2169
|
-
}, intervalMs);
|
|
2930
|
+
this.device.props.onDevicePixelRatioChange?.(this, {
|
|
2931
|
+
oldRatio
|
|
2932
|
+
});
|
|
2170
2933
|
}
|
|
2171
|
-
/**
|
|
2172
|
-
* Calculated the absolute position of the canvas
|
|
2173
|
-
* @note - getBoundingClientRect() is normally cheap but can be expensive
|
|
2174
|
-
* if called before browser has finished a reflow. Should not be the case here.
|
|
2175
|
-
*/
|
|
2176
2934
|
updatePosition() {
|
|
2935
|
+
if (this.destroyed) {
|
|
2936
|
+
return;
|
|
2937
|
+
}
|
|
2177
2938
|
const newRect = this.htmlCanvas?.getBoundingClientRect();
|
|
2178
2939
|
if (newRect) {
|
|
2179
2940
|
const position = [newRect.left, newRect.top];
|
|
@@ -2182,13 +2943,15 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2182
2943
|
if (positionChanged) {
|
|
2183
2944
|
const oldPosition = this._position;
|
|
2184
2945
|
this._position = position;
|
|
2185
|
-
this.device.props.onPositionChange?.(this, {
|
|
2946
|
+
this.device.props.onPositionChange?.(this, {
|
|
2947
|
+
oldPosition
|
|
2948
|
+
});
|
|
2186
2949
|
}
|
|
2187
2950
|
}
|
|
2188
2951
|
}
|
|
2189
2952
|
};
|
|
2190
|
-
var
|
|
2191
|
-
__publicField(
|
|
2953
|
+
var CanvasSurface = _CanvasSurface;
|
|
2954
|
+
__publicField(CanvasSurface, "defaultProps", {
|
|
2192
2955
|
id: void 0,
|
|
2193
2956
|
canvas: null,
|
|
2194
2957
|
width: 800,
|
|
@@ -2216,7 +2979,7 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2216
2979
|
}
|
|
2217
2980
|
function getCanvasFromDOM(canvasId) {
|
|
2218
2981
|
const canvas = document.getElementById(canvasId);
|
|
2219
|
-
if (!
|
|
2982
|
+
if (!CanvasSurface.isHTMLCanvas(canvas)) {
|
|
2220
2983
|
throw new Error("Object is not a canvas element");
|
|
2221
2984
|
}
|
|
2222
2985
|
return canvas;
|
|
@@ -2240,33 +3003,40 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2240
3003
|
const point = pixel;
|
|
2241
3004
|
const x = scaleX(point[0], ratio, width);
|
|
2242
3005
|
let y = scaleY(point[1], ratio, height, yInvert);
|
|
2243
|
-
let
|
|
2244
|
-
const xHigh =
|
|
2245
|
-
|
|
3006
|
+
let temporary = scaleX(point[0] + 1, ratio, width);
|
|
3007
|
+
const xHigh = temporary === width - 1 ? temporary : temporary - 1;
|
|
3008
|
+
temporary = scaleY(point[1] + 1, ratio, height, yInvert);
|
|
2246
3009
|
let yHigh;
|
|
2247
3010
|
if (yInvert) {
|
|
2248
|
-
|
|
3011
|
+
temporary = temporary === 0 ? temporary : temporary + 1;
|
|
2249
3012
|
yHigh = y;
|
|
2250
|
-
y =
|
|
3013
|
+
y = temporary;
|
|
2251
3014
|
} else {
|
|
2252
|
-
yHigh =
|
|
3015
|
+
yHigh = temporary === height - 1 ? temporary : temporary - 1;
|
|
2253
3016
|
}
|
|
2254
3017
|
return {
|
|
2255
3018
|
x,
|
|
2256
3019
|
y,
|
|
2257
|
-
// when ratio < 1, current css pixel and next css pixel may point to same device pixel, set width/height to 1 in those cases.
|
|
2258
3020
|
width: Math.max(xHigh - x + 1, 1),
|
|
2259
3021
|
height: Math.max(yHigh - y + 1, 1)
|
|
2260
3022
|
};
|
|
2261
3023
|
}
|
|
2262
3024
|
function scaleX(x, ratio, width) {
|
|
2263
|
-
|
|
2264
|
-
return r;
|
|
3025
|
+
return Math.min(Math.round(x * ratio), width - 1);
|
|
2265
3026
|
}
|
|
2266
3027
|
function scaleY(y, ratio, height, yInvert) {
|
|
2267
3028
|
return yInvert ? Math.max(0, height - 1 - Math.round(y * ratio)) : Math.min(Math.round(y * ratio), height - 1);
|
|
2268
3029
|
}
|
|
2269
3030
|
|
|
3031
|
+
// src/adapter/canvas-context.ts
|
|
3032
|
+
var CanvasContext = class extends CanvasSurface {
|
|
3033
|
+
};
|
|
3034
|
+
__publicField(CanvasContext, "defaultProps", CanvasSurface.defaultProps);
|
|
3035
|
+
|
|
3036
|
+
// src/adapter/presentation-context.ts
|
|
3037
|
+
var PresentationContext = class extends CanvasSurface {
|
|
3038
|
+
};
|
|
3039
|
+
|
|
2270
3040
|
// src/adapter/resources/sampler.ts
|
|
2271
3041
|
var _Sampler = class extends Resource {
|
|
2272
3042
|
get [Symbol.toStringTag]() {
|
|
@@ -2321,7 +3091,15 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2321
3091
|
depth;
|
|
2322
3092
|
/** mip levels in this texture */
|
|
2323
3093
|
mipLevels;
|
|
2324
|
-
/**
|
|
3094
|
+
/** sample count */
|
|
3095
|
+
samples;
|
|
3096
|
+
/** Rows are multiples of this length, padded with extra bytes if needed */
|
|
3097
|
+
byteAlignment;
|
|
3098
|
+
/** The ready promise is always resolved. It is provided for type compatibility with DynamicTexture. */
|
|
3099
|
+
ready = Promise.resolve(this);
|
|
3100
|
+
/** isReady is always true. It is provided for type compatibility with DynamicTexture. */
|
|
3101
|
+
isReady = true;
|
|
3102
|
+
/** "Time" of last update. Monotonically increasing timestamp. TODO move to DynamicTexture? */
|
|
2325
3103
|
updateTimestamp;
|
|
2326
3104
|
get [Symbol.toStringTag]() {
|
|
2327
3105
|
return "Texture";
|
|
@@ -2330,7 +3108,7 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2330
3108
|
return `Texture(${this.id},${this.format},${this.width}x${this.height})`;
|
|
2331
3109
|
}
|
|
2332
3110
|
/** Do not use directly. Create with device.createTexture() */
|
|
2333
|
-
constructor(device, props) {
|
|
3111
|
+
constructor(device, props, backendProps) {
|
|
2334
3112
|
props = _Texture.normalizeProps(device, props);
|
|
2335
3113
|
super(device, props, _Texture.defaultProps);
|
|
2336
3114
|
this.dimension = this.props.dimension;
|
|
@@ -2340,6 +3118,10 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2340
3118
|
this.height = this.props.height;
|
|
2341
3119
|
this.depth = this.props.depth;
|
|
2342
3120
|
this.mipLevels = this.props.mipLevels;
|
|
3121
|
+
this.samples = this.props.samples || 1;
|
|
3122
|
+
if (this.dimension === "cube") {
|
|
3123
|
+
this.depth = 6;
|
|
3124
|
+
}
|
|
2343
3125
|
if (this.props.width === void 0 || this.props.height === void 0) {
|
|
2344
3126
|
if (device.isExternalImage(props.data)) {
|
|
2345
3127
|
const size = device.getExternalImageSize(props.data);
|
|
@@ -2350,17 +3132,14 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2350
3132
|
this.height = 1;
|
|
2351
3133
|
if (this.props.width === void 0 || this.props.height === void 0) {
|
|
2352
3134
|
log.warn(
|
|
2353
|
-
`${this} created with undefined width or height. This is deprecated. Use
|
|
3135
|
+
`${this} created with undefined width or height. This is deprecated. Use DynamicTexture instead.`
|
|
2354
3136
|
)();
|
|
2355
3137
|
}
|
|
2356
3138
|
}
|
|
2357
3139
|
}
|
|
3140
|
+
this.byteAlignment = backendProps?.byteAlignment || 1;
|
|
2358
3141
|
this.updateTimestamp = device.incrementTimestamp();
|
|
2359
3142
|
}
|
|
2360
|
-
/** Set sampler props associated with this texture */
|
|
2361
|
-
setSampler(sampler) {
|
|
2362
|
-
this.sampler = sampler instanceof Sampler ? sampler : this.device.createSampler(sampler);
|
|
2363
|
-
}
|
|
2364
3143
|
/**
|
|
2365
3144
|
* Create a new texture with the same parameters and optionally a different size
|
|
2366
3145
|
* @note Textures are immutable and cannot be resized after creation, but we can create a similar texture with the same parameters but a new size.
|
|
@@ -2369,6 +3148,105 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2369
3148
|
clone(size) {
|
|
2370
3149
|
return this.device.createTexture({ ...this.props, ...size });
|
|
2371
3150
|
}
|
|
3151
|
+
/** Set sampler props associated with this texture */
|
|
3152
|
+
setSampler(sampler) {
|
|
3153
|
+
this.sampler = sampler instanceof Sampler ? sampler : this.device.createSampler(sampler);
|
|
3154
|
+
}
|
|
3155
|
+
/**
|
|
3156
|
+
* Copy raw image data (bytes) into the texture.
|
|
3157
|
+
*
|
|
3158
|
+
* @note Deprecated compatibility wrapper over {@link writeData}.
|
|
3159
|
+
* @note Uses the same layout defaults and alignment rules as {@link writeData}.
|
|
3160
|
+
* @note Tightly packed CPU uploads can omit `bytesPerRow` and `rowsPerImage`.
|
|
3161
|
+
* @note If the CPU source rows are padded, pass explicit `bytesPerRow` and `rowsPerImage`.
|
|
3162
|
+
* @deprecated Use writeData()
|
|
3163
|
+
*/
|
|
3164
|
+
copyImageData(options) {
|
|
3165
|
+
const { data, depth, ...writeOptions } = options;
|
|
3166
|
+
this.writeData(data, {
|
|
3167
|
+
...writeOptions,
|
|
3168
|
+
depthOrArrayLayers: writeOptions.depthOrArrayLayers ?? depth
|
|
3169
|
+
});
|
|
3170
|
+
}
|
|
3171
|
+
/**
|
|
3172
|
+
* Calculates the memory layout of the texture, required when reading and writing data.
|
|
3173
|
+
* @return the backend-aligned linear layout, in particular bytesPerRow which includes any required padding for buffer copy/read paths
|
|
3174
|
+
*/
|
|
3175
|
+
computeMemoryLayout(options_ = {}) {
|
|
3176
|
+
const options = this._normalizeTextureReadOptions(options_);
|
|
3177
|
+
const { width = this.width, height = this.height, depthOrArrayLayers = this.depth } = options;
|
|
3178
|
+
const { format, byteAlignment } = this;
|
|
3179
|
+
return textureFormatDecoder.computeMemoryLayout({
|
|
3180
|
+
format,
|
|
3181
|
+
width,
|
|
3182
|
+
height,
|
|
3183
|
+
depth: depthOrArrayLayers,
|
|
3184
|
+
byteAlignment
|
|
3185
|
+
});
|
|
3186
|
+
}
|
|
3187
|
+
/**
|
|
3188
|
+
* Read the contents of a texture into a GPU Buffer.
|
|
3189
|
+
* @returns A Buffer containing the texture data.
|
|
3190
|
+
*
|
|
3191
|
+
* @note The memory layout of the texture data is determined by the texture format and dimensions.
|
|
3192
|
+
* @note The application can call Texture.computeMemoryLayout() to compute the backend-aligned layout.
|
|
3193
|
+
* @note The application can call Buffer.readAsync() to read the returned buffer on the CPU.
|
|
3194
|
+
* @note The destination buffer must be supplied by the caller and must be large enough for the requested region.
|
|
3195
|
+
* @note On WebGPU this corresponds to a texture-to-buffer copy and uses buffer-copy alignment rules.
|
|
3196
|
+
* @note On WebGL, luma.gl emulates the same logical readback behavior.
|
|
3197
|
+
*/
|
|
3198
|
+
readBuffer(options, buffer) {
|
|
3199
|
+
throw new Error("readBuffer not implemented");
|
|
3200
|
+
}
|
|
3201
|
+
/**
|
|
3202
|
+
* Reads data from a texture into an ArrayBuffer.
|
|
3203
|
+
* @returns An ArrayBuffer containing the texture data.
|
|
3204
|
+
*
|
|
3205
|
+
* @note The memory layout of the texture data is determined by the texture format and dimensions.
|
|
3206
|
+
* @note The application can call Texture.computeMemoryLayout() to compute the layout.
|
|
3207
|
+
* @deprecated Use Texture.readBuffer() with an explicit destination buffer, or DynamicTexture.readAsync() for convenience readback.
|
|
3208
|
+
*/
|
|
3209
|
+
readDataAsync(options) {
|
|
3210
|
+
throw new Error("readBuffer not implemented");
|
|
3211
|
+
}
|
|
3212
|
+
/**
|
|
3213
|
+
* Writes a GPU Buffer into a texture.
|
|
3214
|
+
*
|
|
3215
|
+
* @param buffer - Source GPU buffer.
|
|
3216
|
+
* @param options - Destination subresource, extent, and source layout options.
|
|
3217
|
+
* @note The memory layout of the texture data is determined by the texture format and dimensions.
|
|
3218
|
+
* @note The application can call Texture.computeMemoryLayout() to compute the backend-aligned layout.
|
|
3219
|
+
* @note On WebGPU this corresponds to a buffer-to-texture copy and uses buffer-copy alignment rules.
|
|
3220
|
+
* @note On WebGL, luma.gl emulates the same destination and layout semantics.
|
|
3221
|
+
*/
|
|
3222
|
+
writeBuffer(buffer, options) {
|
|
3223
|
+
throw new Error("readBuffer not implemented");
|
|
3224
|
+
}
|
|
3225
|
+
/**
|
|
3226
|
+
* Writes an array buffer into a texture.
|
|
3227
|
+
*
|
|
3228
|
+
* @param data - Source texel data.
|
|
3229
|
+
* @param options - Destination subresource, extent, and source layout options.
|
|
3230
|
+
* @note If `bytesPerRow` and `rowsPerImage` are omitted, luma.gl computes a tightly packed CPU-memory layout for the requested region.
|
|
3231
|
+
* @note On WebGPU this corresponds to `GPUQueue.writeTexture()` and does not implicitly pad rows to 256 bytes.
|
|
3232
|
+
* @note On WebGL, padded CPU data is supported via the same `bytesPerRow` and `rowsPerImage` options.
|
|
3233
|
+
*/
|
|
3234
|
+
writeData(data, options) {
|
|
3235
|
+
throw new Error("readBuffer not implemented");
|
|
3236
|
+
}
|
|
3237
|
+
// IMPLEMENTATION SPECIFIC
|
|
3238
|
+
/**
|
|
3239
|
+
* WebGL can read data synchronously.
|
|
3240
|
+
* @note While it is convenient, the performance penalty is very significant
|
|
3241
|
+
*/
|
|
3242
|
+
readDataSyncWebGL(options) {
|
|
3243
|
+
throw new Error("readDataSyncWebGL not available");
|
|
3244
|
+
}
|
|
3245
|
+
/** Generate mipmaps (WebGL only) */
|
|
3246
|
+
generateMipmapsWebGL() {
|
|
3247
|
+
throw new Error("generateMipmapsWebGL not available");
|
|
3248
|
+
}
|
|
3249
|
+
// HELPERS
|
|
2372
3250
|
/** Ensure we have integer coordinates */
|
|
2373
3251
|
static normalizeProps(device, props) {
|
|
2374
3252
|
const newProps = { ...props };
|
|
@@ -2381,7 +3259,6 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2381
3259
|
}
|
|
2382
3260
|
return newProps;
|
|
2383
3261
|
}
|
|
2384
|
-
// HELPERS
|
|
2385
3262
|
/** Initialize texture with supplied props */
|
|
2386
3263
|
// eslint-disable-next-line max-statements
|
|
2387
3264
|
_initializeData(data) {
|
|
@@ -2415,23 +3292,166 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2415
3292
|
}
|
|
2416
3293
|
}
|
|
2417
3294
|
_normalizeCopyImageDataOptions(options_) {
|
|
2418
|
-
const {
|
|
2419
|
-
const options = {
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
}
|
|
2424
|
-
options.bytesPerRow = options_.bytesPerRow || width * (info.bytesPerPixel || 4);
|
|
2425
|
-
options.rowsPerImage = options_.rowsPerImage || height;
|
|
2426
|
-
return options;
|
|
3295
|
+
const { data, depth, ...writeOptions } = options_;
|
|
3296
|
+
const options = this._normalizeTextureWriteOptions({
|
|
3297
|
+
...writeOptions,
|
|
3298
|
+
depthOrArrayLayers: writeOptions.depthOrArrayLayers ?? depth
|
|
3299
|
+
});
|
|
3300
|
+
return { data, depth: options.depthOrArrayLayers, ...options };
|
|
2427
3301
|
}
|
|
2428
3302
|
_normalizeCopyExternalImageOptions(options_) {
|
|
3303
|
+
const optionsWithoutUndefined = _Texture._omitUndefined(options_);
|
|
3304
|
+
const mipLevel = optionsWithoutUndefined.mipLevel ?? 0;
|
|
3305
|
+
const mipLevelSize = this._getMipLevelSize(mipLevel);
|
|
2429
3306
|
const size = this.device.getExternalImageSize(options_.image);
|
|
2430
|
-
const options = {
|
|
2431
|
-
|
|
2432
|
-
|
|
3307
|
+
const options = {
|
|
3308
|
+
..._Texture.defaultCopyExternalImageOptions,
|
|
3309
|
+
...mipLevelSize,
|
|
3310
|
+
...size,
|
|
3311
|
+
...optionsWithoutUndefined
|
|
3312
|
+
};
|
|
3313
|
+
options.width = Math.min(options.width, mipLevelSize.width - options.x);
|
|
3314
|
+
options.height = Math.min(options.height, mipLevelSize.height - options.y);
|
|
3315
|
+
options.depth = Math.min(options.depth, mipLevelSize.depthOrArrayLayers - options.z);
|
|
3316
|
+
return options;
|
|
3317
|
+
}
|
|
3318
|
+
_normalizeTextureReadOptions(options_) {
|
|
3319
|
+
const optionsWithoutUndefined = _Texture._omitUndefined(options_);
|
|
3320
|
+
const mipLevel = optionsWithoutUndefined.mipLevel ?? 0;
|
|
3321
|
+
const mipLevelSize = this._getMipLevelSize(mipLevel);
|
|
3322
|
+
const options = {
|
|
3323
|
+
..._Texture.defaultTextureReadOptions,
|
|
3324
|
+
...mipLevelSize,
|
|
3325
|
+
...optionsWithoutUndefined
|
|
3326
|
+
};
|
|
3327
|
+
options.width = Math.min(options.width, mipLevelSize.width - options.x);
|
|
3328
|
+
options.height = Math.min(options.height, mipLevelSize.height - options.y);
|
|
3329
|
+
options.depthOrArrayLayers = Math.min(
|
|
3330
|
+
options.depthOrArrayLayers,
|
|
3331
|
+
mipLevelSize.depthOrArrayLayers - options.z
|
|
3332
|
+
);
|
|
2433
3333
|
return options;
|
|
2434
3334
|
}
|
|
3335
|
+
/**
|
|
3336
|
+
* Normalizes a texture read request and validates the color-only readback contract used by the
|
|
3337
|
+
* current texture read APIs. Supported dimensions are `2d`, `cube`, `cube-array`,
|
|
3338
|
+
* `2d-array`, and `3d`.
|
|
3339
|
+
*
|
|
3340
|
+
* @throws if the texture format, aspect, or dimension is not supported by the first-pass
|
|
3341
|
+
* color-read implementation.
|
|
3342
|
+
*/
|
|
3343
|
+
_getSupportedColorReadOptions(options_) {
|
|
3344
|
+
const options = this._normalizeTextureReadOptions(options_);
|
|
3345
|
+
const formatInfo = textureFormatDecoder.getInfo(this.format);
|
|
3346
|
+
this._validateColorReadAspect(options);
|
|
3347
|
+
this._validateColorReadFormat(formatInfo);
|
|
3348
|
+
switch (this.dimension) {
|
|
3349
|
+
case "2d":
|
|
3350
|
+
case "cube":
|
|
3351
|
+
case "cube-array":
|
|
3352
|
+
case "2d-array":
|
|
3353
|
+
case "3d":
|
|
3354
|
+
return options;
|
|
3355
|
+
default:
|
|
3356
|
+
throw new Error(`${this} color readback does not support ${this.dimension} textures`);
|
|
3357
|
+
}
|
|
3358
|
+
}
|
|
3359
|
+
/** Validates that a read request targets the full color aspect of the texture. */
|
|
3360
|
+
_validateColorReadAspect(options) {
|
|
3361
|
+
if (options.aspect !== "all") {
|
|
3362
|
+
throw new Error(`${this} color readback only supports aspect 'all'`);
|
|
3363
|
+
}
|
|
3364
|
+
}
|
|
3365
|
+
/** Validates that a read request targets an uncompressed color-renderable texture format. */
|
|
3366
|
+
_validateColorReadFormat(formatInfo) {
|
|
3367
|
+
if (formatInfo.compressed) {
|
|
3368
|
+
throw new Error(
|
|
3369
|
+
`${this} color readback does not support compressed formats (${this.format})`
|
|
3370
|
+
);
|
|
3371
|
+
}
|
|
3372
|
+
switch (formatInfo.attachment) {
|
|
3373
|
+
case "color":
|
|
3374
|
+
return;
|
|
3375
|
+
case "depth":
|
|
3376
|
+
throw new Error(`${this} color readback does not support depth formats (${this.format})`);
|
|
3377
|
+
case "stencil":
|
|
3378
|
+
throw new Error(`${this} color readback does not support stencil formats (${this.format})`);
|
|
3379
|
+
case "depth-stencil":
|
|
3380
|
+
throw new Error(
|
|
3381
|
+
`${this} color readback does not support depth-stencil formats (${this.format})`
|
|
3382
|
+
);
|
|
3383
|
+
default:
|
|
3384
|
+
throw new Error(`${this} color readback does not support format ${this.format}`);
|
|
3385
|
+
}
|
|
3386
|
+
}
|
|
3387
|
+
_normalizeTextureWriteOptions(options_) {
|
|
3388
|
+
const optionsWithoutUndefined = _Texture._omitUndefined(options_);
|
|
3389
|
+
const mipLevel = optionsWithoutUndefined.mipLevel ?? 0;
|
|
3390
|
+
const mipLevelSize = this._getMipLevelSize(mipLevel);
|
|
3391
|
+
const options = {
|
|
3392
|
+
..._Texture.defaultTextureWriteOptions,
|
|
3393
|
+
...mipLevelSize,
|
|
3394
|
+
...optionsWithoutUndefined
|
|
3395
|
+
};
|
|
3396
|
+
options.width = Math.min(options.width, mipLevelSize.width - options.x);
|
|
3397
|
+
options.height = Math.min(options.height, mipLevelSize.height - options.y);
|
|
3398
|
+
options.depthOrArrayLayers = Math.min(
|
|
3399
|
+
options.depthOrArrayLayers,
|
|
3400
|
+
mipLevelSize.depthOrArrayLayers - options.z
|
|
3401
|
+
);
|
|
3402
|
+
const layout = textureFormatDecoder.computeMemoryLayout({
|
|
3403
|
+
format: this.format,
|
|
3404
|
+
width: options.width,
|
|
3405
|
+
height: options.height,
|
|
3406
|
+
depth: options.depthOrArrayLayers,
|
|
3407
|
+
byteAlignment: this.byteAlignment
|
|
3408
|
+
});
|
|
3409
|
+
const minimumBytesPerRow = layout.bytesPerPixel * options.width;
|
|
3410
|
+
options.bytesPerRow = optionsWithoutUndefined.bytesPerRow ?? layout.bytesPerRow;
|
|
3411
|
+
options.rowsPerImage = optionsWithoutUndefined.rowsPerImage ?? options.height;
|
|
3412
|
+
if (options.bytesPerRow < minimumBytesPerRow) {
|
|
3413
|
+
throw new Error(
|
|
3414
|
+
`bytesPerRow (${options.bytesPerRow}) must be at least ${minimumBytesPerRow} for ${this.format}`
|
|
3415
|
+
);
|
|
3416
|
+
}
|
|
3417
|
+
if (options.rowsPerImage < options.height) {
|
|
3418
|
+
throw new Error(
|
|
3419
|
+
`rowsPerImage (${options.rowsPerImage}) must be at least ${options.height} for ${this.format}`
|
|
3420
|
+
);
|
|
3421
|
+
}
|
|
3422
|
+
const bytesPerPixel = this.device.getTextureFormatInfo(this.format).bytesPerPixel;
|
|
3423
|
+
if (bytesPerPixel && options.bytesPerRow % bytesPerPixel !== 0) {
|
|
3424
|
+
throw new Error(
|
|
3425
|
+
`bytesPerRow (${options.bytesPerRow}) must be a multiple of bytesPerPixel (${bytesPerPixel}) for ${this.format}`
|
|
3426
|
+
);
|
|
3427
|
+
}
|
|
3428
|
+
return options;
|
|
3429
|
+
}
|
|
3430
|
+
_getMipLevelSize(mipLevel) {
|
|
3431
|
+
const width = Math.max(1, this.width >> mipLevel);
|
|
3432
|
+
const height = this.baseDimension === "1d" ? 1 : Math.max(1, this.height >> mipLevel);
|
|
3433
|
+
const depthOrArrayLayers = this.dimension === "3d" ? Math.max(1, this.depth >> mipLevel) : this.depth;
|
|
3434
|
+
return { width, height, depthOrArrayLayers };
|
|
3435
|
+
}
|
|
3436
|
+
getAllocatedByteLength() {
|
|
3437
|
+
let allocatedByteLength = 0;
|
|
3438
|
+
for (let mipLevel = 0; mipLevel < this.mipLevels; mipLevel++) {
|
|
3439
|
+
const { width, height, depthOrArrayLayers } = this._getMipLevelSize(mipLevel);
|
|
3440
|
+
allocatedByteLength += textureFormatDecoder.computeMemoryLayout({
|
|
3441
|
+
format: this.format,
|
|
3442
|
+
width,
|
|
3443
|
+
height,
|
|
3444
|
+
depth: depthOrArrayLayers,
|
|
3445
|
+
byteAlignment: 1
|
|
3446
|
+
}).byteLength;
|
|
3447
|
+
}
|
|
3448
|
+
return allocatedByteLength * this.samples;
|
|
3449
|
+
}
|
|
3450
|
+
static _omitUndefined(options) {
|
|
3451
|
+
return Object.fromEntries(
|
|
3452
|
+
Object.entries(options).filter(([, value]) => value !== void 0)
|
|
3453
|
+
);
|
|
3454
|
+
}
|
|
2435
3455
|
};
|
|
2436
3456
|
var Texture = _Texture;
|
|
2437
3457
|
/** The texture can be bound for use as a sampled texture in a shader */
|
|
@@ -2448,13 +3468,12 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2448
3468
|
__publicField(Texture, "TEXTURE", 4);
|
|
2449
3469
|
/** @deprecated Use Texture.RENDER */
|
|
2450
3470
|
__publicField(Texture, "RENDER_ATTACHMENT", 16);
|
|
2451
|
-
/** Default options */
|
|
2452
3471
|
__publicField(Texture, "defaultProps", {
|
|
2453
3472
|
...Resource.defaultProps,
|
|
2454
3473
|
data: null,
|
|
2455
3474
|
dimension: "2d",
|
|
2456
3475
|
format: "rgba8unorm",
|
|
2457
|
-
usage: _Texture.
|
|
3476
|
+
usage: _Texture.SAMPLE | _Texture.RENDER | _Texture.COPY_DST,
|
|
2458
3477
|
width: void 0,
|
|
2459
3478
|
height: void 0,
|
|
2460
3479
|
depth: 1,
|
|
@@ -2468,6 +3487,10 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2468
3487
|
byteOffset: 0,
|
|
2469
3488
|
bytesPerRow: void 0,
|
|
2470
3489
|
rowsPerImage: void 0,
|
|
3490
|
+
width: void 0,
|
|
3491
|
+
height: void 0,
|
|
3492
|
+
depthOrArrayLayers: void 0,
|
|
3493
|
+
depth: 1,
|
|
2471
3494
|
mipLevel: 0,
|
|
2472
3495
|
x: 0,
|
|
2473
3496
|
y: 0,
|
|
@@ -2491,6 +3514,29 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2491
3514
|
premultipliedAlpha: false,
|
|
2492
3515
|
flipY: false
|
|
2493
3516
|
});
|
|
3517
|
+
__publicField(Texture, "defaultTextureReadOptions", {
|
|
3518
|
+
x: 0,
|
|
3519
|
+
y: 0,
|
|
3520
|
+
z: 0,
|
|
3521
|
+
width: void 0,
|
|
3522
|
+
height: void 0,
|
|
3523
|
+
depthOrArrayLayers: 1,
|
|
3524
|
+
mipLevel: 0,
|
|
3525
|
+
aspect: "all"
|
|
3526
|
+
});
|
|
3527
|
+
__publicField(Texture, "defaultTextureWriteOptions", {
|
|
3528
|
+
byteOffset: 0,
|
|
3529
|
+
bytesPerRow: void 0,
|
|
3530
|
+
rowsPerImage: void 0,
|
|
3531
|
+
x: 0,
|
|
3532
|
+
y: 0,
|
|
3533
|
+
z: 0,
|
|
3534
|
+
width: void 0,
|
|
3535
|
+
height: void 0,
|
|
3536
|
+
depthOrArrayLayers: 1,
|
|
3537
|
+
mipLevel: 0,
|
|
3538
|
+
aspect: "all"
|
|
3539
|
+
});
|
|
2494
3540
|
|
|
2495
3541
|
// src/adapter/resources/texture-view.ts
|
|
2496
3542
|
var _TextureView = class extends Resource {
|
|
@@ -2537,24 +3583,32 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2537
3583
|
const log2 = shaderLog.slice().sort((a, b) => a.lineNum - b.lineNum);
|
|
2538
3584
|
switch (options?.showSourceCode || "no") {
|
|
2539
3585
|
case "all":
|
|
2540
|
-
let
|
|
3586
|
+
let currentMessageIndex = 0;
|
|
2541
3587
|
for (let lineNum = 1; lineNum <= lines.length; lineNum++) {
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
formattedLog +=
|
|
3588
|
+
const line = lines[lineNum - 1];
|
|
3589
|
+
const currentMessage = log2[currentMessageIndex];
|
|
3590
|
+
if (line && currentMessage) {
|
|
3591
|
+
formattedLog += getNumberedLine(line, lineNum, options);
|
|
3592
|
+
}
|
|
3593
|
+
while (log2.length > currentMessageIndex && currentMessage.lineNum === lineNum) {
|
|
3594
|
+
const message = log2[currentMessageIndex++];
|
|
3595
|
+
if (message) {
|
|
3596
|
+
formattedLog += formatCompilerMessage(message, lines, message.lineNum, {
|
|
3597
|
+
...options,
|
|
3598
|
+
inlineSource: false
|
|
3599
|
+
});
|
|
3600
|
+
}
|
|
3601
|
+
}
|
|
3602
|
+
}
|
|
3603
|
+
while (log2.length > currentMessageIndex) {
|
|
3604
|
+
const message = log2[currentMessageIndex++];
|
|
3605
|
+
if (message) {
|
|
3606
|
+
formattedLog += formatCompilerMessage(message, [], 0, {
|
|
2546
3607
|
...options,
|
|
2547
3608
|
inlineSource: false
|
|
2548
3609
|
});
|
|
2549
3610
|
}
|
|
2550
3611
|
}
|
|
2551
|
-
while (log2.length > currentMessage) {
|
|
2552
|
-
const message = log2[currentMessage++];
|
|
2553
|
-
formattedLog += formatCompilerMessage(message, [], 0, {
|
|
2554
|
-
...options,
|
|
2555
|
-
inlineSource: false
|
|
2556
|
-
});
|
|
2557
|
-
}
|
|
2558
3612
|
return formattedLog;
|
|
2559
3613
|
case "issues":
|
|
2560
3614
|
case "no":
|
|
@@ -2576,8 +3630,8 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
2576
3630
|
|
|
2577
3631
|
`;
|
|
2578
3632
|
}
|
|
2579
|
-
const color = message.type === "error" ? "red" : "
|
|
2580
|
-
return options?.html ? `<div class='luma-compiler-log
|
|
3633
|
+
const color = message.type === "error" ? "red" : "orange";
|
|
3634
|
+
return options?.html ? `<div class='luma-compiler-log-${message.type}' style="color:${color};"><b> ${message.type.toUpperCase()}: ${message.message}</b></div>` : `${message.type.toUpperCase()}: ${message.message}`;
|
|
2581
3635
|
}
|
|
2582
3636
|
function getNumberedLines(lines, lineNum, options) {
|
|
2583
3637
|
let numberedLines = "";
|
|
@@ -2663,29 +3717,34 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
2663
3717
|
}
|
|
2664
3718
|
const shaderName = shaderId;
|
|
2665
3719
|
const shaderTitle = `${this.stage} shader "${shaderName}"`;
|
|
2666
|
-
|
|
3720
|
+
const htmlLog = formatCompilerLog(messages, this.source, { showSourceCode: "all", html: true });
|
|
2667
3721
|
const translatedSource = this.getTranslatedSource();
|
|
3722
|
+
const container = document.createElement("div");
|
|
3723
|
+
container.innerHTML = `<h1>Compilation error in ${shaderTitle}</h1>
|
|
3724
|
+
<div style="display:flex;position:fixed;top:10px;right:20px;gap:2px;">
|
|
3725
|
+
<button id="copy">Copy source</button><br/>
|
|
3726
|
+
<button id="close">Close</button>
|
|
3727
|
+
</div>
|
|
3728
|
+
<code><pre>${htmlLog}</pre></code>`;
|
|
2668
3729
|
if (translatedSource) {
|
|
2669
|
-
|
|
2670
|
-
}
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
button.
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
const dataURI = `data:text/plain,${encodeURIComponent(this.source)}`;
|
|
2688
|
-
navigator.clipboard.writeText(dataURI);
|
|
3730
|
+
container.innerHTML += `<br /><h1>Translated Source</h1><br /><br /><code><pre>${translatedSource}</pre></code>`;
|
|
3731
|
+
}
|
|
3732
|
+
container.style.top = "0";
|
|
3733
|
+
container.style.left = "0";
|
|
3734
|
+
container.style.background = "white";
|
|
3735
|
+
container.style.position = "fixed";
|
|
3736
|
+
container.style.zIndex = "9999";
|
|
3737
|
+
container.style.maxWidth = "100vw";
|
|
3738
|
+
container.style.maxHeight = "100vh";
|
|
3739
|
+
container.style.overflowY = "auto";
|
|
3740
|
+
document.body.appendChild(container);
|
|
3741
|
+
const error = container.querySelector(".luma-compiler-log-error");
|
|
3742
|
+
error?.scrollIntoView();
|
|
3743
|
+
container.querySelector("button#close").onclick = () => {
|
|
3744
|
+
container.remove();
|
|
3745
|
+
};
|
|
3746
|
+
container.querySelector("button#copy").onclick = () => {
|
|
3747
|
+
navigator.clipboard.writeText(this.source);
|
|
2689
3748
|
};
|
|
2690
3749
|
}
|
|
2691
3750
|
};
|
|
@@ -2705,7 +3764,7 @@ ${htmlLog}
|
|
|
2705
3764
|
function getShaderName(shader, defaultName = "unnamed") {
|
|
2706
3765
|
const SHADER_NAME_REGEXP = /#define[\s*]SHADER_NAME[\s*]([A-Za-z0-9_-]+)[\s*]/;
|
|
2707
3766
|
const match = SHADER_NAME_REGEXP.exec(shader);
|
|
2708
|
-
return match
|
|
3767
|
+
return match?.[1] ?? defaultName;
|
|
2709
3768
|
}
|
|
2710
3769
|
|
|
2711
3770
|
// src/adapter/resources/framebuffer.ts
|
|
@@ -2731,7 +3790,12 @@ ${htmlLog}
|
|
|
2731
3790
|
(colorAttachment) => colorAttachment.texture.clone(size)
|
|
2732
3791
|
);
|
|
2733
3792
|
const depthStencilAttachment = this.depthStencilAttachment && this.depthStencilAttachment.texture.clone(size);
|
|
2734
|
-
return this.device.createFramebuffer({
|
|
3793
|
+
return this.device.createFramebuffer({
|
|
3794
|
+
...this.props,
|
|
3795
|
+
...size,
|
|
3796
|
+
colorAttachments,
|
|
3797
|
+
depthStencilAttachment
|
|
3798
|
+
});
|
|
2735
3799
|
}
|
|
2736
3800
|
resize(size) {
|
|
2737
3801
|
let updateSize = !size;
|
|
@@ -2806,17 +3870,15 @@ ${htmlLog}
|
|
|
2806
3870
|
* and destroys existing textures if owned
|
|
2807
3871
|
*/
|
|
2808
3872
|
resizeAttachments(width, height) {
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
}
|
|
2819
|
-
}
|
|
3873
|
+
this.colorAttachments.forEach((colorAttachment, i) => {
|
|
3874
|
+
const resizedTexture = colorAttachment.texture.clone({
|
|
3875
|
+
width,
|
|
3876
|
+
height
|
|
3877
|
+
});
|
|
3878
|
+
this.destroyAttachedResource(colorAttachment);
|
|
3879
|
+
this.colorAttachments[i] = resizedTexture.view;
|
|
3880
|
+
this.attachResource(resizedTexture.view);
|
|
3881
|
+
});
|
|
2820
3882
|
if (this.depthStencilAttachment) {
|
|
2821
3883
|
const resizedTexture = this.depthStencilAttachment.texture.clone({
|
|
2822
3884
|
width,
|
|
@@ -2853,30 +3915,538 @@ ${htmlLog}
|
|
|
2853
3915
|
linkStatus = "pending";
|
|
2854
3916
|
/** The hash of the pipeline */
|
|
2855
3917
|
hash = "";
|
|
3918
|
+
/** Optional shared backend implementation */
|
|
3919
|
+
sharedRenderPipeline = null;
|
|
3920
|
+
/** Whether shader or pipeline compilation/linking is still in progress */
|
|
3921
|
+
get isPending() {
|
|
3922
|
+
return this.linkStatus === "pending" || this.vs.compilationStatus === "pending" || this.fs?.compilationStatus === "pending";
|
|
3923
|
+
}
|
|
3924
|
+
/** Whether shader or pipeline compilation/linking has failed */
|
|
3925
|
+
get isErrored() {
|
|
3926
|
+
return this.linkStatus === "error" || this.vs.compilationStatus === "error" || this.fs?.compilationStatus === "error";
|
|
3927
|
+
}
|
|
2856
3928
|
constructor(device, props) {
|
|
2857
3929
|
super(device, props, _RenderPipeline.defaultProps);
|
|
2858
3930
|
this.shaderLayout = this.props.shaderLayout;
|
|
2859
3931
|
this.bufferLayout = this.props.bufferLayout || [];
|
|
3932
|
+
this.sharedRenderPipeline = this.props._sharedRenderPipeline || null;
|
|
3933
|
+
}
|
|
3934
|
+
};
|
|
3935
|
+
var RenderPipeline = _RenderPipeline;
|
|
3936
|
+
__publicField(RenderPipeline, "defaultProps", {
|
|
3937
|
+
...Resource.defaultProps,
|
|
3938
|
+
vs: null,
|
|
3939
|
+
vertexEntryPoint: "vertexMain",
|
|
3940
|
+
vsConstants: {},
|
|
3941
|
+
fs: null,
|
|
3942
|
+
fragmentEntryPoint: "fragmentMain",
|
|
3943
|
+
fsConstants: {},
|
|
3944
|
+
shaderLayout: null,
|
|
3945
|
+
bufferLayout: [],
|
|
3946
|
+
topology: "triangle-list",
|
|
3947
|
+
colorAttachmentFormats: void 0,
|
|
3948
|
+
depthStencilAttachmentFormat: void 0,
|
|
3949
|
+
parameters: {},
|
|
3950
|
+
varyings: void 0,
|
|
3951
|
+
bufferMode: void 0,
|
|
3952
|
+
disableWarnings: false,
|
|
3953
|
+
_sharedRenderPipeline: void 0,
|
|
3954
|
+
bindings: void 0,
|
|
3955
|
+
bindGroups: void 0
|
|
3956
|
+
});
|
|
3957
|
+
|
|
3958
|
+
// src/adapter/resources/shared-render-pipeline.ts
|
|
3959
|
+
var SharedRenderPipeline = class extends Resource {
|
|
3960
|
+
get [Symbol.toStringTag]() {
|
|
3961
|
+
return "SharedRenderPipeline";
|
|
3962
|
+
}
|
|
3963
|
+
constructor(device, props) {
|
|
3964
|
+
super(device, props, {
|
|
3965
|
+
...Resource.defaultProps,
|
|
3966
|
+
handle: void 0,
|
|
3967
|
+
vs: void 0,
|
|
3968
|
+
fs: void 0,
|
|
3969
|
+
varyings: void 0,
|
|
3970
|
+
bufferMode: void 0
|
|
3971
|
+
});
|
|
3972
|
+
}
|
|
3973
|
+
};
|
|
3974
|
+
|
|
3975
|
+
// src/adapter/resources/compute-pipeline.ts
|
|
3976
|
+
var _ComputePipeline = class extends Resource {
|
|
3977
|
+
get [Symbol.toStringTag]() {
|
|
3978
|
+
return "ComputePipeline";
|
|
3979
|
+
}
|
|
3980
|
+
hash = "";
|
|
3981
|
+
/** The merged shader layout */
|
|
3982
|
+
shaderLayout;
|
|
3983
|
+
constructor(device, props) {
|
|
3984
|
+
super(device, props, _ComputePipeline.defaultProps);
|
|
3985
|
+
this.shaderLayout = props.shaderLayout;
|
|
3986
|
+
}
|
|
3987
|
+
};
|
|
3988
|
+
var ComputePipeline = _ComputePipeline;
|
|
3989
|
+
__publicField(ComputePipeline, "defaultProps", {
|
|
3990
|
+
...Resource.defaultProps,
|
|
3991
|
+
shader: void 0,
|
|
3992
|
+
entryPoint: void 0,
|
|
3993
|
+
constants: {},
|
|
3994
|
+
shaderLayout: void 0
|
|
3995
|
+
});
|
|
3996
|
+
|
|
3997
|
+
// src/factories/pipeline-factory.ts
|
|
3998
|
+
var _PipelineFactory = class {
|
|
3999
|
+
/** Get the singleton default pipeline factory for the specified device */
|
|
4000
|
+
static getDefaultPipelineFactory(device) {
|
|
4001
|
+
const moduleData = device.getModuleData("@luma.gl/core");
|
|
4002
|
+
moduleData.defaultPipelineFactory ||= new _PipelineFactory(device);
|
|
4003
|
+
return moduleData.defaultPipelineFactory;
|
|
4004
|
+
}
|
|
4005
|
+
device;
|
|
4006
|
+
_hashCounter = 0;
|
|
4007
|
+
_hashes = {};
|
|
4008
|
+
_renderPipelineCache = {};
|
|
4009
|
+
_computePipelineCache = {};
|
|
4010
|
+
_sharedRenderPipelineCache = {};
|
|
4011
|
+
get [Symbol.toStringTag]() {
|
|
4012
|
+
return "PipelineFactory";
|
|
4013
|
+
}
|
|
4014
|
+
toString() {
|
|
4015
|
+
return `PipelineFactory(${this.device.id})`;
|
|
4016
|
+
}
|
|
4017
|
+
constructor(device) {
|
|
4018
|
+
this.device = device;
|
|
4019
|
+
}
|
|
4020
|
+
/**
|
|
4021
|
+
* WebGL has two cache layers with different priorities:
|
|
4022
|
+
* - `_sharedRenderPipelineCache` owns `WEBGLSharedRenderPipeline` / `WebGLProgram` reuse.
|
|
4023
|
+
* - `_renderPipelineCache` owns `RenderPipeline` wrapper reuse.
|
|
4024
|
+
*
|
|
4025
|
+
* Shared WebGL program reuse is the hard requirement. Wrapper reuse is beneficial,
|
|
4026
|
+
* but wrapper cache misses are acceptable if that keeps the cache logic simple and
|
|
4027
|
+
* prevents incorrect cache hits.
|
|
4028
|
+
*
|
|
4029
|
+
* In particular, wrapper hash logic must never force program creation or linked-program
|
|
4030
|
+
* introspection just to decide whether a shared WebGL program can be reused.
|
|
4031
|
+
*/
|
|
4032
|
+
/** Return a RenderPipeline matching supplied props. Reuses an equivalent pipeline if already created. */
|
|
4033
|
+
createRenderPipeline(props) {
|
|
4034
|
+
if (!this.device.props._cachePipelines) {
|
|
4035
|
+
return this.device.createRenderPipeline(props);
|
|
4036
|
+
}
|
|
4037
|
+
const allProps = { ...RenderPipeline.defaultProps, ...props };
|
|
4038
|
+
const cache = this._renderPipelineCache;
|
|
4039
|
+
const hash = this._hashRenderPipeline(allProps);
|
|
4040
|
+
let pipeline = cache[hash]?.resource;
|
|
4041
|
+
if (!pipeline) {
|
|
4042
|
+
const sharedRenderPipeline = this.device.type === "webgl" && this.device.props._sharePipelines ? this.createSharedRenderPipeline(allProps) : void 0;
|
|
4043
|
+
pipeline = this.device.createRenderPipeline({
|
|
4044
|
+
...allProps,
|
|
4045
|
+
id: allProps.id ? `${allProps.id}-cached` : uid("unnamed-cached"),
|
|
4046
|
+
_sharedRenderPipeline: sharedRenderPipeline
|
|
4047
|
+
});
|
|
4048
|
+
pipeline.hash = hash;
|
|
4049
|
+
cache[hash] = { resource: pipeline, useCount: 1 };
|
|
4050
|
+
if (this.device.props.debugFactories) {
|
|
4051
|
+
log.log(3, `${this}: ${pipeline} created, count=${cache[hash].useCount}`)();
|
|
4052
|
+
}
|
|
4053
|
+
} else {
|
|
4054
|
+
cache[hash].useCount++;
|
|
4055
|
+
if (this.device.props.debugFactories) {
|
|
4056
|
+
log.log(
|
|
4057
|
+
3,
|
|
4058
|
+
`${this}: ${cache[hash].resource} reused, count=${cache[hash].useCount}, (id=${props.id})`
|
|
4059
|
+
)();
|
|
4060
|
+
}
|
|
4061
|
+
}
|
|
4062
|
+
return pipeline;
|
|
4063
|
+
}
|
|
4064
|
+
/** Return a ComputePipeline matching supplied props. Reuses an equivalent pipeline if already created. */
|
|
4065
|
+
createComputePipeline(props) {
|
|
4066
|
+
if (!this.device.props._cachePipelines) {
|
|
4067
|
+
return this.device.createComputePipeline(props);
|
|
4068
|
+
}
|
|
4069
|
+
const allProps = { ...ComputePipeline.defaultProps, ...props };
|
|
4070
|
+
const cache = this._computePipelineCache;
|
|
4071
|
+
const hash = this._hashComputePipeline(allProps);
|
|
4072
|
+
let pipeline = cache[hash]?.resource;
|
|
4073
|
+
if (!pipeline) {
|
|
4074
|
+
pipeline = this.device.createComputePipeline({
|
|
4075
|
+
...allProps,
|
|
4076
|
+
id: allProps.id ? `${allProps.id}-cached` : void 0
|
|
4077
|
+
});
|
|
4078
|
+
pipeline.hash = hash;
|
|
4079
|
+
cache[hash] = { resource: pipeline, useCount: 1 };
|
|
4080
|
+
if (this.device.props.debugFactories) {
|
|
4081
|
+
log.log(3, `${this}: ${pipeline} created, count=${cache[hash].useCount}`)();
|
|
4082
|
+
}
|
|
4083
|
+
} else {
|
|
4084
|
+
cache[hash].useCount++;
|
|
4085
|
+
if (this.device.props.debugFactories) {
|
|
4086
|
+
log.log(
|
|
4087
|
+
3,
|
|
4088
|
+
`${this}: ${cache[hash].resource} reused, count=${cache[hash].useCount}, (id=${props.id})`
|
|
4089
|
+
)();
|
|
4090
|
+
}
|
|
4091
|
+
}
|
|
4092
|
+
return pipeline;
|
|
4093
|
+
}
|
|
4094
|
+
release(pipeline) {
|
|
4095
|
+
if (!this.device.props._cachePipelines) {
|
|
4096
|
+
pipeline.destroy();
|
|
4097
|
+
return;
|
|
4098
|
+
}
|
|
4099
|
+
const cache = this._getCache(pipeline);
|
|
4100
|
+
const hash = pipeline.hash;
|
|
4101
|
+
cache[hash].useCount--;
|
|
4102
|
+
if (cache[hash].useCount === 0) {
|
|
4103
|
+
this._destroyPipeline(pipeline);
|
|
4104
|
+
if (this.device.props.debugFactories) {
|
|
4105
|
+
log.log(3, `${this}: ${pipeline} released and destroyed`)();
|
|
4106
|
+
}
|
|
4107
|
+
} else if (cache[hash].useCount < 0) {
|
|
4108
|
+
log.error(`${this}: ${pipeline} released, useCount < 0, resetting`)();
|
|
4109
|
+
cache[hash].useCount = 0;
|
|
4110
|
+
} else if (this.device.props.debugFactories) {
|
|
4111
|
+
log.log(3, `${this}: ${pipeline} released, count=${cache[hash].useCount}`)();
|
|
4112
|
+
}
|
|
4113
|
+
}
|
|
4114
|
+
createSharedRenderPipeline(props) {
|
|
4115
|
+
const sharedPipelineHash = this._hashSharedRenderPipeline(props);
|
|
4116
|
+
let sharedCacheItem = this._sharedRenderPipelineCache[sharedPipelineHash];
|
|
4117
|
+
if (!sharedCacheItem) {
|
|
4118
|
+
const sharedRenderPipeline = this.device._createSharedRenderPipelineWebGL(props);
|
|
4119
|
+
sharedCacheItem = { resource: sharedRenderPipeline, useCount: 0 };
|
|
4120
|
+
this._sharedRenderPipelineCache[sharedPipelineHash] = sharedCacheItem;
|
|
4121
|
+
}
|
|
4122
|
+
sharedCacheItem.useCount++;
|
|
4123
|
+
return sharedCacheItem.resource;
|
|
4124
|
+
}
|
|
4125
|
+
releaseSharedRenderPipeline(pipeline) {
|
|
4126
|
+
if (!pipeline.sharedRenderPipeline) {
|
|
4127
|
+
return;
|
|
4128
|
+
}
|
|
4129
|
+
const sharedPipelineHash = this._hashSharedRenderPipeline(pipeline.sharedRenderPipeline.props);
|
|
4130
|
+
const sharedCacheItem = this._sharedRenderPipelineCache[sharedPipelineHash];
|
|
4131
|
+
if (!sharedCacheItem) {
|
|
4132
|
+
return;
|
|
4133
|
+
}
|
|
4134
|
+
sharedCacheItem.useCount--;
|
|
4135
|
+
if (sharedCacheItem.useCount === 0) {
|
|
4136
|
+
sharedCacheItem.resource.destroy();
|
|
4137
|
+
delete this._sharedRenderPipelineCache[sharedPipelineHash];
|
|
4138
|
+
}
|
|
4139
|
+
}
|
|
4140
|
+
// PRIVATE
|
|
4141
|
+
/** Destroy a cached pipeline, removing it from the cache if configured to do so. */
|
|
4142
|
+
_destroyPipeline(pipeline) {
|
|
4143
|
+
const cache = this._getCache(pipeline);
|
|
4144
|
+
if (!this.device.props._destroyPipelines) {
|
|
4145
|
+
return false;
|
|
4146
|
+
}
|
|
4147
|
+
delete cache[pipeline.hash];
|
|
4148
|
+
pipeline.destroy();
|
|
4149
|
+
if (pipeline instanceof RenderPipeline) {
|
|
4150
|
+
this.releaseSharedRenderPipeline(pipeline);
|
|
4151
|
+
}
|
|
4152
|
+
return true;
|
|
4153
|
+
}
|
|
4154
|
+
/** Get the appropriate cache for the type of pipeline */
|
|
4155
|
+
_getCache(pipeline) {
|
|
4156
|
+
let cache;
|
|
4157
|
+
if (pipeline instanceof ComputePipeline) {
|
|
4158
|
+
cache = this._computePipelineCache;
|
|
4159
|
+
}
|
|
4160
|
+
if (pipeline instanceof RenderPipeline) {
|
|
4161
|
+
cache = this._renderPipelineCache;
|
|
4162
|
+
}
|
|
4163
|
+
if (!cache) {
|
|
4164
|
+
throw new Error(`${this}`);
|
|
4165
|
+
}
|
|
4166
|
+
if (!cache[pipeline.hash]) {
|
|
4167
|
+
throw new Error(`${this}: ${pipeline} matched incorrect entry`);
|
|
4168
|
+
}
|
|
4169
|
+
return cache;
|
|
4170
|
+
}
|
|
4171
|
+
/** Calculate a hash based on all the inputs for a compute pipeline */
|
|
4172
|
+
_hashComputePipeline(props) {
|
|
4173
|
+
const { type } = this.device;
|
|
4174
|
+
const shaderHash = this._getHash(props.shader.source);
|
|
4175
|
+
const shaderLayoutHash = this._getHash(JSON.stringify(props.shaderLayout));
|
|
4176
|
+
return `${type}/C/${shaderHash}SL${shaderLayoutHash}`;
|
|
4177
|
+
}
|
|
4178
|
+
/** Calculate a hash based on all the inputs for a render pipeline */
|
|
4179
|
+
_hashRenderPipeline(props) {
|
|
4180
|
+
const vsHash = props.vs ? this._getHash(props.vs.source) : 0;
|
|
4181
|
+
const fsHash = props.fs ? this._getHash(props.fs.source) : 0;
|
|
4182
|
+
const varyingHash = this._getWebGLVaryingHash(props);
|
|
4183
|
+
const shaderLayoutHash = this._getHash(JSON.stringify(props.shaderLayout));
|
|
4184
|
+
const bufferLayoutHash = this._getHash(JSON.stringify(props.bufferLayout));
|
|
4185
|
+
const { type } = this.device;
|
|
4186
|
+
switch (type) {
|
|
4187
|
+
case "webgl":
|
|
4188
|
+
const webglParameterHash = this._getHash(JSON.stringify(props.parameters));
|
|
4189
|
+
return `${type}/R/${vsHash}/${fsHash}V${varyingHash}T${props.topology}P${webglParameterHash}SL${shaderLayoutHash}BL${bufferLayoutHash}`;
|
|
4190
|
+
case "webgpu":
|
|
4191
|
+
default:
|
|
4192
|
+
const entryPointHash = this._getHash(
|
|
4193
|
+
JSON.stringify({
|
|
4194
|
+
vertexEntryPoint: props.vertexEntryPoint,
|
|
4195
|
+
fragmentEntryPoint: props.fragmentEntryPoint
|
|
4196
|
+
})
|
|
4197
|
+
);
|
|
4198
|
+
const parameterHash = this._getHash(JSON.stringify(props.parameters));
|
|
4199
|
+
const attachmentHash = this._getWebGPUAttachmentHash(props);
|
|
4200
|
+
return `${type}/R/${vsHash}/${fsHash}V${varyingHash}T${props.topology}EP${entryPointHash}P${parameterHash}SL${shaderLayoutHash}BL${bufferLayoutHash}A${attachmentHash}`;
|
|
4201
|
+
}
|
|
4202
|
+
}
|
|
4203
|
+
// This is the only gate for shared `WebGLProgram` reuse.
|
|
4204
|
+
// Only include inputs that affect program linking or transform-feedback linkage.
|
|
4205
|
+
// Wrapper-only concerns such as topology, parameters, attachment formats and layout
|
|
4206
|
+
// overrides must not be added here.
|
|
4207
|
+
_hashSharedRenderPipeline(props) {
|
|
4208
|
+
const vsHash = props.vs ? this._getHash(props.vs.source) : 0;
|
|
4209
|
+
const fsHash = props.fs ? this._getHash(props.fs.source) : 0;
|
|
4210
|
+
const varyingHash = this._getWebGLVaryingHash(props);
|
|
4211
|
+
return `webgl/S/${vsHash}/${fsHash}V${varyingHash}`;
|
|
4212
|
+
}
|
|
4213
|
+
_getHash(key) {
|
|
4214
|
+
if (this._hashes[key] === void 0) {
|
|
4215
|
+
this._hashes[key] = this._hashCounter++;
|
|
4216
|
+
}
|
|
4217
|
+
return this._hashes[key];
|
|
4218
|
+
}
|
|
4219
|
+
_getWebGLVaryingHash(props) {
|
|
4220
|
+
const { varyings = [], bufferMode = null } = props;
|
|
4221
|
+
return this._getHash(JSON.stringify({ varyings, bufferMode }));
|
|
4222
|
+
}
|
|
4223
|
+
_getWebGPUAttachmentHash(props) {
|
|
4224
|
+
const colorAttachmentFormats = props.colorAttachmentFormats ?? [
|
|
4225
|
+
this.device.preferredColorFormat
|
|
4226
|
+
];
|
|
4227
|
+
const depthStencilAttachmentFormat = props.parameters?.depthWriteEnabled ? props.depthStencilAttachmentFormat || this.device.preferredDepthFormat : null;
|
|
4228
|
+
return this._getHash(
|
|
4229
|
+
JSON.stringify({
|
|
4230
|
+
colorAttachmentFormats,
|
|
4231
|
+
depthStencilAttachmentFormat
|
|
4232
|
+
})
|
|
4233
|
+
);
|
|
4234
|
+
}
|
|
4235
|
+
};
|
|
4236
|
+
var PipelineFactory = _PipelineFactory;
|
|
4237
|
+
__publicField(PipelineFactory, "defaultProps", { ...RenderPipeline.defaultProps });
|
|
4238
|
+
|
|
4239
|
+
// src/factories/shader-factory.ts
|
|
4240
|
+
var _ShaderFactory = class {
|
|
4241
|
+
/** Returns the default ShaderFactory for the given {@link Device}, creating one if necessary. */
|
|
4242
|
+
static getDefaultShaderFactory(device) {
|
|
4243
|
+
const moduleData = device.getModuleData("@luma.gl/core");
|
|
4244
|
+
moduleData.defaultShaderFactory ||= new _ShaderFactory(device);
|
|
4245
|
+
return moduleData.defaultShaderFactory;
|
|
4246
|
+
}
|
|
4247
|
+
device;
|
|
4248
|
+
_cache = {};
|
|
4249
|
+
get [Symbol.toStringTag]() {
|
|
4250
|
+
return "ShaderFactory";
|
|
4251
|
+
}
|
|
4252
|
+
toString() {
|
|
4253
|
+
return `${this[Symbol.toStringTag]}(${this.device.id})`;
|
|
4254
|
+
}
|
|
4255
|
+
/** @internal */
|
|
4256
|
+
constructor(device) {
|
|
4257
|
+
this.device = device;
|
|
4258
|
+
}
|
|
4259
|
+
/** Requests a {@link Shader} from the cache, creating a new Shader only if necessary. */
|
|
4260
|
+
createShader(props) {
|
|
4261
|
+
if (!this.device.props._cacheShaders) {
|
|
4262
|
+
return this.device.createShader(props);
|
|
4263
|
+
}
|
|
4264
|
+
const key = this._hashShader(props);
|
|
4265
|
+
let cacheEntry = this._cache[key];
|
|
4266
|
+
if (!cacheEntry) {
|
|
4267
|
+
const resource = this.device.createShader({
|
|
4268
|
+
...props,
|
|
4269
|
+
id: props.id ? `${props.id}-cached` : void 0
|
|
4270
|
+
});
|
|
4271
|
+
this._cache[key] = cacheEntry = { resource, useCount: 1 };
|
|
4272
|
+
if (this.device.props.debugFactories) {
|
|
4273
|
+
log.log(3, `${this}: Created new shader ${resource.id}`)();
|
|
4274
|
+
}
|
|
4275
|
+
} else {
|
|
4276
|
+
cacheEntry.useCount++;
|
|
4277
|
+
if (this.device.props.debugFactories) {
|
|
4278
|
+
log.log(
|
|
4279
|
+
3,
|
|
4280
|
+
`${this}: Reusing shader ${cacheEntry.resource.id} count=${cacheEntry.useCount}`
|
|
4281
|
+
)();
|
|
4282
|
+
}
|
|
4283
|
+
}
|
|
4284
|
+
return cacheEntry.resource;
|
|
4285
|
+
}
|
|
4286
|
+
/** Releases a previously-requested {@link Shader}, destroying it if no users remain. */
|
|
4287
|
+
release(shader) {
|
|
4288
|
+
if (!this.device.props._cacheShaders) {
|
|
4289
|
+
shader.destroy();
|
|
4290
|
+
return;
|
|
4291
|
+
}
|
|
4292
|
+
const key = this._hashShader(shader);
|
|
4293
|
+
const cacheEntry = this._cache[key];
|
|
4294
|
+
if (cacheEntry) {
|
|
4295
|
+
cacheEntry.useCount--;
|
|
4296
|
+
if (cacheEntry.useCount === 0) {
|
|
4297
|
+
if (this.device.props._destroyShaders) {
|
|
4298
|
+
delete this._cache[key];
|
|
4299
|
+
cacheEntry.resource.destroy();
|
|
4300
|
+
if (this.device.props.debugFactories) {
|
|
4301
|
+
log.log(3, `${this}: Releasing shader ${shader.id}, destroyed`)();
|
|
4302
|
+
}
|
|
4303
|
+
}
|
|
4304
|
+
} else if (cacheEntry.useCount < 0) {
|
|
4305
|
+
throw new Error(`ShaderFactory: Shader ${shader.id} released too many times`);
|
|
4306
|
+
} else if (this.device.props.debugFactories) {
|
|
4307
|
+
log.log(3, `${this}: Releasing shader ${shader.id} count=${cacheEntry.useCount}`)();
|
|
4308
|
+
}
|
|
4309
|
+
}
|
|
4310
|
+
}
|
|
4311
|
+
// PRIVATE
|
|
4312
|
+
_hashShader(value) {
|
|
4313
|
+
return `${value.stage}:${value.source}`;
|
|
4314
|
+
}
|
|
4315
|
+
};
|
|
4316
|
+
var ShaderFactory = _ShaderFactory;
|
|
4317
|
+
__publicField(ShaderFactory, "defaultProps", { ...Shader.defaultProps });
|
|
4318
|
+
|
|
4319
|
+
// src/adapter-utils/bind-groups.ts
|
|
4320
|
+
function getShaderLayoutBinding(shaderLayout, bindingName, options) {
|
|
4321
|
+
const bindingLayout = shaderLayout.bindings.find(
|
|
4322
|
+
(binding) => binding.name === bindingName || `${binding.name.toLocaleLowerCase()}uniforms` === bindingName.toLocaleLowerCase()
|
|
4323
|
+
);
|
|
4324
|
+
if (!bindingLayout && !options?.ignoreWarnings) {
|
|
4325
|
+
log.warn(`Binding ${bindingName} not set: Not found in shader layout.`)();
|
|
4326
|
+
}
|
|
4327
|
+
return bindingLayout || null;
|
|
4328
|
+
}
|
|
4329
|
+
function normalizeBindingsByGroup(shaderLayout, bindingsOrBindGroups) {
|
|
4330
|
+
if (!bindingsOrBindGroups) {
|
|
4331
|
+
return {};
|
|
4332
|
+
}
|
|
4333
|
+
if (areBindingsGrouped(bindingsOrBindGroups)) {
|
|
4334
|
+
const bindGroups2 = bindingsOrBindGroups;
|
|
4335
|
+
return Object.fromEntries(
|
|
4336
|
+
Object.entries(bindGroups2).map(([group, bindings]) => [Number(group), { ...bindings }])
|
|
4337
|
+
);
|
|
4338
|
+
}
|
|
4339
|
+
const bindGroups = {};
|
|
4340
|
+
for (const [bindingName, binding] of Object.entries(bindingsOrBindGroups)) {
|
|
4341
|
+
const bindingLayout = getShaderLayoutBinding(shaderLayout, bindingName);
|
|
4342
|
+
const group = bindingLayout?.group ?? 0;
|
|
4343
|
+
bindGroups[group] ||= {};
|
|
4344
|
+
bindGroups[group][bindingName] = binding;
|
|
4345
|
+
}
|
|
4346
|
+
return bindGroups;
|
|
4347
|
+
}
|
|
4348
|
+
function flattenBindingsByGroup(bindGroups) {
|
|
4349
|
+
const bindings = {};
|
|
4350
|
+
for (const groupBindings of Object.values(bindGroups)) {
|
|
4351
|
+
Object.assign(bindings, groupBindings);
|
|
4352
|
+
}
|
|
4353
|
+
return bindings;
|
|
4354
|
+
}
|
|
4355
|
+
function areBindingsGrouped(bindingsOrBindGroups) {
|
|
4356
|
+
const keys = Object.keys(bindingsOrBindGroups);
|
|
4357
|
+
return keys.length > 0 && keys.every((key) => /^\d+$/.test(key));
|
|
4358
|
+
}
|
|
4359
|
+
|
|
4360
|
+
// src/factories/bind-group-factory.ts
|
|
4361
|
+
var BindGroupFactory = class {
|
|
4362
|
+
device;
|
|
4363
|
+
_layoutCacheByPipeline = /* @__PURE__ */ new WeakMap();
|
|
4364
|
+
_bindGroupCacheByLayout = /* @__PURE__ */ new WeakMap();
|
|
4365
|
+
constructor(device) {
|
|
4366
|
+
this.device = device;
|
|
4367
|
+
}
|
|
4368
|
+
getBindGroups(pipeline, bindings, bindGroupCacheKeys) {
|
|
4369
|
+
if (this.device.type !== "webgpu" || pipeline.shaderLayout.bindings.length === 0) {
|
|
4370
|
+
return {};
|
|
4371
|
+
}
|
|
4372
|
+
const bindingsByGroup = normalizeBindingsByGroup(pipeline.shaderLayout, bindings);
|
|
4373
|
+
const resolvedBindGroups = {};
|
|
4374
|
+
for (const group of getBindGroupIndicesUpToMax(pipeline.shaderLayout.bindings)) {
|
|
4375
|
+
const groupBindings = bindingsByGroup[group];
|
|
4376
|
+
const bindGroupLayout = this._getBindGroupLayout(pipeline, group);
|
|
4377
|
+
if (!groupBindings || Object.keys(groupBindings).length === 0) {
|
|
4378
|
+
if (!hasBindingsInGroup(pipeline.shaderLayout.bindings, group)) {
|
|
4379
|
+
resolvedBindGroups[group] = this._getEmptyBindGroup(
|
|
4380
|
+
bindGroupLayout,
|
|
4381
|
+
pipeline.shaderLayout,
|
|
4382
|
+
group
|
|
4383
|
+
);
|
|
4384
|
+
}
|
|
4385
|
+
continue;
|
|
4386
|
+
}
|
|
4387
|
+
const bindGroupCacheKey = bindGroupCacheKeys?.[group];
|
|
4388
|
+
if (bindGroupCacheKey) {
|
|
4389
|
+
const layoutCache = this._getLayoutBindGroupCache(bindGroupLayout);
|
|
4390
|
+
if (layoutCache.bindGroupsBySource.has(bindGroupCacheKey)) {
|
|
4391
|
+
resolvedBindGroups[group] = layoutCache.bindGroupsBySource.get(bindGroupCacheKey) || null;
|
|
4392
|
+
continue;
|
|
4393
|
+
}
|
|
4394
|
+
const bindGroup = this.device._createBindGroupWebGPU(
|
|
4395
|
+
bindGroupLayout,
|
|
4396
|
+
pipeline.shaderLayout,
|
|
4397
|
+
groupBindings,
|
|
4398
|
+
group
|
|
4399
|
+
);
|
|
4400
|
+
layoutCache.bindGroupsBySource.set(bindGroupCacheKey, bindGroup);
|
|
4401
|
+
resolvedBindGroups[group] = bindGroup;
|
|
4402
|
+
} else {
|
|
4403
|
+
resolvedBindGroups[group] = this.device._createBindGroupWebGPU(
|
|
4404
|
+
bindGroupLayout,
|
|
4405
|
+
pipeline.shaderLayout,
|
|
4406
|
+
groupBindings,
|
|
4407
|
+
group
|
|
4408
|
+
);
|
|
4409
|
+
}
|
|
4410
|
+
}
|
|
4411
|
+
return resolvedBindGroups;
|
|
4412
|
+
}
|
|
4413
|
+
_getBindGroupLayout(pipeline, group) {
|
|
4414
|
+
let layoutCache = this._layoutCacheByPipeline.get(pipeline);
|
|
4415
|
+
if (!layoutCache) {
|
|
4416
|
+
layoutCache = {};
|
|
4417
|
+
this._layoutCacheByPipeline.set(pipeline, layoutCache);
|
|
4418
|
+
}
|
|
4419
|
+
layoutCache[group] ||= this.device._createBindGroupLayoutWebGPU(pipeline, group);
|
|
4420
|
+
return layoutCache[group];
|
|
4421
|
+
}
|
|
4422
|
+
_getEmptyBindGroup(bindGroupLayout, shaderLayout, group) {
|
|
4423
|
+
const layoutCache = this._getLayoutBindGroupCache(bindGroupLayout);
|
|
4424
|
+
layoutCache.emptyBindGroup ||= this.device._createBindGroupWebGPU(bindGroupLayout, shaderLayout, {}, group) || null;
|
|
4425
|
+
return layoutCache.emptyBindGroup;
|
|
4426
|
+
}
|
|
4427
|
+
_getLayoutBindGroupCache(bindGroupLayout) {
|
|
4428
|
+
let layoutCache = this._bindGroupCacheByLayout.get(bindGroupLayout);
|
|
4429
|
+
if (!layoutCache) {
|
|
4430
|
+
layoutCache = { bindGroupsBySource: /* @__PURE__ */ new WeakMap() };
|
|
4431
|
+
this._bindGroupCacheByLayout.set(bindGroupLayout, layoutCache);
|
|
4432
|
+
}
|
|
4433
|
+
return layoutCache;
|
|
2860
4434
|
}
|
|
2861
4435
|
};
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
parameters: {},
|
|
2877
|
-
bindings: {},
|
|
2878
|
-
uniforms: {}
|
|
2879
|
-
});
|
|
4436
|
+
function _getDefaultBindGroupFactory(device) {
|
|
4437
|
+
device._factories.bindGroupFactory ||= new BindGroupFactory(device);
|
|
4438
|
+
return device._factories.bindGroupFactory;
|
|
4439
|
+
}
|
|
4440
|
+
function getBindGroupIndicesUpToMax(bindings) {
|
|
4441
|
+
const maxGroup = bindings.reduce(
|
|
4442
|
+
(highestGroup, binding) => Math.max(highestGroup, binding.group),
|
|
4443
|
+
-1
|
|
4444
|
+
);
|
|
4445
|
+
return Array.from({ length: maxGroup + 1 }, (_, group) => group);
|
|
4446
|
+
}
|
|
4447
|
+
function hasBindingsInGroup(bindings, group) {
|
|
4448
|
+
return bindings.some((binding) => binding.group === group);
|
|
4449
|
+
}
|
|
2880
4450
|
|
|
2881
4451
|
// src/adapter/resources/render-pass.ts
|
|
2882
4452
|
var _RenderPass = class extends Resource {
|
|
@@ -2916,28 +4486,6 @@ ${htmlLog}
|
|
|
2916
4486
|
endTimestampIndex: void 0
|
|
2917
4487
|
});
|
|
2918
4488
|
|
|
2919
|
-
// src/adapter/resources/compute-pipeline.ts
|
|
2920
|
-
var _ComputePipeline = class extends Resource {
|
|
2921
|
-
get [Symbol.toStringTag]() {
|
|
2922
|
-
return "ComputePipeline";
|
|
2923
|
-
}
|
|
2924
|
-
hash = "";
|
|
2925
|
-
/** The merged shader layout */
|
|
2926
|
-
shaderLayout;
|
|
2927
|
-
constructor(device, props) {
|
|
2928
|
-
super(device, props, _ComputePipeline.defaultProps);
|
|
2929
|
-
this.shaderLayout = props.shaderLayout;
|
|
2930
|
-
}
|
|
2931
|
-
};
|
|
2932
|
-
var ComputePipeline = _ComputePipeline;
|
|
2933
|
-
__publicField(ComputePipeline, "defaultProps", {
|
|
2934
|
-
...Resource.defaultProps,
|
|
2935
|
-
shader: void 0,
|
|
2936
|
-
entryPoint: void 0,
|
|
2937
|
-
constants: {},
|
|
2938
|
-
shaderLayout: void 0
|
|
2939
|
-
});
|
|
2940
|
-
|
|
2941
4489
|
// src/adapter/resources/compute-pass.ts
|
|
2942
4490
|
var _ComputePass = class extends Resource {
|
|
2943
4491
|
constructor(device, props) {
|
|
@@ -2960,8 +4508,69 @@ ${htmlLog}
|
|
|
2960
4508
|
get [Symbol.toStringTag]() {
|
|
2961
4509
|
return "CommandEncoder";
|
|
2962
4510
|
}
|
|
4511
|
+
_timeProfilingQuerySet = null;
|
|
4512
|
+
_timeProfilingSlotCount = 0;
|
|
4513
|
+
_gpuTimeMs;
|
|
2963
4514
|
constructor(device, props) {
|
|
2964
4515
|
super(device, props, _CommandEncoder.defaultProps);
|
|
4516
|
+
this._timeProfilingQuerySet = props.timeProfilingQuerySet ?? null;
|
|
4517
|
+
this._timeProfilingSlotCount = 0;
|
|
4518
|
+
this._gpuTimeMs = void 0;
|
|
4519
|
+
}
|
|
4520
|
+
/**
|
|
4521
|
+
* Reads all resolved timestamp pairs on the current profiler query set and caches the sum
|
|
4522
|
+
* as milliseconds on this encoder.
|
|
4523
|
+
*/
|
|
4524
|
+
async resolveTimeProfilingQuerySet() {
|
|
4525
|
+
this._gpuTimeMs = void 0;
|
|
4526
|
+
if (!this._timeProfilingQuerySet) {
|
|
4527
|
+
return;
|
|
4528
|
+
}
|
|
4529
|
+
const pairCount = Math.floor(this._timeProfilingSlotCount / 2);
|
|
4530
|
+
if (pairCount <= 0) {
|
|
4531
|
+
return;
|
|
4532
|
+
}
|
|
4533
|
+
const queryCount = pairCount * 2;
|
|
4534
|
+
const results = await this._timeProfilingQuerySet.readResults({
|
|
4535
|
+
firstQuery: 0,
|
|
4536
|
+
queryCount
|
|
4537
|
+
});
|
|
4538
|
+
let totalDurationNanoseconds = 0n;
|
|
4539
|
+
for (let queryIndex = 0; queryIndex < queryCount; queryIndex += 2) {
|
|
4540
|
+
totalDurationNanoseconds += results[queryIndex + 1] - results[queryIndex];
|
|
4541
|
+
}
|
|
4542
|
+
this._gpuTimeMs = Number(totalDurationNanoseconds) / 1e6;
|
|
4543
|
+
}
|
|
4544
|
+
/** Returns the number of query slots consumed by automatic pass profiling on this encoder. */
|
|
4545
|
+
getTimeProfilingSlotCount() {
|
|
4546
|
+
return this._timeProfilingSlotCount;
|
|
4547
|
+
}
|
|
4548
|
+
getTimeProfilingQuerySet() {
|
|
4549
|
+
return this._timeProfilingQuerySet;
|
|
4550
|
+
}
|
|
4551
|
+
/** Internal helper for auto-assigning timestamp slots to render/compute passes on this encoder. */
|
|
4552
|
+
_applyTimeProfilingToPassProps(props) {
|
|
4553
|
+
const passProps = props || {};
|
|
4554
|
+
if (!this._supportsTimestampQueries() || !this._timeProfilingQuerySet) {
|
|
4555
|
+
return passProps;
|
|
4556
|
+
}
|
|
4557
|
+
if (passProps.timestampQuerySet !== void 0 || passProps.beginTimestampIndex !== void 0 || passProps.endTimestampIndex !== void 0) {
|
|
4558
|
+
return passProps;
|
|
4559
|
+
}
|
|
4560
|
+
const beginTimestampIndex = this._timeProfilingSlotCount;
|
|
4561
|
+
if (beginTimestampIndex + 1 >= this._timeProfilingQuerySet.props.count) {
|
|
4562
|
+
return passProps;
|
|
4563
|
+
}
|
|
4564
|
+
this._timeProfilingSlotCount += 2;
|
|
4565
|
+
return {
|
|
4566
|
+
...passProps,
|
|
4567
|
+
timestampQuerySet: this._timeProfilingQuerySet,
|
|
4568
|
+
beginTimestampIndex,
|
|
4569
|
+
endTimestampIndex: beginTimestampIndex + 1
|
|
4570
|
+
};
|
|
4571
|
+
}
|
|
4572
|
+
_supportsTimestampQueries() {
|
|
4573
|
+
return this.device.features.has("timestamp-query");
|
|
2965
4574
|
}
|
|
2966
4575
|
};
|
|
2967
4576
|
var CommandEncoder = _CommandEncoder;
|
|
@@ -2970,7 +4579,8 @@ ${htmlLog}
|
|
|
2970
4579
|
// beginComputePass(optional GPUComputePassDescriptor descriptor = {}): GPUComputePassEncoder;
|
|
2971
4580
|
__publicField(CommandEncoder, "defaultProps", {
|
|
2972
4581
|
...Resource.defaultProps,
|
|
2973
|
-
measureExecutionTime: void 0
|
|
4582
|
+
measureExecutionTime: void 0,
|
|
4583
|
+
timeProfilingQuerySet: void 0
|
|
2974
4584
|
});
|
|
2975
4585
|
|
|
2976
4586
|
// src/adapter/resources/command-buffer.ts
|
|
@@ -2987,13 +4597,22 @@ ${htmlLog}
|
|
|
2987
4597
|
...Resource.defaultProps
|
|
2988
4598
|
});
|
|
2989
4599
|
|
|
2990
|
-
// src/shadertypes/
|
|
4600
|
+
// src/shadertypes/shader-types/shader-type-decoder.ts
|
|
2991
4601
|
function getVariableShaderTypeInfo(format) {
|
|
2992
|
-
const
|
|
4602
|
+
const resolvedFormat = resolveVariableShaderTypeAlias(format);
|
|
4603
|
+
const decoded = UNIFORM_FORMATS[resolvedFormat];
|
|
4604
|
+
if (!decoded) {
|
|
4605
|
+
throw new Error(`Unsupported variable shader type: ${format}`);
|
|
4606
|
+
}
|
|
2993
4607
|
return decoded;
|
|
2994
4608
|
}
|
|
2995
4609
|
function getAttributeShaderTypeInfo(attributeType) {
|
|
2996
|
-
const
|
|
4610
|
+
const resolvedAttributeType = resolveAttributeShaderTypeAlias(attributeType);
|
|
4611
|
+
const decoded = TYPE_INFO[resolvedAttributeType];
|
|
4612
|
+
if (!decoded) {
|
|
4613
|
+
throw new Error(`Unsupported attribute shader type: ${attributeType}`);
|
|
4614
|
+
}
|
|
4615
|
+
const [primitiveType, components] = decoded;
|
|
2997
4616
|
const integer = primitiveType === "i32" || primitiveType === "u32";
|
|
2998
4617
|
const signed = primitiveType !== "u32";
|
|
2999
4618
|
const byteLength = PRIMITIVE_TYPE_SIZES[primitiveType] * components;
|
|
@@ -3005,6 +4624,33 @@ ${htmlLog}
|
|
|
3005
4624
|
signed
|
|
3006
4625
|
};
|
|
3007
4626
|
}
|
|
4627
|
+
var ShaderTypeDecoder = class {
|
|
4628
|
+
getVariableShaderTypeInfo(format) {
|
|
4629
|
+
return getVariableShaderTypeInfo(format);
|
|
4630
|
+
}
|
|
4631
|
+
getAttributeShaderTypeInfo(attributeType) {
|
|
4632
|
+
return getAttributeShaderTypeInfo(attributeType);
|
|
4633
|
+
}
|
|
4634
|
+
makeShaderAttributeType(primitiveType, components) {
|
|
4635
|
+
return makeShaderAttributeType(primitiveType, components);
|
|
4636
|
+
}
|
|
4637
|
+
resolveAttributeShaderTypeAlias(alias) {
|
|
4638
|
+
return resolveAttributeShaderTypeAlias(alias);
|
|
4639
|
+
}
|
|
4640
|
+
resolveVariableShaderTypeAlias(alias) {
|
|
4641
|
+
return resolveVariableShaderTypeAlias(alias);
|
|
4642
|
+
}
|
|
4643
|
+
};
|
|
4644
|
+
function makeShaderAttributeType(primitiveType, components) {
|
|
4645
|
+
return components === 1 ? primitiveType : `vec${components}<${primitiveType}>`;
|
|
4646
|
+
}
|
|
4647
|
+
function resolveAttributeShaderTypeAlias(alias) {
|
|
4648
|
+
return WGSL_ATTRIBUTE_TYPE_ALIAS_MAP[alias] || alias;
|
|
4649
|
+
}
|
|
4650
|
+
function resolveVariableShaderTypeAlias(alias) {
|
|
4651
|
+
return WGSL_VARIABLE_TYPE_ALIAS_MAP[alias] || alias;
|
|
4652
|
+
}
|
|
4653
|
+
var shaderTypeDecoder = new ShaderTypeDecoder();
|
|
3008
4654
|
var PRIMITIVE_TYPE_SIZES = {
|
|
3009
4655
|
f32: 4,
|
|
3010
4656
|
f16: 2,
|
|
@@ -3101,7 +4747,18 @@ ${htmlLog}
|
|
|
3101
4747
|
vec4h: "vec4<f16>"
|
|
3102
4748
|
};
|
|
3103
4749
|
var WGSL_VARIABLE_TYPE_ALIAS_MAP = {
|
|
3104
|
-
|
|
4750
|
+
vec2i: "vec2<i32>",
|
|
4751
|
+
vec3i: "vec3<i32>",
|
|
4752
|
+
vec4i: "vec4<i32>",
|
|
4753
|
+
vec2u: "vec2<u32>",
|
|
4754
|
+
vec3u: "vec3<u32>",
|
|
4755
|
+
vec4u: "vec4<u32>",
|
|
4756
|
+
vec2f: "vec2<f32>",
|
|
4757
|
+
vec3f: "vec3<f32>",
|
|
4758
|
+
vec4f: "vec4<f32>",
|
|
4759
|
+
vec2h: "vec2<f16>",
|
|
4760
|
+
vec3h: "vec3<f16>",
|
|
4761
|
+
vec4h: "vec4<f16>",
|
|
3105
4762
|
mat2x2f: "mat2x2<f32>",
|
|
3106
4763
|
mat2x3f: "mat2x3<f32>",
|
|
3107
4764
|
mat2x4f: "mat2x4<f32>",
|
|
@@ -3168,10 +4825,10 @@ ${htmlLog}
|
|
|
3168
4825
|
if (!shaderDeclaration) {
|
|
3169
4826
|
return null;
|
|
3170
4827
|
}
|
|
3171
|
-
const attributeTypeInfo = getAttributeShaderTypeInfo(shaderDeclaration.type);
|
|
3172
|
-
const defaultVertexFormat = getCompatibleVertexFormat(attributeTypeInfo);
|
|
4828
|
+
const attributeTypeInfo = shaderTypeDecoder.getAttributeShaderTypeInfo(shaderDeclaration.type);
|
|
4829
|
+
const defaultVertexFormat = vertexFormatDecoder.getCompatibleVertexFormat(attributeTypeInfo);
|
|
3173
4830
|
const vertexFormat = bufferMapping?.vertexFormat || defaultVertexFormat;
|
|
3174
|
-
const vertexFormatInfo = getVertexFormatInfo(vertexFormat);
|
|
4831
|
+
const vertexFormatInfo = vertexFormatDecoder.getVertexFormatInfo(vertexFormat);
|
|
3175
4832
|
return {
|
|
3176
4833
|
attributeName: bufferMapping?.attributeName || shaderDeclaration.name,
|
|
3177
4834
|
bufferName: bufferMapping?.bufferName || shaderDeclaration.name,
|
|
@@ -3239,7 +4896,7 @@ ${htmlLog}
|
|
|
3239
4896
|
let byteStride = bufferLayout.byteStride;
|
|
3240
4897
|
if (typeof bufferLayout.byteStride !== "number") {
|
|
3241
4898
|
for (const attributeMapping2 of bufferLayout.attributes || []) {
|
|
3242
|
-
const info = getVertexFormatInfo(attributeMapping2.format);
|
|
4899
|
+
const info = vertexFormatDecoder.getVertexFormatInfo(attributeMapping2.format);
|
|
3243
4900
|
byteStride += info.byteLength;
|
|
3244
4901
|
}
|
|
3245
4902
|
}
|
|
@@ -3327,6 +4984,20 @@ ${htmlLog}
|
|
|
3327
4984
|
count: void 0
|
|
3328
4985
|
});
|
|
3329
4986
|
|
|
4987
|
+
// src/adapter/resources/fence.ts
|
|
4988
|
+
var _Fence = class extends Resource {
|
|
4989
|
+
get [Symbol.toStringTag]() {
|
|
4990
|
+
return "Fence";
|
|
4991
|
+
}
|
|
4992
|
+
constructor(device, props = {}) {
|
|
4993
|
+
super(device, props, _Fence.defaultProps);
|
|
4994
|
+
}
|
|
4995
|
+
};
|
|
4996
|
+
var Fence = _Fence;
|
|
4997
|
+
__publicField(Fence, "defaultProps", {
|
|
4998
|
+
...Resource.defaultProps
|
|
4999
|
+
});
|
|
5000
|
+
|
|
3330
5001
|
// src/adapter/resources/pipeline-layout.ts
|
|
3331
5002
|
var _PipelineLayout = class extends Resource {
|
|
3332
5003
|
get [Symbol.toStringTag]() {
|
|
@@ -3345,6 +5016,200 @@ ${htmlLog}
|
|
|
3345
5016
|
}
|
|
3346
5017
|
});
|
|
3347
5018
|
|
|
5019
|
+
// src/shadertypes/data-types/decode-data-types.ts
|
|
5020
|
+
function alignTo(size, count) {
|
|
5021
|
+
switch (count) {
|
|
5022
|
+
case 1:
|
|
5023
|
+
return size;
|
|
5024
|
+
case 2:
|
|
5025
|
+
return size + size % 2;
|
|
5026
|
+
default:
|
|
5027
|
+
return size + (4 - size % 4) % 4;
|
|
5028
|
+
}
|
|
5029
|
+
}
|
|
5030
|
+
function getTypedArrayConstructor(type) {
|
|
5031
|
+
const [, , , , Constructor] = NORMALIZED_TYPE_MAP2[type];
|
|
5032
|
+
return Constructor;
|
|
5033
|
+
}
|
|
5034
|
+
var NORMALIZED_TYPE_MAP2 = {
|
|
5035
|
+
uint8: ["uint8", "u32", 1, false, Uint8Array],
|
|
5036
|
+
sint8: ["sint8", "i32", 1, false, Int8Array],
|
|
5037
|
+
unorm8: ["uint8", "f32", 1, true, Uint8Array],
|
|
5038
|
+
snorm8: ["sint8", "f32", 1, true, Int8Array],
|
|
5039
|
+
uint16: ["uint16", "u32", 2, false, Uint16Array],
|
|
5040
|
+
sint16: ["sint16", "i32", 2, false, Int16Array],
|
|
5041
|
+
unorm16: ["uint16", "u32", 2, true, Uint16Array],
|
|
5042
|
+
snorm16: ["sint16", "i32", 2, true, Int16Array],
|
|
5043
|
+
float16: ["float16", "f16", 2, false, Uint16Array],
|
|
5044
|
+
float32: ["float32", "f32", 4, false, Float32Array],
|
|
5045
|
+
uint32: ["uint32", "u32", 4, false, Uint32Array],
|
|
5046
|
+
sint32: ["sint32", "i32", 4, false, Int32Array]
|
|
5047
|
+
};
|
|
5048
|
+
|
|
5049
|
+
// src/shadertypes/shader-types/shader-block-layout.ts
|
|
5050
|
+
function makeShaderBlockLayout(uniformTypes, options = {}) {
|
|
5051
|
+
const copiedUniformTypes = { ...uniformTypes };
|
|
5052
|
+
const layout = options.layout ?? "std140";
|
|
5053
|
+
const fields = {};
|
|
5054
|
+
let size = 0;
|
|
5055
|
+
for (const [key, uniformType] of Object.entries(copiedUniformTypes)) {
|
|
5056
|
+
size = addToLayout(fields, key, uniformType, size, layout);
|
|
5057
|
+
}
|
|
5058
|
+
size = alignTo(size, getTypeAlignment(copiedUniformTypes, layout));
|
|
5059
|
+
return {
|
|
5060
|
+
layout,
|
|
5061
|
+
byteLength: size * 4,
|
|
5062
|
+
uniformTypes: copiedUniformTypes,
|
|
5063
|
+
fields
|
|
5064
|
+
};
|
|
5065
|
+
}
|
|
5066
|
+
function getLeafLayoutInfo(type, layout) {
|
|
5067
|
+
const resolvedType = resolveVariableShaderTypeAlias(type);
|
|
5068
|
+
const decodedType = getVariableShaderTypeInfo(resolvedType);
|
|
5069
|
+
const matrixMatch = /^mat(\d)x(\d)<.+>$/.exec(resolvedType);
|
|
5070
|
+
if (matrixMatch) {
|
|
5071
|
+
const columns = Number(matrixMatch[1]);
|
|
5072
|
+
const rows = Number(matrixMatch[2]);
|
|
5073
|
+
const columnInfo = getVectorLayoutInfo(
|
|
5074
|
+
rows,
|
|
5075
|
+
resolvedType,
|
|
5076
|
+
decodedType.type,
|
|
5077
|
+
layout
|
|
5078
|
+
);
|
|
5079
|
+
const columnStride = getMatrixColumnStride(columnInfo.size, columnInfo.alignment, layout);
|
|
5080
|
+
return {
|
|
5081
|
+
alignment: columnInfo.alignment,
|
|
5082
|
+
size: columns * columnStride,
|
|
5083
|
+
components: columns * rows,
|
|
5084
|
+
columns,
|
|
5085
|
+
rows,
|
|
5086
|
+
columnStride,
|
|
5087
|
+
shaderType: resolvedType,
|
|
5088
|
+
type: decodedType.type
|
|
5089
|
+
};
|
|
5090
|
+
}
|
|
5091
|
+
const vectorMatch = /^vec(\d)<.+>$/.exec(resolvedType);
|
|
5092
|
+
if (vectorMatch) {
|
|
5093
|
+
return getVectorLayoutInfo(
|
|
5094
|
+
Number(vectorMatch[1]),
|
|
5095
|
+
resolvedType,
|
|
5096
|
+
decodedType.type,
|
|
5097
|
+
layout
|
|
5098
|
+
);
|
|
5099
|
+
}
|
|
5100
|
+
return {
|
|
5101
|
+
alignment: 1,
|
|
5102
|
+
size: 1,
|
|
5103
|
+
components: 1,
|
|
5104
|
+
columns: 1,
|
|
5105
|
+
rows: 1,
|
|
5106
|
+
columnStride: 1,
|
|
5107
|
+
shaderType: resolvedType,
|
|
5108
|
+
type: decodedType.type
|
|
5109
|
+
};
|
|
5110
|
+
}
|
|
5111
|
+
function isCompositeShaderTypeStruct(value) {
|
|
5112
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
5113
|
+
}
|
|
5114
|
+
function addToLayout(fields, name2, type, offset, layout) {
|
|
5115
|
+
if (typeof type === "string") {
|
|
5116
|
+
const info = getLeafLayoutInfo(type, layout);
|
|
5117
|
+
const alignedOffset = alignTo(offset, info.alignment);
|
|
5118
|
+
fields[name2] = {
|
|
5119
|
+
offset: alignedOffset,
|
|
5120
|
+
...info
|
|
5121
|
+
};
|
|
5122
|
+
return alignedOffset + info.size;
|
|
5123
|
+
}
|
|
5124
|
+
if (Array.isArray(type)) {
|
|
5125
|
+
if (Array.isArray(type[0])) {
|
|
5126
|
+
throw new Error(`Nested arrays are not supported for ${name2}`);
|
|
5127
|
+
}
|
|
5128
|
+
const elementType = type[0];
|
|
5129
|
+
const length = type[1];
|
|
5130
|
+
const stride = getArrayStride(elementType, layout);
|
|
5131
|
+
const arrayOffset = alignTo(offset, getTypeAlignment(type, layout));
|
|
5132
|
+
for (let i = 0; i < length; i++) {
|
|
5133
|
+
addToLayout(fields, `${name2}[${i}]`, elementType, arrayOffset + i * stride, layout);
|
|
5134
|
+
}
|
|
5135
|
+
return arrayOffset + stride * length;
|
|
5136
|
+
}
|
|
5137
|
+
if (isCompositeShaderTypeStruct(type)) {
|
|
5138
|
+
const structAlignment = getTypeAlignment(type, layout);
|
|
5139
|
+
let structOffset = alignTo(offset, structAlignment);
|
|
5140
|
+
for (const [memberName, memberType] of Object.entries(type)) {
|
|
5141
|
+
structOffset = addToLayout(fields, `${name2}.${memberName}`, memberType, structOffset, layout);
|
|
5142
|
+
}
|
|
5143
|
+
return alignTo(structOffset, structAlignment);
|
|
5144
|
+
}
|
|
5145
|
+
throw new Error(`Unsupported CompositeShaderType for ${name2}`);
|
|
5146
|
+
}
|
|
5147
|
+
function getTypeSize(type, layout) {
|
|
5148
|
+
if (typeof type === "string") {
|
|
5149
|
+
return getLeafLayoutInfo(type, layout).size;
|
|
5150
|
+
}
|
|
5151
|
+
if (Array.isArray(type)) {
|
|
5152
|
+
const elementType = type[0];
|
|
5153
|
+
const length = type[1];
|
|
5154
|
+
if (Array.isArray(elementType)) {
|
|
5155
|
+
throw new Error("Nested arrays are not supported");
|
|
5156
|
+
}
|
|
5157
|
+
return getArrayStride(elementType, layout) * length;
|
|
5158
|
+
}
|
|
5159
|
+
let size = 0;
|
|
5160
|
+
for (const memberType of Object.values(type)) {
|
|
5161
|
+
const compositeMemberType = memberType;
|
|
5162
|
+
size = alignTo(size, getTypeAlignment(compositeMemberType, layout));
|
|
5163
|
+
size += getTypeSize(compositeMemberType, layout);
|
|
5164
|
+
}
|
|
5165
|
+
return alignTo(size, getTypeAlignment(type, layout));
|
|
5166
|
+
}
|
|
5167
|
+
function getTypeAlignment(type, layout) {
|
|
5168
|
+
if (typeof type === "string") {
|
|
5169
|
+
return getLeafLayoutInfo(type, layout).alignment;
|
|
5170
|
+
}
|
|
5171
|
+
if (Array.isArray(type)) {
|
|
5172
|
+
const elementType = type[0];
|
|
5173
|
+
const elementAlignment = getTypeAlignment(elementType, layout);
|
|
5174
|
+
return uses16ByteArrayAlignment(layout) ? Math.max(elementAlignment, 4) : elementAlignment;
|
|
5175
|
+
}
|
|
5176
|
+
let maxAlignment = 1;
|
|
5177
|
+
for (const memberType of Object.values(type)) {
|
|
5178
|
+
const memberAlignment = getTypeAlignment(memberType, layout);
|
|
5179
|
+
maxAlignment = Math.max(maxAlignment, memberAlignment);
|
|
5180
|
+
}
|
|
5181
|
+
return uses16ByteStructAlignment(layout) ? Math.max(maxAlignment, 4) : maxAlignment;
|
|
5182
|
+
}
|
|
5183
|
+
function getVectorLayoutInfo(components, shaderType, type, layout) {
|
|
5184
|
+
return {
|
|
5185
|
+
alignment: components === 2 ? 2 : 4,
|
|
5186
|
+
size: components === 3 ? 3 : components,
|
|
5187
|
+
components,
|
|
5188
|
+
columns: 1,
|
|
5189
|
+
rows: components,
|
|
5190
|
+
columnStride: components === 3 ? 3 : components,
|
|
5191
|
+
shaderType,
|
|
5192
|
+
type
|
|
5193
|
+
};
|
|
5194
|
+
}
|
|
5195
|
+
function getArrayStride(elementType, layout) {
|
|
5196
|
+
const elementSize = getTypeSize(elementType, layout);
|
|
5197
|
+
const elementAlignment = getTypeAlignment(elementType, layout);
|
|
5198
|
+
return getArrayLikeStride(elementSize, elementAlignment, layout);
|
|
5199
|
+
}
|
|
5200
|
+
function getArrayLikeStride(size, alignment, layout) {
|
|
5201
|
+
return alignTo(size, uses16ByteArrayAlignment(layout) ? 4 : alignment);
|
|
5202
|
+
}
|
|
5203
|
+
function getMatrixColumnStride(size, alignment, layout) {
|
|
5204
|
+
return layout === "std140" ? 4 : alignTo(size, alignment);
|
|
5205
|
+
}
|
|
5206
|
+
function uses16ByteArrayAlignment(layout) {
|
|
5207
|
+
return layout === "std140" || layout === "wgsl-uniform";
|
|
5208
|
+
}
|
|
5209
|
+
function uses16ByteStructAlignment(layout) {
|
|
5210
|
+
return layout === "std140" || layout === "wgsl-uniform";
|
|
5211
|
+
}
|
|
5212
|
+
|
|
3348
5213
|
// src/utils/array-utils-flat.ts
|
|
3349
5214
|
var arrayBuffer;
|
|
3350
5215
|
function getScratchArrayBuffer(byteLength) {
|
|
@@ -3369,92 +5234,201 @@ ${htmlLog}
|
|
|
3369
5234
|
return isTypedArray(value);
|
|
3370
5235
|
}
|
|
3371
5236
|
|
|
3372
|
-
// src/portable/
|
|
3373
|
-
var
|
|
3374
|
-
|
|
3375
|
-
layout
|
|
3376
|
-
/**
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
constructor(
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
5237
|
+
// src/portable/shader-block-writer.ts
|
|
5238
|
+
var ShaderBlockWriter = class {
|
|
5239
|
+
/** Layout metadata used to flatten and serialize values. */
|
|
5240
|
+
layout;
|
|
5241
|
+
/**
|
|
5242
|
+
* Creates a writer for a precomputed shader-block layout.
|
|
5243
|
+
*/
|
|
5244
|
+
constructor(layout) {
|
|
5245
|
+
this.layout = layout;
|
|
5246
|
+
}
|
|
5247
|
+
/**
|
|
5248
|
+
* Returns `true` if the flattened layout contains the given field.
|
|
5249
|
+
*/
|
|
5250
|
+
has(name2) {
|
|
5251
|
+
return Boolean(this.layout.fields[name2]);
|
|
5252
|
+
}
|
|
5253
|
+
/**
|
|
5254
|
+
* Returns offset and size metadata for a flattened field.
|
|
5255
|
+
*/
|
|
5256
|
+
get(name2) {
|
|
5257
|
+
const entry = this.layout.fields[name2];
|
|
5258
|
+
return entry ? { offset: entry.offset, size: entry.size } : void 0;
|
|
5259
|
+
}
|
|
5260
|
+
/**
|
|
5261
|
+
* Flattens nested composite values into leaf-path values understood by {@link UniformBlock}.
|
|
5262
|
+
*
|
|
5263
|
+
* Top-level values may be supplied either in nested object form matching the
|
|
5264
|
+
* declared composite shader types or as already-flattened leaf-path values.
|
|
5265
|
+
*/
|
|
5266
|
+
getFlatUniformValues(uniformValues) {
|
|
5267
|
+
const flattenedUniformValues = {};
|
|
5268
|
+
for (const [name2, value] of Object.entries(uniformValues)) {
|
|
5269
|
+
const uniformType = this.layout.uniformTypes[name2];
|
|
5270
|
+
if (uniformType) {
|
|
5271
|
+
this._flattenCompositeValue(flattenedUniformValues, name2, uniformType, value);
|
|
5272
|
+
} else if (this.layout.fields[name2]) {
|
|
5273
|
+
flattenedUniformValues[name2] = value;
|
|
5274
|
+
}
|
|
5275
|
+
}
|
|
5276
|
+
return flattenedUniformValues;
|
|
5277
|
+
}
|
|
5278
|
+
/**
|
|
5279
|
+
* Serializes the supplied values into buffer-backed binary data.
|
|
5280
|
+
*
|
|
5281
|
+
* The returned view length matches {@link ShaderBlockLayout.byteLength}, which
|
|
5282
|
+
* is the exact packed size of the block.
|
|
5283
|
+
*/
|
|
3395
5284
|
getData(uniformValues) {
|
|
3396
|
-
const
|
|
5285
|
+
const buffer = getScratchArrayBuffer(this.layout.byteLength);
|
|
5286
|
+
new Uint8Array(buffer, 0, this.layout.byteLength).fill(0);
|
|
3397
5287
|
const typedArrays = {
|
|
3398
|
-
i32: new Int32Array(
|
|
3399
|
-
u32: new Uint32Array(
|
|
3400
|
-
f32: new Float32Array(
|
|
3401
|
-
|
|
3402
|
-
f16: new Uint16Array(arrayBuffer2)
|
|
5288
|
+
i32: new Int32Array(buffer),
|
|
5289
|
+
u32: new Uint32Array(buffer),
|
|
5290
|
+
f32: new Float32Array(buffer),
|
|
5291
|
+
f16: new Uint16Array(buffer)
|
|
3403
5292
|
};
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
5293
|
+
const flattenedUniformValues = this.getFlatUniformValues(uniformValues);
|
|
5294
|
+
for (const [name2, value] of Object.entries(flattenedUniformValues)) {
|
|
5295
|
+
this._writeLeafValue(typedArrays, name2, value);
|
|
5296
|
+
}
|
|
5297
|
+
return new Uint8Array(buffer, 0, this.layout.byteLength);
|
|
5298
|
+
}
|
|
5299
|
+
/**
|
|
5300
|
+
* Recursively flattens nested values using the declared composite shader type.
|
|
5301
|
+
*/
|
|
5302
|
+
_flattenCompositeValue(flattenedUniformValues, baseName, uniformType, value) {
|
|
5303
|
+
if (value === void 0) {
|
|
5304
|
+
return;
|
|
5305
|
+
}
|
|
5306
|
+
if (typeof uniformType === "string" || this.layout.fields[baseName]) {
|
|
5307
|
+
flattenedUniformValues[baseName] = value;
|
|
5308
|
+
return;
|
|
5309
|
+
}
|
|
5310
|
+
if (Array.isArray(uniformType)) {
|
|
5311
|
+
const elementType = uniformType[0];
|
|
5312
|
+
const length = uniformType[1];
|
|
5313
|
+
if (Array.isArray(elementType)) {
|
|
5314
|
+
throw new Error(`Nested arrays are not supported for ${baseName}`);
|
|
3409
5315
|
}
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
5316
|
+
if (typeof elementType === "string" && isNumberArray(value)) {
|
|
5317
|
+
this._flattenPackedArray(flattenedUniformValues, baseName, elementType, length, value);
|
|
5318
|
+
return;
|
|
5319
|
+
}
|
|
5320
|
+
if (!Array.isArray(value)) {
|
|
5321
|
+
log.warn(`Unsupported uniform array value for ${baseName}:`, value)();
|
|
5322
|
+
return;
|
|
5323
|
+
}
|
|
5324
|
+
for (let index = 0; index < Math.min(value.length, length); index++) {
|
|
5325
|
+
const elementValue = value[index];
|
|
5326
|
+
if (elementValue === void 0) {
|
|
3417
5327
|
continue;
|
|
3418
5328
|
}
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
5329
|
+
this._flattenCompositeValue(
|
|
5330
|
+
flattenedUniformValues,
|
|
5331
|
+
`${baseName}[${index}]`,
|
|
5332
|
+
elementType,
|
|
5333
|
+
elementValue
|
|
5334
|
+
);
|
|
5335
|
+
}
|
|
5336
|
+
return;
|
|
5337
|
+
}
|
|
5338
|
+
if (isCompositeShaderTypeStruct(uniformType) && isCompositeUniformObject(value)) {
|
|
5339
|
+
for (const [key, subValue] of Object.entries(value)) {
|
|
5340
|
+
if (subValue === void 0) {
|
|
3425
5341
|
continue;
|
|
3426
5342
|
}
|
|
3427
|
-
|
|
5343
|
+
const nestedName = `${baseName}.${key}`;
|
|
5344
|
+
this._flattenCompositeValue(flattenedUniformValues, nestedName, uniformType[key], subValue);
|
|
3428
5345
|
}
|
|
5346
|
+
return;
|
|
3429
5347
|
}
|
|
3430
|
-
|
|
5348
|
+
log.warn(`Unsupported uniform value for ${baseName}:`, value)();
|
|
3431
5349
|
}
|
|
3432
|
-
/**
|
|
3433
|
-
|
|
3434
|
-
|
|
5350
|
+
/**
|
|
5351
|
+
* Expands tightly packed numeric arrays into per-element leaf fields.
|
|
5352
|
+
*/
|
|
5353
|
+
_flattenPackedArray(flattenedUniformValues, baseName, elementType, length, value) {
|
|
5354
|
+
const numericValue = value;
|
|
5355
|
+
const elementLayout = getLeafLayoutInfo(elementType, this.layout.layout);
|
|
5356
|
+
const packedElementLength = elementLayout.components;
|
|
5357
|
+
for (let index = 0; index < length; index++) {
|
|
5358
|
+
const start = index * packedElementLength;
|
|
5359
|
+
if (start >= numericValue.length) {
|
|
5360
|
+
break;
|
|
5361
|
+
}
|
|
5362
|
+
if (packedElementLength === 1) {
|
|
5363
|
+
flattenedUniformValues[`${baseName}[${index}]`] = Number(numericValue[start]);
|
|
5364
|
+
} else {
|
|
5365
|
+
flattenedUniformValues[`${baseName}[${index}]`] = sliceNumericArray(
|
|
5366
|
+
value,
|
|
5367
|
+
start,
|
|
5368
|
+
start + packedElementLength
|
|
5369
|
+
);
|
|
5370
|
+
}
|
|
5371
|
+
}
|
|
3435
5372
|
}
|
|
3436
|
-
/**
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
5373
|
+
/**
|
|
5374
|
+
* Writes one flattened leaf value into its typed-array view.
|
|
5375
|
+
*/
|
|
5376
|
+
_writeLeafValue(typedArrays, name2, value) {
|
|
5377
|
+
const entry = this.layout.fields[name2];
|
|
5378
|
+
if (!entry) {
|
|
5379
|
+
log.warn(`Uniform ${name2} not found in layout`)();
|
|
5380
|
+
return;
|
|
5381
|
+
}
|
|
5382
|
+
const { type, components, columns, rows, offset, columnStride } = entry;
|
|
5383
|
+
const array = typedArrays[type];
|
|
5384
|
+
if (components === 1) {
|
|
5385
|
+
array[offset] = Number(value);
|
|
5386
|
+
return;
|
|
5387
|
+
}
|
|
5388
|
+
const sourceValue = value;
|
|
5389
|
+
if (columns === 1) {
|
|
5390
|
+
for (let componentIndex = 0; componentIndex < components; componentIndex++) {
|
|
5391
|
+
array[offset + componentIndex] = Number(sourceValue[componentIndex] ?? 0);
|
|
5392
|
+
}
|
|
5393
|
+
return;
|
|
5394
|
+
}
|
|
5395
|
+
let sourceIndex = 0;
|
|
5396
|
+
for (let columnIndex = 0; columnIndex < columns; columnIndex++) {
|
|
5397
|
+
const columnOffset = offset + columnIndex * columnStride;
|
|
5398
|
+
for (let rowIndex = 0; rowIndex < rows; rowIndex++) {
|
|
5399
|
+
array[columnOffset + rowIndex] = Number(sourceValue[sourceIndex++] ?? 0);
|
|
5400
|
+
}
|
|
5401
|
+
}
|
|
3440
5402
|
}
|
|
3441
5403
|
};
|
|
5404
|
+
function isCompositeUniformObject(value) {
|
|
5405
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value) && !ArrayBuffer.isView(value);
|
|
5406
|
+
}
|
|
5407
|
+
function sliceNumericArray(value, start, end) {
|
|
5408
|
+
return Array.prototype.slice.call(value, start, end);
|
|
5409
|
+
}
|
|
3442
5410
|
|
|
3443
5411
|
// src/utils/array-equal.ts
|
|
5412
|
+
var MAX_ELEMENTWISE_ARRAY_COMPARE_LENGTH = 128;
|
|
3444
5413
|
function arrayEqual(a, b, limit = 16) {
|
|
3445
|
-
if (a
|
|
3446
|
-
return
|
|
5414
|
+
if (a === b) {
|
|
5415
|
+
return true;
|
|
3447
5416
|
}
|
|
3448
5417
|
const arrayA = a;
|
|
3449
5418
|
const arrayB = b;
|
|
3450
|
-
if (!isNumberArray(arrayA)) {
|
|
5419
|
+
if (!isNumberArray(arrayA) || !isNumberArray(arrayB)) {
|
|
3451
5420
|
return false;
|
|
3452
5421
|
}
|
|
3453
|
-
if (
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
5422
|
+
if (arrayA.length !== arrayB.length) {
|
|
5423
|
+
return false;
|
|
5424
|
+
}
|
|
5425
|
+
const maxCompareLength = Math.min(limit, MAX_ELEMENTWISE_ARRAY_COMPARE_LENGTH);
|
|
5426
|
+
if (arrayA.length > maxCompareLength) {
|
|
5427
|
+
return false;
|
|
5428
|
+
}
|
|
5429
|
+
for (let i = 0; i < arrayA.length; ++i) {
|
|
5430
|
+
if (arrayB[i] !== arrayA[i]) {
|
|
5431
|
+
return false;
|
|
3458
5432
|
}
|
|
3459
5433
|
}
|
|
3460
5434
|
return true;
|
|
@@ -3519,27 +5493,33 @@ ${htmlLog}
|
|
|
3519
5493
|
};
|
|
3520
5494
|
|
|
3521
5495
|
// src/portable/uniform-store.ts
|
|
5496
|
+
var minUniformBufferSize = 1024;
|
|
3522
5497
|
var UniformStore = class {
|
|
5498
|
+
/** Device used to infer layout and allocate buffers. */
|
|
5499
|
+
device;
|
|
3523
5500
|
/** Stores the uniform values for each uniform block */
|
|
3524
5501
|
uniformBlocks = /* @__PURE__ */ new Map();
|
|
3525
|
-
/**
|
|
3526
|
-
|
|
5502
|
+
/** Flattened layout metadata for each block. */
|
|
5503
|
+
shaderBlockLayouts = /* @__PURE__ */ new Map();
|
|
5504
|
+
/** Serializers for block-backed uniform data. */
|
|
5505
|
+
shaderBlockWriters = /* @__PURE__ */ new Map();
|
|
3527
5506
|
/** Actual buffer for the blocks */
|
|
3528
5507
|
uniformBuffers = /* @__PURE__ */ new Map();
|
|
3529
5508
|
/**
|
|
3530
|
-
*
|
|
3531
|
-
* @param blocks
|
|
5509
|
+
* Creates a new {@link UniformStore} for the supplied device and block definitions.
|
|
3532
5510
|
*/
|
|
3533
|
-
constructor(blocks) {
|
|
5511
|
+
constructor(device, blocks) {
|
|
5512
|
+
this.device = device;
|
|
3534
5513
|
for (const [bufferName, block] of Object.entries(blocks)) {
|
|
3535
5514
|
const uniformBufferName = bufferName;
|
|
3536
|
-
const
|
|
3537
|
-
block.
|
|
3538
|
-
|
|
3539
|
-
);
|
|
3540
|
-
this.
|
|
5515
|
+
const shaderBlockLayout = makeShaderBlockLayout(block.uniformTypes ?? {}, {
|
|
5516
|
+
layout: block.layout ?? getDefaultUniformBufferLayout(device)
|
|
5517
|
+
});
|
|
5518
|
+
const shaderBlockWriter = new ShaderBlockWriter(shaderBlockLayout);
|
|
5519
|
+
this.shaderBlockLayouts.set(uniformBufferName, shaderBlockLayout);
|
|
5520
|
+
this.shaderBlockWriters.set(uniformBufferName, shaderBlockWriter);
|
|
3541
5521
|
const uniformBlock = new UniformBlock({ name: bufferName });
|
|
3542
|
-
uniformBlock.setUniforms(block.defaultUniforms || {});
|
|
5522
|
+
uniformBlock.setUniforms(shaderBlockWriter.getFlatUniformValues(block.defaultUniforms || {}));
|
|
3543
5523
|
this.uniformBlocks.set(uniformBufferName, uniformBlock);
|
|
3544
5524
|
}
|
|
3545
5525
|
}
|
|
@@ -3551,33 +5531,51 @@ ${htmlLog}
|
|
|
3551
5531
|
}
|
|
3552
5532
|
/**
|
|
3553
5533
|
* Set uniforms
|
|
3554
|
-
*
|
|
5534
|
+
*
|
|
5535
|
+
* Makes all group properties partial and eagerly propagates changes to any
|
|
5536
|
+
* managed GPU buffers.
|
|
3555
5537
|
*/
|
|
3556
5538
|
setUniforms(uniforms) {
|
|
3557
5539
|
for (const [blockName, uniformValues] of Object.entries(uniforms)) {
|
|
3558
|
-
|
|
5540
|
+
const uniformBufferName = blockName;
|
|
5541
|
+
const shaderBlockWriter = this.shaderBlockWriters.get(uniformBufferName);
|
|
5542
|
+
const flattenedUniforms = shaderBlockWriter?.getFlatUniformValues(
|
|
5543
|
+
uniformValues || {}
|
|
5544
|
+
);
|
|
5545
|
+
this.uniformBlocks.get(uniformBufferName)?.setUniforms(flattenedUniforms || {});
|
|
3559
5546
|
}
|
|
3560
5547
|
this.updateUniformBuffers();
|
|
3561
5548
|
}
|
|
3562
|
-
/**
|
|
5549
|
+
/**
|
|
5550
|
+
* Returns the allocation size for the named uniform buffer.
|
|
5551
|
+
*
|
|
5552
|
+
* This may exceed the packed layout size because minimum buffer-size policy is
|
|
5553
|
+
* applied at the store layer.
|
|
5554
|
+
*/
|
|
3563
5555
|
getUniformBufferByteLength(uniformBufferName) {
|
|
3564
|
-
|
|
5556
|
+
const packedByteLength = this.shaderBlockLayouts.get(uniformBufferName)?.byteLength || 0;
|
|
5557
|
+
return Math.max(packedByteLength, minUniformBufferSize);
|
|
3565
5558
|
}
|
|
3566
|
-
/**
|
|
5559
|
+
/**
|
|
5560
|
+
* Returns packed binary data that can be uploaded to the named uniform buffer.
|
|
5561
|
+
*
|
|
5562
|
+
* The returned view length matches the packed block size and is not padded to
|
|
5563
|
+
* the store's minimum allocation size.
|
|
5564
|
+
*/
|
|
3567
5565
|
getUniformBufferData(uniformBufferName) {
|
|
3568
5566
|
const uniformValues = this.uniformBlocks.get(uniformBufferName)?.getAllUniforms() || {};
|
|
3569
|
-
|
|
5567
|
+
const shaderBlockWriter = this.shaderBlockWriters.get(uniformBufferName);
|
|
5568
|
+
return shaderBlockWriter?.getData(uniformValues) || new Uint8Array(0);
|
|
3570
5569
|
}
|
|
3571
5570
|
/**
|
|
3572
|
-
* Creates an unmanaged uniform buffer
|
|
3573
|
-
* The new buffer is initialized with current / supplied values
|
|
5571
|
+
* Creates an unmanaged uniform buffer initialized with the current or supplied values.
|
|
3574
5572
|
*/
|
|
3575
|
-
createUniformBuffer(
|
|
5573
|
+
createUniformBuffer(uniformBufferName, uniforms) {
|
|
3576
5574
|
if (uniforms) {
|
|
3577
5575
|
this.setUniforms(uniforms);
|
|
3578
5576
|
}
|
|
3579
5577
|
const byteLength = this.getUniformBufferByteLength(uniformBufferName);
|
|
3580
|
-
const uniformBuffer = device.createBuffer({
|
|
5578
|
+
const uniformBuffer = this.device.createBuffer({
|
|
3581
5579
|
usage: Buffer2.UNIFORM | Buffer2.COPY_DST,
|
|
3582
5580
|
byteLength
|
|
3583
5581
|
});
|
|
@@ -3585,11 +5583,11 @@ ${htmlLog}
|
|
|
3585
5583
|
uniformBuffer.write(uniformBufferData);
|
|
3586
5584
|
return uniformBuffer;
|
|
3587
5585
|
}
|
|
3588
|
-
/**
|
|
3589
|
-
getManagedUniformBuffer(
|
|
5586
|
+
/** Returns the managed uniform buffer for the named block. */
|
|
5587
|
+
getManagedUniformBuffer(uniformBufferName) {
|
|
3590
5588
|
if (!this.uniformBuffers.get(uniformBufferName)) {
|
|
3591
5589
|
const byteLength = this.getUniformBufferByteLength(uniformBufferName);
|
|
3592
|
-
const uniformBuffer = device.createBuffer({
|
|
5590
|
+
const uniformBuffer = this.device.createBuffer({
|
|
3593
5591
|
usage: Buffer2.UNIFORM | Buffer2.COPY_DST,
|
|
3594
5592
|
byteLength
|
|
3595
5593
|
});
|
|
@@ -3597,7 +5595,11 @@ ${htmlLog}
|
|
|
3597
5595
|
}
|
|
3598
5596
|
return this.uniformBuffers.get(uniformBufferName);
|
|
3599
5597
|
}
|
|
3600
|
-
/**
|
|
5598
|
+
/**
|
|
5599
|
+
* Updates every managed uniform buffer whose source uniforms have changed.
|
|
5600
|
+
*
|
|
5601
|
+
* @returns The first redraw reason encountered, or `false` if nothing changed.
|
|
5602
|
+
*/
|
|
3601
5603
|
updateUniformBuffers() {
|
|
3602
5604
|
let reason = false;
|
|
3603
5605
|
for (const uniformBufferName of this.uniformBlocks.keys()) {
|
|
@@ -3609,7 +5611,11 @@ ${htmlLog}
|
|
|
3609
5611
|
}
|
|
3610
5612
|
return reason;
|
|
3611
5613
|
}
|
|
3612
|
-
/**
|
|
5614
|
+
/**
|
|
5615
|
+
* Updates one managed uniform buffer if its corresponding block is dirty.
|
|
5616
|
+
*
|
|
5617
|
+
* @returns The redraw reason for the update, or `false` if no write occurred.
|
|
5618
|
+
*/
|
|
3613
5619
|
updateUniformBuffer(uniformBufferName) {
|
|
3614
5620
|
const uniformBlock = this.uniformBlocks.get(uniformBufferName);
|
|
3615
5621
|
let uniformBuffer = this.uniformBuffers.get(uniformBufferName);
|
|
@@ -3630,8 +5636,49 @@ ${htmlLog}
|
|
|
3630
5636
|
return reason;
|
|
3631
5637
|
}
|
|
3632
5638
|
};
|
|
5639
|
+
function getDefaultUniformBufferLayout(device) {
|
|
5640
|
+
return device.type === "webgpu" ? "wgsl-uniform" : "std140";
|
|
5641
|
+
}
|
|
5642
|
+
|
|
5643
|
+
// src/shadertypes/texture-types/texture-layout.ts
|
|
5644
|
+
function getTextureImageView(arrayBuffer2, memoryLayout, format, image = 0) {
|
|
5645
|
+
const formatInfo = textureFormatDecoder.getInfo(format);
|
|
5646
|
+
const bytesPerComponent = formatInfo.bytesPerPixel / formatInfo.components;
|
|
5647
|
+
const { bytesPerImage } = memoryLayout;
|
|
5648
|
+
const offset = bytesPerImage * image;
|
|
5649
|
+
const totalPixels = memoryLayout.bytesPerImage / bytesPerComponent;
|
|
5650
|
+
switch (format) {
|
|
5651
|
+
case "rgba8unorm":
|
|
5652
|
+
case "bgra8unorm":
|
|
5653
|
+
case "rgba8uint":
|
|
5654
|
+
return new Uint8Array(arrayBuffer2, offset, totalPixels);
|
|
5655
|
+
case "r8unorm":
|
|
5656
|
+
return new Uint8Array(arrayBuffer2, offset, totalPixels);
|
|
5657
|
+
case "r16uint":
|
|
5658
|
+
case "rgba16uint":
|
|
5659
|
+
return new Uint16Array(arrayBuffer2, offset, totalPixels);
|
|
5660
|
+
case "r32uint":
|
|
5661
|
+
case "rgba32uint":
|
|
5662
|
+
return new Uint32Array(arrayBuffer2, offset, totalPixels);
|
|
5663
|
+
case "r32float":
|
|
5664
|
+
return new Float32Array(arrayBuffer2, offset, totalPixels);
|
|
5665
|
+
case "rgba16float":
|
|
5666
|
+
return new Uint16Array(arrayBuffer2, offset, totalPixels);
|
|
5667
|
+
case "rgba32float":
|
|
5668
|
+
return new Float32Array(arrayBuffer2, offset, totalPixels);
|
|
5669
|
+
default:
|
|
5670
|
+
throw new Error(`Unsupported format: ${format}`);
|
|
5671
|
+
}
|
|
5672
|
+
}
|
|
5673
|
+
function setTextureImageData(arrayBuffer2, memoryLayout, format, data, image = 0) {
|
|
5674
|
+
const offset = 0;
|
|
5675
|
+
const totalPixels = memoryLayout.bytesPerImage / memoryLayout.bytesPerPixel;
|
|
5676
|
+
const subArray = data.subarray(0, totalPixels);
|
|
5677
|
+
const typedArray = getTextureImageView(arrayBuffer2, memoryLayout, format, image);
|
|
5678
|
+
typedArray.set(subArray, offset);
|
|
5679
|
+
}
|
|
3633
5680
|
|
|
3634
|
-
// src/shadertypes/
|
|
5681
|
+
// src/shadertypes/texture-types/pixel-utils.ts
|
|
3635
5682
|
function readPixel(pixelData, x, y, bitsPerChannel) {
|
|
3636
5683
|
if (x < 0 || x >= pixelData.width || y < 0 || y >= pixelData.height) {
|
|
3637
5684
|
throw new Error("Coordinates out of bounds.");
|
|
@@ -3641,7 +5688,7 @@ ${htmlLog}
|
|
|
3641
5688
|
let bitOffsetWithinPixel = 0;
|
|
3642
5689
|
const channels = [];
|
|
3643
5690
|
for (let i = 0; i < 4; i++) {
|
|
3644
|
-
const bits = bitsPerChannel[i];
|
|
5691
|
+
const bits = bitsPerChannel[i] ?? 0;
|
|
3645
5692
|
if (bits <= 0) {
|
|
3646
5693
|
channels.push(0);
|
|
3647
5694
|
} else {
|
|
@@ -3650,14 +5697,14 @@ ${htmlLog}
|
|
|
3650
5697
|
bitOffsetWithinPixel += bits;
|
|
3651
5698
|
}
|
|
3652
5699
|
}
|
|
3653
|
-
return [channels[0], channels[1], channels[2], channels[3]];
|
|
5700
|
+
return [channels[0] ?? 0, channels[1] ?? 0, channels[2] ?? 0, channels[3] ?? 0];
|
|
3654
5701
|
}
|
|
3655
5702
|
function writePixel(dataView, bitOffset, bitsPerChannel, pixel) {
|
|
3656
5703
|
let currentBitOffset = bitOffset;
|
|
3657
5704
|
for (let channel = 0; channel < 4; channel++) {
|
|
3658
|
-
const bits = bitsPerChannel[channel];
|
|
5705
|
+
const bits = bitsPerChannel[channel] ?? 0;
|
|
3659
5706
|
const maxValue = (1 << bits) - 1;
|
|
3660
|
-
const channelValue = pixel[channel] & maxValue;
|
|
5707
|
+
const channelValue = (pixel[channel] ?? 0) & maxValue;
|
|
3661
5708
|
writeBitsToDataView(dataView, currentBitOffset, bits, channelValue);
|
|
3662
5709
|
currentBitOffset += bits;
|
|
3663
5710
|
}
|