@forgeax/engine-rhi-debug 0.0.0-dev.8d955ade1c79

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 (237) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +178 -0
  3. package/dist/.tsbuildinfo +1 -0
  4. package/dist/__tests__/bootstrap-integration.test.d.ts +2 -0
  5. package/dist/__tests__/bootstrap-integration.test.d.ts.map +1 -0
  6. package/dist/__tests__/consumer-inventory.unit.test.d.ts +2 -0
  7. package/dist/__tests__/consumer-inventory.unit.test.d.ts.map +1 -0
  8. package/dist/__tests__/copy-src-usage-validity.dawn.test.d.ts +15 -0
  9. package/dist/__tests__/copy-src-usage-validity.dawn.test.d.ts.map +1 -0
  10. package/dist/__tests__/coverage-invariant.test-d.d.ts +2 -0
  11. package/dist/__tests__/coverage-invariant.test-d.d.ts.map +1 -0
  12. package/dist/__tests__/coverage-invariant.unit.test.d.ts +2 -0
  13. package/dist/__tests__/coverage-invariant.unit.test.d.ts.map +1 -0
  14. package/dist/__tests__/e2e.browser.test.d.ts +2 -0
  15. package/dist/__tests__/e2e.browser.test.d.ts.map +1 -0
  16. package/dist/__tests__/error-code-narrowing.test-d.d.ts +2 -0
  17. package/dist/__tests__/error-code-narrowing.test-d.d.ts.map +1 -0
  18. package/dist/__tests__/errors-v7.test-d.d.ts +2 -0
  19. package/dist/__tests__/errors-v7.test-d.d.ts.map +1 -0
  20. package/dist/__tests__/errors-v7.unit.test.d.ts +2 -0
  21. package/dist/__tests__/errors-v7.unit.test.d.ts.map +1 -0
  22. package/dist/__tests__/errors.unit.test.d.ts +2 -0
  23. package/dist/__tests__/errors.unit.test.d.ts.map +1 -0
  24. package/dist/__tests__/event-semantics-coverage.unit.test.d.ts +2 -0
  25. package/dist/__tests__/event-semantics-coverage.unit.test.d.ts.map +1 -0
  26. package/dist/__tests__/format-info.unit.test.d.ts +2 -0
  27. package/dist/__tests__/format-info.unit.test.d.ts.map +1 -0
  28. package/dist/__tests__/frame-model-parity.test-d.d.ts +2 -0
  29. package/dist/__tests__/frame-model-parity.test-d.d.ts.map +1 -0
  30. package/dist/__tests__/frame-model-parity.unit.test.d.ts +2 -0
  31. package/dist/__tests__/frame-model-parity.unit.test.d.ts.map +1 -0
  32. package/dist/__tests__/guard-gates.test.d.ts +2 -0
  33. package/dist/__tests__/guard-gates.test.d.ts.map +1 -0
  34. package/dist/__tests__/public-surface.integration.test.d.ts +2 -0
  35. package/dist/__tests__/public-surface.integration.test.d.ts.map +1 -0
  36. package/dist/__tests__/readback-fault-cleanup.unit.test.d.ts +2 -0
  37. package/dist/__tests__/readback-fault-cleanup.unit.test.d.ts.map +1 -0
  38. package/dist/__tests__/readback-format-matrix.dawn.test.d.ts +2 -0
  39. package/dist/__tests__/readback-format-matrix.dawn.test.d.ts.map +1 -0
  40. package/dist/__tests__/readback-format-matrix.unit.test.d.ts +2 -0
  41. package/dist/__tests__/readback-format-matrix.unit.test.d.ts.map +1 -0
  42. package/dist/__tests__/readback-matrix-fixture.d.ts +32 -0
  43. package/dist/__tests__/readback-matrix-fixture.d.ts.map +1 -0
  44. package/dist/__tests__/recorder-bootstrap.unit.test.d.ts +2 -0
  45. package/dist/__tests__/recorder-bootstrap.unit.test.d.ts.map +1 -0
  46. package/dist/__tests__/recorder-budget.unit.test.d.ts +2 -0
  47. package/dist/__tests__/recorder-budget.unit.test.d.ts.map +1 -0
  48. package/dist/__tests__/recorder-fail-fast.unit.test.d.ts +2 -0
  49. package/dist/__tests__/recorder-fail-fast.unit.test.d.ts.map +1 -0
  50. package/dist/__tests__/recorder-lifecycle.unit.test.d.ts +2 -0
  51. package/dist/__tests__/recorder-lifecycle.unit.test.d.ts.map +1 -0
  52. package/dist/__tests__/recorder-push-event.unit.test.d.ts +2 -0
  53. package/dist/__tests__/recorder-push-event.unit.test.d.ts.map +1 -0
  54. package/dist/__tests__/recorder-session.integration.test.d.ts +2 -0
  55. package/dist/__tests__/recorder-session.integration.test.d.ts.map +1 -0
  56. package/dist/__tests__/recorder-session.unit.test.d.ts +2 -0
  57. package/dist/__tests__/recorder-session.unit.test.d.ts.map +1 -0
  58. package/dist/__tests__/recorder-steady-frame.dawn.test.d.ts +2 -0
  59. package/dist/__tests__/recorder-steady-frame.dawn.test.d.ts.map +1 -0
  60. package/dist/__tests__/replay-fail-fast.unit.test.d.ts +2 -0
  61. package/dist/__tests__/replay-fail-fast.unit.test.d.ts.map +1 -0
  62. package/dist/__tests__/replay-session.dawn.test.d.ts +2 -0
  63. package/dist/__tests__/replay-session.dawn.test.d.ts.map +1 -0
  64. package/dist/__tests__/replay-session.test-d.d.ts +2 -0
  65. package/dist/__tests__/replay-session.test-d.d.ts.map +1 -0
  66. package/dist/__tests__/replay-session.unit.test.d.ts +2 -0
  67. package/dist/__tests__/replay-session.unit.test.d.ts.map +1 -0
  68. package/dist/__tests__/resolve-texture-descriptor.unit.test.d.ts +2 -0
  69. package/dist/__tests__/resolve-texture-descriptor.unit.test.d.ts.map +1 -0
  70. package/dist/__tests__/resource-lifecycle.unit.test.d.ts +2 -0
  71. package/dist/__tests__/resource-lifecycle.unit.test.d.ts.map +1 -0
  72. package/dist/__tests__/rhi-debug-fresh-replay.dawn.test.d.ts +2 -0
  73. package/dist/__tests__/rhi-debug-fresh-replay.dawn.test.d.ts.map +1 -0
  74. package/dist/__tests__/tape-index.unit.test.d.ts +2 -0
  75. package/dist/__tests__/tape-index.unit.test.d.ts.map +1 -0
  76. package/dist/__tests__/tape-v7-invalid.unit.test.d.ts +2 -0
  77. package/dist/__tests__/tape-v7-invalid.unit.test.d.ts.map +1 -0
  78. package/dist/__tests__/tape-v7-roundtrip.unit.test.d.ts +2 -0
  79. package/dist/__tests__/tape-v7-roundtrip.unit.test.d.ts.map +1 -0
  80. package/dist/__tests__/tape-v7-version.unit.test.d.ts +2 -0
  81. package/dist/__tests__/tape-v7-version.unit.test.d.ts.map +1 -0
  82. package/dist/__tests__/tree-shake.unit.test.d.ts +2 -0
  83. package/dist/__tests__/tree-shake.unit.test.d.ts.map +1 -0
  84. package/dist/__tests__/types.test.d.ts +2 -0
  85. package/dist/__tests__/types.test.d.ts.map +1 -0
  86. package/dist/browser.d.ts +45 -0
  87. package/dist/browser.d.ts.map +1 -0
  88. package/dist/browser.mjs +83 -0
  89. package/dist/browser.mjs.map +1 -0
  90. package/dist/errors.d.ts +85 -0
  91. package/dist/errors.d.ts.map +1 -0
  92. package/dist/frame-model.d.ts +158 -0
  93. package/dist/frame-model.d.ts.map +1 -0
  94. package/dist/index.d.ts +17 -0
  95. package/dist/index.d.ts.map +1 -0
  96. package/dist/index.mjs +10415 -0
  97. package/dist/index.mjs.map +1 -0
  98. package/dist/protocol/codec.d.ts +6 -0
  99. package/dist/protocol/codec.d.ts.map +1 -0
  100. package/dist/protocol/event-semantics.d.ts +15 -0
  101. package/dist/protocol/event-semantics.d.ts.map +1 -0
  102. package/dist/protocol/tape-index.d.ts +30 -0
  103. package/dist/protocol/tape-index.d.ts.map +1 -0
  104. package/dist/protocol/types.d.ts +44 -0
  105. package/dist/protocol/types.d.ts.map +1 -0
  106. package/dist/protocol/validation.d.ts +7 -0
  107. package/dist/protocol/validation.d.ts.map +1 -0
  108. package/dist/readback.d.ts +156 -0
  109. package/dist/readback.d.ts.map +1 -0
  110. package/dist/recorder/assemble.d.ts +11 -0
  111. package/dist/recorder/assemble.d.ts.map +1 -0
  112. package/dist/recorder/closure.d.ts +39 -0
  113. package/dist/recorder/closure.d.ts.map +1 -0
  114. package/dist/recorder/core.d.ts +296 -0
  115. package/dist/recorder/core.d.ts.map +1 -0
  116. package/dist/recorder/device.d.ts +4 -0
  117. package/dist/recorder/device.d.ts.map +1 -0
  118. package/dist/recorder/encoder.d.ts +5 -0
  119. package/dist/recorder/encoder.d.ts.map +1 -0
  120. package/dist/recorder/lifecycle.d.ts +20 -0
  121. package/dist/recorder/lifecycle.d.ts.map +1 -0
  122. package/dist/recorder/pass.d.ts +6 -0
  123. package/dist/recorder/pass.d.ts.map +1 -0
  124. package/dist/recorder/proxy.d.ts +19 -0
  125. package/dist/recorder/proxy.d.ts.map +1 -0
  126. package/dist/recorder/queue.d.ts +4 -0
  127. package/dist/recorder/queue.d.ts.map +1 -0
  128. package/dist/recorder/resource-registry.d.ts +15 -0
  129. package/dist/recorder/resource-registry.d.ts.map +1 -0
  130. package/dist/recorder/session.d.ts +25 -0
  131. package/dist/recorder/session.d.ts.map +1 -0
  132. package/dist/recorder/shader.d.ts +3 -0
  133. package/dist/recorder/shader.d.ts.map +1 -0
  134. package/dist/recorder/snapshot.d.ts +10 -0
  135. package/dist/recorder/snapshot.d.ts.map +1 -0
  136. package/dist/recorder/wrap.d.ts +4 -0
  137. package/dist/recorder/wrap.d.ts.map +1 -0
  138. package/dist/recorder.d.ts +7 -0
  139. package/dist/recorder.d.ts.map +1 -0
  140. package/dist/replay/device-request.d.ts +8 -0
  141. package/dist/replay/device-request.d.ts.map +1 -0
  142. package/dist/replay/execute-support.d.ts +33 -0
  143. package/dist/replay/execute-support.d.ts.map +1 -0
  144. package/dist/replay/execute.d.ts +18 -0
  145. package/dist/replay/execute.d.ts.map +1 -0
  146. package/dist/replay/readback.d.ts +32 -0
  147. package/dist/replay/readback.d.ts.map +1 -0
  148. package/dist/replay/resources.d.ts +57 -0
  149. package/dist/replay/resources.d.ts.map +1 -0
  150. package/dist/replay/session.d.ts +49 -0
  151. package/dist/replay/session.d.ts.map +1 -0
  152. package/dist/replay/texture-format.d.ts +21 -0
  153. package/dist/replay/texture-format.d.ts.map +1 -0
  154. package/dist/texel-decode.d.ts +35 -0
  155. package/dist/texel-decode.d.ts.map +1 -0
  156. package/dist/texel-layout.d.ts +76 -0
  157. package/dist/texel-layout.d.ts.map +1 -0
  158. package/dist/types.d.ts +722 -0
  159. package/dist/types.d.ts.map +1 -0
  160. package/package.json +72 -0
  161. package/src/__tests__/bootstrap-integration.test.ts +268 -0
  162. package/src/__tests__/consumer-inventory.unit.test.ts +154 -0
  163. package/src/__tests__/copy-src-usage-validity.dawn.test.ts +117 -0
  164. package/src/__tests__/coverage-invariant.test-d.ts +115 -0
  165. package/src/__tests__/coverage-invariant.unit.test.ts +45 -0
  166. package/src/__tests__/e2e.browser.test.ts +239 -0
  167. package/src/__tests__/error-code-narrowing.test-d.ts +32 -0
  168. package/src/__tests__/errors-v7.test-d.ts +19 -0
  169. package/src/__tests__/errors-v7.unit.test.ts +15 -0
  170. package/src/__tests__/errors.unit.test.ts +83 -0
  171. package/src/__tests__/event-semantics-coverage.unit.test.ts +22 -0
  172. package/src/__tests__/format-info.unit.test.ts +85 -0
  173. package/src/__tests__/frame-model-parity.test-d.ts +20 -0
  174. package/src/__tests__/frame-model-parity.unit.test.ts +285 -0
  175. package/src/__tests__/guard-gates.test.ts +317 -0
  176. package/src/__tests__/public-surface.integration.test.ts +38 -0
  177. package/src/__tests__/readback-fault-cleanup.unit.test.ts +66 -0
  178. package/src/__tests__/readback-format-matrix.dawn.test.ts +378 -0
  179. package/src/__tests__/readback-format-matrix.unit.test.ts +120 -0
  180. package/src/__tests__/readback-matrix-fixture.ts +20 -0
  181. package/src/__tests__/recorder-bootstrap.unit.test.ts +302 -0
  182. package/src/__tests__/recorder-budget.unit.test.ts +42 -0
  183. package/src/__tests__/recorder-fail-fast.unit.test.ts +434 -0
  184. package/src/__tests__/recorder-lifecycle.unit.test.ts +42 -0
  185. package/src/__tests__/recorder-push-event.unit.test.ts +573 -0
  186. package/src/__tests__/recorder-session.integration.test.ts +32 -0
  187. package/src/__tests__/recorder-session.unit.test.ts +63 -0
  188. package/src/__tests__/recorder-steady-frame.dawn.test.ts +52 -0
  189. package/src/__tests__/replay-fail-fast.unit.test.ts +155 -0
  190. package/src/__tests__/replay-session.dawn.test.ts +220 -0
  191. package/src/__tests__/replay-session.test-d.ts +27 -0
  192. package/src/__tests__/replay-session.unit.test.ts +171 -0
  193. package/src/__tests__/resolve-texture-descriptor.unit.test.ts +144 -0
  194. package/src/__tests__/resource-lifecycle.unit.test.ts +114 -0
  195. package/src/__tests__/rhi-debug-fresh-replay.dawn.test.ts +178 -0
  196. package/src/__tests__/tape-index.unit.test.ts +56 -0
  197. package/src/__tests__/tape-v7-invalid.unit.test.ts +45 -0
  198. package/src/__tests__/tape-v7-roundtrip.unit.test.ts +66 -0
  199. package/src/__tests__/tape-v7-version.unit.test.ts +13 -0
  200. package/src/__tests__/tree-shake.unit.test.ts +151 -0
  201. package/src/__tests__/types.test.ts +257 -0
  202. package/src/browser.ts +146 -0
  203. package/src/errors.ts +173 -0
  204. package/src/frame-model.ts +753 -0
  205. package/src/index.ts +92 -0
  206. package/src/pako.d.ts +8 -0
  207. package/src/protocol/codec.ts +220 -0
  208. package/src/protocol/event-semantics.ts +180 -0
  209. package/src/protocol/tape-index.ts +120 -0
  210. package/src/protocol/types.ts +60 -0
  211. package/src/protocol/validation.ts +173 -0
  212. package/src/readback.ts +804 -0
  213. package/src/recorder/assemble.ts +192 -0
  214. package/src/recorder/closure.ts +408 -0
  215. package/src/recorder/core.ts +587 -0
  216. package/src/recorder/device.ts +474 -0
  217. package/src/recorder/encoder.ts +251 -0
  218. package/src/recorder/lifecycle.ts +847 -0
  219. package/src/recorder/pass.ts +241 -0
  220. package/src/recorder/proxy.ts +59 -0
  221. package/src/recorder/queue.ts +109 -0
  222. package/src/recorder/resource-registry.ts +53 -0
  223. package/src/recorder/session.ts +152 -0
  224. package/src/recorder/shader.ts +47 -0
  225. package/src/recorder/snapshot.ts +38 -0
  226. package/src/recorder/wrap.ts +157 -0
  227. package/src/recorder.ts +15 -0
  228. package/src/replay/device-request.ts +38 -0
  229. package/src/replay/execute-support.ts +243 -0
  230. package/src/replay/execute.ts +870 -0
  231. package/src/replay/readback.ts +671 -0
  232. package/src/replay/resources.ts +154 -0
  233. package/src/replay/session.ts +509 -0
  234. package/src/replay/texture-format.ts +99 -0
  235. package/src/texel-decode.ts +289 -0
  236. package/src/texel-layout.ts +324 -0
  237. package/src/types.ts +888 -0
package/src/types.ts ADDED
@@ -0,0 +1,888 @@
1
+ // @forgeax/engine-rhi-debug/src/types — RhiCallEvent closed union, Tape, work inspection types, RhiCapsRecorded.
2
+ //
3
+ // Shape:
4
+ // - RhiCallEvent: closed union (~40 kind incl. initialData + frameMark), each kind name 1:1 with RHI method name.
5
+ // Excludes: writeTimestamp/resolveQuerySet (per OOS-3).
6
+ // Includes: core RHI + copyExternalImageToTexture + clearBuffer (per IS-11).
7
+ // - Tape: header with formatVersion, rhiCapsRecorded, events array, blobPool map.
8
+ // - InspectReport: frameIdx, workIndex, bindings, drawCall, rt (path string, not inline base64).
9
+ // - RhiCapsRecorded: subset of RhiCaps relevant to cross-device replay.
10
+ //
11
+ // Related: requirements IS-3 / IS-5 / IS-11; plan-strategy §3.1 types.ts module + §8 naming conv.
12
+
13
+ /// <reference types="@webgpu/types" />
14
+
15
+ /**
16
+ * Unique identifier for a recorded RHI handle within a tape.
17
+ *
18
+ * Encodes the type tag and raw numeric handle value into a single string
19
+ * (e.g. "buffer:3", "texture:7"). forgeax Handle<T> brand types do not
20
+ * collide across kinds (research F-1), so a single-level string key suffices.
21
+ */
22
+ export type HandleId = string;
23
+
24
+ /**
25
+ * Subset of RhiCaps recorded alongside each tape for cross-device replay
26
+ * capability matching. Only the caps that affect rendering output are
27
+ * included (not backendKind, compute, indirectDrawing, etc. — those do
28
+ * not change the pixel output of a given RHI call sequence).
29
+ *
30
+ * Canvas format is included because it determines swap-chain format,
31
+ * which affects color-attachment pixel encoding.
32
+ */
33
+ export interface RhiCapsRecorded {
34
+ readonly canvasFormat: GPUTextureFormat;
35
+ readonly rgba16floatRenderable: boolean;
36
+ readonly float32Filterable: boolean;
37
+ readonly textureCompressionBc: boolean;
38
+ readonly textureCompressionEtc2: boolean;
39
+ readonly textureCompressionAstc: boolean;
40
+ readonly storageBuffer: boolean;
41
+ readonly timestampQuery: boolean;
42
+ }
43
+
44
+ // ============================================================================
45
+ // RhiCallEvent — closed union (each kind maps 1:1 to an RHI method)
46
+ // ============================================================================
47
+
48
+ /**
49
+ * Marker event inserted at frame boundaries. Appears after all RHI calls
50
+ * within frame N, before calls in frame N+1.
51
+ *
52
+ * Bootstrap-period calls (before the first frameMark) are assigned to frameIdx=0,
53
+ * appearing before the `frameMark { frameIdx: 0 }` event (per AC-08 / Q&A q14).
54
+ */
55
+ export interface RhiCallEventFrameMark {
56
+ readonly kind: 'frameMark';
57
+ readonly frameIdx: number;
58
+ }
59
+
60
+ // -- RhiDevice create* calls (each creates a resource, producing a HandleId) --
61
+
62
+ export interface RhiCallEventCreateBuffer {
63
+ readonly kind: 'createBuffer';
64
+ readonly handleId: HandleId;
65
+ readonly desc: {
66
+ readonly size: GPUSize64;
67
+ readonly usage: GPUBufferUsageFlags;
68
+ readonly mappedAtCreation?: boolean | undefined;
69
+ };
70
+ }
71
+
72
+ export interface RhiCallEventCreateTexture {
73
+ readonly kind: 'createTexture';
74
+ readonly handleId: HandleId;
75
+ /** Present only for a canvas swapchain texture synthesized from getCurrentTexture. */
76
+ readonly origin?: 'swapchain' | undefined;
77
+ readonly desc: {
78
+ readonly size: GPUExtent3DStrict;
79
+ readonly mipLevelCount?: number | undefined;
80
+ readonly sampleCount?: number | undefined;
81
+ readonly dimension?: GPUTextureDimension | undefined;
82
+ readonly format: GPUTextureFormat;
83
+ readonly usage: GPUTextureUsageFlags;
84
+ readonly viewFormats?: Iterable<GPUTextureFormat> | undefined;
85
+ readonly textureBindingViewDimension?: GPUTextureViewDimension | undefined;
86
+ };
87
+ }
88
+
89
+ /** A successful GPUBuffer.destroy call observed while recording. */
90
+ export interface RhiCallEventDestroyBuffer {
91
+ readonly kind: 'destroyBuffer';
92
+ readonly handleId: HandleId;
93
+ }
94
+
95
+ /** A successful GPUTexture.destroy call observed while recording. */
96
+ export interface RhiCallEventDestroyTexture {
97
+ readonly kind: 'destroyTexture';
98
+ readonly handleId: HandleId;
99
+ }
100
+
101
+ export interface RhiCallEventCreateTextureView {
102
+ readonly kind: 'createTextureView';
103
+ readonly sourceHandleId: HandleId;
104
+ readonly resultHandleId: HandleId;
105
+ readonly desc: {
106
+ readonly format?: GPUTextureFormat | undefined;
107
+ readonly dimension?: GPUTextureViewDimension | undefined;
108
+ readonly usage?: number | undefined;
109
+ readonly aspect?: GPUTextureAspect | undefined;
110
+ readonly baseMipLevel?: number | undefined;
111
+ readonly mipLevelCount?: number | undefined;
112
+ readonly baseArrayLayer?: number | undefined;
113
+ readonly arrayLayerCount?: number | undefined;
114
+ };
115
+ }
116
+
117
+ export interface RhiCallEventCreateSampler {
118
+ readonly kind: 'createSampler';
119
+ readonly handleId: HandleId;
120
+ readonly desc?: Partial<GPUSamplerDescriptor> | undefined;
121
+ }
122
+
123
+ export interface RhiCallEventCreateBindGroupLayout {
124
+ readonly kind: 'createBindGroupLayout';
125
+ readonly handleId: HandleId;
126
+ readonly desc: {
127
+ readonly label?: string | undefined;
128
+ readonly entries: Iterable<GPUBindGroupLayoutEntry>;
129
+ };
130
+ }
131
+
132
+ /**
133
+ * Resource kind discriminator stored alongside each createBindGroup
134
+ * entry. Mirrors the closed RHI BindResource union (`sampler` /
135
+ * `buffer` / `textureView` / `externalTexture`) so the inspector can
136
+ * report the binding's true type without re-reading the BindGroupLayout
137
+ * (I-8 fix, round 1 implement-review). Texture-view entries cover
138
+ * cubemaps, 2D, 3D, and array textures — InspectBindingEntry.kind
139
+ * narrows further into 'texture' (cubemap or otherwise) on the inspect
140
+ * report side.
141
+ */
142
+ export type RhiBindResourceKind = 'sampler' | 'buffer' | 'textureView' | 'externalTexture';
143
+
144
+ export interface RhiCallEventCreateBindGroup {
145
+ readonly kind: 'createBindGroup';
146
+ readonly handleId: HandleId;
147
+ readonly layoutHandleId: HandleId;
148
+ readonly entries: readonly {
149
+ readonly binding: GPUBindGroupEntry['binding'];
150
+ readonly resourceKind: RhiBindResourceKind;
151
+ // Buffer bindings only: the sub-range the recording bound. A dynamic-offset
152
+ // uniform/storage slice (`hasDynamicOffset` BGL entry) binds `size` bytes,
153
+ // not the whole buffer; dropping these binds the entire buffer on replay,
154
+ // which exceeds the device's uniform/storage binding-size limit and fails
155
+ // createBindGroup. undefined = bind whole buffer from offset 0 (spec default).
156
+ readonly bufferOffset?: number;
157
+ readonly bufferSize?: number;
158
+ }[];
159
+ readonly resourceHandleIds: readonly HandleId[];
160
+ }
161
+
162
+ export interface RhiCallEventCreatePipelineLayout {
163
+ readonly kind: 'createPipelineLayout';
164
+ readonly handleId: HandleId;
165
+ readonly bglHandleIds: readonly HandleId[];
166
+ }
167
+
168
+ export interface RhiCallEventCreateRenderPipeline {
169
+ readonly kind: 'createRenderPipeline';
170
+ readonly handleId: HandleId;
171
+ readonly desc: {
172
+ /** Serialized stage omits opaque shader module; the handle id is authoritative. */
173
+ readonly vertex?: {
174
+ readonly entryPoint?: string | undefined;
175
+ readonly buffers: Iterable<GPUVertexBufferLayout | null | undefined>;
176
+ readonly constants?: Record<string, number> | undefined;
177
+ };
178
+ readonly primitive?: GPUPrimitiveState | undefined;
179
+ readonly depthStencil?: GPUDepthStencilState | undefined;
180
+ readonly multisample?: GPUMultisampleState | undefined;
181
+ /** Serialized stage omits opaque shader module; the handle id is authoritative. */
182
+ readonly fragment?: {
183
+ readonly entryPoint?: string | undefined;
184
+ readonly targets: Iterable<GPUColorTargetState | null | undefined>;
185
+ readonly constants?: Record<string, number> | undefined;
186
+ };
187
+ };
188
+ readonly layoutHandleId: HandleId;
189
+ /** HandleId of the re-created vertex shader module for cross-device binding. */
190
+ readonly vertexShaderModuleHandleId?: HandleId | undefined;
191
+ /** HandleId of the re-created fragment shader module for cross-device binding. */
192
+ readonly fragmentShaderModuleHandleId?: HandleId | undefined;
193
+ }
194
+
195
+ export interface RhiCallEventCreateComputePipeline {
196
+ readonly kind: 'createComputePipeline';
197
+ readonly handleId: HandleId;
198
+ readonly desc: {
199
+ readonly compute: GPUProgrammableStage;
200
+ };
201
+ readonly layoutHandleId: HandleId;
202
+ /** HandleId of the re-created compute shader module for cross-device binding. */
203
+ readonly computeShaderModuleHandleId?: HandleId | undefined;
204
+ }
205
+
206
+ export interface RhiCallEventCreateShaderModule {
207
+ readonly kind: 'createShaderModule';
208
+ readonly handleId: HandleId;
209
+ readonly wgslCode: string;
210
+ }
211
+
212
+ export interface RhiCallEventCreateCommandEncoder {
213
+ readonly kind: 'createCommandEncoder';
214
+ readonly cmdHandleId: HandleId;
215
+ readonly desc?: Partial<GPUCommandEncoderDescriptor> | undefined;
216
+ }
217
+
218
+ // -- RhiQueue operations --
219
+
220
+ export interface RhiCallEventWriteBuffer {
221
+ readonly kind: 'writeBuffer';
222
+ readonly handleId: HandleId;
223
+ readonly bufferOffset: number;
224
+ readonly dataHash: string;
225
+ readonly size: number;
226
+ }
227
+
228
+ export interface RhiCallEventWriteTexture {
229
+ readonly kind: 'writeTexture';
230
+ readonly destination: {
231
+ readonly textureHandleId: HandleId;
232
+ readonly mipLevel?: number | undefined;
233
+ readonly origin?: GPUOrigin3D | undefined;
234
+ readonly aspect?: GPUTextureAspect | undefined;
235
+ };
236
+ readonly dataHash: string;
237
+ readonly dataLayout: {
238
+ readonly offset?: number | undefined;
239
+ readonly bytesPerRow?: number | undefined;
240
+ readonly rowsPerImage?: number | undefined;
241
+ };
242
+ readonly size: GPUExtent3DStrict;
243
+ }
244
+
245
+ export interface RhiCallEventCopyExternalImageToTexture {
246
+ readonly kind: 'copyExternalImageToTexture';
247
+ readonly source: {
248
+ readonly origin?: GPUOrigin2DStrict | undefined;
249
+ readonly flipY?: boolean | undefined;
250
+ };
251
+ readonly destination: {
252
+ readonly textureHandleId: HandleId;
253
+ readonly mipLevel?: number | undefined;
254
+ readonly origin?: GPUOrigin3D | undefined;
255
+ readonly aspect?: GPUTextureAspect | undefined;
256
+ readonly colorSpace?: PredefinedColorSpace | undefined;
257
+ readonly premultipliedAlpha?: boolean | undefined;
258
+ };
259
+ readonly copySize: GPUExtent3DStrict;
260
+ }
261
+
262
+ export interface RhiCallEventSubmit {
263
+ readonly kind: 'submit';
264
+ readonly cmdHandleIds: readonly HandleId[];
265
+ }
266
+
267
+ // -- RhiCommandEncoder operations --
268
+
269
+ export interface RhiCallEventBeginRenderPass {
270
+ readonly kind: 'beginRenderPass';
271
+ readonly cmdHandleId: HandleId;
272
+ readonly passHandleId: HandleId;
273
+ readonly desc: {
274
+ /** Attachment handles are replaced by the parallel HandleId arrays on replay. */
275
+ readonly colorAttachments: Iterable<
276
+ | {
277
+ readonly view: unknown;
278
+ readonly resolveTarget?: unknown;
279
+ readonly [key: string]: unknown;
280
+ }
281
+ | null
282
+ | undefined
283
+ >;
284
+ readonly depthStencilAttachment?:
285
+ | {
286
+ readonly view: unknown;
287
+ readonly [key: string]: unknown;
288
+ }
289
+ | undefined;
290
+ readonly occlusionQuerySet?: unknown | undefined;
291
+ readonly timestampWrites?: unknown | undefined;
292
+ readonly maxDrawCount?: number | undefined;
293
+ };
294
+ readonly colorAttachmentViewHandleIds: readonly (HandleId | undefined)[];
295
+ /**
296
+ * Fresh-device handle identities for MSAA resolve targets. Optional for
297
+ * backwards compatibility with tapes recorded before resolve capture was
298
+ * added; those tapes retain their serialized descriptor behavior.
299
+ */
300
+ readonly colorAttachmentResolveTargetHandleIds?: readonly (HandleId | undefined)[];
301
+ readonly depthStencilViewHandleId?: HandleId | undefined;
302
+ }
303
+
304
+ export interface RhiCallEventBeginComputePass {
305
+ readonly kind: 'beginComputePass';
306
+ readonly cmdHandleId: HandleId;
307
+ readonly passHandleId: HandleId;
308
+ readonly desc?: Partial<GPUComputePassDescriptor> | undefined;
309
+ }
310
+
311
+ export interface RhiCallEventCopyBufferToBuffer {
312
+ readonly kind: 'copyBufferToBuffer';
313
+ readonly cmdHandleId: HandleId;
314
+ readonly sourceHandleId: HandleId;
315
+ readonly sourceOffset: number;
316
+ readonly destinationHandleId: HandleId;
317
+ readonly destinationOffset: number;
318
+ readonly size: number;
319
+ }
320
+
321
+ export interface RhiCallEventCopyBufferToTexture {
322
+ readonly kind: 'copyBufferToTexture';
323
+ readonly cmdHandleId: HandleId;
324
+ readonly source: Omit<GPUTexelCopyBufferInfo, 'buffer'> & { readonly bufferHandleId: HandleId };
325
+ readonly destination: Omit<GPUTexelCopyTextureInfo, 'texture'> & {
326
+ readonly textureHandleId: HandleId;
327
+ };
328
+ readonly copySize: GPUExtent3DStrict;
329
+ }
330
+
331
+ export interface RhiCallEventCopyTextureToBuffer {
332
+ readonly kind: 'copyTextureToBuffer';
333
+ readonly cmdHandleId: HandleId;
334
+ readonly source: Omit<GPUTexelCopyTextureInfo, 'texture'> & {
335
+ readonly textureHandleId: HandleId;
336
+ };
337
+ readonly destination: Omit<GPUTexelCopyBufferInfo, 'buffer'> & {
338
+ readonly bufferHandleId: HandleId;
339
+ };
340
+ readonly copySize: GPUExtent3DStrict;
341
+ }
342
+
343
+ export interface RhiCallEventCopyTextureToTexture {
344
+ readonly kind: 'copyTextureToTexture';
345
+ readonly cmdHandleId: HandleId;
346
+ readonly source: Omit<GPUTexelCopyTextureInfo, 'texture'> & {
347
+ readonly textureHandleId: HandleId;
348
+ };
349
+ readonly destination: Omit<GPUTexelCopyTextureInfo, 'texture'> & {
350
+ readonly textureHandleId: HandleId;
351
+ };
352
+ readonly copySize: GPUExtent3DStrict;
353
+ }
354
+
355
+ export interface RhiCallEventClearBuffer {
356
+ readonly kind: 'clearBuffer';
357
+ readonly cmdHandleId: HandleId;
358
+ readonly handleId: HandleId;
359
+ readonly offset?: number | undefined;
360
+ readonly size?: number | undefined;
361
+ }
362
+
363
+ export interface RhiCallEventPushDebugGroup {
364
+ readonly kind: 'pushDebugGroup';
365
+ readonly cmdHandleId: HandleId;
366
+ readonly groupLabel: string;
367
+ }
368
+
369
+ export interface RhiCallEventPopDebugGroup {
370
+ readonly kind: 'popDebugGroup';
371
+ readonly cmdHandleId: HandleId;
372
+ }
373
+
374
+ export interface RhiCallEventInsertDebugMarker {
375
+ readonly kind: 'insertDebugMarker';
376
+ readonly cmdHandleId: HandleId;
377
+ readonly markerLabel: string;
378
+ }
379
+
380
+ export interface RhiCallEventFinish {
381
+ readonly kind: 'finish';
382
+ readonly cmdHandleId: HandleId;
383
+ }
384
+
385
+ // -- RhiRenderPassEncoder operations --
386
+
387
+ export interface RhiCallEventSetPipeline {
388
+ readonly kind: 'setPipeline';
389
+ readonly passHandleId: HandleId;
390
+ readonly pipelineHandleId: HandleId;
391
+ }
392
+
393
+ export interface RhiCallEventSetVertexBuffer {
394
+ readonly kind: 'setVertexBuffer';
395
+ readonly passHandleId: HandleId;
396
+ readonly slot: number;
397
+ readonly bufferHandleId: HandleId;
398
+ readonly offset?: number | undefined;
399
+ readonly size?: number | undefined;
400
+ }
401
+
402
+ export interface RhiCallEventSetIndexBuffer {
403
+ readonly kind: 'setIndexBuffer';
404
+ readonly passHandleId: HandleId;
405
+ readonly bufferHandleId: HandleId;
406
+ readonly format: 'uint16' | 'uint32';
407
+ readonly offset?: number | undefined;
408
+ readonly size?: number | undefined;
409
+ }
410
+
411
+ export interface RhiCallEventSetBindGroup {
412
+ readonly kind: 'setBindGroup';
413
+ readonly passHandleId: HandleId;
414
+ readonly index: number;
415
+ readonly bindGroupHandleId: HandleId;
416
+ readonly dynamicOffsets?: readonly number[] | undefined;
417
+ }
418
+
419
+ export interface RhiCallEventDraw {
420
+ readonly kind: 'draw';
421
+ readonly passHandleId: HandleId;
422
+ readonly vertexCount: number;
423
+ readonly instanceCount: number;
424
+ readonly firstVertex: number;
425
+ readonly firstInstance: number;
426
+ }
427
+
428
+ export interface RhiCallEventDrawIndexed {
429
+ readonly kind: 'drawIndexed';
430
+ readonly passHandleId: HandleId;
431
+ readonly indexCount: number;
432
+ readonly instanceCount: number;
433
+ readonly firstIndex: number;
434
+ readonly baseVertex: number;
435
+ readonly firstInstance: number;
436
+ }
437
+
438
+ export interface RhiCallEventSetViewport {
439
+ readonly kind: 'setViewport';
440
+ readonly passHandleId: HandleId;
441
+ readonly x: number;
442
+ readonly y: number;
443
+ readonly w: number;
444
+ readonly h: number;
445
+ readonly minDepth: number;
446
+ readonly maxDepth: number;
447
+ }
448
+
449
+ export interface RhiCallEventSetScissorRect {
450
+ readonly kind: 'setScissorRect';
451
+ readonly passHandleId: HandleId;
452
+ readonly x: number;
453
+ readonly y: number;
454
+ readonly w: number;
455
+ readonly h: number;
456
+ }
457
+
458
+ export interface RhiCallEventSetStencilReference {
459
+ readonly kind: 'setStencilReference';
460
+ readonly passHandleId: HandleId;
461
+ readonly reference: number;
462
+ }
463
+
464
+ export interface RhiCallEventEndRenderPass {
465
+ readonly kind: 'endRenderPass';
466
+ readonly passHandleId: HandleId;
467
+ }
468
+
469
+ export interface RhiCallEventSetBlendConstant {
470
+ readonly kind: 'setBlendConstant';
471
+ readonly passHandleId: HandleId;
472
+ readonly color: GPUColor;
473
+ }
474
+
475
+ export interface RhiCallEventDrawIndirect {
476
+ readonly kind: 'drawIndirect';
477
+ readonly passHandleId: HandleId;
478
+ readonly indirectBufferHandleId: HandleId;
479
+ readonly indirectOffset: number;
480
+ }
481
+
482
+ export interface RhiCallEventDrawIndexedIndirect {
483
+ readonly kind: 'drawIndexedIndirect';
484
+ readonly passHandleId: HandleId;
485
+ readonly indirectBufferHandleId: HandleId;
486
+ readonly indirectOffset: number;
487
+ }
488
+
489
+ export interface RhiCallEventPassPushDebugGroup {
490
+ readonly kind: 'passPushDebugGroup';
491
+ readonly passHandleId: HandleId;
492
+ readonly groupLabel: string;
493
+ }
494
+
495
+ export interface RhiCallEventPassPopDebugGroup {
496
+ readonly kind: 'passPopDebugGroup';
497
+ readonly passHandleId: HandleId;
498
+ }
499
+
500
+ export interface RhiCallEventPassInsertDebugMarker {
501
+ readonly kind: 'passInsertDebugMarker';
502
+ readonly passHandleId: HandleId;
503
+ readonly markerLabel: string;
504
+ }
505
+
506
+ // -- RhiComputePassEncoder operations --
507
+
508
+ export interface RhiCallEventSetComputePipeline {
509
+ readonly kind: 'setComputePipeline';
510
+ readonly passHandleId: HandleId;
511
+ readonly pipelineHandleId: HandleId;
512
+ }
513
+
514
+ export interface RhiCallEventDispatchWorkgroups {
515
+ readonly kind: 'dispatchWorkgroups';
516
+ readonly passHandleId: HandleId;
517
+ readonly x: number;
518
+ readonly y: number;
519
+ readonly z: number;
520
+ }
521
+
522
+ export interface RhiCallEventDispatchWorkgroupsIndirect {
523
+ readonly kind: 'dispatchWorkgroupsIndirect';
524
+ readonly passHandleId: HandleId;
525
+ readonly indirectBufferHandleId: HandleId;
526
+ readonly indirectOffset: number;
527
+ }
528
+
529
+ export interface RhiCallEventEndComputePass {
530
+ readonly kind: 'endComputePass';
531
+ readonly passHandleId: HandleId;
532
+ }
533
+
534
+ /**
535
+ * Initial-data event representing a resource snapshot captured at recording start.
536
+ *
537
+ * handleId points to a resource declared by a prior create* event in the
538
+ * bootstrap prefix. dataHash is a key into the tape's blobPool, where the
539
+ * resource's actual GPU bytes (read back via copyToBuffer/mapAsync) are stored
540
+ * with djb2 hash-dedup (D-1: reuse unified serialization path, no separate pool).
541
+ *
542
+ * The resource kind (buffer vs texture) and its shape are recorded in the
543
+ * descriptor registry (snapshotResource reads it), not duplicated in this event
544
+ * (architecture-principles #1 SSOT — avoid two sources for shape).
545
+ */
546
+ export interface RhiCallEventInitialData {
547
+ readonly kind: 'initialData';
548
+ readonly handleId: HandleId;
549
+ readonly dataHash: string;
550
+ }
551
+
552
+ /**
553
+ * Closed union of all recordable RHI call events.
554
+ *
555
+ * v1 covers: core RHI methods + copyExternalImageToTexture + clearBuffer (IS-11).
556
+ * Excludes: writeTimestamp/resolveQuerySet (OOS-3),
557
+ * executeBundles (OOS-10), beginOcclusionQuery/endOcclusionQuery.
558
+ *
559
+ * Kinds are named 1:1 with RHI method names per plan-strategy §8 naming convention.
560
+ * The frameMark kind is the only non-method event — it marks frame boundaries.
561
+ */
562
+ export type RhiCallEvent =
563
+ | RhiCallEventFrameMark
564
+ | RhiCallEventCreateBuffer
565
+ | RhiCallEventCreateTexture
566
+ | RhiCallEventDestroyBuffer
567
+ | RhiCallEventDestroyTexture
568
+ | RhiCallEventCreateTextureView
569
+ | RhiCallEventCreateSampler
570
+ | RhiCallEventCreateBindGroupLayout
571
+ | RhiCallEventCreateBindGroup
572
+ | RhiCallEventCreatePipelineLayout
573
+ | RhiCallEventCreateRenderPipeline
574
+ | RhiCallEventCreateComputePipeline
575
+ | RhiCallEventCreateShaderModule
576
+ | RhiCallEventCreateCommandEncoder
577
+ | RhiCallEventWriteBuffer
578
+ | RhiCallEventWriteTexture
579
+ | RhiCallEventCopyExternalImageToTexture
580
+ | RhiCallEventSubmit
581
+ | RhiCallEventBeginRenderPass
582
+ | RhiCallEventBeginComputePass
583
+ | RhiCallEventCopyBufferToBuffer
584
+ | RhiCallEventCopyBufferToTexture
585
+ | RhiCallEventCopyTextureToBuffer
586
+ | RhiCallEventCopyTextureToTexture
587
+ | RhiCallEventClearBuffer
588
+ | RhiCallEventPushDebugGroup
589
+ | RhiCallEventPopDebugGroup
590
+ | RhiCallEventInsertDebugMarker
591
+ | RhiCallEventFinish
592
+ | RhiCallEventSetPipeline
593
+ | RhiCallEventSetVertexBuffer
594
+ | RhiCallEventSetIndexBuffer
595
+ | RhiCallEventSetBindGroup
596
+ | RhiCallEventDraw
597
+ | RhiCallEventDrawIndexed
598
+ | RhiCallEventSetViewport
599
+ | RhiCallEventSetScissorRect
600
+ | RhiCallEventSetStencilReference
601
+ | RhiCallEventEndRenderPass
602
+ | RhiCallEventSetBlendConstant
603
+ | RhiCallEventDrawIndirect
604
+ | RhiCallEventDrawIndexedIndirect
605
+ | RhiCallEventPassPushDebugGroup
606
+ | RhiCallEventPassPopDebugGroup
607
+ | RhiCallEventPassInsertDebugMarker
608
+ | RhiCallEventSetComputePipeline
609
+ | RhiCallEventDispatchWorkgroups
610
+ | RhiCallEventDispatchWorkgroupsIndirect
611
+ | RhiCallEventEndComputePass
612
+ | RhiCallEventInitialData;
613
+
614
+ // ============================================================================
615
+ // Tape
616
+ // ============================================================================
617
+
618
+ /**
619
+ * A recorded frame tape.
620
+ *
621
+ * Contains the sequence of RHI calls (events) plus a binary blob pool
622
+ * for buffer data that is hash-deduplicated across events.
623
+ *
624
+ * formatVersion: integer version of the tape format. Mismatch with runtime
625
+ * version causes deserialize to reject with 'tape-format-version-mismatch'.
626
+ * rhiCapsRecorded: the caps of the recording device for cross-device matching.
627
+ * events: the ordered sequence of RHI call events including frameMark boundaries.
628
+ * blobPool: hash-deduplicated binary data (buffer contents, shader source, etc).
629
+ * Keyed by hash string, valued as ArrayBuffer.
630
+ */
631
+ export interface Tape {
632
+ readonly formatVersion: number;
633
+ readonly rhiCapsRecorded: RhiCapsRecorded;
634
+ readonly events: readonly RhiCallEvent[];
635
+ readonly blobPool: ReadonlyMap<string, ArrayBuffer>;
636
+ }
637
+
638
+ // ============================================================================
639
+ // InspectReport
640
+ // ============================================================================
641
+
642
+ /**
643
+ * Information about a GPU binding group entry as seen at inspect time.
644
+ */
645
+ export interface InspectBindingEntry {
646
+ readonly groupIndex: number;
647
+ readonly entryIndex: number;
648
+ readonly handleId: HandleId;
649
+ readonly kind: 'buffer' | 'texture' | 'sampler' | 'textureView';
650
+ }
651
+
652
+ /**
653
+ * Information about the work item at the inspected workIndex.
654
+ */
655
+ export interface InspectDrawCall {
656
+ readonly pipelineKind: 'render' | 'compute';
657
+ readonly pipelineHandleId: HandleId;
658
+ readonly vertexCount?: number | undefined;
659
+ readonly instanceCount?: number | undefined;
660
+ readonly indexCount?: number | undefined;
661
+ readonly dispatchX?: number | undefined;
662
+ readonly dispatchY?: number | undefined;
663
+ readonly dispatchZ?: number | undefined;
664
+ /** Present on `draw` — the first vertex offset (raw event field carried through). */
665
+ readonly firstVertex?: number | undefined;
666
+ /** Present on `drawIndexed` — index of the first element of the index buffer to read. */
667
+ readonly firstIndex?: number | undefined;
668
+ /** Present on `draw` and `drawIndexed` — the first instance for instanced rendering. */
669
+ readonly firstInstance?: number | undefined;
670
+ /** Present on `drawIndexed` — vertex offset added before indexing the vertex buffer. */
671
+ readonly baseVertex?: number | undefined;
672
+ /** Present on `drawIndirect` / `drawIndexedIndirect` — handle of the buffer holding the parameters. */
673
+ readonly indirectBufferHandleId?: HandleId | undefined;
674
+ /** Present on `drawIndirect` / `drawIndexedIndirect` — byte offset into the indirect buffer. */
675
+ readonly indirectOffset?: number | undefined;
676
+ }
677
+
678
+ /**
679
+ * Pipeline state for a single draw call, extracted from createRenderPipeline +
680
+ * runtime events (pure event analysis, zero GPU). The seven WebGPU pipeline
681
+ * stages the viewer's PipelineState panel renders; attached to InspectReport so
682
+ * an AI `inspect-offline` call sees identical data. SSOT producer:
683
+ * `makePipelineState` in inspect-core.ts; whole-frame producer: buildFrameModel.
684
+ */
685
+ export interface DrawPipelineState {
686
+ readonly inputAssembly: {
687
+ readonly topology: GPUPrimitiveTopology;
688
+ readonly stripIndexFormat: GPUIndexFormat | undefined;
689
+ };
690
+ readonly vertexInput: {
691
+ readonly buffers: readonly {
692
+ readonly arrayStride: number;
693
+ readonly stepMode: GPUVertexStepMode;
694
+ readonly attributes: readonly {
695
+ readonly format: GPUVertexFormat;
696
+ readonly offset: number;
697
+ readonly shaderLocation: number;
698
+ }[];
699
+ }[];
700
+ };
701
+ readonly shaders: {
702
+ readonly vertexShaderModuleHandleId: HandleId | undefined;
703
+ readonly fragmentShaderModuleHandleId: HandleId | undefined;
704
+ /** Active vertex entry point (a module may bundle several; this is the one this draw runs). */
705
+ readonly vertexEntryPoint: string | undefined;
706
+ /** Active fragment entry point — disambiguates a multi-entrypoint module (e.g. fs_main vs fs_gbuffer). */
707
+ readonly fragmentEntryPoint: string | undefined;
708
+ };
709
+ readonly rasterizer: {
710
+ readonly cullMode: GPUCullMode;
711
+ readonly frontFace: GPUFrontFace;
712
+ };
713
+ readonly depthStencil: {
714
+ readonly format: GPUTextureFormat;
715
+ readonly depthWriteEnabled: boolean;
716
+ readonly depthCompare: GPUCompareFunction;
717
+ readonly stencilFront: NonNullable<GPUDepthStencilState['stencilFront']>;
718
+ readonly stencilBack: NonNullable<GPUDepthStencilState['stencilBack']>;
719
+ readonly stencilReadMask: number;
720
+ readonly stencilWriteMask: number;
721
+ readonly depthBias: number;
722
+ readonly depthBiasSlopeScale: number;
723
+ readonly depthBiasClamp: number;
724
+ readonly stencilReference: number;
725
+ };
726
+ readonly blend: {
727
+ readonly colorTargets: readonly {
728
+ readonly format: GPUTextureFormat;
729
+ readonly color: GPUBlendComponent | undefined;
730
+ readonly alpha: GPUBlendComponent | undefined;
731
+ readonly writeMask: GPUColorWriteFlags;
732
+ }[];
733
+ readonly blendConstant: GPUColor | undefined;
734
+ };
735
+ readonly multisample: {
736
+ readonly count: number;
737
+ readonly mask: number;
738
+ readonly alphaToCoverageEnabled: boolean;
739
+ };
740
+ }
741
+
742
+ /**
743
+ * A resource descriptor parsed from a create* event, discriminated by kind.
744
+ * Consumed by the viewer's ResourceInspector panel and the cli `summary`
745
+ * subcommand (via the FrameModel.resources map). SSOT producer: `buildResources`
746
+ * in inspect-core.ts.
747
+ */
748
+ export type CreateDescriptor =
749
+ | {
750
+ readonly kind: 'createBuffer';
751
+ readonly handleId: HandleId;
752
+ readonly size: GPUSize64;
753
+ readonly usage: GPUBufferUsageFlags;
754
+ }
755
+ | {
756
+ readonly kind: 'createTexture';
757
+ readonly handleId: HandleId;
758
+ readonly format: GPUTextureFormat;
759
+ readonly size: readonly number[];
760
+ readonly mipLevelCount: number;
761
+ readonly sampleCount: number;
762
+ readonly dimension: GPUTextureDimension;
763
+ readonly usage: GPUTextureUsageFlags;
764
+ }
765
+ | {
766
+ readonly kind: 'createSampler';
767
+ readonly handleId: HandleId;
768
+ readonly desc: Partial<GPUSamplerDescriptor> | undefined;
769
+ }
770
+ | {
771
+ readonly kind: 'createBindGroupLayout';
772
+ readonly handleId: HandleId;
773
+ readonly entries: readonly GPUBindGroupLayoutEntry[];
774
+ }
775
+ | {
776
+ readonly kind: 'createPipelineLayout';
777
+ readonly handleId: HandleId;
778
+ readonly bglHandleIds: readonly HandleId[];
779
+ }
780
+ | {
781
+ readonly kind: 'createRenderPipeline';
782
+ readonly handleId: HandleId;
783
+ readonly vertex: GPUVertexState | undefined;
784
+ readonly primitive: GPUPrimitiveState | undefined;
785
+ readonly depthStencil: GPUDepthStencilState | undefined;
786
+ readonly multisample: GPUMultisampleState | undefined;
787
+ readonly fragment: GPUFragmentState | undefined;
788
+ readonly layoutHandleId: HandleId;
789
+ readonly vertexShaderModuleHandleId: HandleId | undefined;
790
+ readonly fragmentShaderModuleHandleId: HandleId | undefined;
791
+ }
792
+ | { readonly kind: 'createShaderModule'; readonly handleId: HandleId; readonly wgslCode: string };
793
+
794
+ /**
795
+ * Decoded RGBA8 pixels of the RT readback at the inspected draw call — the
796
+ * structured RT payload produced by the node-free browser path (L3b
797
+ * `inspectDrawJson`). `format` describes the native replay texels, so callers
798
+ * can decode wide and floating-point attachments correctly. `pixels` are
799
+ * tight-packed with row-alignment padding stripped.
800
+ */
801
+ export interface InspectRtPixels {
802
+ readonly width: number;
803
+ readonly height: number;
804
+ readonly format: string;
805
+ readonly pixels: Uint8Array;
806
+ }
807
+
808
+ /**
809
+ * The RT readback at the inspected draw call, in one of two genuinely
810
+ * distinct forms keyed by execution environment:
811
+ *
812
+ * - `string` — a PNG **file path** on disk, produced by the DevKit Node shell
813
+ * after `rhi.inspect`, which encodes the readback to a PNG under the
814
+ * inspect/ output dir. Discriminate with `typeof rt === 'string'`.
815
+ * - {@link InspectRtPixels} — the native `{ width, height, format, pixels }` tuple,
816
+ * produced by the node-free browser path (`inspectDrawJson`), which cannot
817
+ * write files and so hands back raw RGBA8 pixels. Discriminate with
818
+ * `typeof rt === 'object'` (or `'pixels' in rt`).
819
+ *
820
+ * AI users branch on `typeof` — the union is the single source of truth for
821
+ * "what an `rt` field may hold", so no untyped-value cast is needed at either
822
+ * producer.
823
+ */
824
+ export type InspectRtPayload = string | InspectRtPixels;
825
+
826
+ /**
827
+ * Structured report produced by inspectWork(replay, workIndex, fields?).
828
+ *
829
+ * frameIdx/workIndex/passIdx are **always present** — they identify the inspected
830
+ * draw and are computed regardless of the `fields` selector.
831
+ *
832
+ * bindings/drawCall/rt are **field-cropped**: each is present only when the
833
+ * `fields` selector includes its name, or when `fields` is undefined (full
834
+ * report). When a field is not requested it is genuinely absent (the key is not
835
+ * set), not assigned `undefined` (AC-12). AI users must narrow before reading
836
+ * (`report.drawCall?.pipelineKind`, `if (report.bindings) …`).
837
+ *
838
+ * frameIdx: the frame index containing this draw call.
839
+ * workIndex: the global work ordinal within the tape.
840
+ * passIdx: the render/compute pass index containing this draw.
841
+ * bindings: the bind group bindings active at this draw call (cropped: present
842
+ * when fields includes 'bindings' or is undefined).
843
+ * drawCall: metadata about the draw/dispatch call itself (cropped: present when
844
+ * fields includes 'drawCall' or is undefined).
845
+ * rt: the RT readback ({@link InspectRtPayload}) — a PNG file path string on
846
+ * the Node CLI path, or a decoded {width,height,pixels} object on the
847
+ * browser path. Cropped: present when fields includes 'rt' or is undefined
848
+ * (full report).
849
+ * pipelineState: the seven WebGPU pipeline stages active at this draw
850
+ * ({@link DrawPipelineState}), derived from pure event analysis. Always
851
+ * present for render draws (never gated by `fields`); the AI sees the same
852
+ * pipeline state the viewer's PipelineState panel renders.
853
+ */
854
+ export interface InspectReport {
855
+ readonly frameIdx: number;
856
+ readonly workIndex: number;
857
+ readonly passIdx: number;
858
+ readonly bindings?: readonly InspectBindingEntry[] | undefined;
859
+ readonly drawCall?: InspectDrawCall | undefined;
860
+ readonly rt?: InspectRtPayload | undefined;
861
+ readonly pipelineState?: DrawPipelineState | undefined;
862
+ }
863
+
864
+ /**
865
+ * Fields selector for inspectWork — controls which data is computed and returned.
866
+ * An empty array means "minimum report" (frameIdx/workIndex/passIdx only).
867
+ * undefined means "full report" (all fields including RT PNG).
868
+ */
869
+ export type InspectFields = 'bindings' | 'drawCall' | 'rt';
870
+
871
+ /**
872
+ * RHI commands that are known to be out-of-scope for current capture.
873
+ *
874
+ * These commands remain silent pass-throughs in the recorder (no pushEvent)
875
+ * but are explicitly listed here so the coverage-invariant test can
876
+ * distinguish "known-exempt" from "forgotten". New commands added to an
877
+ * encoder interface that are not in this set AND have no RhiCallEvent kind
878
+ * will cause the coverage-invariant .test-d.ts to fail at compile time.
879
+ *
880
+ * @internal
881
+ */
882
+ export const DEFERRED_COMMANDS = new Set<string>([
883
+ 'beginOcclusionQuery',
884
+ 'endOcclusionQuery',
885
+ 'executeBundles',
886
+ 'writeTimestamp',
887
+ 'resolveQuerySet',
888
+ ]);