@luma.gl/core 9.2.6 → 9.3.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (280) hide show
  1. package/dist/adapter/canvas-context.d.ts +6 -162
  2. package/dist/adapter/canvas-context.d.ts.map +1 -1
  3. package/dist/adapter/canvas-context.js +5 -419
  4. package/dist/adapter/canvas-context.js.map +1 -1
  5. package/dist/adapter/canvas-observer.d.ts +32 -0
  6. package/dist/adapter/canvas-observer.d.ts.map +1 -0
  7. package/dist/adapter/canvas-observer.js +90 -0
  8. package/dist/adapter/canvas-observer.js.map +1 -0
  9. package/dist/adapter/canvas-surface.d.ts +150 -0
  10. package/dist/adapter/canvas-surface.d.ts.map +1 -0
  11. package/dist/adapter/canvas-surface.js +392 -0
  12. package/dist/adapter/canvas-surface.js.map +1 -0
  13. package/dist/adapter/device.d.ts +81 -16
  14. package/dist/adapter/device.d.ts.map +1 -1
  15. package/dist/adapter/device.js +191 -10
  16. package/dist/adapter/device.js.map +1 -1
  17. package/dist/adapter/luma.js +1 -1
  18. package/dist/adapter/luma.js.map +1 -1
  19. package/dist/adapter/presentation-context.d.ts +11 -0
  20. package/dist/adapter/presentation-context.d.ts.map +1 -0
  21. package/dist/adapter/presentation-context.js +12 -0
  22. package/dist/adapter/presentation-context.js.map +1 -0
  23. package/dist/adapter/resources/buffer.d.ts +1 -1
  24. package/dist/adapter/resources/buffer.d.ts.map +1 -1
  25. package/dist/adapter/resources/buffer.js +14 -6
  26. package/dist/adapter/resources/buffer.js.map +1 -1
  27. package/dist/adapter/resources/command-buffer.d.ts +3 -1
  28. package/dist/adapter/resources/command-buffer.d.ts.map +1 -1
  29. package/dist/adapter/resources/command-buffer.js +3 -1
  30. package/dist/adapter/resources/command-buffer.js.map +1 -1
  31. package/dist/adapter/resources/command-encoder.d.ts +30 -7
  32. package/dist/adapter/resources/command-encoder.d.ts.map +1 -1
  33. package/dist/adapter/resources/command-encoder.js +68 -2
  34. package/dist/adapter/resources/command-encoder.js.map +1 -1
  35. package/dist/adapter/resources/compute-pipeline.d.ts +2 -2
  36. package/dist/adapter/resources/compute-pipeline.d.ts.map +1 -1
  37. package/dist/adapter/resources/fence.d.ts +16 -0
  38. package/dist/adapter/resources/fence.d.ts.map +1 -0
  39. package/dist/adapter/resources/fence.js +17 -0
  40. package/dist/adapter/resources/fence.js.map +1 -0
  41. package/dist/adapter/resources/framebuffer.d.ts +1 -1
  42. package/dist/adapter/resources/framebuffer.d.ts.map +1 -1
  43. package/dist/adapter/resources/framebuffer.js +15 -12
  44. package/dist/adapter/resources/framebuffer.js.map +1 -1
  45. package/dist/adapter/resources/query-set.d.ts +17 -1
  46. package/dist/adapter/resources/query-set.d.ts.map +1 -1
  47. package/dist/adapter/resources/query-set.js.map +1 -1
  48. package/dist/adapter/resources/render-pipeline.d.ts +28 -10
  49. package/dist/adapter/resources/render-pipeline.d.ts.map +1 -1
  50. package/dist/adapter/resources/render-pipeline.js +21 -2
  51. package/dist/adapter/resources/render-pipeline.js.map +1 -1
  52. package/dist/adapter/resources/resource.d.ts +13 -0
  53. package/dist/adapter/resources/resource.d.ts.map +1 -1
  54. package/dist/adapter/resources/resource.js +243 -14
  55. package/dist/adapter/resources/resource.js.map +1 -1
  56. package/dist/adapter/resources/shader.js +27 -25
  57. package/dist/adapter/resources/shader.js.map +1 -1
  58. package/dist/adapter/resources/shared-render-pipeline.d.ts +22 -0
  59. package/dist/adapter/resources/shared-render-pipeline.d.ts.map +1 -0
  60. package/dist/adapter/resources/shared-render-pipeline.js +25 -0
  61. package/dist/adapter/resources/shared-render-pipeline.js.map +1 -0
  62. package/dist/adapter/resources/texture-view.d.ts +1 -1
  63. package/dist/adapter/resources/texture-view.d.ts.map +1 -1
  64. package/dist/adapter/resources/texture.d.ts +168 -28
  65. package/dist/adapter/resources/texture.d.ts.map +1 -1
  66. package/dist/adapter/resources/texture.js +284 -25
  67. package/dist/adapter/resources/texture.js.map +1 -1
  68. package/dist/adapter/types/attachments.d.ts +1 -1
  69. package/dist/adapter/types/attachments.d.ts.map +1 -1
  70. package/dist/adapter/types/buffer-layout.d.ts +1 -1
  71. package/dist/adapter/types/buffer-layout.d.ts.map +1 -1
  72. package/dist/adapter/types/parameters.d.ts +3 -1
  73. package/dist/adapter/types/parameters.d.ts.map +1 -1
  74. package/dist/adapter/types/parameters.js +1 -0
  75. package/dist/adapter/types/parameters.js.map +1 -1
  76. package/dist/adapter/types/shader-layout.d.ts +10 -6
  77. package/dist/adapter/types/shader-layout.d.ts.map +1 -1
  78. package/dist/adapter/types/uniforms.d.ts +6 -0
  79. package/dist/adapter/types/uniforms.d.ts.map +1 -1
  80. package/dist/adapter-utils/bind-groups.d.ts +9 -0
  81. package/dist/adapter-utils/bind-groups.d.ts.map +1 -0
  82. package/dist/adapter-utils/bind-groups.js +41 -0
  83. package/dist/adapter-utils/bind-groups.js.map +1 -0
  84. package/dist/adapter-utils/format-compiler-log.d.ts.map +1 -1
  85. package/dist/adapter-utils/format-compiler-log.js +23 -15
  86. package/dist/adapter-utils/format-compiler-log.js.map +1 -1
  87. package/dist/adapter-utils/get-attribute-from-layouts.d.ts +2 -2
  88. package/dist/adapter-utils/get-attribute-from-layouts.d.ts.map +1 -1
  89. package/dist/adapter-utils/get-attribute-from-layouts.js +6 -6
  90. package/dist/adapter-utils/get-attribute-from-layouts.js.map +1 -1
  91. package/dist/dist.dev.js +2686 -644
  92. package/dist/dist.min.js +10 -9
  93. package/dist/factories/bind-group-factory.d.ts +20 -0
  94. package/dist/factories/bind-group-factory.d.ts.map +1 -0
  95. package/dist/factories/bind-group-factory.js +79 -0
  96. package/dist/factories/bind-group-factory.js.map +1 -0
  97. package/dist/factories/core-module-state.d.ts +7 -0
  98. package/dist/factories/core-module-state.d.ts.map +1 -0
  99. package/dist/{shadertypes/data-types/shader-types.js → factories/core-module-state.js} +1 -1
  100. package/dist/factories/core-module-state.js.map +1 -0
  101. package/dist/factories/pipeline-factory.d.ts +54 -0
  102. package/dist/factories/pipeline-factory.d.ts.map +1 -0
  103. package/dist/factories/pipeline-factory.js +270 -0
  104. package/dist/factories/pipeline-factory.js.map +1 -0
  105. package/dist/factories/shader-factory.d.ts +20 -0
  106. package/dist/factories/shader-factory.d.ts.map +1 -0
  107. package/dist/factories/shader-factory.js +84 -0
  108. package/dist/factories/shader-factory.js.map +1 -0
  109. package/dist/index.cjs +2422 -554
  110. package/dist/index.cjs.map +4 -4
  111. package/dist/index.d.ts +30 -14
  112. package/dist/index.d.ts.map +1 -1
  113. package/dist/index.js +19 -7
  114. package/dist/index.js.map +1 -1
  115. package/dist/portable/shader-block-writer.d.ts +51 -0
  116. package/dist/portable/shader-block-writer.d.ts.map +1 -0
  117. package/dist/portable/shader-block-writer.js +185 -0
  118. package/dist/portable/shader-block-writer.js.map +1 -0
  119. package/dist/portable/uniform-block.d.ts +1 -1
  120. package/dist/portable/uniform-block.d.ts.map +1 -1
  121. package/dist/portable/uniform-store.d.ts +55 -24
  122. package/dist/portable/uniform-store.d.ts.map +1 -1
  123. package/dist/portable/uniform-store.js +73 -25
  124. package/dist/portable/uniform-store.js.map +1 -1
  125. package/dist/shadertypes/data-types/data-type-decoder.d.ts +20 -0
  126. package/dist/shadertypes/data-types/data-type-decoder.d.ts.map +1 -0
  127. package/dist/shadertypes/data-types/data-type-decoder.js +79 -0
  128. package/dist/shadertypes/data-types/data-type-decoder.js.map +1 -0
  129. package/dist/shadertypes/data-types/data-types.d.ts +31 -12
  130. package/dist/shadertypes/data-types/data-types.d.ts.map +1 -1
  131. package/dist/shadertypes/data-types/decode-data-types.d.ts.map +1 -1
  132. package/dist/shadertypes/data-types/decode-data-types.js +2 -1
  133. package/dist/shadertypes/data-types/decode-data-types.js.map +1 -1
  134. package/dist/{image-utils → shadertypes/image-types}/image-types.d.ts +0 -6
  135. package/dist/shadertypes/image-types/image-types.d.ts.map +1 -0
  136. package/dist/shadertypes/image-types/image-types.js.map +1 -0
  137. package/dist/shadertypes/shader-types/shader-block-layout.d.ts +72 -0
  138. package/dist/shadertypes/shader-types/shader-block-layout.d.ts.map +1 -0
  139. package/dist/shadertypes/shader-types/shader-block-layout.js +209 -0
  140. package/dist/shadertypes/shader-types/shader-block-layout.js.map +1 -0
  141. package/dist/shadertypes/shader-types/shader-type-decoder.d.ts +41 -0
  142. package/dist/shadertypes/shader-types/shader-type-decoder.d.ts.map +1 -0
  143. package/dist/shadertypes/{data-types/decode-shader-types.js → shader-types/shader-type-decoder.js} +43 -4
  144. package/dist/shadertypes/shader-types/shader-type-decoder.js.map +1 -0
  145. package/dist/shadertypes/shader-types/shader-types.d.ts +101 -0
  146. package/dist/shadertypes/shader-types/shader-types.d.ts.map +1 -0
  147. package/dist/shadertypes/shader-types/shader-types.js +30 -0
  148. package/dist/shadertypes/shader-types/shader-types.js.map +1 -0
  149. package/dist/shadertypes/texture-types/pixel-utils.d.ts.map +1 -0
  150. package/dist/shadertypes/{textures → texture-types}/pixel-utils.js +4 -4
  151. package/dist/shadertypes/texture-types/pixel-utils.js.map +1 -0
  152. package/dist/shadertypes/texture-types/texture-format-decoder.d.ts +36 -0
  153. package/dist/shadertypes/texture-types/texture-format-decoder.d.ts.map +1 -0
  154. package/dist/shadertypes/{textures → texture-types}/texture-format-decoder.js +109 -37
  155. package/dist/shadertypes/texture-types/texture-format-decoder.js.map +1 -0
  156. package/dist/shadertypes/texture-types/texture-format-generics.d.ts +34 -0
  157. package/dist/shadertypes/texture-types/texture-format-generics.d.ts.map +1 -0
  158. package/dist/shadertypes/texture-types/texture-format-generics.js.map +1 -0
  159. package/dist/shadertypes/texture-types/texture-format-table.d.ts.map +1 -0
  160. package/dist/shadertypes/{textures → texture-types}/texture-format-table.js +10 -9
  161. package/dist/shadertypes/texture-types/texture-format-table.js.map +1 -0
  162. package/dist/shadertypes/{textures → texture-types}/texture-formats.d.ts +51 -17
  163. package/dist/shadertypes/texture-types/texture-formats.d.ts.map +1 -0
  164. package/dist/shadertypes/{textures → texture-types}/texture-formats.js +1 -0
  165. package/dist/shadertypes/texture-types/texture-formats.js.map +1 -0
  166. package/dist/shadertypes/texture-types/texture-layout.d.ts +5 -0
  167. package/dist/shadertypes/texture-types/texture-layout.d.ts.map +1 -0
  168. package/dist/shadertypes/texture-types/texture-layout.js +41 -0
  169. package/dist/shadertypes/texture-types/texture-layout.js.map +1 -0
  170. package/dist/shadertypes/vertex-types/vertex-format-decoder.d.ts +24 -0
  171. package/dist/shadertypes/vertex-types/vertex-format-decoder.d.ts.map +1 -0
  172. package/dist/shadertypes/vertex-types/vertex-format-decoder.js +106 -0
  173. package/dist/shadertypes/vertex-types/vertex-format-decoder.js.map +1 -0
  174. package/dist/shadertypes/vertex-types/vertex-formats.d.ts +50 -0
  175. package/dist/shadertypes/vertex-types/vertex-formats.d.ts.map +1 -0
  176. package/dist/shadertypes/vertex-types/vertex-formats.js.map +1 -0
  177. package/dist/utils/array-equal.d.ts +1 -1
  178. package/dist/utils/array-equal.d.ts.map +1 -1
  179. package/dist/utils/array-equal.js +15 -9
  180. package/dist/utils/array-equal.js.map +1 -1
  181. package/dist/utils/assert.d.ts +5 -0
  182. package/dist/utils/assert.d.ts.map +1 -0
  183. package/dist/utils/assert.js +17 -0
  184. package/dist/utils/assert.js.map +1 -0
  185. package/dist/utils/stats-manager.d.ts.map +1 -1
  186. package/dist/utils/stats-manager.js +61 -1
  187. package/dist/utils/stats-manager.js.map +1 -1
  188. package/package.json +6 -6
  189. package/src/adapter/canvas-context.ts +7 -556
  190. package/src/adapter/canvas-observer.ts +130 -0
  191. package/src/adapter/canvas-surface.ts +521 -0
  192. package/src/adapter/device.ts +308 -24
  193. package/src/adapter/presentation-context.ts +16 -0
  194. package/src/adapter/resources/buffer.ts +13 -5
  195. package/src/adapter/resources/command-buffer.ts +4 -2
  196. package/src/adapter/resources/command-encoder.ts +101 -10
  197. package/src/adapter/resources/compute-pipeline.ts +2 -2
  198. package/src/adapter/resources/fence.ts +32 -0
  199. package/src/adapter/resources/framebuffer.ts +16 -13
  200. package/src/adapter/resources/query-set.ts +17 -1
  201. package/src/adapter/resources/render-pipeline.ts +52 -16
  202. package/src/adapter/resources/resource.ts +289 -14
  203. package/src/adapter/resources/shader.ts +28 -28
  204. package/src/adapter/resources/shared-render-pipeline.ts +40 -0
  205. package/src/adapter/resources/texture-view.ts +1 -1
  206. package/src/adapter/resources/texture.ts +427 -49
  207. package/src/adapter/types/attachments.ts +1 -1
  208. package/src/adapter/types/buffer-layout.ts +1 -1
  209. package/src/adapter/types/parameters.ts +4 -1
  210. package/src/adapter/types/shader-layout.ts +15 -9
  211. package/src/adapter/types/uniforms.ts +12 -0
  212. package/src/adapter-utils/bind-groups.ts +71 -0
  213. package/src/adapter-utils/format-compiler-log.ts +23 -15
  214. package/src/adapter-utils/get-attribute-from-layouts.ts +8 -11
  215. package/src/factories/bind-group-factory.ts +139 -0
  216. package/src/factories/core-module-state.ts +11 -0
  217. package/src/factories/pipeline-factory.ts +328 -0
  218. package/src/factories/shader-factory.ts +103 -0
  219. package/src/index.ts +70 -26
  220. package/src/portable/shader-block-writer.ts +254 -0
  221. package/src/portable/uniform-block.ts +1 -1
  222. package/src/portable/uniform-store.ts +98 -40
  223. package/src/shadertypes/data-types/data-type-decoder.ts +105 -0
  224. package/src/shadertypes/data-types/data-types.ts +100 -48
  225. package/src/shadertypes/data-types/decode-data-types.ts +2 -1
  226. package/src/{image-utils → shadertypes/image-types}/image-types.ts +0 -7
  227. package/src/shadertypes/shader-types/shader-block-layout.ts +340 -0
  228. package/src/shadertypes/{data-types/decode-shader-types.ts → shader-types/shader-type-decoder.ts} +88 -14
  229. package/src/shadertypes/shader-types/shader-types.ts +207 -0
  230. package/src/shadertypes/{textures → texture-types}/pixel-utils.ts +4 -4
  231. package/src/shadertypes/{textures → texture-types}/texture-format-decoder.ts +166 -45
  232. package/src/shadertypes/{textures → texture-types}/texture-format-generics.ts +42 -48
  233. package/src/shadertypes/{textures → texture-types}/texture-format-table.ts +10 -9
  234. package/src/shadertypes/{textures → texture-types}/texture-formats.ts +73 -17
  235. package/src/shadertypes/texture-types/texture-layout.ts +60 -0
  236. package/src/shadertypes/vertex-types/vertex-format-decoder.ts +131 -0
  237. package/src/shadertypes/vertex-types/vertex-formats.ts +183 -0
  238. package/src/utils/array-equal.ts +21 -9
  239. package/src/utils/assert.ts +18 -0
  240. package/src/utils/stats-manager.ts +76 -2
  241. package/dist/image-utils/image-types.d.ts.map +0 -1
  242. package/dist/image-utils/image-types.js.map +0 -1
  243. package/dist/portable/uniform-buffer-layout.d.ts +0 -28
  244. package/dist/portable/uniform-buffer-layout.d.ts.map +0 -1
  245. package/dist/portable/uniform-buffer-layout.js +0 -96
  246. package/dist/portable/uniform-buffer-layout.js.map +0 -1
  247. package/dist/shadertypes/data-types/decode-shader-types.d.ts +0 -17
  248. package/dist/shadertypes/data-types/decode-shader-types.d.ts.map +0 -1
  249. package/dist/shadertypes/data-types/decode-shader-types.js.map +0 -1
  250. package/dist/shadertypes/data-types/shader-types.d.ts +0 -45
  251. package/dist/shadertypes/data-types/shader-types.d.ts.map +0 -1
  252. package/dist/shadertypes/data-types/shader-types.js.map +0 -1
  253. package/dist/shadertypes/textures/pixel-utils.d.ts.map +0 -1
  254. package/dist/shadertypes/textures/pixel-utils.js.map +0 -1
  255. package/dist/shadertypes/textures/texture-format-decoder.d.ts +0 -18
  256. package/dist/shadertypes/textures/texture-format-decoder.d.ts.map +0 -1
  257. package/dist/shadertypes/textures/texture-format-decoder.js.map +0 -1
  258. package/dist/shadertypes/textures/texture-format-generics.d.ts +0 -33
  259. package/dist/shadertypes/textures/texture-format-generics.d.ts.map +0 -1
  260. package/dist/shadertypes/textures/texture-format-generics.js.map +0 -1
  261. package/dist/shadertypes/textures/texture-format-table.d.ts.map +0 -1
  262. package/dist/shadertypes/textures/texture-format-table.js.map +0 -1
  263. package/dist/shadertypes/textures/texture-formats.d.ts.map +0 -1
  264. package/dist/shadertypes/textures/texture-formats.js.map +0 -1
  265. package/dist/shadertypes/vertex-arrays/decode-vertex-format.d.ts +0 -18
  266. package/dist/shadertypes/vertex-arrays/decode-vertex-format.d.ts.map +0 -1
  267. package/dist/shadertypes/vertex-arrays/decode-vertex-format.js +0 -100
  268. package/dist/shadertypes/vertex-arrays/decode-vertex-format.js.map +0 -1
  269. package/dist/shadertypes/vertex-arrays/vertex-formats.d.ts +0 -27
  270. package/dist/shadertypes/vertex-arrays/vertex-formats.d.ts.map +0 -1
  271. package/dist/shadertypes/vertex-arrays/vertex-formats.js.map +0 -1
  272. package/src/portable/uniform-buffer-layout.ts +0 -118
  273. package/src/shadertypes/data-types/shader-types.ts +0 -87
  274. package/src/shadertypes/vertex-arrays/decode-vertex-format.ts +0 -124
  275. package/src/shadertypes/vertex-arrays/vertex-formats.ts +0 -91
  276. /package/dist/{image-utils → shadertypes/image-types}/image-types.js +0 -0
  277. /package/dist/shadertypes/{textures → texture-types}/pixel-utils.d.ts +0 -0
  278. /package/dist/shadertypes/{textures → texture-types}/texture-format-generics.js +0 -0
  279. /package/dist/shadertypes/{textures → texture-types}/texture-format-table.d.ts +0 -0
  280. /package/dist/shadertypes/{vertex-arrays → vertex-types}/vertex-formats.js +0 -0
package/dist/index.cjs CHANGED
@@ -36,45 +36,75 @@ __export(dist_exports, {
36
36
  DeviceFeatures: () => DeviceFeatures,
37
37
  DeviceLimits: () => DeviceLimits,
38
38
  ExternalTexture: () => ExternalTexture,
39
+ Fence: () => Fence,
39
40
  Framebuffer: () => Framebuffer,
41
+ PipelineFactory: () => PipelineFactory,
40
42
  PipelineLayout: () => PipelineLayout,
43
+ PresentationContext: () => PresentationContext,
41
44
  QuerySet: () => QuerySet,
42
45
  RenderPass: () => RenderPass,
43
46
  RenderPipeline: () => RenderPipeline,
44
47
  Resource: () => Resource,
45
48
  Sampler: () => Sampler,
46
49
  Shader: () => Shader,
50
+ ShaderBlockWriter: () => ShaderBlockWriter,
51
+ ShaderFactory: () => ShaderFactory,
52
+ SharedRenderPipeline: () => SharedRenderPipeline,
47
53
  Texture: () => Texture,
48
- TextureFormatDecoder: () => TextureFormatDecoder,
49
54
  TextureView: () => TextureView,
50
55
  TransformFeedback: () => TransformFeedback,
51
56
  UniformBlock: () => UniformBlock,
52
- UniformBufferLayout: () => UniformBufferLayout,
53
57
  UniformStore: () => UniformStore,
54
58
  VertexArray: () => VertexArray,
59
+ _getDefaultBindGroupFactory: () => _getDefaultBindGroupFactory,
55
60
  _getTextureFormatDefinition: () => getTextureFormatDefinition,
56
61
  _getTextureFormatTable: () => getTextureFormatTable,
62
+ assert: () => assert,
63
+ assertDefined: () => assertDefined,
64
+ dataTypeDecoder: () => dataTypeDecoder,
65
+ flattenBindingsByGroup: () => flattenBindingsByGroup,
57
66
  getAttributeInfosFromLayouts: () => getAttributeInfosFromLayouts,
58
67
  getAttributeShaderTypeInfo: () => getAttributeShaderTypeInfo,
59
- getDataType: () => getDataType,
60
- getDataTypeInfo: () => getDataTypeInfo,
61
- getNormalizedDataType: () => getNormalizedDataType,
68
+ getExternalImageSize: () => getExternalImageSize,
62
69
  getScratchArray: () => getScratchArray,
70
+ getShaderLayoutBinding: () => getShaderLayoutBinding,
71
+ getTextureImageView: () => getTextureImageView,
63
72
  getTypedArrayConstructor: () => getTypedArrayConstructor,
64
73
  getVariableShaderTypeInfo: () => getVariableShaderTypeInfo,
65
- getVertexFormatFromAttribute: () => getVertexFormatFromAttribute,
66
- getVertexFormatInfo: () => getVertexFormatInfo,
74
+ isExternalImage: () => isExternalImage,
67
75
  log: () => log,
68
76
  luma: () => luma,
69
- makeVertexFormat: () => makeVertexFormat,
77
+ makeShaderBlockLayout: () => makeShaderBlockLayout,
78
+ normalizeBindingsByGroup: () => normalizeBindingsByGroup,
70
79
  readPixel: () => readPixel,
80
+ setTextureImageData: () => setTextureImageData,
81
+ shaderTypeDecoder: () => shaderTypeDecoder,
71
82
  textureFormatDecoder: () => textureFormatDecoder,
83
+ vertexFormatDecoder: () => vertexFormatDecoder,
72
84
  writePixel: () => writePixel
73
85
  });
74
86
  module.exports = __toCommonJS(dist_exports);
75
87
 
76
88
  // dist/utils/stats-manager.js
77
89
  var import_stats = require("@probe.gl/stats");
90
+ var GPU_TIME_AND_MEMORY_STATS = "GPU Time and Memory";
91
+ var GPU_TIME_AND_MEMORY_STAT_ORDER = [
92
+ "Adapter",
93
+ "GPU",
94
+ "GPU Type",
95
+ "GPU Backend",
96
+ "Frame Rate",
97
+ "CPU Time",
98
+ "GPU Time",
99
+ "GPU Memory",
100
+ "Buffer Memory",
101
+ "Texture Memory",
102
+ "Referenced Buffer Memory",
103
+ "Referenced Texture Memory",
104
+ "Swap Chain Texture"
105
+ ];
106
+ var ORDERED_STATS_CACHE = /* @__PURE__ */ new WeakMap();
107
+ var ORDERED_STAT_NAME_SET_CACHE = /* @__PURE__ */ new WeakMap();
78
108
  var StatsManager = class {
79
109
  stats = /* @__PURE__ */ new Map();
80
110
  getStats(name2) {
@@ -84,10 +114,50 @@ var StatsManager = class {
84
114
  if (!this.stats.has(name2)) {
85
115
  this.stats.set(name2, new import_stats.Stats({ id: name2 }));
86
116
  }
87
- return this.stats.get(name2);
117
+ const stats = this.stats.get(name2);
118
+ if (name2 === GPU_TIME_AND_MEMORY_STATS) {
119
+ initializeStats(stats, GPU_TIME_AND_MEMORY_STAT_ORDER);
120
+ }
121
+ return stats;
88
122
  }
89
123
  };
90
124
  var lumaStats = new StatsManager();
125
+ function initializeStats(stats, orderedStatNames) {
126
+ const statsMap = stats.stats;
127
+ let addedOrderedStat = false;
128
+ for (const statName of orderedStatNames) {
129
+ if (!statsMap[statName]) {
130
+ stats.get(statName);
131
+ addedOrderedStat = true;
132
+ }
133
+ }
134
+ const statCount = Object.keys(statsMap).length;
135
+ const cachedStats = ORDERED_STATS_CACHE.get(stats);
136
+ if (!addedOrderedStat && (cachedStats == null ? void 0 : cachedStats.orderedStatNames) === orderedStatNames && cachedStats.statCount === statCount) {
137
+ return;
138
+ }
139
+ const reorderedStats = {};
140
+ let orderedStatNamesSet = ORDERED_STAT_NAME_SET_CACHE.get(orderedStatNames);
141
+ if (!orderedStatNamesSet) {
142
+ orderedStatNamesSet = new Set(orderedStatNames);
143
+ ORDERED_STAT_NAME_SET_CACHE.set(orderedStatNames, orderedStatNamesSet);
144
+ }
145
+ for (const statName of orderedStatNames) {
146
+ if (statsMap[statName]) {
147
+ reorderedStats[statName] = statsMap[statName];
148
+ }
149
+ }
150
+ for (const [statName, stat] of Object.entries(statsMap)) {
151
+ if (!orderedStatNamesSet.has(statName)) {
152
+ reorderedStats[statName] = stat;
153
+ }
154
+ }
155
+ for (const statName of Object.keys(statsMap)) {
156
+ delete statsMap[statName];
157
+ }
158
+ Object.assign(statsMap, reorderedStats);
159
+ ORDERED_STATS_CACHE.set(stats, { orderedStatNames, statCount });
160
+ }
91
161
 
92
162
  // dist/utils/log.js
93
163
  var import_log = require("@probe.gl/log");
@@ -102,19 +172,75 @@ function uid(id = "id") {
102
172
  }
103
173
 
104
174
  // dist/adapter/resources/resource.js
175
+ var CPU_HOTSPOT_PROFILER_MODULE = "cpu-hotspot-profiler";
176
+ var RESOURCE_COUNTS_STATS = "GPU Resource Counts";
177
+ var LEGACY_RESOURCE_COUNTS_STATS = "Resource Counts";
178
+ var GPU_TIME_AND_MEMORY_STATS2 = "GPU Time and Memory";
179
+ var BASE_RESOURCE_COUNT_ORDER = [
180
+ "Resources",
181
+ "Buffers",
182
+ "Textures",
183
+ "Samplers",
184
+ "TextureViews",
185
+ "Framebuffers",
186
+ "QuerySets",
187
+ "Shaders",
188
+ "RenderPipelines",
189
+ "ComputePipelines",
190
+ "PipelineLayouts",
191
+ "VertexArrays",
192
+ "RenderPasss",
193
+ "ComputePasss",
194
+ "CommandEncoders",
195
+ "CommandBuffers"
196
+ ];
197
+ var WEBGL_RESOURCE_COUNT_ORDER = [
198
+ "Resources",
199
+ "Buffers",
200
+ "Textures",
201
+ "Samplers",
202
+ "TextureViews",
203
+ "Framebuffers",
204
+ "QuerySets",
205
+ "Shaders",
206
+ "RenderPipelines",
207
+ "SharedRenderPipelines",
208
+ "ComputePipelines",
209
+ "PipelineLayouts",
210
+ "VertexArrays",
211
+ "RenderPasss",
212
+ "ComputePasss",
213
+ "CommandEncoders",
214
+ "CommandBuffers"
215
+ ];
216
+ var BASE_RESOURCE_COUNT_STAT_ORDER = BASE_RESOURCE_COUNT_ORDER.flatMap((resourceType) => [
217
+ `${resourceType} Created`,
218
+ `${resourceType} Active`
219
+ ]);
220
+ var WEBGL_RESOURCE_COUNT_STAT_ORDER = WEBGL_RESOURCE_COUNT_ORDER.flatMap((resourceType) => [
221
+ `${resourceType} Created`,
222
+ `${resourceType} Active`
223
+ ]);
224
+ var ORDERED_STATS_CACHE2 = /* @__PURE__ */ new WeakMap();
225
+ var ORDERED_STAT_NAME_SET_CACHE2 = /* @__PURE__ */ new WeakMap();
105
226
  var Resource = class {
106
227
  toString() {
107
228
  return `${this[Symbol.toStringTag] || this.constructor.name}:"${this.id}"`;
108
229
  }
109
230
  /** props.id, for debugging. */
110
231
  id;
232
+ /** The props that this resource was created with */
111
233
  props;
234
+ /** User data object, reserved for the application */
112
235
  userData = {};
236
+ /** The device that this resource is associated with - TODO can we remove this dup? */
113
237
  _device;
114
238
  /** Whether this resource has been destroyed */
115
239
  destroyed = false;
116
240
  /** For resources that allocate GPU memory */
117
241
  allocatedBytes = 0;
242
+ /** Stats bucket currently holding the tracked allocation */
243
+ allocatedBytesName = null;
118
244
  /** Attached resources will be destroyed when this resource is destroyed. Tracks auto-created "sub" resources. */
119
245
  _attachedResources = /* @__PURE__ */ new Set();
120
246
  /**
@@ -136,6 +262,9 @@ var Resource = class {
136
262
  * destroy can be called on any resource to release it before it is garbage collected.
137
263
  */
138
264
  destroy() {
265
+ if (this.destroyed) {
266
+ return;
267
+ }
139
268
  this.destroyResource();
140
269
  }
141
270
  /** @deprecated Use destroy() */
@@ -174,7 +303,7 @@ var Resource = class {
174
303
  }
175
304
  /** Destroy all owned resources. Make sure the resources are no longer needed before calling. */
176
305
  destroyAttachedResources() {
177
- for (const resource of Object.values(this._attachedResources)) {
306
+ for (const resource of this._attachedResources) {
178
307
  resource.destroy();
179
308
  }
180
309
  this._attachedResources = /* @__PURE__ */ new Set();
@@ -182,37 +311,107 @@ var Resource = class {
182
311
  // PROTECTED METHODS
183
312
  /** Perform all destroy steps. Can be called by derived resources when overriding destroy() */
184
313
  destroyResource() {
314
+ if (this.destroyed) {
315
+ return;
316
+ }
185
317
  this.destroyAttachedResources();
186
318
  this.removeStats();
187
319
  this.destroyed = true;
188
320
  }
189
321
  /** Called by .destroy() to track object destruction. Subclass must call if overriding destroy() */
190
322
  removeStats() {
191
- const stats = this._device.statsManager.getStats("Resource Counts");
192
- const name2 = this[Symbol.toStringTag];
193
- stats.get(`${name2}s Active`).decrementCount();
323
+ const profiler = getCpuHotspotProfiler(this._device);
324
+ const startTime = profiler ? getTimestamp() : 0;
325
+ const statsObjects = [
326
+ this._device.statsManager.getStats(RESOURCE_COUNTS_STATS),
327
+ this._device.statsManager.getStats(LEGACY_RESOURCE_COUNTS_STATS)
328
+ ];
329
+ const orderedStatNames = getResourceCountStatOrder(this._device);
330
+ for (const stats of statsObjects) {
331
+ initializeStats2(stats, orderedStatNames);
332
+ }
333
+ const name2 = this.getStatsName();
334
+ for (const stats of statsObjects) {
335
+ stats.get("Resources Active").decrementCount();
336
+ stats.get(`${name2}s Active`).decrementCount();
337
+ }
338
+ if (profiler) {
339
+ profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
340
+ profiler.statsBookkeepingTimeMs = (profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
341
+ }
194
342
  }
195
343
  /** Called by subclass to track memory allocations */
196
- trackAllocatedMemory(bytes, name2 = this[Symbol.toStringTag]) {
197
- const stats = this._device.statsManager.getStats("Resource Counts");
344
+ trackAllocatedMemory(bytes, name2 = this.getStatsName()) {
345
+ const profiler = getCpuHotspotProfiler(this._device);
346
+ const startTime = profiler ? getTimestamp() : 0;
347
+ const stats = this._device.statsManager.getStats(GPU_TIME_AND_MEMORY_STATS2);
348
+ if (this.allocatedBytes > 0 && this.allocatedBytesName) {
349
+ stats.get("GPU Memory").subtractCount(this.allocatedBytes);
350
+ stats.get(`${this.allocatedBytesName} Memory`).subtractCount(this.allocatedBytes);
351
+ }
198
352
  stats.get("GPU Memory").addCount(bytes);
199
353
  stats.get(`${name2} Memory`).addCount(bytes);
354
+ if (profiler) {
355
+ profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
356
+ profiler.statsBookkeepingTimeMs = (profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
357
+ }
200
358
  this.allocatedBytes = bytes;
359
+ this.allocatedBytesName = name2;
360
+ }
361
+ /** Called by subclass to track handle-backed memory allocations separately from owned allocations */
362
+ trackReferencedMemory(bytes, name2 = this.getStatsName()) {
363
+ this.trackAllocatedMemory(bytes, `Referenced ${name2}`);
201
364
  }
202
365
  /** Called by subclass to track memory deallocations */
203
- trackDeallocatedMemory(name2 = this[Symbol.toStringTag]) {
204
- const stats = this._device.statsManager.getStats("Resource Counts");
366
+ trackDeallocatedMemory(name2 = this.getStatsName()) {
367
+ if (this.allocatedBytes === 0) {
368
+ this.allocatedBytesName = null;
369
+ return;
370
+ }
371
+ const profiler = getCpuHotspotProfiler(this._device);
372
+ const startTime = profiler ? getTimestamp() : 0;
373
+ const stats = this._device.statsManager.getStats(GPU_TIME_AND_MEMORY_STATS2);
205
374
  stats.get("GPU Memory").subtractCount(this.allocatedBytes);
206
- stats.get(`${name2} Memory`).subtractCount(this.allocatedBytes);
375
+ stats.get(`${this.allocatedBytesName || name2} Memory`).subtractCount(this.allocatedBytes);
376
+ if (profiler) {
377
+ profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
378
+ profiler.statsBookkeepingTimeMs = (profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
379
+ }
207
380
  this.allocatedBytes = 0;
381
+ this.allocatedBytesName = null;
382
+ }
383
+ /** Called by subclass to deallocate handle-backed memory tracked via trackReferencedMemory() */
384
+ trackDeallocatedReferencedMemory(name2 = this.getStatsName()) {
385
+ this.trackDeallocatedMemory(`Referenced ${name2}`);
208
386
  }
209
387
  /** Called by resource constructor to track object creation */
210
388
  addStats() {
211
- const stats = this._device.statsManager.getStats("Resource Counts");
212
- const name2 = this[Symbol.toStringTag];
213
- stats.get("Resources Created").incrementCount();
214
- stats.get(`${name2}s Created`).incrementCount();
215
- stats.get(`${name2}s Active`).incrementCount();
389
+ const name2 = this.getStatsName();
390
+ const profiler = getCpuHotspotProfiler(this._device);
391
+ const startTime = profiler ? getTimestamp() : 0;
392
+ const statsObjects = [
393
+ this._device.statsManager.getStats(RESOURCE_COUNTS_STATS),
394
+ this._device.statsManager.getStats(LEGACY_RESOURCE_COUNTS_STATS)
395
+ ];
396
+ const orderedStatNames = getResourceCountStatOrder(this._device);
397
+ for (const stats of statsObjects) {
398
+ initializeStats2(stats, orderedStatNames);
399
+ }
400
+ for (const stats of statsObjects) {
401
+ stats.get("Resources Created").incrementCount();
402
+ stats.get("Resources Active").incrementCount();
403
+ stats.get(`${name2}s Created`).incrementCount();
404
+ stats.get(`${name2}s Active`).incrementCount();
405
+ }
406
+ if (profiler) {
407
+ profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
408
+ profiler.statsBookkeepingTimeMs = (profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
409
+ }
410
+ recordTransientCanvasResourceCreate(this._device, name2);
411
+ }
412
+ /** Canonical resource name used for stats buckets. */
413
+ getStatsName() {
414
+ return getCanonicalResourceName(this);
216
415
  }
217
416
  };
218
417
  /** Default properties for resource */
@@ -230,6 +429,97 @@ function selectivelyMerge(props, defaultProps) {
230
429
  }
231
430
  return mergedProps;
232
431
  }
432
+ function initializeStats2(stats, orderedStatNames) {
433
+ const statsMap = stats.stats;
434
+ let addedOrderedStat = false;
435
+ for (const statName of orderedStatNames) {
436
+ if (!statsMap[statName]) {
437
+ stats.get(statName);
438
+ addedOrderedStat = true;
439
+ }
440
+ }
441
+ const statCount = Object.keys(statsMap).length;
442
+ const cachedStats = ORDERED_STATS_CACHE2.get(stats);
443
+ if (!addedOrderedStat && (cachedStats == null ? void 0 : cachedStats.orderedStatNames) === orderedStatNames && cachedStats.statCount === statCount) {
444
+ return;
445
+ }
446
+ const reorderedStats = {};
447
+ let orderedStatNamesSet = ORDERED_STAT_NAME_SET_CACHE2.get(orderedStatNames);
448
+ if (!orderedStatNamesSet) {
449
+ orderedStatNamesSet = new Set(orderedStatNames);
450
+ ORDERED_STAT_NAME_SET_CACHE2.set(orderedStatNames, orderedStatNamesSet);
451
+ }
452
+ for (const statName of orderedStatNames) {
453
+ if (statsMap[statName]) {
454
+ reorderedStats[statName] = statsMap[statName];
455
+ }
456
+ }
457
+ for (const [statName, stat] of Object.entries(statsMap)) {
458
+ if (!orderedStatNamesSet.has(statName)) {
459
+ reorderedStats[statName] = stat;
460
+ }
461
+ }
462
+ for (const statName of Object.keys(statsMap)) {
463
+ delete statsMap[statName];
464
+ }
465
+ Object.assign(statsMap, reorderedStats);
466
+ ORDERED_STATS_CACHE2.set(stats, { orderedStatNames, statCount });
467
+ }
468
+ function getResourceCountStatOrder(device) {
469
+ return device.type === "webgl" ? WEBGL_RESOURCE_COUNT_STAT_ORDER : BASE_RESOURCE_COUNT_STAT_ORDER;
470
+ }
471
+ function getCpuHotspotProfiler(device) {
472
+ const profiler = device.userData[CPU_HOTSPOT_PROFILER_MODULE];
473
+ return (profiler == null ? void 0 : profiler.enabled) ? profiler : null;
474
+ }
475
+ function getTimestamp() {
476
+ var _a, _b;
477
+ return ((_b = (_a = globalThis.performance) == null ? void 0 : _a.now) == null ? void 0 : _b.call(_a)) ?? Date.now();
478
+ }
479
+ function recordTransientCanvasResourceCreate(device, name2) {
480
+ const profiler = getCpuHotspotProfiler(device);
481
+ if (!profiler || !profiler.activeDefaultFramebufferAcquireDepth) {
482
+ return;
483
+ }
484
+ profiler.transientCanvasResourceCreates = (profiler.transientCanvasResourceCreates || 0) + 1;
485
+ switch (name2) {
486
+ case "Texture":
487
+ profiler.transientCanvasTextureCreates = (profiler.transientCanvasTextureCreates || 0) + 1;
488
+ break;
489
+ case "TextureView":
490
+ profiler.transientCanvasTextureViewCreates = (profiler.transientCanvasTextureViewCreates || 0) + 1;
491
+ break;
492
+ case "Sampler":
493
+ profiler.transientCanvasSamplerCreates = (profiler.transientCanvasSamplerCreates || 0) + 1;
494
+ break;
495
+ case "Framebuffer":
496
+ profiler.transientCanvasFramebufferCreates = (profiler.transientCanvasFramebufferCreates || 0) + 1;
497
+ break;
498
+ default:
499
+ break;
500
+ }
501
+ }
502
+ function getCanonicalResourceName(resource) {
503
+ let prototype = Object.getPrototypeOf(resource);
504
+ while (prototype) {
505
+ const parentPrototype = Object.getPrototypeOf(prototype);
506
+ if (!parentPrototype || parentPrototype === Resource.prototype) {
507
+ return getPrototypeToStringTag(prototype) || resource[Symbol.toStringTag] || resource.constructor.name;
508
+ }
509
+ prototype = parentPrototype;
510
+ }
511
+ return resource[Symbol.toStringTag] || resource.constructor.name;
512
+ }
513
+ function getPrototypeToStringTag(prototype) {
514
+ const descriptor = Object.getOwnPropertyDescriptor(prototype, Symbol.toStringTag);
515
+ if (typeof (descriptor == null ? void 0 : descriptor.get) === "function") {
516
+ return descriptor.get.call(prototype);
517
+ }
518
+ if (typeof (descriptor == null ? void 0 : descriptor.value) === "string") {
519
+ return descriptor.value;
520
+ }
521
+ return null;
522
+ }
233
523
 
234
524
  // dist/adapter/resources/buffer.js
235
525
  var _Buffer = class extends Resource {
@@ -269,15 +559,23 @@ var _Buffer = class extends Resource {
269
559
  /** A partial CPU-side copy of the data in this buffer, for debugging purposes */
270
560
  debugData = new ArrayBuffer(0);
271
561
  /** This doesn't handle partial non-zero offset updates correctly */
272
- _setDebugData(data, byteOffset, byteLength) {
273
- const arrayBuffer2 = ArrayBuffer.isView(data) ? data.buffer : data;
562
+ _setDebugData(data, _byteOffset, byteLength) {
563
+ let arrayBufferView = null;
564
+ let arrayBuffer2;
565
+ if (ArrayBuffer.isView(data)) {
566
+ arrayBufferView = data;
567
+ arrayBuffer2 = data.buffer;
568
+ } else {
569
+ arrayBuffer2 = data;
570
+ }
274
571
  const debugDataLength = Math.min(data ? data.byteLength : byteLength, _Buffer.DEBUG_DATA_MAX_LENGTH);
275
572
  if (arrayBuffer2 === null) {
276
573
  this.debugData = new ArrayBuffer(debugDataLength);
277
- } else if (byteOffset === 0 && byteLength === arrayBuffer2.byteLength) {
278
- this.debugData = arrayBuffer2.slice(0, debugDataLength);
279
574
  } else {
280
- this.debugData = arrayBuffer2.slice(byteOffset, byteOffset + debugDataLength);
575
+ const sourceByteOffset = Math.min((arrayBufferView == null ? void 0 : arrayBufferView.byteOffset) || 0, arrayBuffer2.byteLength);
576
+ const availableByteLength = Math.max(0, arrayBuffer2.byteLength - sourceByteOffset);
577
+ const copyByteLength = Math.min(debugDataLength, availableByteLength);
578
+ this.debugData = new Uint8Array(arrayBuffer2, sourceByteOffset, copyByteLength).slice().buffer;
281
579
  }
282
580
  }
283
581
  };
@@ -311,61 +609,73 @@ __publicField(Buffer2, "defaultProps", {
311
609
  onMapped: void 0
312
610
  });
313
611
 
314
- // dist/shadertypes/data-types/decode-data-types.js
315
- function getDataTypeInfo(type) {
316
- const [signedType, primitiveType, byteLength] = NORMALIZED_TYPE_MAP[type];
317
- const normalized = type.includes("norm");
318
- const integer = !normalized && !type.startsWith("float");
319
- const signed = type.startsWith("s");
320
- return {
321
- signedType,
322
- primitiveType,
323
- byteLength,
324
- normalized,
325
- integer,
326
- signed
327
- };
328
- }
329
- function getNormalizedDataType(signedDataType) {
330
- const dataType = signedDataType;
331
- switch (dataType) {
332
- case "uint8":
333
- return "unorm8";
334
- case "sint8":
335
- return "snorm8";
336
- case "uint16":
337
- return "unorm16";
338
- case "sint16":
339
- return "snorm16";
340
- default:
341
- return dataType;
612
+ // dist/shadertypes/data-types/data-type-decoder.js
613
+ var DataTypeDecoder = class {
614
+ /**
615
+ * Gets info about a data type constant (signed or normalized)
616
+ * @returns underlying primitive / signed types, byte length, normalization, integer, signed flags
617
+ */
618
+ getDataTypeInfo(type) {
619
+ const [signedType, primitiveType, byteLength] = NORMALIZED_TYPE_MAP[type];
620
+ const normalized = type.includes("norm");
621
+ const integer = !normalized && !type.startsWith("float");
622
+ const signed = type.startsWith("s");
623
+ return {
624
+ signedType,
625
+ primitiveType,
626
+ byteLength,
627
+ normalized,
628
+ integer,
629
+ signed
630
+ // TODO - add webglOnly flag
631
+ };
342
632
  }
343
- }
344
- function alignTo(size, count) {
345
- switch (count) {
346
- case 1:
347
- return size;
348
- case 2:
349
- return size + size % 2;
350
- default:
351
- return size + (4 - size % 4) % 4;
633
+ /** Build a vertex format from a signed data type and a component */
634
+ getNormalizedDataType(signedDataType) {
635
+ const dataType = signedDataType;
636
+ switch (dataType) {
637
+ case "uint8":
638
+ return "unorm8";
639
+ case "sint8":
640
+ return "snorm8";
641
+ case "uint16":
642
+ return "unorm16";
643
+ case "sint16":
644
+ return "snorm16";
645
+ default:
646
+ return dataType;
647
+ }
352
648
  }
353
- }
354
- function getDataType(arrayOrType) {
355
- const Constructor = ArrayBuffer.isView(arrayOrType) ? arrayOrType.constructor : arrayOrType;
356
- if (Constructor === Uint8ClampedArray) {
357
- return "uint8";
649
+ /** Align offset to 1, 2 or 4 elements (4, 8 or 16 bytes) */
650
+ alignTo(size, count) {
651
+ switch (count) {
652
+ case 1:
653
+ return size;
654
+ case 2:
655
+ return size + size % 2;
656
+ default:
657
+ return size + (4 - size % 4) % 4;
658
+ }
358
659
  }
359
- const info = Object.values(NORMALIZED_TYPE_MAP).find((entry) => Constructor === entry[4]);
360
- if (!info) {
361
- throw new Error(Constructor.name);
660
+ /** Returns the VariableShaderType that corresponds to a typed array */
661
+ getDataType(arrayOrType) {
662
+ const Constructor = ArrayBuffer.isView(arrayOrType) ? arrayOrType.constructor : arrayOrType;
663
+ if (Constructor === Uint8ClampedArray) {
664
+ return "uint8";
665
+ }
666
+ const info = Object.values(NORMALIZED_TYPE_MAP).find((entry) => Constructor === entry[4]);
667
+ if (!info) {
668
+ throw new Error(Constructor.name);
669
+ }
670
+ return info[0];
362
671
  }
363
- return info[0];
364
- }
365
- function getTypedArrayConstructor(type) {
366
- const [, , , , Constructor] = NORMALIZED_TYPE_MAP[type];
367
- return Constructor;
368
- }
672
+ /** Returns the TypedArray that corresponds to a shader data type */
673
+ getTypedArrayConstructor(type) {
674
+ const [, , , , Constructor] = NORMALIZED_TYPE_MAP[type];
675
+ return Constructor;
676
+ }
677
+ };
678
+ var dataTypeDecoder = new DataTypeDecoder();
369
679
  var NORMALIZED_TYPE_MAP = {
370
680
  uint8: ["uint8", "u32", 1, false, Uint8Array],
371
681
  sint8: ["sint8", "i32", 1, false, Int8Array],
@@ -381,87 +691,99 @@ var NORMALIZED_TYPE_MAP = {
381
691
  sint32: ["sint32", "i32", 4, false, Int32Array]
382
692
  };
383
693
 
384
- // dist/shadertypes/vertex-arrays/decode-vertex-format.js
385
- function getVertexFormatInfo(format) {
386
- let webglOnly;
387
- if (format.endsWith("-webgl")) {
388
- format.replace("-webgl", "");
389
- webglOnly = true;
390
- }
391
- const [type_, count] = format.split("x");
392
- const type = type_;
393
- const components = count ? parseInt(count) : 1;
394
- const decodedType = getDataTypeInfo(type);
395
- const result = {
396
- type,
397
- components,
398
- byteLength: decodedType.byteLength * components,
399
- integer: decodedType.integer,
400
- signed: decodedType.signed,
401
- normalized: decodedType.normalized
402
- };
403
- if (webglOnly) {
404
- result.webglOnly = true;
405
- }
406
- return result;
407
- }
408
- function makeVertexFormat(signedDataType, components, normalized) {
409
- const dataType = normalized ? getNormalizedDataType(signedDataType) : signedDataType;
410
- switch (dataType) {
411
- case "unorm8":
412
- if (components === 1) {
413
- return "unorm8";
414
- }
415
- if (components === 3) {
416
- return "unorm8x3-webgl";
417
- }
418
- return `${dataType}x${components}`;
419
- case "snorm8":
420
- case "uint8":
421
- case "sint8":
422
- case "uint16":
423
- case "sint16":
424
- case "unorm16":
425
- case "snorm16":
426
- case "float16":
427
- if (components === 1 || components === 3) {
428
- throw new Error(`size: ${components}`);
429
- }
430
- return `${dataType}x${components}`;
431
- default:
432
- return components === 1 ? dataType : `${dataType}x${components}`;
433
- }
434
- }
435
- function getVertexFormatFromAttribute(typedArray, size, normalized) {
436
- if (!size || size > 4) {
437
- throw new Error(`size ${size}`);
694
+ // dist/shadertypes/vertex-types/vertex-format-decoder.js
695
+ var VertexFormatDecoder = class {
696
+ /**
697
+ * Decodes a vertex format, returning type, components, byte length and flags (integer, signed, normalized)
698
+ */
699
+ getVertexFormatInfo(format) {
700
+ let webglOnly;
701
+ if (format.endsWith("-webgl")) {
702
+ format.replace("-webgl", "");
703
+ webglOnly = true;
704
+ }
705
+ const [type_, count] = format.split("x");
706
+ const type = type_;
707
+ const components = count ? parseInt(count) : 1;
708
+ const decodedType = dataTypeDecoder.getDataTypeInfo(type);
709
+ const result = {
710
+ type,
711
+ components,
712
+ byteLength: decodedType.byteLength * components,
713
+ integer: decodedType.integer,
714
+ signed: decodedType.signed,
715
+ normalized: decodedType.normalized
716
+ };
717
+ if (webglOnly) {
718
+ result.webglOnly = true;
719
+ }
720
+ return result;
721
+ }
722
+ /** Build a vertex format from a signed data type and a component */
723
+ makeVertexFormat(signedDataType, components, normalized) {
724
+ const dataType = normalized ? dataTypeDecoder.getNormalizedDataType(signedDataType) : signedDataType;
725
+ switch (dataType) {
726
+ case "unorm8":
727
+ if (components === 1) {
728
+ return "unorm8";
729
+ }
730
+ if (components === 3) {
731
+ return "unorm8x3-webgl";
732
+ }
733
+ return `${dataType}x${components}`;
734
+ case "snorm8":
735
+ case "uint8":
736
+ case "sint8":
737
+ case "uint16":
738
+ case "sint16":
739
+ case "unorm16":
740
+ case "snorm16":
741
+ case "float16":
742
+ if (components === 1 || components === 3) {
743
+ throw new Error(`size: ${components}`);
744
+ }
745
+ return `${dataType}x${components}`;
746
+ default:
747
+ return components === 1 ? dataType : `${dataType}x${components}`;
748
+ }
438
749
  }
439
- const components = size;
440
- const signedDataType = getDataType(typedArray);
441
- return makeVertexFormat(signedDataType, components, normalized);
442
- }
443
- function getCompatibleVertexFormat(opts) {
444
- let vertexType;
445
- switch (opts.primitiveType) {
446
- case "f32":
447
- vertexType = "float32";
448
- break;
449
- case "i32":
450
- vertexType = "sint32";
451
- break;
452
- case "u32":
453
- vertexType = "uint32";
454
- break;
455
- case "f16":
456
- return opts.components <= 2 ? "float16x2" : "float16x4";
750
+ /** Get the vertex format for an attribute with TypedArray and size */
751
+ getVertexFormatFromAttribute(typedArray, size, normalized) {
752
+ if (!size || size > 4) {
753
+ throw new Error(`size ${size}`);
754
+ }
755
+ const components = size;
756
+ const signedDataType = dataTypeDecoder.getDataType(typedArray);
757
+ return this.makeVertexFormat(signedDataType, components, normalized);
457
758
  }
458
- if (opts.components === 1) {
459
- return vertexType;
759
+ /**
760
+ * Return a "default" vertex format for a certain shader data type
761
+ * The simplest vertex format that matches the shader attribute's data type
762
+ */
763
+ getCompatibleVertexFormat(opts) {
764
+ let vertexType;
765
+ switch (opts.primitiveType) {
766
+ case "f32":
767
+ vertexType = "float32";
768
+ break;
769
+ case "i32":
770
+ vertexType = "sint32";
771
+ break;
772
+ case "u32":
773
+ vertexType = "uint32";
774
+ break;
775
+ case "f16":
776
+ return opts.components <= 2 ? "float16x2" : "float16x4";
777
+ }
778
+ if (opts.components === 1) {
779
+ return vertexType;
780
+ }
781
+ return `${vertexType}x${opts.components}`;
460
782
  }
461
- return `${vertexType}x${opts.components}`;
462
- }
783
+ };
784
+ var vertexFormatDecoder = new VertexFormatDecoder();
463
785
 
464
- // dist/shadertypes/textures/texture-format-table.js
786
+ // dist/shadertypes/texture-types/texture-format-table.js
465
787
  var texture_compression_bc = "texture-compression-bc";
466
788
  var texture_compression_astc = "texture-compression-astc";
467
789
  var texture_compression_etc2 = "texture-compression-etc2";
@@ -472,6 +794,7 @@ var float32_renderable = "float32-renderable-webgl";
472
794
  var float16_renderable = "float16-renderable-webgl";
473
795
  var rgb9e5ufloat_renderable = "rgb9e5ufloat-renderable-webgl";
474
796
  var snorm8_renderable = "snorm8-renderable-webgl";
797
+ var norm16_webgl = "norm16-webgl";
475
798
  var norm16_renderable = "norm16-renderable-webgl";
476
799
  var snorm16_renderable = "snorm16-renderable-webgl";
477
800
  var float32_filterable = "float32-filterable";
@@ -505,16 +828,16 @@ var TEXTURE_FORMAT_COLOR_DEPTH_TABLE = {
505
828
  "rgba8sint": {},
506
829
  "bgra8unorm": {},
507
830
  "bgra8unorm-srgb": {},
508
- "r16unorm": { f: norm16_renderable },
509
- "rg16unorm": { render: norm16_renderable },
510
- "rgb16unorm-webgl": { f: norm16_renderable },
831
+ "r16unorm": { f: norm16_webgl, render: norm16_renderable },
832
+ "rg16unorm": { f: norm16_webgl, render: norm16_renderable },
833
+ "rgb16unorm-webgl": { f: norm16_webgl, render: false },
511
834
  // rgb not renderable
512
- "rgba16unorm": { render: norm16_renderable },
513
- "r16snorm": { f: snorm16_renderable },
514
- "rg16snorm": { render: snorm16_renderable },
515
- "rgb16snorm-webgl": { f: norm16_renderable },
835
+ "rgba16unorm": { f: norm16_webgl, render: norm16_renderable },
836
+ "r16snorm": { f: norm16_webgl, render: snorm16_renderable },
837
+ "rg16snorm": { f: norm16_webgl, render: snorm16_renderable },
838
+ "rgb16snorm-webgl": { f: norm16_webgl, render: false },
516
839
  // rgb not renderable
517
- "rgba16snorm": { render: snorm16_renderable },
840
+ "rgba16snorm": { f: norm16_webgl, render: snorm16_renderable },
518
841
  "r16uint": {},
519
842
  "rg16uint": {},
520
843
  "rgba16uint": {},
@@ -617,7 +940,7 @@ var TEXTURE_FORMAT_COMPRESSED_TABLE = {
617
940
  // WEBGL_compressed_texture_pvrtc
618
941
  "pvrtc-rgb4unorm-webgl": { f: texture_compression_pvrtc_webgl },
619
942
  "pvrtc-rgba4unorm-webgl": { f: texture_compression_pvrtc_webgl },
620
- "pvrtc-rbg2unorm-webgl": { f: texture_compression_pvrtc_webgl },
943
+ "pvrtc-rgb2unorm-webgl": { f: texture_compression_pvrtc_webgl },
621
944
  "pvrtc-rgba2unorm-webgl": { f: texture_compression_pvrtc_webgl },
622
945
  // WEBGL_compressed_texture_etc1
623
946
  "etc1-rbg-unorm-webgl": { f: texture_compression_etc1_webgl },
@@ -631,7 +954,10 @@ var TEXTURE_FORMAT_TABLE = {
631
954
  ...TEXTURE_FORMAT_COMPRESSED_TABLE
632
955
  };
633
956
 
634
- // dist/shadertypes/textures/texture-format-decoder.js
957
+ // dist/shadertypes/texture-types/texture-format-decoder.js
958
+ var RGB_FORMAT_REGEX = /^(r|rg|rgb|rgba|bgra)([0-9]*)([a-z]*)(-srgb)?(-webgl)?$/;
959
+ var COLOR_FORMAT_PREFIXES = ["rgb", "rgba", "bgra"];
960
+ var DEPTH_FORMAT_PREFIXES = ["depth", "stencil"];
635
961
  var COMPRESSED_TEXTURE_FORMAT_PREFIXES = [
636
962
  "bc1",
637
963
  "bc2",
@@ -647,49 +973,71 @@ var COMPRESSED_TEXTURE_FORMAT_PREFIXES = [
647
973
  "astc",
648
974
  "pvrtc"
649
975
  ];
650
- var RGB_FORMAT_REGEX = /^(r|rg|rgb|rgba|bgra)([0-9]*)([a-z]*)(-srgb)?(-webgl)?$/;
651
976
  var TextureFormatDecoder = class {
652
- /** Returns information about a texture format, e.g. attatchment type, components, byte length and flags (integer, signed, normalized) */
653
- getInfo(format) {
654
- return getTextureFormatInfo(format);
655
- }
656
977
  /** Checks if a texture format is color */
657
978
  isColor(format) {
658
- return format.startsWith("rgba") || format.startsWith("bgra") || format.startsWith("rgb");
979
+ return COLOR_FORMAT_PREFIXES.some((prefix) => format.startsWith(prefix));
659
980
  }
660
981
  /** Checks if a texture format is depth or stencil */
661
982
  isDepthStencil(format) {
662
- return format.startsWith("depth") || format.startsWith("stencil");
983
+ return DEPTH_FORMAT_PREFIXES.some((prefix) => format.startsWith(prefix));
663
984
  }
664
985
  /** Checks if a texture format is compressed */
665
986
  isCompressed(format) {
666
987
  return COMPRESSED_TEXTURE_FORMAT_PREFIXES.some((prefix) => format.startsWith(prefix));
667
988
  }
668
- /**
669
- * Returns the "static" capabilities of a texture format.
670
- * @note Needs to be checked against current device
671
- */
989
+ /** Returns information about a texture format, e.g. attachment type, components, byte length and flags (integer, signed, normalized) */
990
+ getInfo(format) {
991
+ return getTextureFormatInfo(format);
992
+ }
993
+ /** "static" capabilities of a texture format. @note Needs to be adjusted against current device */
672
994
  getCapabilities(format) {
673
- const info = getTextureFormatDefinition(format);
674
- const formatCapabilities = {
675
- format,
676
- create: info.f ?? true,
677
- render: info.render ?? true,
678
- filter: info.filter ?? true,
679
- blend: info.blend ?? true,
680
- store: info.store ?? true
681
- };
682
- const formatInfo = getTextureFormatInfo(format);
683
- const isDepthStencil = format.startsWith("depth") || format.startsWith("stencil");
684
- const isSigned = formatInfo == null ? void 0 : formatInfo.signed;
685
- const isInteger = formatInfo == null ? void 0 : formatInfo.integer;
686
- const isWebGLSpecific = formatInfo == null ? void 0 : formatInfo.webgl;
687
- formatCapabilities.render &&= !isSigned;
688
- formatCapabilities.filter &&= !isDepthStencil && !isSigned && !isInteger && !isWebGLSpecific;
689
- return formatCapabilities;
995
+ return getTextureFormatCapabilities(format);
996
+ }
997
+ /** Computes the memory layout for a texture, in particular including row byte alignment */
998
+ computeMemoryLayout(opts) {
999
+ return computeTextureMemoryLayout(opts);
690
1000
  }
691
1001
  };
692
1002
  var textureFormatDecoder = new TextureFormatDecoder();
1003
+ function computeTextureMemoryLayout({ format, width, height, depth, byteAlignment }) {
1004
+ const formatInfo = textureFormatDecoder.getInfo(format);
1005
+ const { bytesPerPixel, bytesPerBlock = bytesPerPixel, blockWidth = 1, blockHeight = 1, compressed = false } = formatInfo;
1006
+ const blockColumns = compressed ? Math.ceil(width / blockWidth) : width;
1007
+ const blockRows = compressed ? Math.ceil(height / blockHeight) : height;
1008
+ const unpaddedBytesPerRow = blockColumns * bytesPerBlock;
1009
+ const bytesPerRow = Math.ceil(unpaddedBytesPerRow / byteAlignment) * byteAlignment;
1010
+ const rowsPerImage = blockRows;
1011
+ const byteLength = bytesPerRow * rowsPerImage * depth;
1012
+ return {
1013
+ bytesPerPixel,
1014
+ bytesPerRow,
1015
+ rowsPerImage,
1016
+ depthOrArrayLayers: depth,
1017
+ bytesPerImage: bytesPerRow * rowsPerImage,
1018
+ byteLength
1019
+ };
1020
+ }
1021
+ function getTextureFormatCapabilities(format) {
1022
+ const info = getTextureFormatDefinition(format);
1023
+ const formatCapabilities = {
1024
+ format,
1025
+ create: info.f ?? true,
1026
+ render: info.render ?? true,
1027
+ filter: info.filter ?? true,
1028
+ blend: info.blend ?? true,
1029
+ store: info.store ?? true
1030
+ };
1031
+ const formatInfo = getTextureFormatInfo(format);
1032
+ const isDepthStencil = format.startsWith("depth") || format.startsWith("stencil");
1033
+ const isSigned = formatInfo == null ? void 0 : formatInfo.signed;
1034
+ const isInteger = formatInfo == null ? void 0 : formatInfo.integer;
1035
+ const isWebGLSpecific = formatInfo == null ? void 0 : formatInfo.webgl;
1036
+ const isCompressed = Boolean(formatInfo == null ? void 0 : formatInfo.compressed);
1037
+ formatCapabilities.render &&= !isDepthStencil && !isCompressed;
1038
+ formatCapabilities.filter &&= !isDepthStencil && !isSigned && !isInteger && !isWebGLSpecific;
1039
+ return formatCapabilities;
1040
+ }
693
1041
  function getTextureFormatInfo(format) {
694
1042
  let formatInfo = getTextureFormatInfoUsingTable(format);
695
1043
  if (textureFormatDecoder.isCompressed(format)) {
@@ -698,19 +1046,20 @@ function getTextureFormatInfo(format) {
698
1046
  formatInfo.bytesPerPixel = 1;
699
1047
  formatInfo.srgb = false;
700
1048
  formatInfo.compressed = true;
1049
+ formatInfo.bytesPerBlock = getCompressedTextureBlockByteLength(format);
701
1050
  const blockSize = getCompressedTextureBlockSize(format);
702
1051
  if (blockSize) {
703
1052
  formatInfo.blockWidth = blockSize.blockWidth;
704
1053
  formatInfo.blockHeight = blockSize.blockHeight;
705
1054
  }
706
1055
  }
707
- const matches = RGB_FORMAT_REGEX.exec(format);
1056
+ const matches = !formatInfo.packed ? RGB_FORMAT_REGEX.exec(format) : null;
708
1057
  if (matches) {
709
1058
  const [, channels, length, type, srgb, suffix] = matches;
710
1059
  const dataType = `${type}${length}`;
711
- const decodedType = getDataTypeInfo(dataType);
1060
+ const decodedType = dataTypeDecoder.getDataTypeInfo(dataType);
712
1061
  const bits = decodedType.byteLength * 8;
713
- const components = channels.length;
1062
+ const components = (channels == null ? void 0 : channels.length) ?? 1;
714
1063
  const bitsPerChannel = [
715
1064
  bits,
716
1065
  components >= 2 ? bits : 0,
@@ -727,7 +1076,7 @@ function getTextureFormatInfo(format) {
727
1076
  signed: decodedType.signed,
728
1077
  normalized: decodedType.normalized,
729
1078
  bitsPerChannel,
730
- bytesPerPixel: decodedType.byteLength * channels.length,
1079
+ bytesPerPixel: decodedType.byteLength * components,
731
1080
  packed: formatInfo.packed,
732
1081
  srgb: formatInfo.srgb
733
1082
  };
@@ -784,10 +1133,31 @@ function getCompressedTextureBlockSize(format) {
784
1133
  const [, blockWidth, blockHeight] = matches;
785
1134
  return { blockWidth: Number(blockWidth), blockHeight: Number(blockHeight) };
786
1135
  }
1136
+ if (format.startsWith("bc") || format.startsWith("etc1") || format.startsWith("etc2") || format.startsWith("eac") || format.startsWith("atc")) {
1137
+ return { blockWidth: 4, blockHeight: 4 };
1138
+ }
1139
+ if (format.startsWith("pvrtc-rgb4") || format.startsWith("pvrtc-rgba4")) {
1140
+ return { blockWidth: 4, blockHeight: 4 };
1141
+ }
1142
+ if (format.startsWith("pvrtc-rgb2") || format.startsWith("pvrtc-rgba2")) {
1143
+ return { blockWidth: 8, blockHeight: 4 };
1144
+ }
787
1145
  return null;
788
1146
  }
1147
+ function getCompressedTextureBlockByteLength(format) {
1148
+ 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") {
1149
+ return 8;
1150
+ }
1151
+ 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") {
1152
+ return 16;
1153
+ }
1154
+ if (format.startsWith("pvrtc")) {
1155
+ return 8;
1156
+ }
1157
+ return 16;
1158
+ }
789
1159
 
790
- // dist/image-utils/image-types.js
1160
+ // dist/shadertypes/image-types/image-types.js
791
1161
  function isExternalImage(data) {
792
1162
  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;
793
1163
  }
@@ -810,6 +1180,53 @@ function getExternalImageSize(data) {
810
1180
  // dist/adapter/device.js
811
1181
  var DeviceLimits = class {
812
1182
  };
1183
+ function formatErrorLogArguments(context, args) {
1184
+ const formattedContext = formatErrorLogValue(context);
1185
+ const formattedArgs = args.map(formatErrorLogValue).filter((arg) => arg !== void 0);
1186
+ return [formattedContext, ...formattedArgs].filter((arg) => arg !== void 0);
1187
+ }
1188
+ function formatErrorLogValue(value) {
1189
+ var _a;
1190
+ if (value === void 0) {
1191
+ return void 0;
1192
+ }
1193
+ if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
1194
+ return value;
1195
+ }
1196
+ if (value instanceof Error) {
1197
+ return value.message;
1198
+ }
1199
+ if (Array.isArray(value)) {
1200
+ return value.map(formatErrorLogValue);
1201
+ }
1202
+ if (typeof value === "object") {
1203
+ if (hasCustomToString(value)) {
1204
+ const stringValue = String(value);
1205
+ if (stringValue !== "[object Object]") {
1206
+ return stringValue;
1207
+ }
1208
+ }
1209
+ if (looksLikeGPUCompilationMessage(value)) {
1210
+ return formatGPUCompilationMessage(value);
1211
+ }
1212
+ return ((_a = value.constructor) == null ? void 0 : _a.name) || "Object";
1213
+ }
1214
+ return String(value);
1215
+ }
1216
+ function hasCustomToString(value) {
1217
+ return "toString" in value && typeof value.toString === "function" && value.toString !== Object.prototype.toString;
1218
+ }
1219
+ function looksLikeGPUCompilationMessage(value) {
1220
+ return "message" in value && "type" in value;
1221
+ }
1222
+ function formatGPUCompilationMessage(value) {
1223
+ const type = typeof value.type === "string" ? value.type : "message";
1224
+ const message = typeof value.message === "string" ? value.message : "";
1225
+ const lineNum = typeof value.lineNum === "number" ? value.lineNum : null;
1226
+ const linePos = typeof value.linePos === "number" ? value.linePos : null;
1227
+ const location = lineNum !== null && linePos !== null ? ` @ ${lineNum}:${linePos}` : lineNum !== null ? ` @ ${lineNum}` : "";
1228
+ return `${type}${location}: ${message}`.trim();
1229
+ }
813
1230
  var DeviceFeatures = class {
814
1231
  features;
815
1232
  disabledFeatures;
@@ -840,19 +1257,24 @@ var _Device = class {
840
1257
  userData = {};
841
1258
  /** stats */
842
1259
  statsManager = lumaStats;
1260
+ /** Internal per-device factory storage */
1261
+ _factories = {};
843
1262
  /** An abstract timestamp used for change tracking */
844
1263
  timestamp = 0;
845
1264
  /** True if this device has been reused during device creation (app has multiple references) */
846
1265
  _reused = false;
847
1266
  /** Used by other luma.gl modules to store data on the device */
848
- _lumaData = {};
1267
+ _moduleData = {};
849
1268
  _textureCaps = {};
1269
+ /** Internal timestamp query set used when GPU timing collection is enabled for this device. */
1270
+ _debugGPUTimeQuery = null;
850
1271
  constructor(props) {
851
1272
  this.props = { ..._Device.defaultProps, ...props };
852
1273
  this.id = this.props.id || uid(this[Symbol.toStringTag].toLowerCase());
853
1274
  }
1275
+ // TODO - just expose the shadertypes decoders?
854
1276
  getVertexFormatInfo(format) {
855
- return getVertexFormatInfo(format);
1277
+ return vertexFormatDecoder.getVertexFormatInfo(format);
856
1278
  }
857
1279
  isVertexFormatSupported(format) {
858
1280
  return true;
@@ -900,6 +1322,16 @@ var _Device = class {
900
1322
  isTextureFormatCompressed(format) {
901
1323
  return textureFormatDecoder.isCompressed(format);
902
1324
  }
1325
+ /** Returns the compressed texture formats that can be created and sampled on this device */
1326
+ getSupportedCompressedTextureFormats() {
1327
+ const supportedFormats = [];
1328
+ for (const format of Object.keys(getTextureFormatTable())) {
1329
+ if (this.isTextureFormatCompressed(format) && this.isTextureFormatSupported(format)) {
1330
+ supportedFormats.push(format);
1331
+ }
1332
+ }
1333
+ return supportedFormats;
1334
+ }
903
1335
  // DEBUG METHODS
904
1336
  pushDebugGroup(groupLabel) {
905
1337
  this.commandEncoder.pushDebugGroup(groupLabel);
@@ -944,7 +1376,8 @@ var _Device = class {
944
1376
  reportError(error, context, ...args) {
945
1377
  const isHandled = this.props.onError(error, context);
946
1378
  if (!isHandled) {
947
- return log.error(error.message, context, ...args);
1379
+ const logArguments = formatErrorLogArguments(context, args);
1380
+ return log.error(this.type === "webgl" ? "%cWebGL" : "%cWebGPU", "color: white; background: red; padding: 2px 6px; border-radius: 3px;", error.message, ...logArguments);
948
1381
  }
949
1382
  return () => {
950
1383
  };
@@ -966,6 +1399,10 @@ or create a device with the 'debug: true' prop.`;
966
1399
  }
967
1400
  return this.canvasContext;
968
1401
  }
1402
+ /** Create a fence sync object */
1403
+ createFence() {
1404
+ throw new Error("createFence() not implemented");
1405
+ }
969
1406
  /** Create a RenderPass using the default CommandEncoder */
970
1407
  beginRenderPass(props) {
971
1408
  return this.commandEncoder.beginRenderPass(props);
@@ -974,6 +1411,78 @@ or create a device with the 'debug: true' prop.`;
974
1411
  beginComputePass(props) {
975
1412
  return this.commandEncoder.beginComputePass(props);
976
1413
  }
1414
+ /**
1415
+ * Generate mipmaps for a WebGPU texture.
1416
+ * WebGPU textures must be created up front with the required mip count, usage flags, and a format that supports the chosen generation path.
1417
+ * WebGL uses `Texture.generateMipmapsWebGL()` directly because the backend manages mip generation on the texture object itself.
1418
+ */
1419
+ generateMipmapsWebGPU(_texture) {
1420
+ throw new Error("not implemented");
1421
+ }
1422
+ /** Internal helper for creating a shareable WebGL render-pipeline implementation. */
1423
+ _createSharedRenderPipelineWebGL(_props) {
1424
+ throw new Error("_createSharedRenderPipelineWebGL() not implemented");
1425
+ }
1426
+ /** Internal WebGPU-only helper for retrieving the native bind-group layout for a pipeline group. */
1427
+ _createBindGroupLayoutWebGPU(_pipeline, _group) {
1428
+ throw new Error("_createBindGroupLayoutWebGPU() not implemented");
1429
+ }
1430
+ /** Internal WebGPU-only helper for creating a native bind group. */
1431
+ _createBindGroupWebGPU(_bindGroupLayout, _shaderLayout, _bindings, _group) {
1432
+ throw new Error("_createBindGroupWebGPU() not implemented");
1433
+ }
1434
+ /**
1435
+ * Internal helper that returns `true` when timestamp-query GPU timing should be
1436
+ * collected for this device.
1437
+ */
1438
+ _supportsDebugGPUTime() {
1439
+ return this.features.has("timestamp-query") && Boolean(this.props.debug || this.props.debugGPUTime);
1440
+ }
1441
+ /**
1442
+ * Internal helper that enables device-managed GPU timing collection on the
1443
+ * default command encoder. Reuses the existing query set if timing is already enabled.
1444
+ *
1445
+ * @param queryCount - Number of timestamp slots reserved for profiled passes.
1446
+ * @returns The device-managed timestamp QuerySet, or `null` when timing is not supported or could not be enabled.
1447
+ */
1448
+ _enableDebugGPUTime(queryCount = 256) {
1449
+ if (!this._supportsDebugGPUTime()) {
1450
+ return null;
1451
+ }
1452
+ if (this._debugGPUTimeQuery) {
1453
+ return this._debugGPUTimeQuery;
1454
+ }
1455
+ try {
1456
+ this._debugGPUTimeQuery = this.createQuerySet({ type: "timestamp", count: queryCount });
1457
+ this.commandEncoder = this.createCommandEncoder({
1458
+ id: this.commandEncoder.props.id,
1459
+ timeProfilingQuerySet: this._debugGPUTimeQuery
1460
+ });
1461
+ } catch {
1462
+ this._debugGPUTimeQuery = null;
1463
+ }
1464
+ return this._debugGPUTimeQuery;
1465
+ }
1466
+ /**
1467
+ * Internal helper that disables device-managed GPU timing collection and restores
1468
+ * the default command encoder to an unprofiled state.
1469
+ */
1470
+ _disableDebugGPUTime() {
1471
+ if (!this._debugGPUTimeQuery) {
1472
+ return;
1473
+ }
1474
+ if (this.commandEncoder.getTimeProfilingQuerySet() === this._debugGPUTimeQuery) {
1475
+ this.commandEncoder = this.createCommandEncoder({
1476
+ id: this.commandEncoder.props.id
1477
+ });
1478
+ }
1479
+ this._debugGPUTimeQuery.destroy();
1480
+ this._debugGPUTimeQuery = null;
1481
+ }
1482
+ /** Internal helper that returns `true` when device-managed GPU timing is currently active. */
1483
+ _isDebugGPUTimeEnabled() {
1484
+ return this._debugGPUTimeQuery !== null;
1485
+ }
977
1486
  // DEPRECATED METHODS
978
1487
  /** @deprecated Use getDefaultCanvasContext() */
979
1488
  getCanvasContext() {
@@ -1009,6 +1518,12 @@ or create a device with the 'debug: true' prop.`;
1009
1518
  resetWebGL() {
1010
1519
  throw new Error("not implemented");
1011
1520
  }
1521
+ // INTERNAL LUMA.GL METHODS
1522
+ getModuleData(moduleName) {
1523
+ this._moduleData[moduleName] ||= {};
1524
+ return this._moduleData[moduleName];
1525
+ }
1526
+ // INTERNAL HELPERS
1012
1527
  // IMPLEMENTATION
1013
1528
  /** Helper to get the canvas context props */
1014
1529
  static _getCanvasContextProps(props) {
@@ -1075,7 +1590,8 @@ __publicField(Device, "defaultProps", {
1075
1590
  onVisibilityChange: (context) => log.log(1, `${context} Visibility changed ${context.isVisible}`)(),
1076
1591
  onDevicePixelRatioChange: (context, info) => log.log(1, `${context} DPR changed ${info.oldRatio} => ${context.devicePixelRatio}`)(),
1077
1592
  // Debug flags
1078
- debug: log.get("debug") || void 0,
1593
+ debug: getDefaultDebugValue(),
1594
+ debugGPUTime: false,
1079
1595
  debugShaders: log.get("debug-shaders") || void 0,
1080
1596
  debugFramebuffers: Boolean(log.get("debug-framebuffers")),
1081
1597
  debugFactories: Boolean(log.get("debug-factories")),
@@ -1086,9 +1602,11 @@ __publicField(Device, "defaultProps", {
1086
1602
  // Experimental
1087
1603
  _reuseDevices: false,
1088
1604
  _requestMaxLimits: true,
1089
- _cacheShaders: false,
1090
- _cachePipelines: false,
1091
- _cacheDestroyPolicy: "unused",
1605
+ _cacheShaders: true,
1606
+ _destroyShaders: false,
1607
+ _cachePipelines: true,
1608
+ _sharePipelines: true,
1609
+ _destroyPipelines: false,
1092
1610
  // TODO - Change these after confirming things work as expected
1093
1611
  _initializeFeatures: true,
1094
1612
  _disabledFeatures: {
@@ -1097,6 +1615,25 @@ __publicField(Device, "defaultProps", {
1097
1615
  // INTERNAL
1098
1616
  _handle: void 0
1099
1617
  });
1618
+ function _getDefaultDebugValue(logDebugValue, nodeEnv) {
1619
+ if (logDebugValue !== void 0 && logDebugValue !== null) {
1620
+ return Boolean(logDebugValue);
1621
+ }
1622
+ if (nodeEnv !== void 0) {
1623
+ return nodeEnv !== "production";
1624
+ }
1625
+ return false;
1626
+ }
1627
+ function getDefaultDebugValue() {
1628
+ return _getDefaultDebugValue(log.get("debug"), getNodeEnv());
1629
+ }
1630
+ function getNodeEnv() {
1631
+ const processObject = globalThis.process;
1632
+ if (!(processObject == null ? void 0 : processObject.env)) {
1633
+ return void 0;
1634
+ }
1635
+ return processObject.env["NODE_ENV"];
1636
+ }
1100
1637
 
1101
1638
  // dist/adapter/luma.js
1102
1639
  var STARTUP_MESSAGE = "set luma.log.level=1 (or higher) to trace rendering";
@@ -1116,7 +1653,7 @@ var _Luma = class {
1116
1653
  VERSION = (
1117
1654
  // Version detection using build plugin
1118
1655
  // @ts-expect-error no-undef
1119
- true ? "9.2.6" : "running from source"
1656
+ true ? "9.3.0-alpha.10" : "running from source"
1120
1657
  );
1121
1658
  spector;
1122
1659
  preregisteredAdapters = /* @__PURE__ */ new Map();
@@ -1281,9 +1818,91 @@ function getPageLoadPromise() {
1281
1818
  return pageLoadPromise;
1282
1819
  }
1283
1820
 
1284
- // dist/adapter/canvas-context.js
1821
+ // dist/adapter/canvas-surface.js
1285
1822
  var import_env2 = require("@probe.gl/env");
1286
1823
 
1824
+ // dist/adapter/canvas-observer.js
1825
+ var CanvasObserver = class {
1826
+ props;
1827
+ _resizeObserver;
1828
+ _intersectionObserver;
1829
+ _observeDevicePixelRatioTimeout = null;
1830
+ _observeDevicePixelRatioMediaQuery = null;
1831
+ _handleDevicePixelRatioChange = () => this._refreshDevicePixelRatio();
1832
+ _trackPositionInterval = null;
1833
+ _started = false;
1834
+ get started() {
1835
+ return this._started;
1836
+ }
1837
+ constructor(props) {
1838
+ this.props = props;
1839
+ }
1840
+ start() {
1841
+ if (this._started || !this.props.canvas) {
1842
+ return;
1843
+ }
1844
+ this._started = true;
1845
+ this._intersectionObserver ||= new IntersectionObserver((entries) => this.props.onIntersection(entries));
1846
+ this._resizeObserver ||= new ResizeObserver((entries) => this.props.onResize(entries));
1847
+ this._intersectionObserver.observe(this.props.canvas);
1848
+ try {
1849
+ this._resizeObserver.observe(this.props.canvas, { box: "device-pixel-content-box" });
1850
+ } catch {
1851
+ this._resizeObserver.observe(this.props.canvas, { box: "content-box" });
1852
+ }
1853
+ this._observeDevicePixelRatioTimeout = setTimeout(() => this._refreshDevicePixelRatio(), 0);
1854
+ if (this.props.trackPosition) {
1855
+ this._trackPosition();
1856
+ }
1857
+ }
1858
+ stop() {
1859
+ var _a, _b;
1860
+ if (!this._started) {
1861
+ return;
1862
+ }
1863
+ this._started = false;
1864
+ if (this._observeDevicePixelRatioTimeout) {
1865
+ clearTimeout(this._observeDevicePixelRatioTimeout);
1866
+ this._observeDevicePixelRatioTimeout = null;
1867
+ }
1868
+ if (this._observeDevicePixelRatioMediaQuery) {
1869
+ this._observeDevicePixelRatioMediaQuery.removeEventListener("change", this._handleDevicePixelRatioChange);
1870
+ this._observeDevicePixelRatioMediaQuery = null;
1871
+ }
1872
+ if (this._trackPositionInterval) {
1873
+ clearInterval(this._trackPositionInterval);
1874
+ this._trackPositionInterval = null;
1875
+ }
1876
+ (_a = this._resizeObserver) == null ? void 0 : _a.disconnect();
1877
+ (_b = this._intersectionObserver) == null ? void 0 : _b.disconnect();
1878
+ }
1879
+ _refreshDevicePixelRatio() {
1880
+ var _a;
1881
+ if (!this._started) {
1882
+ return;
1883
+ }
1884
+ this.props.onDevicePixelRatioChange();
1885
+ (_a = this._observeDevicePixelRatioMediaQuery) == null ? void 0 : _a.removeEventListener("change", this._handleDevicePixelRatioChange);
1886
+ this._observeDevicePixelRatioMediaQuery = matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`);
1887
+ this._observeDevicePixelRatioMediaQuery.addEventListener("change", this._handleDevicePixelRatioChange, { once: true });
1888
+ }
1889
+ _trackPosition(intervalMs = 100) {
1890
+ if (this._trackPositionInterval) {
1891
+ return;
1892
+ }
1893
+ this._trackPositionInterval = setInterval(() => {
1894
+ if (!this._started) {
1895
+ if (this._trackPositionInterval) {
1896
+ clearInterval(this._trackPositionInterval);
1897
+ this._trackPositionInterval = null;
1898
+ }
1899
+ } else {
1900
+ this.props.onPositionChange();
1901
+ }
1902
+ }, intervalMs);
1903
+ }
1904
+ };
1905
+
1287
1906
  // dist/utils/promise-utils.js
1288
1907
  function withResolvers() {
1289
1908
  let resolve;
@@ -1295,8 +1914,22 @@ function withResolvers() {
1295
1914
  return { promise, resolve, reject };
1296
1915
  }
1297
1916
 
1298
- // dist/adapter/canvas-context.js
1299
- var _CanvasContext = class {
1917
+ // dist/utils/assert.js
1918
+ function assert(condition, message) {
1919
+ var _a;
1920
+ if (!condition) {
1921
+ const error = new Error(message ?? "luma.gl assertion failed.");
1922
+ (_a = Error.captureStackTrace) == null ? void 0 : _a.call(Error, error, assert);
1923
+ throw error;
1924
+ }
1925
+ }
1926
+ function assertDefined(value, message) {
1927
+ assert(value, message);
1928
+ return value;
1929
+ }
1930
+
1931
+ // dist/adapter/canvas-surface.js
1932
+ var _CanvasSurface = class {
1300
1933
  static isHTMLCanvas(canvas) {
1301
1934
  return typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement;
1302
1935
  }
@@ -1330,17 +1963,21 @@ var _CanvasContext = class {
1330
1963
  drawingBufferWidth;
1331
1964
  /** Height of drawing buffer: automatically tracks this.pixelHeight if props.autoResize is true */
1332
1965
  drawingBufferHeight;
1966
+ /** Resolves when the canvas is initialized, i.e. when the ResizeObserver has updated the pixel size */
1333
1967
  _initializedResolvers = withResolvers();
1334
- _resizeObserver;
1335
- _intersectionObserver;
1336
- _position;
1968
+ _canvasObserver;
1969
+ /** Position of the canvas in the document, updated by a timer */
1970
+ _position = [0, 0];
1971
+ /** Whether this canvas context has been destroyed */
1337
1972
  destroyed = false;
1973
+ /** Whether the drawing buffer size needs to be resized (deferred resizing to avoid flicker) */
1974
+ _needsDrawingBufferResize = true;
1338
1975
  toString() {
1339
1976
  return `${this[Symbol.toStringTag]}(${this.id})`;
1340
1977
  }
1341
1978
  constructor(props) {
1342
1979
  var _a, _b;
1343
- this.props = { ..._CanvasContext.defaultProps, ...props };
1980
+ this.props = { ..._CanvasSurface.defaultProps, ...props };
1344
1981
  props = this.props;
1345
1982
  this.initialized = this._initializedResolvers.promise;
1346
1983
  if (!(0, import_env2.isBrowser)()) {
@@ -1352,11 +1989,11 @@ var _CanvasContext = class {
1352
1989
  } else {
1353
1990
  this.canvas = props.canvas;
1354
1991
  }
1355
- if (_CanvasContext.isHTMLCanvas(this.canvas)) {
1992
+ if (_CanvasSurface.isHTMLCanvas(this.canvas)) {
1356
1993
  this.id = props.id || this.canvas.id;
1357
1994
  this.type = "html-canvas";
1358
1995
  this.htmlCanvas = this.canvas;
1359
- } else if (_CanvasContext.isOffscreenCanvas(this.canvas)) {
1996
+ } else if (_CanvasSurface.isOffscreenCanvas(this.canvas)) {
1360
1997
  this.id = props.id || "offscreen-canvas";
1361
1998
  this.type = "offscreen-canvas";
1362
1999
  this.offscreenCanvas = this.canvas;
@@ -1372,23 +2009,21 @@ var _CanvasContext = class {
1372
2009
  this.drawingBufferHeight = this.canvas.height;
1373
2010
  this.devicePixelRatio = globalThis.devicePixelRatio || 1;
1374
2011
  this._position = [0, 0];
1375
- if (_CanvasContext.isHTMLCanvas(this.canvas)) {
1376
- this._intersectionObserver = new IntersectionObserver((entries) => this._handleIntersection(entries));
1377
- this._intersectionObserver.observe(this.canvas);
1378
- this._resizeObserver = new ResizeObserver((entries) => this._handleResize(entries));
1379
- try {
1380
- this._resizeObserver.observe(this.canvas, { box: "device-pixel-content-box" });
1381
- } catch {
1382
- this._resizeObserver.observe(this.canvas, { box: "content-box" });
1383
- }
1384
- setTimeout(() => this._observeDevicePixelRatio(), 0);
1385
- if (this.props.trackPosition) {
1386
- this._trackPosition();
1387
- }
1388
- }
2012
+ this._canvasObserver = new CanvasObserver({
2013
+ canvas: this.htmlCanvas,
2014
+ trackPosition: this.props.trackPosition,
2015
+ onResize: (entries) => this._handleResize(entries),
2016
+ onIntersection: (entries) => this._handleIntersection(entries),
2017
+ onDevicePixelRatioChange: () => this._observeDevicePixelRatio(),
2018
+ onPositionChange: () => this.updatePosition()
2019
+ });
1389
2020
  }
1390
2021
  destroy() {
1391
- this.destroyed = true;
2022
+ if (!this.destroyed) {
2023
+ this.destroyed = true;
2024
+ this._stopObservers();
2025
+ this.device = null;
2026
+ }
1392
2027
  }
1393
2028
  setProps(props) {
1394
2029
  if ("useDevicePixels" in props) {
@@ -1397,55 +2032,41 @@ var _CanvasContext = class {
1397
2032
  }
1398
2033
  return this;
1399
2034
  }
1400
- // SIZE METHODS
1401
- /**
1402
- * Returns the size covered by the canvas in CSS pixels
1403
- * @note This can be different from the actual device pixel size of a canvas due to DPR scaling, and rounding to integer pixels
1404
- * @note This is independent of the canvas' internal drawing buffer size (.width, .height).
1405
- */
2035
+ /** Returns a framebuffer with properly resized current 'swap chain' textures */
2036
+ getCurrentFramebuffer(options) {
2037
+ this._resizeDrawingBufferIfNeeded();
2038
+ return this._getCurrentFramebuffer(options);
2039
+ }
1406
2040
  getCSSSize() {
1407
2041
  return [this.cssWidth, this.cssHeight];
1408
2042
  }
1409
2043
  getPosition() {
1410
2044
  return this._position;
1411
2045
  }
1412
- /**
1413
- * Returns the size covered by the canvas in actual device pixels.
1414
- * @note This can be different from the 'CSS' size of a canvas due to DPR scaling, and rounding to integer pixels
1415
- * @note This is independent of the canvas' internal drawing buffer size (.width, .height).
1416
- */
1417
2046
  getDevicePixelSize() {
1418
2047
  return [this.devicePixelWidth, this.devicePixelHeight];
1419
2048
  }
1420
- /** Get the drawing buffer size (number of pixels GPU is rendering into, can be different from CSS size) */
1421
2049
  getDrawingBufferSize() {
1422
2050
  return [this.drawingBufferWidth, this.drawingBufferHeight];
1423
2051
  }
1424
- /** Returns the biggest allowed framebuffer size. @todo Allow the application to limit this? */
1425
2052
  getMaxDrawingBufferSize() {
1426
2053
  const maxTextureDimension = this.device.limits.maxTextureDimension2D;
1427
2054
  return [maxTextureDimension, maxTextureDimension];
1428
2055
  }
1429
- /** Update the canvas drawing buffer size. Called automatically if props.autoResize is true. */
1430
2056
  setDrawingBufferSize(width, height) {
1431
- this.canvas.width = width;
1432
- this.canvas.height = height;
2057
+ width = Math.floor(width);
2058
+ height = Math.floor(height);
2059
+ if (this.drawingBufferWidth === width && this.drawingBufferHeight === height) {
2060
+ return;
2061
+ }
1433
2062
  this.drawingBufferWidth = width;
1434
2063
  this.drawingBufferHeight = height;
2064
+ this._needsDrawingBufferResize = true;
1435
2065
  }
1436
- /**
1437
- * Returns the current DPR (number of physical pixels per CSS pixel), if props.useDevicePixels is true
1438
- * @note This can be a fractional (non-integer) number, e.g. when the user zooms in the browser.
1439
- * @note This function handles the non-HTML canvas cases
1440
- */
1441
2066
  getDevicePixelRatio() {
1442
- const dpr = typeof window !== "undefined" && window.devicePixelRatio;
1443
- return dpr || 1;
2067
+ const devicePixelRatio2 = typeof window !== "undefined" && window.devicePixelRatio;
2068
+ return devicePixelRatio2 || 1;
1444
2069
  }
1445
- // DEPRECATED METHODS
1446
- /**
1447
- * Maps CSS pixel position to device pixel position
1448
- */
1449
2070
  cssToDevicePixels(cssPixel, yInvert = true) {
1450
2071
  const ratio = this.cssToDeviceRatio();
1451
2072
  const [width, height] = this.getDrawingBufferSize();
@@ -1455,10 +2076,10 @@ var _CanvasContext = class {
1455
2076
  getPixelSize() {
1456
2077
  return this.getDevicePixelSize();
1457
2078
  }
1458
- /** @deprecated - TODO which values should we use for aspect */
2079
+ /** @deprecated Use the current drawing buffer size for projection setup. */
1459
2080
  getAspect() {
1460
- const [width, height] = this.getDevicePixelSize();
1461
- return width / height;
2081
+ const [width, height] = this.getDrawingBufferSize();
2082
+ return width > 0 && height > 0 ? width / height : 1;
1462
2083
  }
1463
2084
  /** @deprecated Returns multiplier need to convert CSS size to Device size */
1464
2085
  cssToDeviceRatio() {
@@ -1474,19 +2095,41 @@ var _CanvasContext = class {
1474
2095
  resize(size) {
1475
2096
  this.setDrawingBufferSize(size.width, size.height);
1476
2097
  }
1477
- // IMPLEMENTATION
1478
- /**
1479
- * Allows subclass constructor to override the canvas id for auto created canvases.
1480
- * This can really help when debugging DOM in apps that create multiple devices
1481
- */
1482
2098
  _setAutoCreatedCanvasId(id) {
1483
2099
  var _a;
1484
2100
  if (((_a = this.htmlCanvas) == null ? void 0 : _a.id) === "lumagl-auto-created-canvas") {
1485
2101
  this.htmlCanvas.id = id;
1486
2102
  }
1487
2103
  }
1488
- /** reacts to an observed intersection */
2104
+ /**
2105
+ * Starts DOM observation after the derived context and its device are fully initialized.
2106
+ *
2107
+ * `CanvasSurface` construction runs before subclasses can assign `this.device`, and the
2108
+ * default WebGL canvas context is created before `WebGLDevice` has initialized `limits`,
2109
+ * `features`, and the rest of its runtime state. Deferring observer startup avoids early
2110
+ * `ResizeObserver` and DPR callbacks running against a partially initialized device.
2111
+ */
2112
+ _startObservers() {
2113
+ if (this.destroyed) {
2114
+ return;
2115
+ }
2116
+ this._canvasObserver.start();
2117
+ }
2118
+ /**
2119
+ * Stops all DOM observation and timers associated with a canvas surface.
2120
+ *
2121
+ * This pairs with `_startObservers()` so teardown uses the same lifecycle whether a context is
2122
+ * explicitly destroyed, abandoned during device reuse, or temporarily has not started observing
2123
+ * yet. Centralizing shutdown here keeps resize/DPR/position watchers from surviving past the
2124
+ * lifetime of the owning device.
2125
+ */
2126
+ _stopObservers() {
2127
+ this._canvasObserver.stop();
2128
+ }
1489
2129
  _handleIntersection(entries) {
2130
+ if (this.destroyed) {
2131
+ return;
2132
+ }
1490
2133
  const entry = entries.find((entry_) => entry_.target === this.canvas);
1491
2134
  if (!entry) {
1492
2135
  return;
@@ -1497,22 +2140,21 @@ var _CanvasContext = class {
1497
2140
  this.device.props.onVisibilityChange(this);
1498
2141
  }
1499
2142
  }
1500
- /**
1501
- * Reacts to an observed resize by using the most accurate pixel size information the browser can provide
1502
- * @see https://web.dev/articles/device-pixel-content-box
1503
- * @see https://webgpufundamentals.org/webgpu/lessons/webgpu-resizing-the-canvas.html
1504
- */
1505
2143
  _handleResize(entries) {
1506
- var _a, _b;
2144
+ var _a, _b, _c, _d, _e;
2145
+ if (this.destroyed) {
2146
+ return;
2147
+ }
1507
2148
  const entry = entries.find((entry_) => entry_.target === this.canvas);
1508
2149
  if (!entry) {
1509
2150
  return;
1510
2151
  }
1511
- this.cssWidth = entry.contentBoxSize[0].inlineSize;
1512
- this.cssHeight = entry.contentBoxSize[0].blockSize;
2152
+ const contentBoxSize = assertDefined((_a = entry.contentBoxSize) == null ? void 0 : _a[0]);
2153
+ this.cssWidth = contentBoxSize.inlineSize;
2154
+ this.cssHeight = contentBoxSize.blockSize;
1513
2155
  const oldPixelSize = this.getDevicePixelSize();
1514
- const devicePixelWidth = ((_a = entry.devicePixelContentBoxSize) == null ? void 0 : _a[0].inlineSize) || entry.contentBoxSize[0].inlineSize * devicePixelRatio;
1515
- const devicePixelHeight = ((_b = entry.devicePixelContentBoxSize) == null ? void 0 : _b[0].blockSize) || entry.contentBoxSize[0].blockSize * devicePixelRatio;
2156
+ const devicePixelWidth = ((_c = (_b = entry.devicePixelContentBoxSize) == null ? void 0 : _b[0]) == null ? void 0 : _c.inlineSize) || contentBoxSize.inlineSize * devicePixelRatio;
2157
+ const devicePixelHeight = ((_e = (_d = entry.devicePixelContentBoxSize) == null ? void 0 : _d[0]) == null ? void 0 : _e.blockSize) || contentBoxSize.blockSize * devicePixelRatio;
1516
2158
  const [maxDevicePixelWidth, maxDevicePixelHeight] = this.getMaxDrawingBufferSize();
1517
2159
  this.devicePixelWidth = Math.max(1, Math.min(devicePixelWidth, maxDevicePixelWidth));
1518
2160
  this.devicePixelHeight = Math.max(1, Math.min(devicePixelHeight, maxDevicePixelHeight));
@@ -1522,44 +2164,46 @@ var _CanvasContext = class {
1522
2164
  _updateDrawingBufferSize() {
1523
2165
  if (this.props.autoResize) {
1524
2166
  if (typeof this.props.useDevicePixels === "number") {
1525
- const dpr = this.props.useDevicePixels;
1526
- this.setDrawingBufferSize(this.cssWidth * dpr, this.cssHeight * dpr);
2167
+ const devicePixelRatio2 = this.props.useDevicePixels;
2168
+ this.setDrawingBufferSize(this.cssWidth * devicePixelRatio2, this.cssHeight * devicePixelRatio2);
1527
2169
  } else if (this.props.useDevicePixels) {
1528
2170
  this.setDrawingBufferSize(this.devicePixelWidth, this.devicePixelHeight);
1529
2171
  } else {
1530
2172
  this.setDrawingBufferSize(this.cssWidth, this.cssHeight);
1531
2173
  }
1532
- this._updateDevice();
1533
2174
  }
1534
2175
  this._initializedResolvers.resolve();
1535
2176
  this.isInitialized = true;
1536
2177
  this.updatePosition();
1537
2178
  }
1538
- /** Monitor DPR changes */
2179
+ _resizeDrawingBufferIfNeeded() {
2180
+ if (this._needsDrawingBufferResize) {
2181
+ this._needsDrawingBufferResize = false;
2182
+ const sizeChanged = this.drawingBufferWidth !== this.canvas.width || this.drawingBufferHeight !== this.canvas.height;
2183
+ if (sizeChanged) {
2184
+ this.canvas.width = this.drawingBufferWidth;
2185
+ this.canvas.height = this.drawingBufferHeight;
2186
+ this._configureDevice();
2187
+ }
2188
+ }
2189
+ }
1539
2190
  _observeDevicePixelRatio() {
2191
+ var _a, _b;
2192
+ if (this.destroyed || !this._canvasObserver.started) {
2193
+ return;
2194
+ }
1540
2195
  const oldRatio = this.devicePixelRatio;
1541
2196
  this.devicePixelRatio = window.devicePixelRatio;
1542
2197
  this.updatePosition();
1543
- this.device.props.onDevicePixelRatioChange(this, { oldRatio });
1544
- matchMedia(`(resolution: ${this.devicePixelRatio}dppx)`).addEventListener("change", () => this._observeDevicePixelRatio(), { once: true });
1545
- }
1546
- /** Start tracking positions with a timer */
1547
- _trackPosition(intervalMs = 100) {
1548
- const intervalId = setInterval(() => {
1549
- if (this.destroyed) {
1550
- clearInterval(intervalId);
1551
- } else {
1552
- this.updatePosition();
1553
- }
1554
- }, intervalMs);
2198
+ (_b = (_a = this.device.props).onDevicePixelRatioChange) == null ? void 0 : _b.call(_a, this, {
2199
+ oldRatio
2200
+ });
1555
2201
  }
1556
- /**
1557
- * Calculated the absolute position of the canvas
1558
- * @note - getBoundingClientRect() is normally cheap but can be expensive
1559
- * if called before browser has finished a reflow. Should not be the case here.
1560
- */
1561
2202
  updatePosition() {
1562
2203
  var _a, _b, _c;
2204
+ if (this.destroyed) {
2205
+ return;
2206
+ }
1563
2207
  const newRect = (_a = this.htmlCanvas) == null ? void 0 : _a.getBoundingClientRect();
1564
2208
  if (newRect) {
1565
2209
  const position = [newRect.left, newRect.top];
@@ -1568,13 +2212,15 @@ var _CanvasContext = class {
1568
2212
  if (positionChanged) {
1569
2213
  const oldPosition = this._position;
1570
2214
  this._position = position;
1571
- (_c = (_b = this.device.props).onPositionChange) == null ? void 0 : _c.call(_b, this, { oldPosition });
2215
+ (_c = (_b = this.device.props).onPositionChange) == null ? void 0 : _c.call(_b, this, {
2216
+ oldPosition
2217
+ });
1572
2218
  }
1573
2219
  }
1574
2220
  }
1575
2221
  };
1576
- var CanvasContext = _CanvasContext;
1577
- __publicField(CanvasContext, "defaultProps", {
2222
+ var CanvasSurface = _CanvasSurface;
2223
+ __publicField(CanvasSurface, "defaultProps", {
1578
2224
  id: void 0,
1579
2225
  canvas: null,
1580
2226
  width: 800,
@@ -1602,7 +2248,7 @@ function getContainer(container) {
1602
2248
  }
1603
2249
  function getCanvasFromDOM(canvasId) {
1604
2250
  const canvas = document.getElementById(canvasId);
1605
- if (!CanvasContext.isHTMLCanvas(canvas)) {
2251
+ if (!CanvasSurface.isHTMLCanvas(canvas)) {
1606
2252
  throw new Error("Object is not a canvas element");
1607
2253
  }
1608
2254
  return canvas;
@@ -1626,33 +2272,40 @@ function scalePixels(pixel, ratio, width, height, yInvert) {
1626
2272
  const point = pixel;
1627
2273
  const x = scaleX(point[0], ratio, width);
1628
2274
  let y = scaleY(point[1], ratio, height, yInvert);
1629
- let t = scaleX(point[0] + 1, ratio, width);
1630
- const xHigh = t === width - 1 ? t : t - 1;
1631
- t = scaleY(point[1] + 1, ratio, height, yInvert);
2275
+ let temporary = scaleX(point[0] + 1, ratio, width);
2276
+ const xHigh = temporary === width - 1 ? temporary : temporary - 1;
2277
+ temporary = scaleY(point[1] + 1, ratio, height, yInvert);
1632
2278
  let yHigh;
1633
2279
  if (yInvert) {
1634
- t = t === 0 ? t : t + 1;
2280
+ temporary = temporary === 0 ? temporary : temporary + 1;
1635
2281
  yHigh = y;
1636
- y = t;
2282
+ y = temporary;
1637
2283
  } else {
1638
- yHigh = t === height - 1 ? t : t - 1;
2284
+ yHigh = temporary === height - 1 ? temporary : temporary - 1;
1639
2285
  }
1640
2286
  return {
1641
2287
  x,
1642
2288
  y,
1643
- // when ratio < 1, current css pixel and next css pixel may point to same device pixel, set width/height to 1 in those cases.
1644
2289
  width: Math.max(xHigh - x + 1, 1),
1645
2290
  height: Math.max(yHigh - y + 1, 1)
1646
2291
  };
1647
2292
  }
1648
2293
  function scaleX(x, ratio, width) {
1649
- const r = Math.min(Math.round(x * ratio), width - 1);
1650
- return r;
2294
+ return Math.min(Math.round(x * ratio), width - 1);
1651
2295
  }
1652
2296
  function scaleY(y, ratio, height, yInvert) {
1653
2297
  return yInvert ? Math.max(0, height - 1 - Math.round(y * ratio)) : Math.min(Math.round(y * ratio), height - 1);
1654
2298
  }
1655
2299
 
2300
+ // dist/adapter/canvas-context.js
2301
+ var CanvasContext = class extends CanvasSurface {
2302
+ };
2303
+ __publicField(CanvasContext, "defaultProps", CanvasSurface.defaultProps);
2304
+
2305
+ // dist/adapter/presentation-context.js
2306
+ var PresentationContext = class extends CanvasSurface {
2307
+ };
2308
+
1656
2309
  // dist/adapter/resources/sampler.js
1657
2310
  var _Sampler = class extends Resource {
1658
2311
  get [Symbol.toStringTag]() {
@@ -1707,7 +2360,15 @@ var _Texture = class extends Resource {
1707
2360
  depth;
1708
2361
  /** mip levels in this texture */
1709
2362
  mipLevels;
1710
- /** "Time" of last update. Monotonically increasing timestamp. TODO move to AsyncTexture? */
2363
+ /** sample count */
2364
+ samples;
2365
+ /** Rows are multiples of this length, padded with extra bytes if needed */
2366
+ byteAlignment;
2367
+ /** The ready promise is always resolved. It is provided for type compatibility with DynamicTexture. */
2368
+ ready = Promise.resolve(this);
2369
+ /** isReady is always true. It is provided for type compatibility with DynamicTexture. */
2370
+ isReady = true;
2371
+ /** "Time" of last update. Monotonically increasing timestamp. TODO move to DynamicTexture? */
1711
2372
  updateTimestamp;
1712
2373
  get [Symbol.toStringTag]() {
1713
2374
  return "Texture";
@@ -1716,7 +2377,7 @@ var _Texture = class extends Resource {
1716
2377
  return `Texture(${this.id},${this.format},${this.width}x${this.height})`;
1717
2378
  }
1718
2379
  /** Do not use directly. Create with device.createTexture() */
1719
- constructor(device, props) {
2380
+ constructor(device, props, backendProps) {
1720
2381
  props = _Texture.normalizeProps(device, props);
1721
2382
  super(device, props, _Texture.defaultProps);
1722
2383
  this.dimension = this.props.dimension;
@@ -1726,6 +2387,10 @@ var _Texture = class extends Resource {
1726
2387
  this.height = this.props.height;
1727
2388
  this.depth = this.props.depth;
1728
2389
  this.mipLevels = this.props.mipLevels;
2390
+ this.samples = this.props.samples || 1;
2391
+ if (this.dimension === "cube") {
2392
+ this.depth = 6;
2393
+ }
1729
2394
  if (this.props.width === void 0 || this.props.height === void 0) {
1730
2395
  if (device.isExternalImage(props.data)) {
1731
2396
  const size = device.getExternalImageSize(props.data);
@@ -1735,16 +2400,13 @@ var _Texture = class extends Resource {
1735
2400
  this.width = 1;
1736
2401
  this.height = 1;
1737
2402
  if (this.props.width === void 0 || this.props.height === void 0) {
1738
- log.warn(`${this} created with undefined width or height. This is deprecated. Use AsyncTexture instead.`)();
2403
+ log.warn(`${this} created with undefined width or height. This is deprecated. Use DynamicTexture instead.`)();
1739
2404
  }
1740
2405
  }
1741
2406
  }
2407
+ this.byteAlignment = (backendProps == null ? void 0 : backendProps.byteAlignment) || 1;
1742
2408
  this.updateTimestamp = device.incrementTimestamp();
1743
2409
  }
1744
- /** Set sampler props associated with this texture */
1745
- setSampler(sampler) {
1746
- this.sampler = sampler instanceof Sampler ? sampler : this.device.createSampler(sampler);
1747
- }
1748
2410
  /**
1749
2411
  * Create a new texture with the same parameters and optionally a different size
1750
2412
  * @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.
@@ -1753,6 +2415,105 @@ var _Texture = class extends Resource {
1753
2415
  clone(size) {
1754
2416
  return this.device.createTexture({ ...this.props, ...size });
1755
2417
  }
2418
+ /** Set sampler props associated with this texture */
2419
+ setSampler(sampler) {
2420
+ this.sampler = sampler instanceof Sampler ? sampler : this.device.createSampler(sampler);
2421
+ }
2422
+ /**
2423
+ * Copy raw image data (bytes) into the texture.
2424
+ *
2425
+ * @note Deprecated compatibility wrapper over {@link writeData}.
2426
+ * @note Uses the same layout defaults and alignment rules as {@link writeData}.
2427
+ * @note Tightly packed CPU uploads can omit `bytesPerRow` and `rowsPerImage`.
2428
+ * @note If the CPU source rows are padded, pass explicit `bytesPerRow` and `rowsPerImage`.
2429
+ * @deprecated Use writeData()
2430
+ */
2431
+ copyImageData(options) {
2432
+ const { data, depth, ...writeOptions } = options;
2433
+ this.writeData(data, {
2434
+ ...writeOptions,
2435
+ depthOrArrayLayers: writeOptions.depthOrArrayLayers ?? depth
2436
+ });
2437
+ }
2438
+ /**
2439
+ * Calculates the memory layout of the texture, required when reading and writing data.
2440
+ * @return the backend-aligned linear layout, in particular bytesPerRow which includes any required padding for buffer copy/read paths
2441
+ */
2442
+ computeMemoryLayout(options_ = {}) {
2443
+ const options = this._normalizeTextureReadOptions(options_);
2444
+ const { width = this.width, height = this.height, depthOrArrayLayers = this.depth } = options;
2445
+ const { format, byteAlignment } = this;
2446
+ return textureFormatDecoder.computeMemoryLayout({
2447
+ format,
2448
+ width,
2449
+ height,
2450
+ depth: depthOrArrayLayers,
2451
+ byteAlignment
2452
+ });
2453
+ }
2454
+ /**
2455
+ * Read the contents of a texture into a GPU Buffer.
2456
+ * @returns A Buffer containing the texture data.
2457
+ *
2458
+ * @note The memory layout of the texture data is determined by the texture format and dimensions.
2459
+ * @note The application can call Texture.computeMemoryLayout() to compute the backend-aligned layout.
2460
+ * @note The application can call Buffer.readAsync() to read the returned buffer on the CPU.
2461
+ * @note The destination buffer must be supplied by the caller and must be large enough for the requested region.
2462
+ * @note On WebGPU this corresponds to a texture-to-buffer copy and uses buffer-copy alignment rules.
2463
+ * @note On WebGL, luma.gl emulates the same logical readback behavior.
2464
+ */
2465
+ readBuffer(options, buffer) {
2466
+ throw new Error("readBuffer not implemented");
2467
+ }
2468
+ /**
2469
+ * Reads data from a texture into an ArrayBuffer.
2470
+ * @returns An ArrayBuffer containing the texture data.
2471
+ *
2472
+ * @note The memory layout of the texture data is determined by the texture format and dimensions.
2473
+ * @note The application can call Texture.computeMemoryLayout() to compute the layout.
2474
+ * @deprecated Use Texture.readBuffer() with an explicit destination buffer, or DynamicTexture.readAsync() for convenience readback.
2475
+ */
2476
+ readDataAsync(options) {
2477
+ throw new Error("readBuffer not implemented");
2478
+ }
2479
+ /**
2480
+ * Writes a GPU Buffer into a texture.
2481
+ *
2482
+ * @param buffer - Source GPU buffer.
2483
+ * @param options - Destination subresource, extent, and source layout options.
2484
+ * @note The memory layout of the texture data is determined by the texture format and dimensions.
2485
+ * @note The application can call Texture.computeMemoryLayout() to compute the backend-aligned layout.
2486
+ * @note On WebGPU this corresponds to a buffer-to-texture copy and uses buffer-copy alignment rules.
2487
+ * @note On WebGL, luma.gl emulates the same destination and layout semantics.
2488
+ */
2489
+ writeBuffer(buffer, options) {
2490
+ throw new Error("readBuffer not implemented");
2491
+ }
2492
+ /**
2493
+ * Writes an array buffer into a texture.
2494
+ *
2495
+ * @param data - Source texel data.
2496
+ * @param options - Destination subresource, extent, and source layout options.
2497
+ * @note If `bytesPerRow` and `rowsPerImage` are omitted, luma.gl computes a tightly packed CPU-memory layout for the requested region.
2498
+ * @note On WebGPU this corresponds to `GPUQueue.writeTexture()` and does not implicitly pad rows to 256 bytes.
2499
+ * @note On WebGL, padded CPU data is supported via the same `bytesPerRow` and `rowsPerImage` options.
2500
+ */
2501
+ writeData(data, options) {
2502
+ throw new Error("readBuffer not implemented");
2503
+ }
2504
+ // IMPLEMENTATION SPECIFIC
2505
+ /**
2506
+ * WebGL can read data synchronously.
2507
+ * @note While it is convenient, the performance penalty is very significant
2508
+ */
2509
+ readDataSyncWebGL(options) {
2510
+ throw new Error("readDataSyncWebGL not available");
2511
+ }
2512
+ /** Generate mipmaps (WebGL only) */
2513
+ generateMipmapsWebGL() {
2514
+ throw new Error("generateMipmapsWebGL not available");
2515
+ }
2516
+ // HELPERS
1756
2517
  /** Ensure we have integer coordinates */
1757
2518
  static normalizeProps(device, props) {
1758
2519
  const newProps = { ...props };
@@ -1765,7 +2526,6 @@ var _Texture = class extends Resource {
1765
2526
  }
1766
2527
  return newProps;
1767
2528
  }
1768
- // HELPERS
1769
2529
  /** Initialize texture with supplied props */
1770
2530
  // eslint-disable-next-line max-statements
1771
2531
  _initializeData(data) {
@@ -1799,23 +2559,148 @@ var _Texture = class extends Resource {
1799
2559
  }
1800
2560
  }
1801
2561
  _normalizeCopyImageDataOptions(options_) {
1802
- const { width, height, depth } = this;
1803
- const options = { ..._Texture.defaultCopyDataOptions, width, height, depth, ...options_ };
1804
- const info = this.device.getTextureFormatInfo(this.format);
1805
- if (!options_.bytesPerRow && !info.bytesPerPixel) {
1806
- throw new Error(`bytesPerRow must be provided for texture format ${this.format}`);
1807
- }
1808
- options.bytesPerRow = options_.bytesPerRow || width * (info.bytesPerPixel || 4);
1809
- options.rowsPerImage = options_.rowsPerImage || height;
1810
- return options;
2562
+ const { data, depth, ...writeOptions } = options_;
2563
+ const options = this._normalizeTextureWriteOptions({
2564
+ ...writeOptions,
2565
+ depthOrArrayLayers: writeOptions.depthOrArrayLayers ?? depth
2566
+ });
2567
+ return { data, depth: options.depthOrArrayLayers, ...options };
1811
2568
  }
1812
2569
  _normalizeCopyExternalImageOptions(options_) {
2570
+ const optionsWithoutUndefined = _Texture._omitUndefined(options_);
2571
+ const mipLevel = optionsWithoutUndefined.mipLevel ?? 0;
2572
+ const mipLevelSize = this._getMipLevelSize(mipLevel);
1813
2573
  const size = this.device.getExternalImageSize(options_.image);
1814
- const options = { ..._Texture.defaultCopyExternalImageOptions, ...size, ...options_ };
1815
- options.width = Math.min(options.width, this.width - options.x);
1816
- options.height = Math.min(options.height, this.height - options.y);
2574
+ const options = {
2575
+ ..._Texture.defaultCopyExternalImageOptions,
2576
+ ...mipLevelSize,
2577
+ ...size,
2578
+ ...optionsWithoutUndefined
2579
+ };
2580
+ options.width = Math.min(options.width, mipLevelSize.width - options.x);
2581
+ options.height = Math.min(options.height, mipLevelSize.height - options.y);
2582
+ options.depth = Math.min(options.depth, mipLevelSize.depthOrArrayLayers - options.z);
2583
+ return options;
2584
+ }
2585
+ _normalizeTextureReadOptions(options_) {
2586
+ const optionsWithoutUndefined = _Texture._omitUndefined(options_);
2587
+ const mipLevel = optionsWithoutUndefined.mipLevel ?? 0;
2588
+ const mipLevelSize = this._getMipLevelSize(mipLevel);
2589
+ const options = {
2590
+ ..._Texture.defaultTextureReadOptions,
2591
+ ...mipLevelSize,
2592
+ ...optionsWithoutUndefined
2593
+ };
2594
+ options.width = Math.min(options.width, mipLevelSize.width - options.x);
2595
+ options.height = Math.min(options.height, mipLevelSize.height - options.y);
2596
+ options.depthOrArrayLayers = Math.min(options.depthOrArrayLayers, mipLevelSize.depthOrArrayLayers - options.z);
2597
+ return options;
2598
+ }
2599
+ /**
2600
+ * Normalizes a texture read request and validates the color-only readback contract used by the
2601
+ * current texture read APIs. Supported dimensions are `2d`, `cube`, `cube-array`,
2602
+ * `2d-array`, and `3d`.
2603
+ *
2604
+ * @throws if the texture format, aspect, or dimension is not supported by the first-pass
2605
+ * color-read implementation.
2606
+ */
2607
+ _getSupportedColorReadOptions(options_) {
2608
+ const options = this._normalizeTextureReadOptions(options_);
2609
+ const formatInfo = textureFormatDecoder.getInfo(this.format);
2610
+ this._validateColorReadAspect(options);
2611
+ this._validateColorReadFormat(formatInfo);
2612
+ switch (this.dimension) {
2613
+ case "2d":
2614
+ case "cube":
2615
+ case "cube-array":
2616
+ case "2d-array":
2617
+ case "3d":
2618
+ return options;
2619
+ default:
2620
+ throw new Error(`${this} color readback does not support ${this.dimension} textures`);
2621
+ }
2622
+ }
2623
+ /** Validates that a read request targets the full color aspect of the texture. */
2624
+ _validateColorReadAspect(options) {
2625
+ if (options.aspect !== "all") {
2626
+ throw new Error(`${this} color readback only supports aspect 'all'`);
2627
+ }
2628
+ }
2629
+ /** Validates that a read request targets an uncompressed color-renderable texture format. */
2630
+ _validateColorReadFormat(formatInfo) {
2631
+ if (formatInfo.compressed) {
2632
+ throw new Error(`${this} color readback does not support compressed formats (${this.format})`);
2633
+ }
2634
+ switch (formatInfo.attachment) {
2635
+ case "color":
2636
+ return;
2637
+ case "depth":
2638
+ throw new Error(`${this} color readback does not support depth formats (${this.format})`);
2639
+ case "stencil":
2640
+ throw new Error(`${this} color readback does not support stencil formats (${this.format})`);
2641
+ case "depth-stencil":
2642
+ throw new Error(`${this} color readback does not support depth-stencil formats (${this.format})`);
2643
+ default:
2644
+ throw new Error(`${this} color readback does not support format ${this.format}`);
2645
+ }
2646
+ }
2647
+ _normalizeTextureWriteOptions(options_) {
2648
+ const optionsWithoutUndefined = _Texture._omitUndefined(options_);
2649
+ const mipLevel = optionsWithoutUndefined.mipLevel ?? 0;
2650
+ const mipLevelSize = this._getMipLevelSize(mipLevel);
2651
+ const options = {
2652
+ ..._Texture.defaultTextureWriteOptions,
2653
+ ...mipLevelSize,
2654
+ ...optionsWithoutUndefined
2655
+ };
2656
+ options.width = Math.min(options.width, mipLevelSize.width - options.x);
2657
+ options.height = Math.min(options.height, mipLevelSize.height - options.y);
2658
+ options.depthOrArrayLayers = Math.min(options.depthOrArrayLayers, mipLevelSize.depthOrArrayLayers - options.z);
2659
+ const layout = textureFormatDecoder.computeMemoryLayout({
2660
+ format: this.format,
2661
+ width: options.width,
2662
+ height: options.height,
2663
+ depth: options.depthOrArrayLayers,
2664
+ byteAlignment: this.byteAlignment
2665
+ });
2666
+ const minimumBytesPerRow = layout.bytesPerPixel * options.width;
2667
+ options.bytesPerRow = optionsWithoutUndefined.bytesPerRow ?? layout.bytesPerRow;
2668
+ options.rowsPerImage = optionsWithoutUndefined.rowsPerImage ?? options.height;
2669
+ if (options.bytesPerRow < minimumBytesPerRow) {
2670
+ throw new Error(`bytesPerRow (${options.bytesPerRow}) must be at least ${minimumBytesPerRow} for ${this.format}`);
2671
+ }
2672
+ if (options.rowsPerImage < options.height) {
2673
+ throw new Error(`rowsPerImage (${options.rowsPerImage}) must be at least ${options.height} for ${this.format}`);
2674
+ }
2675
+ const bytesPerPixel = this.device.getTextureFormatInfo(this.format).bytesPerPixel;
2676
+ if (bytesPerPixel && options.bytesPerRow % bytesPerPixel !== 0) {
2677
+ throw new Error(`bytesPerRow (${options.bytesPerRow}) must be a multiple of bytesPerPixel (${bytesPerPixel}) for ${this.format}`);
2678
+ }
1817
2679
  return options;
1818
2680
  }
2681
+ _getMipLevelSize(mipLevel) {
2682
+ const width = Math.max(1, this.width >> mipLevel);
2683
+ const height = this.baseDimension === "1d" ? 1 : Math.max(1, this.height >> mipLevel);
2684
+ const depthOrArrayLayers = this.dimension === "3d" ? Math.max(1, this.depth >> mipLevel) : this.depth;
2685
+ return { width, height, depthOrArrayLayers };
2686
+ }
2687
+ getAllocatedByteLength() {
2688
+ let allocatedByteLength = 0;
2689
+ for (let mipLevel = 0; mipLevel < this.mipLevels; mipLevel++) {
2690
+ const { width, height, depthOrArrayLayers } = this._getMipLevelSize(mipLevel);
2691
+ allocatedByteLength += textureFormatDecoder.computeMemoryLayout({
2692
+ format: this.format,
2693
+ width,
2694
+ height,
2695
+ depth: depthOrArrayLayers,
2696
+ byteAlignment: 1
2697
+ }).byteLength;
2698
+ }
2699
+ return allocatedByteLength * this.samples;
2700
+ }
2701
+ static _omitUndefined(options) {
2702
+ return Object.fromEntries(Object.entries(options).filter(([, value]) => value !== void 0));
2703
+ }
1819
2704
  };
1820
2705
  var Texture = _Texture;
1821
2706
  /** The texture can be bound for use as a sampled texture in a shader */
@@ -1832,13 +2717,12 @@ __publicField(Texture, "COPY_DST", 2);
1832
2717
  __publicField(Texture, "TEXTURE", 4);
1833
2718
  /** @deprecated Use Texture.RENDER */
1834
2719
  __publicField(Texture, "RENDER_ATTACHMENT", 16);
1835
- /** Default options */
1836
2720
  __publicField(Texture, "defaultProps", {
1837
2721
  ...Resource.defaultProps,
1838
2722
  data: null,
1839
2723
  dimension: "2d",
1840
2724
  format: "rgba8unorm",
1841
- usage: _Texture.TEXTURE | _Texture.RENDER_ATTACHMENT | _Texture.COPY_DST,
2725
+ usage: _Texture.SAMPLE | _Texture.RENDER | _Texture.COPY_DST,
1842
2726
  width: void 0,
1843
2727
  height: void 0,
1844
2728
  depth: 1,
@@ -1852,6 +2736,10 @@ __publicField(Texture, "defaultCopyDataOptions", {
1852
2736
  byteOffset: 0,
1853
2737
  bytesPerRow: void 0,
1854
2738
  rowsPerImage: void 0,
2739
+ width: void 0,
2740
+ height: void 0,
2741
+ depthOrArrayLayers: void 0,
2742
+ depth: 1,
1855
2743
  mipLevel: 0,
1856
2744
  x: 0,
1857
2745
  y: 0,
@@ -1875,6 +2763,29 @@ __publicField(Texture, "defaultCopyExternalImageOptions", {
1875
2763
  premultipliedAlpha: false,
1876
2764
  flipY: false
1877
2765
  });
2766
+ __publicField(Texture, "defaultTextureReadOptions", {
2767
+ x: 0,
2768
+ y: 0,
2769
+ z: 0,
2770
+ width: void 0,
2771
+ height: void 0,
2772
+ depthOrArrayLayers: 1,
2773
+ mipLevel: 0,
2774
+ aspect: "all"
2775
+ });
2776
+ __publicField(Texture, "defaultTextureWriteOptions", {
2777
+ byteOffset: 0,
2778
+ bytesPerRow: void 0,
2779
+ rowsPerImage: void 0,
2780
+ x: 0,
2781
+ y: 0,
2782
+ z: 0,
2783
+ width: void 0,
2784
+ height: void 0,
2785
+ depthOrArrayLayers: 1,
2786
+ mipLevel: 0,
2787
+ aspect: "all"
2788
+ });
1878
2789
 
1879
2790
  // dist/adapter/resources/texture-view.js
1880
2791
  var _TextureView = class extends Resource {
@@ -1921,24 +2832,32 @@ function formatCompilerLog(shaderLog, source, options) {
1921
2832
  const log2 = shaderLog.slice().sort((a, b) => a.lineNum - b.lineNum);
1922
2833
  switch ((options == null ? void 0 : options.showSourceCode) || "no") {
1923
2834
  case "all":
1924
- let currentMessage = 0;
2835
+ let currentMessageIndex = 0;
1925
2836
  for (let lineNum = 1; lineNum <= lines.length; lineNum++) {
1926
- formattedLog += getNumberedLine(lines[lineNum - 1], lineNum, options);
1927
- while (log2.length > currentMessage && log2[currentMessage].lineNum === lineNum) {
1928
- const message = log2[currentMessage++];
1929
- formattedLog += formatCompilerMessage(message, lines, message.lineNum, {
2837
+ const line = lines[lineNum - 1];
2838
+ const currentMessage = log2[currentMessageIndex];
2839
+ if (line && currentMessage) {
2840
+ formattedLog += getNumberedLine(line, lineNum, options);
2841
+ }
2842
+ while (log2.length > currentMessageIndex && currentMessage.lineNum === lineNum) {
2843
+ const message = log2[currentMessageIndex++];
2844
+ if (message) {
2845
+ formattedLog += formatCompilerMessage(message, lines, message.lineNum, {
2846
+ ...options,
2847
+ inlineSource: false
2848
+ });
2849
+ }
2850
+ }
2851
+ }
2852
+ while (log2.length > currentMessageIndex) {
2853
+ const message = log2[currentMessageIndex++];
2854
+ if (message) {
2855
+ formattedLog += formatCompilerMessage(message, [], 0, {
1930
2856
  ...options,
1931
2857
  inlineSource: false
1932
2858
  });
1933
2859
  }
1934
2860
  }
1935
- while (log2.length > currentMessage) {
1936
- const message = log2[currentMessage++];
1937
- formattedLog += formatCompilerMessage(message, [], 0, {
1938
- ...options,
1939
- inlineSource: false
1940
- });
1941
- }
1942
2861
  return formattedLog;
1943
2862
  case "issues":
1944
2863
  case "no":
@@ -1960,8 +2879,8 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
1960
2879
 
1961
2880
  `;
1962
2881
  }
1963
- const color = message.type === "error" ? "red" : "#8B4000";
1964
- return (options == null ? void 0 : options.html) ? `<div class='luma-compiler-log-error' style="color:${color};"><b> ${message.type.toUpperCase()}: ${message.message}</b></div>` : `${message.type.toUpperCase()}: ${message.message}`;
2882
+ const color = message.type === "error" ? "red" : "orange";
2883
+ return (options == null ? void 0 : 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}`;
1965
2884
  }
1966
2885
  function getNumberedLines(lines, lineNum, options) {
1967
2886
  let numberedLines = "";
@@ -2042,35 +2961,39 @@ var _Shader = class extends Resource {
2042
2961
  * TODO - this HTML formatting code should not be in Device, should be pluggable
2043
2962
  */
2044
2963
  _displayShaderLog(messages, shaderId) {
2045
- var _a;
2046
2964
  if (typeof document === "undefined" || !(document == null ? void 0 : document.createElement)) {
2047
2965
  return;
2048
2966
  }
2049
2967
  const shaderName = shaderId;
2050
2968
  const shaderTitle = `${this.stage} shader "${shaderName}"`;
2051
- let htmlLog = formatCompilerLog(messages, this.source, { showSourceCode: "all", html: true });
2969
+ const htmlLog = formatCompilerLog(messages, this.source, { showSourceCode: "all", html: true });
2052
2970
  const translatedSource = this.getTranslatedSource();
2971
+ const container = document.createElement("div");
2972
+ container.innerHTML = `<h1>Compilation error in ${shaderTitle}</h1>
2973
+ <div style="display:flex;position:fixed;top:10px;right:20px;gap:2px;">
2974
+ <button id="copy">Copy source</button><br/>
2975
+ <button id="close">Close</button>
2976
+ </div>
2977
+ <code><pre>${htmlLog}</pre></code>`;
2053
2978
  if (translatedSource) {
2054
- htmlLog += `<br /><br /><h1>Translated Source</h1><br /><br /><code style="user-select:text;"><pre>${translatedSource}</pre></code>`;
2055
- }
2056
- const button = document.createElement("Button");
2057
- button.innerHTML = `
2058
- <h1>Compilation error in ${shaderTitle}</h1><br /><br />
2059
- <code style="user-select:text;"><pre>
2060
- ${htmlLog}
2061
- </pre></code>`;
2062
- button.style.top = "10px";
2063
- button.style.left = "10px";
2064
- button.style.position = "absolute";
2065
- button.style.zIndex = "9999";
2066
- button.style.width = "100%";
2067
- button.style.textAlign = "left";
2068
- document.body.appendChild(button);
2069
- const errors = document.getElementsByClassName("luma-compiler-log-error");
2070
- (_a = errors[0]) == null ? void 0 : _a.scrollIntoView();
2071
- button.onclick = () => {
2072
- const dataURI = `data:text/plain,${encodeURIComponent(this.source)}`;
2073
- navigator.clipboard.writeText(dataURI);
2979
+ container.innerHTML += `<br /><h1>Translated Source</h1><br /><br /><code><pre>${translatedSource}</pre></code>`;
2980
+ }
2981
+ container.style.top = "0";
2982
+ container.style.left = "0";
2983
+ container.style.background = "white";
2984
+ container.style.position = "fixed";
2985
+ container.style.zIndex = "9999";
2986
+ container.style.maxWidth = "100vw";
2987
+ container.style.maxHeight = "100vh";
2988
+ container.style.overflowY = "auto";
2989
+ document.body.appendChild(container);
2990
+ const error = container.querySelector(".luma-compiler-log-error");
2991
+ error == null ? void 0 : error.scrollIntoView();
2992
+ container.querySelector("button#close").onclick = () => {
2993
+ container.remove();
2994
+ };
2995
+ container.querySelector("button#copy").onclick = () => {
2996
+ navigator.clipboard.writeText(this.source);
2074
2997
  };
2075
2998
  }
2076
2999
  };
@@ -2090,7 +3013,7 @@ function getShaderIdFromProps(props) {
2090
3013
  function getShaderName(shader, defaultName = "unnamed") {
2091
3014
  const SHADER_NAME_REGEXP = /#define[\s*]SHADER_NAME[\s*]([A-Za-z0-9_-]+)[\s*]/;
2092
3015
  const match = SHADER_NAME_REGEXP.exec(shader);
2093
- return match ? match[1] : defaultName;
3016
+ return (match == null ? void 0 : match[1]) ?? defaultName;
2094
3017
  }
2095
3018
 
2096
3019
  // dist/adapter/resources/framebuffer.js
@@ -2114,7 +3037,12 @@ var _Framebuffer = class extends Resource {
2114
3037
  clone(size) {
2115
3038
  const colorAttachments = this.colorAttachments.map((colorAttachment) => colorAttachment.texture.clone(size));
2116
3039
  const depthStencilAttachment = this.depthStencilAttachment && this.depthStencilAttachment.texture.clone(size);
2117
- return this.device.createFramebuffer({ ...this.props, colorAttachments, depthStencilAttachment });
3040
+ return this.device.createFramebuffer({
3041
+ ...this.props,
3042
+ ...size,
3043
+ colorAttachments,
3044
+ depthStencilAttachment
3045
+ });
2118
3046
  }
2119
3047
  resize(size) {
2120
3048
  let updateSize = !size;
@@ -2189,17 +3117,15 @@ var _Framebuffer = class extends Resource {
2189
3117
  * and destroys existing textures if owned
2190
3118
  */
2191
3119
  resizeAttachments(width, height) {
2192
- for (let i = 0; i < this.colorAttachments.length; ++i) {
2193
- if (this.colorAttachments[i]) {
2194
- const resizedTexture = this.colorAttachments[i].texture.clone({
2195
- width,
2196
- height
2197
- });
2198
- this.destroyAttachedResource(this.colorAttachments[i]);
2199
- this.colorAttachments[i] = resizedTexture.view;
2200
- this.attachResource(resizedTexture.view);
2201
- }
2202
- }
3120
+ this.colorAttachments.forEach((colorAttachment, i) => {
3121
+ const resizedTexture = colorAttachment.texture.clone({
3122
+ width,
3123
+ height
3124
+ });
3125
+ this.destroyAttachedResource(colorAttachment);
3126
+ this.colorAttachments[i] = resizedTexture.view;
3127
+ this.attachResource(resizedTexture.view);
3128
+ });
2203
3129
  if (this.depthStencilAttachment) {
2204
3130
  const resizedTexture = this.depthStencilAttachment.texture.clone({
2205
3131
  width,
@@ -2236,10 +3162,23 @@ var _RenderPipeline = class extends Resource {
2236
3162
  linkStatus = "pending";
2237
3163
  /** The hash of the pipeline */
2238
3164
  hash = "";
3165
+ /** Optional shared backend implementation */
3166
+ sharedRenderPipeline = null;
3167
+ /** Whether shader or pipeline compilation/linking is still in progress */
3168
+ get isPending() {
3169
+ var _a;
3170
+ return this.linkStatus === "pending" || this.vs.compilationStatus === "pending" || ((_a = this.fs) == null ? void 0 : _a.compilationStatus) === "pending";
3171
+ }
3172
+ /** Whether shader or pipeline compilation/linking has failed */
3173
+ get isErrored() {
3174
+ var _a;
3175
+ return this.linkStatus === "error" || this.vs.compilationStatus === "error" || ((_a = this.fs) == null ? void 0 : _a.compilationStatus) === "error";
3176
+ }
2239
3177
  constructor(device, props) {
2240
3178
  super(device, props, _RenderPipeline.defaultProps);
2241
3179
  this.shaderLayout = this.props.shaderLayout;
2242
3180
  this.bufferLayout = this.props.bufferLayout || [];
3181
+ this.sharedRenderPipeline = this.props._sharedRenderPipeline || null;
2243
3182
  }
2244
3183
  };
2245
3184
  var RenderPipeline = _RenderPipeline;
@@ -2257,47 +3196,30 @@ __publicField(RenderPipeline, "defaultProps", {
2257
3196
  colorAttachmentFormats: void 0,
2258
3197
  depthStencilAttachmentFormat: void 0,
2259
3198
  parameters: {},
2260
- bindings: {},
2261
- uniforms: {}
3199
+ varyings: void 0,
3200
+ bufferMode: void 0,
3201
+ disableWarnings: false,
3202
+ _sharedRenderPipeline: void 0,
3203
+ bindings: void 0,
3204
+ bindGroups: void 0
2262
3205
  });
2263
3206
 
2264
- // dist/adapter/resources/render-pass.js
2265
- var _RenderPass = class extends Resource {
3207
+ // dist/adapter/resources/shared-render-pipeline.js
3208
+ var SharedRenderPipeline = class extends Resource {
2266
3209
  get [Symbol.toStringTag]() {
2267
- return "RenderPass";
3210
+ return "SharedRenderPipeline";
2268
3211
  }
2269
3212
  constructor(device, props) {
2270
- props = _RenderPass.normalizeProps(device, props);
2271
- super(device, props, _RenderPass.defaultProps);
2272
- }
2273
- static normalizeProps(device, props) {
2274
- return props;
3213
+ super(device, props, {
3214
+ ...Resource.defaultProps,
3215
+ handle: void 0,
3216
+ vs: void 0,
3217
+ fs: void 0,
3218
+ varyings: void 0,
3219
+ bufferMode: void 0
3220
+ });
2275
3221
  }
2276
3222
  };
2277
- var RenderPass = _RenderPass;
2278
- /** TODO - should be [0, 0, 0, 0], update once deck.gl tests run clean */
2279
- __publicField(RenderPass, "defaultClearColor", [0, 0, 0, 1]);
2280
- /** Depth 1.0 represents the far plance */
2281
- __publicField(RenderPass, "defaultClearDepth", 1);
2282
- /** Clears all stencil bits */
2283
- __publicField(RenderPass, "defaultClearStencil", 0);
2284
- /** Default properties for RenderPass */
2285
- __publicField(RenderPass, "defaultProps", {
2286
- ...Resource.defaultProps,
2287
- framebuffer: null,
2288
- parameters: void 0,
2289
- clearColor: _RenderPass.defaultClearColor,
2290
- clearColors: void 0,
2291
- clearDepth: _RenderPass.defaultClearDepth,
2292
- clearStencil: _RenderPass.defaultClearStencil,
2293
- depthReadOnly: false,
2294
- stencilReadOnly: false,
2295
- discard: false,
2296
- occlusionQuerySet: void 0,
2297
- timestampQuerySet: void 0,
2298
- beginTimestampIndex: void 0,
2299
- endTimestampIndex: void 0
2300
- });
2301
3223
 
2302
3224
  // dist/adapter/resources/compute-pipeline.js
2303
3225
  var _ComputePipeline = class extends Resource {
@@ -2321,62 +3243,594 @@ __publicField(ComputePipeline, "defaultProps", {
2321
3243
  shaderLayout: void 0
2322
3244
  });
2323
3245
 
2324
- // dist/adapter/resources/compute-pass.js
2325
- var _ComputePass = class extends Resource {
2326
- constructor(device, props) {
2327
- super(device, props, _ComputePass.defaultProps);
2328
- }
2329
- get [Symbol.toStringTag]() {
2330
- return "ComputePass";
2331
- }
2332
- };
2333
- var ComputePass = _ComputePass;
2334
- __publicField(ComputePass, "defaultProps", {
2335
- ...Resource.defaultProps,
2336
- timestampQuerySet: void 0,
2337
- beginTimestampIndex: void 0,
2338
- endTimestampIndex: void 0
2339
- });
2340
-
2341
- // dist/adapter/resources/command-encoder.js
2342
- var _CommandEncoder = class extends Resource {
3246
+ // dist/factories/pipeline-factory.js
3247
+ var _PipelineFactory = class {
3248
+ /** Get the singleton default pipeline factory for the specified device */
3249
+ static getDefaultPipelineFactory(device) {
3250
+ const moduleData = device.getModuleData("@luma.gl/core");
3251
+ moduleData.defaultPipelineFactory ||= new _PipelineFactory(device);
3252
+ return moduleData.defaultPipelineFactory;
3253
+ }
3254
+ device;
3255
+ _hashCounter = 0;
3256
+ _hashes = {};
3257
+ _renderPipelineCache = {};
3258
+ _computePipelineCache = {};
3259
+ _sharedRenderPipelineCache = {};
2343
3260
  get [Symbol.toStringTag]() {
2344
- return "CommandEncoder";
2345
- }
2346
- constructor(device, props) {
2347
- super(device, props, _CommandEncoder.defaultProps);
3261
+ return "PipelineFactory";
2348
3262
  }
2349
- };
2350
- var CommandEncoder = _CommandEncoder;
2351
- // TODO - luma.gl has these on the device, should we align with WebGPU API?
2352
- // beginRenderPass(GPURenderPassDescriptor descriptor): GPURenderPassEncoder;
2353
- // beginComputePass(optional GPUComputePassDescriptor descriptor = {}): GPUComputePassEncoder;
2354
- __publicField(CommandEncoder, "defaultProps", {
2355
- ...Resource.defaultProps,
2356
- measureExecutionTime: void 0
2357
- });
2358
-
2359
- // dist/adapter/resources/command-buffer.js
2360
- var _CommandBuffer = class extends Resource {
2361
- get [Symbol.toStringTag]() {
2362
- return "CommandBuffer";
3263
+ toString() {
3264
+ return `PipelineFactory(${this.device.id})`;
2363
3265
  }
2364
- constructor(device, props) {
2365
- super(device, props, _CommandBuffer.defaultProps);
3266
+ constructor(device) {
3267
+ this.device = device;
2366
3268
  }
2367
- };
2368
- var CommandBuffer = _CommandBuffer;
3269
+ /**
3270
+ * WebGL has two cache layers with different priorities:
3271
+ * - `_sharedRenderPipelineCache` owns `WEBGLSharedRenderPipeline` / `WebGLProgram` reuse.
3272
+ * - `_renderPipelineCache` owns `RenderPipeline` wrapper reuse.
3273
+ *
3274
+ * Shared WebGL program reuse is the hard requirement. Wrapper reuse is beneficial,
3275
+ * but wrapper cache misses are acceptable if that keeps the cache logic simple and
3276
+ * prevents incorrect cache hits.
3277
+ *
3278
+ * In particular, wrapper hash logic must never force program creation or linked-program
3279
+ * introspection just to decide whether a shared WebGL program can be reused.
3280
+ */
3281
+ /** Return a RenderPipeline matching supplied props. Reuses an equivalent pipeline if already created. */
3282
+ createRenderPipeline(props) {
3283
+ var _a;
3284
+ if (!this.device.props._cachePipelines) {
3285
+ return this.device.createRenderPipeline(props);
3286
+ }
3287
+ const allProps = { ...RenderPipeline.defaultProps, ...props };
3288
+ const cache = this._renderPipelineCache;
3289
+ const hash = this._hashRenderPipeline(allProps);
3290
+ let pipeline = (_a = cache[hash]) == null ? void 0 : _a.resource;
3291
+ if (!pipeline) {
3292
+ const sharedRenderPipeline = this.device.type === "webgl" && this.device.props._sharePipelines ? this.createSharedRenderPipeline(allProps) : void 0;
3293
+ pipeline = this.device.createRenderPipeline({
3294
+ ...allProps,
3295
+ id: allProps.id ? `${allProps.id}-cached` : uid("unnamed-cached"),
3296
+ _sharedRenderPipeline: sharedRenderPipeline
3297
+ });
3298
+ pipeline.hash = hash;
3299
+ cache[hash] = { resource: pipeline, useCount: 1 };
3300
+ if (this.device.props.debugFactories) {
3301
+ log.log(3, `${this}: ${pipeline} created, count=${cache[hash].useCount}`)();
3302
+ }
3303
+ } else {
3304
+ cache[hash].useCount++;
3305
+ if (this.device.props.debugFactories) {
3306
+ log.log(3, `${this}: ${cache[hash].resource} reused, count=${cache[hash].useCount}, (id=${props.id})`)();
3307
+ }
3308
+ }
3309
+ return pipeline;
3310
+ }
3311
+ /** Return a ComputePipeline matching supplied props. Reuses an equivalent pipeline if already created. */
3312
+ createComputePipeline(props) {
3313
+ var _a;
3314
+ if (!this.device.props._cachePipelines) {
3315
+ return this.device.createComputePipeline(props);
3316
+ }
3317
+ const allProps = { ...ComputePipeline.defaultProps, ...props };
3318
+ const cache = this._computePipelineCache;
3319
+ const hash = this._hashComputePipeline(allProps);
3320
+ let pipeline = (_a = cache[hash]) == null ? void 0 : _a.resource;
3321
+ if (!pipeline) {
3322
+ pipeline = this.device.createComputePipeline({
3323
+ ...allProps,
3324
+ id: allProps.id ? `${allProps.id}-cached` : void 0
3325
+ });
3326
+ pipeline.hash = hash;
3327
+ cache[hash] = { resource: pipeline, useCount: 1 };
3328
+ if (this.device.props.debugFactories) {
3329
+ log.log(3, `${this}: ${pipeline} created, count=${cache[hash].useCount}`)();
3330
+ }
3331
+ } else {
3332
+ cache[hash].useCount++;
3333
+ if (this.device.props.debugFactories) {
3334
+ log.log(3, `${this}: ${cache[hash].resource} reused, count=${cache[hash].useCount}, (id=${props.id})`)();
3335
+ }
3336
+ }
3337
+ return pipeline;
3338
+ }
3339
+ release(pipeline) {
3340
+ if (!this.device.props._cachePipelines) {
3341
+ pipeline.destroy();
3342
+ return;
3343
+ }
3344
+ const cache = this._getCache(pipeline);
3345
+ const hash = pipeline.hash;
3346
+ cache[hash].useCount--;
3347
+ if (cache[hash].useCount === 0) {
3348
+ this._destroyPipeline(pipeline);
3349
+ if (this.device.props.debugFactories) {
3350
+ log.log(3, `${this}: ${pipeline} released and destroyed`)();
3351
+ }
3352
+ } else if (cache[hash].useCount < 0) {
3353
+ log.error(`${this}: ${pipeline} released, useCount < 0, resetting`)();
3354
+ cache[hash].useCount = 0;
3355
+ } else if (this.device.props.debugFactories) {
3356
+ log.log(3, `${this}: ${pipeline} released, count=${cache[hash].useCount}`)();
3357
+ }
3358
+ }
3359
+ createSharedRenderPipeline(props) {
3360
+ const sharedPipelineHash = this._hashSharedRenderPipeline(props);
3361
+ let sharedCacheItem = this._sharedRenderPipelineCache[sharedPipelineHash];
3362
+ if (!sharedCacheItem) {
3363
+ const sharedRenderPipeline = this.device._createSharedRenderPipelineWebGL(props);
3364
+ sharedCacheItem = { resource: sharedRenderPipeline, useCount: 0 };
3365
+ this._sharedRenderPipelineCache[sharedPipelineHash] = sharedCacheItem;
3366
+ }
3367
+ sharedCacheItem.useCount++;
3368
+ return sharedCacheItem.resource;
3369
+ }
3370
+ releaseSharedRenderPipeline(pipeline) {
3371
+ if (!pipeline.sharedRenderPipeline) {
3372
+ return;
3373
+ }
3374
+ const sharedPipelineHash = this._hashSharedRenderPipeline(pipeline.sharedRenderPipeline.props);
3375
+ const sharedCacheItem = this._sharedRenderPipelineCache[sharedPipelineHash];
3376
+ if (!sharedCacheItem) {
3377
+ return;
3378
+ }
3379
+ sharedCacheItem.useCount--;
3380
+ if (sharedCacheItem.useCount === 0) {
3381
+ sharedCacheItem.resource.destroy();
3382
+ delete this._sharedRenderPipelineCache[sharedPipelineHash];
3383
+ }
3384
+ }
3385
+ // PRIVATE
3386
+ /** Destroy a cached pipeline, removing it from the cache if configured to do so. */
3387
+ _destroyPipeline(pipeline) {
3388
+ const cache = this._getCache(pipeline);
3389
+ if (!this.device.props._destroyPipelines) {
3390
+ return false;
3391
+ }
3392
+ delete cache[pipeline.hash];
3393
+ pipeline.destroy();
3394
+ if (pipeline instanceof RenderPipeline) {
3395
+ this.releaseSharedRenderPipeline(pipeline);
3396
+ }
3397
+ return true;
3398
+ }
3399
+ /** Get the appropriate cache for the type of pipeline */
3400
+ _getCache(pipeline) {
3401
+ let cache;
3402
+ if (pipeline instanceof ComputePipeline) {
3403
+ cache = this._computePipelineCache;
3404
+ }
3405
+ if (pipeline instanceof RenderPipeline) {
3406
+ cache = this._renderPipelineCache;
3407
+ }
3408
+ if (!cache) {
3409
+ throw new Error(`${this}`);
3410
+ }
3411
+ if (!cache[pipeline.hash]) {
3412
+ throw new Error(`${this}: ${pipeline} matched incorrect entry`);
3413
+ }
3414
+ return cache;
3415
+ }
3416
+ /** Calculate a hash based on all the inputs for a compute pipeline */
3417
+ _hashComputePipeline(props) {
3418
+ const { type } = this.device;
3419
+ const shaderHash = this._getHash(props.shader.source);
3420
+ const shaderLayoutHash = this._getHash(JSON.stringify(props.shaderLayout));
3421
+ return `${type}/C/${shaderHash}SL${shaderLayoutHash}`;
3422
+ }
3423
+ /** Calculate a hash based on all the inputs for a render pipeline */
3424
+ _hashRenderPipeline(props) {
3425
+ const vsHash = props.vs ? this._getHash(props.vs.source) : 0;
3426
+ const fsHash = props.fs ? this._getHash(props.fs.source) : 0;
3427
+ const varyingHash = this._getWebGLVaryingHash(props);
3428
+ const shaderLayoutHash = this._getHash(JSON.stringify(props.shaderLayout));
3429
+ const bufferLayoutHash = this._getHash(JSON.stringify(props.bufferLayout));
3430
+ const { type } = this.device;
3431
+ switch (type) {
3432
+ case "webgl":
3433
+ const webglParameterHash = this._getHash(JSON.stringify(props.parameters));
3434
+ return `${type}/R/${vsHash}/${fsHash}V${varyingHash}T${props.topology}P${webglParameterHash}SL${shaderLayoutHash}BL${bufferLayoutHash}`;
3435
+ case "webgpu":
3436
+ default:
3437
+ const entryPointHash = this._getHash(JSON.stringify({
3438
+ vertexEntryPoint: props.vertexEntryPoint,
3439
+ fragmentEntryPoint: props.fragmentEntryPoint
3440
+ }));
3441
+ const parameterHash = this._getHash(JSON.stringify(props.parameters));
3442
+ const attachmentHash = this._getWebGPUAttachmentHash(props);
3443
+ return `${type}/R/${vsHash}/${fsHash}V${varyingHash}T${props.topology}EP${entryPointHash}P${parameterHash}SL${shaderLayoutHash}BL${bufferLayoutHash}A${attachmentHash}`;
3444
+ }
3445
+ }
3446
+ // This is the only gate for shared `WebGLProgram` reuse.
3447
+ // Only include inputs that affect program linking or transform-feedback linkage.
3448
+ // Wrapper-only concerns such as topology, parameters, attachment formats and layout
3449
+ // overrides must not be added here.
3450
+ _hashSharedRenderPipeline(props) {
3451
+ const vsHash = props.vs ? this._getHash(props.vs.source) : 0;
3452
+ const fsHash = props.fs ? this._getHash(props.fs.source) : 0;
3453
+ const varyingHash = this._getWebGLVaryingHash(props);
3454
+ return `webgl/S/${vsHash}/${fsHash}V${varyingHash}`;
3455
+ }
3456
+ _getHash(key) {
3457
+ if (this._hashes[key] === void 0) {
3458
+ this._hashes[key] = this._hashCounter++;
3459
+ }
3460
+ return this._hashes[key];
3461
+ }
3462
+ _getWebGLVaryingHash(props) {
3463
+ const { varyings = [], bufferMode = null } = props;
3464
+ return this._getHash(JSON.stringify({ varyings, bufferMode }));
3465
+ }
3466
+ _getWebGPUAttachmentHash(props) {
3467
+ var _a;
3468
+ const colorAttachmentFormats = props.colorAttachmentFormats ?? [
3469
+ this.device.preferredColorFormat
3470
+ ];
3471
+ const depthStencilAttachmentFormat = ((_a = props.parameters) == null ? void 0 : _a.depthWriteEnabled) ? props.depthStencilAttachmentFormat || this.device.preferredDepthFormat : null;
3472
+ return this._getHash(JSON.stringify({
3473
+ colorAttachmentFormats,
3474
+ depthStencilAttachmentFormat
3475
+ }));
3476
+ }
3477
+ };
3478
+ var PipelineFactory = _PipelineFactory;
3479
+ __publicField(PipelineFactory, "defaultProps", { ...RenderPipeline.defaultProps });
3480
+
3481
+ // dist/factories/shader-factory.js
3482
+ var _ShaderFactory = class {
3483
+ /** Returns the default ShaderFactory for the given {@link Device}, creating one if necessary. */
3484
+ static getDefaultShaderFactory(device) {
3485
+ const moduleData = device.getModuleData("@luma.gl/core");
3486
+ moduleData.defaultShaderFactory ||= new _ShaderFactory(device);
3487
+ return moduleData.defaultShaderFactory;
3488
+ }
3489
+ device;
3490
+ _cache = {};
3491
+ get [Symbol.toStringTag]() {
3492
+ return "ShaderFactory";
3493
+ }
3494
+ toString() {
3495
+ return `${this[Symbol.toStringTag]}(${this.device.id})`;
3496
+ }
3497
+ /** @internal */
3498
+ constructor(device) {
3499
+ this.device = device;
3500
+ }
3501
+ /** Requests a {@link Shader} from the cache, creating a new Shader only if necessary. */
3502
+ createShader(props) {
3503
+ if (!this.device.props._cacheShaders) {
3504
+ return this.device.createShader(props);
3505
+ }
3506
+ const key = this._hashShader(props);
3507
+ let cacheEntry = this._cache[key];
3508
+ if (!cacheEntry) {
3509
+ const resource = this.device.createShader({
3510
+ ...props,
3511
+ id: props.id ? `${props.id}-cached` : void 0
3512
+ });
3513
+ this._cache[key] = cacheEntry = { resource, useCount: 1 };
3514
+ if (this.device.props.debugFactories) {
3515
+ log.log(3, `${this}: Created new shader ${resource.id}`)();
3516
+ }
3517
+ } else {
3518
+ cacheEntry.useCount++;
3519
+ if (this.device.props.debugFactories) {
3520
+ log.log(3, `${this}: Reusing shader ${cacheEntry.resource.id} count=${cacheEntry.useCount}`)();
3521
+ }
3522
+ }
3523
+ return cacheEntry.resource;
3524
+ }
3525
+ /** Releases a previously-requested {@link Shader}, destroying it if no users remain. */
3526
+ release(shader) {
3527
+ if (!this.device.props._cacheShaders) {
3528
+ shader.destroy();
3529
+ return;
3530
+ }
3531
+ const key = this._hashShader(shader);
3532
+ const cacheEntry = this._cache[key];
3533
+ if (cacheEntry) {
3534
+ cacheEntry.useCount--;
3535
+ if (cacheEntry.useCount === 0) {
3536
+ if (this.device.props._destroyShaders) {
3537
+ delete this._cache[key];
3538
+ cacheEntry.resource.destroy();
3539
+ if (this.device.props.debugFactories) {
3540
+ log.log(3, `${this}: Releasing shader ${shader.id}, destroyed`)();
3541
+ }
3542
+ }
3543
+ } else if (cacheEntry.useCount < 0) {
3544
+ throw new Error(`ShaderFactory: Shader ${shader.id} released too many times`);
3545
+ } else if (this.device.props.debugFactories) {
3546
+ log.log(3, `${this}: Releasing shader ${shader.id} count=${cacheEntry.useCount}`)();
3547
+ }
3548
+ }
3549
+ }
3550
+ // PRIVATE
3551
+ _hashShader(value) {
3552
+ return `${value.stage}:${value.source}`;
3553
+ }
3554
+ };
3555
+ var ShaderFactory = _ShaderFactory;
3556
+ __publicField(ShaderFactory, "defaultProps", { ...Shader.defaultProps });
3557
+
3558
+ // dist/adapter-utils/bind-groups.js
3559
+ function getShaderLayoutBinding(shaderLayout, bindingName, options) {
3560
+ const bindingLayout = shaderLayout.bindings.find((binding) => binding.name === bindingName || `${binding.name.toLocaleLowerCase()}uniforms` === bindingName.toLocaleLowerCase());
3561
+ if (!bindingLayout && !(options == null ? void 0 : options.ignoreWarnings)) {
3562
+ log.warn(`Binding ${bindingName} not set: Not found in shader layout.`)();
3563
+ }
3564
+ return bindingLayout || null;
3565
+ }
3566
+ function normalizeBindingsByGroup(shaderLayout, bindingsOrBindGroups) {
3567
+ if (!bindingsOrBindGroups) {
3568
+ return {};
3569
+ }
3570
+ if (areBindingsGrouped(bindingsOrBindGroups)) {
3571
+ const bindGroups2 = bindingsOrBindGroups;
3572
+ return Object.fromEntries(Object.entries(bindGroups2).map(([group, bindings]) => [Number(group), { ...bindings }]));
3573
+ }
3574
+ const bindGroups = {};
3575
+ for (const [bindingName, binding] of Object.entries(bindingsOrBindGroups)) {
3576
+ const bindingLayout = getShaderLayoutBinding(shaderLayout, bindingName);
3577
+ const group = (bindingLayout == null ? void 0 : bindingLayout.group) ?? 0;
3578
+ bindGroups[group] ||= {};
3579
+ bindGroups[group][bindingName] = binding;
3580
+ }
3581
+ return bindGroups;
3582
+ }
3583
+ function flattenBindingsByGroup(bindGroups) {
3584
+ const bindings = {};
3585
+ for (const groupBindings of Object.values(bindGroups)) {
3586
+ Object.assign(bindings, groupBindings);
3587
+ }
3588
+ return bindings;
3589
+ }
3590
+ function areBindingsGrouped(bindingsOrBindGroups) {
3591
+ const keys = Object.keys(bindingsOrBindGroups);
3592
+ return keys.length > 0 && keys.every((key) => /^\d+$/.test(key));
3593
+ }
3594
+
3595
+ // dist/factories/bind-group-factory.js
3596
+ var BindGroupFactory = class {
3597
+ device;
3598
+ _layoutCacheByPipeline = /* @__PURE__ */ new WeakMap();
3599
+ _bindGroupCacheByLayout = /* @__PURE__ */ new WeakMap();
3600
+ constructor(device) {
3601
+ this.device = device;
3602
+ }
3603
+ getBindGroups(pipeline, bindings, bindGroupCacheKeys) {
3604
+ if (this.device.type !== "webgpu" || pipeline.shaderLayout.bindings.length === 0) {
3605
+ return {};
3606
+ }
3607
+ const bindingsByGroup = normalizeBindingsByGroup(pipeline.shaderLayout, bindings);
3608
+ const resolvedBindGroups = {};
3609
+ for (const group of getBindGroupIndicesUpToMax(pipeline.shaderLayout.bindings)) {
3610
+ const groupBindings = bindingsByGroup[group];
3611
+ const bindGroupLayout = this._getBindGroupLayout(pipeline, group);
3612
+ if (!groupBindings || Object.keys(groupBindings).length === 0) {
3613
+ if (!hasBindingsInGroup(pipeline.shaderLayout.bindings, group)) {
3614
+ resolvedBindGroups[group] = this._getEmptyBindGroup(bindGroupLayout, pipeline.shaderLayout, group);
3615
+ }
3616
+ continue;
3617
+ }
3618
+ const bindGroupCacheKey = bindGroupCacheKeys == null ? void 0 : bindGroupCacheKeys[group];
3619
+ if (bindGroupCacheKey) {
3620
+ const layoutCache = this._getLayoutBindGroupCache(bindGroupLayout);
3621
+ if (layoutCache.bindGroupsBySource.has(bindGroupCacheKey)) {
3622
+ resolvedBindGroups[group] = layoutCache.bindGroupsBySource.get(bindGroupCacheKey) || null;
3623
+ continue;
3624
+ }
3625
+ const bindGroup = this.device._createBindGroupWebGPU(bindGroupLayout, pipeline.shaderLayout, groupBindings, group);
3626
+ layoutCache.bindGroupsBySource.set(bindGroupCacheKey, bindGroup);
3627
+ resolvedBindGroups[group] = bindGroup;
3628
+ } else {
3629
+ resolvedBindGroups[group] = this.device._createBindGroupWebGPU(bindGroupLayout, pipeline.shaderLayout, groupBindings, group);
3630
+ }
3631
+ }
3632
+ return resolvedBindGroups;
3633
+ }
3634
+ _getBindGroupLayout(pipeline, group) {
3635
+ let layoutCache = this._layoutCacheByPipeline.get(pipeline);
3636
+ if (!layoutCache) {
3637
+ layoutCache = {};
3638
+ this._layoutCacheByPipeline.set(pipeline, layoutCache);
3639
+ }
3640
+ layoutCache[group] ||= this.device._createBindGroupLayoutWebGPU(pipeline, group);
3641
+ return layoutCache[group];
3642
+ }
3643
+ _getEmptyBindGroup(bindGroupLayout, shaderLayout, group) {
3644
+ const layoutCache = this._getLayoutBindGroupCache(bindGroupLayout);
3645
+ layoutCache.emptyBindGroup ||= this.device._createBindGroupWebGPU(bindGroupLayout, shaderLayout, {}, group) || null;
3646
+ return layoutCache.emptyBindGroup;
3647
+ }
3648
+ _getLayoutBindGroupCache(bindGroupLayout) {
3649
+ let layoutCache = this._bindGroupCacheByLayout.get(bindGroupLayout);
3650
+ if (!layoutCache) {
3651
+ layoutCache = { bindGroupsBySource: /* @__PURE__ */ new WeakMap() };
3652
+ this._bindGroupCacheByLayout.set(bindGroupLayout, layoutCache);
3653
+ }
3654
+ return layoutCache;
3655
+ }
3656
+ };
3657
+ function _getDefaultBindGroupFactory(device) {
3658
+ device._factories.bindGroupFactory ||= new BindGroupFactory(device);
3659
+ return device._factories.bindGroupFactory;
3660
+ }
3661
+ function getBindGroupIndicesUpToMax(bindings) {
3662
+ const maxGroup = bindings.reduce((highestGroup, binding) => Math.max(highestGroup, binding.group), -1);
3663
+ return Array.from({ length: maxGroup + 1 }, (_, group) => group);
3664
+ }
3665
+ function hasBindingsInGroup(bindings, group) {
3666
+ return bindings.some((binding) => binding.group === group);
3667
+ }
3668
+
3669
+ // dist/adapter/resources/render-pass.js
3670
+ var _RenderPass = class extends Resource {
3671
+ get [Symbol.toStringTag]() {
3672
+ return "RenderPass";
3673
+ }
3674
+ constructor(device, props) {
3675
+ props = _RenderPass.normalizeProps(device, props);
3676
+ super(device, props, _RenderPass.defaultProps);
3677
+ }
3678
+ static normalizeProps(device, props) {
3679
+ return props;
3680
+ }
3681
+ };
3682
+ var RenderPass = _RenderPass;
3683
+ /** TODO - should be [0, 0, 0, 0], update once deck.gl tests run clean */
3684
+ __publicField(RenderPass, "defaultClearColor", [0, 0, 0, 1]);
3685
+ /** Depth 1.0 represents the far plance */
3686
+ __publicField(RenderPass, "defaultClearDepth", 1);
3687
+ /** Clears all stencil bits */
3688
+ __publicField(RenderPass, "defaultClearStencil", 0);
3689
+ /** Default properties for RenderPass */
3690
+ __publicField(RenderPass, "defaultProps", {
3691
+ ...Resource.defaultProps,
3692
+ framebuffer: null,
3693
+ parameters: void 0,
3694
+ clearColor: _RenderPass.defaultClearColor,
3695
+ clearColors: void 0,
3696
+ clearDepth: _RenderPass.defaultClearDepth,
3697
+ clearStencil: _RenderPass.defaultClearStencil,
3698
+ depthReadOnly: false,
3699
+ stencilReadOnly: false,
3700
+ discard: false,
3701
+ occlusionQuerySet: void 0,
3702
+ timestampQuerySet: void 0,
3703
+ beginTimestampIndex: void 0,
3704
+ endTimestampIndex: void 0
3705
+ });
3706
+
3707
+ // dist/adapter/resources/compute-pass.js
3708
+ var _ComputePass = class extends Resource {
3709
+ constructor(device, props) {
3710
+ super(device, props, _ComputePass.defaultProps);
3711
+ }
3712
+ get [Symbol.toStringTag]() {
3713
+ return "ComputePass";
3714
+ }
3715
+ };
3716
+ var ComputePass = _ComputePass;
3717
+ __publicField(ComputePass, "defaultProps", {
3718
+ ...Resource.defaultProps,
3719
+ timestampQuerySet: void 0,
3720
+ beginTimestampIndex: void 0,
3721
+ endTimestampIndex: void 0
3722
+ });
3723
+
3724
+ // dist/adapter/resources/command-encoder.js
3725
+ var _CommandEncoder = class extends Resource {
3726
+ get [Symbol.toStringTag]() {
3727
+ return "CommandEncoder";
3728
+ }
3729
+ _timeProfilingQuerySet = null;
3730
+ _timeProfilingSlotCount = 0;
3731
+ _gpuTimeMs;
3732
+ constructor(device, props) {
3733
+ super(device, props, _CommandEncoder.defaultProps);
3734
+ this._timeProfilingQuerySet = props.timeProfilingQuerySet ?? null;
3735
+ this._timeProfilingSlotCount = 0;
3736
+ this._gpuTimeMs = void 0;
3737
+ }
3738
+ /**
3739
+ * Reads all resolved timestamp pairs on the current profiler query set and caches the sum
3740
+ * as milliseconds on this encoder.
3741
+ */
3742
+ async resolveTimeProfilingQuerySet() {
3743
+ this._gpuTimeMs = void 0;
3744
+ if (!this._timeProfilingQuerySet) {
3745
+ return;
3746
+ }
3747
+ const pairCount = Math.floor(this._timeProfilingSlotCount / 2);
3748
+ if (pairCount <= 0) {
3749
+ return;
3750
+ }
3751
+ const queryCount = pairCount * 2;
3752
+ const results = await this._timeProfilingQuerySet.readResults({
3753
+ firstQuery: 0,
3754
+ queryCount
3755
+ });
3756
+ let totalDurationNanoseconds = 0n;
3757
+ for (let queryIndex = 0; queryIndex < queryCount; queryIndex += 2) {
3758
+ totalDurationNanoseconds += results[queryIndex + 1] - results[queryIndex];
3759
+ }
3760
+ this._gpuTimeMs = Number(totalDurationNanoseconds) / 1e6;
3761
+ }
3762
+ /** Returns the number of query slots consumed by automatic pass profiling on this encoder. */
3763
+ getTimeProfilingSlotCount() {
3764
+ return this._timeProfilingSlotCount;
3765
+ }
3766
+ getTimeProfilingQuerySet() {
3767
+ return this._timeProfilingQuerySet;
3768
+ }
3769
+ /** Internal helper for auto-assigning timestamp slots to render/compute passes on this encoder. */
3770
+ _applyTimeProfilingToPassProps(props) {
3771
+ const passProps = props || {};
3772
+ if (!this._supportsTimestampQueries() || !this._timeProfilingQuerySet) {
3773
+ return passProps;
3774
+ }
3775
+ if (passProps.timestampQuerySet !== void 0 || passProps.beginTimestampIndex !== void 0 || passProps.endTimestampIndex !== void 0) {
3776
+ return passProps;
3777
+ }
3778
+ const beginTimestampIndex = this._timeProfilingSlotCount;
3779
+ if (beginTimestampIndex + 1 >= this._timeProfilingQuerySet.props.count) {
3780
+ return passProps;
3781
+ }
3782
+ this._timeProfilingSlotCount += 2;
3783
+ return {
3784
+ ...passProps,
3785
+ timestampQuerySet: this._timeProfilingQuerySet,
3786
+ beginTimestampIndex,
3787
+ endTimestampIndex: beginTimestampIndex + 1
3788
+ };
3789
+ }
3790
+ _supportsTimestampQueries() {
3791
+ return this.device.features.has("timestamp-query");
3792
+ }
3793
+ };
3794
+ var CommandEncoder = _CommandEncoder;
3795
+ // TODO - luma.gl has these on the device, should we align with WebGPU API?
3796
+ // beginRenderPass(GPURenderPassDescriptor descriptor): GPURenderPassEncoder;
3797
+ // beginComputePass(optional GPUComputePassDescriptor descriptor = {}): GPUComputePassEncoder;
3798
+ __publicField(CommandEncoder, "defaultProps", {
3799
+ ...Resource.defaultProps,
3800
+ measureExecutionTime: void 0,
3801
+ timeProfilingQuerySet: void 0
3802
+ });
3803
+
3804
+ // dist/adapter/resources/command-buffer.js
3805
+ var _CommandBuffer = class extends Resource {
3806
+ get [Symbol.toStringTag]() {
3807
+ return "CommandBuffer";
3808
+ }
3809
+ constructor(device, props) {
3810
+ super(device, props, _CommandBuffer.defaultProps);
3811
+ }
3812
+ };
3813
+ var CommandBuffer = _CommandBuffer;
2369
3814
  __publicField(CommandBuffer, "defaultProps", {
2370
3815
  ...Resource.defaultProps
2371
3816
  });
2372
3817
 
2373
- // dist/shadertypes/data-types/decode-shader-types.js
3818
+ // dist/shadertypes/shader-types/shader-type-decoder.js
2374
3819
  function getVariableShaderTypeInfo(format) {
2375
- const decoded = UNIFORM_FORMATS[format];
3820
+ const resolvedFormat = resolveVariableShaderTypeAlias(format);
3821
+ const decoded = UNIFORM_FORMATS[resolvedFormat];
3822
+ if (!decoded) {
3823
+ throw new Error(`Unsupported variable shader type: ${format}`);
3824
+ }
2376
3825
  return decoded;
2377
3826
  }
2378
3827
  function getAttributeShaderTypeInfo(attributeType) {
2379
- const [primitiveType, components] = TYPE_INFO[attributeType];
3828
+ const resolvedAttributeType = resolveAttributeShaderTypeAlias(attributeType);
3829
+ const decoded = TYPE_INFO[resolvedAttributeType];
3830
+ if (!decoded) {
3831
+ throw new Error(`Unsupported attribute shader type: ${attributeType}`);
3832
+ }
3833
+ const [primitiveType, components] = decoded;
2380
3834
  const integer = primitiveType === "i32" || primitiveType === "u32";
2381
3835
  const signed = primitiveType !== "u32";
2382
3836
  const byteLength = PRIMITIVE_TYPE_SIZES[primitiveType] * components;
@@ -2388,6 +3842,33 @@ function getAttributeShaderTypeInfo(attributeType) {
2388
3842
  signed
2389
3843
  };
2390
3844
  }
3845
+ var ShaderTypeDecoder = class {
3846
+ getVariableShaderTypeInfo(format) {
3847
+ return getVariableShaderTypeInfo(format);
3848
+ }
3849
+ getAttributeShaderTypeInfo(attributeType) {
3850
+ return getAttributeShaderTypeInfo(attributeType);
3851
+ }
3852
+ makeShaderAttributeType(primitiveType, components) {
3853
+ return makeShaderAttributeType(primitiveType, components);
3854
+ }
3855
+ resolveAttributeShaderTypeAlias(alias) {
3856
+ return resolveAttributeShaderTypeAlias(alias);
3857
+ }
3858
+ resolveVariableShaderTypeAlias(alias) {
3859
+ return resolveVariableShaderTypeAlias(alias);
3860
+ }
3861
+ };
3862
+ function makeShaderAttributeType(primitiveType, components) {
3863
+ return components === 1 ? primitiveType : `vec${components}<${primitiveType}>`;
3864
+ }
3865
+ function resolveAttributeShaderTypeAlias(alias) {
3866
+ return WGSL_ATTRIBUTE_TYPE_ALIAS_MAP[alias] || alias;
3867
+ }
3868
+ function resolveVariableShaderTypeAlias(alias) {
3869
+ return WGSL_VARIABLE_TYPE_ALIAS_MAP[alias] || alias;
3870
+ }
3871
+ var shaderTypeDecoder = new ShaderTypeDecoder();
2391
3872
  var PRIMITIVE_TYPE_SIZES = {
2392
3873
  f32: 4,
2393
3874
  f16: 2,
@@ -2484,7 +3965,18 @@ var WGSL_ATTRIBUTE_TYPE_ALIAS_MAP = {
2484
3965
  vec4h: "vec4<f16>"
2485
3966
  };
2486
3967
  var WGSL_VARIABLE_TYPE_ALIAS_MAP = {
2487
- ...WGSL_ATTRIBUTE_TYPE_ALIAS_MAP,
3968
+ vec2i: "vec2<i32>",
3969
+ vec3i: "vec3<i32>",
3970
+ vec4i: "vec4<i32>",
3971
+ vec2u: "vec2<u32>",
3972
+ vec3u: "vec3<u32>",
3973
+ vec4u: "vec4<u32>",
3974
+ vec2f: "vec2<f32>",
3975
+ vec3f: "vec3<f32>",
3976
+ vec4f: "vec4<f32>",
3977
+ vec2h: "vec2<f16>",
3978
+ vec3h: "vec3<f16>",
3979
+ vec4h: "vec4<f16>",
2488
3980
  mat2x2f: "mat2x2<f32>",
2489
3981
  mat2x3f: "mat2x3<f32>",
2490
3982
  mat2x4f: "mat2x4<f32>",
@@ -2548,10 +4040,10 @@ function getAttributeInfoFromLayouts(shaderLayout, bufferLayout, name2) {
2548
4040
  if (!shaderDeclaration) {
2549
4041
  return null;
2550
4042
  }
2551
- const attributeTypeInfo = getAttributeShaderTypeInfo(shaderDeclaration.type);
2552
- const defaultVertexFormat = getCompatibleVertexFormat(attributeTypeInfo);
4043
+ const attributeTypeInfo = shaderTypeDecoder.getAttributeShaderTypeInfo(shaderDeclaration.type);
4044
+ const defaultVertexFormat = vertexFormatDecoder.getCompatibleVertexFormat(attributeTypeInfo);
2553
4045
  const vertexFormat = (bufferMapping == null ? void 0 : bufferMapping.vertexFormat) || defaultVertexFormat;
2554
- const vertexFormatInfo = getVertexFormatInfo(vertexFormat);
4046
+ const vertexFormatInfo = vertexFormatDecoder.getVertexFormatInfo(vertexFormat);
2555
4047
  return {
2556
4048
  attributeName: (bufferMapping == null ? void 0 : bufferMapping.attributeName) || shaderDeclaration.name,
2557
4049
  bufferName: (bufferMapping == null ? void 0 : bufferMapping.bufferName) || shaderDeclaration.name,
@@ -2620,7 +4112,7 @@ function getAttributeFromAttributesList(bufferLayouts, name2) {
2620
4112
  let byteStride = bufferLayout.byteStride;
2621
4113
  if (typeof bufferLayout.byteStride !== "number") {
2622
4114
  for (const attributeMapping2 of bufferLayout.attributes || []) {
2623
- const info = getVertexFormatInfo(attributeMapping2.format);
4115
+ const info = vertexFormatDecoder.getVertexFormatInfo(attributeMapping2.format);
2624
4116
  byteStride += info.byteLength;
2625
4117
  }
2626
4118
  }
@@ -2704,6 +4196,20 @@ __publicField(QuerySet, "defaultProps", {
2704
4196
  count: void 0
2705
4197
  });
2706
4198
 
4199
+ // dist/adapter/resources/fence.js
4200
+ var _Fence = class extends Resource {
4201
+ get [Symbol.toStringTag]() {
4202
+ return "Fence";
4203
+ }
4204
+ constructor(device, props = {}) {
4205
+ super(device, props, _Fence.defaultProps);
4206
+ }
4207
+ };
4208
+ var Fence = _Fence;
4209
+ __publicField(Fence, "defaultProps", {
4210
+ ...Resource.defaultProps
4211
+ });
4212
+
2707
4213
  // dist/adapter/resources/pipeline-layout.js
2708
4214
  var _PipelineLayout = class extends Resource {
2709
4215
  get [Symbol.toStringTag]() {
@@ -2722,6 +4228,190 @@ __publicField(PipelineLayout, "defaultProps", {
2722
4228
  }
2723
4229
  });
2724
4230
 
4231
+ // dist/shadertypes/data-types/decode-data-types.js
4232
+ function alignTo(size, count) {
4233
+ switch (count) {
4234
+ case 1:
4235
+ return size;
4236
+ case 2:
4237
+ return size + size % 2;
4238
+ default:
4239
+ return size + (4 - size % 4) % 4;
4240
+ }
4241
+ }
4242
+ function getTypedArrayConstructor(type) {
4243
+ const [, , , , Constructor] = NORMALIZED_TYPE_MAP2[type];
4244
+ return Constructor;
4245
+ }
4246
+ var NORMALIZED_TYPE_MAP2 = {
4247
+ uint8: ["uint8", "u32", 1, false, Uint8Array],
4248
+ sint8: ["sint8", "i32", 1, false, Int8Array],
4249
+ unorm8: ["uint8", "f32", 1, true, Uint8Array],
4250
+ snorm8: ["sint8", "f32", 1, true, Int8Array],
4251
+ uint16: ["uint16", "u32", 2, false, Uint16Array],
4252
+ sint16: ["sint16", "i32", 2, false, Int16Array],
4253
+ unorm16: ["uint16", "u32", 2, true, Uint16Array],
4254
+ snorm16: ["sint16", "i32", 2, true, Int16Array],
4255
+ float16: ["float16", "f16", 2, false, Uint16Array],
4256
+ float32: ["float32", "f32", 4, false, Float32Array],
4257
+ uint32: ["uint32", "u32", 4, false, Uint32Array],
4258
+ sint32: ["sint32", "i32", 4, false, Int32Array]
4259
+ };
4260
+
4261
+ // dist/shadertypes/shader-types/shader-block-layout.js
4262
+ function makeShaderBlockLayout(uniformTypes, options = {}) {
4263
+ const copiedUniformTypes = { ...uniformTypes };
4264
+ const layout = options.layout ?? "std140";
4265
+ const fields = {};
4266
+ let size = 0;
4267
+ for (const [key, uniformType] of Object.entries(copiedUniformTypes)) {
4268
+ size = addToLayout(fields, key, uniformType, size, layout);
4269
+ }
4270
+ size = alignTo(size, getTypeAlignment(copiedUniformTypes, layout));
4271
+ return {
4272
+ layout,
4273
+ byteLength: size * 4,
4274
+ uniformTypes: copiedUniformTypes,
4275
+ fields
4276
+ };
4277
+ }
4278
+ function getLeafLayoutInfo(type, layout) {
4279
+ const resolvedType = resolveVariableShaderTypeAlias(type);
4280
+ const decodedType = getVariableShaderTypeInfo(resolvedType);
4281
+ const matrixMatch = /^mat(\d)x(\d)<.+>$/.exec(resolvedType);
4282
+ if (matrixMatch) {
4283
+ const columns = Number(matrixMatch[1]);
4284
+ const rows = Number(matrixMatch[2]);
4285
+ const columnInfo = getVectorLayoutInfo(rows, resolvedType, decodedType.type, layout);
4286
+ const columnStride = getMatrixColumnStride(columnInfo.size, columnInfo.alignment, layout);
4287
+ return {
4288
+ alignment: columnInfo.alignment,
4289
+ size: columns * columnStride,
4290
+ components: columns * rows,
4291
+ columns,
4292
+ rows,
4293
+ columnStride,
4294
+ shaderType: resolvedType,
4295
+ type: decodedType.type
4296
+ };
4297
+ }
4298
+ const vectorMatch = /^vec(\d)<.+>$/.exec(resolvedType);
4299
+ if (vectorMatch) {
4300
+ return getVectorLayoutInfo(Number(vectorMatch[1]), resolvedType, decodedType.type, layout);
4301
+ }
4302
+ return {
4303
+ alignment: 1,
4304
+ size: 1,
4305
+ components: 1,
4306
+ columns: 1,
4307
+ rows: 1,
4308
+ columnStride: 1,
4309
+ shaderType: resolvedType,
4310
+ type: decodedType.type
4311
+ };
4312
+ }
4313
+ function isCompositeShaderTypeStruct(value) {
4314
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
4315
+ }
4316
+ function addToLayout(fields, name2, type, offset, layout) {
4317
+ if (typeof type === "string") {
4318
+ const info = getLeafLayoutInfo(type, layout);
4319
+ const alignedOffset = alignTo(offset, info.alignment);
4320
+ fields[name2] = {
4321
+ offset: alignedOffset,
4322
+ ...info
4323
+ };
4324
+ return alignedOffset + info.size;
4325
+ }
4326
+ if (Array.isArray(type)) {
4327
+ if (Array.isArray(type[0])) {
4328
+ throw new Error(`Nested arrays are not supported for ${name2}`);
4329
+ }
4330
+ const elementType = type[0];
4331
+ const length = type[1];
4332
+ const stride = getArrayStride(elementType, layout);
4333
+ const arrayOffset = alignTo(offset, getTypeAlignment(type, layout));
4334
+ for (let i = 0; i < length; i++) {
4335
+ addToLayout(fields, `${name2}[${i}]`, elementType, arrayOffset + i * stride, layout);
4336
+ }
4337
+ return arrayOffset + stride * length;
4338
+ }
4339
+ if (isCompositeShaderTypeStruct(type)) {
4340
+ const structAlignment = getTypeAlignment(type, layout);
4341
+ let structOffset = alignTo(offset, structAlignment);
4342
+ for (const [memberName, memberType] of Object.entries(type)) {
4343
+ structOffset = addToLayout(fields, `${name2}.${memberName}`, memberType, structOffset, layout);
4344
+ }
4345
+ return alignTo(structOffset, structAlignment);
4346
+ }
4347
+ throw new Error(`Unsupported CompositeShaderType for ${name2}`);
4348
+ }
4349
+ function getTypeSize(type, layout) {
4350
+ if (typeof type === "string") {
4351
+ return getLeafLayoutInfo(type, layout).size;
4352
+ }
4353
+ if (Array.isArray(type)) {
4354
+ const elementType = type[0];
4355
+ const length = type[1];
4356
+ if (Array.isArray(elementType)) {
4357
+ throw new Error("Nested arrays are not supported");
4358
+ }
4359
+ return getArrayStride(elementType, layout) * length;
4360
+ }
4361
+ let size = 0;
4362
+ for (const memberType of Object.values(type)) {
4363
+ const compositeMemberType = memberType;
4364
+ size = alignTo(size, getTypeAlignment(compositeMemberType, layout));
4365
+ size += getTypeSize(compositeMemberType, layout);
4366
+ }
4367
+ return alignTo(size, getTypeAlignment(type, layout));
4368
+ }
4369
+ function getTypeAlignment(type, layout) {
4370
+ if (typeof type === "string") {
4371
+ return getLeafLayoutInfo(type, layout).alignment;
4372
+ }
4373
+ if (Array.isArray(type)) {
4374
+ const elementType = type[0];
4375
+ const elementAlignment = getTypeAlignment(elementType, layout);
4376
+ return uses16ByteArrayAlignment(layout) ? Math.max(elementAlignment, 4) : elementAlignment;
4377
+ }
4378
+ let maxAlignment = 1;
4379
+ for (const memberType of Object.values(type)) {
4380
+ const memberAlignment = getTypeAlignment(memberType, layout);
4381
+ maxAlignment = Math.max(maxAlignment, memberAlignment);
4382
+ }
4383
+ return uses16ByteStructAlignment(layout) ? Math.max(maxAlignment, 4) : maxAlignment;
4384
+ }
4385
+ function getVectorLayoutInfo(components, shaderType, type, layout) {
4386
+ return {
4387
+ alignment: components === 2 ? 2 : 4,
4388
+ size: components === 3 ? 3 : components,
4389
+ components,
4390
+ columns: 1,
4391
+ rows: components,
4392
+ columnStride: components === 3 ? 3 : components,
4393
+ shaderType,
4394
+ type
4395
+ };
4396
+ }
4397
+ function getArrayStride(elementType, layout) {
4398
+ const elementSize = getTypeSize(elementType, layout);
4399
+ const elementAlignment = getTypeAlignment(elementType, layout);
4400
+ return getArrayLikeStride(elementSize, elementAlignment, layout);
4401
+ }
4402
+ function getArrayLikeStride(size, alignment, layout) {
4403
+ return alignTo(size, uses16ByteArrayAlignment(layout) ? 4 : alignment);
4404
+ }
4405
+ function getMatrixColumnStride(size, alignment, layout) {
4406
+ return layout === "std140" ? 4 : alignTo(size, alignment);
4407
+ }
4408
+ function uses16ByteArrayAlignment(layout) {
4409
+ return layout === "std140" || layout === "wgsl-uniform";
4410
+ }
4411
+ function uses16ByteStructAlignment(layout) {
4412
+ return layout === "std140" || layout === "wgsl-uniform";
4413
+ }
4414
+
2725
4415
  // dist/utils/array-utils-flat.js
2726
4416
  var arrayBuffer;
2727
4417
  function getScratchArrayBuffer(byteLength) {
@@ -2746,88 +4436,192 @@ function isNumberArray(value) {
2746
4436
  return isTypedArray(value);
2747
4437
  }
2748
4438
 
2749
- // dist/portable/uniform-buffer-layout.js
2750
- var minBufferSize = 1024;
2751
- var UniformBufferLayout = class {
2752
- layout = {};
2753
- /** number of bytes needed for buffer allocation */
2754
- byteLength;
2755
- /** Create a new UniformBufferLayout given a map of attributes. */
2756
- constructor(uniformTypes, uniformSizes = {}) {
2757
- let size = 0;
2758
- for (const [key, uniformType] of Object.entries(uniformTypes)) {
2759
- const typeAndComponents = getVariableShaderTypeInfo(uniformType);
2760
- const { type, components } = typeAndComponents;
2761
- const count = components * ((uniformSizes == null ? void 0 : uniformSizes[key]) ?? 1);
2762
- size = alignTo(size, count);
2763
- const offset = size;
2764
- size += count;
2765
- this.layout[key] = { type, size: count, offset };
2766
- }
2767
- size += (4 - size % 4) % 4;
2768
- const actualByteLength = size * 4;
2769
- this.byteLength = Math.max(actualByteLength, minBufferSize);
2770
- }
2771
- /** Get the data for the complete buffer */
4439
+ // dist/portable/shader-block-writer.js
4440
+ var ShaderBlockWriter = class {
4441
+ /** Layout metadata used to flatten and serialize values. */
4442
+ layout;
4443
+ /**
4444
+ * Creates a writer for a precomputed shader-block layout.
4445
+ */
4446
+ constructor(layout) {
4447
+ this.layout = layout;
4448
+ }
4449
+ /**
4450
+ * Returns `true` if the flattened layout contains the given field.
4451
+ */
4452
+ has(name2) {
4453
+ return Boolean(this.layout.fields[name2]);
4454
+ }
4455
+ /**
4456
+ * Returns offset and size metadata for a flattened field.
4457
+ */
4458
+ get(name2) {
4459
+ const entry = this.layout.fields[name2];
4460
+ return entry ? { offset: entry.offset, size: entry.size } : void 0;
4461
+ }
4462
+ /**
4463
+ * Flattens nested composite values into leaf-path values understood by {@link UniformBlock}.
4464
+ *
4465
+ * Top-level values may be supplied either in nested object form matching the
4466
+ * declared composite shader types or as already-flattened leaf-path values.
4467
+ */
4468
+ getFlatUniformValues(uniformValues) {
4469
+ const flattenedUniformValues = {};
4470
+ for (const [name2, value] of Object.entries(uniformValues)) {
4471
+ const uniformType = this.layout.uniformTypes[name2];
4472
+ if (uniformType) {
4473
+ this._flattenCompositeValue(flattenedUniformValues, name2, uniformType, value);
4474
+ } else if (this.layout.fields[name2]) {
4475
+ flattenedUniformValues[name2] = value;
4476
+ }
4477
+ }
4478
+ return flattenedUniformValues;
4479
+ }
4480
+ /**
4481
+ * Serializes the supplied values into buffer-backed binary data.
4482
+ *
4483
+ * The returned view length matches {@link ShaderBlockLayout.byteLength}, which
4484
+ * is the exact packed size of the block.
4485
+ */
2772
4486
  getData(uniformValues) {
2773
- const arrayBuffer2 = getScratchArrayBuffer(this.byteLength);
4487
+ const buffer = getScratchArrayBuffer(this.layout.byteLength);
4488
+ new Uint8Array(buffer, 0, this.layout.byteLength).fill(0);
2774
4489
  const typedArrays = {
2775
- i32: new Int32Array(arrayBuffer2),
2776
- u32: new Uint32Array(arrayBuffer2),
2777
- f32: new Float32Array(arrayBuffer2),
2778
- // TODO not implemented
2779
- f16: new Uint16Array(arrayBuffer2)
4490
+ i32: new Int32Array(buffer),
4491
+ u32: new Uint32Array(buffer),
4492
+ f32: new Float32Array(buffer),
4493
+ f16: new Uint16Array(buffer)
2780
4494
  };
2781
- for (const [name2, value] of Object.entries(uniformValues)) {
2782
- const uniformLayout = this.layout[name2];
2783
- if (!uniformLayout) {
2784
- log.warn(`Supplied uniform value ${name2} not present in uniform block layout`)();
2785
- continue;
4495
+ const flattenedUniformValues = this.getFlatUniformValues(uniformValues);
4496
+ for (const [name2, value] of Object.entries(flattenedUniformValues)) {
4497
+ this._writeLeafValue(typedArrays, name2, value);
4498
+ }
4499
+ return new Uint8Array(buffer, 0, this.layout.byteLength);
4500
+ }
4501
+ /**
4502
+ * Recursively flattens nested values using the declared composite shader type.
4503
+ */
4504
+ _flattenCompositeValue(flattenedUniformValues, baseName, uniformType, value) {
4505
+ if (value === void 0) {
4506
+ return;
4507
+ }
4508
+ if (typeof uniformType === "string" || this.layout.fields[baseName]) {
4509
+ flattenedUniformValues[baseName] = value;
4510
+ return;
4511
+ }
4512
+ if (Array.isArray(uniformType)) {
4513
+ const elementType = uniformType[0];
4514
+ const length = uniformType[1];
4515
+ if (Array.isArray(elementType)) {
4516
+ throw new Error(`Nested arrays are not supported for ${baseName}`);
4517
+ }
4518
+ if (typeof elementType === "string" && isNumberArray(value)) {
4519
+ this._flattenPackedArray(flattenedUniformValues, baseName, elementType, length, value);
4520
+ return;
4521
+ }
4522
+ if (!Array.isArray(value)) {
4523
+ log.warn(`Unsupported uniform array value for ${baseName}:`, value)();
4524
+ return;
2786
4525
  }
2787
- const { type, size, offset } = uniformLayout;
2788
- const typedArray = typedArrays[type];
2789
- if (size === 1) {
2790
- if (typeof value !== "number" && typeof value !== "boolean") {
2791
- log.warn(`Supplied value for single component uniform ${name2} is not a number: ${value}`)();
4526
+ for (let index = 0; index < Math.min(value.length, length); index++) {
4527
+ const elementValue = value[index];
4528
+ if (elementValue === void 0) {
2792
4529
  continue;
2793
4530
  }
2794
- typedArray[offset] = Number(value);
2795
- } else {
2796
- if (!isNumberArray(value)) {
2797
- log.warn(`Supplied value for multi component / array uniform ${name2} is not a numeric array: ${value}`)();
4531
+ this._flattenCompositeValue(flattenedUniformValues, `${baseName}[${index}]`, elementType, elementValue);
4532
+ }
4533
+ return;
4534
+ }
4535
+ if (isCompositeShaderTypeStruct(uniformType) && isCompositeUniformObject(value)) {
4536
+ for (const [key, subValue] of Object.entries(value)) {
4537
+ if (subValue === void 0) {
2798
4538
  continue;
2799
4539
  }
2800
- typedArray.set(value, offset);
4540
+ const nestedName = `${baseName}.${key}`;
4541
+ this._flattenCompositeValue(flattenedUniformValues, nestedName, uniformType[key], subValue);
2801
4542
  }
4543
+ return;
2802
4544
  }
2803
- return new Uint8Array(arrayBuffer2, 0, this.byteLength);
4545
+ log.warn(`Unsupported uniform value for ${baseName}:`, value)();
2804
4546
  }
2805
- /** Does this layout have a field with specified name */
2806
- has(name2) {
2807
- return Boolean(this.layout[name2]);
4547
+ /**
4548
+ * Expands tightly packed numeric arrays into per-element leaf fields.
4549
+ */
4550
+ _flattenPackedArray(flattenedUniformValues, baseName, elementType, length, value) {
4551
+ const numericValue = value;
4552
+ const elementLayout = getLeafLayoutInfo(elementType, this.layout.layout);
4553
+ const packedElementLength = elementLayout.components;
4554
+ for (let index = 0; index < length; index++) {
4555
+ const start = index * packedElementLength;
4556
+ if (start >= numericValue.length) {
4557
+ break;
4558
+ }
4559
+ if (packedElementLength === 1) {
4560
+ flattenedUniformValues[`${baseName}[${index}]`] = Number(numericValue[start]);
4561
+ } else {
4562
+ flattenedUniformValues[`${baseName}[${index}]`] = sliceNumericArray(value, start, start + packedElementLength);
4563
+ }
4564
+ }
2808
4565
  }
2809
- /** Get offset and size for a field with specified name */
2810
- get(name2) {
2811
- const layout = this.layout[name2];
2812
- return layout;
4566
+ /**
4567
+ * Writes one flattened leaf value into its typed-array view.
4568
+ */
4569
+ _writeLeafValue(typedArrays, name2, value) {
4570
+ const entry = this.layout.fields[name2];
4571
+ if (!entry) {
4572
+ log.warn(`Uniform ${name2} not found in layout`)();
4573
+ return;
4574
+ }
4575
+ const { type, components, columns, rows, offset, columnStride } = entry;
4576
+ const array = typedArrays[type];
4577
+ if (components === 1) {
4578
+ array[offset] = Number(value);
4579
+ return;
4580
+ }
4581
+ const sourceValue = value;
4582
+ if (columns === 1) {
4583
+ for (let componentIndex = 0; componentIndex < components; componentIndex++) {
4584
+ array[offset + componentIndex] = Number(sourceValue[componentIndex] ?? 0);
4585
+ }
4586
+ return;
4587
+ }
4588
+ let sourceIndex = 0;
4589
+ for (let columnIndex = 0; columnIndex < columns; columnIndex++) {
4590
+ const columnOffset = offset + columnIndex * columnStride;
4591
+ for (let rowIndex = 0; rowIndex < rows; rowIndex++) {
4592
+ array[columnOffset + rowIndex] = Number(sourceValue[sourceIndex++] ?? 0);
4593
+ }
4594
+ }
2813
4595
  }
2814
4596
  };
4597
+ function isCompositeUniformObject(value) {
4598
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value) && !ArrayBuffer.isView(value);
4599
+ }
4600
+ function sliceNumericArray(value, start, end) {
4601
+ return Array.prototype.slice.call(value, start, end);
4602
+ }
2815
4603
 
2816
4604
  // dist/utils/array-equal.js
4605
+ var MAX_ELEMENTWISE_ARRAY_COMPARE_LENGTH = 128;
2817
4606
  function arrayEqual(a, b, limit = 16) {
2818
- if (a !== b) {
2819
- return false;
4607
+ if (a === b) {
4608
+ return true;
2820
4609
  }
2821
4610
  const arrayA = a;
2822
4611
  const arrayB = b;
2823
- if (!isNumberArray(arrayA)) {
4612
+ if (!isNumberArray(arrayA) || !isNumberArray(arrayB)) {
2824
4613
  return false;
2825
4614
  }
2826
- if (isNumberArray(arrayB) && arrayA.length === arrayB.length) {
2827
- for (let i = 0; i < arrayA.length; ++i) {
2828
- if (arrayB[i] !== arrayA[i]) {
2829
- return false;
2830
- }
4615
+ if (arrayA.length !== arrayB.length) {
4616
+ return false;
4617
+ }
4618
+ const maxCompareLength = Math.min(limit, MAX_ELEMENTWISE_ARRAY_COMPARE_LENGTH);
4619
+ if (arrayA.length > maxCompareLength) {
4620
+ return false;
4621
+ }
4622
+ for (let i = 0; i < arrayA.length; ++i) {
4623
+ if (arrayB[i] !== arrayA[i]) {
4624
+ return false;
2831
4625
  }
2832
4626
  }
2833
4627
  return true;
@@ -2891,24 +4685,33 @@ var UniformBlock = class {
2891
4685
  };
2892
4686
 
2893
4687
  // dist/portable/uniform-store.js
4688
+ var minUniformBufferSize = 1024;
2894
4689
  var UniformStore = class {
4690
+ /** Device used to infer layout and allocate buffers. */
4691
+ device;
2895
4692
  /** Stores the uniform values for each uniform block */
2896
4693
  uniformBlocks = /* @__PURE__ */ new Map();
2897
- /** Can generate data for a uniform buffer for each block from data */
2898
- uniformBufferLayouts = /* @__PURE__ */ new Map();
4694
+ /** Flattened layout metadata for each block. */
4695
+ shaderBlockLayouts = /* @__PURE__ */ new Map();
4696
+ /** Serializers for block-backed uniform data. */
4697
+ shaderBlockWriters = /* @__PURE__ */ new Map();
2899
4698
  /** Actual buffer for the blocks */
2900
4699
  uniformBuffers = /* @__PURE__ */ new Map();
2901
4700
  /**
2902
- * Create a new UniformStore instance
2903
- * @param blocks
4701
+ * Creates a new {@link UniformStore} for the supplied device and block definitions.
2904
4702
  */
2905
- constructor(blocks) {
4703
+ constructor(device, blocks) {
4704
+ this.device = device;
2906
4705
  for (const [bufferName, block] of Object.entries(blocks)) {
2907
4706
  const uniformBufferName = bufferName;
2908
- const uniformBufferLayout = new UniformBufferLayout(block.uniformTypes ?? {}, block.uniformSizes ?? {});
2909
- this.uniformBufferLayouts.set(uniformBufferName, uniformBufferLayout);
4707
+ const shaderBlockLayout = makeShaderBlockLayout(block.uniformTypes ?? {}, {
4708
+ layout: block.layout ?? getDefaultUniformBufferLayout(device)
4709
+ });
4710
+ const shaderBlockWriter = new ShaderBlockWriter(shaderBlockLayout);
4711
+ this.shaderBlockLayouts.set(uniformBufferName, shaderBlockLayout);
4712
+ this.shaderBlockWriters.set(uniformBufferName, shaderBlockWriter);
2910
4713
  const uniformBlock = new UniformBlock({ name: bufferName });
2911
- uniformBlock.setUniforms(block.defaultUniforms || {});
4714
+ uniformBlock.setUniforms(shaderBlockWriter.getFlatUniformValues(block.defaultUniforms || {}));
2912
4715
  this.uniformBlocks.set(uniformBufferName, uniformBlock);
2913
4716
  }
2914
4717
  }
@@ -2920,36 +4723,52 @@ var UniformStore = class {
2920
4723
  }
2921
4724
  /**
2922
4725
  * Set uniforms
2923
- * Makes all properties partial
4726
+ *
4727
+ * Makes all group properties partial and eagerly propagates changes to any
4728
+ * managed GPU buffers.
2924
4729
  */
2925
4730
  setUniforms(uniforms) {
2926
4731
  var _a;
2927
4732
  for (const [blockName, uniformValues] of Object.entries(uniforms)) {
2928
- (_a = this.uniformBlocks.get(blockName)) == null ? void 0 : _a.setUniforms(uniformValues);
4733
+ const uniformBufferName = blockName;
4734
+ const shaderBlockWriter = this.shaderBlockWriters.get(uniformBufferName);
4735
+ const flattenedUniforms = shaderBlockWriter == null ? void 0 : shaderBlockWriter.getFlatUniformValues(uniformValues || {});
4736
+ (_a = this.uniformBlocks.get(uniformBufferName)) == null ? void 0 : _a.setUniforms(flattenedUniforms || {});
2929
4737
  }
2930
4738
  this.updateUniformBuffers();
2931
4739
  }
2932
- /** Get the required minimum length of the uniform buffer */
4740
+ /**
4741
+ * Returns the allocation size for the named uniform buffer.
4742
+ *
4743
+ * This may exceed the packed layout size because minimum buffer-size policy is
4744
+ * applied at the store layer.
4745
+ */
2933
4746
  getUniformBufferByteLength(uniformBufferName) {
2934
4747
  var _a;
2935
- return ((_a = this.uniformBufferLayouts.get(uniformBufferName)) == null ? void 0 : _a.byteLength) || 0;
4748
+ const packedByteLength = ((_a = this.shaderBlockLayouts.get(uniformBufferName)) == null ? void 0 : _a.byteLength) || 0;
4749
+ return Math.max(packedByteLength, minUniformBufferSize);
2936
4750
  }
2937
- /** Get formatted binary memory that can be uploaded to a buffer */
4751
+ /**
4752
+ * Returns packed binary data that can be uploaded to the named uniform buffer.
4753
+ *
4754
+ * The returned view length matches the packed block size and is not padded to
4755
+ * the store's minimum allocation size.
4756
+ */
2938
4757
  getUniformBufferData(uniformBufferName) {
2939
- var _a, _b;
4758
+ var _a;
2940
4759
  const uniformValues = ((_a = this.uniformBlocks.get(uniformBufferName)) == null ? void 0 : _a.getAllUniforms()) || {};
2941
- return (_b = this.uniformBufferLayouts.get(uniformBufferName)) == null ? void 0 : _b.getData(uniformValues);
4760
+ const shaderBlockWriter = this.shaderBlockWriters.get(uniformBufferName);
4761
+ return (shaderBlockWriter == null ? void 0 : shaderBlockWriter.getData(uniformValues)) || new Uint8Array(0);
2942
4762
  }
2943
4763
  /**
2944
- * Creates an unmanaged uniform buffer (umnanaged means that application is responsible for destroying it)
2945
- * The new buffer is initialized with current / supplied values
4764
+ * Creates an unmanaged uniform buffer initialized with the current or supplied values.
2946
4765
  */
2947
- createUniformBuffer(device, uniformBufferName, uniforms) {
4766
+ createUniformBuffer(uniformBufferName, uniforms) {
2948
4767
  if (uniforms) {
2949
4768
  this.setUniforms(uniforms);
2950
4769
  }
2951
4770
  const byteLength = this.getUniformBufferByteLength(uniformBufferName);
2952
- const uniformBuffer = device.createBuffer({
4771
+ const uniformBuffer = this.device.createBuffer({
2953
4772
  usage: Buffer2.UNIFORM | Buffer2.COPY_DST,
2954
4773
  byteLength
2955
4774
  });
@@ -2957,11 +4776,11 @@ var UniformStore = class {
2957
4776
  uniformBuffer.write(uniformBufferData);
2958
4777
  return uniformBuffer;
2959
4778
  }
2960
- /** Get the managed uniform buffer. "managed" resources are destroyed when the uniformStore is destroyed. */
2961
- getManagedUniformBuffer(device, uniformBufferName) {
4779
+ /** Returns the managed uniform buffer for the named block. */
4780
+ getManagedUniformBuffer(uniformBufferName) {
2962
4781
  if (!this.uniformBuffers.get(uniformBufferName)) {
2963
4782
  const byteLength = this.getUniformBufferByteLength(uniformBufferName);
2964
- const uniformBuffer = device.createBuffer({
4783
+ const uniformBuffer = this.device.createBuffer({
2965
4784
  usage: Buffer2.UNIFORM | Buffer2.COPY_DST,
2966
4785
  byteLength
2967
4786
  });
@@ -2969,7 +4788,11 @@ var UniformStore = class {
2969
4788
  }
2970
4789
  return this.uniformBuffers.get(uniformBufferName);
2971
4790
  }
2972
- /** Updates all uniform buffers where values have changed */
4791
+ /**
4792
+ * Updates every managed uniform buffer whose source uniforms have changed.
4793
+ *
4794
+ * @returns The first redraw reason encountered, or `false` if nothing changed.
4795
+ */
2973
4796
  updateUniformBuffers() {
2974
4797
  let reason = false;
2975
4798
  for (const uniformBufferName of this.uniformBlocks.keys()) {
@@ -2981,7 +4804,11 @@ var UniformStore = class {
2981
4804
  }
2982
4805
  return reason;
2983
4806
  }
2984
- /** Update one uniform buffer. Only updates if values have changed */
4807
+ /**
4808
+ * Updates one managed uniform buffer if its corresponding block is dirty.
4809
+ *
4810
+ * @returns The redraw reason for the update, or `false` if no write occurred.
4811
+ */
2985
4812
  updateUniformBuffer(uniformBufferName) {
2986
4813
  var _a;
2987
4814
  const uniformBlock = this.uniformBlocks.get(uniformBufferName);
@@ -2998,8 +4825,49 @@ var UniformStore = class {
2998
4825
  return reason;
2999
4826
  }
3000
4827
  };
4828
+ function getDefaultUniformBufferLayout(device) {
4829
+ return device.type === "webgpu" ? "wgsl-uniform" : "std140";
4830
+ }
4831
+
4832
+ // dist/shadertypes/texture-types/texture-layout.js
4833
+ function getTextureImageView(arrayBuffer2, memoryLayout, format, image = 0) {
4834
+ const formatInfo = textureFormatDecoder.getInfo(format);
4835
+ const bytesPerComponent = formatInfo.bytesPerPixel / formatInfo.components;
4836
+ const { bytesPerImage } = memoryLayout;
4837
+ const offset = bytesPerImage * image;
4838
+ const totalPixels = memoryLayout.bytesPerImage / bytesPerComponent;
4839
+ switch (format) {
4840
+ case "rgba8unorm":
4841
+ case "bgra8unorm":
4842
+ case "rgba8uint":
4843
+ return new Uint8Array(arrayBuffer2, offset, totalPixels);
4844
+ case "r8unorm":
4845
+ return new Uint8Array(arrayBuffer2, offset, totalPixels);
4846
+ case "r16uint":
4847
+ case "rgba16uint":
4848
+ return new Uint16Array(arrayBuffer2, offset, totalPixels);
4849
+ case "r32uint":
4850
+ case "rgba32uint":
4851
+ return new Uint32Array(arrayBuffer2, offset, totalPixels);
4852
+ case "r32float":
4853
+ return new Float32Array(arrayBuffer2, offset, totalPixels);
4854
+ case "rgba16float":
4855
+ return new Uint16Array(arrayBuffer2, offset, totalPixels);
4856
+ case "rgba32float":
4857
+ return new Float32Array(arrayBuffer2, offset, totalPixels);
4858
+ default:
4859
+ throw new Error(`Unsupported format: ${format}`);
4860
+ }
4861
+ }
4862
+ function setTextureImageData(arrayBuffer2, memoryLayout, format, data, image = 0) {
4863
+ const offset = 0;
4864
+ const totalPixels = memoryLayout.bytesPerImage / memoryLayout.bytesPerPixel;
4865
+ const subArray = data.subarray(0, totalPixels);
4866
+ const typedArray = getTextureImageView(arrayBuffer2, memoryLayout, format, image);
4867
+ typedArray.set(subArray, offset);
4868
+ }
3001
4869
 
3002
- // dist/shadertypes/textures/pixel-utils.js
4870
+ // dist/shadertypes/texture-types/pixel-utils.js
3003
4871
  function readPixel(pixelData, x, y, bitsPerChannel) {
3004
4872
  if (x < 0 || x >= pixelData.width || y < 0 || y >= pixelData.height) {
3005
4873
  throw new Error("Coordinates out of bounds.");
@@ -3009,7 +4877,7 @@ function readPixel(pixelData, x, y, bitsPerChannel) {
3009
4877
  let bitOffsetWithinPixel = 0;
3010
4878
  const channels = [];
3011
4879
  for (let i = 0; i < 4; i++) {
3012
- const bits = bitsPerChannel[i];
4880
+ const bits = bitsPerChannel[i] ?? 0;
3013
4881
  if (bits <= 0) {
3014
4882
  channels.push(0);
3015
4883
  } else {
@@ -3018,14 +4886,14 @@ function readPixel(pixelData, x, y, bitsPerChannel) {
3018
4886
  bitOffsetWithinPixel += bits;
3019
4887
  }
3020
4888
  }
3021
- return [channels[0], channels[1], channels[2], channels[3]];
4889
+ return [channels[0] ?? 0, channels[1] ?? 0, channels[2] ?? 0, channels[3] ?? 0];
3022
4890
  }
3023
4891
  function writePixel(dataView, bitOffset, bitsPerChannel, pixel) {
3024
4892
  let currentBitOffset = bitOffset;
3025
4893
  for (let channel = 0; channel < 4; channel++) {
3026
- const bits = bitsPerChannel[channel];
4894
+ const bits = bitsPerChannel[channel] ?? 0;
3027
4895
  const maxValue = (1 << bits) - 1;
3028
- const channelValue = pixel[channel] & maxValue;
4896
+ const channelValue = (pixel[channel] ?? 0) & maxValue;
3029
4897
  writeBitsToDataView(dataView, currentBitOffset, bits, channelValue);
3030
4898
  currentBitOffset += bits;
3031
4899
  }