@woosh/meep-engine 3.14.0 → 3.14.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (220) hide show
  1. package/README.md +33 -64
  2. package/package.json +1 -1
  3. package/src/avif/native/DECISIONS.md +544 -536
  4. package/src/avif/native/heif/parse_avif_file.d.ts.map +1 -1
  5. package/src/avif/native/heif/parse_avif_file.js +384 -383
  6. package/src/avif/native/heif/parse_image_grid.d.ts.map +1 -1
  7. package/src/avif/native/heif/parse_image_grid.js +49 -48
  8. package/src/basis/BasisBitReader.d.ts +77 -0
  9. package/src/basis/BasisBitReader.d.ts.map +1 -0
  10. package/src/basis/BasisBitReader.js +231 -0
  11. package/src/basis/BasisHuffmanTable.d.ts +53 -0
  12. package/src/basis/BasisHuffmanTable.d.ts.map +1 -0
  13. package/src/basis/BasisHuffmanTable.js +263 -0
  14. package/src/basis/basis_read_huffman_table.d.ts +20 -0
  15. package/src/basis/basis_read_huffman_table.d.ts.map +1 -0
  16. package/src/basis/basis_read_huffman_table.js +187 -0
  17. package/src/basis/etc1s/Etc1sSelectorHistory.d.ts +50 -0
  18. package/src/basis/etc1s/Etc1sSelectorHistory.d.ts.map +1 -0
  19. package/src/basis/etc1s/Etc1sSelectorHistory.js +89 -0
  20. package/src/basis/etc1s/etc1s_block_colors.d.ts +14 -0
  21. package/src/basis/etc1s/etc1s_block_colors.d.ts.map +1 -0
  22. package/src/basis/etc1s/etc1s_block_colors.js +75 -0
  23. package/src/basis/etc1s/etc1s_decode_slice.d.ts +57 -0
  24. package/src/basis/etc1s/etc1s_decode_slice.d.ts.map +1 -0
  25. package/src/basis/etc1s/etc1s_decode_slice.js +258 -0
  26. package/src/basis/etc1s/etc1s_read_endpoint_codebook.d.ts +48 -0
  27. package/src/basis/etc1s/etc1s_read_endpoint_codebook.d.ts.map +1 -0
  28. package/src/basis/etc1s/etc1s_read_endpoint_codebook.js +111 -0
  29. package/src/basis/etc1s/etc1s_read_selector_codebook.d.ts +42 -0
  30. package/src/basis/etc1s/etc1s_read_selector_codebook.d.ts.map +1 -0
  31. package/src/basis/etc1s/etc1s_read_selector_codebook.js +127 -0
  32. package/src/basis/etc1s/etc1s_read_slice_tables.d.ts +54 -0
  33. package/src/basis/etc1s/etc1s_read_slice_tables.d.ts.map +1 -0
  34. package/src/basis/etc1s/etc1s_read_slice_tables.js +47 -0
  35. package/src/basis/transcode/build_range_plan.js +54 -0
  36. package/src/basis/transcode/etc1s_to_bc1.d.ts +24 -0
  37. package/src/basis/transcode/etc1s_to_bc1.d.ts.map +1 -0
  38. package/src/basis/transcode/etc1s_to_bc1.js +205 -0
  39. package/src/basis/transcode/etc1s_to_bc7.d.ts +30 -0
  40. package/src/basis/transcode/etc1s_to_bc7.d.ts.map +1 -0
  41. package/src/basis/transcode/etc1s_to_bc7.js +496 -0
  42. package/src/basis/transcode/fit_endpoints.d.ts +59 -0
  43. package/src/basis/transcode/fit_endpoints.d.ts.map +1 -0
  44. package/src/basis/transcode/fit_endpoints.js +226 -0
  45. package/src/{avif/native/isobmff → core/binary}/ByteCursor.d.ts +19 -6
  46. package/src/core/binary/ByteCursor.d.ts.map +1 -0
  47. package/src/{avif/native/isobmff → core/binary}/ByteCursor.js +41 -14
  48. package/src/engine/EngineHarness.js +1 -1
  49. package/src/engine/asset/codec/Codec.d.ts.map +1 -0
  50. package/src/engine/asset/codec/CodecWithFallback.d.ts.map +1 -0
  51. package/src/engine/asset/{loaders/image/codec → codec}/CodecWithFallback.js +2 -2
  52. package/src/engine/asset/loaders/image/IMAGE_CODEC_REVIEW_2026_08_28.md +4 -4
  53. package/src/engine/asset/loaders/image/ImageRGBADataLoader.d.ts +1 -1
  54. package/src/engine/asset/loaders/image/ImageRGBADataLoader.d.ts.map +1 -1
  55. package/src/engine/asset/loaders/image/ImageRGBADataLoader.js +1 -1
  56. package/src/engine/asset/loaders/image/codec/NativeImageDecoder.d.ts +1 -1
  57. package/src/engine/asset/loaders/image/codec/NativeImageDecoder.d.ts.map +1 -1
  58. package/src/engine/asset/loaders/image/codec/NativeImageDecoder.js +1 -1
  59. package/src/engine/asset/loaders/image/codec/ThreadedImageDecoder.d.ts +1 -1
  60. package/src/engine/asset/loaders/image/codec/ThreadedImageDecoder.d.ts.map +1 -1
  61. package/src/engine/asset/loaders/image/codec/ThreadedImageDecoder.js +1 -1
  62. package/src/engine/graphics/texture/atlas/TextureAtlas.d.ts.map +1 -1
  63. package/src/engine/graphics/texture/atlas/TextureAtlas.js +13 -0
  64. package/src/engine/physics/broadphase/generate_pairs.d.ts.map +1 -1
  65. package/src/engine/physics/broadphase/generate_pairs.js +7 -1
  66. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  67. package/src/ktx2/KTX2_IDENTIFIER.d.ts +14 -0
  68. package/src/ktx2/KTX2_IDENTIFIER.d.ts.map +1 -0
  69. package/src/ktx2/KTX2_IDENTIFIER.js +15 -0
  70. package/src/ktx2/KhrDfModel.d.ts +35 -0
  71. package/src/ktx2/KhrDfModel.d.ts.map +1 -0
  72. package/src/ktx2/KhrDfModel.js +49 -0
  73. package/src/ktx2/SupercompressionScheme.d.ts +16 -0
  74. package/src/ktx2/SupercompressionScheme.d.ts.map +1 -0
  75. package/src/ktx2/SupercompressionScheme.js +23 -0
  76. package/src/ktx2/ktx2_read.d.ts +71 -0
  77. package/src/ktx2/ktx2_read.d.ts.map +1 -0
  78. package/src/ktx2/ktx2_read.js +581 -0
  79. package/src/ktx2/ktx2_read_basis_lz_global_data.d.ts +27 -0
  80. package/src/ktx2/ktx2_read_basis_lz_global_data.d.ts.map +1 -0
  81. package/src/ktx2/ktx2_read_basis_lz_global_data.js +189 -0
  82. package/src/ktx2/vk_format_to_texture_format.d.ts +55 -0
  83. package/src/ktx2/vk_format_to_texture_format.d.ts.map +1 -0
  84. package/src/ktx2/vk_format_to_texture_format.js +290 -0
  85. package/src/shade/descriptor/GPUTextureUsage.d.ts +23 -0
  86. package/src/shade/descriptor/GPUTextureUsage.d.ts.map +1 -0
  87. package/src/shade/descriptor/GPUTextureUsage.js +24 -0
  88. package/src/shade/descriptor/WebGPUExtensionType.d.ts +3 -0
  89. package/src/shade/descriptor/WebGPUExtensionType.js +26 -0
  90. package/src/shade/descriptor/texture/TextureDescriptor.d.ts +2 -6
  91. package/src/shade/descriptor/texture/TextureDescriptor.d.ts.map +1 -1
  92. package/src/shade/descriptor/texture/TextureDescriptor.js +24 -40
  93. package/src/shade/descriptor/texture/format/TextureFormat.d.ts +125 -0
  94. package/src/shade/descriptor/texture/format/TextureFormat.d.ts.map +1 -0
  95. package/src/shade/descriptor/texture/format/TextureFormat.js +146 -0
  96. package/src/shade/descriptor/texture/format/gpu_texture_format_info.d.ts +60 -0
  97. package/src/shade/descriptor/texture/format/gpu_texture_format_info.d.ts.map +1 -1
  98. package/src/shade/descriptor/texture/format/gpu_texture_format_info.js +102 -0
  99. package/src/shade/device/graph/TextureResourceDescriptor.d.ts.map +1 -1
  100. package/src/shade/device/graph/TextureResourceDescriptor.js +160 -155
  101. package/src/shade/device/mock/SoftwareGPUQueue.d.ts +11 -4
  102. package/src/shade/device/mock/SoftwareGPUQueue.d.ts.map +1 -1
  103. package/src/shade/device/mock/SoftwareGPUQueue.js +31 -37
  104. package/src/shade/device/mock/SoftwareGPUTexture.d.ts.map +1 -1
  105. package/src/shade/device/mock/SoftwareGPUTexture.js +8 -4
  106. package/src/shade/device/timing/profile/frame_graph_extract_topology.d.ts.map +1 -1
  107. package/src/shade/device/timing/profile/frame_graph_extract_topology.js +164 -174
  108. package/src/shade/playground/ground_seam/README.md +235 -0
  109. package/src/shade/playground/ground_seam/capture_scene_color.d.ts +45 -0
  110. package/src/shade/playground/ground_seam/capture_scene_color.d.ts.map +1 -0
  111. package/src/shade/playground/ground_seam/capture_scene_color.js +242 -0
  112. package/src/shade/playground/ground_seam/depth_step_across_seam.d.ts +11 -0
  113. package/src/shade/playground/ground_seam/depth_step_across_seam.d.ts.map +1 -0
  114. package/src/shade/playground/ground_seam/depth_step_across_seam.js +185 -0
  115. package/src/shade/playground/ground_seam/index.html +195 -0
  116. package/src/shade/playground/ground_seam/main.d.ts +2 -0
  117. package/src/shade/playground/ground_seam/main.d.ts.map +1 -0
  118. package/src/shade/playground/ground_seam/main.js +879 -0
  119. package/src/shade/playground/ground_seam/make_grid_texture.d.ts +29 -0
  120. package/src/shade/playground/ground_seam/make_grid_texture.d.ts.map +1 -0
  121. package/src/shade/playground/ground_seam/make_grid_texture.js +105 -0
  122. package/src/shade/playground/ground_seam/make_ground.d.ts +70 -0
  123. package/src/shade/playground/ground_seam/make_ground.d.ts.map +1 -0
  124. package/src/shade/playground/ground_seam/make_ground.js +161 -0
  125. package/src/shade/playground/ground_seam/measure_flicker.d.ts +71 -0
  126. package/src/shade/playground/ground_seam/measure_flicker.d.ts.map +1 -0
  127. package/src/shade/playground/ground_seam/measure_flicker.js +531 -0
  128. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  129. package/src/shade/renderer/Renderer.js +2519 -2511
  130. package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts.map +1 -1
  131. package/src/shade/renderer/hiz/HierarchicalZBuffer.js +275 -274
  132. package/src/shade/renderer/light/GPULightCollection.d.ts.map +1 -1
  133. package/src/shade/renderer/light/GPULightCollection.js +323 -314
  134. package/src/shade/renderer/lightmap/GPULightMap.js +336 -336
  135. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts.map +1 -1
  136. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.js +12 -2
  137. package/src/shade/renderer/material/standard/fragment_gbuffer.d.ts.map +1 -1
  138. package/src/shade/renderer/material/standard/fragment_gbuffer.js +3 -1
  139. package/src/shade/renderer/material/standard/fragment_gbuffer_vt.js +169 -169
  140. package/src/shade/renderer/path_tracer/shader/chunk_sample_material_data.d.ts.map +1 -1
  141. package/src/shade/renderer/path_tracer/shader/chunk_sample_material_data.js +3 -1
  142. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  143. package/src/shade/renderer/rasterize/native/oit/chunk_forward_shade_standard_fragment_brick4.d.ts.map +1 -1
  144. package/src/shade/renderer/rasterize/native/oit/chunk_forward_shade_standard_fragment_brick4.js +3 -1
  145. package/src/shade/renderer/rasterize/native/oit/chunk_forward_shade_standard_fragment_ibl.d.ts.map +1 -1
  146. package/src/shade/renderer/rasterize/native/oit/chunk_forward_shade_standard_fragment_ibl.js +3 -1
  147. package/src/shade/renderer/shader/chunk/geometry/normal/chunk_decode_tangent_normal.d.ts +28 -0
  148. package/src/shade/renderer/shader/chunk/geometry/normal/chunk_decode_tangent_normal.d.ts.map +1 -0
  149. package/src/shade/renderer/shader/chunk/geometry/normal/chunk_decode_tangent_normal.js +39 -0
  150. package/src/shade/renderer/shader/chunk/geometry/triangle/chunk_barycentric_full.d.ts +45 -0
  151. package/src/shade/renderer/shader/chunk/geometry/triangle/chunk_barycentric_full.d.ts.map +1 -1
  152. package/src/shade/renderer/shader/chunk/geometry/triangle/chunk_barycentric_full.js +94 -61
  153. package/src/shade/renderer/shader/chunk/geometry/triangle/chunk_barycentric_solve.d.ts +24 -0
  154. package/src/shade/renderer/shader/chunk/geometry/triangle/chunk_barycentric_solve.d.ts.map +1 -0
  155. package/src/shade/renderer/shader/chunk/geometry/triangle/chunk_barycentric_solve.js +43 -0
  156. package/src/shade/renderer/texture/COMPRESSED_TEXTURE_PLAN_2026_09_01.md +1462 -0
  157. package/src/shade/renderer/texture/TextureManager.d.ts.map +1 -1
  158. package/src/shade/renderer/texture/TextureManager.js +20 -8
  159. package/src/shade/renderer/texture/TextureRole.d.ts +19 -0
  160. package/src/shade/renderer/texture/TextureRole.d.ts.map +1 -0
  161. package/src/shade/renderer/texture/TextureRole.js +26 -0
  162. package/src/shade/renderer/texture/TextureVariantSet.d.ts +71 -0
  163. package/src/shade/renderer/texture/TextureVariantSet.d.ts.map +1 -0
  164. package/src/shade/renderer/texture/TextureVariantSet.js +105 -0
  165. package/src/shade/renderer/texture/download_texture_data.d.ts.map +1 -1
  166. package/src/shade/renderer/texture/download_texture_data.js +22 -0
  167. package/src/shade/renderer/texture/format/gpu_texture_compression_support.d.ts +15 -0
  168. package/src/shade/renderer/texture/format/gpu_texture_compression_support.d.ts.map +1 -0
  169. package/src/shade/renderer/texture/format/gpu_texture_compression_support.js +50 -0
  170. package/src/shade/renderer/texture/format/gpu_texture_format_can_generate_mipmaps.d.ts +27 -0
  171. package/src/shade/renderer/texture/format/gpu_texture_format_can_generate_mipmaps.d.ts.map +1 -0
  172. package/src/shade/renderer/texture/format/gpu_texture_format_can_generate_mipmaps.js +65 -0
  173. package/src/shade/renderer/texture/format/infer_format_from_parameters.d.ts +11 -0
  174. package/src/shade/renderer/texture/format/infer_format_from_parameters.d.ts.map +1 -0
  175. package/src/shade/renderer/texture/format/infer_format_from_parameters.js +88 -0
  176. package/src/shade/renderer/texture/format/texture_format_from_shade_image.d.ts +24 -0
  177. package/src/shade/renderer/texture/format/texture_format_from_shade_image.d.ts.map +1 -0
  178. package/src/shade/renderer/texture/format/texture_format_from_shade_image.js +71 -0
  179. package/src/shade/renderer/texture/format/texture_format_preference.d.ts +22 -0
  180. package/src/shade/renderer/texture/format/texture_format_preference.d.ts.map +1 -0
  181. package/src/shade/renderer/texture/format/texture_format_preference.js +89 -0
  182. package/src/shade/renderer/texture/format/texture_variant_select.d.ts +24 -0
  183. package/src/shade/renderer/texture/format/texture_variant_select.d.ts.map +1 -0
  184. package/src/shade/renderer/texture/format/texture_variant_select.js +38 -0
  185. package/src/shade/renderer/texture/shade_texture_might_have_alpha.d.ts +9 -1
  186. package/src/shade/renderer/texture/shade_texture_might_have_alpha.d.ts.map +1 -1
  187. package/src/shade/renderer/texture/shade_texture_might_have_alpha.js +73 -8
  188. package/src/shade/renderer/texture/source/AlphaMode.d.ts +27 -0
  189. package/src/shade/renderer/texture/source/AlphaMode.d.ts.map +1 -0
  190. package/src/shade/renderer/texture/source/AlphaMode.js +52 -0
  191. package/src/shade/renderer/texture/source/ShadeImage.d.ts +33 -0
  192. package/src/shade/renderer/texture/source/ShadeImage.d.ts.map +1 -1
  193. package/src/shade/renderer/texture/source/ShadeImage.js +74 -0
  194. package/src/shade/renderer/texture/source/ShadeTexelData.d.ts +78 -0
  195. package/src/shade/renderer/texture/source/ShadeTexelData.d.ts.map +1 -0
  196. package/src/shade/renderer/texture/source/ShadeTexelData.js +158 -0
  197. package/src/shade/renderer/texture/texture_descriptor_from_texture_shade.d.ts +0 -10
  198. package/src/shade/renderer/texture/texture_descriptor_from_texture_shade.d.ts.map +1 -1
  199. package/src/shade/renderer/texture/texture_descriptor_from_texture_shade.js +73 -175
  200. package/src/shade/renderer/texture/texture_write_level.d.ts +32 -0
  201. package/src/shade/renderer/texture/texture_write_level.d.ts.map +1 -0
  202. package/src/shade/renderer/texture/texture_write_level.js +77 -0
  203. package/src/shade/renderer/texture/texture_write_to_gpu.d.ts +8 -1
  204. package/src/shade/renderer/texture/texture_write_to_gpu.d.ts.map +1 -1
  205. package/src/shade/renderer/texture/texture_write_to_gpu.js +62 -37
  206. package/src/shade/renderer/texture/virtual/source/VTSourceImage.d.ts +8 -0
  207. package/src/shade/renderer/texture/virtual/source/VTSourceImage.d.ts.map +1 -1
  208. package/src/shade/renderer/texture/virtual/source/VTSourceImage.js +8 -0
  209. package/src/shade/util/texture_mip_extent.d.ts +49 -0
  210. package/src/shade/util/texture_mip_extent.d.ts.map +1 -0
  211. package/src/shade/util/texture_mip_extent.js +87 -0
  212. package/src/avif/native/isobmff/ByteCursor.d.ts.map +0 -1
  213. package/src/engine/asset/loaders/image/codec/Codec.d.ts.map +0 -1
  214. package/src/engine/asset/loaders/image/codec/CodecWithFallback.d.ts.map +0 -1
  215. package/src/shade/util/compute_max_mip_count.d.ts +0 -8
  216. package/src/shade/util/compute_max_mip_count.d.ts.map +0 -1
  217. package/src/shade/util/compute_max_mip_count.js +0 -27
  218. /package/src/engine/asset/{loaders/image/codec → codec}/Codec.d.ts +0 -0
  219. /package/src/engine/asset/{loaders/image/codec → codec}/Codec.js +0 -0
  220. /package/src/engine/asset/{loaders/image/codec → codec}/CodecWithFallback.d.ts +0 -0
@@ -1,174 +1,164 @@
1
- import { assert } from "../../../../core/assert.js";
2
- import { gpu_texture_format_info } from "../../../descriptor/texture/format/gpu_texture_format_info.js";
3
- import {
4
- GPUProfilePass,
5
- GPUProfileResource,
6
- GPUProfileResourceKind,
7
- GPUProfileScope,
8
- GPUProfileTopology
9
- } from "./GPUProfileTopology.js";
10
-
11
- /**
12
- * Declared bytes for a texture descriptor: the whole mip chain, at the given sample count.
13
- *
14
- * A format the engine's table does not know reports 0 rather than throwing. A capture is a
15
- * diagnostic; refusing to record one because a size could not be worked out would be the wrong
16
- * trade every time.
17
- *
18
- * @param {TextureResourceDescriptor} descriptor
19
- * @returns {number}
20
- */
21
- function texture_byte_size(descriptor) {
22
- let info;
23
-
24
- try {
25
- info = gpu_texture_format_info(descriptor.format);
26
- } catch {
27
- // `gpu_texture_format_info` throws on a name it does not know. Correct for the renderer,
28
- // wrong here: a capture is a diagnostic, and losing the whole recording because one
29
- // resource used a format the table has not caught up with is the wrong trade every time.
30
- return 0;
31
- }
32
-
33
- const { block_width, block_height, bytes_per_block } = info;
34
-
35
- let total = 0;
36
-
37
- for (let mip = 0; mip < descriptor.mipLevelCount; mip++) {
38
- const w = Math.max(1, Math.floor(descriptor.resolution[0]) >> mip);
39
- const h = Math.max(1, Math.floor(descriptor.resolution[1]) >> mip);
40
- const d = Math.max(1, Math.floor(descriptor.resolution[2]) >> mip);
41
-
42
- total += Math.ceil(w / block_width) * Math.ceil(h / block_height) * d * bytes_per_block;
43
- }
44
-
45
- return total * descriptor.sampleCount;
46
- }
47
-
48
- /**
49
- * Record the shape of a compiled frame graph.
50
- *
51
- * **Call after `compile`, and ideally after `execute`.** Reference counts and cull decisions are
52
- * what `compile` derives; before it every pass reads as culled, which would be recorded as a frame
53
- * in which nothing ran.
54
- *
55
- * Resources are keyed by **node**, one per version, matching `FrameGraph.exportToJson`. Passes
56
- * record the node they touched rather than the underlying resource, so a registry-keyed model would
57
- * leave every reference past version 0 pointing at nothing.
58
- *
59
- * @param {FrameGraph} graph
60
- * @returns {GPUProfileTopology}
61
- *
62
- * @author Alex Goldring
63
- * @copyright Company Named Limited (c) 2026
64
- */
65
- export function frame_graph_extract_topology(graph) {
66
- assert.defined(graph, 'graph');
67
-
68
- const topology = new GPUProfileTopology();
69
-
70
- topology.name = graph.name;
71
-
72
- /**
73
- * Scopes are reached through the nodes that were recorded inside them, and flattened to an
74
- * array here. `FrameGraph` keeps them as a parent chain rather than a list, so this walk is
75
- * what turns the chain into something a reader can index.
76
- *
77
- * @type {Map<FrameGraphScope, number>}
78
- */
79
- const scope_ids = new Map();
80
-
81
- /**
82
- * @param {FrameGraphScope|null} scope
83
- * @returns {number} index, or -1
84
- */
85
- function intern_scope(scope) {
86
- if (scope === null || scope === undefined) {
87
- return -1;
88
- }
89
-
90
- const existing = scope_ids.get(scope);
91
-
92
- if (existing !== undefined) {
93
- return existing;
94
- }
95
-
96
- // parent first, so a parent always has a lower index than its children and a reader can
97
- // resolve the chain in one forward pass
98
- const parent = intern_scope(scope.parent);
99
-
100
- const record = new GPUProfileScope();
101
-
102
- record.name = scope.name;
103
- record.parent = parent;
104
-
105
- const id = topology.scopes.length;
106
-
107
- topology.scopes.push(record);
108
- scope_ids.set(scope, id);
109
-
110
- return id;
111
- }
112
-
113
- for (const node of graph.__pass_nodes) {
114
- const pass = new GPUProfilePass();
115
-
116
- pass.id = node.id;
117
- pass.name = node.name;
118
- pass.scope = intern_scope(node.scope);
119
- pass.culled = !node.can_execute();
120
- pass.has_side_effects = node.has_side_effects;
121
- pass.ref_count = node.ref_count;
122
- pass.reads = node.resource_reads.slice();
123
- pass.writes = node.resource_writes.slice();
124
- pass.creates = node.resource_creates.slice();
125
-
126
- topology.passes.push(pass);
127
- }
128
-
129
- for (const node of graph.__resource_nodes) {
130
- const entry = graph.__resource_registry[node.resource_id];
131
-
132
- const resource = new GPUProfileResource();
133
-
134
- resource.id = node.id;
135
- resource.name = node.name;
136
- resource.version = node.version;
137
- resource.producer = node.producer !== null ? node.producer.id : -1;
138
-
139
- if (entry !== undefined) {
140
- resource.transient = entry.isTransient();
141
- resource.imported = entry.isImported();
142
- }
143
-
144
- const descriptor = entry?.resource_descriptor;
145
-
146
- if (descriptor !== undefined && descriptor !== null) {
147
- const type = descriptor.type;
148
-
149
- if (type === 'buffer') {
150
- resource.kind = GPUProfileResourceKind.BUFFER;
151
- resource.size = descriptor.size;
152
- resource.usage = descriptor.usage;
153
- resource.byte_size = descriptor.size;
154
- } else if (type === 'texture') {
155
- resource.kind = GPUProfileResourceKind.TEXTURE;
156
- resource.resolution = [
157
- Math.floor(descriptor.resolution[0]),
158
- Math.floor(descriptor.resolution[1]),
159
- Math.floor(descriptor.resolution[2])
160
- ];
161
- resource.mip_level_count = descriptor.mipLevelCount;
162
- resource.sample_count = descriptor.sampleCount;
163
- resource.format = descriptor.format;
164
- resource.dimension = descriptor.dimension;
165
- resource.usage = descriptor.usage;
166
- resource.byte_size = texture_byte_size(descriptor);
167
- }
168
- }
169
-
170
- topology.resources.push(resource);
171
- }
172
-
173
- return topology;
174
- }
1
+ import { assert } from "../../../../core/assert.js";
2
+ import { gpu_texture_format_memory_footprint } from "../../../descriptor/texture/format/gpu_texture_format_info.js";
3
+ import {
4
+ GPUProfilePass,
5
+ GPUProfileResource,
6
+ GPUProfileResourceKind,
7
+ GPUProfileScope,
8
+ GPUProfileTopology
9
+ } from "./GPUProfileTopology.js";
10
+
11
+ /**
12
+ * Declared bytes for a texture descriptor: the whole mip chain, at the given sample count.
13
+ *
14
+ * A format the engine's table does not know reports 0 rather than throwing. A capture is a
15
+ * diagnostic; refusing to record one because a size could not be worked out would be the wrong
16
+ * trade every time.
17
+ *
18
+ * @param {TextureResourceDescriptor} descriptor
19
+ * @returns {number}
20
+ */
21
+ function texture_byte_size(descriptor) {
22
+ try {
23
+ return gpu_texture_format_memory_footprint(
24
+ descriptor.format,
25
+ descriptor.resolution,
26
+ descriptor.dimension,
27
+ descriptor.mipLevelCount,
28
+ descriptor.sampleCount
29
+ );
30
+ } catch {
31
+ // `gpu_texture_format_info` throws on a name it does not know. Correct for the renderer,
32
+ // wrong here: a capture is a diagnostic, and losing the whole recording because one
33
+ // resource used a format the table has not caught up with is the wrong trade every time.
34
+ return 0;
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Record the shape of a compiled frame graph.
40
+ *
41
+ * **Call after `compile`, and ideally after `execute`.** Reference counts and cull decisions are
42
+ * what `compile` derives; before it every pass reads as culled, which would be recorded as a frame
43
+ * in which nothing ran.
44
+ *
45
+ * Resources are keyed by **node**, one per version, matching `FrameGraph.exportToJson`. Passes
46
+ * record the node they touched rather than the underlying resource, so a registry-keyed model would
47
+ * leave every reference past version 0 pointing at nothing.
48
+ *
49
+ * @param {FrameGraph} graph
50
+ * @returns {GPUProfileTopology}
51
+ *
52
+ * @author Alex Goldring
53
+ * @copyright Company Named Limited (c) 2026
54
+ */
55
+ export function frame_graph_extract_topology(graph) {
56
+ assert.defined(graph, 'graph');
57
+
58
+ const topology = new GPUProfileTopology();
59
+
60
+ topology.name = graph.name;
61
+
62
+ /**
63
+ * Scopes are reached through the nodes that were recorded inside them, and flattened to an
64
+ * array here. `FrameGraph` keeps them as a parent chain rather than a list, so this walk is
65
+ * what turns the chain into something a reader can index.
66
+ *
67
+ * @type {Map<FrameGraphScope, number>}
68
+ */
69
+ const scope_ids = new Map();
70
+
71
+ /**
72
+ * @param {FrameGraphScope|null} scope
73
+ * @returns {number} index, or -1
74
+ */
75
+ function intern_scope(scope) {
76
+ if (scope === null || scope === undefined) {
77
+ return -1;
78
+ }
79
+
80
+ const existing = scope_ids.get(scope);
81
+
82
+ if (existing !== undefined) {
83
+ return existing;
84
+ }
85
+
86
+ // parent first, so a parent always has a lower index than its children and a reader can
87
+ // resolve the chain in one forward pass
88
+ const parent = intern_scope(scope.parent);
89
+
90
+ const record = new GPUProfileScope();
91
+
92
+ record.name = scope.name;
93
+ record.parent = parent;
94
+
95
+ const id = topology.scopes.length;
96
+
97
+ topology.scopes.push(record);
98
+ scope_ids.set(scope, id);
99
+
100
+ return id;
101
+ }
102
+
103
+ for (const node of graph.__pass_nodes) {
104
+ const pass = new GPUProfilePass();
105
+
106
+ pass.id = node.id;
107
+ pass.name = node.name;
108
+ pass.scope = intern_scope(node.scope);
109
+ pass.culled = !node.can_execute();
110
+ pass.has_side_effects = node.has_side_effects;
111
+ pass.ref_count = node.ref_count;
112
+ pass.reads = node.resource_reads.slice();
113
+ pass.writes = node.resource_writes.slice();
114
+ pass.creates = node.resource_creates.slice();
115
+
116
+ topology.passes.push(pass);
117
+ }
118
+
119
+ for (const node of graph.__resource_nodes) {
120
+ const entry = graph.__resource_registry[node.resource_id];
121
+
122
+ const resource = new GPUProfileResource();
123
+
124
+ resource.id = node.id;
125
+ resource.name = node.name;
126
+ resource.version = node.version;
127
+ resource.producer = node.producer !== null ? node.producer.id : -1;
128
+
129
+ if (entry !== undefined) {
130
+ resource.transient = entry.isTransient();
131
+ resource.imported = entry.isImported();
132
+ }
133
+
134
+ const descriptor = entry?.resource_descriptor;
135
+
136
+ if (descriptor !== undefined && descriptor !== null) {
137
+ const type = descriptor.type;
138
+
139
+ if (type === 'buffer') {
140
+ resource.kind = GPUProfileResourceKind.BUFFER;
141
+ resource.size = descriptor.size;
142
+ resource.usage = descriptor.usage;
143
+ resource.byte_size = descriptor.size;
144
+ } else if (type === 'texture') {
145
+ resource.kind = GPUProfileResourceKind.TEXTURE;
146
+ resource.resolution = [
147
+ Math.floor(descriptor.resolution[0]),
148
+ Math.floor(descriptor.resolution[1]),
149
+ Math.floor(descriptor.resolution[2])
150
+ ];
151
+ resource.mip_level_count = descriptor.mipLevelCount;
152
+ resource.sample_count = descriptor.sampleCount;
153
+ resource.format = descriptor.format;
154
+ resource.dimension = descriptor.dimension;
155
+ resource.usage = descriptor.usage;
156
+ resource.byte_size = texture_byte_size(descriptor);
157
+ }
158
+ }
159
+
160
+ topology.resources.push(resource);
161
+ }
162
+
163
+ return topology;
164
+ }
@@ -0,0 +1,235 @@
1
+ # ground seam
2
+
3
+ A 425×425 ground quad, two triangles, a tiling grid albedo, a still camera. Under TAA the half of
4
+ the quad on one side of the triangles' shared edge boils at texel granularity and the other half is
5
+ clean, with a hard straight seam between them. It is invisible in a still frame and only exists in a
6
+ multi-frame difference.
7
+
8
+ `npm run dev`, then `/src/shade/playground/ground_seam/`. HMR is off across the playground by
9
+ design — a reload drops the temporal accumulation this page exists to measure.
10
+
11
+ ## What it does differently from looking at the screen
12
+
13
+ The report this page was built from was written from outside the engine, by screenshotting a demo
14
+ through CDP, and three of its conclusions had to be retracted — two stated before they were
15
+ measured, one from a sign error in a hand-rolled camera basis. So nothing here is read off a
16
+ picture:
17
+
18
+ - **Frames are read back from a texture the page owns.** A canvas texture cannot carry `COPY_SRC`
19
+ and is rotated away the moment it is presented; a `drawImage` off it a task later returns an empty
20
+ bitmap, and a comparison of two blanks reports perfect agreement. `Renderer.render_to_target`
21
+ shares the view context, so the history being measured is the history the on-screen path builds.
22
+ - **Frames are driven from JS**, so the burst length is a number chosen here rather than one the
23
+ compositor handed over. The jitter sequence is 16 phases at scale 1, and the default burst is 16.
24
+ - **Pixels are assigned to triangles, not to a fitted line.** Each pixel is unprojected through
25
+ `camera.view_projection_matrix`, intersected with the ground plane and labelled by the sign of
26
+ `x + z` — the shared edge, derived from the index buffer. The unprojection round-trips itself and
27
+ reports the error, which runs about `4e-11` px.
28
+ - **Both diagonals are always reported.** The one in the mesh and the one that is not, so a whole-
29
+ frame asymmetry caused by the view cannot be mistaken for a seam.
30
+ - **Profiles, not half-plane means.** A mean over each half reports the same number for a step at
31
+ the boundary and for a smooth gradient across the frame, and those are different findings.
32
+
33
+ Pin `feature_automatic_exposure_enabled = false` before measuring anything — it drifts for seconds
34
+ after any change, by more than the signal is worth. The page does this at startup. And check the
35
+ frame is not black before believing a stability win; a black frame is perfectly stable.
36
+
37
+ ## What it found
38
+
39
+ Reproduced at 1258×566, pixel ratio 1. Profiling the relative luminance spread across a 16-frame
40
+ burst against screen distance from the shared edge gives a step from 0.046 to 0.022 centred on the
41
+ edge, over about four pixels. The control cut along the *other* diagonal, through the same picture,
42
+ is flat.
43
+
44
+ **The rasterizer is not the source.** For a planar surface under reverse-Z with an infinite far
45
+ plane the written depth is exactly affine in screen space, so each triangle's depth was fitted
46
+ separately by least squares and the two fits evaluated on the shared edge. Residuals `6e-11`, and
47
+ the two planes disagree by **0.23 ULP of f32** at worst. There is no depth step.
48
+
49
+ **The disocclusion chain the report suspected does not exist.** `shader_depth_occlusion_clip`'s
50
+ confidence is **exactly 1.0 at every pixel**, both sides. Velocity is ~`1e-5` px and flat.
51
+
52
+ **TAA creates the step out of continuous inputs.** Captured at `AfterTransparency` — the exact
53
+ texture the resolve reads — the incoming colour's per-pixel swing is 0.371 vs 0.366 across the edge
54
+ and flat in profile. Captured at `BeforePresent` it is 0.046 vs 0.022 with a hard step. And it is
55
+ not a blend-weight difference: re-running the resolve's own arithmetic with its own chunks gives
56
+ blend 0.0222 vs 0.0248 — nearly equal, and *lower* on the noisy side. What moves is the clipped
57
+ history. (That probe is no longer here; see "The two probes that are gone".)
58
+
59
+ **The incoming colour does differ per triangle — in temporal shape, not amplitude.** Total variation
60
+ along the burst divided by its range ("jaggedness": 1 for a single sweep, 15 for a full alternation)
61
+ steps from **7.28 to 5.32 in a single pixel** at the edge, while the range itself is flat to 1.5%. A
62
+ neighbourhood-clamped filter rebuilds its box from the current frame every frame, so a value that
63
+ jumps to the far end of its range each frame keeps the history at the box boundary and never
64
+ settles, while a value that sweeps smoothly converges.
65
+
66
+ **The source is `chunk_barycentric_full`'s anchor.** The decisive control is
67
+ `GROUND_TRIANGULATION.rotated`: the same two triangles, same diagonal, same winding, same three
68
+ vertices per face, same UVs, same coverage, same depth — each index triple cyclically rotated so a
69
+ different corner is first. Nothing geometric changes. The reconstruction anchors every pixel on
70
+ `pixel - ndc0` and divides by `determinant(mat2x2(ndc2 - ndc1, ndc0 - ndc1))`, so vertex 0 is the
71
+ origin the whole thing is measured from, and in f32 the rotation changes which differences are
72
+ formed and how they round.
73
+
74
+ | 1258×566 | jaggedness − / + | ratio | post-TAA spread − / + | ratio |
75
+ |---|---|---|---|---|
76
+ | default `(0,2,1) (2,3,1)` | 7.28 / 5.32 | 1.37 | 0.0458 / 0.0218 | **2.11** |
77
+ | anchor-rotated `(2,1,0) (3,1,2)` | 4.33 / 4.36 | 0.99 | 0.0139 / 0.0149 | **0.94** |
78
+
79
+ `globalThis.__meshlet_signature` is published on every rebuild so a null result on an index-order
80
+ A/B cannot be mistaken for "the reconstruction does not care" — the two builds' meshlet data
81
+ differ, so the change reached the GPU.
82
+
83
+ This also accounts for the rest: subdividing fixes it because each small triangle's anchor is near
84
+ its own pixels; flipping the diagonal changes each triangle's vertex set and so its conditioning;
85
+ it is TAA-specific because a static ~`1e-4` bias is invisible until jitter turns it into a temporal
86
+ signal; and it is resolution-dependent because the NDC magnitudes and the pixel footprint both are.
87
+
88
+ ## The fix
89
+
90
+ `chunk_barycentric_full` was rewritten to solve the same system without an anchor and without ever
91
+ dividing by w. A point with barycentric `l` sits at screen position
92
+ `sum(l_i * P_i.xy) / sum(l_i * P_i.w)`; setting that equal to the pixel and adding `sum(l) == 1`
93
+ gives a 3×3 system whose Cramer solution is three 2×2 determinants of `u = x - pixel.x*w` and
94
+ `v = y - pixel.y*w`, normalised by their sum. Each `l_i` is the same expression in the other two, so
95
+ rotating the corners permutes the outputs and changes nothing else. The derivatives are the same
96
+ system solved at `pixel + (1,0)` and `pixel + (0,1)` — exactly the whole-pixel forward difference
97
+ the old code produced by algebra, reusing every input.
98
+
99
+ Measured here, 1258×566, per-pixel relative luminance spread over a 16-frame burst:
100
+
101
+ | | before | after |
102
+ |---|---|---|
103
+ | default `(0,2,1) (2,3,1)` | 0.0458 / 0.0218 — **2.11** | 0.0153 / 0.0127 — **1.21** |
104
+ | anchor-rotated | 0.0139 / 0.0149 — 0.94 | 0.0154 / 0.0121 — 1.27 |
105
+ | flipped diagonal | 0.0382 / 0.0322 — 1.19 | 0.0120 / 0.0156 — 0.77 |
106
+ | 8×8 subdivided | 0.0185 / 0.0164 — 1.13 | 0.0154 / 0.0127 — 1.21 |
107
+ | 1898×926 anchor-rotated | 0.0216 / 0.0062 — **3.49** | 0.0105 / 0.0076 — 1.38 |
108
+ | 640×360 default | 0.0218 / 0.0534 — **0.41** | 0.0216 / 0.0208 — 1.04 |
109
+
110
+ Repeated three times from a fresh page, the first row reads 1.205 / 1.206 / 1.206 — so the change
111
+ from 2.11 is some three orders of magnitude larger than the run-to-run spread. (The brief that
112
+ prompted this warned that its whole-frame "pixels changed" number swung between 0.5% and 3.8% on
113
+ identical configurations. A metric that is profiled against a classified boundary rather than summed
114
+ over the frame does not have that problem.)
115
+
116
+ The two-triangle quad now measures the same as the same quad subdivided 8×8 — 1.21 against 1.21 —
117
+ and the subdivided case is the reference for "no seam is possible here", so the residual asymmetry
118
+ is the view's own, one half being more oblique than the other. The absolute flicker also falls 3×
119
+ on the side that was boiling and 1.7× on the side that was not, so this is a stability improvement
120
+ everywhere and not only at the edge.
121
+
122
+ It changes stability, not appearance, and does not cost anything:
123
+
124
+ - the converged image is unchanged — mean luminance per side 0.02902 / 0.03243 before,
125
+ 0.02918 / 0.03244 after;
126
+ - on Sponza, two builds differ by *less* than two runs of the same build (mean channel difference
127
+ 0.0277 against a 0.0295 run-to-run control, and the same 191 maximum on TAA edge pixels either
128
+ way — that control is what makes the 191 readable, and without it the number looks alarming);
129
+ - in a g-buffer-bound configuration (2400×1300, full-screen geometry, post chain off) it is
130
+ *faster*: 1.440 ms/frame against 1.502, medians of five 120-frame runs. Three reciprocals replace
131
+ seven divides, which is where that comes from;
132
+ - all 35 pre-existing tests in `chunk_barycentric_full.spec.js` pass unchanged, 8 were added for
133
+ the case that was failing, and the full `src/shade` suite (3051 tests) passes.
134
+
135
+ Of the 8 new tests, **6 also pass against the old implementation** — the algebra was never wrong
136
+ for `w != 0`, so those are characterisation, not regression. The two that fail against it are the
137
+ ones that matter: a vertex exactly on the eye plane (the old code divides by its w), and cyclic
138
+ rotation of the corners. On that second one the old code moves by exactly one f32 ULP even with the
139
+ emulator's f64 arithmetic; the new code is bit-identical.
140
+
141
+ Residual order-dependence is not zero — the anchor-rotated build still differs slightly, because
142
+ `barycentric_interpolate_uv` and the attribute interpolators sum `uv_i * l_i` in index order. That
143
+ is a sum of three same-signed terms with no catastrophic cancellation, and it no longer produces a
144
+ seam.
145
+
146
+ ### Why the pixel-relative offsets use `fma`
147
+
148
+ `u` and `v` are formed with `fma(-pixel.x, w, x)` rather than `x - pixel.x * w`. It is the one place
149
+ in the function where operands cancel, so it is the one place a fused multiply-add is worth asking
150
+ for: a single rounding, with the error bounded relative to the result rather than to the
151
+ intermediate product.
152
+
153
+ Measured rather than assumed, because our own tooling cannot answer it — `WGSLLanguageCore`
154
+ implements `fma` as plain `x * y + z`, so no emulator test observes fusion:
155
+
156
+ - **it changes the emitted code.** Full-precision aggregates over 356k pixels are bit-reproducible
157
+ within a build and move in the fifth digit between the two forms, so this driver was *not* already
158
+ contracting the plain expression;
159
+ - **it is faster** — 2.230 / 2.298 ms per frame against 2.429 for the plain form, medians of seven
160
+ 120-frame runs, alternating between builds. One op instead of two. Absolute frame times drift
161
+ between sessions by more than this difference, so only the adjacent pairs mean anything;
162
+ - **it buys no measurable image quality**, because there is none left to buy: the two-triangle quad
163
+ already matches its own 32×32 subdivision at extents of 425, 4000 and 40000, and the residual is
164
+ texture aliasing that subdivision does not fix either. The `extent` control exists to look for
165
+ headroom, and there is none up to a quad 94× the size of the repro.
166
+
167
+ An attempt to measure reconstruction accuracy directly — treating the subdivided quad as ground
168
+ truth for the same surface — **does not work**: 1×1 and 32×32 differ by about 1% in mean luminance
169
+ from causes unrelated to reconstruction, which swamps the effect. Recorded here so nobody spends the
170
+ afternoon on it twice.
171
+
172
+ What WGSL *guarantees* about fusion is not established either; the spec's §15.7.5 and §17.5.32 did
173
+ not come back legible. Portably the claim is "at worst a no-op, measured to help here".
174
+
175
+ The other cancellation site is `u.y*v.z - u.z*v.y` in `chunk_barycentric_solve`, a difference of two
176
+ products, which cancels hardest when a pixel sits near an edge. **The rewrite created it**, and it
177
+ is worth being clear about that rather than filing it as inherited debt: the old formulation
178
+ evaluated *one* 2×2 determinant, via the `determinant()` builtin, and it was a per-triangle constant
179
+ that only cancelled for slivers. This one evaluates *nine* — three cofactors in each of three solves
180
+ — and they depend on the pixel.
181
+
182
+ That trade is deliberate and it measures out well: when a cofactor cancels, the weight it produces
183
+ is near zero, so the absolute error in the interpolated attribute stays small, which is the benign
184
+ direction. The badly conditioned part of the old code was never its determinant but the
185
+ `deltaVec`/`interpInvW` chain that followed, and that is gone.
186
+
187
+ Kahan's fma-based 2×2 determinant would hold each of the nine to ~1.5 ulp regardless of
188
+ cancellation, for about 27 extra operations across the three solves. Nothing measurable currently
189
+ demands it; it is where to go if conditioning bites here again.
190
+
191
+ ## What is not established
192
+
193
+ - **The anchor rotation was a diagnostic, not a fix.** Before the rewrite it removed the seam at
194
+ 1258×566 and made it *worse* at 1898×926 (ratio 3.49 against the default's 1.11) — which is what
195
+ a rounding-conditioning story predicts, and why the fix had to remove the anchor rather than pick
196
+ a better one.
197
+ - **Jaggedness is a strong correlate, not a proven complete chain.** It tracks the output seam in
198
+ five of six configurations measured and fails in one (1898×926 anchor-rotated: jaggedness flat,
199
+ output ratio 3.49).
200
+ - **Which term dominates is unknown.** The anchor subtraction, the determinant and the gradient
201
+ terms were not separated.
202
+ - Anisotropy is *not* it: dropping the sampler to 1× leaves the step nearly intact (jaggedness ratio
203
+ 1.34, output ratio 1.86).
204
+
205
+ ## The two probes that are gone
206
+
207
+ Ruling out the disocclusion chain took reaching two things no extension can see: the velocity and
208
+ disocclusion buffers are not published to any frame record — `ViewTextures` says so deliberately —
209
+ and the resolve's blend weight is a local in a fragment shader. `capture_taa_inputs.js` and
210
+ `capture_taa_decision.js` read them through two hooks added to `Renderer` for the purpose, the
211
+ second one importing the resolve's own code chunks so the arithmetic it reports is the frame's
212
+ rather than a re-implementation of it.
213
+
214
+ Both are **removed**, along with the hooks. They were instrumentation for one question, that
215
+ question is answered above, and the cost of keeping them is two permanent fields on `Renderer` and
216
+ a per-frame branch in the hot path for everyone who never runs this page. Their findings survive in
217
+ "What it found"; the code survives in the history — `git log -- src/shade/playground/ground_seam`,
218
+ commit `df0b623f6`. Anything needing them again should restore the pair together and delete them
219
+ again afterwards.
220
+
221
+ What is left needs no hooks: `capture_scene_color.js` uses the sanctioned `RenderExtension` API,
222
+ and the depth readback goes through the public `Renderer.texture_depth_current`.
223
+
224
+ ## Reproducing
225
+
226
+ ```js
227
+ await configure({ segments: 1, triangulation: 'default', taa: true });
228
+
229
+ await measure(); // burst, difference map, per-side split, profile across both diagonals
230
+ await probe_depth(); // do the two triangles' depth planes meet on the shared edge?
231
+ await probe_pre_taa(16, 'pre_taa'); // the resolve's input
232
+ await probe_pre_taa(16, 'post_taa'); // its output
233
+ ```
234
+
235
+ Every one leaves its full result on `globalThis.__last_*`.
@@ -0,0 +1,45 @@
1
+ /**
2
+ * The scene colour *before* the temporal filter, made readable.
3
+ *
4
+ * This exists to split one question in two. The burst measurement sees the picture the temporal
5
+ * filter produced, and a seam in it can come from either side of that filter: the shading may be
6
+ * responding differently to the sub-pixel jitter on the two triangles, or the shading may be
7
+ * identical and the filter may be resolving it differently. Those want opposite fixes, and no
8
+ * amount of staring at the output distinguishes them.
9
+ *
10
+ * {@link FramePhase.AfterTransparency} is the last phase before the upscale, so what is captured
11
+ * here is the full pre-TAA frame at internal resolution — the temporal filter's *input*.
12
+ *
13
+ * The pass writes an imported texture, which the graph treats as a side effect, so it is not elided
14
+ * for having no consumer inside the frame.
15
+ */
16
+ export class CaptureSceneColor extends RenderExtension {
17
+ /**
18
+ * @param {GPUDevice} device
19
+ */
20
+ constructor(device: GPUDevice);
21
+ /**
22
+ * Whether to record at all. Off by default: a capture costs a full-resolution copy every frame,
23
+ * and the burst measurement this page mostly runs does not want one.
24
+ *
25
+ * @type {boolean}
26
+ */
27
+ enabled: boolean;
28
+ /**
29
+ * Luminance of the captured frame, one entry per pixel.
30
+ *
31
+ * Rec. 709 weights on the linear HDR values — this is upstream of the tonemap, so the numbers
32
+ * are radiance rather than display code values and there is no 8-bit quantization floor under
33
+ * the measurement.
34
+ *
35
+ * @returns {Promise<{luma: Float32Array, width: number, height: number}>}
36
+ */
37
+ read_luminance(): Promise<{
38
+ luma: Float32Array;
39
+ width: number;
40
+ height: number;
41
+ }>;
42
+ #private;
43
+ }
44
+ import { RenderExtension } from "../../renderer/extension/RenderExtension.js";
45
+ //# sourceMappingURL=capture_scene_color.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capture_scene_color.d.ts","sourceRoot":"","sources":["../../../../../src/shade/playground/ground_seam/capture_scene_color.js"],"names":[],"mappings":"AA8CA;;;;;;;;;;;;;;GAcG;AACH;IA2CI;;OAEG;IACH,+BAIC;IAfD;;;;;OAKG;IACH,SAFU,OAAO,CAED;IAuEhB;;;;;;;;OAQG;IACH;cAF4B,YAAY;eAAS,MAAM;gBAAU,MAAM;OAwCtE;;CACJ;gCA5N+B,6CAA6C"}