@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.
- package/README.md +168 -152
- package/package.json +1 -1
- package/src/REVIEW_2026_08_06.md +610 -610
- package/src/core/geom/3d/shape/ConvexHullShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/ConvexHullShape3D.js +28 -4
- package/src/engine/graphics/render/frame_graph/FrameGraph.d.ts +26 -0
- package/src/engine/graphics/render/frame_graph/FrameGraph.d.ts.map +1 -1
- package/src/engine/graphics/render/frame_graph/FrameGraph.js +47 -0
- package/src/engine/physics/ecs/PhysicsSystem.d.ts +0 -3
- package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
- package/src/engine/physics/ecs/PhysicsSystem.js +0 -3
- package/src/shade/device/ShadeGPUCommandContext.d.ts +21 -0
- package/src/shade/device/ShadeGPUCommandContext.d.ts.map +1 -1
- package/src/shade/device/ShadeGPUCommandContext.js +940 -749
- package/src/shade/device/timing/GPUTimerArray.d.ts +22 -4
- package/src/shade/device/timing/GPUTimerArray.d.ts.map +1 -1
- package/src/shade/device/timing/GPUTimerArray.js +88 -14
- package/src/shade/device/timing/GPU_PROFILER_PROPOSAL_2026_08_28.md +349 -98
- package/src/shade/device/timing/profile/GPUFrameRecorder.d.ts +93 -0
- package/src/shade/device/timing/profile/GPUFrameRecorder.d.ts.map +1 -0
- package/src/shade/device/timing/profile/GPUFrameRecorder.js +297 -0
- package/src/shade/device/timing/profile/GPUProfileCapture.d.ts +62 -0
- package/src/shade/device/timing/profile/GPUProfileCapture.d.ts.map +1 -0
- package/src/shade/device/timing/profile/GPUProfileCapture.js +77 -0
- package/src/shade/device/timing/profile/GPUProfileFrame.d.ts +73 -0
- package/src/shade/device/timing/profile/GPUProfileFrame.d.ts.map +1 -0
- package/src/shade/device/timing/profile/GPUProfileFrame.js +88 -0
- package/src/shade/device/timing/profile/GPUProfileLevel.d.ts +20 -0
- package/src/shade/device/timing/profile/GPUProfileLevel.d.ts.map +1 -0
- package/src/shade/device/timing/profile/GPUProfileLevel.js +50 -0
- package/src/shade/device/timing/profile/GPUProfileMeta.d.ts +63 -0
- package/src/shade/device/timing/profile/GPUProfileMeta.d.ts.map +1 -0
- package/src/shade/device/timing/profile/GPUProfileMeta.js +73 -0
- package/src/shade/device/timing/profile/GPUProfileSession.d.ts +173 -0
- package/src/shade/device/timing/profile/GPUProfileSession.d.ts.map +1 -0
- package/src/shade/device/timing/profile/GPUProfileSession.js +470 -0
- package/src/shade/device/timing/profile/GPUProfileSpan.d.ts +60 -0
- package/src/shade/device/timing/profile/GPUProfileSpan.d.ts.map +1 -0
- package/src/shade/device/timing/profile/GPUProfileSpan.js +65 -0
- package/src/shade/device/timing/profile/GPUProfileSpanKind.d.ts +19 -0
- package/src/shade/device/timing/profile/GPUProfileSpanKind.d.ts.map +1 -0
- package/src/shade/device/timing/profile/GPUProfileSpanKind.js +25 -0
- package/src/shade/device/timing/profile/GPUProfileTopology.d.ts +159 -0
- package/src/shade/device/timing/profile/GPUProfileTopology.d.ts.map +1 -0
- package/src/shade/device/timing/profile/GPUProfileTopology.js +202 -0
- package/src/shade/device/timing/profile/GPUProfileWork.d.ts +90 -0
- package/src/shade/device/timing/profile/GPUProfileWork.d.ts.map +1 -0
- package/src/shade/device/timing/profile/GPUProfileWork.js +115 -0
- package/src/shade/device/timing/profile/SGPTDefect.d.ts +43 -0
- package/src/shade/device/timing/profile/SGPTDefect.d.ts.map +1 -0
- package/src/shade/device/timing/profile/SGPTDefect.js +65 -0
- package/src/shade/device/timing/profile/SGPTHeader.d.ts +38 -0
- package/src/shade/device/timing/profile/SGPTHeader.d.ts.map +1 -0
- package/src/shade/device/timing/profile/SGPTHeader.js +46 -0
- package/src/shade/device/timing/profile/SGPTRecordRef.d.ts +37 -0
- package/src/shade/device/timing/profile/SGPTRecordRef.d.ts.map +1 -0
- package/src/shade/device/timing/profile/SGPTRecordRef.js +45 -0
- package/src/shade/device/timing/profile/SGPTWriteStream.d.ts +103 -0
- package/src/shade/device/timing/profile/SGPTWriteStream.d.ts.map +1 -0
- package/src/shade/device/timing/profile/SGPTWriteStream.js +287 -0
- package/src/shade/device/timing/profile/SGPT_DEFECT.d.ts +19 -0
- package/src/shade/device/timing/profile/SGPT_DEFECT.d.ts.map +1 -0
- package/src/shade/device/timing/profile/SGPT_DEFECT.js +26 -0
- package/src/shade/device/timing/profile/SGPT_FLAG.d.ts +8 -0
- package/src/shade/device/timing/profile/SGPT_FLAG.d.ts.map +1 -0
- package/src/shade/device/timing/profile/SGPT_FLAG.js +15 -0
- package/src/shade/device/timing/profile/SGPT_FORMAT.md +345 -0
- package/src/shade/device/timing/profile/SGPT_FORMAT_VERSION.d.ts +10 -0
- package/src/shade/device/timing/profile/SGPT_FORMAT_VERSION.d.ts.map +1 -0
- package/src/shade/device/timing/profile/SGPT_FORMAT_VERSION.js +9 -0
- package/src/shade/device/timing/profile/SGPT_FRAME_SLACK.d.ts +17 -0
- package/src/shade/device/timing/profile/SGPT_FRAME_SLACK.d.ts.map +1 -0
- package/src/shade/device/timing/profile/SGPT_FRAME_SLACK.js +16 -0
- package/src/shade/device/timing/profile/SGPT_HEADER_CHECKSUM_COVERAGE.d.ts +16 -0
- package/src/shade/device/timing/profile/SGPT_HEADER_CHECKSUM_COVERAGE.d.ts.map +1 -0
- package/src/shade/device/timing/profile/SGPT_HEADER_CHECKSUM_COVERAGE.js +15 -0
- package/src/shade/device/timing/profile/SGPT_HEADER_OFFSET.d.ts +15 -0
- package/src/shade/device/timing/profile/SGPT_HEADER_OFFSET.d.ts.map +1 -0
- package/src/shade/device/timing/profile/SGPT_HEADER_OFFSET.js +29 -0
- package/src/shade/device/timing/profile/SGPT_HEADER_SIZE.d.ts +7 -0
- package/src/shade/device/timing/profile/SGPT_HEADER_SIZE.d.ts.map +1 -0
- package/src/shade/device/timing/profile/SGPT_HEADER_SIZE.js +6 -0
- package/src/shade/device/timing/profile/SGPT_MAGIC.d.ts +7 -0
- package/src/shade/device/timing/profile/SGPT_MAGIC.d.ts.map +1 -0
- package/src/shade/device/timing/profile/SGPT_MAGIC.js +6 -0
- package/src/shade/device/timing/profile/SGPT_MIN_READER_VERSION.d.ts +16 -0
- package/src/shade/device/timing/profile/SGPT_MIN_READER_VERSION.d.ts.map +1 -0
- package/src/shade/device/timing/profile/SGPT_MIN_READER_VERSION.js +15 -0
- package/src/shade/device/timing/profile/SGPT_RECORD_HEADER_SIZE.d.ts +7 -0
- package/src/shade/device/timing/profile/SGPT_RECORD_HEADER_SIZE.d.ts.map +1 -0
- package/src/shade/device/timing/profile/SGPT_RECORD_HEADER_SIZE.js +6 -0
- package/src/shade/device/timing/profile/SGPT_RECORD_OFFSET.d.ts +13 -0
- package/src/shade/device/timing/profile/SGPT_RECORD_OFFSET.d.ts.map +1 -0
- package/src/shade/device/timing/profile/SGPT_RECORD_OFFSET.js +23 -0
- package/src/shade/device/timing/profile/SGPT_RECORD_SYNC.d.ts +12 -0
- package/src/shade/device/timing/profile/SGPT_RECORD_SYNC.d.ts.map +1 -0
- package/src/shade/device/timing/profile/SGPT_RECORD_SYNC.js +11 -0
- package/src/shade/device/timing/profile/SGPT_RECORD_TYPE.d.ts +18 -0
- package/src/shade/device/timing/profile/SGPT_RECORD_TYPE.d.ts.map +1 -0
- package/src/shade/device/timing/profile/SGPT_RECORD_TYPE.js +46 -0
- package/src/shade/device/timing/profile/frame_graph_extract_topology.d.ts +20 -0
- package/src/shade/device/timing/profile/frame_graph_extract_topology.d.ts.map +1 -0
- package/src/shade/device/timing/profile/frame_graph_extract_topology.js +174 -0
- package/src/shade/device/timing/profile/make_profiling_pass_encoder.d.ts +21 -0
- package/src/shade/device/timing/profile/make_profiling_pass_encoder.d.ts.map +1 -0
- package/src/shade/device/timing/profile/make_profiling_pass_encoder.js +114 -0
- package/src/shade/device/timing/profile/parse_workgroup_size.d.ts +20 -0
- package/src/shade/device/timing/profile/parse_workgroup_size.d.ts.map +1 -0
- package/src/shade/device/timing/profile/parse_workgroup_size.js +43 -0
- package/src/shade/device/timing/profile/sgpt_fourcc.d.ts +18 -0
- package/src/shade/device/timing/profile/sgpt_fourcc.d.ts.map +1 -0
- package/src/shade/device/timing/profile/sgpt_fourcc.js +34 -0
- package/src/shade/device/timing/profile/sgpt_frame_codec.d.ts +42 -0
- package/src/shade/device/timing/profile/sgpt_frame_codec.d.ts.map +1 -0
- package/src/shade/device/timing/profile/sgpt_frame_codec.js +172 -0
- package/src/shade/device/timing/profile/sgpt_meta_codec.d.ts +20 -0
- package/src/shade/device/timing/profile/sgpt_meta_codec.d.ts.map +1 -0
- package/src/shade/device/timing/profile/sgpt_meta_codec.js +65 -0
- package/src/shade/device/timing/profile/sgpt_read_capture.d.ts +19 -0
- package/src/shade/device/timing/profile/sgpt_read_capture.d.ts.map +1 -0
- package/src/shade/device/timing/profile/sgpt_read_capture.js +134 -0
- package/src/shade/device/timing/profile/sgpt_read_header.d.ts +22 -0
- package/src/shade/device/timing/profile/sgpt_read_header.d.ts.map +1 -0
- package/src/shade/device/timing/profile/sgpt_read_header.js +94 -0
- package/src/shade/device/timing/profile/sgpt_read_records.d.ts +27 -0
- package/src/shade/device/timing/profile/sgpt_read_records.d.ts.map +1 -0
- package/src/shade/device/timing/profile/sgpt_read_records.js +153 -0
- package/src/shade/device/timing/profile/sgpt_topology_codec.d.ts +54 -0
- package/src/shade/device/timing/profile/sgpt_topology_codec.d.ts.map +1 -0
- package/src/shade/device/timing/profile/sgpt_topology_codec.js +329 -0
- package/src/shade/device/timing/profile/sgpt_write_header.d.ts +22 -0
- package/src/shade/device/timing/profile/sgpt_write_header.d.ts.map +1 -0
- package/src/shade/device/timing/profile/sgpt_write_header.js +47 -0
- package/src/shade/device/timing/profile/sgpt_write_record.d.ts +23 -0
- package/src/shade/device/timing/profile/sgpt_write_record.d.ts.map +1 -0
- package/src/shade/device/timing/profile/sgpt_write_record.js +62 -0
- package/src/shade/renderer/Renderer.d.ts +21 -0
- package/src/shade/renderer/Renderer.d.ts.map +1 -1
- package/src/shade/renderer/Renderer.js +2513 -2455
- package/src/engine/save/GameStateLoader.d.ts +0 -49
- package/src/engine/save/GameStateLoader.d.ts.map +0 -1
- package/src/engine/save/GameStateLoader.js +0 -168
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
# The `.sgpt` container — format specification
|
|
2
|
+
|
|
3
|
+
**S**hade **G**PU **P**rofile **T**race, format version 2.
|
|
4
|
+
|
|
5
|
+
This document is the normative description of the file. It is written for somebody outside Company
|
|
6
|
+
Named who wants to read or write one without reading the engine's source. Every integer is
|
|
7
|
+
little-endian and unsigned unless stated otherwise.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 1. What the format is for, and what it is not
|
|
12
|
+
|
|
13
|
+
A capture holds **what a renderer asked a GPU to do over a run of frames, and how long each piece
|
|
14
|
+
took**: pass timings, the frame graph's structure and dependencies, declared resource sizes, and
|
|
15
|
+
dispatch and draw counts.
|
|
16
|
+
|
|
17
|
+
It deliberately does **not** hold buffer or texture contents, shader source, or anything else that
|
|
18
|
+
scales with the size of the resources it describes. That exclusion is what keeps a frame record in
|
|
19
|
+
the kilobytes and makes an uncapped recording practical.
|
|
20
|
+
|
|
21
|
+
### 1.1 Two properties the layout exists to provide
|
|
22
|
+
|
|
23
|
+
**A truncated capture is a capture.** A recording that ended when the tab did — which is the state
|
|
24
|
+
of every capture of a crash, a device loss, or a hang — must be readable up to the last intact
|
|
25
|
+
record. So every record is self-framed and checksummed, symbols travel inside the record that
|
|
26
|
+
introduces them, and the directory is an index over the stream rather than a prerequisite for
|
|
27
|
+
reading it.
|
|
28
|
+
|
|
29
|
+
**A reader may not understand everything, and must say so rather than fail.** Records carry a type
|
|
30
|
+
and a length; an unrecognised type is skipped by length. This is what lets a newer writer add record
|
|
31
|
+
types without a version bump, and what lets an older reader open the result and report honestly
|
|
32
|
+
which parts it could not show.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 2. File header
|
|
37
|
+
|
|
38
|
+
Thirty-two bytes at offset 0.
|
|
39
|
+
|
|
40
|
+
| Offset | Size | Field | Notes |
|
|
41
|
+
|---|---|---|---|
|
|
42
|
+
| 0 | 4 | `magic` | `0x54504753` — the ASCII bytes `S`, `G`, `P`, `T` in that order |
|
|
43
|
+
| 4 | 2 | `format_version` | 2 for this document |
|
|
44
|
+
| 6 | 2 | `min_reader_version` | the oldest reader that can read this file correctly |
|
|
45
|
+
| 8 | 4 | `flags` | see below |
|
|
46
|
+
| 12 | 4 | `header_checksum` | CRC-32 over bytes `[0, 8)` **only** |
|
|
47
|
+
| 16 | 8 | `directory_offset` | absolute; **0 when there is no directory** |
|
|
48
|
+
| 24 | 8 | `directory_byte_length` | 0 when absent |
|
|
49
|
+
|
|
50
|
+
Records begin at offset 32.
|
|
51
|
+
|
|
52
|
+
### 2.1 Flags
|
|
53
|
+
|
|
54
|
+
| Bit | Name | Meaning |
|
|
55
|
+
|---|---|---|
|
|
56
|
+
| 0 | `CLOSED` | the writer reached `stop()` and the file is complete as intended |
|
|
57
|
+
|
|
58
|
+
### 2.2 Why the checksum stops at byte 8
|
|
59
|
+
|
|
60
|
+
Everything from `flags` onward is written twice: zeroed when the header is laid down, and patched
|
|
61
|
+
when the session stops. A checksum covering those fields would have to be recomputed at stop — fine
|
|
62
|
+
for a capture that stops, and exactly wrong for one that does not, which would then carry a checksum
|
|
63
|
+
over bytes that were never written and read as corrupt.
|
|
64
|
+
|
|
65
|
+
What remains under the checksum is what a reader must trust before it can do anything at all: *is
|
|
66
|
+
this an `.sgpt`, and can this build read it.* Those never change after the header is written.
|
|
67
|
+
|
|
68
|
+
**A reader must not treat a missing `CLOSED` flag or a zero `directory_offset` as damage.** Both are
|
|
69
|
+
the normal state of an interrupted session, and such a file is fully readable by §3.
|
|
70
|
+
|
|
71
|
+
### 2.3 Version handling
|
|
72
|
+
|
|
73
|
+
A reader **must** refuse a file whose `min_reader_version` exceeds the highest format version it
|
|
74
|
+
implements, and **must** accept anything else. `min_reader_version` is raised only when a change
|
|
75
|
+
would make an older reader produce *wrong* answers rather than incomplete ones — a new record type
|
|
76
|
+
it would skip is incomplete; a reordered field is wrong.
|
|
77
|
+
|
|
78
|
+
Format version 2 keeps `min_reader_version` at 1: it added the `TOPO` record, which a version-1
|
|
79
|
+
reader skips by length, and appended a topology reference to the end of a frame's payload, which a
|
|
80
|
+
version-1 reader stops before.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 3. Records
|
|
85
|
+
|
|
86
|
+
Every record, whatever its type, is framed identically.
|
|
87
|
+
|
|
88
|
+
| Offset | Size | Field |
|
|
89
|
+
|---|---|---|
|
|
90
|
+
| 0 | 4 | `sync` — `0x43455253`, the ASCII bytes `S`, `R`, `E`, `C` |
|
|
91
|
+
| 4 | 4 | `record_type` — a four-character tag as a u32 |
|
|
92
|
+
| 8 | 4 | `payload_byte_length` |
|
|
93
|
+
| 12 | 4 | `payload_checksum` — CRC-32 over the payload bytes only |
|
|
94
|
+
| 16 | … | payload |
|
|
95
|
+
|
|
96
|
+
`payload_byte_length` is a u32 rather than a u64 because no record describes anything that scales
|
|
97
|
+
with resource size (§1); four gigabytes is not a ceiling anything can approach.
|
|
98
|
+
|
|
99
|
+
### 3.1 Reading, and resynchronising
|
|
100
|
+
|
|
101
|
+
The canonical read is a **forward scan from offset 32**, not a walk of the directory:
|
|
102
|
+
|
|
103
|
+
1. At the current offset, a record is present if — and only if — all four hold: the sync marker
|
|
104
|
+
matches, at least 16 bytes remain, the payload fits within the file, and the payload's CRC-32
|
|
105
|
+
matches `payload_checksum`.
|
|
106
|
+
2. If it does, decode or skip it by type and advance past its payload.
|
|
107
|
+
3. If it does not, scan forward one byte at a time for the next offset where all four hold. Report
|
|
108
|
+
the skipped bytes as damage; do not stop.
|
|
109
|
+
4. If the scan reaches the end without finding another record, the stream was truncated inside a
|
|
110
|
+
record. Report it. Everything already decoded stands.
|
|
111
|
+
|
|
112
|
+
**The sync marker alone is not sufficient and a reader must not treat it as such.** Four bytes of
|
|
113
|
+
payload can spell `SREC` — a pass label could — and resynchronising onto a false positive
|
|
114
|
+
desynchronises everything after it. The length and the checksum are what confirm a candidate.
|
|
115
|
+
|
|
116
|
+
### 3.2 Record types
|
|
117
|
+
|
|
118
|
+
| Tag | u32 | Payload | Cardinality |
|
|
119
|
+
|---|---|---|---|
|
|
120
|
+
| `META` | `0x4154454D` | §4 | 1, immediately after the header |
|
|
121
|
+
| `SYMS` | `0x534D5953` | §5 | 0..n, always before the records referencing them |
|
|
122
|
+
| `TOPO` | `0x4F504F54` | §6 | 0..n |
|
|
123
|
+
| `FRAM` | `0x4D415246` | §7 | 0..n |
|
|
124
|
+
| `CNTR` | `0x52544E43` | reserved | 0..1 |
|
|
125
|
+
| `DIRE` | `0x45524944` | §8 | 0..1, last |
|
|
126
|
+
|
|
127
|
+
An unrecognised tag **must** be skipped using `payload_byte_length`.
|
|
128
|
+
|
|
129
|
+
### 3.3 Primitive encodings
|
|
130
|
+
|
|
131
|
+
- `uintVar` — 7 bits per byte, low group first, high bit set on every byte but the last. Values are
|
|
132
|
+
limited to 2³¹−1.
|
|
133
|
+
- `utf8` — a `uintVar` byte length followed by that many UTF-8 bytes.
|
|
134
|
+
- `f64` — IEEE 754 binary64, little-endian.
|
|
135
|
+
- **Optional index** — a value of −1 meaning "none", written as `uintVar(value + 1)`. Zero means
|
|
136
|
+
none.
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## 4. `META`
|
|
141
|
+
|
|
142
|
+
| Field | Type | Notes |
|
|
143
|
+
|---|---|---|
|
|
144
|
+
| `level` | u8 | 0 `TIMING`, 1 `STRUCTURE`, 2 `WORKLOAD`, 3 `VERBOSE` |
|
|
145
|
+
| `wall_clock_start_ms` | f64 | `Date.now()` at session start; for ordering captures, not for timing |
|
|
146
|
+
| `note` | utf8 | free text from whoever captured |
|
|
147
|
+
| `engine_version` | utf8 | |
|
|
148
|
+
| `adapter_vendor` | utf8 | from `GPUAdapterInfo`; empty where the browser withheld it |
|
|
149
|
+
| `adapter_architecture` | utf8 | |
|
|
150
|
+
| `adapter_device` | utf8 | |
|
|
151
|
+
| `adapter_description` | utf8 | |
|
|
152
|
+
| `feature_count` | uintVar | |
|
|
153
|
+
| `features` | utf8 × count | `GPUFeatureName`s the device was created with |
|
|
154
|
+
|
|
155
|
+
### 4.1 On timestamp resolution — a deliberate absence
|
|
156
|
+
|
|
157
|
+
**There is no field here describing the device's timestamp quantum, and adding one is out of
|
|
158
|
+
scope.**
|
|
159
|
+
|
|
160
|
+
Browsers quantize WebGPU timestamps as a timing-attack mitigation; Chrome to 100 µs unless
|
|
161
|
+
`chrome://flags/#enable-webgpu-developer-features` is set. Most passes in a real renderer run below
|
|
162
|
+
that and are reported as exactly zero.
|
|
163
|
+
|
|
164
|
+
Recovering the quantum from the data — a GCD over observed timestamps, or any equivalent — *is* the
|
|
165
|
+
timing attack the mitigation exists to prevent, and doing it imperfectly applies a wrong correction
|
|
166
|
+
to every number in the file. So a capture records what the device reported, zeros included, and says
|
|
167
|
+
nothing further. A reader that wants to present this honestly should aggregate across many frames
|
|
168
|
+
rather than trust any single one, and should say so where the reader will see it.
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## 5. `SYMS`
|
|
173
|
+
|
|
174
|
+
| Field | Type |
|
|
175
|
+
|---|---|
|
|
176
|
+
| `first_index` | uintVar |
|
|
177
|
+
| `count` | uintVar |
|
|
178
|
+
| `strings` | utf8 × count |
|
|
179
|
+
|
|
180
|
+
Strings occupy one index space across the whole file; a block declares where its run begins. Every
|
|
181
|
+
later reference is a `uintVar` index into that space.
|
|
182
|
+
|
|
183
|
+
A `SYMS` block **always precedes** the record that references its strings. A writer must not gather
|
|
184
|
+
symbols into one block at the end of the file: a capture truncated before that block would resolve
|
|
185
|
+
no names at all, which is precisely the capture of the crash somebody was trying to record.
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## 6. `TOPO` — frame graph structure
|
|
190
|
+
|
|
191
|
+
Present at capture level `STRUCTURE` and above.
|
|
192
|
+
|
|
193
|
+
| Field | Type |
|
|
194
|
+
|---|---|
|
|
195
|
+
| `id` | uintVar — what a frame refers to |
|
|
196
|
+
| `name` | symbol index |
|
|
197
|
+
| `scope_count` | uintVar |
|
|
198
|
+
| **per scope** | `name` (symbol index), `parent` (optional index) |
|
|
199
|
+
| `pass_count` | uintVar |
|
|
200
|
+
| **per pass** | see §6.1 |
|
|
201
|
+
| `resource_count` | uintVar |
|
|
202
|
+
| **per resource** | see §6.2 |
|
|
203
|
+
|
|
204
|
+
A scope's parent always appears at a lower index than the scope itself, so a reader resolves the
|
|
205
|
+
chain in one forward pass.
|
|
206
|
+
|
|
207
|
+
### 6.1 Pass
|
|
208
|
+
|
|
209
|
+
| Field | Type |
|
|
210
|
+
|---|---|
|
|
211
|
+
| `id` | uintVar |
|
|
212
|
+
| `name` | symbol index |
|
|
213
|
+
| `scope` | optional index |
|
|
214
|
+
| `flags` | u8 — bit 0 `CULLED`, bit 1 `HAS_SIDE_EFFECTS` |
|
|
215
|
+
| `ref_count` | uintVar |
|
|
216
|
+
| `reads` | uintVar count, then that many resource **node** ids |
|
|
217
|
+
| `writes` | same |
|
|
218
|
+
| `creates` | same |
|
|
219
|
+
|
|
220
|
+
### 6.2 Resource
|
|
221
|
+
|
|
222
|
+
One entry per resource **node** — that is, per version. A pass records the node it touched rather
|
|
223
|
+
than the underlying resource, so a registry-keyed model would leave every reference past version 0
|
|
224
|
+
dangling.
|
|
225
|
+
|
|
226
|
+
| Field | Type |
|
|
227
|
+
|---|---|
|
|
228
|
+
| `id` | uintVar |
|
|
229
|
+
| `name` | symbol index |
|
|
230
|
+
| `version` | uintVar |
|
|
231
|
+
| `flags` | u8 — bit 2 `TRANSIENT`, bit 3 `IMPORTED` |
|
|
232
|
+
| `producer` | optional index — the pass that produced this version |
|
|
233
|
+
| `kind` | u8 — 0 none, 1 buffer, 2 texture |
|
|
234
|
+
| `usage` | uintVar — `GPUBufferUsage` / `GPUTextureUsage` bitmask |
|
|
235
|
+
| `byte_size` | uintVar — declared bytes, §6.3 |
|
|
236
|
+
| **if buffer** | `size` (uintVar) |
|
|
237
|
+
| **if texture** | `width`, `height`, `depth`, `mip_level_count`, `sample_count` (uintVar each), `format`, `dimension` (symbol indices) |
|
|
238
|
+
|
|
239
|
+
### 6.3 `byte_size` is declared, and is computed by the writer
|
|
240
|
+
|
|
241
|
+
Declared, not allocated: a pooled allocator may serve a larger block, and an aliasing one may serve
|
|
242
|
+
the same block to two resources whose lifetimes do not overlap.
|
|
243
|
+
|
|
244
|
+
For a texture it covers the whole mip chain at the given sample count. **The writer computes it**
|
|
245
|
+
rather than leaving a reader to, because working it out needs the format's block dimensions — so a
|
|
246
|
+
reader never has to carry a copy of that table, and a format the reader has never heard of still
|
|
247
|
+
reports a size. A writer that cannot determine a size **must** write 0.
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## 7. `FRAM` — one frame
|
|
252
|
+
|
|
253
|
+
| Field | Type |
|
|
254
|
+
|---|---|
|
|
255
|
+
| `frame_index` | uintVar — the renderer's own counter, not a position in the file |
|
|
256
|
+
| `cpu_begin_ms` | f64 — `performance.now()` when encoding began |
|
|
257
|
+
| `cpu_submit_ms` | f64 — `performance.now()` at submit |
|
|
258
|
+
| `gpu_epoch_ns` | u64 — the earliest GPU timestamp in this frame |
|
|
259
|
+
| `dropped_pass_count` | uintVar — passes that went untimed, §7.2 |
|
|
260
|
+
| `span_count` | uintVar |
|
|
261
|
+
| **per span** | §7.1 |
|
|
262
|
+
| `topology_id` | optional index — **appended last**, absent in a format-1 file |
|
|
263
|
+
|
|
264
|
+
### 7.1 Span
|
|
265
|
+
|
|
266
|
+
| Field | Type |
|
|
267
|
+
|---|---|
|
|
268
|
+
| `label` | symbol index |
|
|
269
|
+
| `kind` | u8 — 0 compute, 1 render |
|
|
270
|
+
| `query_set_id` | u8 — §7.3 |
|
|
271
|
+
| `t_begin_ns` | u32 — nanoseconds from `gpu_epoch_ns` |
|
|
272
|
+
| `duration_ns` | uintVar |
|
|
273
|
+
| `graph_pass_id` | optional index — the frame graph pass that was executing when this pass opened |
|
|
274
|
+
| `has_work` | u8 — 1 if a workload block follows |
|
|
275
|
+
| **if `has_work`** | `dispatch_count`, `indirect_dispatch_count`, `workgroups_x/y/z`, `draw_count`, `indirect_draw_count`, `vertex_count`, `index_count`, `instance_count` (uintVar each), `pipeline` (symbol index), `workgroup_size_x/y/z` (uintVar each) |
|
|
276
|
+
|
|
277
|
+
`t_begin_ns` is a u32 of nanoseconds, holding 4.29 s — three orders of magnitude past any frame, and
|
|
278
|
+
enough to survive a stall rather than wrap. A writer **must** clamp rather than wrap, and **must**
|
|
279
|
+
write a duration of 0 where a device reports an end before its begin.
|
|
280
|
+
|
|
281
|
+
`has_work` is per span rather than per frame because a frame genuinely mixes the two: a pass opened
|
|
282
|
+
before the recorder was attached has no workload record, and a per-frame flag would have to lie
|
|
283
|
+
about one of them.
|
|
284
|
+
|
|
285
|
+
A `workgroup_size` of `[0, 0, 0]` means **unknown** — typically an override-expression size — and is
|
|
286
|
+
not the same as zero work. A reader must not compute an invocation count from it.
|
|
287
|
+
|
|
288
|
+
### 7.2 `dropped_pass_count`
|
|
289
|
+
|
|
290
|
+
Passes the recorder could not time because the frame had more of them than its query set had slots.
|
|
291
|
+
Carried because an untimed pass reads downstream as a free one. A reader should surface a non-zero
|
|
292
|
+
value rather than presenting the frame as complete.
|
|
293
|
+
|
|
294
|
+
### 7.3 `query_set_id`
|
|
295
|
+
|
|
296
|
+
Which of the frame's command contexts produced this span. Timestamps from two different
|
|
297
|
+
`GPUQuerySet`s are not specified to share a clock domain, and a frame ordinarily spans several.
|
|
298
|
+
Carried so that an anomaly following a query-set boundary is visible rather than unfalsifiable.
|
|
299
|
+
|
|
300
|
+
### 7.4 The two clocks are not one clock
|
|
301
|
+
|
|
302
|
+
`cpu_*` come from `performance.now()`; `gpu_epoch_ns` and the spans come from the device. WebGPU
|
|
303
|
+
exposes no calibration between them, and this format carries none. Anything that places the two on
|
|
304
|
+
one axis is anchoring, not synchronising, and should say so.
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## 8. `DIRE` — directory
|
|
309
|
+
|
|
310
|
+
| Field | Type |
|
|
311
|
+
|---|---|
|
|
312
|
+
| `record_count` | uintVar |
|
|
313
|
+
| **per record** | `type` (u32), `offset` (u64), `byte_length` (u32) |
|
|
314
|
+
|
|
315
|
+
Written last, and does not index itself.
|
|
316
|
+
|
|
317
|
+
**A reader must not require it, and must not prefer it to the records.** It exists so that a future
|
|
318
|
+
reader can seek instead of scan. A capture that never reached `stop()` has none, and is not thereby
|
|
319
|
+
a lesser capture.
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## 9. Conformance summary
|
|
324
|
+
|
|
325
|
+
A conforming **reader**:
|
|
326
|
+
|
|
327
|
+
- refuses a file whose magic does not match or whose `min_reader_version` exceeds its own;
|
|
328
|
+
- reads by scanning records, and does not require a directory or the `CLOSED` flag;
|
|
329
|
+
- validates sync, length and checksum together before accepting a record;
|
|
330
|
+
- resynchronises past damage and reports it, rather than stopping;
|
|
331
|
+
- skips unrecognised record types by length and reports that it did;
|
|
332
|
+
- treats `[0, 0, 0]` workgroup sizes and absent workload blocks as *unknown*, never as zero.
|
|
333
|
+
|
|
334
|
+
A conforming **writer**:
|
|
335
|
+
|
|
336
|
+
- emits `META` first and `DIRE` last, and patches only `flags` and the directory fields;
|
|
337
|
+
- emits a `SYMS` block before any record referencing its strings;
|
|
338
|
+
- never gathers symbols into a single trailing block;
|
|
339
|
+
- clamps rather than wraps out-of-range span times, and writes 0 for an unknown size;
|
|
340
|
+
- records what the device reported, without correcting for timestamp quantization.
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
*Company Named Limited (c) 2026. The format is documented for interoperability; the engine that
|
|
345
|
+
writes it is proprietary and source-available under its own licence.*
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Version of the `.sgpt` layout this build writes.
|
|
3
|
+
*
|
|
4
|
+
* Bump for any change to what a record's payload means. Adding a *new* record type is not such a
|
|
5
|
+
* change — readers skip unknown types by length — so it does not need one.
|
|
6
|
+
*
|
|
7
|
+
* @type {number}
|
|
8
|
+
*/
|
|
9
|
+
export const SGPT_FORMAT_VERSION: number;
|
|
10
|
+
//# sourceMappingURL=SGPT_FORMAT_VERSION.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SGPT_FORMAT_VERSION.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/device/timing/profile/SGPT_FORMAT_VERSION.js"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,kCAFU,MAAM,CAEqB"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Version of the `.sgpt` layout this build writes.
|
|
3
|
+
*
|
|
4
|
+
* Bump for any change to what a record's payload means. Adding a *new* record type is not such a
|
|
5
|
+
* change — readers skip unknown types by length — so it does not need one.
|
|
6
|
+
*
|
|
7
|
+
* @type {number}
|
|
8
|
+
*/
|
|
9
|
+
export const SGPT_FORMAT_VERSION = 2;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bytes the writer reserves at each frame boundary, so that {@link BinaryBuffer} growth — an
|
|
3
|
+
* allocation and a copy — happens *between* frames rather than inside one.
|
|
4
|
+
*
|
|
5
|
+
* The cost of a grow was never CPU time; it is a memcpy that may evict some cache and make the next
|
|
6
|
+
* GPU upload marginally slower, which is a rounding error against what is being measured. This
|
|
7
|
+
* keeps even that out of the interval a frame's timings are taken over.
|
|
8
|
+
*
|
|
9
|
+
* 1 MiB against a level-2 frame record of a few kilobytes is three orders of magnitude of headroom,
|
|
10
|
+
* so a reservation actually forces a grow only once every few hundred frames. That ratio holds only
|
|
11
|
+
* because resource *contents* are out of scope: nothing in a record scales with the size of the
|
|
12
|
+
* buffers and textures it describes.
|
|
13
|
+
*
|
|
14
|
+
* @type {number}
|
|
15
|
+
*/
|
|
16
|
+
export const SGPT_FRAME_SLACK: number;
|
|
17
|
+
//# sourceMappingURL=SGPT_FRAME_SLACK.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SGPT_FRAME_SLACK.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/device/timing/profile/SGPT_FRAME_SLACK.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,+BAFU,MAAM,CAE4B"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bytes the writer reserves at each frame boundary, so that {@link BinaryBuffer} growth — an
|
|
3
|
+
* allocation and a copy — happens *between* frames rather than inside one.
|
|
4
|
+
*
|
|
5
|
+
* The cost of a grow was never CPU time; it is a memcpy that may evict some cache and make the next
|
|
6
|
+
* GPU upload marginally slower, which is a rounding error against what is being measured. This
|
|
7
|
+
* keeps even that out of the interval a frame's timings are taken over.
|
|
8
|
+
*
|
|
9
|
+
* 1 MiB against a level-2 frame record of a few kilobytes is three orders of magnitude of headroom,
|
|
10
|
+
* so a reservation actually forces a grow only once every few hundred frames. That ratio holds only
|
|
11
|
+
* because resource *contents* are out of scope: nothing in a record scales with the size of the
|
|
12
|
+
* buffers and textures it describes.
|
|
13
|
+
*
|
|
14
|
+
* @type {number}
|
|
15
|
+
*/
|
|
16
|
+
export const SGPT_FRAME_SLACK = 1024 * 1024;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bytes the header checksum covers: the magic and the two version fields, and nothing else.
|
|
3
|
+
*
|
|
4
|
+
* It stops short of `flags` on purpose. Everything from `flags` onward is patched at
|
|
5
|
+
* {@link GPUProfileSession#stop} — the CLOSED bit and the directory pointer — and a checksum
|
|
6
|
+
* covering them would have to be recomputed then. That is fine for a capture that stops, and
|
|
7
|
+
* exactly wrong for one that does not: the file would carry a checksum over bytes that were never
|
|
8
|
+
* written, and a reader would call the recoverable case corrupt.
|
|
9
|
+
*
|
|
10
|
+
* What is left under the checksum is what a reader must trust before it can do anything at all —
|
|
11
|
+
* is this an `.sgpt`, and can this build read it. Those never change after the header is written.
|
|
12
|
+
*
|
|
13
|
+
* @type {number}
|
|
14
|
+
*/
|
|
15
|
+
export const SGPT_HEADER_CHECKSUM_COVERAGE: number;
|
|
16
|
+
//# sourceMappingURL=SGPT_HEADER_CHECKSUM_COVERAGE.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SGPT_HEADER_CHECKSUM_COVERAGE.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/device/timing/profile/SGPT_HEADER_CHECKSUM_COVERAGE.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,4CAFU,MAAM,CAE+B"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bytes the header checksum covers: the magic and the two version fields, and nothing else.
|
|
3
|
+
*
|
|
4
|
+
* It stops short of `flags` on purpose. Everything from `flags` onward is patched at
|
|
5
|
+
* {@link GPUProfileSession#stop} — the CLOSED bit and the directory pointer — and a checksum
|
|
6
|
+
* covering them would have to be recomputed then. That is fine for a capture that stops, and
|
|
7
|
+
* exactly wrong for one that does not: the file would carry a checksum over bytes that were never
|
|
8
|
+
* written, and a reader would call the recoverable case corrupt.
|
|
9
|
+
*
|
|
10
|
+
* What is left under the checksum is what a reader must trust before it can do anything at all —
|
|
11
|
+
* is this an `.sgpt`, and can this build read it. Those never change after the header is written.
|
|
12
|
+
*
|
|
13
|
+
* @type {number}
|
|
14
|
+
*/
|
|
15
|
+
export const SGPT_HEADER_CHECKSUM_COVERAGE = 8;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Byte offsets of the fields in an `.sgpt` file header. The header is the only fixed-layout region
|
|
3
|
+
* in the container; everything after it is records (see {@link SGPT_RECORD_OFFSET }).
|
|
4
|
+
*/
|
|
5
|
+
export type SGPT_HEADER_OFFSET = number;
|
|
6
|
+
export namespace SGPT_HEADER_OFFSET {
|
|
7
|
+
let MAGIC: number;
|
|
8
|
+
let FORMAT_VERSION: number;
|
|
9
|
+
let MIN_READER_VERSION: number;
|
|
10
|
+
let FLAGS: number;
|
|
11
|
+
let HEADER_CHECKSUM: number;
|
|
12
|
+
let DIRECTORY_OFFSET: number;
|
|
13
|
+
let DIRECTORY_BYTE_LENGTH: number;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=SGPT_HEADER_OFFSET.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SGPT_HEADER_OFFSET.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/device/timing/profile/SGPT_HEADER_OFFSET.js"],"names":[],"mappings":";;;;iCAIU,MAAM"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Byte offsets of the fields in an `.sgpt` file header. The header is the only fixed-layout region
|
|
3
|
+
* in the container; everything after it is records (see {@link SGPT_RECORD_OFFSET}).
|
|
4
|
+
*
|
|
5
|
+
* @enum {number}
|
|
6
|
+
*/
|
|
7
|
+
export const SGPT_HEADER_OFFSET = {
|
|
8
|
+
/** u32, {@link SGPT_MAGIC} */
|
|
9
|
+
MAGIC: 0,
|
|
10
|
+
/** u16, {@link SGPT_FORMAT_VERSION} */
|
|
11
|
+
FORMAT_VERSION: 4,
|
|
12
|
+
/** u16, {@link SGPT_MIN_READER_VERSION} */
|
|
13
|
+
MIN_READER_VERSION: 6,
|
|
14
|
+
/** u32, {@link SGPT_FLAG} bitmask */
|
|
15
|
+
FLAGS: 8,
|
|
16
|
+
/** u32, crc32 over bytes `[0, 12)` — the fields above, and nothing that is patched later */
|
|
17
|
+
HEADER_CHECKSUM: 12,
|
|
18
|
+
/**
|
|
19
|
+
* u64, absolute offset of the directory record.
|
|
20
|
+
*
|
|
21
|
+
* **Zero means there is no directory**, which is the state of every capture that never reached
|
|
22
|
+
* {@link GPUProfileSession.stop} — the tab closed, the device was lost. Such a file is still
|
|
23
|
+
* fully readable by scanning records, and a reader that treats a zero here as corruption is
|
|
24
|
+
* throwing away exactly the captures worth having.
|
|
25
|
+
*/
|
|
26
|
+
DIRECTORY_OFFSET: 16,
|
|
27
|
+
/** u64, byte length of the directory record including its own framing. Zero when absent. */
|
|
28
|
+
DIRECTORY_BYTE_LENGTH: 24
|
|
29
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SGPT_HEADER_SIZE.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/device/timing/profile/SGPT_HEADER_SIZE.js"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,+BAFU,MAAM,CAEmB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SGPT_MAGIC.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/device/timing/profile/SGPT_MAGIC.js"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,yBAFU,MAAM,CAEqB"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The oldest reader that can still make sense of what this build writes.
|
|
3
|
+
*
|
|
4
|
+
* A reader refuses a file whose `min_reader_version` exceeds its own {@link SGPT_FORMAT_VERSION},
|
|
5
|
+
* and opens anything else. Raise this only when a change makes an older reader produce *wrong*
|
|
6
|
+
* answers rather than incomplete ones — a new record type it would skip is incomplete, a reordered
|
|
7
|
+
* field is wrong.
|
|
8
|
+
*
|
|
9
|
+
* Still 1 at format version 2: the topology link was appended to the end of a frame's payload and
|
|
10
|
+
* `TOPO` is a new record type, so a version-1 reader skips one by length and stops before the other.
|
|
11
|
+
* It sees a capture with no structure, which is incomplete rather than wrong.
|
|
12
|
+
*
|
|
13
|
+
* @type {number}
|
|
14
|
+
*/
|
|
15
|
+
export const SGPT_MIN_READER_VERSION: number;
|
|
16
|
+
//# sourceMappingURL=SGPT_MIN_READER_VERSION.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SGPT_MIN_READER_VERSION.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/device/timing/profile/SGPT_MIN_READER_VERSION.js"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,sCAFU,MAAM,CAEyB"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The oldest reader that can still make sense of what this build writes.
|
|
3
|
+
*
|
|
4
|
+
* A reader refuses a file whose `min_reader_version` exceeds its own {@link SGPT_FORMAT_VERSION},
|
|
5
|
+
* and opens anything else. Raise this only when a change makes an older reader produce *wrong*
|
|
6
|
+
* answers rather than incomplete ones — a new record type it would skip is incomplete, a reordered
|
|
7
|
+
* field is wrong.
|
|
8
|
+
*
|
|
9
|
+
* Still 1 at format version 2: the topology link was appended to the end of a frame's payload and
|
|
10
|
+
* `TOPO` is a new record type, so a version-1 reader skips one by length and stops before the other.
|
|
11
|
+
* It sees a capture with no structure, which is incomplete rather than wrong.
|
|
12
|
+
*
|
|
13
|
+
* @type {number}
|
|
14
|
+
*/
|
|
15
|
+
export const SGPT_MIN_READER_VERSION = 1;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SGPT_RECORD_HEADER_SIZE.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/device/timing/profile/SGPT_RECORD_HEADER_SIZE.js"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,sCAFU,MAAM,CAE0B"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Byte offsets within a record's framing. Every record in the stream carries this same 16-byte head,
|
|
3
|
+
* whatever its type, which is what makes the stream scannable by a reader that understands none of
|
|
4
|
+
* the payloads.
|
|
5
|
+
*/
|
|
6
|
+
export type SGPT_RECORD_OFFSET = number;
|
|
7
|
+
export namespace SGPT_RECORD_OFFSET {
|
|
8
|
+
let SYNC: number;
|
|
9
|
+
let TYPE: number;
|
|
10
|
+
let PAYLOAD_BYTE_LENGTH: number;
|
|
11
|
+
let PAYLOAD_CHECKSUM: number;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=SGPT_RECORD_OFFSET.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SGPT_RECORD_OFFSET.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/device/timing/profile/SGPT_RECORD_OFFSET.js"],"names":[],"mappings":";;;;;iCAKU,MAAM"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Byte offsets within a record's framing. Every record in the stream carries this same 16-byte head,
|
|
3
|
+
* whatever its type, which is what makes the stream scannable by a reader that understands none of
|
|
4
|
+
* the payloads.
|
|
5
|
+
*
|
|
6
|
+
* @enum {number}
|
|
7
|
+
*/
|
|
8
|
+
export const SGPT_RECORD_OFFSET = {
|
|
9
|
+
/** u32, {@link SGPT_RECORD_SYNC} */
|
|
10
|
+
SYNC: 0,
|
|
11
|
+
/** u32, a {@link SGPT_RECORD_TYPE} */
|
|
12
|
+
TYPE: 4,
|
|
13
|
+
/**
|
|
14
|
+
* u32, payload bytes following this head.
|
|
15
|
+
*
|
|
16
|
+
* u32 rather than u64 deliberately: a record describes one frame's control flow, and buffer and
|
|
17
|
+
* texture *contents* are a non-goal of this format, so nothing in a record scales with the size
|
|
18
|
+
* of the resources it describes. Four gigabytes is not a ceiling anything can approach.
|
|
19
|
+
*/
|
|
20
|
+
PAYLOAD_BYTE_LENGTH: 8,
|
|
21
|
+
/** u32, crc32 over the payload bytes only */
|
|
22
|
+
PAYLOAD_CHECKSUM: 12
|
|
23
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `'SREC'`, the little-endian u32 that opens every record in the stream.
|
|
3
|
+
*
|
|
4
|
+
* A reader that has lost its place — corruption, a torn write, a capture that ended when the tab
|
|
5
|
+
* did — scans forward for this and resumes. It is not a guarantee on its own: four bytes of payload
|
|
6
|
+
* can spell `SREC` by accident. It is the cheap filter, and the record's length and checksum are
|
|
7
|
+
* what actually confirm the find. See {@link sgpt_read_records}.
|
|
8
|
+
*
|
|
9
|
+
* @type {number}
|
|
10
|
+
*/
|
|
11
|
+
export const SGPT_RECORD_SYNC: number;
|
|
12
|
+
//# sourceMappingURL=SGPT_RECORD_SYNC.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SGPT_RECORD_SYNC.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/device/timing/profile/SGPT_RECORD_SYNC.js"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,+BAFU,MAAM,CAE2B"}
|