@woosh/meep-engine 3.10.0 → 3.11.0

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 (142) hide show
  1. package/README.md +168 -152
  2. package/package.json +1 -1
  3. package/src/REVIEW_2026_08_06.md +610 -610
  4. package/src/core/geom/3d/shape/ConvexHullShape3D.d.ts.map +1 -1
  5. package/src/core/geom/3d/shape/ConvexHullShape3D.js +28 -4
  6. package/src/engine/graphics/render/frame_graph/FrameGraph.d.ts +26 -0
  7. package/src/engine/graphics/render/frame_graph/FrameGraph.d.ts.map +1 -1
  8. package/src/engine/graphics/render/frame_graph/FrameGraph.js +47 -0
  9. package/src/engine/physics/ecs/PhysicsSystem.d.ts +0 -3
  10. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  11. package/src/engine/physics/ecs/PhysicsSystem.js +0 -3
  12. package/src/shade/device/ShadeGPUCommandContext.d.ts +21 -0
  13. package/src/shade/device/ShadeGPUCommandContext.d.ts.map +1 -1
  14. package/src/shade/device/ShadeGPUCommandContext.js +940 -749
  15. package/src/shade/device/timing/GPUTimerArray.d.ts +22 -4
  16. package/src/shade/device/timing/GPUTimerArray.d.ts.map +1 -1
  17. package/src/shade/device/timing/GPUTimerArray.js +88 -14
  18. package/src/shade/device/timing/GPU_PROFILER_PROPOSAL_2026_08_28.md +349 -98
  19. package/src/shade/device/timing/profile/GPUFrameRecorder.d.ts +93 -0
  20. package/src/shade/device/timing/profile/GPUFrameRecorder.d.ts.map +1 -0
  21. package/src/shade/device/timing/profile/GPUFrameRecorder.js +297 -0
  22. package/src/shade/device/timing/profile/GPUProfileCapture.d.ts +62 -0
  23. package/src/shade/device/timing/profile/GPUProfileCapture.d.ts.map +1 -0
  24. package/src/shade/device/timing/profile/GPUProfileCapture.js +77 -0
  25. package/src/shade/device/timing/profile/GPUProfileFrame.d.ts +73 -0
  26. package/src/shade/device/timing/profile/GPUProfileFrame.d.ts.map +1 -0
  27. package/src/shade/device/timing/profile/GPUProfileFrame.js +88 -0
  28. package/src/shade/device/timing/profile/GPUProfileLevel.d.ts +20 -0
  29. package/src/shade/device/timing/profile/GPUProfileLevel.d.ts.map +1 -0
  30. package/src/shade/device/timing/profile/GPUProfileLevel.js +50 -0
  31. package/src/shade/device/timing/profile/GPUProfileMeta.d.ts +63 -0
  32. package/src/shade/device/timing/profile/GPUProfileMeta.d.ts.map +1 -0
  33. package/src/shade/device/timing/profile/GPUProfileMeta.js +73 -0
  34. package/src/shade/device/timing/profile/GPUProfileSession.d.ts +173 -0
  35. package/src/shade/device/timing/profile/GPUProfileSession.d.ts.map +1 -0
  36. package/src/shade/device/timing/profile/GPUProfileSession.js +470 -0
  37. package/src/shade/device/timing/profile/GPUProfileSpan.d.ts +60 -0
  38. package/src/shade/device/timing/profile/GPUProfileSpan.d.ts.map +1 -0
  39. package/src/shade/device/timing/profile/GPUProfileSpan.js +65 -0
  40. package/src/shade/device/timing/profile/GPUProfileSpanKind.d.ts +19 -0
  41. package/src/shade/device/timing/profile/GPUProfileSpanKind.d.ts.map +1 -0
  42. package/src/shade/device/timing/profile/GPUProfileSpanKind.js +25 -0
  43. package/src/shade/device/timing/profile/GPUProfileTopology.d.ts +159 -0
  44. package/src/shade/device/timing/profile/GPUProfileTopology.d.ts.map +1 -0
  45. package/src/shade/device/timing/profile/GPUProfileTopology.js +202 -0
  46. package/src/shade/device/timing/profile/GPUProfileWork.d.ts +90 -0
  47. package/src/shade/device/timing/profile/GPUProfileWork.d.ts.map +1 -0
  48. package/src/shade/device/timing/profile/GPUProfileWork.js +115 -0
  49. package/src/shade/device/timing/profile/SGPTDefect.d.ts +43 -0
  50. package/src/shade/device/timing/profile/SGPTDefect.d.ts.map +1 -0
  51. package/src/shade/device/timing/profile/SGPTDefect.js +65 -0
  52. package/src/shade/device/timing/profile/SGPTHeader.d.ts +38 -0
  53. package/src/shade/device/timing/profile/SGPTHeader.d.ts.map +1 -0
  54. package/src/shade/device/timing/profile/SGPTHeader.js +46 -0
  55. package/src/shade/device/timing/profile/SGPTRecordRef.d.ts +37 -0
  56. package/src/shade/device/timing/profile/SGPTRecordRef.d.ts.map +1 -0
  57. package/src/shade/device/timing/profile/SGPTRecordRef.js +45 -0
  58. package/src/shade/device/timing/profile/SGPTWriteStream.d.ts +103 -0
  59. package/src/shade/device/timing/profile/SGPTWriteStream.d.ts.map +1 -0
  60. package/src/shade/device/timing/profile/SGPTWriteStream.js +287 -0
  61. package/src/shade/device/timing/profile/SGPT_DEFECT.d.ts +19 -0
  62. package/src/shade/device/timing/profile/SGPT_DEFECT.d.ts.map +1 -0
  63. package/src/shade/device/timing/profile/SGPT_DEFECT.js +26 -0
  64. package/src/shade/device/timing/profile/SGPT_FLAG.d.ts +8 -0
  65. package/src/shade/device/timing/profile/SGPT_FLAG.d.ts.map +1 -0
  66. package/src/shade/device/timing/profile/SGPT_FLAG.js +15 -0
  67. package/src/shade/device/timing/profile/SGPT_FORMAT.md +345 -0
  68. package/src/shade/device/timing/profile/SGPT_FORMAT_VERSION.d.ts +10 -0
  69. package/src/shade/device/timing/profile/SGPT_FORMAT_VERSION.d.ts.map +1 -0
  70. package/src/shade/device/timing/profile/SGPT_FORMAT_VERSION.js +9 -0
  71. package/src/shade/device/timing/profile/SGPT_FRAME_SLACK.d.ts +17 -0
  72. package/src/shade/device/timing/profile/SGPT_FRAME_SLACK.d.ts.map +1 -0
  73. package/src/shade/device/timing/profile/SGPT_FRAME_SLACK.js +16 -0
  74. package/src/shade/device/timing/profile/SGPT_HEADER_CHECKSUM_COVERAGE.d.ts +16 -0
  75. package/src/shade/device/timing/profile/SGPT_HEADER_CHECKSUM_COVERAGE.d.ts.map +1 -0
  76. package/src/shade/device/timing/profile/SGPT_HEADER_CHECKSUM_COVERAGE.js +15 -0
  77. package/src/shade/device/timing/profile/SGPT_HEADER_OFFSET.d.ts +15 -0
  78. package/src/shade/device/timing/profile/SGPT_HEADER_OFFSET.d.ts.map +1 -0
  79. package/src/shade/device/timing/profile/SGPT_HEADER_OFFSET.js +29 -0
  80. package/src/shade/device/timing/profile/SGPT_HEADER_SIZE.d.ts +7 -0
  81. package/src/shade/device/timing/profile/SGPT_HEADER_SIZE.d.ts.map +1 -0
  82. package/src/shade/device/timing/profile/SGPT_HEADER_SIZE.js +6 -0
  83. package/src/shade/device/timing/profile/SGPT_MAGIC.d.ts +7 -0
  84. package/src/shade/device/timing/profile/SGPT_MAGIC.d.ts.map +1 -0
  85. package/src/shade/device/timing/profile/SGPT_MAGIC.js +6 -0
  86. package/src/shade/device/timing/profile/SGPT_MIN_READER_VERSION.d.ts +16 -0
  87. package/src/shade/device/timing/profile/SGPT_MIN_READER_VERSION.d.ts.map +1 -0
  88. package/src/shade/device/timing/profile/SGPT_MIN_READER_VERSION.js +15 -0
  89. package/src/shade/device/timing/profile/SGPT_RECORD_HEADER_SIZE.d.ts +7 -0
  90. package/src/shade/device/timing/profile/SGPT_RECORD_HEADER_SIZE.d.ts.map +1 -0
  91. package/src/shade/device/timing/profile/SGPT_RECORD_HEADER_SIZE.js +6 -0
  92. package/src/shade/device/timing/profile/SGPT_RECORD_OFFSET.d.ts +13 -0
  93. package/src/shade/device/timing/profile/SGPT_RECORD_OFFSET.d.ts.map +1 -0
  94. package/src/shade/device/timing/profile/SGPT_RECORD_OFFSET.js +23 -0
  95. package/src/shade/device/timing/profile/SGPT_RECORD_SYNC.d.ts +12 -0
  96. package/src/shade/device/timing/profile/SGPT_RECORD_SYNC.d.ts.map +1 -0
  97. package/src/shade/device/timing/profile/SGPT_RECORD_SYNC.js +11 -0
  98. package/src/shade/device/timing/profile/SGPT_RECORD_TYPE.d.ts +18 -0
  99. package/src/shade/device/timing/profile/SGPT_RECORD_TYPE.d.ts.map +1 -0
  100. package/src/shade/device/timing/profile/SGPT_RECORD_TYPE.js +46 -0
  101. package/src/shade/device/timing/profile/frame_graph_extract_topology.d.ts +20 -0
  102. package/src/shade/device/timing/profile/frame_graph_extract_topology.d.ts.map +1 -0
  103. package/src/shade/device/timing/profile/frame_graph_extract_topology.js +174 -0
  104. package/src/shade/device/timing/profile/make_profiling_pass_encoder.d.ts +21 -0
  105. package/src/shade/device/timing/profile/make_profiling_pass_encoder.d.ts.map +1 -0
  106. package/src/shade/device/timing/profile/make_profiling_pass_encoder.js +114 -0
  107. package/src/shade/device/timing/profile/parse_workgroup_size.d.ts +20 -0
  108. package/src/shade/device/timing/profile/parse_workgroup_size.d.ts.map +1 -0
  109. package/src/shade/device/timing/profile/parse_workgroup_size.js +43 -0
  110. package/src/shade/device/timing/profile/sgpt_fourcc.d.ts +18 -0
  111. package/src/shade/device/timing/profile/sgpt_fourcc.d.ts.map +1 -0
  112. package/src/shade/device/timing/profile/sgpt_fourcc.js +34 -0
  113. package/src/shade/device/timing/profile/sgpt_frame_codec.d.ts +42 -0
  114. package/src/shade/device/timing/profile/sgpt_frame_codec.d.ts.map +1 -0
  115. package/src/shade/device/timing/profile/sgpt_frame_codec.js +172 -0
  116. package/src/shade/device/timing/profile/sgpt_meta_codec.d.ts +20 -0
  117. package/src/shade/device/timing/profile/sgpt_meta_codec.d.ts.map +1 -0
  118. package/src/shade/device/timing/profile/sgpt_meta_codec.js +65 -0
  119. package/src/shade/device/timing/profile/sgpt_read_capture.d.ts +19 -0
  120. package/src/shade/device/timing/profile/sgpt_read_capture.d.ts.map +1 -0
  121. package/src/shade/device/timing/profile/sgpt_read_capture.js +134 -0
  122. package/src/shade/device/timing/profile/sgpt_read_header.d.ts +22 -0
  123. package/src/shade/device/timing/profile/sgpt_read_header.d.ts.map +1 -0
  124. package/src/shade/device/timing/profile/sgpt_read_header.js +94 -0
  125. package/src/shade/device/timing/profile/sgpt_read_records.d.ts +27 -0
  126. package/src/shade/device/timing/profile/sgpt_read_records.d.ts.map +1 -0
  127. package/src/shade/device/timing/profile/sgpt_read_records.js +153 -0
  128. package/src/shade/device/timing/profile/sgpt_topology_codec.d.ts +54 -0
  129. package/src/shade/device/timing/profile/sgpt_topology_codec.d.ts.map +1 -0
  130. package/src/shade/device/timing/profile/sgpt_topology_codec.js +329 -0
  131. package/src/shade/device/timing/profile/sgpt_write_header.d.ts +22 -0
  132. package/src/shade/device/timing/profile/sgpt_write_header.d.ts.map +1 -0
  133. package/src/shade/device/timing/profile/sgpt_write_header.js +47 -0
  134. package/src/shade/device/timing/profile/sgpt_write_record.d.ts +23 -0
  135. package/src/shade/device/timing/profile/sgpt_write_record.d.ts.map +1 -0
  136. package/src/shade/device/timing/profile/sgpt_write_record.js +62 -0
  137. package/src/shade/renderer/Renderer.d.ts +21 -0
  138. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  139. package/src/shade/renderer/Renderer.js +2513 -2455
  140. package/src/engine/save/GameStateLoader.d.ts +0 -49
  141. package/src/engine/save/GameStateLoader.d.ts.map +0 -1
  142. package/src/engine/save/GameStateLoader.js +0 -168
@@ -5,18 +5,36 @@ export class GPUTimerArray {
5
5
  * @param {number} [size] number of query slots
6
6
  */
7
7
  constructor(device: GPUDevice, size?: number);
8
+ /**
9
+ * How many passes went untimed because {@link size} was too small for the frame.
10
+ *
11
+ * @returns {number}
12
+ */
13
+ get dropped_count(): number;
8
14
  /**
9
15
  *
10
16
  * @param {string} label
11
- * @returns {GPUComputePassTimestampWrites}
17
+ * @returns {GPUComputePassTimestampWrites|undefined} undefined when the array is full
12
18
  */
13
- getComputeWrites(label: string): GPUComputePassTimestampWrites;
19
+ getComputeWrites(label: string): GPUComputePassTimestampWrites | undefined;
14
20
  /**
15
21
  *
16
22
  * @param {string} label
17
- * @returns {GPURenderPassTimestampWrites}
23
+ * @returns {GPURenderPassTimestampWrites|undefined} undefined when the array is full
24
+ */
25
+ getRenderWrites(label: string): GPURenderPassTimestampWrites | undefined;
26
+ /**
27
+ * Visit every slot that was claimed this frame, in slot order, with its raw timestamps.
28
+ *
29
+ * Raw: nanoseconds as the device reported them, `BigInt`, unscaled. {@link
30
+ * results_to_console_table} is the same data rounded for a human to read at a glance; a
31
+ * recording needs the values themselves, and the difference matters once quantization is in
32
+ * play — see the profiler's treatment of `timestamp_period_ns`.
33
+ *
34
+ * @param {(slot_id: number, label: string, type: string, t_begin: bigint, t_end: bigint) => void} visitor
35
+ * @returns {void}
18
36
  */
19
- getRenderWrites(label: string): GPURenderPassTimestampWrites;
37
+ traverse_results(visitor: (slot_id: number, label: string, type: string, t_begin: bigint, t_end: bigint) => void): void;
20
38
  destroy(): void;
21
39
  /**
22
40
  *
@@ -1 +1 @@
1
- {"version":3,"file":"GPUTimerArray.d.ts","sourceRoot":"","sources":["../../../../../src/shade/device/timing/GPUTimerArray.js"],"names":[],"mappings":"AAGA;IA8FI;;;;OAIG;IACH,sCAFW,MAAM,EAoChB;IA/ED;;;;OAIG;IACH,wBAHW,MAAM,iCAgBhB;IAED;;;;OAIG;IACH,uBAHW,MAAM,gCAgBhB;IA2CD,gBAQC;IAED;;;OAGG;IACH,0CAQC;IAED,kCAwBC;IAED;;;OAGG;IACH,gCAqBC;;CAEJ"}
1
+ {"version":3,"file":"GPUTimerArray.d.ts","sourceRoot":"","sources":["../../../../../src/shade/device/timing/GPUTimerArray.js"],"names":[],"mappings":"AAGA;IAwKI;;;;OAIG;IACH,sCAFW,MAAM,EAoChB;IAjKD;;;;OAIG;IACH,4BAEC;IAgED;;;;OAIG;IACH,wBAHW,MAAM,GACJ,gCAA8B,SAAS,CAInD;IAED;;;;OAIG;IACH,uBAHW,MAAM,GACJ,+BAA6B,SAAS,CAIlD;IAED;;;;;;;;;;OAUG;IACH,oCAHqB,MAAM,SAAS,MAAM,QAAQ,MAAM,WAAW,MAAM,SAAS,MAAM,KAAK,IAAI,GACpF,IAAI,CAsBhB;IA2CD,gBAQC;IAED;;;OAGG;IACH,0CAQC;IAED,kCAwBC;IAED;;;OAGG;IACH,gCAqBC;;CAEJ"}
@@ -38,13 +38,44 @@ export class GPUTimerArray {
38
38
  #slot_metadata = [];
39
39
 
40
40
  /**
41
+ * Passes that asked for a slot after the array ran out.
42
+ *
43
+ * Reported rather than swallowed. A profile capture instruments far more passes than a one-off
44
+ * debug frame does, and a silent shortfall reads downstream as "those passes were free".
45
+ *
46
+ * @type {number}
47
+ */
48
+ #dropped_count = 0;
49
+
50
+ /**
51
+ * How many passes went untimed because {@link size} was too small for the frame.
52
+ *
53
+ * @returns {number}
54
+ */
55
+ get dropped_count() {
56
+ return this.#dropped_count;
57
+ }
58
+
59
+ /**
60
+ * Claim a slot, or report that there is none.
61
+ *
62
+ * The bound check is the point. `IdPool` hands out ids indefinitely, and an id at or past
63
+ * {@link size} addresses a query index the query set does not have — which WebGPU rejects at
64
+ * the `beginRenderPass` that used it, blaming a pass that did nothing wrong and saying nothing
65
+ * about the one that exhausted the array.
41
66
  *
42
67
  * @param {string} label
43
68
  * @param {string} type
44
- * @return {number}
69
+ * @return {number} slot id, or -1 when the array is full
45
70
  */
46
71
  #bind_slot(label, type) {
47
72
 
73
+ if (this.#slots.peek() >= this.#size) {
74
+ this.#dropped_count++;
75
+
76
+ return -1;
77
+ }
78
+
48
79
  const id = this.#slots.get();
49
80
 
50
81
  this.#slot_metadata[id] = {
@@ -56,15 +87,27 @@ export class GPUTimerArray {
56
87
  }
57
88
 
58
89
  /**
59
- *
60
90
  * @param {string} label
61
- * @returns {GPUComputePassTimestampWrites}
91
+ * @param {string} type one of 'compute', 'render'
92
+ * @returns {GPUComputePassTimestampWrites|GPURenderPassTimestampWrites|undefined} undefined when
93
+ * there is no slot left, in which case the caller must leave `timestampWrites` off its
94
+ * descriptor — an untimed pass is the correct degradation, an invalid one is not
62
95
  */
63
- getComputeWrites(label) {
96
+ #get_writes(label, type) {
64
97
 
65
98
  const querySet = this.#query_set;
66
99
 
67
- const id = this.#bind_slot(label, 'compute');
100
+ if (querySet === undefined) {
101
+ // same guard as `resolve` and `download_results`: with the feature withheld the timers
102
+ // go quiet rather than taking the frame down
103
+ return undefined;
104
+ }
105
+
106
+ const id = this.#bind_slot(label, type);
107
+
108
+ if (id === -1) {
109
+ return undefined;
110
+ }
68
111
 
69
112
  const index0 = id * 2;
70
113
 
@@ -78,21 +121,52 @@ export class GPUTimerArray {
78
121
  /**
79
122
  *
80
123
  * @param {string} label
81
- * @returns {GPURenderPassTimestampWrites}
124
+ * @returns {GPUComputePassTimestampWrites|undefined} undefined when the array is full
125
+ */
126
+ getComputeWrites(label) {
127
+ return this.#get_writes(label, 'compute');
128
+ }
129
+
130
+ /**
131
+ *
132
+ * @param {string} label
133
+ * @returns {GPURenderPassTimestampWrites|undefined} undefined when the array is full
82
134
  */
83
135
  getRenderWrites(label) {
136
+ return this.#get_writes(label, 'render');
137
+ }
84
138
 
85
- const querySet = this.#query_set;
139
+ /**
140
+ * Visit every slot that was claimed this frame, in slot order, with its raw timestamps.
141
+ *
142
+ * Raw: nanoseconds as the device reported them, `BigInt`, unscaled. {@link
143
+ * results_to_console_table} is the same data rounded for a human to read at a glance; a
144
+ * recording needs the values themselves, and the difference matters once quantization is in
145
+ * play — see the profiler's treatment of `timestamp_period_ns`.
146
+ *
147
+ * @param {(slot_id: number, label: string, type: string, t_begin: bigint, t_end: bigint) => void} visitor
148
+ * @returns {void}
149
+ */
150
+ traverse_results(visitor) {
151
+ assert.isFunction(visitor, 'visitor');
86
152
 
87
- const id = this.#bind_slot(label, 'render');
153
+ const results = this.#results;
88
154
 
89
- const index0 = id * 2;
155
+ if (results === undefined) {
156
+ return;
157
+ }
90
158
 
91
- return {
92
- querySet,
93
- beginningOfPassWriteIndex: index0,
94
- endOfPassWriteIndex: index0 + 1,
95
- };
159
+ this.#slots.traverseUsed(slot_id => {
160
+ const meta = this.#slot_metadata[slot_id];
161
+
162
+ visitor(
163
+ slot_id,
164
+ meta.label,
165
+ meta.type,
166
+ results[slot_id * 2],
167
+ results[slot_id * 2 + 1]
168
+ );
169
+ });
96
170
  }
97
171
 
98
172
  /**