@luma.gl/core 9.2.6 → 9.3.0-alpha.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/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 +193 -11
- package/dist/adapter/device.js.map +1 -1
- package/dist/adapter/luma.d.ts.map +1 -1
- package/dist/adapter/luma.js +2 -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 +1 -1
- package/dist/adapter/resources/buffer.d.ts.map +1 -1
- package/dist/adapter/resources/buffer.js +14 -6
- 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 +2734 -644
- 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 +88 -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 +2447 -534
- 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 +4 -3
- 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 +110 -38
- 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 +12 -11
- 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 +144 -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 +311 -25
- package/src/adapter/luma.ts +1 -0
- package/src/adapter/presentation-context.ts +16 -0
- package/src/adapter/resources/buffer.ts +13 -5
- 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 +157 -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 +4 -3
- 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 +167 -46
- package/src/shadertypes/{textures → texture-types}/texture-format-generics.ts +42 -48
- package/src/shadertypes/{textures → texture-types}/texture-format-table.ts +12 -11
- 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 +175 -0
- package/src/shadertypes/vertex-types/vertex-formats.ts +196 -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 {
|
|
@@ -897,18 +1276,26 @@ var __exports__ = (() => {
|
|
|
897
1276
|
/** A partial CPU-side copy of the data in this buffer, for debugging purposes */
|
|
898
1277
|
debugData = new ArrayBuffer(0);
|
|
899
1278
|
/** This doesn't handle partial non-zero offset updates correctly */
|
|
900
|
-
_setDebugData(data,
|
|
901
|
-
|
|
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
|
+
}
|
|
902
1288
|
const debugDataLength = Math.min(
|
|
903
1289
|
data ? data.byteLength : byteLength,
|
|
904
1290
|
_Buffer.DEBUG_DATA_MAX_LENGTH
|
|
905
1291
|
);
|
|
906
1292
|
if (arrayBuffer2 === null) {
|
|
907
1293
|
this.debugData = new ArrayBuffer(debugDataLength);
|
|
908
|
-
} else if (byteOffset === 0 && byteLength === arrayBuffer2.byteLength) {
|
|
909
|
-
this.debugData = arrayBuffer2.slice(0, debugDataLength);
|
|
910
1294
|
} else {
|
|
911
|
-
|
|
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;
|
|
912
1299
|
}
|
|
913
1300
|
}
|
|
914
1301
|
};
|
|
@@ -942,61 +1329,73 @@ var __exports__ = (() => {
|
|
|
942
1329
|
onMapped: void 0
|
|
943
1330
|
});
|
|
944
1331
|
|
|
945
|
-
// src/shadertypes/data-types/
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
signedType,
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
case "sint8":
|
|
966
|
-
return "snorm8";
|
|
967
|
-
case "uint16":
|
|
968
|
-
return "unorm16";
|
|
969
|
-
case "sint16":
|
|
970
|
-
return "snorm16";
|
|
971
|
-
default:
|
|
972
|
-
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
|
+
};
|
|
973
1352
|
}
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
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
|
+
}
|
|
983
1368
|
}
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
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
|
+
}
|
|
989
1379
|
}
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
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];
|
|
993
1391
|
}
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
}
|
|
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();
|
|
1000
1399
|
var NORMALIZED_TYPE_MAP = {
|
|
1001
1400
|
uint8: ["uint8", "u32", 1, false, Uint8Array],
|
|
1002
1401
|
sint8: ["sint8", "i32", 1, false, Int8Array],
|
|
@@ -1012,87 +1411,138 @@ var __exports__ = (() => {
|
|
|
1012
1411
|
sint32: ["sint32", "i32", 4, false, Int32Array]
|
|
1013
1412
|
};
|
|
1014
1413
|
|
|
1015
|
-
// src/shadertypes/vertex-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
type
|
|
1028
|
-
components
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
case "unorm8":
|
|
1043
|
-
if (components === 1) {
|
|
1044
|
-
return "unorm8";
|
|
1045
|
-
}
|
|
1046
|
-
if (components === 3) {
|
|
1047
|
-
return "unorm8x3-webgl";
|
|
1048
|
-
}
|
|
1049
|
-
return `${dataType}x${components}`;
|
|
1050
|
-
case "snorm8":
|
|
1051
|
-
case "uint8":
|
|
1052
|
-
case "sint8":
|
|
1053
|
-
case "uint16":
|
|
1054
|
-
case "sint16":
|
|
1055
|
-
case "unorm16":
|
|
1056
|
-
case "snorm16":
|
|
1057
|
-
case "float16":
|
|
1058
|
-
if (components === 1 || components === 3) {
|
|
1059
|
-
throw new Error(`size: ${components}`);
|
|
1060
|
-
}
|
|
1061
|
-
return `${dataType}x${components}`;
|
|
1062
|
-
default:
|
|
1063
|
-
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;
|
|
1064
1441
|
}
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
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
|
+
if (components === 1) {
|
|
1456
|
+
return "snorm8";
|
|
1457
|
+
}
|
|
1458
|
+
if (components === 3) {
|
|
1459
|
+
return "snorm8x3-webgl";
|
|
1460
|
+
}
|
|
1461
|
+
return `${dataType}x${components}`;
|
|
1462
|
+
case "uint8":
|
|
1463
|
+
case "sint8":
|
|
1464
|
+
if (components === 1 || components === 3) {
|
|
1465
|
+
throw new Error(`size: ${components}`);
|
|
1466
|
+
}
|
|
1467
|
+
return `${dataType}x${components}`;
|
|
1468
|
+
case "uint16":
|
|
1469
|
+
if (components === 1) {
|
|
1470
|
+
return "uint16";
|
|
1471
|
+
}
|
|
1472
|
+
if (components === 3) {
|
|
1473
|
+
return "uint16x3-webgl";
|
|
1474
|
+
}
|
|
1475
|
+
return `${dataType}x${components}`;
|
|
1476
|
+
case "sint16":
|
|
1477
|
+
if (components === 1) {
|
|
1478
|
+
return "sint16";
|
|
1479
|
+
}
|
|
1480
|
+
if (components === 3) {
|
|
1481
|
+
return "sint16x3-webgl";
|
|
1482
|
+
}
|
|
1483
|
+
return `${dataType}x${components}`;
|
|
1484
|
+
case "unorm16":
|
|
1485
|
+
if (components === 1) {
|
|
1486
|
+
return "unorm16";
|
|
1487
|
+
}
|
|
1488
|
+
if (components === 3) {
|
|
1489
|
+
return "unorm16x3-webgl";
|
|
1490
|
+
}
|
|
1491
|
+
return `${dataType}x${components}`;
|
|
1492
|
+
case "snorm16":
|
|
1493
|
+
if (components === 1) {
|
|
1494
|
+
return "snorm16";
|
|
1495
|
+
}
|
|
1496
|
+
if (components === 3) {
|
|
1497
|
+
return "snorm16x3-webgl";
|
|
1498
|
+
}
|
|
1499
|
+
return `${dataType}x${components}`;
|
|
1500
|
+
case "float16":
|
|
1501
|
+
if (components === 1 || components === 3) {
|
|
1502
|
+
throw new Error(`size: ${components}`);
|
|
1503
|
+
}
|
|
1504
|
+
return `${dataType}x${components}`;
|
|
1505
|
+
default:
|
|
1506
|
+
return components === 1 ? dataType : `${dataType}x${components}`;
|
|
1507
|
+
}
|
|
1069
1508
|
}
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
vertexType = "float32";
|
|
1079
|
-
break;
|
|
1080
|
-
case "i32":
|
|
1081
|
-
vertexType = "sint32";
|
|
1082
|
-
break;
|
|
1083
|
-
case "u32":
|
|
1084
|
-
vertexType = "uint32";
|
|
1085
|
-
break;
|
|
1086
|
-
case "f16":
|
|
1087
|
-
return opts.components <= 2 ? "float16x2" : "float16x4";
|
|
1509
|
+
/** Get the vertex format for an attribute with TypedArray and size */
|
|
1510
|
+
getVertexFormatFromAttribute(typedArray, size, normalized) {
|
|
1511
|
+
if (!size || size > 4) {
|
|
1512
|
+
throw new Error(`size ${size}`);
|
|
1513
|
+
}
|
|
1514
|
+
const components = size;
|
|
1515
|
+
const signedDataType = dataTypeDecoder.getDataType(typedArray);
|
|
1516
|
+
return this.makeVertexFormat(signedDataType, components, normalized);
|
|
1088
1517
|
}
|
|
1089
|
-
|
|
1090
|
-
|
|
1518
|
+
/**
|
|
1519
|
+
* Return a "default" vertex format for a certain shader data type
|
|
1520
|
+
* The simplest vertex format that matches the shader attribute's data type
|
|
1521
|
+
*/
|
|
1522
|
+
getCompatibleVertexFormat(opts) {
|
|
1523
|
+
let vertexType;
|
|
1524
|
+
switch (opts.primitiveType) {
|
|
1525
|
+
case "f32":
|
|
1526
|
+
vertexType = "float32";
|
|
1527
|
+
break;
|
|
1528
|
+
case "i32":
|
|
1529
|
+
vertexType = "sint32";
|
|
1530
|
+
break;
|
|
1531
|
+
case "u32":
|
|
1532
|
+
vertexType = "uint32";
|
|
1533
|
+
break;
|
|
1534
|
+
case "f16":
|
|
1535
|
+
return opts.components <= 2 ? "float16x2" : "float16x4";
|
|
1536
|
+
}
|
|
1537
|
+
if (opts.components === 1) {
|
|
1538
|
+
return vertexType;
|
|
1539
|
+
}
|
|
1540
|
+
return `${vertexType}x${opts.components}`;
|
|
1091
1541
|
}
|
|
1092
|
-
|
|
1093
|
-
|
|
1542
|
+
};
|
|
1543
|
+
var vertexFormatDecoder = new VertexFormatDecoder();
|
|
1094
1544
|
|
|
1095
|
-
// src/shadertypes/
|
|
1545
|
+
// src/shadertypes/texture-types/texture-format-table.ts
|
|
1096
1546
|
var texture_compression_bc = "texture-compression-bc";
|
|
1097
1547
|
var texture_compression_astc = "texture-compression-astc";
|
|
1098
1548
|
var texture_compression_etc2 = "texture-compression-etc2";
|
|
@@ -1103,6 +1553,7 @@ var __exports__ = (() => {
|
|
|
1103
1553
|
var float16_renderable = "float16-renderable-webgl";
|
|
1104
1554
|
var rgb9e5ufloat_renderable = "rgb9e5ufloat-renderable-webgl";
|
|
1105
1555
|
var snorm8_renderable = "snorm8-renderable-webgl";
|
|
1556
|
+
var norm16_webgl = "norm16-webgl";
|
|
1106
1557
|
var norm16_renderable = "norm16-renderable-webgl";
|
|
1107
1558
|
var snorm16_renderable = "snorm16-renderable-webgl";
|
|
1108
1559
|
var float32_filterable = "float32-filterable";
|
|
@@ -1136,16 +1587,16 @@ var __exports__ = (() => {
|
|
|
1136
1587
|
"rgba8sint": {},
|
|
1137
1588
|
"bgra8unorm": {},
|
|
1138
1589
|
"bgra8unorm-srgb": {},
|
|
1139
|
-
"r16unorm": { f: norm16_renderable },
|
|
1140
|
-
"rg16unorm": { render: norm16_renderable },
|
|
1141
|
-
"rgb16unorm-webgl": { f:
|
|
1590
|
+
"r16unorm": { f: norm16_webgl, render: norm16_renderable },
|
|
1591
|
+
"rg16unorm": { f: norm16_webgl, render: norm16_renderable },
|
|
1592
|
+
"rgb16unorm-webgl": { f: norm16_webgl, render: false },
|
|
1142
1593
|
// rgb not renderable
|
|
1143
|
-
"rgba16unorm": { render: norm16_renderable },
|
|
1144
|
-
"r16snorm": { f: snorm16_renderable },
|
|
1145
|
-
"rg16snorm": { render: snorm16_renderable },
|
|
1146
|
-
"rgb16snorm-webgl": { f:
|
|
1594
|
+
"rgba16unorm": { f: norm16_webgl, render: norm16_renderable },
|
|
1595
|
+
"r16snorm": { f: norm16_webgl, render: snorm16_renderable },
|
|
1596
|
+
"rg16snorm": { f: norm16_webgl, render: snorm16_renderable },
|
|
1597
|
+
"rgb16snorm-webgl": { f: norm16_webgl, render: false },
|
|
1147
1598
|
// rgb not renderable
|
|
1148
|
-
"rgba16snorm": { render: snorm16_renderable },
|
|
1599
|
+
"rgba16snorm": { f: norm16_webgl, render: snorm16_renderable },
|
|
1149
1600
|
"r16uint": {},
|
|
1150
1601
|
"rg16uint": {},
|
|
1151
1602
|
"rgba16uint": {},
|
|
@@ -1248,7 +1699,7 @@ var __exports__ = (() => {
|
|
|
1248
1699
|
// WEBGL_compressed_texture_pvrtc
|
|
1249
1700
|
"pvrtc-rgb4unorm-webgl": { f: texture_compression_pvrtc_webgl },
|
|
1250
1701
|
"pvrtc-rgba4unorm-webgl": { f: texture_compression_pvrtc_webgl },
|
|
1251
|
-
"pvrtc-
|
|
1702
|
+
"pvrtc-rgb2unorm-webgl": { f: texture_compression_pvrtc_webgl },
|
|
1252
1703
|
"pvrtc-rgba2unorm-webgl": { f: texture_compression_pvrtc_webgl },
|
|
1253
1704
|
// WEBGL_compressed_texture_etc1
|
|
1254
1705
|
"etc1-rbg-unorm-webgl": { f: texture_compression_etc1_webgl },
|
|
@@ -1262,7 +1713,10 @@ var __exports__ = (() => {
|
|
|
1262
1713
|
...TEXTURE_FORMAT_COMPRESSED_TABLE
|
|
1263
1714
|
};
|
|
1264
1715
|
|
|
1265
|
-
// src/shadertypes/
|
|
1716
|
+
// src/shadertypes/texture-types/texture-format-decoder.ts
|
|
1717
|
+
var RGB_FORMAT_REGEX = /^(r|rg|rgb|rgba|bgra)([0-9]*)([a-z]*)(-srgb)?(-webgl)?$/;
|
|
1718
|
+
var COLOR_FORMAT_PREFIXES = ["rgb", "rgba", "bgra"];
|
|
1719
|
+
var DEPTH_FORMAT_PREFIXES = ["depth", "stencil"];
|
|
1266
1720
|
var COMPRESSED_TEXTURE_FORMAT_PREFIXES = [
|
|
1267
1721
|
"bc1",
|
|
1268
1722
|
"bc2",
|
|
@@ -1278,49 +1732,83 @@ var __exports__ = (() => {
|
|
|
1278
1732
|
"astc",
|
|
1279
1733
|
"pvrtc"
|
|
1280
1734
|
];
|
|
1281
|
-
var RGB_FORMAT_REGEX = /^(r|rg|rgb|rgba|bgra)([0-9]*)([a-z]*)(-srgb)?(-webgl)?$/;
|
|
1282
1735
|
var TextureFormatDecoder = class {
|
|
1283
|
-
/** Returns information about a texture format, e.g. attatchment type, components, byte length and flags (integer, signed, normalized) */
|
|
1284
|
-
getInfo(format) {
|
|
1285
|
-
return getTextureFormatInfo(format);
|
|
1286
|
-
}
|
|
1287
1736
|
/** Checks if a texture format is color */
|
|
1288
1737
|
isColor(format) {
|
|
1289
|
-
return
|
|
1738
|
+
return COLOR_FORMAT_PREFIXES.some((prefix) => format.startsWith(prefix));
|
|
1290
1739
|
}
|
|
1291
1740
|
/** Checks if a texture format is depth or stencil */
|
|
1292
1741
|
isDepthStencil(format) {
|
|
1293
|
-
return
|
|
1742
|
+
return DEPTH_FORMAT_PREFIXES.some((prefix) => format.startsWith(prefix));
|
|
1294
1743
|
}
|
|
1295
1744
|
/** Checks if a texture format is compressed */
|
|
1296
1745
|
isCompressed(format) {
|
|
1297
1746
|
return COMPRESSED_TEXTURE_FORMAT_PREFIXES.some((prefix) => format.startsWith(prefix));
|
|
1298
1747
|
}
|
|
1299
|
-
/**
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1748
|
+
/** Returns information about a texture format, e.g. attachment type, components, byte length and flags (integer, signed, normalized) */
|
|
1749
|
+
getInfo(format) {
|
|
1750
|
+
return getTextureFormatInfo(format);
|
|
1751
|
+
}
|
|
1752
|
+
/** "static" capabilities of a texture format. @note Needs to be adjusted against current device */
|
|
1303
1753
|
getCapabilities(format) {
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
filter: info.filter ?? true,
|
|
1310
|
-
blend: info.blend ?? true,
|
|
1311
|
-
store: info.store ?? true
|
|
1312
|
-
};
|
|
1313
|
-
const formatInfo = getTextureFormatInfo(format);
|
|
1314
|
-
const isDepthStencil = format.startsWith("depth") || format.startsWith("stencil");
|
|
1315
|
-
const isSigned = formatInfo?.signed;
|
|
1316
|
-
const isInteger = formatInfo?.integer;
|
|
1317
|
-
const isWebGLSpecific = formatInfo?.webgl;
|
|
1318
|
-
formatCapabilities.render &&= !isSigned;
|
|
1319
|
-
formatCapabilities.filter &&= !isDepthStencil && !isSigned && !isInteger && !isWebGLSpecific;
|
|
1320
|
-
return formatCapabilities;
|
|
1754
|
+
return getTextureFormatCapabilities(format);
|
|
1755
|
+
}
|
|
1756
|
+
/** Computes the memory layout for a texture, in particular including row byte alignment */
|
|
1757
|
+
computeMemoryLayout(opts) {
|
|
1758
|
+
return computeTextureMemoryLayout(opts);
|
|
1321
1759
|
}
|
|
1322
1760
|
};
|
|
1323
1761
|
var textureFormatDecoder = new TextureFormatDecoder();
|
|
1762
|
+
function computeTextureMemoryLayout({
|
|
1763
|
+
format,
|
|
1764
|
+
width,
|
|
1765
|
+
height,
|
|
1766
|
+
depth,
|
|
1767
|
+
byteAlignment
|
|
1768
|
+
}) {
|
|
1769
|
+
const formatInfo = textureFormatDecoder.getInfo(format);
|
|
1770
|
+
const {
|
|
1771
|
+
bytesPerPixel,
|
|
1772
|
+
bytesPerBlock = bytesPerPixel,
|
|
1773
|
+
blockWidth = 1,
|
|
1774
|
+
blockHeight = 1,
|
|
1775
|
+
compressed = false
|
|
1776
|
+
} = formatInfo;
|
|
1777
|
+
const blockColumns = compressed ? Math.ceil(width / blockWidth) : width;
|
|
1778
|
+
const blockRows = compressed ? Math.ceil(height / blockHeight) : height;
|
|
1779
|
+
const unpaddedBytesPerRow = blockColumns * bytesPerBlock;
|
|
1780
|
+
const bytesPerRow = Math.ceil(unpaddedBytesPerRow / byteAlignment) * byteAlignment;
|
|
1781
|
+
const rowsPerImage = blockRows;
|
|
1782
|
+
const byteLength = bytesPerRow * rowsPerImage * depth;
|
|
1783
|
+
return {
|
|
1784
|
+
bytesPerPixel,
|
|
1785
|
+
bytesPerRow,
|
|
1786
|
+
rowsPerImage,
|
|
1787
|
+
depthOrArrayLayers: depth,
|
|
1788
|
+
bytesPerImage: bytesPerRow * rowsPerImage,
|
|
1789
|
+
byteLength
|
|
1790
|
+
};
|
|
1791
|
+
}
|
|
1792
|
+
function getTextureFormatCapabilities(format) {
|
|
1793
|
+
const info = getTextureFormatDefinition(format);
|
|
1794
|
+
const formatCapabilities = {
|
|
1795
|
+
format,
|
|
1796
|
+
create: info.f ?? true,
|
|
1797
|
+
render: info.render ?? true,
|
|
1798
|
+
filter: info.filter ?? true,
|
|
1799
|
+
blend: info.blend ?? true,
|
|
1800
|
+
store: info.store ?? true
|
|
1801
|
+
};
|
|
1802
|
+
const formatInfo = getTextureFormatInfo(format);
|
|
1803
|
+
const isDepthStencil = format.startsWith("depth") || format.startsWith("stencil");
|
|
1804
|
+
const isSigned = formatInfo?.signed;
|
|
1805
|
+
const isInteger = formatInfo?.integer;
|
|
1806
|
+
const isWebGLSpecific = formatInfo?.webgl;
|
|
1807
|
+
const isCompressed = Boolean(formatInfo?.compressed);
|
|
1808
|
+
formatCapabilities.render &&= !isDepthStencil && !isCompressed;
|
|
1809
|
+
formatCapabilities.filter &&= !isDepthStencil && !isSigned && !isInteger && !isWebGLSpecific;
|
|
1810
|
+
return formatCapabilities;
|
|
1811
|
+
}
|
|
1324
1812
|
function getTextureFormatInfo(format) {
|
|
1325
1813
|
let formatInfo = getTextureFormatInfoUsingTable(format);
|
|
1326
1814
|
if (textureFormatDecoder.isCompressed(format)) {
|
|
@@ -1329,19 +1817,20 @@ var __exports__ = (() => {
|
|
|
1329
1817
|
formatInfo.bytesPerPixel = 1;
|
|
1330
1818
|
formatInfo.srgb = false;
|
|
1331
1819
|
formatInfo.compressed = true;
|
|
1820
|
+
formatInfo.bytesPerBlock = getCompressedTextureBlockByteLength(format);
|
|
1332
1821
|
const blockSize = getCompressedTextureBlockSize(format);
|
|
1333
1822
|
if (blockSize) {
|
|
1334
1823
|
formatInfo.blockWidth = blockSize.blockWidth;
|
|
1335
1824
|
formatInfo.blockHeight = blockSize.blockHeight;
|
|
1336
1825
|
}
|
|
1337
1826
|
}
|
|
1338
|
-
const matches = RGB_FORMAT_REGEX.exec(format);
|
|
1827
|
+
const matches = !formatInfo.packed ? RGB_FORMAT_REGEX.exec(format) : null;
|
|
1339
1828
|
if (matches) {
|
|
1340
1829
|
const [, channels, length, type, srgb, suffix] = matches;
|
|
1341
1830
|
const dataType = `${type}${length}`;
|
|
1342
|
-
const decodedType = getDataTypeInfo(dataType);
|
|
1831
|
+
const decodedType = dataTypeDecoder.getDataTypeInfo(dataType);
|
|
1343
1832
|
const bits = decodedType.byteLength * 8;
|
|
1344
|
-
const components = channels
|
|
1833
|
+
const components = channels?.length ?? 1;
|
|
1345
1834
|
const bitsPerChannel = [
|
|
1346
1835
|
bits,
|
|
1347
1836
|
components >= 2 ? bits : 0,
|
|
@@ -1358,7 +1847,7 @@ var __exports__ = (() => {
|
|
|
1358
1847
|
signed: decodedType.signed,
|
|
1359
1848
|
normalized: decodedType.normalized,
|
|
1360
1849
|
bitsPerChannel,
|
|
1361
|
-
bytesPerPixel: decodedType.byteLength *
|
|
1850
|
+
bytesPerPixel: decodedType.byteLength * components,
|
|
1362
1851
|
packed: formatInfo.packed,
|
|
1363
1852
|
srgb: formatInfo.srgb
|
|
1364
1853
|
};
|
|
@@ -1414,10 +1903,31 @@ var __exports__ = (() => {
|
|
|
1414
1903
|
const [, blockWidth, blockHeight] = matches;
|
|
1415
1904
|
return { blockWidth: Number(blockWidth), blockHeight: Number(blockHeight) };
|
|
1416
1905
|
}
|
|
1906
|
+
if (format.startsWith("bc") || format.startsWith("etc1") || format.startsWith("etc2") || format.startsWith("eac") || format.startsWith("atc")) {
|
|
1907
|
+
return { blockWidth: 4, blockHeight: 4 };
|
|
1908
|
+
}
|
|
1909
|
+
if (format.startsWith("pvrtc-rgb4") || format.startsWith("pvrtc-rgba4")) {
|
|
1910
|
+
return { blockWidth: 4, blockHeight: 4 };
|
|
1911
|
+
}
|
|
1912
|
+
if (format.startsWith("pvrtc-rgb2") || format.startsWith("pvrtc-rgba2")) {
|
|
1913
|
+
return { blockWidth: 8, blockHeight: 4 };
|
|
1914
|
+
}
|
|
1417
1915
|
return null;
|
|
1418
1916
|
}
|
|
1917
|
+
function getCompressedTextureBlockByteLength(format) {
|
|
1918
|
+
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") {
|
|
1919
|
+
return 8;
|
|
1920
|
+
}
|
|
1921
|
+
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") {
|
|
1922
|
+
return 16;
|
|
1923
|
+
}
|
|
1924
|
+
if (format.startsWith("pvrtc")) {
|
|
1925
|
+
return 8;
|
|
1926
|
+
}
|
|
1927
|
+
return 16;
|
|
1928
|
+
}
|
|
1419
1929
|
|
|
1420
|
-
// src/image-
|
|
1930
|
+
// src/shadertypes/image-types/image-types.ts
|
|
1421
1931
|
function isExternalImage(data) {
|
|
1422
1932
|
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;
|
|
1423
1933
|
}
|
|
@@ -1440,6 +1950,52 @@ var __exports__ = (() => {
|
|
|
1440
1950
|
// src/adapter/device.ts
|
|
1441
1951
|
var DeviceLimits = class {
|
|
1442
1952
|
};
|
|
1953
|
+
function formatErrorLogArguments(context, args) {
|
|
1954
|
+
const formattedContext = formatErrorLogValue(context);
|
|
1955
|
+
const formattedArgs = args.map(formatErrorLogValue).filter((arg) => arg !== void 0);
|
|
1956
|
+
return [formattedContext, ...formattedArgs].filter((arg) => arg !== void 0);
|
|
1957
|
+
}
|
|
1958
|
+
function formatErrorLogValue(value) {
|
|
1959
|
+
if (value === void 0) {
|
|
1960
|
+
return void 0;
|
|
1961
|
+
}
|
|
1962
|
+
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
1963
|
+
return value;
|
|
1964
|
+
}
|
|
1965
|
+
if (value instanceof Error) {
|
|
1966
|
+
return value.message;
|
|
1967
|
+
}
|
|
1968
|
+
if (Array.isArray(value)) {
|
|
1969
|
+
return value.map(formatErrorLogValue);
|
|
1970
|
+
}
|
|
1971
|
+
if (typeof value === "object") {
|
|
1972
|
+
if (hasCustomToString(value)) {
|
|
1973
|
+
const stringValue = String(value);
|
|
1974
|
+
if (stringValue !== "[object Object]") {
|
|
1975
|
+
return stringValue;
|
|
1976
|
+
}
|
|
1977
|
+
}
|
|
1978
|
+
if (looksLikeGPUCompilationMessage(value)) {
|
|
1979
|
+
return formatGPUCompilationMessage(value);
|
|
1980
|
+
}
|
|
1981
|
+
return value.constructor?.name || "Object";
|
|
1982
|
+
}
|
|
1983
|
+
return String(value);
|
|
1984
|
+
}
|
|
1985
|
+
function hasCustomToString(value) {
|
|
1986
|
+
return "toString" in value && typeof value.toString === "function" && value.toString !== Object.prototype.toString;
|
|
1987
|
+
}
|
|
1988
|
+
function looksLikeGPUCompilationMessage(value) {
|
|
1989
|
+
return "message" in value && "type" in value;
|
|
1990
|
+
}
|
|
1991
|
+
function formatGPUCompilationMessage(value) {
|
|
1992
|
+
const type = typeof value.type === "string" ? value.type : "message";
|
|
1993
|
+
const message = typeof value.message === "string" ? value.message : "";
|
|
1994
|
+
const lineNum = typeof value.lineNum === "number" ? value.lineNum : null;
|
|
1995
|
+
const linePos = typeof value.linePos === "number" ? value.linePos : null;
|
|
1996
|
+
const location = lineNum !== null && linePos !== null ? ` @ ${lineNum}:${linePos}` : lineNum !== null ? ` @ ${lineNum}` : "";
|
|
1997
|
+
return `${type}${location}: ${message}`.trim();
|
|
1998
|
+
}
|
|
1443
1999
|
var DeviceFeatures = class {
|
|
1444
2000
|
features;
|
|
1445
2001
|
disabledFeatures;
|
|
@@ -1469,19 +2025,24 @@ var __exports__ = (() => {
|
|
|
1469
2025
|
userData = {};
|
|
1470
2026
|
/** stats */
|
|
1471
2027
|
statsManager = lumaStats;
|
|
2028
|
+
/** Internal per-device factory storage */
|
|
2029
|
+
_factories = {};
|
|
1472
2030
|
/** An abstract timestamp used for change tracking */
|
|
1473
2031
|
timestamp = 0;
|
|
1474
2032
|
/** True if this device has been reused during device creation (app has multiple references) */
|
|
1475
2033
|
_reused = false;
|
|
1476
2034
|
/** Used by other luma.gl modules to store data on the device */
|
|
1477
|
-
|
|
2035
|
+
_moduleData = {};
|
|
1478
2036
|
_textureCaps = {};
|
|
2037
|
+
/** Internal timestamp query set used when GPU timing collection is enabled for this device. */
|
|
2038
|
+
_debugGPUTimeQuery = null;
|
|
1479
2039
|
constructor(props) {
|
|
1480
2040
|
this.props = { ..._Device.defaultProps, ...props };
|
|
1481
2041
|
this.id = this.props.id || uid(this[Symbol.toStringTag].toLowerCase());
|
|
1482
2042
|
}
|
|
2043
|
+
// TODO - just expose the shadertypes decoders?
|
|
1483
2044
|
getVertexFormatInfo(format) {
|
|
1484
|
-
return getVertexFormatInfo(format);
|
|
2045
|
+
return vertexFormatDecoder.getVertexFormatInfo(format);
|
|
1485
2046
|
}
|
|
1486
2047
|
isVertexFormatSupported(format) {
|
|
1487
2048
|
return true;
|
|
@@ -1529,6 +2090,16 @@ var __exports__ = (() => {
|
|
|
1529
2090
|
isTextureFormatCompressed(format) {
|
|
1530
2091
|
return textureFormatDecoder.isCompressed(format);
|
|
1531
2092
|
}
|
|
2093
|
+
/** Returns the compressed texture formats that can be created and sampled on this device */
|
|
2094
|
+
getSupportedCompressedTextureFormats() {
|
|
2095
|
+
const supportedFormats = [];
|
|
2096
|
+
for (const format of Object.keys(getTextureFormatTable())) {
|
|
2097
|
+
if (this.isTextureFormatCompressed(format) && this.isTextureFormatSupported(format)) {
|
|
2098
|
+
supportedFormats.push(format);
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
return supportedFormats;
|
|
2102
|
+
}
|
|
1532
2103
|
// DEBUG METHODS
|
|
1533
2104
|
pushDebugGroup(groupLabel) {
|
|
1534
2105
|
this.commandEncoder.pushDebugGroup(groupLabel);
|
|
@@ -1571,7 +2142,13 @@ var __exports__ = (() => {
|
|
|
1571
2142
|
reportError(error, context, ...args) {
|
|
1572
2143
|
const isHandled = this.props.onError(error, context);
|
|
1573
2144
|
if (!isHandled) {
|
|
1574
|
-
|
|
2145
|
+
const logArguments = formatErrorLogArguments(context, args);
|
|
2146
|
+
return log.error(
|
|
2147
|
+
this.type === "webgl" ? "%cWebGL" : "%cWebGPU",
|
|
2148
|
+
"color: white; background: red; padding: 2px 6px; border-radius: 3px;",
|
|
2149
|
+
error.message,
|
|
2150
|
+
...logArguments
|
|
2151
|
+
);
|
|
1575
2152
|
}
|
|
1576
2153
|
return () => {
|
|
1577
2154
|
};
|
|
@@ -1593,6 +2170,10 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1593
2170
|
}
|
|
1594
2171
|
return this.canvasContext;
|
|
1595
2172
|
}
|
|
2173
|
+
/** Create a fence sync object */
|
|
2174
|
+
createFence() {
|
|
2175
|
+
throw new Error("createFence() not implemented");
|
|
2176
|
+
}
|
|
1596
2177
|
/** Create a RenderPass using the default CommandEncoder */
|
|
1597
2178
|
beginRenderPass(props) {
|
|
1598
2179
|
return this.commandEncoder.beginRenderPass(props);
|
|
@@ -1601,6 +2182,78 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1601
2182
|
beginComputePass(props) {
|
|
1602
2183
|
return this.commandEncoder.beginComputePass(props);
|
|
1603
2184
|
}
|
|
2185
|
+
/**
|
|
2186
|
+
* Generate mipmaps for a WebGPU texture.
|
|
2187
|
+
* WebGPU textures must be created up front with the required mip count, usage flags, and a format that supports the chosen generation path.
|
|
2188
|
+
* WebGL uses `Texture.generateMipmapsWebGL()` directly because the backend manages mip generation on the texture object itself.
|
|
2189
|
+
*/
|
|
2190
|
+
generateMipmapsWebGPU(_texture) {
|
|
2191
|
+
throw new Error("not implemented");
|
|
2192
|
+
}
|
|
2193
|
+
/** Internal helper for creating a shareable WebGL render-pipeline implementation. */
|
|
2194
|
+
_createSharedRenderPipelineWebGL(_props) {
|
|
2195
|
+
throw new Error("_createSharedRenderPipelineWebGL() not implemented");
|
|
2196
|
+
}
|
|
2197
|
+
/** Internal WebGPU-only helper for retrieving the native bind-group layout for a pipeline group. */
|
|
2198
|
+
_createBindGroupLayoutWebGPU(_pipeline, _group) {
|
|
2199
|
+
throw new Error("_createBindGroupLayoutWebGPU() not implemented");
|
|
2200
|
+
}
|
|
2201
|
+
/** Internal WebGPU-only helper for creating a native bind group. */
|
|
2202
|
+
_createBindGroupWebGPU(_bindGroupLayout, _shaderLayout, _bindings, _group, _label) {
|
|
2203
|
+
throw new Error("_createBindGroupWebGPU() not implemented");
|
|
2204
|
+
}
|
|
2205
|
+
/**
|
|
2206
|
+
* Internal helper that returns `true` when timestamp-query GPU timing should be
|
|
2207
|
+
* collected for this device.
|
|
2208
|
+
*/
|
|
2209
|
+
_supportsDebugGPUTime() {
|
|
2210
|
+
return this.features.has("timestamp-query") && Boolean(this.props.debug || this.props.debugGPUTime);
|
|
2211
|
+
}
|
|
2212
|
+
/**
|
|
2213
|
+
* Internal helper that enables device-managed GPU timing collection on the
|
|
2214
|
+
* default command encoder. Reuses the existing query set if timing is already enabled.
|
|
2215
|
+
*
|
|
2216
|
+
* @param queryCount - Number of timestamp slots reserved for profiled passes.
|
|
2217
|
+
* @returns The device-managed timestamp QuerySet, or `null` when timing is not supported or could not be enabled.
|
|
2218
|
+
*/
|
|
2219
|
+
_enableDebugGPUTime(queryCount = 256) {
|
|
2220
|
+
if (!this._supportsDebugGPUTime()) {
|
|
2221
|
+
return null;
|
|
2222
|
+
}
|
|
2223
|
+
if (this._debugGPUTimeQuery) {
|
|
2224
|
+
return this._debugGPUTimeQuery;
|
|
2225
|
+
}
|
|
2226
|
+
try {
|
|
2227
|
+
this._debugGPUTimeQuery = this.createQuerySet({ type: "timestamp", count: queryCount });
|
|
2228
|
+
this.commandEncoder = this.createCommandEncoder({
|
|
2229
|
+
id: this.commandEncoder.props.id,
|
|
2230
|
+
timeProfilingQuerySet: this._debugGPUTimeQuery
|
|
2231
|
+
});
|
|
2232
|
+
} catch {
|
|
2233
|
+
this._debugGPUTimeQuery = null;
|
|
2234
|
+
}
|
|
2235
|
+
return this._debugGPUTimeQuery;
|
|
2236
|
+
}
|
|
2237
|
+
/**
|
|
2238
|
+
* Internal helper that disables device-managed GPU timing collection and restores
|
|
2239
|
+
* the default command encoder to an unprofiled state.
|
|
2240
|
+
*/
|
|
2241
|
+
_disableDebugGPUTime() {
|
|
2242
|
+
if (!this._debugGPUTimeQuery) {
|
|
2243
|
+
return;
|
|
2244
|
+
}
|
|
2245
|
+
if (this.commandEncoder.getTimeProfilingQuerySet() === this._debugGPUTimeQuery) {
|
|
2246
|
+
this.commandEncoder = this.createCommandEncoder({
|
|
2247
|
+
id: this.commandEncoder.props.id
|
|
2248
|
+
});
|
|
2249
|
+
}
|
|
2250
|
+
this._debugGPUTimeQuery.destroy();
|
|
2251
|
+
this._debugGPUTimeQuery = null;
|
|
2252
|
+
}
|
|
2253
|
+
/** Internal helper that returns `true` when device-managed GPU timing is currently active. */
|
|
2254
|
+
_isDebugGPUTimeEnabled() {
|
|
2255
|
+
return this._debugGPUTimeQuery !== null;
|
|
2256
|
+
}
|
|
1604
2257
|
// DEPRECATED METHODS
|
|
1605
2258
|
/** @deprecated Use getDefaultCanvasContext() */
|
|
1606
2259
|
getCanvasContext() {
|
|
@@ -1636,6 +2289,12 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1636
2289
|
resetWebGL() {
|
|
1637
2290
|
throw new Error("not implemented");
|
|
1638
2291
|
}
|
|
2292
|
+
// INTERNAL LUMA.GL METHODS
|
|
2293
|
+
getModuleData(moduleName) {
|
|
2294
|
+
this._moduleData[moduleName] ||= {};
|
|
2295
|
+
return this._moduleData[moduleName];
|
|
2296
|
+
}
|
|
2297
|
+
// INTERNAL HELPERS
|
|
1639
2298
|
// IMPLEMENTATION
|
|
1640
2299
|
/** Helper to get the canvas context props */
|
|
1641
2300
|
static _getCanvasContextProps(props) {
|
|
@@ -1702,7 +2361,8 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1702
2361
|
onVisibilityChange: (context) => log.log(1, `${context} Visibility changed ${context.isVisible}`)(),
|
|
1703
2362
|
onDevicePixelRatioChange: (context, info) => log.log(1, `${context} DPR changed ${info.oldRatio} => ${context.devicePixelRatio}`)(),
|
|
1704
2363
|
// Debug flags
|
|
1705
|
-
debug:
|
|
2364
|
+
debug: getDefaultDebugValue(),
|
|
2365
|
+
debugGPUTime: false,
|
|
1706
2366
|
debugShaders: log.get("debug-shaders") || void 0,
|
|
1707
2367
|
debugFramebuffers: Boolean(log.get("debug-framebuffers")),
|
|
1708
2368
|
debugFactories: Boolean(log.get("debug-factories")),
|
|
@@ -1713,9 +2373,11 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1713
2373
|
// Experimental
|
|
1714
2374
|
_reuseDevices: false,
|
|
1715
2375
|
_requestMaxLimits: true,
|
|
1716
|
-
_cacheShaders:
|
|
1717
|
-
|
|
1718
|
-
|
|
2376
|
+
_cacheShaders: true,
|
|
2377
|
+
_destroyShaders: false,
|
|
2378
|
+
_cachePipelines: true,
|
|
2379
|
+
_sharePipelines: true,
|
|
2380
|
+
_destroyPipelines: false,
|
|
1719
2381
|
// TODO - Change these after confirming things work as expected
|
|
1720
2382
|
_initializeFeatures: true,
|
|
1721
2383
|
_disabledFeatures: {
|
|
@@ -1724,6 +2386,25 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1724
2386
|
// INTERNAL
|
|
1725
2387
|
_handle: void 0
|
|
1726
2388
|
});
|
|
2389
|
+
function _getDefaultDebugValue(logDebugValue, nodeEnv) {
|
|
2390
|
+
if (logDebugValue !== void 0 && logDebugValue !== null) {
|
|
2391
|
+
return Boolean(logDebugValue);
|
|
2392
|
+
}
|
|
2393
|
+
if (nodeEnv !== void 0) {
|
|
2394
|
+
return nodeEnv !== "production";
|
|
2395
|
+
}
|
|
2396
|
+
return false;
|
|
2397
|
+
}
|
|
2398
|
+
function getDefaultDebugValue() {
|
|
2399
|
+
return _getDefaultDebugValue(log.get("debug"), getNodeEnv());
|
|
2400
|
+
}
|
|
2401
|
+
function getNodeEnv() {
|
|
2402
|
+
const processObject = globalThis.process;
|
|
2403
|
+
if (!processObject?.env) {
|
|
2404
|
+
return void 0;
|
|
2405
|
+
}
|
|
2406
|
+
return processObject.env["NODE_ENV"];
|
|
2407
|
+
}
|
|
1727
2408
|
|
|
1728
2409
|
// src/adapter/luma.ts
|
|
1729
2410
|
var STARTUP_MESSAGE = "set luma.log.level=1 (or higher) to trace rendering";
|
|
@@ -1901,6 +2582,100 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1901
2582
|
return pageLoadPromise;
|
|
1902
2583
|
}
|
|
1903
2584
|
|
|
2585
|
+
// src/adapter/canvas-observer.ts
|
|
2586
|
+
var CanvasObserver = class {
|
|
2587
|
+
props;
|
|
2588
|
+
_resizeObserver;
|
|
2589
|
+
_intersectionObserver;
|
|
2590
|
+
_observeDevicePixelRatioTimeout = null;
|
|
2591
|
+
_observeDevicePixelRatioMediaQuery = null;
|
|
2592
|
+
_handleDevicePixelRatioChange = () => this._refreshDevicePixelRatio();
|
|
2593
|
+
_trackPositionInterval = null;
|
|
2594
|
+
_started = false;
|
|
2595
|
+
get started() {
|
|
2596
|
+
return this._started;
|
|
2597
|
+
}
|
|
2598
|
+
constructor(props) {
|
|
2599
|
+
this.props = props;
|
|
2600
|
+
}
|
|
2601
|
+
start() {
|
|
2602
|
+
if (this._started || !this.props.canvas) {
|
|
2603
|
+
return;
|
|
2604
|
+
}
|
|
2605
|
+
this._started = true;
|
|
2606
|
+
this._intersectionObserver ||= new IntersectionObserver(
|
|
2607
|
+
(entries) => this.props.onIntersection(entries)
|
|
2608
|
+
);
|
|
2609
|
+
this._resizeObserver ||= new ResizeObserver((entries) => this.props.onResize(entries));
|
|
2610
|
+
this._intersectionObserver.observe(this.props.canvas);
|
|
2611
|
+
try {
|
|
2612
|
+
this._resizeObserver.observe(this.props.canvas, { box: "device-pixel-content-box" });
|
|
2613
|
+
} catch {
|
|
2614
|
+
this._resizeObserver.observe(this.props.canvas, { box: "content-box" });
|
|
2615
|
+
}
|
|
2616
|
+
this._observeDevicePixelRatioTimeout = setTimeout(() => this._refreshDevicePixelRatio(), 0);
|
|
2617
|
+
if (this.props.trackPosition) {
|
|
2618
|
+
this._trackPosition();
|
|
2619
|
+
}
|
|
2620
|
+
}
|
|
2621
|
+
stop() {
|
|
2622
|
+
if (!this._started) {
|
|
2623
|
+
return;
|
|
2624
|
+
}
|
|
2625
|
+
this._started = false;
|
|
2626
|
+
if (this._observeDevicePixelRatioTimeout) {
|
|
2627
|
+
clearTimeout(this._observeDevicePixelRatioTimeout);
|
|
2628
|
+
this._observeDevicePixelRatioTimeout = null;
|
|
2629
|
+
}
|
|
2630
|
+
if (this._observeDevicePixelRatioMediaQuery) {
|
|
2631
|
+
this._observeDevicePixelRatioMediaQuery.removeEventListener(
|
|
2632
|
+
"change",
|
|
2633
|
+
this._handleDevicePixelRatioChange
|
|
2634
|
+
);
|
|
2635
|
+
this._observeDevicePixelRatioMediaQuery = null;
|
|
2636
|
+
}
|
|
2637
|
+
if (this._trackPositionInterval) {
|
|
2638
|
+
clearInterval(this._trackPositionInterval);
|
|
2639
|
+
this._trackPositionInterval = null;
|
|
2640
|
+
}
|
|
2641
|
+
this._resizeObserver?.disconnect();
|
|
2642
|
+
this._intersectionObserver?.disconnect();
|
|
2643
|
+
}
|
|
2644
|
+
_refreshDevicePixelRatio() {
|
|
2645
|
+
if (!this._started) {
|
|
2646
|
+
return;
|
|
2647
|
+
}
|
|
2648
|
+
this.props.onDevicePixelRatioChange();
|
|
2649
|
+
this._observeDevicePixelRatioMediaQuery?.removeEventListener(
|
|
2650
|
+
"change",
|
|
2651
|
+
this._handleDevicePixelRatioChange
|
|
2652
|
+
);
|
|
2653
|
+
this._observeDevicePixelRatioMediaQuery = matchMedia(
|
|
2654
|
+
`(resolution: ${window.devicePixelRatio}dppx)`
|
|
2655
|
+
);
|
|
2656
|
+
this._observeDevicePixelRatioMediaQuery.addEventListener(
|
|
2657
|
+
"change",
|
|
2658
|
+
this._handleDevicePixelRatioChange,
|
|
2659
|
+
{ once: true }
|
|
2660
|
+
);
|
|
2661
|
+
}
|
|
2662
|
+
_trackPosition(intervalMs = 100) {
|
|
2663
|
+
if (this._trackPositionInterval) {
|
|
2664
|
+
return;
|
|
2665
|
+
}
|
|
2666
|
+
this._trackPositionInterval = setInterval(() => {
|
|
2667
|
+
if (!this._started) {
|
|
2668
|
+
if (this._trackPositionInterval) {
|
|
2669
|
+
clearInterval(this._trackPositionInterval);
|
|
2670
|
+
this._trackPositionInterval = null;
|
|
2671
|
+
}
|
|
2672
|
+
} else {
|
|
2673
|
+
this.props.onPositionChange();
|
|
2674
|
+
}
|
|
2675
|
+
}, intervalMs);
|
|
2676
|
+
}
|
|
2677
|
+
};
|
|
2678
|
+
|
|
1904
2679
|
// src/utils/promise-utils.ts
|
|
1905
2680
|
function withResolvers() {
|
|
1906
2681
|
let resolve;
|
|
@@ -1912,8 +2687,21 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1912
2687
|
return { promise, resolve, reject };
|
|
1913
2688
|
}
|
|
1914
2689
|
|
|
1915
|
-
// src/
|
|
1916
|
-
|
|
2690
|
+
// src/utils/assert.ts
|
|
2691
|
+
function assert2(condition, message) {
|
|
2692
|
+
if (!condition) {
|
|
2693
|
+
const error = new Error(message ?? "luma.gl assertion failed.");
|
|
2694
|
+
Error.captureStackTrace?.(error, assert2);
|
|
2695
|
+
throw error;
|
|
2696
|
+
}
|
|
2697
|
+
}
|
|
2698
|
+
function assertDefined(value, message) {
|
|
2699
|
+
assert2(value, message);
|
|
2700
|
+
return value;
|
|
2701
|
+
}
|
|
2702
|
+
|
|
2703
|
+
// src/adapter/canvas-surface.ts
|
|
2704
|
+
var _CanvasSurface = class {
|
|
1917
2705
|
static isHTMLCanvas(canvas) {
|
|
1918
2706
|
return typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement;
|
|
1919
2707
|
}
|
|
@@ -1947,16 +2735,20 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1947
2735
|
drawingBufferWidth;
|
|
1948
2736
|
/** Height of drawing buffer: automatically tracks this.pixelHeight if props.autoResize is true */
|
|
1949
2737
|
drawingBufferHeight;
|
|
2738
|
+
/** Resolves when the canvas is initialized, i.e. when the ResizeObserver has updated the pixel size */
|
|
1950
2739
|
_initializedResolvers = withResolvers();
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
_position;
|
|
2740
|
+
_canvasObserver;
|
|
2741
|
+
/** Position of the canvas in the document, updated by a timer */
|
|
2742
|
+
_position = [0, 0];
|
|
2743
|
+
/** Whether this canvas context has been destroyed */
|
|
1954
2744
|
destroyed = false;
|
|
2745
|
+
/** Whether the drawing buffer size needs to be resized (deferred resizing to avoid flicker) */
|
|
2746
|
+
_needsDrawingBufferResize = true;
|
|
1955
2747
|
toString() {
|
|
1956
2748
|
return `${this[Symbol.toStringTag]}(${this.id})`;
|
|
1957
2749
|
}
|
|
1958
2750
|
constructor(props) {
|
|
1959
|
-
this.props = { ...
|
|
2751
|
+
this.props = { ..._CanvasSurface.defaultProps, ...props };
|
|
1960
2752
|
props = this.props;
|
|
1961
2753
|
this.initialized = this._initializedResolvers.promise;
|
|
1962
2754
|
if (!isBrowser()) {
|
|
@@ -1968,11 +2760,11 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1968
2760
|
} else {
|
|
1969
2761
|
this.canvas = props.canvas;
|
|
1970
2762
|
}
|
|
1971
|
-
if (
|
|
2763
|
+
if (_CanvasSurface.isHTMLCanvas(this.canvas)) {
|
|
1972
2764
|
this.id = props.id || this.canvas.id;
|
|
1973
2765
|
this.type = "html-canvas";
|
|
1974
2766
|
this.htmlCanvas = this.canvas;
|
|
1975
|
-
} else if (
|
|
2767
|
+
} else if (_CanvasSurface.isOffscreenCanvas(this.canvas)) {
|
|
1976
2768
|
this.id = props.id || "offscreen-canvas";
|
|
1977
2769
|
this.type = "offscreen-canvas";
|
|
1978
2770
|
this.offscreenCanvas = this.canvas;
|
|
@@ -1988,25 +2780,21 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1988
2780
|
this.drawingBufferHeight = this.canvas.height;
|
|
1989
2781
|
this.devicePixelRatio = globalThis.devicePixelRatio || 1;
|
|
1990
2782
|
this._position = [0, 0];
|
|
1991
|
-
|
|
1992
|
-
this.
|
|
1993
|
-
|
|
1994
|
-
)
|
|
1995
|
-
this.
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
} catch {
|
|
2000
|
-
this._resizeObserver.observe(this.canvas, { box: "content-box" });
|
|
2001
|
-
}
|
|
2002
|
-
setTimeout(() => this._observeDevicePixelRatio(), 0);
|
|
2003
|
-
if (this.props.trackPosition) {
|
|
2004
|
-
this._trackPosition();
|
|
2005
|
-
}
|
|
2006
|
-
}
|
|
2783
|
+
this._canvasObserver = new CanvasObserver({
|
|
2784
|
+
canvas: this.htmlCanvas,
|
|
2785
|
+
trackPosition: this.props.trackPosition,
|
|
2786
|
+
onResize: (entries) => this._handleResize(entries),
|
|
2787
|
+
onIntersection: (entries) => this._handleIntersection(entries),
|
|
2788
|
+
onDevicePixelRatioChange: () => this._observeDevicePixelRatio(),
|
|
2789
|
+
onPositionChange: () => this.updatePosition()
|
|
2790
|
+
});
|
|
2007
2791
|
}
|
|
2008
2792
|
destroy() {
|
|
2009
|
-
this.destroyed
|
|
2793
|
+
if (!this.destroyed) {
|
|
2794
|
+
this.destroyed = true;
|
|
2795
|
+
this._stopObservers();
|
|
2796
|
+
this.device = null;
|
|
2797
|
+
}
|
|
2010
2798
|
}
|
|
2011
2799
|
setProps(props) {
|
|
2012
2800
|
if ("useDevicePixels" in props) {
|
|
@@ -2015,55 +2803,41 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2015
2803
|
}
|
|
2016
2804
|
return this;
|
|
2017
2805
|
}
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
*/
|
|
2806
|
+
/** Returns a framebuffer with properly resized current 'swap chain' textures */
|
|
2807
|
+
getCurrentFramebuffer(options) {
|
|
2808
|
+
this._resizeDrawingBufferIfNeeded();
|
|
2809
|
+
return this._getCurrentFramebuffer(options);
|
|
2810
|
+
}
|
|
2024
2811
|
getCSSSize() {
|
|
2025
2812
|
return [this.cssWidth, this.cssHeight];
|
|
2026
2813
|
}
|
|
2027
2814
|
getPosition() {
|
|
2028
2815
|
return this._position;
|
|
2029
2816
|
}
|
|
2030
|
-
/**
|
|
2031
|
-
* Returns the size covered by the canvas in actual device pixels.
|
|
2032
|
-
* @note This can be different from the 'CSS' size of a canvas due to DPR scaling, and rounding to integer pixels
|
|
2033
|
-
* @note This is independent of the canvas' internal drawing buffer size (.width, .height).
|
|
2034
|
-
*/
|
|
2035
2817
|
getDevicePixelSize() {
|
|
2036
2818
|
return [this.devicePixelWidth, this.devicePixelHeight];
|
|
2037
2819
|
}
|
|
2038
|
-
/** Get the drawing buffer size (number of pixels GPU is rendering into, can be different from CSS size) */
|
|
2039
2820
|
getDrawingBufferSize() {
|
|
2040
2821
|
return [this.drawingBufferWidth, this.drawingBufferHeight];
|
|
2041
2822
|
}
|
|
2042
|
-
/** Returns the biggest allowed framebuffer size. @todo Allow the application to limit this? */
|
|
2043
2823
|
getMaxDrawingBufferSize() {
|
|
2044
2824
|
const maxTextureDimension = this.device.limits.maxTextureDimension2D;
|
|
2045
2825
|
return [maxTextureDimension, maxTextureDimension];
|
|
2046
2826
|
}
|
|
2047
|
-
/** Update the canvas drawing buffer size. Called automatically if props.autoResize is true. */
|
|
2048
2827
|
setDrawingBufferSize(width, height) {
|
|
2049
|
-
|
|
2050
|
-
|
|
2828
|
+
width = Math.floor(width);
|
|
2829
|
+
height = Math.floor(height);
|
|
2830
|
+
if (this.drawingBufferWidth === width && this.drawingBufferHeight === height) {
|
|
2831
|
+
return;
|
|
2832
|
+
}
|
|
2051
2833
|
this.drawingBufferWidth = width;
|
|
2052
2834
|
this.drawingBufferHeight = height;
|
|
2835
|
+
this._needsDrawingBufferResize = true;
|
|
2053
2836
|
}
|
|
2054
|
-
/**
|
|
2055
|
-
* Returns the current DPR (number of physical pixels per CSS pixel), if props.useDevicePixels is true
|
|
2056
|
-
* @note This can be a fractional (non-integer) number, e.g. when the user zooms in the browser.
|
|
2057
|
-
* @note This function handles the non-HTML canvas cases
|
|
2058
|
-
*/
|
|
2059
2837
|
getDevicePixelRatio() {
|
|
2060
|
-
const
|
|
2061
|
-
return
|
|
2838
|
+
const devicePixelRatio2 = typeof window !== "undefined" && window.devicePixelRatio;
|
|
2839
|
+
return devicePixelRatio2 || 1;
|
|
2062
2840
|
}
|
|
2063
|
-
// DEPRECATED METHODS
|
|
2064
|
-
/**
|
|
2065
|
-
* Maps CSS pixel position to device pixel position
|
|
2066
|
-
*/
|
|
2067
2841
|
cssToDevicePixels(cssPixel, yInvert = true) {
|
|
2068
2842
|
const ratio = this.cssToDeviceRatio();
|
|
2069
2843
|
const [width, height] = this.getDrawingBufferSize();
|
|
@@ -2073,10 +2847,10 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2073
2847
|
getPixelSize() {
|
|
2074
2848
|
return this.getDevicePixelSize();
|
|
2075
2849
|
}
|
|
2076
|
-
/** @deprecated
|
|
2850
|
+
/** @deprecated Use the current drawing buffer size for projection setup. */
|
|
2077
2851
|
getAspect() {
|
|
2078
|
-
const [width, height] = this.
|
|
2079
|
-
return width / height;
|
|
2852
|
+
const [width, height] = this.getDrawingBufferSize();
|
|
2853
|
+
return width > 0 && height > 0 ? width / height : 1;
|
|
2080
2854
|
}
|
|
2081
2855
|
/** @deprecated Returns multiplier need to convert CSS size to Device size */
|
|
2082
2856
|
cssToDeviceRatio() {
|
|
@@ -2092,18 +2866,40 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2092
2866
|
resize(size) {
|
|
2093
2867
|
this.setDrawingBufferSize(size.width, size.height);
|
|
2094
2868
|
}
|
|
2095
|
-
// IMPLEMENTATION
|
|
2096
|
-
/**
|
|
2097
|
-
* Allows subclass constructor to override the canvas id for auto created canvases.
|
|
2098
|
-
* This can really help when debugging DOM in apps that create multiple devices
|
|
2099
|
-
*/
|
|
2100
2869
|
_setAutoCreatedCanvasId(id) {
|
|
2101
2870
|
if (this.htmlCanvas?.id === "lumagl-auto-created-canvas") {
|
|
2102
2871
|
this.htmlCanvas.id = id;
|
|
2103
2872
|
}
|
|
2104
2873
|
}
|
|
2105
|
-
/**
|
|
2874
|
+
/**
|
|
2875
|
+
* Starts DOM observation after the derived context and its device are fully initialized.
|
|
2876
|
+
*
|
|
2877
|
+
* `CanvasSurface` construction runs before subclasses can assign `this.device`, and the
|
|
2878
|
+
* default WebGL canvas context is created before `WebGLDevice` has initialized `limits`,
|
|
2879
|
+
* `features`, and the rest of its runtime state. Deferring observer startup avoids early
|
|
2880
|
+
* `ResizeObserver` and DPR callbacks running against a partially initialized device.
|
|
2881
|
+
*/
|
|
2882
|
+
_startObservers() {
|
|
2883
|
+
if (this.destroyed) {
|
|
2884
|
+
return;
|
|
2885
|
+
}
|
|
2886
|
+
this._canvasObserver.start();
|
|
2887
|
+
}
|
|
2888
|
+
/**
|
|
2889
|
+
* Stops all DOM observation and timers associated with a canvas surface.
|
|
2890
|
+
*
|
|
2891
|
+
* This pairs with `_startObservers()` so teardown uses the same lifecycle whether a context is
|
|
2892
|
+
* explicitly destroyed, abandoned during device reuse, or temporarily has not started observing
|
|
2893
|
+
* yet. Centralizing shutdown here keeps resize/DPR/position watchers from surviving past the
|
|
2894
|
+
* lifetime of the owning device.
|
|
2895
|
+
*/
|
|
2896
|
+
_stopObservers() {
|
|
2897
|
+
this._canvasObserver.stop();
|
|
2898
|
+
}
|
|
2106
2899
|
_handleIntersection(entries) {
|
|
2900
|
+
if (this.destroyed) {
|
|
2901
|
+
return;
|
|
2902
|
+
}
|
|
2107
2903
|
const entry = entries.find((entry_) => entry_.target === this.canvas);
|
|
2108
2904
|
if (!entry) {
|
|
2109
2905
|
return;
|
|
@@ -2114,21 +2910,20 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2114
2910
|
this.device.props.onVisibilityChange(this);
|
|
2115
2911
|
}
|
|
2116
2912
|
}
|
|
2117
|
-
/**
|
|
2118
|
-
* Reacts to an observed resize by using the most accurate pixel size information the browser can provide
|
|
2119
|
-
* @see https://web.dev/articles/device-pixel-content-box
|
|
2120
|
-
* @see https://webgpufundamentals.org/webgpu/lessons/webgpu-resizing-the-canvas.html
|
|
2121
|
-
*/
|
|
2122
2913
|
_handleResize(entries) {
|
|
2914
|
+
if (this.destroyed) {
|
|
2915
|
+
return;
|
|
2916
|
+
}
|
|
2123
2917
|
const entry = entries.find((entry_) => entry_.target === this.canvas);
|
|
2124
2918
|
if (!entry) {
|
|
2125
2919
|
return;
|
|
2126
2920
|
}
|
|
2127
|
-
|
|
2128
|
-
this.
|
|
2921
|
+
const contentBoxSize = assertDefined(entry.contentBoxSize?.[0]);
|
|
2922
|
+
this.cssWidth = contentBoxSize.inlineSize;
|
|
2923
|
+
this.cssHeight = contentBoxSize.blockSize;
|
|
2129
2924
|
const oldPixelSize = this.getDevicePixelSize();
|
|
2130
|
-
const devicePixelWidth = entry.devicePixelContentBoxSize?.[0]
|
|
2131
|
-
const devicePixelHeight = entry.devicePixelContentBoxSize?.[0]
|
|
2925
|
+
const devicePixelWidth = entry.devicePixelContentBoxSize?.[0]?.inlineSize || contentBoxSize.inlineSize * devicePixelRatio;
|
|
2926
|
+
const devicePixelHeight = entry.devicePixelContentBoxSize?.[0]?.blockSize || contentBoxSize.blockSize * devicePixelRatio;
|
|
2132
2927
|
const [maxDevicePixelWidth, maxDevicePixelHeight] = this.getMaxDrawingBufferSize();
|
|
2133
2928
|
this.devicePixelWidth = Math.max(1, Math.min(devicePixelWidth, maxDevicePixelWidth));
|
|
2134
2929
|
this.devicePixelHeight = Math.max(1, Math.min(devicePixelHeight, maxDevicePixelHeight));
|
|
@@ -2138,47 +2933,47 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2138
2933
|
_updateDrawingBufferSize() {
|
|
2139
2934
|
if (this.props.autoResize) {
|
|
2140
2935
|
if (typeof this.props.useDevicePixels === "number") {
|
|
2141
|
-
const
|
|
2142
|
-
this.setDrawingBufferSize(
|
|
2936
|
+
const devicePixelRatio2 = this.props.useDevicePixels;
|
|
2937
|
+
this.setDrawingBufferSize(
|
|
2938
|
+
this.cssWidth * devicePixelRatio2,
|
|
2939
|
+
this.cssHeight * devicePixelRatio2
|
|
2940
|
+
);
|
|
2143
2941
|
} else if (this.props.useDevicePixels) {
|
|
2144
2942
|
this.setDrawingBufferSize(this.devicePixelWidth, this.devicePixelHeight);
|
|
2145
2943
|
} else {
|
|
2146
2944
|
this.setDrawingBufferSize(this.cssWidth, this.cssHeight);
|
|
2147
2945
|
}
|
|
2148
|
-
this._updateDevice();
|
|
2149
2946
|
}
|
|
2150
2947
|
this._initializedResolvers.resolve();
|
|
2151
2948
|
this.isInitialized = true;
|
|
2152
2949
|
this.updatePosition();
|
|
2153
2950
|
}
|
|
2154
|
-
|
|
2951
|
+
_resizeDrawingBufferIfNeeded() {
|
|
2952
|
+
if (this._needsDrawingBufferResize) {
|
|
2953
|
+
this._needsDrawingBufferResize = false;
|
|
2954
|
+
const sizeChanged = this.drawingBufferWidth !== this.canvas.width || this.drawingBufferHeight !== this.canvas.height;
|
|
2955
|
+
if (sizeChanged) {
|
|
2956
|
+
this.canvas.width = this.drawingBufferWidth;
|
|
2957
|
+
this.canvas.height = this.drawingBufferHeight;
|
|
2958
|
+
this._configureDevice();
|
|
2959
|
+
}
|
|
2960
|
+
}
|
|
2961
|
+
}
|
|
2155
2962
|
_observeDevicePixelRatio() {
|
|
2963
|
+
if (this.destroyed || !this._canvasObserver.started) {
|
|
2964
|
+
return;
|
|
2965
|
+
}
|
|
2156
2966
|
const oldRatio = this.devicePixelRatio;
|
|
2157
2967
|
this.devicePixelRatio = window.devicePixelRatio;
|
|
2158
2968
|
this.updatePosition();
|
|
2159
|
-
this.device.props.onDevicePixelRatioChange(this, {
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
() => this._observeDevicePixelRatio(),
|
|
2163
|
-
{ once: true }
|
|
2164
|
-
);
|
|
2165
|
-
}
|
|
2166
|
-
/** Start tracking positions with a timer */
|
|
2167
|
-
_trackPosition(intervalMs = 100) {
|
|
2168
|
-
const intervalId = setInterval(() => {
|
|
2169
|
-
if (this.destroyed) {
|
|
2170
|
-
clearInterval(intervalId);
|
|
2171
|
-
} else {
|
|
2172
|
-
this.updatePosition();
|
|
2173
|
-
}
|
|
2174
|
-
}, intervalMs);
|
|
2969
|
+
this.device.props.onDevicePixelRatioChange?.(this, {
|
|
2970
|
+
oldRatio
|
|
2971
|
+
});
|
|
2175
2972
|
}
|
|
2176
|
-
/**
|
|
2177
|
-
* Calculated the absolute position of the canvas
|
|
2178
|
-
* @note - getBoundingClientRect() is normally cheap but can be expensive
|
|
2179
|
-
* if called before browser has finished a reflow. Should not be the case here.
|
|
2180
|
-
*/
|
|
2181
2973
|
updatePosition() {
|
|
2974
|
+
if (this.destroyed) {
|
|
2975
|
+
return;
|
|
2976
|
+
}
|
|
2182
2977
|
const newRect = this.htmlCanvas?.getBoundingClientRect();
|
|
2183
2978
|
if (newRect) {
|
|
2184
2979
|
const position = [newRect.left, newRect.top];
|
|
@@ -2187,13 +2982,15 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2187
2982
|
if (positionChanged) {
|
|
2188
2983
|
const oldPosition = this._position;
|
|
2189
2984
|
this._position = position;
|
|
2190
|
-
this.device.props.onPositionChange?.(this, {
|
|
2985
|
+
this.device.props.onPositionChange?.(this, {
|
|
2986
|
+
oldPosition
|
|
2987
|
+
});
|
|
2191
2988
|
}
|
|
2192
2989
|
}
|
|
2193
2990
|
}
|
|
2194
2991
|
};
|
|
2195
|
-
var
|
|
2196
|
-
__publicField(
|
|
2992
|
+
var CanvasSurface = _CanvasSurface;
|
|
2993
|
+
__publicField(CanvasSurface, "defaultProps", {
|
|
2197
2994
|
id: void 0,
|
|
2198
2995
|
canvas: null,
|
|
2199
2996
|
width: 800,
|
|
@@ -2221,7 +3018,7 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2221
3018
|
}
|
|
2222
3019
|
function getCanvasFromDOM(canvasId) {
|
|
2223
3020
|
const canvas = document.getElementById(canvasId);
|
|
2224
|
-
if (!
|
|
3021
|
+
if (!CanvasSurface.isHTMLCanvas(canvas)) {
|
|
2225
3022
|
throw new Error("Object is not a canvas element");
|
|
2226
3023
|
}
|
|
2227
3024
|
return canvas;
|
|
@@ -2245,33 +3042,40 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2245
3042
|
const point = pixel;
|
|
2246
3043
|
const x = scaleX(point[0], ratio, width);
|
|
2247
3044
|
let y = scaleY(point[1], ratio, height, yInvert);
|
|
2248
|
-
let
|
|
2249
|
-
const xHigh =
|
|
2250
|
-
|
|
3045
|
+
let temporary = scaleX(point[0] + 1, ratio, width);
|
|
3046
|
+
const xHigh = temporary === width - 1 ? temporary : temporary - 1;
|
|
3047
|
+
temporary = scaleY(point[1] + 1, ratio, height, yInvert);
|
|
2251
3048
|
let yHigh;
|
|
2252
3049
|
if (yInvert) {
|
|
2253
|
-
|
|
3050
|
+
temporary = temporary === 0 ? temporary : temporary + 1;
|
|
2254
3051
|
yHigh = y;
|
|
2255
|
-
y =
|
|
3052
|
+
y = temporary;
|
|
2256
3053
|
} else {
|
|
2257
|
-
yHigh =
|
|
3054
|
+
yHigh = temporary === height - 1 ? temporary : temporary - 1;
|
|
2258
3055
|
}
|
|
2259
3056
|
return {
|
|
2260
3057
|
x,
|
|
2261
3058
|
y,
|
|
2262
|
-
// when ratio < 1, current css pixel and next css pixel may point to same device pixel, set width/height to 1 in those cases.
|
|
2263
3059
|
width: Math.max(xHigh - x + 1, 1),
|
|
2264
3060
|
height: Math.max(yHigh - y + 1, 1)
|
|
2265
3061
|
};
|
|
2266
3062
|
}
|
|
2267
3063
|
function scaleX(x, ratio, width) {
|
|
2268
|
-
|
|
2269
|
-
return r;
|
|
3064
|
+
return Math.min(Math.round(x * ratio), width - 1);
|
|
2270
3065
|
}
|
|
2271
3066
|
function scaleY(y, ratio, height, yInvert) {
|
|
2272
3067
|
return yInvert ? Math.max(0, height - 1 - Math.round(y * ratio)) : Math.min(Math.round(y * ratio), height - 1);
|
|
2273
3068
|
}
|
|
2274
3069
|
|
|
3070
|
+
// src/adapter/canvas-context.ts
|
|
3071
|
+
var CanvasContext = class extends CanvasSurface {
|
|
3072
|
+
};
|
|
3073
|
+
__publicField(CanvasContext, "defaultProps", CanvasSurface.defaultProps);
|
|
3074
|
+
|
|
3075
|
+
// src/adapter/presentation-context.ts
|
|
3076
|
+
var PresentationContext = class extends CanvasSurface {
|
|
3077
|
+
};
|
|
3078
|
+
|
|
2275
3079
|
// src/adapter/resources/sampler.ts
|
|
2276
3080
|
var _Sampler = class extends Resource {
|
|
2277
3081
|
get [Symbol.toStringTag]() {
|
|
@@ -2326,7 +3130,15 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2326
3130
|
depth;
|
|
2327
3131
|
/** mip levels in this texture */
|
|
2328
3132
|
mipLevels;
|
|
2329
|
-
/**
|
|
3133
|
+
/** sample count */
|
|
3134
|
+
samples;
|
|
3135
|
+
/** Rows are multiples of this length, padded with extra bytes if needed */
|
|
3136
|
+
byteAlignment;
|
|
3137
|
+
/** The ready promise is always resolved. It is provided for type compatibility with DynamicTexture. */
|
|
3138
|
+
ready = Promise.resolve(this);
|
|
3139
|
+
/** isReady is always true. It is provided for type compatibility with DynamicTexture. */
|
|
3140
|
+
isReady = true;
|
|
3141
|
+
/** "Time" of last update. Monotonically increasing timestamp. TODO move to DynamicTexture? */
|
|
2330
3142
|
updateTimestamp;
|
|
2331
3143
|
get [Symbol.toStringTag]() {
|
|
2332
3144
|
return "Texture";
|
|
@@ -2335,7 +3147,7 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2335
3147
|
return `Texture(${this.id},${this.format},${this.width}x${this.height})`;
|
|
2336
3148
|
}
|
|
2337
3149
|
/** Do not use directly. Create with device.createTexture() */
|
|
2338
|
-
constructor(device, props) {
|
|
3150
|
+
constructor(device, props, backendProps) {
|
|
2339
3151
|
props = _Texture.normalizeProps(device, props);
|
|
2340
3152
|
super(device, props, _Texture.defaultProps);
|
|
2341
3153
|
this.dimension = this.props.dimension;
|
|
@@ -2345,6 +3157,10 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2345
3157
|
this.height = this.props.height;
|
|
2346
3158
|
this.depth = this.props.depth;
|
|
2347
3159
|
this.mipLevels = this.props.mipLevels;
|
|
3160
|
+
this.samples = this.props.samples || 1;
|
|
3161
|
+
if (this.dimension === "cube") {
|
|
3162
|
+
this.depth = 6;
|
|
3163
|
+
}
|
|
2348
3164
|
if (this.props.width === void 0 || this.props.height === void 0) {
|
|
2349
3165
|
if (device.isExternalImage(props.data)) {
|
|
2350
3166
|
const size = device.getExternalImageSize(props.data);
|
|
@@ -2355,17 +3171,14 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2355
3171
|
this.height = 1;
|
|
2356
3172
|
if (this.props.width === void 0 || this.props.height === void 0) {
|
|
2357
3173
|
log.warn(
|
|
2358
|
-
`${this} created with undefined width or height. This is deprecated. Use
|
|
3174
|
+
`${this} created with undefined width or height. This is deprecated. Use DynamicTexture instead.`
|
|
2359
3175
|
)();
|
|
2360
3176
|
}
|
|
2361
3177
|
}
|
|
2362
3178
|
}
|
|
3179
|
+
this.byteAlignment = backendProps?.byteAlignment || 1;
|
|
2363
3180
|
this.updateTimestamp = device.incrementTimestamp();
|
|
2364
3181
|
}
|
|
2365
|
-
/** Set sampler props associated with this texture */
|
|
2366
|
-
setSampler(sampler) {
|
|
2367
|
-
this.sampler = sampler instanceof Sampler ? sampler : this.device.createSampler(sampler);
|
|
2368
|
-
}
|
|
2369
3182
|
/**
|
|
2370
3183
|
* Create a new texture with the same parameters and optionally a different size
|
|
2371
3184
|
* @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.
|
|
@@ -2374,6 +3187,105 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2374
3187
|
clone(size) {
|
|
2375
3188
|
return this.device.createTexture({ ...this.props, ...size });
|
|
2376
3189
|
}
|
|
3190
|
+
/** Set sampler props associated with this texture */
|
|
3191
|
+
setSampler(sampler) {
|
|
3192
|
+
this.sampler = sampler instanceof Sampler ? sampler : this.device.createSampler(sampler);
|
|
3193
|
+
}
|
|
3194
|
+
/**
|
|
3195
|
+
* Copy raw image data (bytes) into the texture.
|
|
3196
|
+
*
|
|
3197
|
+
* @note Deprecated compatibility wrapper over {@link writeData}.
|
|
3198
|
+
* @note Uses the same layout defaults and alignment rules as {@link writeData}.
|
|
3199
|
+
* @note Tightly packed CPU uploads can omit `bytesPerRow` and `rowsPerImage`.
|
|
3200
|
+
* @note If the CPU source rows are padded, pass explicit `bytesPerRow` and `rowsPerImage`.
|
|
3201
|
+
* @deprecated Use writeData()
|
|
3202
|
+
*/
|
|
3203
|
+
copyImageData(options) {
|
|
3204
|
+
const { data, depth, ...writeOptions } = options;
|
|
3205
|
+
this.writeData(data, {
|
|
3206
|
+
...writeOptions,
|
|
3207
|
+
depthOrArrayLayers: writeOptions.depthOrArrayLayers ?? depth
|
|
3208
|
+
});
|
|
3209
|
+
}
|
|
3210
|
+
/**
|
|
3211
|
+
* Calculates the memory layout of the texture, required when reading and writing data.
|
|
3212
|
+
* @return the backend-aligned linear layout, in particular bytesPerRow which includes any required padding for buffer copy/read paths
|
|
3213
|
+
*/
|
|
3214
|
+
computeMemoryLayout(options_ = {}) {
|
|
3215
|
+
const options = this._normalizeTextureReadOptions(options_);
|
|
3216
|
+
const { width = this.width, height = this.height, depthOrArrayLayers = this.depth } = options;
|
|
3217
|
+
const { format, byteAlignment } = this;
|
|
3218
|
+
return textureFormatDecoder.computeMemoryLayout({
|
|
3219
|
+
format,
|
|
3220
|
+
width,
|
|
3221
|
+
height,
|
|
3222
|
+
depth: depthOrArrayLayers,
|
|
3223
|
+
byteAlignment
|
|
3224
|
+
});
|
|
3225
|
+
}
|
|
3226
|
+
/**
|
|
3227
|
+
* Read the contents of a texture into a GPU Buffer.
|
|
3228
|
+
* @returns A Buffer containing the texture data.
|
|
3229
|
+
*
|
|
3230
|
+
* @note The memory layout of the texture data is determined by the texture format and dimensions.
|
|
3231
|
+
* @note The application can call Texture.computeMemoryLayout() to compute the backend-aligned layout.
|
|
3232
|
+
* @note The application can call Buffer.readAsync() to read the returned buffer on the CPU.
|
|
3233
|
+
* @note The destination buffer must be supplied by the caller and must be large enough for the requested region.
|
|
3234
|
+
* @note On WebGPU this corresponds to a texture-to-buffer copy and uses buffer-copy alignment rules.
|
|
3235
|
+
* @note On WebGL, luma.gl emulates the same logical readback behavior.
|
|
3236
|
+
*/
|
|
3237
|
+
readBuffer(options, buffer) {
|
|
3238
|
+
throw new Error("readBuffer not implemented");
|
|
3239
|
+
}
|
|
3240
|
+
/**
|
|
3241
|
+
* Reads data from a texture into an ArrayBuffer.
|
|
3242
|
+
* @returns An ArrayBuffer containing the texture data.
|
|
3243
|
+
*
|
|
3244
|
+
* @note The memory layout of the texture data is determined by the texture format and dimensions.
|
|
3245
|
+
* @note The application can call Texture.computeMemoryLayout() to compute the layout.
|
|
3246
|
+
* @deprecated Use Texture.readBuffer() with an explicit destination buffer, or DynamicTexture.readAsync() for convenience readback.
|
|
3247
|
+
*/
|
|
3248
|
+
readDataAsync(options) {
|
|
3249
|
+
throw new Error("readBuffer not implemented");
|
|
3250
|
+
}
|
|
3251
|
+
/**
|
|
3252
|
+
* Writes a GPU Buffer into a texture.
|
|
3253
|
+
*
|
|
3254
|
+
* @param buffer - Source GPU buffer.
|
|
3255
|
+
* @param options - Destination subresource, extent, and source layout options.
|
|
3256
|
+
* @note The memory layout of the texture data is determined by the texture format and dimensions.
|
|
3257
|
+
* @note The application can call Texture.computeMemoryLayout() to compute the backend-aligned layout.
|
|
3258
|
+
* @note On WebGPU this corresponds to a buffer-to-texture copy and uses buffer-copy alignment rules.
|
|
3259
|
+
* @note On WebGL, luma.gl emulates the same destination and layout semantics.
|
|
3260
|
+
*/
|
|
3261
|
+
writeBuffer(buffer, options) {
|
|
3262
|
+
throw new Error("readBuffer not implemented");
|
|
3263
|
+
}
|
|
3264
|
+
/**
|
|
3265
|
+
* Writes an array buffer into a texture.
|
|
3266
|
+
*
|
|
3267
|
+
* @param data - Source texel data.
|
|
3268
|
+
* @param options - Destination subresource, extent, and source layout options.
|
|
3269
|
+
* @note If `bytesPerRow` and `rowsPerImage` are omitted, luma.gl computes a tightly packed CPU-memory layout for the requested region.
|
|
3270
|
+
* @note On WebGPU this corresponds to `GPUQueue.writeTexture()` and does not implicitly pad rows to 256 bytes.
|
|
3271
|
+
* @note On WebGL, padded CPU data is supported via the same `bytesPerRow` and `rowsPerImage` options.
|
|
3272
|
+
*/
|
|
3273
|
+
writeData(data, options) {
|
|
3274
|
+
throw new Error("readBuffer not implemented");
|
|
3275
|
+
}
|
|
3276
|
+
// IMPLEMENTATION SPECIFIC
|
|
3277
|
+
/**
|
|
3278
|
+
* WebGL can read data synchronously.
|
|
3279
|
+
* @note While it is convenient, the performance penalty is very significant
|
|
3280
|
+
*/
|
|
3281
|
+
readDataSyncWebGL(options) {
|
|
3282
|
+
throw new Error("readDataSyncWebGL not available");
|
|
3283
|
+
}
|
|
3284
|
+
/** Generate mipmaps (WebGL only) */
|
|
3285
|
+
generateMipmapsWebGL() {
|
|
3286
|
+
throw new Error("generateMipmapsWebGL not available");
|
|
3287
|
+
}
|
|
3288
|
+
// HELPERS
|
|
2377
3289
|
/** Ensure we have integer coordinates */
|
|
2378
3290
|
static normalizeProps(device, props) {
|
|
2379
3291
|
const newProps = { ...props };
|
|
@@ -2386,7 +3298,6 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2386
3298
|
}
|
|
2387
3299
|
return newProps;
|
|
2388
3300
|
}
|
|
2389
|
-
// HELPERS
|
|
2390
3301
|
/** Initialize texture with supplied props */
|
|
2391
3302
|
// eslint-disable-next-line max-statements
|
|
2392
3303
|
_initializeData(data) {
|
|
@@ -2420,23 +3331,166 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2420
3331
|
}
|
|
2421
3332
|
}
|
|
2422
3333
|
_normalizeCopyImageDataOptions(options_) {
|
|
2423
|
-
const {
|
|
2424
|
-
const options = {
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
}
|
|
2429
|
-
options.bytesPerRow = options_.bytesPerRow || width * (info.bytesPerPixel || 4);
|
|
2430
|
-
options.rowsPerImage = options_.rowsPerImage || height;
|
|
2431
|
-
return options;
|
|
3334
|
+
const { data, depth, ...writeOptions } = options_;
|
|
3335
|
+
const options = this._normalizeTextureWriteOptions({
|
|
3336
|
+
...writeOptions,
|
|
3337
|
+
depthOrArrayLayers: writeOptions.depthOrArrayLayers ?? depth
|
|
3338
|
+
});
|
|
3339
|
+
return { data, depth: options.depthOrArrayLayers, ...options };
|
|
2432
3340
|
}
|
|
2433
3341
|
_normalizeCopyExternalImageOptions(options_) {
|
|
3342
|
+
const optionsWithoutUndefined = _Texture._omitUndefined(options_);
|
|
3343
|
+
const mipLevel = optionsWithoutUndefined.mipLevel ?? 0;
|
|
3344
|
+
const mipLevelSize = this._getMipLevelSize(mipLevel);
|
|
2434
3345
|
const size = this.device.getExternalImageSize(options_.image);
|
|
2435
|
-
const options = {
|
|
2436
|
-
|
|
2437
|
-
|
|
3346
|
+
const options = {
|
|
3347
|
+
..._Texture.defaultCopyExternalImageOptions,
|
|
3348
|
+
...mipLevelSize,
|
|
3349
|
+
...size,
|
|
3350
|
+
...optionsWithoutUndefined
|
|
3351
|
+
};
|
|
3352
|
+
options.width = Math.min(options.width, mipLevelSize.width - options.x);
|
|
3353
|
+
options.height = Math.min(options.height, mipLevelSize.height - options.y);
|
|
3354
|
+
options.depth = Math.min(options.depth, mipLevelSize.depthOrArrayLayers - options.z);
|
|
3355
|
+
return options;
|
|
3356
|
+
}
|
|
3357
|
+
_normalizeTextureReadOptions(options_) {
|
|
3358
|
+
const optionsWithoutUndefined = _Texture._omitUndefined(options_);
|
|
3359
|
+
const mipLevel = optionsWithoutUndefined.mipLevel ?? 0;
|
|
3360
|
+
const mipLevelSize = this._getMipLevelSize(mipLevel);
|
|
3361
|
+
const options = {
|
|
3362
|
+
..._Texture.defaultTextureReadOptions,
|
|
3363
|
+
...mipLevelSize,
|
|
3364
|
+
...optionsWithoutUndefined
|
|
3365
|
+
};
|
|
3366
|
+
options.width = Math.min(options.width, mipLevelSize.width - options.x);
|
|
3367
|
+
options.height = Math.min(options.height, mipLevelSize.height - options.y);
|
|
3368
|
+
options.depthOrArrayLayers = Math.min(
|
|
3369
|
+
options.depthOrArrayLayers,
|
|
3370
|
+
mipLevelSize.depthOrArrayLayers - options.z
|
|
3371
|
+
);
|
|
2438
3372
|
return options;
|
|
2439
3373
|
}
|
|
3374
|
+
/**
|
|
3375
|
+
* Normalizes a texture read request and validates the color-only readback contract used by the
|
|
3376
|
+
* current texture read APIs. Supported dimensions are `2d`, `cube`, `cube-array`,
|
|
3377
|
+
* `2d-array`, and `3d`.
|
|
3378
|
+
*
|
|
3379
|
+
* @throws if the texture format, aspect, or dimension is not supported by the first-pass
|
|
3380
|
+
* color-read implementation.
|
|
3381
|
+
*/
|
|
3382
|
+
_getSupportedColorReadOptions(options_) {
|
|
3383
|
+
const options = this._normalizeTextureReadOptions(options_);
|
|
3384
|
+
const formatInfo = textureFormatDecoder.getInfo(this.format);
|
|
3385
|
+
this._validateColorReadAspect(options);
|
|
3386
|
+
this._validateColorReadFormat(formatInfo);
|
|
3387
|
+
switch (this.dimension) {
|
|
3388
|
+
case "2d":
|
|
3389
|
+
case "cube":
|
|
3390
|
+
case "cube-array":
|
|
3391
|
+
case "2d-array":
|
|
3392
|
+
case "3d":
|
|
3393
|
+
return options;
|
|
3394
|
+
default:
|
|
3395
|
+
throw new Error(`${this} color readback does not support ${this.dimension} textures`);
|
|
3396
|
+
}
|
|
3397
|
+
}
|
|
3398
|
+
/** Validates that a read request targets the full color aspect of the texture. */
|
|
3399
|
+
_validateColorReadAspect(options) {
|
|
3400
|
+
if (options.aspect !== "all") {
|
|
3401
|
+
throw new Error(`${this} color readback only supports aspect 'all'`);
|
|
3402
|
+
}
|
|
3403
|
+
}
|
|
3404
|
+
/** Validates that a read request targets an uncompressed color-renderable texture format. */
|
|
3405
|
+
_validateColorReadFormat(formatInfo) {
|
|
3406
|
+
if (formatInfo.compressed) {
|
|
3407
|
+
throw new Error(
|
|
3408
|
+
`${this} color readback does not support compressed formats (${this.format})`
|
|
3409
|
+
);
|
|
3410
|
+
}
|
|
3411
|
+
switch (formatInfo.attachment) {
|
|
3412
|
+
case "color":
|
|
3413
|
+
return;
|
|
3414
|
+
case "depth":
|
|
3415
|
+
throw new Error(`${this} color readback does not support depth formats (${this.format})`);
|
|
3416
|
+
case "stencil":
|
|
3417
|
+
throw new Error(`${this} color readback does not support stencil formats (${this.format})`);
|
|
3418
|
+
case "depth-stencil":
|
|
3419
|
+
throw new Error(
|
|
3420
|
+
`${this} color readback does not support depth-stencil formats (${this.format})`
|
|
3421
|
+
);
|
|
3422
|
+
default:
|
|
3423
|
+
throw new Error(`${this} color readback does not support format ${this.format}`);
|
|
3424
|
+
}
|
|
3425
|
+
}
|
|
3426
|
+
_normalizeTextureWriteOptions(options_) {
|
|
3427
|
+
const optionsWithoutUndefined = _Texture._omitUndefined(options_);
|
|
3428
|
+
const mipLevel = optionsWithoutUndefined.mipLevel ?? 0;
|
|
3429
|
+
const mipLevelSize = this._getMipLevelSize(mipLevel);
|
|
3430
|
+
const options = {
|
|
3431
|
+
..._Texture.defaultTextureWriteOptions,
|
|
3432
|
+
...mipLevelSize,
|
|
3433
|
+
...optionsWithoutUndefined
|
|
3434
|
+
};
|
|
3435
|
+
options.width = Math.min(options.width, mipLevelSize.width - options.x);
|
|
3436
|
+
options.height = Math.min(options.height, mipLevelSize.height - options.y);
|
|
3437
|
+
options.depthOrArrayLayers = Math.min(
|
|
3438
|
+
options.depthOrArrayLayers,
|
|
3439
|
+
mipLevelSize.depthOrArrayLayers - options.z
|
|
3440
|
+
);
|
|
3441
|
+
const layout = textureFormatDecoder.computeMemoryLayout({
|
|
3442
|
+
format: this.format,
|
|
3443
|
+
width: options.width,
|
|
3444
|
+
height: options.height,
|
|
3445
|
+
depth: options.depthOrArrayLayers,
|
|
3446
|
+
byteAlignment: this.byteAlignment
|
|
3447
|
+
});
|
|
3448
|
+
const minimumBytesPerRow = layout.bytesPerPixel * options.width;
|
|
3449
|
+
options.bytesPerRow = optionsWithoutUndefined.bytesPerRow ?? layout.bytesPerRow;
|
|
3450
|
+
options.rowsPerImage = optionsWithoutUndefined.rowsPerImage ?? options.height;
|
|
3451
|
+
if (options.bytesPerRow < minimumBytesPerRow) {
|
|
3452
|
+
throw new Error(
|
|
3453
|
+
`bytesPerRow (${options.bytesPerRow}) must be at least ${minimumBytesPerRow} for ${this.format}`
|
|
3454
|
+
);
|
|
3455
|
+
}
|
|
3456
|
+
if (options.rowsPerImage < options.height) {
|
|
3457
|
+
throw new Error(
|
|
3458
|
+
`rowsPerImage (${options.rowsPerImage}) must be at least ${options.height} for ${this.format}`
|
|
3459
|
+
);
|
|
3460
|
+
}
|
|
3461
|
+
const bytesPerPixel = this.device.getTextureFormatInfo(this.format).bytesPerPixel;
|
|
3462
|
+
if (bytesPerPixel && options.bytesPerRow % bytesPerPixel !== 0) {
|
|
3463
|
+
throw new Error(
|
|
3464
|
+
`bytesPerRow (${options.bytesPerRow}) must be a multiple of bytesPerPixel (${bytesPerPixel}) for ${this.format}`
|
|
3465
|
+
);
|
|
3466
|
+
}
|
|
3467
|
+
return options;
|
|
3468
|
+
}
|
|
3469
|
+
_getMipLevelSize(mipLevel) {
|
|
3470
|
+
const width = Math.max(1, this.width >> mipLevel);
|
|
3471
|
+
const height = this.baseDimension === "1d" ? 1 : Math.max(1, this.height >> mipLevel);
|
|
3472
|
+
const depthOrArrayLayers = this.dimension === "3d" ? Math.max(1, this.depth >> mipLevel) : this.depth;
|
|
3473
|
+
return { width, height, depthOrArrayLayers };
|
|
3474
|
+
}
|
|
3475
|
+
getAllocatedByteLength() {
|
|
3476
|
+
let allocatedByteLength = 0;
|
|
3477
|
+
for (let mipLevel = 0; mipLevel < this.mipLevels; mipLevel++) {
|
|
3478
|
+
const { width, height, depthOrArrayLayers } = this._getMipLevelSize(mipLevel);
|
|
3479
|
+
allocatedByteLength += textureFormatDecoder.computeMemoryLayout({
|
|
3480
|
+
format: this.format,
|
|
3481
|
+
width,
|
|
3482
|
+
height,
|
|
3483
|
+
depth: depthOrArrayLayers,
|
|
3484
|
+
byteAlignment: 1
|
|
3485
|
+
}).byteLength;
|
|
3486
|
+
}
|
|
3487
|
+
return allocatedByteLength * this.samples;
|
|
3488
|
+
}
|
|
3489
|
+
static _omitUndefined(options) {
|
|
3490
|
+
return Object.fromEntries(
|
|
3491
|
+
Object.entries(options).filter(([, value]) => value !== void 0)
|
|
3492
|
+
);
|
|
3493
|
+
}
|
|
2440
3494
|
};
|
|
2441
3495
|
var Texture = _Texture;
|
|
2442
3496
|
/** The texture can be bound for use as a sampled texture in a shader */
|
|
@@ -2453,13 +3507,12 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2453
3507
|
__publicField(Texture, "TEXTURE", 4);
|
|
2454
3508
|
/** @deprecated Use Texture.RENDER */
|
|
2455
3509
|
__publicField(Texture, "RENDER_ATTACHMENT", 16);
|
|
2456
|
-
/** Default options */
|
|
2457
3510
|
__publicField(Texture, "defaultProps", {
|
|
2458
3511
|
...Resource.defaultProps,
|
|
2459
3512
|
data: null,
|
|
2460
3513
|
dimension: "2d",
|
|
2461
3514
|
format: "rgba8unorm",
|
|
2462
|
-
usage: _Texture.
|
|
3515
|
+
usage: _Texture.SAMPLE | _Texture.RENDER | _Texture.COPY_DST,
|
|
2463
3516
|
width: void 0,
|
|
2464
3517
|
height: void 0,
|
|
2465
3518
|
depth: 1,
|
|
@@ -2473,6 +3526,10 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2473
3526
|
byteOffset: 0,
|
|
2474
3527
|
bytesPerRow: void 0,
|
|
2475
3528
|
rowsPerImage: void 0,
|
|
3529
|
+
width: void 0,
|
|
3530
|
+
height: void 0,
|
|
3531
|
+
depthOrArrayLayers: void 0,
|
|
3532
|
+
depth: 1,
|
|
2476
3533
|
mipLevel: 0,
|
|
2477
3534
|
x: 0,
|
|
2478
3535
|
y: 0,
|
|
@@ -2496,6 +3553,29 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2496
3553
|
premultipliedAlpha: false,
|
|
2497
3554
|
flipY: false
|
|
2498
3555
|
});
|
|
3556
|
+
__publicField(Texture, "defaultTextureReadOptions", {
|
|
3557
|
+
x: 0,
|
|
3558
|
+
y: 0,
|
|
3559
|
+
z: 0,
|
|
3560
|
+
width: void 0,
|
|
3561
|
+
height: void 0,
|
|
3562
|
+
depthOrArrayLayers: 1,
|
|
3563
|
+
mipLevel: 0,
|
|
3564
|
+
aspect: "all"
|
|
3565
|
+
});
|
|
3566
|
+
__publicField(Texture, "defaultTextureWriteOptions", {
|
|
3567
|
+
byteOffset: 0,
|
|
3568
|
+
bytesPerRow: void 0,
|
|
3569
|
+
rowsPerImage: void 0,
|
|
3570
|
+
x: 0,
|
|
3571
|
+
y: 0,
|
|
3572
|
+
z: 0,
|
|
3573
|
+
width: void 0,
|
|
3574
|
+
height: void 0,
|
|
3575
|
+
depthOrArrayLayers: 1,
|
|
3576
|
+
mipLevel: 0,
|
|
3577
|
+
aspect: "all"
|
|
3578
|
+
});
|
|
2499
3579
|
|
|
2500
3580
|
// src/adapter/resources/texture-view.ts
|
|
2501
3581
|
var _TextureView = class extends Resource {
|
|
@@ -2542,24 +3622,32 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2542
3622
|
const log2 = shaderLog.slice().sort((a, b) => a.lineNum - b.lineNum);
|
|
2543
3623
|
switch (options?.showSourceCode || "no") {
|
|
2544
3624
|
case "all":
|
|
2545
|
-
let
|
|
3625
|
+
let currentMessageIndex = 0;
|
|
2546
3626
|
for (let lineNum = 1; lineNum <= lines.length; lineNum++) {
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
formattedLog +=
|
|
3627
|
+
const line = lines[lineNum - 1];
|
|
3628
|
+
const currentMessage = log2[currentMessageIndex];
|
|
3629
|
+
if (line && currentMessage) {
|
|
3630
|
+
formattedLog += getNumberedLine(line, lineNum, options);
|
|
3631
|
+
}
|
|
3632
|
+
while (log2.length > currentMessageIndex && currentMessage.lineNum === lineNum) {
|
|
3633
|
+
const message = log2[currentMessageIndex++];
|
|
3634
|
+
if (message) {
|
|
3635
|
+
formattedLog += formatCompilerMessage(message, lines, message.lineNum, {
|
|
3636
|
+
...options,
|
|
3637
|
+
inlineSource: false
|
|
3638
|
+
});
|
|
3639
|
+
}
|
|
3640
|
+
}
|
|
3641
|
+
}
|
|
3642
|
+
while (log2.length > currentMessageIndex) {
|
|
3643
|
+
const message = log2[currentMessageIndex++];
|
|
3644
|
+
if (message) {
|
|
3645
|
+
formattedLog += formatCompilerMessage(message, [], 0, {
|
|
2551
3646
|
...options,
|
|
2552
3647
|
inlineSource: false
|
|
2553
3648
|
});
|
|
2554
3649
|
}
|
|
2555
3650
|
}
|
|
2556
|
-
while (log2.length > currentMessage) {
|
|
2557
|
-
const message = log2[currentMessage++];
|
|
2558
|
-
formattedLog += formatCompilerMessage(message, [], 0, {
|
|
2559
|
-
...options,
|
|
2560
|
-
inlineSource: false
|
|
2561
|
-
});
|
|
2562
|
-
}
|
|
2563
3651
|
return formattedLog;
|
|
2564
3652
|
case "issues":
|
|
2565
3653
|
case "no":
|
|
@@ -2581,8 +3669,8 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
2581
3669
|
|
|
2582
3670
|
`;
|
|
2583
3671
|
}
|
|
2584
|
-
const color = message.type === "error" ? "red" : "
|
|
2585
|
-
return options?.html ? `<div class='luma-compiler-log
|
|
3672
|
+
const color = message.type === "error" ? "red" : "orange";
|
|
3673
|
+
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}`;
|
|
2586
3674
|
}
|
|
2587
3675
|
function getNumberedLines(lines, lineNum, options) {
|
|
2588
3676
|
let numberedLines = "";
|
|
@@ -2668,29 +3756,34 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
2668
3756
|
}
|
|
2669
3757
|
const shaderName = shaderId;
|
|
2670
3758
|
const shaderTitle = `${this.stage} shader "${shaderName}"`;
|
|
2671
|
-
|
|
3759
|
+
const htmlLog = formatCompilerLog(messages, this.source, { showSourceCode: "all", html: true });
|
|
2672
3760
|
const translatedSource = this.getTranslatedSource();
|
|
3761
|
+
const container = document.createElement("div");
|
|
3762
|
+
container.innerHTML = `<h1>Compilation error in ${shaderTitle}</h1>
|
|
3763
|
+
<div style="display:flex;position:fixed;top:10px;right:20px;gap:2px;">
|
|
3764
|
+
<button id="copy">Copy source</button><br/>
|
|
3765
|
+
<button id="close">Close</button>
|
|
3766
|
+
</div>
|
|
3767
|
+
<code><pre>${htmlLog}</pre></code>`;
|
|
2673
3768
|
if (translatedSource) {
|
|
2674
|
-
|
|
2675
|
-
}
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
button.
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
const dataURI = `data:text/plain,${encodeURIComponent(this.source)}`;
|
|
2693
|
-
navigator.clipboard.writeText(dataURI);
|
|
3769
|
+
container.innerHTML += `<br /><h1>Translated Source</h1><br /><br /><code><pre>${translatedSource}</pre></code>`;
|
|
3770
|
+
}
|
|
3771
|
+
container.style.top = "0";
|
|
3772
|
+
container.style.left = "0";
|
|
3773
|
+
container.style.background = "white";
|
|
3774
|
+
container.style.position = "fixed";
|
|
3775
|
+
container.style.zIndex = "9999";
|
|
3776
|
+
container.style.maxWidth = "100vw";
|
|
3777
|
+
container.style.maxHeight = "100vh";
|
|
3778
|
+
container.style.overflowY = "auto";
|
|
3779
|
+
document.body.appendChild(container);
|
|
3780
|
+
const error = container.querySelector(".luma-compiler-log-error");
|
|
3781
|
+
error?.scrollIntoView();
|
|
3782
|
+
container.querySelector("button#close").onclick = () => {
|
|
3783
|
+
container.remove();
|
|
3784
|
+
};
|
|
3785
|
+
container.querySelector("button#copy").onclick = () => {
|
|
3786
|
+
navigator.clipboard.writeText(this.source);
|
|
2694
3787
|
};
|
|
2695
3788
|
}
|
|
2696
3789
|
};
|
|
@@ -2710,7 +3803,7 @@ ${htmlLog}
|
|
|
2710
3803
|
function getShaderName(shader, defaultName = "unnamed") {
|
|
2711
3804
|
const SHADER_NAME_REGEXP = /#define[\s*]SHADER_NAME[\s*]([A-Za-z0-9_-]+)[\s*]/;
|
|
2712
3805
|
const match = SHADER_NAME_REGEXP.exec(shader);
|
|
2713
|
-
return match
|
|
3806
|
+
return match?.[1] ?? defaultName;
|
|
2714
3807
|
}
|
|
2715
3808
|
|
|
2716
3809
|
// src/adapter/resources/framebuffer.ts
|
|
@@ -2736,7 +3829,12 @@ ${htmlLog}
|
|
|
2736
3829
|
(colorAttachment) => colorAttachment.texture.clone(size)
|
|
2737
3830
|
);
|
|
2738
3831
|
const depthStencilAttachment = this.depthStencilAttachment && this.depthStencilAttachment.texture.clone(size);
|
|
2739
|
-
return this.device.createFramebuffer({
|
|
3832
|
+
return this.device.createFramebuffer({
|
|
3833
|
+
...this.props,
|
|
3834
|
+
...size,
|
|
3835
|
+
colorAttachments,
|
|
3836
|
+
depthStencilAttachment
|
|
3837
|
+
});
|
|
2740
3838
|
}
|
|
2741
3839
|
resize(size) {
|
|
2742
3840
|
let updateSize = !size;
|
|
@@ -2811,17 +3909,15 @@ ${htmlLog}
|
|
|
2811
3909
|
* and destroys existing textures if owned
|
|
2812
3910
|
*/
|
|
2813
3911
|
resizeAttachments(width, height) {
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
}
|
|
2824
|
-
}
|
|
3912
|
+
this.colorAttachments.forEach((colorAttachment, i) => {
|
|
3913
|
+
const resizedTexture = colorAttachment.texture.clone({
|
|
3914
|
+
width,
|
|
3915
|
+
height
|
|
3916
|
+
});
|
|
3917
|
+
this.destroyAttachedResource(colorAttachment);
|
|
3918
|
+
this.colorAttachments[i] = resizedTexture.view;
|
|
3919
|
+
this.attachResource(resizedTexture.view);
|
|
3920
|
+
});
|
|
2825
3921
|
if (this.depthStencilAttachment) {
|
|
2826
3922
|
const resizedTexture = this.depthStencilAttachment.texture.clone({
|
|
2827
3923
|
width,
|
|
@@ -2858,30 +3954,547 @@ ${htmlLog}
|
|
|
2858
3954
|
linkStatus = "pending";
|
|
2859
3955
|
/** The hash of the pipeline */
|
|
2860
3956
|
hash = "";
|
|
3957
|
+
/** Optional shared backend implementation */
|
|
3958
|
+
sharedRenderPipeline = null;
|
|
3959
|
+
/** Whether shader or pipeline compilation/linking is still in progress */
|
|
3960
|
+
get isPending() {
|
|
3961
|
+
return this.linkStatus === "pending" || this.vs.compilationStatus === "pending" || this.fs?.compilationStatus === "pending";
|
|
3962
|
+
}
|
|
3963
|
+
/** Whether shader or pipeline compilation/linking has failed */
|
|
3964
|
+
get isErrored() {
|
|
3965
|
+
return this.linkStatus === "error" || this.vs.compilationStatus === "error" || this.fs?.compilationStatus === "error";
|
|
3966
|
+
}
|
|
2861
3967
|
constructor(device, props) {
|
|
2862
3968
|
super(device, props, _RenderPipeline.defaultProps);
|
|
2863
3969
|
this.shaderLayout = this.props.shaderLayout;
|
|
2864
3970
|
this.bufferLayout = this.props.bufferLayout || [];
|
|
3971
|
+
this.sharedRenderPipeline = this.props._sharedRenderPipeline || null;
|
|
3972
|
+
}
|
|
3973
|
+
};
|
|
3974
|
+
var RenderPipeline = _RenderPipeline;
|
|
3975
|
+
__publicField(RenderPipeline, "defaultProps", {
|
|
3976
|
+
...Resource.defaultProps,
|
|
3977
|
+
vs: null,
|
|
3978
|
+
vertexEntryPoint: "vertexMain",
|
|
3979
|
+
vsConstants: {},
|
|
3980
|
+
fs: null,
|
|
3981
|
+
fragmentEntryPoint: "fragmentMain",
|
|
3982
|
+
fsConstants: {},
|
|
3983
|
+
shaderLayout: null,
|
|
3984
|
+
bufferLayout: [],
|
|
3985
|
+
topology: "triangle-list",
|
|
3986
|
+
colorAttachmentFormats: void 0,
|
|
3987
|
+
depthStencilAttachmentFormat: void 0,
|
|
3988
|
+
parameters: {},
|
|
3989
|
+
varyings: void 0,
|
|
3990
|
+
bufferMode: void 0,
|
|
3991
|
+
disableWarnings: false,
|
|
3992
|
+
_sharedRenderPipeline: void 0,
|
|
3993
|
+
bindings: void 0,
|
|
3994
|
+
bindGroups: void 0
|
|
3995
|
+
});
|
|
3996
|
+
|
|
3997
|
+
// src/adapter/resources/shared-render-pipeline.ts
|
|
3998
|
+
var SharedRenderPipeline = class extends Resource {
|
|
3999
|
+
get [Symbol.toStringTag]() {
|
|
4000
|
+
return "SharedRenderPipeline";
|
|
4001
|
+
}
|
|
4002
|
+
constructor(device, props) {
|
|
4003
|
+
super(device, props, {
|
|
4004
|
+
...Resource.defaultProps,
|
|
4005
|
+
handle: void 0,
|
|
4006
|
+
vs: void 0,
|
|
4007
|
+
fs: void 0,
|
|
4008
|
+
varyings: void 0,
|
|
4009
|
+
bufferMode: void 0
|
|
4010
|
+
});
|
|
4011
|
+
}
|
|
4012
|
+
};
|
|
4013
|
+
|
|
4014
|
+
// src/adapter/resources/compute-pipeline.ts
|
|
4015
|
+
var _ComputePipeline = class extends Resource {
|
|
4016
|
+
get [Symbol.toStringTag]() {
|
|
4017
|
+
return "ComputePipeline";
|
|
4018
|
+
}
|
|
4019
|
+
hash = "";
|
|
4020
|
+
/** The merged shader layout */
|
|
4021
|
+
shaderLayout;
|
|
4022
|
+
constructor(device, props) {
|
|
4023
|
+
super(device, props, _ComputePipeline.defaultProps);
|
|
4024
|
+
this.shaderLayout = props.shaderLayout;
|
|
4025
|
+
}
|
|
4026
|
+
};
|
|
4027
|
+
var ComputePipeline = _ComputePipeline;
|
|
4028
|
+
__publicField(ComputePipeline, "defaultProps", {
|
|
4029
|
+
...Resource.defaultProps,
|
|
4030
|
+
shader: void 0,
|
|
4031
|
+
entryPoint: void 0,
|
|
4032
|
+
constants: {},
|
|
4033
|
+
shaderLayout: void 0
|
|
4034
|
+
});
|
|
4035
|
+
|
|
4036
|
+
// src/factories/pipeline-factory.ts
|
|
4037
|
+
var _PipelineFactory = class {
|
|
4038
|
+
/** Get the singleton default pipeline factory for the specified device */
|
|
4039
|
+
static getDefaultPipelineFactory(device) {
|
|
4040
|
+
const moduleData = device.getModuleData("@luma.gl/core");
|
|
4041
|
+
moduleData.defaultPipelineFactory ||= new _PipelineFactory(device);
|
|
4042
|
+
return moduleData.defaultPipelineFactory;
|
|
4043
|
+
}
|
|
4044
|
+
device;
|
|
4045
|
+
_hashCounter = 0;
|
|
4046
|
+
_hashes = {};
|
|
4047
|
+
_renderPipelineCache = {};
|
|
4048
|
+
_computePipelineCache = {};
|
|
4049
|
+
_sharedRenderPipelineCache = {};
|
|
4050
|
+
get [Symbol.toStringTag]() {
|
|
4051
|
+
return "PipelineFactory";
|
|
4052
|
+
}
|
|
4053
|
+
toString() {
|
|
4054
|
+
return `PipelineFactory(${this.device.id})`;
|
|
4055
|
+
}
|
|
4056
|
+
constructor(device) {
|
|
4057
|
+
this.device = device;
|
|
4058
|
+
}
|
|
4059
|
+
/**
|
|
4060
|
+
* WebGL has two cache layers with different priorities:
|
|
4061
|
+
* - `_sharedRenderPipelineCache` owns `WEBGLSharedRenderPipeline` / `WebGLProgram` reuse.
|
|
4062
|
+
* - `_renderPipelineCache` owns `RenderPipeline` wrapper reuse.
|
|
4063
|
+
*
|
|
4064
|
+
* Shared WebGL program reuse is the hard requirement. Wrapper reuse is beneficial,
|
|
4065
|
+
* but wrapper cache misses are acceptable if that keeps the cache logic simple and
|
|
4066
|
+
* prevents incorrect cache hits.
|
|
4067
|
+
*
|
|
4068
|
+
* In particular, wrapper hash logic must never force program creation or linked-program
|
|
4069
|
+
* introspection just to decide whether a shared WebGL program can be reused.
|
|
4070
|
+
*/
|
|
4071
|
+
/** Return a RenderPipeline matching supplied props. Reuses an equivalent pipeline if already created. */
|
|
4072
|
+
createRenderPipeline(props) {
|
|
4073
|
+
if (!this.device.props._cachePipelines) {
|
|
4074
|
+
return this.device.createRenderPipeline(props);
|
|
4075
|
+
}
|
|
4076
|
+
const allProps = { ...RenderPipeline.defaultProps, ...props };
|
|
4077
|
+
const cache = this._renderPipelineCache;
|
|
4078
|
+
const hash = this._hashRenderPipeline(allProps);
|
|
4079
|
+
let pipeline = cache[hash]?.resource;
|
|
4080
|
+
if (!pipeline) {
|
|
4081
|
+
const sharedRenderPipeline = this.device.type === "webgl" && this.device.props._sharePipelines ? this.createSharedRenderPipeline(allProps) : void 0;
|
|
4082
|
+
pipeline = this.device.createRenderPipeline({
|
|
4083
|
+
...allProps,
|
|
4084
|
+
id: allProps.id ? `${allProps.id}-cached` : uid("unnamed-cached"),
|
|
4085
|
+
_sharedRenderPipeline: sharedRenderPipeline
|
|
4086
|
+
});
|
|
4087
|
+
pipeline.hash = hash;
|
|
4088
|
+
cache[hash] = { resource: pipeline, useCount: 1 };
|
|
4089
|
+
if (this.device.props.debugFactories) {
|
|
4090
|
+
log.log(3, `${this}: ${pipeline} created, count=${cache[hash].useCount}`)();
|
|
4091
|
+
}
|
|
4092
|
+
} else {
|
|
4093
|
+
cache[hash].useCount++;
|
|
4094
|
+
if (this.device.props.debugFactories) {
|
|
4095
|
+
log.log(
|
|
4096
|
+
3,
|
|
4097
|
+
`${this}: ${cache[hash].resource} reused, count=${cache[hash].useCount}, (id=${props.id})`
|
|
4098
|
+
)();
|
|
4099
|
+
}
|
|
4100
|
+
}
|
|
4101
|
+
return pipeline;
|
|
4102
|
+
}
|
|
4103
|
+
/** Return a ComputePipeline matching supplied props. Reuses an equivalent pipeline if already created. */
|
|
4104
|
+
createComputePipeline(props) {
|
|
4105
|
+
if (!this.device.props._cachePipelines) {
|
|
4106
|
+
return this.device.createComputePipeline(props);
|
|
4107
|
+
}
|
|
4108
|
+
const allProps = { ...ComputePipeline.defaultProps, ...props };
|
|
4109
|
+
const cache = this._computePipelineCache;
|
|
4110
|
+
const hash = this._hashComputePipeline(allProps);
|
|
4111
|
+
let pipeline = cache[hash]?.resource;
|
|
4112
|
+
if (!pipeline) {
|
|
4113
|
+
pipeline = this.device.createComputePipeline({
|
|
4114
|
+
...allProps,
|
|
4115
|
+
id: allProps.id ? `${allProps.id}-cached` : void 0
|
|
4116
|
+
});
|
|
4117
|
+
pipeline.hash = hash;
|
|
4118
|
+
cache[hash] = { resource: pipeline, useCount: 1 };
|
|
4119
|
+
if (this.device.props.debugFactories) {
|
|
4120
|
+
log.log(3, `${this}: ${pipeline} created, count=${cache[hash].useCount}`)();
|
|
4121
|
+
}
|
|
4122
|
+
} else {
|
|
4123
|
+
cache[hash].useCount++;
|
|
4124
|
+
if (this.device.props.debugFactories) {
|
|
4125
|
+
log.log(
|
|
4126
|
+
3,
|
|
4127
|
+
`${this}: ${cache[hash].resource} reused, count=${cache[hash].useCount}, (id=${props.id})`
|
|
4128
|
+
)();
|
|
4129
|
+
}
|
|
4130
|
+
}
|
|
4131
|
+
return pipeline;
|
|
4132
|
+
}
|
|
4133
|
+
release(pipeline) {
|
|
4134
|
+
if (!this.device.props._cachePipelines) {
|
|
4135
|
+
pipeline.destroy();
|
|
4136
|
+
return;
|
|
4137
|
+
}
|
|
4138
|
+
const cache = this._getCache(pipeline);
|
|
4139
|
+
const hash = pipeline.hash;
|
|
4140
|
+
cache[hash].useCount--;
|
|
4141
|
+
if (cache[hash].useCount === 0) {
|
|
4142
|
+
this._destroyPipeline(pipeline);
|
|
4143
|
+
if (this.device.props.debugFactories) {
|
|
4144
|
+
log.log(3, `${this}: ${pipeline} released and destroyed`)();
|
|
4145
|
+
}
|
|
4146
|
+
} else if (cache[hash].useCount < 0) {
|
|
4147
|
+
log.error(`${this}: ${pipeline} released, useCount < 0, resetting`)();
|
|
4148
|
+
cache[hash].useCount = 0;
|
|
4149
|
+
} else if (this.device.props.debugFactories) {
|
|
4150
|
+
log.log(3, `${this}: ${pipeline} released, count=${cache[hash].useCount}`)();
|
|
4151
|
+
}
|
|
4152
|
+
}
|
|
4153
|
+
createSharedRenderPipeline(props) {
|
|
4154
|
+
const sharedPipelineHash = this._hashSharedRenderPipeline(props);
|
|
4155
|
+
let sharedCacheItem = this._sharedRenderPipelineCache[sharedPipelineHash];
|
|
4156
|
+
if (!sharedCacheItem) {
|
|
4157
|
+
const sharedRenderPipeline = this.device._createSharedRenderPipelineWebGL(props);
|
|
4158
|
+
sharedCacheItem = { resource: sharedRenderPipeline, useCount: 0 };
|
|
4159
|
+
this._sharedRenderPipelineCache[sharedPipelineHash] = sharedCacheItem;
|
|
4160
|
+
}
|
|
4161
|
+
sharedCacheItem.useCount++;
|
|
4162
|
+
return sharedCacheItem.resource;
|
|
4163
|
+
}
|
|
4164
|
+
releaseSharedRenderPipeline(pipeline) {
|
|
4165
|
+
if (!pipeline.sharedRenderPipeline) {
|
|
4166
|
+
return;
|
|
4167
|
+
}
|
|
4168
|
+
const sharedPipelineHash = this._hashSharedRenderPipeline(pipeline.sharedRenderPipeline.props);
|
|
4169
|
+
const sharedCacheItem = this._sharedRenderPipelineCache[sharedPipelineHash];
|
|
4170
|
+
if (!sharedCacheItem) {
|
|
4171
|
+
return;
|
|
4172
|
+
}
|
|
4173
|
+
sharedCacheItem.useCount--;
|
|
4174
|
+
if (sharedCacheItem.useCount === 0) {
|
|
4175
|
+
sharedCacheItem.resource.destroy();
|
|
4176
|
+
delete this._sharedRenderPipelineCache[sharedPipelineHash];
|
|
4177
|
+
}
|
|
4178
|
+
}
|
|
4179
|
+
// PRIVATE
|
|
4180
|
+
/** Destroy a cached pipeline, removing it from the cache if configured to do so. */
|
|
4181
|
+
_destroyPipeline(pipeline) {
|
|
4182
|
+
const cache = this._getCache(pipeline);
|
|
4183
|
+
if (!this.device.props._destroyPipelines) {
|
|
4184
|
+
return false;
|
|
4185
|
+
}
|
|
4186
|
+
delete cache[pipeline.hash];
|
|
4187
|
+
pipeline.destroy();
|
|
4188
|
+
if (pipeline instanceof RenderPipeline) {
|
|
4189
|
+
this.releaseSharedRenderPipeline(pipeline);
|
|
4190
|
+
}
|
|
4191
|
+
return true;
|
|
4192
|
+
}
|
|
4193
|
+
/** Get the appropriate cache for the type of pipeline */
|
|
4194
|
+
_getCache(pipeline) {
|
|
4195
|
+
let cache;
|
|
4196
|
+
if (pipeline instanceof ComputePipeline) {
|
|
4197
|
+
cache = this._computePipelineCache;
|
|
4198
|
+
}
|
|
4199
|
+
if (pipeline instanceof RenderPipeline) {
|
|
4200
|
+
cache = this._renderPipelineCache;
|
|
4201
|
+
}
|
|
4202
|
+
if (!cache) {
|
|
4203
|
+
throw new Error(`${this}`);
|
|
4204
|
+
}
|
|
4205
|
+
if (!cache[pipeline.hash]) {
|
|
4206
|
+
throw new Error(`${this}: ${pipeline} matched incorrect entry`);
|
|
4207
|
+
}
|
|
4208
|
+
return cache;
|
|
4209
|
+
}
|
|
4210
|
+
/** Calculate a hash based on all the inputs for a compute pipeline */
|
|
4211
|
+
_hashComputePipeline(props) {
|
|
4212
|
+
const { type } = this.device;
|
|
4213
|
+
const shaderHash = this._getHash(props.shader.source);
|
|
4214
|
+
const shaderLayoutHash = this._getHash(JSON.stringify(props.shaderLayout));
|
|
4215
|
+
return `${type}/C/${shaderHash}SL${shaderLayoutHash}`;
|
|
4216
|
+
}
|
|
4217
|
+
/** Calculate a hash based on all the inputs for a render pipeline */
|
|
4218
|
+
_hashRenderPipeline(props) {
|
|
4219
|
+
const vsHash = props.vs ? this._getHash(props.vs.source) : 0;
|
|
4220
|
+
const fsHash = props.fs ? this._getHash(props.fs.source) : 0;
|
|
4221
|
+
const varyingHash = this._getWebGLVaryingHash(props);
|
|
4222
|
+
const shaderLayoutHash = this._getHash(JSON.stringify(props.shaderLayout));
|
|
4223
|
+
const bufferLayoutHash = this._getHash(JSON.stringify(props.bufferLayout));
|
|
4224
|
+
const { type } = this.device;
|
|
4225
|
+
switch (type) {
|
|
4226
|
+
case "webgl":
|
|
4227
|
+
const webglParameterHash = this._getHash(JSON.stringify(props.parameters));
|
|
4228
|
+
return `${type}/R/${vsHash}/${fsHash}V${varyingHash}T${props.topology}P${webglParameterHash}SL${shaderLayoutHash}BL${bufferLayoutHash}`;
|
|
4229
|
+
case "webgpu":
|
|
4230
|
+
default:
|
|
4231
|
+
const entryPointHash = this._getHash(
|
|
4232
|
+
JSON.stringify({
|
|
4233
|
+
vertexEntryPoint: props.vertexEntryPoint,
|
|
4234
|
+
fragmentEntryPoint: props.fragmentEntryPoint
|
|
4235
|
+
})
|
|
4236
|
+
);
|
|
4237
|
+
const parameterHash = this._getHash(JSON.stringify(props.parameters));
|
|
4238
|
+
const attachmentHash = this._getWebGPUAttachmentHash(props);
|
|
4239
|
+
return `${type}/R/${vsHash}/${fsHash}V${varyingHash}T${props.topology}EP${entryPointHash}P${parameterHash}SL${shaderLayoutHash}BL${bufferLayoutHash}A${attachmentHash}`;
|
|
4240
|
+
}
|
|
4241
|
+
}
|
|
4242
|
+
// This is the only gate for shared `WebGLProgram` reuse.
|
|
4243
|
+
// Only include inputs that affect program linking or transform-feedback linkage.
|
|
4244
|
+
// Wrapper-only concerns such as topology, parameters, attachment formats and layout
|
|
4245
|
+
// overrides must not be added here.
|
|
4246
|
+
_hashSharedRenderPipeline(props) {
|
|
4247
|
+
const vsHash = props.vs ? this._getHash(props.vs.source) : 0;
|
|
4248
|
+
const fsHash = props.fs ? this._getHash(props.fs.source) : 0;
|
|
4249
|
+
const varyingHash = this._getWebGLVaryingHash(props);
|
|
4250
|
+
return `webgl/S/${vsHash}/${fsHash}V${varyingHash}`;
|
|
4251
|
+
}
|
|
4252
|
+
_getHash(key) {
|
|
4253
|
+
if (this._hashes[key] === void 0) {
|
|
4254
|
+
this._hashes[key] = this._hashCounter++;
|
|
4255
|
+
}
|
|
4256
|
+
return this._hashes[key];
|
|
4257
|
+
}
|
|
4258
|
+
_getWebGLVaryingHash(props) {
|
|
4259
|
+
const { varyings = [], bufferMode = null } = props;
|
|
4260
|
+
return this._getHash(JSON.stringify({ varyings, bufferMode }));
|
|
4261
|
+
}
|
|
4262
|
+
_getWebGPUAttachmentHash(props) {
|
|
4263
|
+
const colorAttachmentFormats = props.colorAttachmentFormats ?? [
|
|
4264
|
+
this.device.preferredColorFormat
|
|
4265
|
+
];
|
|
4266
|
+
const depthStencilAttachmentFormat = props.parameters?.depthWriteEnabled ? props.depthStencilAttachmentFormat || this.device.preferredDepthFormat : null;
|
|
4267
|
+
return this._getHash(
|
|
4268
|
+
JSON.stringify({
|
|
4269
|
+
colorAttachmentFormats,
|
|
4270
|
+
depthStencilAttachmentFormat
|
|
4271
|
+
})
|
|
4272
|
+
);
|
|
4273
|
+
}
|
|
4274
|
+
};
|
|
4275
|
+
var PipelineFactory = _PipelineFactory;
|
|
4276
|
+
__publicField(PipelineFactory, "defaultProps", { ...RenderPipeline.defaultProps });
|
|
4277
|
+
|
|
4278
|
+
// src/factories/shader-factory.ts
|
|
4279
|
+
var _ShaderFactory = class {
|
|
4280
|
+
/** Returns the default ShaderFactory for the given {@link Device}, creating one if necessary. */
|
|
4281
|
+
static getDefaultShaderFactory(device) {
|
|
4282
|
+
const moduleData = device.getModuleData("@luma.gl/core");
|
|
4283
|
+
moduleData.defaultShaderFactory ||= new _ShaderFactory(device);
|
|
4284
|
+
return moduleData.defaultShaderFactory;
|
|
4285
|
+
}
|
|
4286
|
+
device;
|
|
4287
|
+
_cache = {};
|
|
4288
|
+
get [Symbol.toStringTag]() {
|
|
4289
|
+
return "ShaderFactory";
|
|
4290
|
+
}
|
|
4291
|
+
toString() {
|
|
4292
|
+
return `${this[Symbol.toStringTag]}(${this.device.id})`;
|
|
4293
|
+
}
|
|
4294
|
+
/** @internal */
|
|
4295
|
+
constructor(device) {
|
|
4296
|
+
this.device = device;
|
|
4297
|
+
}
|
|
4298
|
+
/** Requests a {@link Shader} from the cache, creating a new Shader only if necessary. */
|
|
4299
|
+
createShader(props) {
|
|
4300
|
+
if (!this.device.props._cacheShaders) {
|
|
4301
|
+
return this.device.createShader(props);
|
|
4302
|
+
}
|
|
4303
|
+
const key = this._hashShader(props);
|
|
4304
|
+
let cacheEntry = this._cache[key];
|
|
4305
|
+
if (!cacheEntry) {
|
|
4306
|
+
const resource = this.device.createShader({
|
|
4307
|
+
...props,
|
|
4308
|
+
id: props.id ? `${props.id}-cached` : void 0
|
|
4309
|
+
});
|
|
4310
|
+
this._cache[key] = cacheEntry = { resource, useCount: 1 };
|
|
4311
|
+
if (this.device.props.debugFactories) {
|
|
4312
|
+
log.log(3, `${this}: Created new shader ${resource.id}`)();
|
|
4313
|
+
}
|
|
4314
|
+
} else {
|
|
4315
|
+
cacheEntry.useCount++;
|
|
4316
|
+
if (this.device.props.debugFactories) {
|
|
4317
|
+
log.log(
|
|
4318
|
+
3,
|
|
4319
|
+
`${this}: Reusing shader ${cacheEntry.resource.id} count=${cacheEntry.useCount}`
|
|
4320
|
+
)();
|
|
4321
|
+
}
|
|
4322
|
+
}
|
|
4323
|
+
return cacheEntry.resource;
|
|
4324
|
+
}
|
|
4325
|
+
/** Releases a previously-requested {@link Shader}, destroying it if no users remain. */
|
|
4326
|
+
release(shader) {
|
|
4327
|
+
if (!this.device.props._cacheShaders) {
|
|
4328
|
+
shader.destroy();
|
|
4329
|
+
return;
|
|
4330
|
+
}
|
|
4331
|
+
const key = this._hashShader(shader);
|
|
4332
|
+
const cacheEntry = this._cache[key];
|
|
4333
|
+
if (cacheEntry) {
|
|
4334
|
+
cacheEntry.useCount--;
|
|
4335
|
+
if (cacheEntry.useCount === 0) {
|
|
4336
|
+
if (this.device.props._destroyShaders) {
|
|
4337
|
+
delete this._cache[key];
|
|
4338
|
+
cacheEntry.resource.destroy();
|
|
4339
|
+
if (this.device.props.debugFactories) {
|
|
4340
|
+
log.log(3, `${this}: Releasing shader ${shader.id}, destroyed`)();
|
|
4341
|
+
}
|
|
4342
|
+
}
|
|
4343
|
+
} else if (cacheEntry.useCount < 0) {
|
|
4344
|
+
throw new Error(`ShaderFactory: Shader ${shader.id} released too many times`);
|
|
4345
|
+
} else if (this.device.props.debugFactories) {
|
|
4346
|
+
log.log(3, `${this}: Releasing shader ${shader.id} count=${cacheEntry.useCount}`)();
|
|
4347
|
+
}
|
|
4348
|
+
}
|
|
4349
|
+
}
|
|
4350
|
+
// PRIVATE
|
|
4351
|
+
_hashShader(value) {
|
|
4352
|
+
return `${value.stage}:${value.source}`;
|
|
4353
|
+
}
|
|
4354
|
+
};
|
|
4355
|
+
var ShaderFactory = _ShaderFactory;
|
|
4356
|
+
__publicField(ShaderFactory, "defaultProps", { ...Shader.defaultProps });
|
|
4357
|
+
|
|
4358
|
+
// src/adapter-utils/bind-groups.ts
|
|
4359
|
+
function getShaderLayoutBinding(shaderLayout, bindingName, options) {
|
|
4360
|
+
const bindingLayout = shaderLayout.bindings.find(
|
|
4361
|
+
(binding) => binding.name === bindingName || `${binding.name.toLocaleLowerCase()}uniforms` === bindingName.toLocaleLowerCase()
|
|
4362
|
+
);
|
|
4363
|
+
if (!bindingLayout && !options?.ignoreWarnings) {
|
|
4364
|
+
log.warn(`Binding ${bindingName} not set: Not found in shader layout.`)();
|
|
4365
|
+
}
|
|
4366
|
+
return bindingLayout || null;
|
|
4367
|
+
}
|
|
4368
|
+
function normalizeBindingsByGroup(shaderLayout, bindingsOrBindGroups) {
|
|
4369
|
+
if (!bindingsOrBindGroups) {
|
|
4370
|
+
return {};
|
|
4371
|
+
}
|
|
4372
|
+
if (areBindingsGrouped(bindingsOrBindGroups)) {
|
|
4373
|
+
const bindGroups2 = bindingsOrBindGroups;
|
|
4374
|
+
return Object.fromEntries(
|
|
4375
|
+
Object.entries(bindGroups2).map(([group, bindings]) => [Number(group), { ...bindings }])
|
|
4376
|
+
);
|
|
4377
|
+
}
|
|
4378
|
+
const bindGroups = {};
|
|
4379
|
+
for (const [bindingName, binding] of Object.entries(bindingsOrBindGroups)) {
|
|
4380
|
+
const bindingLayout = getShaderLayoutBinding(shaderLayout, bindingName);
|
|
4381
|
+
const group = bindingLayout?.group ?? 0;
|
|
4382
|
+
bindGroups[group] ||= {};
|
|
4383
|
+
bindGroups[group][bindingName] = binding;
|
|
4384
|
+
}
|
|
4385
|
+
return bindGroups;
|
|
4386
|
+
}
|
|
4387
|
+
function flattenBindingsByGroup(bindGroups) {
|
|
4388
|
+
const bindings = {};
|
|
4389
|
+
for (const groupBindings of Object.values(bindGroups)) {
|
|
4390
|
+
Object.assign(bindings, groupBindings);
|
|
4391
|
+
}
|
|
4392
|
+
return bindings;
|
|
4393
|
+
}
|
|
4394
|
+
function areBindingsGrouped(bindingsOrBindGroups) {
|
|
4395
|
+
const keys = Object.keys(bindingsOrBindGroups);
|
|
4396
|
+
return keys.length > 0 && keys.every((key) => /^\d+$/.test(key));
|
|
4397
|
+
}
|
|
4398
|
+
|
|
4399
|
+
// src/factories/bind-group-factory.ts
|
|
4400
|
+
var BindGroupFactory = class {
|
|
4401
|
+
device;
|
|
4402
|
+
_layoutCacheByPipeline = /* @__PURE__ */ new WeakMap();
|
|
4403
|
+
_bindGroupCacheByLayout = /* @__PURE__ */ new WeakMap();
|
|
4404
|
+
constructor(device) {
|
|
4405
|
+
this.device = device;
|
|
4406
|
+
}
|
|
4407
|
+
getBindGroups(pipeline, bindings, bindGroupCacheKeys) {
|
|
4408
|
+
if (this.device.type !== "webgpu" || pipeline.shaderLayout.bindings.length === 0) {
|
|
4409
|
+
return {};
|
|
4410
|
+
}
|
|
4411
|
+
const bindingsByGroup = normalizeBindingsByGroup(pipeline.shaderLayout, bindings);
|
|
4412
|
+
const resolvedBindGroups = {};
|
|
4413
|
+
for (const group of getBindGroupIndicesUpToMax(pipeline.shaderLayout.bindings)) {
|
|
4414
|
+
const groupBindings = bindingsByGroup[group];
|
|
4415
|
+
const bindGroupLayout = this._getBindGroupLayout(pipeline, group);
|
|
4416
|
+
const bindGroupLabel = getBindGroupLabel(pipeline, pipeline.shaderLayout, group);
|
|
4417
|
+
if (!groupBindings || Object.keys(groupBindings).length === 0) {
|
|
4418
|
+
if (!hasBindingsInGroup(pipeline.shaderLayout.bindings, group)) {
|
|
4419
|
+
resolvedBindGroups[group] = this._getEmptyBindGroup(
|
|
4420
|
+
bindGroupLayout,
|
|
4421
|
+
pipeline.shaderLayout,
|
|
4422
|
+
group,
|
|
4423
|
+
bindGroupLabel
|
|
4424
|
+
);
|
|
4425
|
+
}
|
|
4426
|
+
continue;
|
|
4427
|
+
}
|
|
4428
|
+
const bindGroupCacheKey = bindGroupCacheKeys?.[group];
|
|
4429
|
+
if (bindGroupCacheKey) {
|
|
4430
|
+
const layoutCache = this._getLayoutBindGroupCache(bindGroupLayout);
|
|
4431
|
+
if (layoutCache.bindGroupsBySource.has(bindGroupCacheKey)) {
|
|
4432
|
+
resolvedBindGroups[group] = layoutCache.bindGroupsBySource.get(bindGroupCacheKey) || null;
|
|
4433
|
+
continue;
|
|
4434
|
+
}
|
|
4435
|
+
const bindGroup = this.device._createBindGroupWebGPU(
|
|
4436
|
+
bindGroupLayout,
|
|
4437
|
+
pipeline.shaderLayout,
|
|
4438
|
+
groupBindings,
|
|
4439
|
+
group,
|
|
4440
|
+
bindGroupLabel
|
|
4441
|
+
);
|
|
4442
|
+
layoutCache.bindGroupsBySource.set(bindGroupCacheKey, bindGroup);
|
|
4443
|
+
resolvedBindGroups[group] = bindGroup;
|
|
4444
|
+
} else {
|
|
4445
|
+
resolvedBindGroups[group] = this.device._createBindGroupWebGPU(
|
|
4446
|
+
bindGroupLayout,
|
|
4447
|
+
pipeline.shaderLayout,
|
|
4448
|
+
groupBindings,
|
|
4449
|
+
group,
|
|
4450
|
+
bindGroupLabel
|
|
4451
|
+
);
|
|
4452
|
+
}
|
|
4453
|
+
}
|
|
4454
|
+
return resolvedBindGroups;
|
|
4455
|
+
}
|
|
4456
|
+
_getBindGroupLayout(pipeline, group) {
|
|
4457
|
+
let layoutCache = this._layoutCacheByPipeline.get(pipeline);
|
|
4458
|
+
if (!layoutCache) {
|
|
4459
|
+
layoutCache = {};
|
|
4460
|
+
this._layoutCacheByPipeline.set(pipeline, layoutCache);
|
|
4461
|
+
}
|
|
4462
|
+
layoutCache[group] ||= this.device._createBindGroupLayoutWebGPU(pipeline, group);
|
|
4463
|
+
return layoutCache[group];
|
|
4464
|
+
}
|
|
4465
|
+
_getEmptyBindGroup(bindGroupLayout, shaderLayout, group, label) {
|
|
4466
|
+
const layoutCache = this._getLayoutBindGroupCache(bindGroupLayout);
|
|
4467
|
+
layoutCache.emptyBindGroup ||= this.device._createBindGroupWebGPU(bindGroupLayout, shaderLayout, {}, group, label) || null;
|
|
4468
|
+
return layoutCache.emptyBindGroup;
|
|
4469
|
+
}
|
|
4470
|
+
_getLayoutBindGroupCache(bindGroupLayout) {
|
|
4471
|
+
let layoutCache = this._bindGroupCacheByLayout.get(bindGroupLayout);
|
|
4472
|
+
if (!layoutCache) {
|
|
4473
|
+
layoutCache = { bindGroupsBySource: /* @__PURE__ */ new WeakMap() };
|
|
4474
|
+
this._bindGroupCacheByLayout.set(bindGroupLayout, layoutCache);
|
|
4475
|
+
}
|
|
4476
|
+
return layoutCache;
|
|
2865
4477
|
}
|
|
2866
4478
|
};
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
bindings
|
|
2883
|
-
|
|
2884
|
-
|
|
4479
|
+
function _getDefaultBindGroupFactory(device) {
|
|
4480
|
+
device._factories.bindGroupFactory ||= new BindGroupFactory(device);
|
|
4481
|
+
return device._factories.bindGroupFactory;
|
|
4482
|
+
}
|
|
4483
|
+
function getBindGroupIndicesUpToMax(bindings) {
|
|
4484
|
+
const maxGroup = bindings.reduce(
|
|
4485
|
+
(highestGroup, binding) => Math.max(highestGroup, binding.group),
|
|
4486
|
+
-1
|
|
4487
|
+
);
|
|
4488
|
+
return Array.from({ length: maxGroup + 1 }, (_, group) => group);
|
|
4489
|
+
}
|
|
4490
|
+
function hasBindingsInGroup(bindings, group) {
|
|
4491
|
+
return bindings.some((binding) => binding.group === group);
|
|
4492
|
+
}
|
|
4493
|
+
function getBindGroupLabel(pipeline, shaderLayout, group) {
|
|
4494
|
+
const bindingNames = shaderLayout.bindings.filter((binding) => binding.group === group).sort((left, right) => left.location - right.location).map((binding) => binding.name);
|
|
4495
|
+
const bindingSuffix = bindingNames.length > 0 ? bindingNames.join(",") : "empty";
|
|
4496
|
+
return `${pipeline.id}/group${group}[${bindingSuffix}]`;
|
|
4497
|
+
}
|
|
2885
4498
|
|
|
2886
4499
|
// src/adapter/resources/render-pass.ts
|
|
2887
4500
|
var _RenderPass = class extends Resource {
|
|
@@ -2921,28 +4534,6 @@ ${htmlLog}
|
|
|
2921
4534
|
endTimestampIndex: void 0
|
|
2922
4535
|
});
|
|
2923
4536
|
|
|
2924
|
-
// src/adapter/resources/compute-pipeline.ts
|
|
2925
|
-
var _ComputePipeline = class extends Resource {
|
|
2926
|
-
get [Symbol.toStringTag]() {
|
|
2927
|
-
return "ComputePipeline";
|
|
2928
|
-
}
|
|
2929
|
-
hash = "";
|
|
2930
|
-
/** The merged shader layout */
|
|
2931
|
-
shaderLayout;
|
|
2932
|
-
constructor(device, props) {
|
|
2933
|
-
super(device, props, _ComputePipeline.defaultProps);
|
|
2934
|
-
this.shaderLayout = props.shaderLayout;
|
|
2935
|
-
}
|
|
2936
|
-
};
|
|
2937
|
-
var ComputePipeline = _ComputePipeline;
|
|
2938
|
-
__publicField(ComputePipeline, "defaultProps", {
|
|
2939
|
-
...Resource.defaultProps,
|
|
2940
|
-
shader: void 0,
|
|
2941
|
-
entryPoint: void 0,
|
|
2942
|
-
constants: {},
|
|
2943
|
-
shaderLayout: void 0
|
|
2944
|
-
});
|
|
2945
|
-
|
|
2946
4537
|
// src/adapter/resources/compute-pass.ts
|
|
2947
4538
|
var _ComputePass = class extends Resource {
|
|
2948
4539
|
constructor(device, props) {
|
|
@@ -2965,8 +4556,69 @@ ${htmlLog}
|
|
|
2965
4556
|
get [Symbol.toStringTag]() {
|
|
2966
4557
|
return "CommandEncoder";
|
|
2967
4558
|
}
|
|
4559
|
+
_timeProfilingQuerySet = null;
|
|
4560
|
+
_timeProfilingSlotCount = 0;
|
|
4561
|
+
_gpuTimeMs;
|
|
2968
4562
|
constructor(device, props) {
|
|
2969
4563
|
super(device, props, _CommandEncoder.defaultProps);
|
|
4564
|
+
this._timeProfilingQuerySet = props.timeProfilingQuerySet ?? null;
|
|
4565
|
+
this._timeProfilingSlotCount = 0;
|
|
4566
|
+
this._gpuTimeMs = void 0;
|
|
4567
|
+
}
|
|
4568
|
+
/**
|
|
4569
|
+
* Reads all resolved timestamp pairs on the current profiler query set and caches the sum
|
|
4570
|
+
* as milliseconds on this encoder.
|
|
4571
|
+
*/
|
|
4572
|
+
async resolveTimeProfilingQuerySet() {
|
|
4573
|
+
this._gpuTimeMs = void 0;
|
|
4574
|
+
if (!this._timeProfilingQuerySet) {
|
|
4575
|
+
return;
|
|
4576
|
+
}
|
|
4577
|
+
const pairCount = Math.floor(this._timeProfilingSlotCount / 2);
|
|
4578
|
+
if (pairCount <= 0) {
|
|
4579
|
+
return;
|
|
4580
|
+
}
|
|
4581
|
+
const queryCount = pairCount * 2;
|
|
4582
|
+
const results = await this._timeProfilingQuerySet.readResults({
|
|
4583
|
+
firstQuery: 0,
|
|
4584
|
+
queryCount
|
|
4585
|
+
});
|
|
4586
|
+
let totalDurationNanoseconds = 0n;
|
|
4587
|
+
for (let queryIndex = 0; queryIndex < queryCount; queryIndex += 2) {
|
|
4588
|
+
totalDurationNanoseconds += results[queryIndex + 1] - results[queryIndex];
|
|
4589
|
+
}
|
|
4590
|
+
this._gpuTimeMs = Number(totalDurationNanoseconds) / 1e6;
|
|
4591
|
+
}
|
|
4592
|
+
/** Returns the number of query slots consumed by automatic pass profiling on this encoder. */
|
|
4593
|
+
getTimeProfilingSlotCount() {
|
|
4594
|
+
return this._timeProfilingSlotCount;
|
|
4595
|
+
}
|
|
4596
|
+
getTimeProfilingQuerySet() {
|
|
4597
|
+
return this._timeProfilingQuerySet;
|
|
4598
|
+
}
|
|
4599
|
+
/** Internal helper for auto-assigning timestamp slots to render/compute passes on this encoder. */
|
|
4600
|
+
_applyTimeProfilingToPassProps(props) {
|
|
4601
|
+
const passProps = props || {};
|
|
4602
|
+
if (!this._supportsTimestampQueries() || !this._timeProfilingQuerySet) {
|
|
4603
|
+
return passProps;
|
|
4604
|
+
}
|
|
4605
|
+
if (passProps.timestampQuerySet !== void 0 || passProps.beginTimestampIndex !== void 0 || passProps.endTimestampIndex !== void 0) {
|
|
4606
|
+
return passProps;
|
|
4607
|
+
}
|
|
4608
|
+
const beginTimestampIndex = this._timeProfilingSlotCount;
|
|
4609
|
+
if (beginTimestampIndex + 1 >= this._timeProfilingQuerySet.props.count) {
|
|
4610
|
+
return passProps;
|
|
4611
|
+
}
|
|
4612
|
+
this._timeProfilingSlotCount += 2;
|
|
4613
|
+
return {
|
|
4614
|
+
...passProps,
|
|
4615
|
+
timestampQuerySet: this._timeProfilingQuerySet,
|
|
4616
|
+
beginTimestampIndex,
|
|
4617
|
+
endTimestampIndex: beginTimestampIndex + 1
|
|
4618
|
+
};
|
|
4619
|
+
}
|
|
4620
|
+
_supportsTimestampQueries() {
|
|
4621
|
+
return this.device.features.has("timestamp-query");
|
|
2970
4622
|
}
|
|
2971
4623
|
};
|
|
2972
4624
|
var CommandEncoder = _CommandEncoder;
|
|
@@ -2975,7 +4627,8 @@ ${htmlLog}
|
|
|
2975
4627
|
// beginComputePass(optional GPUComputePassDescriptor descriptor = {}): GPUComputePassEncoder;
|
|
2976
4628
|
__publicField(CommandEncoder, "defaultProps", {
|
|
2977
4629
|
...Resource.defaultProps,
|
|
2978
|
-
measureExecutionTime: void 0
|
|
4630
|
+
measureExecutionTime: void 0,
|
|
4631
|
+
timeProfilingQuerySet: void 0
|
|
2979
4632
|
});
|
|
2980
4633
|
|
|
2981
4634
|
// src/adapter/resources/command-buffer.ts
|
|
@@ -2992,13 +4645,22 @@ ${htmlLog}
|
|
|
2992
4645
|
...Resource.defaultProps
|
|
2993
4646
|
});
|
|
2994
4647
|
|
|
2995
|
-
// src/shadertypes/
|
|
4648
|
+
// src/shadertypes/shader-types/shader-type-decoder.ts
|
|
2996
4649
|
function getVariableShaderTypeInfo(format) {
|
|
2997
|
-
const
|
|
4650
|
+
const resolvedFormat = resolveVariableShaderTypeAlias(format);
|
|
4651
|
+
const decoded = UNIFORM_FORMATS[resolvedFormat];
|
|
4652
|
+
if (!decoded) {
|
|
4653
|
+
throw new Error(`Unsupported variable shader type: ${format}`);
|
|
4654
|
+
}
|
|
2998
4655
|
return decoded;
|
|
2999
4656
|
}
|
|
3000
4657
|
function getAttributeShaderTypeInfo(attributeType) {
|
|
3001
|
-
const
|
|
4658
|
+
const resolvedAttributeType = resolveAttributeShaderTypeAlias(attributeType);
|
|
4659
|
+
const decoded = TYPE_INFO[resolvedAttributeType];
|
|
4660
|
+
if (!decoded) {
|
|
4661
|
+
throw new Error(`Unsupported attribute shader type: ${attributeType}`);
|
|
4662
|
+
}
|
|
4663
|
+
const [primitiveType, components] = decoded;
|
|
3002
4664
|
const integer = primitiveType === "i32" || primitiveType === "u32";
|
|
3003
4665
|
const signed = primitiveType !== "u32";
|
|
3004
4666
|
const byteLength = PRIMITIVE_TYPE_SIZES[primitiveType] * components;
|
|
@@ -3010,6 +4672,33 @@ ${htmlLog}
|
|
|
3010
4672
|
signed
|
|
3011
4673
|
};
|
|
3012
4674
|
}
|
|
4675
|
+
var ShaderTypeDecoder = class {
|
|
4676
|
+
getVariableShaderTypeInfo(format) {
|
|
4677
|
+
return getVariableShaderTypeInfo(format);
|
|
4678
|
+
}
|
|
4679
|
+
getAttributeShaderTypeInfo(attributeType) {
|
|
4680
|
+
return getAttributeShaderTypeInfo(attributeType);
|
|
4681
|
+
}
|
|
4682
|
+
makeShaderAttributeType(primitiveType, components) {
|
|
4683
|
+
return makeShaderAttributeType(primitiveType, components);
|
|
4684
|
+
}
|
|
4685
|
+
resolveAttributeShaderTypeAlias(alias) {
|
|
4686
|
+
return resolveAttributeShaderTypeAlias(alias);
|
|
4687
|
+
}
|
|
4688
|
+
resolveVariableShaderTypeAlias(alias) {
|
|
4689
|
+
return resolveVariableShaderTypeAlias(alias);
|
|
4690
|
+
}
|
|
4691
|
+
};
|
|
4692
|
+
function makeShaderAttributeType(primitiveType, components) {
|
|
4693
|
+
return components === 1 ? primitiveType : `vec${components}<${primitiveType}>`;
|
|
4694
|
+
}
|
|
4695
|
+
function resolveAttributeShaderTypeAlias(alias) {
|
|
4696
|
+
return WGSL_ATTRIBUTE_TYPE_ALIAS_MAP[alias] || alias;
|
|
4697
|
+
}
|
|
4698
|
+
function resolveVariableShaderTypeAlias(alias) {
|
|
4699
|
+
return WGSL_VARIABLE_TYPE_ALIAS_MAP[alias] || alias;
|
|
4700
|
+
}
|
|
4701
|
+
var shaderTypeDecoder = new ShaderTypeDecoder();
|
|
3013
4702
|
var PRIMITIVE_TYPE_SIZES = {
|
|
3014
4703
|
f32: 4,
|
|
3015
4704
|
f16: 2,
|
|
@@ -3106,7 +4795,18 @@ ${htmlLog}
|
|
|
3106
4795
|
vec4h: "vec4<f16>"
|
|
3107
4796
|
};
|
|
3108
4797
|
var WGSL_VARIABLE_TYPE_ALIAS_MAP = {
|
|
3109
|
-
|
|
4798
|
+
vec2i: "vec2<i32>",
|
|
4799
|
+
vec3i: "vec3<i32>",
|
|
4800
|
+
vec4i: "vec4<i32>",
|
|
4801
|
+
vec2u: "vec2<u32>",
|
|
4802
|
+
vec3u: "vec3<u32>",
|
|
4803
|
+
vec4u: "vec4<u32>",
|
|
4804
|
+
vec2f: "vec2<f32>",
|
|
4805
|
+
vec3f: "vec3<f32>",
|
|
4806
|
+
vec4f: "vec4<f32>",
|
|
4807
|
+
vec2h: "vec2<f16>",
|
|
4808
|
+
vec3h: "vec3<f16>",
|
|
4809
|
+
vec4h: "vec4<f16>",
|
|
3110
4810
|
mat2x2f: "mat2x2<f32>",
|
|
3111
4811
|
mat2x3f: "mat2x3<f32>",
|
|
3112
4812
|
mat2x4f: "mat2x4<f32>",
|
|
@@ -3173,10 +4873,10 @@ ${htmlLog}
|
|
|
3173
4873
|
if (!shaderDeclaration) {
|
|
3174
4874
|
return null;
|
|
3175
4875
|
}
|
|
3176
|
-
const attributeTypeInfo = getAttributeShaderTypeInfo(shaderDeclaration.type);
|
|
3177
|
-
const defaultVertexFormat = getCompatibleVertexFormat(attributeTypeInfo);
|
|
4876
|
+
const attributeTypeInfo = shaderTypeDecoder.getAttributeShaderTypeInfo(shaderDeclaration.type);
|
|
4877
|
+
const defaultVertexFormat = vertexFormatDecoder.getCompatibleVertexFormat(attributeTypeInfo);
|
|
3178
4878
|
const vertexFormat = bufferMapping?.vertexFormat || defaultVertexFormat;
|
|
3179
|
-
const vertexFormatInfo = getVertexFormatInfo(vertexFormat);
|
|
4879
|
+
const vertexFormatInfo = vertexFormatDecoder.getVertexFormatInfo(vertexFormat);
|
|
3180
4880
|
return {
|
|
3181
4881
|
attributeName: bufferMapping?.attributeName || shaderDeclaration.name,
|
|
3182
4882
|
bufferName: bufferMapping?.bufferName || shaderDeclaration.name,
|
|
@@ -3244,7 +4944,7 @@ ${htmlLog}
|
|
|
3244
4944
|
let byteStride = bufferLayout.byteStride;
|
|
3245
4945
|
if (typeof bufferLayout.byteStride !== "number") {
|
|
3246
4946
|
for (const attributeMapping2 of bufferLayout.attributes || []) {
|
|
3247
|
-
const info = getVertexFormatInfo(attributeMapping2.format);
|
|
4947
|
+
const info = vertexFormatDecoder.getVertexFormatInfo(attributeMapping2.format);
|
|
3248
4948
|
byteStride += info.byteLength;
|
|
3249
4949
|
}
|
|
3250
4950
|
}
|
|
@@ -3332,6 +5032,20 @@ ${htmlLog}
|
|
|
3332
5032
|
count: void 0
|
|
3333
5033
|
});
|
|
3334
5034
|
|
|
5035
|
+
// src/adapter/resources/fence.ts
|
|
5036
|
+
var _Fence = class extends Resource {
|
|
5037
|
+
get [Symbol.toStringTag]() {
|
|
5038
|
+
return "Fence";
|
|
5039
|
+
}
|
|
5040
|
+
constructor(device, props = {}) {
|
|
5041
|
+
super(device, props, _Fence.defaultProps);
|
|
5042
|
+
}
|
|
5043
|
+
};
|
|
5044
|
+
var Fence = _Fence;
|
|
5045
|
+
__publicField(Fence, "defaultProps", {
|
|
5046
|
+
...Resource.defaultProps
|
|
5047
|
+
});
|
|
5048
|
+
|
|
3335
5049
|
// src/adapter/resources/pipeline-layout.ts
|
|
3336
5050
|
var _PipelineLayout = class extends Resource {
|
|
3337
5051
|
get [Symbol.toStringTag]() {
|
|
@@ -3350,6 +5064,200 @@ ${htmlLog}
|
|
|
3350
5064
|
}
|
|
3351
5065
|
});
|
|
3352
5066
|
|
|
5067
|
+
// src/shadertypes/data-types/decode-data-types.ts
|
|
5068
|
+
function alignTo(size, count) {
|
|
5069
|
+
switch (count) {
|
|
5070
|
+
case 1:
|
|
5071
|
+
return size;
|
|
5072
|
+
case 2:
|
|
5073
|
+
return size + size % 2;
|
|
5074
|
+
default:
|
|
5075
|
+
return size + (4 - size % 4) % 4;
|
|
5076
|
+
}
|
|
5077
|
+
}
|
|
5078
|
+
function getTypedArrayConstructor(type) {
|
|
5079
|
+
const [, , , , Constructor] = NORMALIZED_TYPE_MAP2[type];
|
|
5080
|
+
return Constructor;
|
|
5081
|
+
}
|
|
5082
|
+
var NORMALIZED_TYPE_MAP2 = {
|
|
5083
|
+
uint8: ["uint8", "u32", 1, false, Uint8Array],
|
|
5084
|
+
sint8: ["sint8", "i32", 1, false, Int8Array],
|
|
5085
|
+
unorm8: ["uint8", "f32", 1, true, Uint8Array],
|
|
5086
|
+
snorm8: ["sint8", "f32", 1, true, Int8Array],
|
|
5087
|
+
uint16: ["uint16", "u32", 2, false, Uint16Array],
|
|
5088
|
+
sint16: ["sint16", "i32", 2, false, Int16Array],
|
|
5089
|
+
unorm16: ["uint16", "u32", 2, true, Uint16Array],
|
|
5090
|
+
snorm16: ["sint16", "i32", 2, true, Int16Array],
|
|
5091
|
+
float16: ["float16", "f16", 2, false, Uint16Array],
|
|
5092
|
+
float32: ["float32", "f32", 4, false, Float32Array],
|
|
5093
|
+
uint32: ["uint32", "u32", 4, false, Uint32Array],
|
|
5094
|
+
sint32: ["sint32", "i32", 4, false, Int32Array]
|
|
5095
|
+
};
|
|
5096
|
+
|
|
5097
|
+
// src/shadertypes/shader-types/shader-block-layout.ts
|
|
5098
|
+
function makeShaderBlockLayout(uniformTypes, options = {}) {
|
|
5099
|
+
const copiedUniformTypes = { ...uniformTypes };
|
|
5100
|
+
const layout = options.layout ?? "std140";
|
|
5101
|
+
const fields = {};
|
|
5102
|
+
let size = 0;
|
|
5103
|
+
for (const [key, uniformType] of Object.entries(copiedUniformTypes)) {
|
|
5104
|
+
size = addToLayout(fields, key, uniformType, size, layout);
|
|
5105
|
+
}
|
|
5106
|
+
size = alignTo(size, getTypeAlignment(copiedUniformTypes, layout));
|
|
5107
|
+
return {
|
|
5108
|
+
layout,
|
|
5109
|
+
byteLength: size * 4,
|
|
5110
|
+
uniformTypes: copiedUniformTypes,
|
|
5111
|
+
fields
|
|
5112
|
+
};
|
|
5113
|
+
}
|
|
5114
|
+
function getLeafLayoutInfo(type, layout) {
|
|
5115
|
+
const resolvedType = resolveVariableShaderTypeAlias(type);
|
|
5116
|
+
const decodedType = getVariableShaderTypeInfo(resolvedType);
|
|
5117
|
+
const matrixMatch = /^mat(\d)x(\d)<.+>$/.exec(resolvedType);
|
|
5118
|
+
if (matrixMatch) {
|
|
5119
|
+
const columns = Number(matrixMatch[1]);
|
|
5120
|
+
const rows = Number(matrixMatch[2]);
|
|
5121
|
+
const columnInfo = getVectorLayoutInfo(
|
|
5122
|
+
rows,
|
|
5123
|
+
resolvedType,
|
|
5124
|
+
decodedType.type,
|
|
5125
|
+
layout
|
|
5126
|
+
);
|
|
5127
|
+
const columnStride = getMatrixColumnStride(columnInfo.size, columnInfo.alignment, layout);
|
|
5128
|
+
return {
|
|
5129
|
+
alignment: columnInfo.alignment,
|
|
5130
|
+
size: columns * columnStride,
|
|
5131
|
+
components: columns * rows,
|
|
5132
|
+
columns,
|
|
5133
|
+
rows,
|
|
5134
|
+
columnStride,
|
|
5135
|
+
shaderType: resolvedType,
|
|
5136
|
+
type: decodedType.type
|
|
5137
|
+
};
|
|
5138
|
+
}
|
|
5139
|
+
const vectorMatch = /^vec(\d)<.+>$/.exec(resolvedType);
|
|
5140
|
+
if (vectorMatch) {
|
|
5141
|
+
return getVectorLayoutInfo(
|
|
5142
|
+
Number(vectorMatch[1]),
|
|
5143
|
+
resolvedType,
|
|
5144
|
+
decodedType.type,
|
|
5145
|
+
layout
|
|
5146
|
+
);
|
|
5147
|
+
}
|
|
5148
|
+
return {
|
|
5149
|
+
alignment: 1,
|
|
5150
|
+
size: 1,
|
|
5151
|
+
components: 1,
|
|
5152
|
+
columns: 1,
|
|
5153
|
+
rows: 1,
|
|
5154
|
+
columnStride: 1,
|
|
5155
|
+
shaderType: resolvedType,
|
|
5156
|
+
type: decodedType.type
|
|
5157
|
+
};
|
|
5158
|
+
}
|
|
5159
|
+
function isCompositeShaderTypeStruct(value) {
|
|
5160
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
5161
|
+
}
|
|
5162
|
+
function addToLayout(fields, name2, type, offset, layout) {
|
|
5163
|
+
if (typeof type === "string") {
|
|
5164
|
+
const info = getLeafLayoutInfo(type, layout);
|
|
5165
|
+
const alignedOffset = alignTo(offset, info.alignment);
|
|
5166
|
+
fields[name2] = {
|
|
5167
|
+
offset: alignedOffset,
|
|
5168
|
+
...info
|
|
5169
|
+
};
|
|
5170
|
+
return alignedOffset + info.size;
|
|
5171
|
+
}
|
|
5172
|
+
if (Array.isArray(type)) {
|
|
5173
|
+
if (Array.isArray(type[0])) {
|
|
5174
|
+
throw new Error(`Nested arrays are not supported for ${name2}`);
|
|
5175
|
+
}
|
|
5176
|
+
const elementType = type[0];
|
|
5177
|
+
const length = type[1];
|
|
5178
|
+
const stride = getArrayStride(elementType, layout);
|
|
5179
|
+
const arrayOffset = alignTo(offset, getTypeAlignment(type, layout));
|
|
5180
|
+
for (let i = 0; i < length; i++) {
|
|
5181
|
+
addToLayout(fields, `${name2}[${i}]`, elementType, arrayOffset + i * stride, layout);
|
|
5182
|
+
}
|
|
5183
|
+
return arrayOffset + stride * length;
|
|
5184
|
+
}
|
|
5185
|
+
if (isCompositeShaderTypeStruct(type)) {
|
|
5186
|
+
const structAlignment = getTypeAlignment(type, layout);
|
|
5187
|
+
let structOffset = alignTo(offset, structAlignment);
|
|
5188
|
+
for (const [memberName, memberType] of Object.entries(type)) {
|
|
5189
|
+
structOffset = addToLayout(fields, `${name2}.${memberName}`, memberType, structOffset, layout);
|
|
5190
|
+
}
|
|
5191
|
+
return alignTo(structOffset, structAlignment);
|
|
5192
|
+
}
|
|
5193
|
+
throw new Error(`Unsupported CompositeShaderType for ${name2}`);
|
|
5194
|
+
}
|
|
5195
|
+
function getTypeSize(type, layout) {
|
|
5196
|
+
if (typeof type === "string") {
|
|
5197
|
+
return getLeafLayoutInfo(type, layout).size;
|
|
5198
|
+
}
|
|
5199
|
+
if (Array.isArray(type)) {
|
|
5200
|
+
const elementType = type[0];
|
|
5201
|
+
const length = type[1];
|
|
5202
|
+
if (Array.isArray(elementType)) {
|
|
5203
|
+
throw new Error("Nested arrays are not supported");
|
|
5204
|
+
}
|
|
5205
|
+
return getArrayStride(elementType, layout) * length;
|
|
5206
|
+
}
|
|
5207
|
+
let size = 0;
|
|
5208
|
+
for (const memberType of Object.values(type)) {
|
|
5209
|
+
const compositeMemberType = memberType;
|
|
5210
|
+
size = alignTo(size, getTypeAlignment(compositeMemberType, layout));
|
|
5211
|
+
size += getTypeSize(compositeMemberType, layout);
|
|
5212
|
+
}
|
|
5213
|
+
return alignTo(size, getTypeAlignment(type, layout));
|
|
5214
|
+
}
|
|
5215
|
+
function getTypeAlignment(type, layout) {
|
|
5216
|
+
if (typeof type === "string") {
|
|
5217
|
+
return getLeafLayoutInfo(type, layout).alignment;
|
|
5218
|
+
}
|
|
5219
|
+
if (Array.isArray(type)) {
|
|
5220
|
+
const elementType = type[0];
|
|
5221
|
+
const elementAlignment = getTypeAlignment(elementType, layout);
|
|
5222
|
+
return uses16ByteArrayAlignment(layout) ? Math.max(elementAlignment, 4) : elementAlignment;
|
|
5223
|
+
}
|
|
5224
|
+
let maxAlignment = 1;
|
|
5225
|
+
for (const memberType of Object.values(type)) {
|
|
5226
|
+
const memberAlignment = getTypeAlignment(memberType, layout);
|
|
5227
|
+
maxAlignment = Math.max(maxAlignment, memberAlignment);
|
|
5228
|
+
}
|
|
5229
|
+
return uses16ByteStructAlignment(layout) ? Math.max(maxAlignment, 4) : maxAlignment;
|
|
5230
|
+
}
|
|
5231
|
+
function getVectorLayoutInfo(components, shaderType, type, layout) {
|
|
5232
|
+
return {
|
|
5233
|
+
alignment: components === 2 ? 2 : 4,
|
|
5234
|
+
size: components === 3 ? 3 : components,
|
|
5235
|
+
components,
|
|
5236
|
+
columns: 1,
|
|
5237
|
+
rows: components,
|
|
5238
|
+
columnStride: components === 3 ? 3 : components,
|
|
5239
|
+
shaderType,
|
|
5240
|
+
type
|
|
5241
|
+
};
|
|
5242
|
+
}
|
|
5243
|
+
function getArrayStride(elementType, layout) {
|
|
5244
|
+
const elementSize = getTypeSize(elementType, layout);
|
|
5245
|
+
const elementAlignment = getTypeAlignment(elementType, layout);
|
|
5246
|
+
return getArrayLikeStride(elementSize, elementAlignment, layout);
|
|
5247
|
+
}
|
|
5248
|
+
function getArrayLikeStride(size, alignment, layout) {
|
|
5249
|
+
return alignTo(size, uses16ByteArrayAlignment(layout) ? 4 : alignment);
|
|
5250
|
+
}
|
|
5251
|
+
function getMatrixColumnStride(size, alignment, layout) {
|
|
5252
|
+
return layout === "std140" ? 4 : alignTo(size, alignment);
|
|
5253
|
+
}
|
|
5254
|
+
function uses16ByteArrayAlignment(layout) {
|
|
5255
|
+
return layout === "std140" || layout === "wgsl-uniform";
|
|
5256
|
+
}
|
|
5257
|
+
function uses16ByteStructAlignment(layout) {
|
|
5258
|
+
return layout === "std140" || layout === "wgsl-uniform";
|
|
5259
|
+
}
|
|
5260
|
+
|
|
3353
5261
|
// src/utils/array-utils-flat.ts
|
|
3354
5262
|
var arrayBuffer;
|
|
3355
5263
|
function getScratchArrayBuffer(byteLength) {
|
|
@@ -3374,92 +5282,201 @@ ${htmlLog}
|
|
|
3374
5282
|
return isTypedArray(value);
|
|
3375
5283
|
}
|
|
3376
5284
|
|
|
3377
|
-
// src/portable/
|
|
3378
|
-
var
|
|
3379
|
-
|
|
3380
|
-
layout
|
|
3381
|
-
/**
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
constructor(
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
5285
|
+
// src/portable/shader-block-writer.ts
|
|
5286
|
+
var ShaderBlockWriter = class {
|
|
5287
|
+
/** Layout metadata used to flatten and serialize values. */
|
|
5288
|
+
layout;
|
|
5289
|
+
/**
|
|
5290
|
+
* Creates a writer for a precomputed shader-block layout.
|
|
5291
|
+
*/
|
|
5292
|
+
constructor(layout) {
|
|
5293
|
+
this.layout = layout;
|
|
5294
|
+
}
|
|
5295
|
+
/**
|
|
5296
|
+
* Returns `true` if the flattened layout contains the given field.
|
|
5297
|
+
*/
|
|
5298
|
+
has(name2) {
|
|
5299
|
+
return Boolean(this.layout.fields[name2]);
|
|
5300
|
+
}
|
|
5301
|
+
/**
|
|
5302
|
+
* Returns offset and size metadata for a flattened field.
|
|
5303
|
+
*/
|
|
5304
|
+
get(name2) {
|
|
5305
|
+
const entry = this.layout.fields[name2];
|
|
5306
|
+
return entry ? { offset: entry.offset, size: entry.size } : void 0;
|
|
5307
|
+
}
|
|
5308
|
+
/**
|
|
5309
|
+
* Flattens nested composite values into leaf-path values understood by {@link UniformBlock}.
|
|
5310
|
+
*
|
|
5311
|
+
* Top-level values may be supplied either in nested object form matching the
|
|
5312
|
+
* declared composite shader types or as already-flattened leaf-path values.
|
|
5313
|
+
*/
|
|
5314
|
+
getFlatUniformValues(uniformValues) {
|
|
5315
|
+
const flattenedUniformValues = {};
|
|
5316
|
+
for (const [name2, value] of Object.entries(uniformValues)) {
|
|
5317
|
+
const uniformType = this.layout.uniformTypes[name2];
|
|
5318
|
+
if (uniformType) {
|
|
5319
|
+
this._flattenCompositeValue(flattenedUniformValues, name2, uniformType, value);
|
|
5320
|
+
} else if (this.layout.fields[name2]) {
|
|
5321
|
+
flattenedUniformValues[name2] = value;
|
|
5322
|
+
}
|
|
5323
|
+
}
|
|
5324
|
+
return flattenedUniformValues;
|
|
5325
|
+
}
|
|
5326
|
+
/**
|
|
5327
|
+
* Serializes the supplied values into buffer-backed binary data.
|
|
5328
|
+
*
|
|
5329
|
+
* The returned view length matches {@link ShaderBlockLayout.byteLength}, which
|
|
5330
|
+
* is the exact packed size of the block.
|
|
5331
|
+
*/
|
|
3400
5332
|
getData(uniformValues) {
|
|
3401
|
-
const
|
|
5333
|
+
const buffer = getScratchArrayBuffer(this.layout.byteLength);
|
|
5334
|
+
new Uint8Array(buffer, 0, this.layout.byteLength).fill(0);
|
|
3402
5335
|
const typedArrays = {
|
|
3403
|
-
i32: new Int32Array(
|
|
3404
|
-
u32: new Uint32Array(
|
|
3405
|
-
f32: new Float32Array(
|
|
3406
|
-
|
|
3407
|
-
f16: new Uint16Array(arrayBuffer2)
|
|
5336
|
+
i32: new Int32Array(buffer),
|
|
5337
|
+
u32: new Uint32Array(buffer),
|
|
5338
|
+
f32: new Float32Array(buffer),
|
|
5339
|
+
f16: new Uint16Array(buffer)
|
|
3408
5340
|
};
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
5341
|
+
const flattenedUniformValues = this.getFlatUniformValues(uniformValues);
|
|
5342
|
+
for (const [name2, value] of Object.entries(flattenedUniformValues)) {
|
|
5343
|
+
this._writeLeafValue(typedArrays, name2, value);
|
|
5344
|
+
}
|
|
5345
|
+
return new Uint8Array(buffer, 0, this.layout.byteLength);
|
|
5346
|
+
}
|
|
5347
|
+
/**
|
|
5348
|
+
* Recursively flattens nested values using the declared composite shader type.
|
|
5349
|
+
*/
|
|
5350
|
+
_flattenCompositeValue(flattenedUniformValues, baseName, uniformType, value) {
|
|
5351
|
+
if (value === void 0) {
|
|
5352
|
+
return;
|
|
5353
|
+
}
|
|
5354
|
+
if (typeof uniformType === "string" || this.layout.fields[baseName]) {
|
|
5355
|
+
flattenedUniformValues[baseName] = value;
|
|
5356
|
+
return;
|
|
5357
|
+
}
|
|
5358
|
+
if (Array.isArray(uniformType)) {
|
|
5359
|
+
const elementType = uniformType[0];
|
|
5360
|
+
const length = uniformType[1];
|
|
5361
|
+
if (Array.isArray(elementType)) {
|
|
5362
|
+
throw new Error(`Nested arrays are not supported for ${baseName}`);
|
|
3414
5363
|
}
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
5364
|
+
if (typeof elementType === "string" && isNumberArray(value)) {
|
|
5365
|
+
this._flattenPackedArray(flattenedUniformValues, baseName, elementType, length, value);
|
|
5366
|
+
return;
|
|
5367
|
+
}
|
|
5368
|
+
if (!Array.isArray(value)) {
|
|
5369
|
+
log.warn(`Unsupported uniform array value for ${baseName}:`, value)();
|
|
5370
|
+
return;
|
|
5371
|
+
}
|
|
5372
|
+
for (let index = 0; index < Math.min(value.length, length); index++) {
|
|
5373
|
+
const elementValue = value[index];
|
|
5374
|
+
if (elementValue === void 0) {
|
|
3422
5375
|
continue;
|
|
3423
5376
|
}
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
5377
|
+
this._flattenCompositeValue(
|
|
5378
|
+
flattenedUniformValues,
|
|
5379
|
+
`${baseName}[${index}]`,
|
|
5380
|
+
elementType,
|
|
5381
|
+
elementValue
|
|
5382
|
+
);
|
|
5383
|
+
}
|
|
5384
|
+
return;
|
|
5385
|
+
}
|
|
5386
|
+
if (isCompositeShaderTypeStruct(uniformType) && isCompositeUniformObject(value)) {
|
|
5387
|
+
for (const [key, subValue] of Object.entries(value)) {
|
|
5388
|
+
if (subValue === void 0) {
|
|
3430
5389
|
continue;
|
|
3431
5390
|
}
|
|
3432
|
-
|
|
5391
|
+
const nestedName = `${baseName}.${key}`;
|
|
5392
|
+
this._flattenCompositeValue(flattenedUniformValues, nestedName, uniformType[key], subValue);
|
|
3433
5393
|
}
|
|
5394
|
+
return;
|
|
3434
5395
|
}
|
|
3435
|
-
|
|
5396
|
+
log.warn(`Unsupported uniform value for ${baseName}:`, value)();
|
|
3436
5397
|
}
|
|
3437
|
-
/**
|
|
3438
|
-
|
|
3439
|
-
|
|
5398
|
+
/**
|
|
5399
|
+
* Expands tightly packed numeric arrays into per-element leaf fields.
|
|
5400
|
+
*/
|
|
5401
|
+
_flattenPackedArray(flattenedUniformValues, baseName, elementType, length, value) {
|
|
5402
|
+
const numericValue = value;
|
|
5403
|
+
const elementLayout = getLeafLayoutInfo(elementType, this.layout.layout);
|
|
5404
|
+
const packedElementLength = elementLayout.components;
|
|
5405
|
+
for (let index = 0; index < length; index++) {
|
|
5406
|
+
const start = index * packedElementLength;
|
|
5407
|
+
if (start >= numericValue.length) {
|
|
5408
|
+
break;
|
|
5409
|
+
}
|
|
5410
|
+
if (packedElementLength === 1) {
|
|
5411
|
+
flattenedUniformValues[`${baseName}[${index}]`] = Number(numericValue[start]);
|
|
5412
|
+
} else {
|
|
5413
|
+
flattenedUniformValues[`${baseName}[${index}]`] = sliceNumericArray(
|
|
5414
|
+
value,
|
|
5415
|
+
start,
|
|
5416
|
+
start + packedElementLength
|
|
5417
|
+
);
|
|
5418
|
+
}
|
|
5419
|
+
}
|
|
3440
5420
|
}
|
|
3441
|
-
/**
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
5421
|
+
/**
|
|
5422
|
+
* Writes one flattened leaf value into its typed-array view.
|
|
5423
|
+
*/
|
|
5424
|
+
_writeLeafValue(typedArrays, name2, value) {
|
|
5425
|
+
const entry = this.layout.fields[name2];
|
|
5426
|
+
if (!entry) {
|
|
5427
|
+
log.warn(`Uniform ${name2} not found in layout`)();
|
|
5428
|
+
return;
|
|
5429
|
+
}
|
|
5430
|
+
const { type, components, columns, rows, offset, columnStride } = entry;
|
|
5431
|
+
const array = typedArrays[type];
|
|
5432
|
+
if (components === 1) {
|
|
5433
|
+
array[offset] = Number(value);
|
|
5434
|
+
return;
|
|
5435
|
+
}
|
|
5436
|
+
const sourceValue = value;
|
|
5437
|
+
if (columns === 1) {
|
|
5438
|
+
for (let componentIndex = 0; componentIndex < components; componentIndex++) {
|
|
5439
|
+
array[offset + componentIndex] = Number(sourceValue[componentIndex] ?? 0);
|
|
5440
|
+
}
|
|
5441
|
+
return;
|
|
5442
|
+
}
|
|
5443
|
+
let sourceIndex = 0;
|
|
5444
|
+
for (let columnIndex = 0; columnIndex < columns; columnIndex++) {
|
|
5445
|
+
const columnOffset = offset + columnIndex * columnStride;
|
|
5446
|
+
for (let rowIndex = 0; rowIndex < rows; rowIndex++) {
|
|
5447
|
+
array[columnOffset + rowIndex] = Number(sourceValue[sourceIndex++] ?? 0);
|
|
5448
|
+
}
|
|
5449
|
+
}
|
|
3445
5450
|
}
|
|
3446
5451
|
};
|
|
5452
|
+
function isCompositeUniformObject(value) {
|
|
5453
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value) && !ArrayBuffer.isView(value);
|
|
5454
|
+
}
|
|
5455
|
+
function sliceNumericArray(value, start, end) {
|
|
5456
|
+
return Array.prototype.slice.call(value, start, end);
|
|
5457
|
+
}
|
|
3447
5458
|
|
|
3448
5459
|
// src/utils/array-equal.ts
|
|
5460
|
+
var MAX_ELEMENTWISE_ARRAY_COMPARE_LENGTH = 128;
|
|
3449
5461
|
function arrayEqual(a, b, limit = 16) {
|
|
3450
|
-
if (a
|
|
3451
|
-
return
|
|
5462
|
+
if (a === b) {
|
|
5463
|
+
return true;
|
|
3452
5464
|
}
|
|
3453
5465
|
const arrayA = a;
|
|
3454
5466
|
const arrayB = b;
|
|
3455
|
-
if (!isNumberArray(arrayA)) {
|
|
5467
|
+
if (!isNumberArray(arrayA) || !isNumberArray(arrayB)) {
|
|
3456
5468
|
return false;
|
|
3457
5469
|
}
|
|
3458
|
-
if (
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
5470
|
+
if (arrayA.length !== arrayB.length) {
|
|
5471
|
+
return false;
|
|
5472
|
+
}
|
|
5473
|
+
const maxCompareLength = Math.min(limit, MAX_ELEMENTWISE_ARRAY_COMPARE_LENGTH);
|
|
5474
|
+
if (arrayA.length > maxCompareLength) {
|
|
5475
|
+
return false;
|
|
5476
|
+
}
|
|
5477
|
+
for (let i = 0; i < arrayA.length; ++i) {
|
|
5478
|
+
if (arrayB[i] !== arrayA[i]) {
|
|
5479
|
+
return false;
|
|
3463
5480
|
}
|
|
3464
5481
|
}
|
|
3465
5482
|
return true;
|
|
@@ -3524,27 +5541,33 @@ ${htmlLog}
|
|
|
3524
5541
|
};
|
|
3525
5542
|
|
|
3526
5543
|
// src/portable/uniform-store.ts
|
|
5544
|
+
var minUniformBufferSize = 1024;
|
|
3527
5545
|
var UniformStore = class {
|
|
5546
|
+
/** Device used to infer layout and allocate buffers. */
|
|
5547
|
+
device;
|
|
3528
5548
|
/** Stores the uniform values for each uniform block */
|
|
3529
5549
|
uniformBlocks = /* @__PURE__ */ new Map();
|
|
3530
|
-
/**
|
|
3531
|
-
|
|
5550
|
+
/** Flattened layout metadata for each block. */
|
|
5551
|
+
shaderBlockLayouts = /* @__PURE__ */ new Map();
|
|
5552
|
+
/** Serializers for block-backed uniform data. */
|
|
5553
|
+
shaderBlockWriters = /* @__PURE__ */ new Map();
|
|
3532
5554
|
/** Actual buffer for the blocks */
|
|
3533
5555
|
uniformBuffers = /* @__PURE__ */ new Map();
|
|
3534
5556
|
/**
|
|
3535
|
-
*
|
|
3536
|
-
* @param blocks
|
|
5557
|
+
* Creates a new {@link UniformStore} for the supplied device and block definitions.
|
|
3537
5558
|
*/
|
|
3538
|
-
constructor(blocks) {
|
|
5559
|
+
constructor(device, blocks) {
|
|
5560
|
+
this.device = device;
|
|
3539
5561
|
for (const [bufferName, block] of Object.entries(blocks)) {
|
|
3540
5562
|
const uniformBufferName = bufferName;
|
|
3541
|
-
const
|
|
3542
|
-
block.
|
|
3543
|
-
|
|
3544
|
-
);
|
|
3545
|
-
this.
|
|
5563
|
+
const shaderBlockLayout = makeShaderBlockLayout(block.uniformTypes ?? {}, {
|
|
5564
|
+
layout: block.layout ?? getDefaultUniformBufferLayout(device)
|
|
5565
|
+
});
|
|
5566
|
+
const shaderBlockWriter = new ShaderBlockWriter(shaderBlockLayout);
|
|
5567
|
+
this.shaderBlockLayouts.set(uniformBufferName, shaderBlockLayout);
|
|
5568
|
+
this.shaderBlockWriters.set(uniformBufferName, shaderBlockWriter);
|
|
3546
5569
|
const uniformBlock = new UniformBlock({ name: bufferName });
|
|
3547
|
-
uniformBlock.setUniforms(block.defaultUniforms || {});
|
|
5570
|
+
uniformBlock.setUniforms(shaderBlockWriter.getFlatUniformValues(block.defaultUniforms || {}));
|
|
3548
5571
|
this.uniformBlocks.set(uniformBufferName, uniformBlock);
|
|
3549
5572
|
}
|
|
3550
5573
|
}
|
|
@@ -3556,33 +5579,51 @@ ${htmlLog}
|
|
|
3556
5579
|
}
|
|
3557
5580
|
/**
|
|
3558
5581
|
* Set uniforms
|
|
3559
|
-
*
|
|
5582
|
+
*
|
|
5583
|
+
* Makes all group properties partial and eagerly propagates changes to any
|
|
5584
|
+
* managed GPU buffers.
|
|
3560
5585
|
*/
|
|
3561
5586
|
setUniforms(uniforms) {
|
|
3562
5587
|
for (const [blockName, uniformValues] of Object.entries(uniforms)) {
|
|
3563
|
-
|
|
5588
|
+
const uniformBufferName = blockName;
|
|
5589
|
+
const shaderBlockWriter = this.shaderBlockWriters.get(uniformBufferName);
|
|
5590
|
+
const flattenedUniforms = shaderBlockWriter?.getFlatUniformValues(
|
|
5591
|
+
uniformValues || {}
|
|
5592
|
+
);
|
|
5593
|
+
this.uniformBlocks.get(uniformBufferName)?.setUniforms(flattenedUniforms || {});
|
|
3564
5594
|
}
|
|
3565
5595
|
this.updateUniformBuffers();
|
|
3566
5596
|
}
|
|
3567
|
-
/**
|
|
5597
|
+
/**
|
|
5598
|
+
* Returns the allocation size for the named uniform buffer.
|
|
5599
|
+
*
|
|
5600
|
+
* This may exceed the packed layout size because minimum buffer-size policy is
|
|
5601
|
+
* applied at the store layer.
|
|
5602
|
+
*/
|
|
3568
5603
|
getUniformBufferByteLength(uniformBufferName) {
|
|
3569
|
-
|
|
5604
|
+
const packedByteLength = this.shaderBlockLayouts.get(uniformBufferName)?.byteLength || 0;
|
|
5605
|
+
return Math.max(packedByteLength, minUniformBufferSize);
|
|
3570
5606
|
}
|
|
3571
|
-
/**
|
|
5607
|
+
/**
|
|
5608
|
+
* Returns packed binary data that can be uploaded to the named uniform buffer.
|
|
5609
|
+
*
|
|
5610
|
+
* The returned view length matches the packed block size and is not padded to
|
|
5611
|
+
* the store's minimum allocation size.
|
|
5612
|
+
*/
|
|
3572
5613
|
getUniformBufferData(uniformBufferName) {
|
|
3573
5614
|
const uniformValues = this.uniformBlocks.get(uniformBufferName)?.getAllUniforms() || {};
|
|
3574
|
-
|
|
5615
|
+
const shaderBlockWriter = this.shaderBlockWriters.get(uniformBufferName);
|
|
5616
|
+
return shaderBlockWriter?.getData(uniformValues) || new Uint8Array(0);
|
|
3575
5617
|
}
|
|
3576
5618
|
/**
|
|
3577
|
-
* Creates an unmanaged uniform buffer
|
|
3578
|
-
* The new buffer is initialized with current / supplied values
|
|
5619
|
+
* Creates an unmanaged uniform buffer initialized with the current or supplied values.
|
|
3579
5620
|
*/
|
|
3580
|
-
createUniformBuffer(
|
|
5621
|
+
createUniformBuffer(uniformBufferName, uniforms) {
|
|
3581
5622
|
if (uniforms) {
|
|
3582
5623
|
this.setUniforms(uniforms);
|
|
3583
5624
|
}
|
|
3584
5625
|
const byteLength = this.getUniformBufferByteLength(uniformBufferName);
|
|
3585
|
-
const uniformBuffer = device.createBuffer({
|
|
5626
|
+
const uniformBuffer = this.device.createBuffer({
|
|
3586
5627
|
usage: Buffer2.UNIFORM | Buffer2.COPY_DST,
|
|
3587
5628
|
byteLength
|
|
3588
5629
|
});
|
|
@@ -3590,11 +5631,11 @@ ${htmlLog}
|
|
|
3590
5631
|
uniformBuffer.write(uniformBufferData);
|
|
3591
5632
|
return uniformBuffer;
|
|
3592
5633
|
}
|
|
3593
|
-
/**
|
|
3594
|
-
getManagedUniformBuffer(
|
|
5634
|
+
/** Returns the managed uniform buffer for the named block. */
|
|
5635
|
+
getManagedUniformBuffer(uniformBufferName) {
|
|
3595
5636
|
if (!this.uniformBuffers.get(uniformBufferName)) {
|
|
3596
5637
|
const byteLength = this.getUniformBufferByteLength(uniformBufferName);
|
|
3597
|
-
const uniformBuffer = device.createBuffer({
|
|
5638
|
+
const uniformBuffer = this.device.createBuffer({
|
|
3598
5639
|
usage: Buffer2.UNIFORM | Buffer2.COPY_DST,
|
|
3599
5640
|
byteLength
|
|
3600
5641
|
});
|
|
@@ -3602,7 +5643,11 @@ ${htmlLog}
|
|
|
3602
5643
|
}
|
|
3603
5644
|
return this.uniformBuffers.get(uniformBufferName);
|
|
3604
5645
|
}
|
|
3605
|
-
/**
|
|
5646
|
+
/**
|
|
5647
|
+
* Updates every managed uniform buffer whose source uniforms have changed.
|
|
5648
|
+
*
|
|
5649
|
+
* @returns The first redraw reason encountered, or `false` if nothing changed.
|
|
5650
|
+
*/
|
|
3606
5651
|
updateUniformBuffers() {
|
|
3607
5652
|
let reason = false;
|
|
3608
5653
|
for (const uniformBufferName of this.uniformBlocks.keys()) {
|
|
@@ -3614,7 +5659,11 @@ ${htmlLog}
|
|
|
3614
5659
|
}
|
|
3615
5660
|
return reason;
|
|
3616
5661
|
}
|
|
3617
|
-
/**
|
|
5662
|
+
/**
|
|
5663
|
+
* Updates one managed uniform buffer if its corresponding block is dirty.
|
|
5664
|
+
*
|
|
5665
|
+
* @returns The redraw reason for the update, or `false` if no write occurred.
|
|
5666
|
+
*/
|
|
3618
5667
|
updateUniformBuffer(uniformBufferName) {
|
|
3619
5668
|
const uniformBlock = this.uniformBlocks.get(uniformBufferName);
|
|
3620
5669
|
let uniformBuffer = this.uniformBuffers.get(uniformBufferName);
|
|
@@ -3635,8 +5684,49 @@ ${htmlLog}
|
|
|
3635
5684
|
return reason;
|
|
3636
5685
|
}
|
|
3637
5686
|
};
|
|
5687
|
+
function getDefaultUniformBufferLayout(device) {
|
|
5688
|
+
return device.type === "webgpu" ? "wgsl-uniform" : "std140";
|
|
5689
|
+
}
|
|
5690
|
+
|
|
5691
|
+
// src/shadertypes/texture-types/texture-layout.ts
|
|
5692
|
+
function getTextureImageView(arrayBuffer2, memoryLayout, format, image = 0) {
|
|
5693
|
+
const formatInfo = textureFormatDecoder.getInfo(format);
|
|
5694
|
+
const bytesPerComponent = formatInfo.bytesPerPixel / formatInfo.components;
|
|
5695
|
+
const { bytesPerImage } = memoryLayout;
|
|
5696
|
+
const offset = bytesPerImage * image;
|
|
5697
|
+
const totalPixels = memoryLayout.bytesPerImage / bytesPerComponent;
|
|
5698
|
+
switch (format) {
|
|
5699
|
+
case "rgba8unorm":
|
|
5700
|
+
case "bgra8unorm":
|
|
5701
|
+
case "rgba8uint":
|
|
5702
|
+
return new Uint8Array(arrayBuffer2, offset, totalPixels);
|
|
5703
|
+
case "r8unorm":
|
|
5704
|
+
return new Uint8Array(arrayBuffer2, offset, totalPixels);
|
|
5705
|
+
case "r16uint":
|
|
5706
|
+
case "rgba16uint":
|
|
5707
|
+
return new Uint16Array(arrayBuffer2, offset, totalPixels);
|
|
5708
|
+
case "r32uint":
|
|
5709
|
+
case "rgba32uint":
|
|
5710
|
+
return new Uint32Array(arrayBuffer2, offset, totalPixels);
|
|
5711
|
+
case "r32float":
|
|
5712
|
+
return new Float32Array(arrayBuffer2, offset, totalPixels);
|
|
5713
|
+
case "rgba16float":
|
|
5714
|
+
return new Uint16Array(arrayBuffer2, offset, totalPixels);
|
|
5715
|
+
case "rgba32float":
|
|
5716
|
+
return new Float32Array(arrayBuffer2, offset, totalPixels);
|
|
5717
|
+
default:
|
|
5718
|
+
throw new Error(`Unsupported format: ${format}`);
|
|
5719
|
+
}
|
|
5720
|
+
}
|
|
5721
|
+
function setTextureImageData(arrayBuffer2, memoryLayout, format, data, image = 0) {
|
|
5722
|
+
const offset = 0;
|
|
5723
|
+
const totalPixels = memoryLayout.bytesPerImage / memoryLayout.bytesPerPixel;
|
|
5724
|
+
const subArray = data.subarray(0, totalPixels);
|
|
5725
|
+
const typedArray = getTextureImageView(arrayBuffer2, memoryLayout, format, image);
|
|
5726
|
+
typedArray.set(subArray, offset);
|
|
5727
|
+
}
|
|
3638
5728
|
|
|
3639
|
-
// src/shadertypes/
|
|
5729
|
+
// src/shadertypes/texture-types/pixel-utils.ts
|
|
3640
5730
|
function readPixel(pixelData, x, y, bitsPerChannel) {
|
|
3641
5731
|
if (x < 0 || x >= pixelData.width || y < 0 || y >= pixelData.height) {
|
|
3642
5732
|
throw new Error("Coordinates out of bounds.");
|
|
@@ -3646,7 +5736,7 @@ ${htmlLog}
|
|
|
3646
5736
|
let bitOffsetWithinPixel = 0;
|
|
3647
5737
|
const channels = [];
|
|
3648
5738
|
for (let i = 0; i < 4; i++) {
|
|
3649
|
-
const bits = bitsPerChannel[i];
|
|
5739
|
+
const bits = bitsPerChannel[i] ?? 0;
|
|
3650
5740
|
if (bits <= 0) {
|
|
3651
5741
|
channels.push(0);
|
|
3652
5742
|
} else {
|
|
@@ -3655,14 +5745,14 @@ ${htmlLog}
|
|
|
3655
5745
|
bitOffsetWithinPixel += bits;
|
|
3656
5746
|
}
|
|
3657
5747
|
}
|
|
3658
|
-
return [channels[0], channels[1], channels[2], channels[3]];
|
|
5748
|
+
return [channels[0] ?? 0, channels[1] ?? 0, channels[2] ?? 0, channels[3] ?? 0];
|
|
3659
5749
|
}
|
|
3660
5750
|
function writePixel(dataView, bitOffset, bitsPerChannel, pixel) {
|
|
3661
5751
|
let currentBitOffset = bitOffset;
|
|
3662
5752
|
for (let channel = 0; channel < 4; channel++) {
|
|
3663
|
-
const bits = bitsPerChannel[channel];
|
|
5753
|
+
const bits = bitsPerChannel[channel] ?? 0;
|
|
3664
5754
|
const maxValue = (1 << bits) - 1;
|
|
3665
|
-
const channelValue = pixel[channel] & maxValue;
|
|
5755
|
+
const channelValue = (pixel[channel] ?? 0) & maxValue;
|
|
3666
5756
|
writeBitsToDataView(dataView, currentBitOffset, bits, channelValue);
|
|
3667
5757
|
currentBitOffset += bits;
|
|
3668
5758
|
}
|