@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,153 @@
|
|
|
1
|
+
import { assert } from "../../../../core/assert.js";
|
|
2
|
+
import { crc32 } from "../../../../core/binary/hash/crc32.js";
|
|
3
|
+
import { SGPT_DEFECT } from "./SGPT_DEFECT.js";
|
|
4
|
+
import { SGPTDefect } from "./SGPTDefect.js";
|
|
5
|
+
import { SGPT_HEADER_SIZE } from "./SGPT_HEADER_SIZE.js";
|
|
6
|
+
import { SGPT_RECORD_HEADER_SIZE } from "./SGPT_RECORD_HEADER_SIZE.js";
|
|
7
|
+
import { SGPT_RECORD_SYNC } from "./SGPT_RECORD_SYNC.js";
|
|
8
|
+
import { SGPTRecordRef } from "./SGPTRecordRef.js";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Sync marker as four bytes, in the order they appear on the wire. Compared byte-wise during a
|
|
12
|
+
* scan so that resynchronisation does not depend on alignment — corruption does not politely
|
|
13
|
+
* truncate to a multiple of four.
|
|
14
|
+
*
|
|
15
|
+
* @type {number[]}
|
|
16
|
+
*/
|
|
17
|
+
const SYNC_BYTES = [
|
|
18
|
+
SGPT_RECORD_SYNC & 0xff,
|
|
19
|
+
(SGPT_RECORD_SYNC >>> 8) & 0xff,
|
|
20
|
+
(SGPT_RECORD_SYNC >>> 16) & 0xff,
|
|
21
|
+
(SGPT_RECORD_SYNC >>> 24) & 0xff
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Whether a well-formed, checksum-clean record starts at `offset`.
|
|
26
|
+
*
|
|
27
|
+
* All four conditions are checked together on purpose. The sync marker alone is a four-byte
|
|
28
|
+
* coincidence away from a false positive — a `SREC` in a pass label would do it — and accepting one
|
|
29
|
+
* mid-scan would resynchronise onto garbage and desynchronise everything after. The length has to
|
|
30
|
+
* fit and the payload has to checksum before a candidate counts.
|
|
31
|
+
*
|
|
32
|
+
* @param {Uint8Array} bytes
|
|
33
|
+
* @param {DataView} view over the same bytes, hoisted because the resync scan calls this per byte
|
|
34
|
+
* @param {number} offset
|
|
35
|
+
* @param {number} end
|
|
36
|
+
* @returns {SGPTRecordRef|null}
|
|
37
|
+
*/
|
|
38
|
+
function try_read_record_at(bytes, view, offset, end) {
|
|
39
|
+
if (offset + SGPT_RECORD_HEADER_SIZE > end) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
for (let i = 0; i < 4; i++) {
|
|
44
|
+
if (bytes[offset + i] !== SYNC_BYTES[i]) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const type = view.getUint32(offset + 4, true);
|
|
50
|
+
const payload_byte_length = view.getUint32(offset + 8, true);
|
|
51
|
+
const stored_checksum = view.getUint32(offset + 12, true);
|
|
52
|
+
|
|
53
|
+
const payload_offset = offset + SGPT_RECORD_HEADER_SIZE;
|
|
54
|
+
|
|
55
|
+
if (payload_offset + payload_byte_length > end) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (crc32(bytes, payload_offset, payload_byte_length) !== stored_checksum) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return new SGPTRecordRef(type, offset, payload_offset, payload_byte_length);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Walk the record stream, resynchronising past anything that is not a record.
|
|
68
|
+
*
|
|
69
|
+
* The stream is designed to be read this way rather than through the directory, and the directory
|
|
70
|
+
* is an index over the result rather than a prerequisite for it. A capture that ended when the tab
|
|
71
|
+
* did has no directory at all, and it is exactly the capture worth reading.
|
|
72
|
+
*
|
|
73
|
+
* Two recoverable outcomes are reported and kept going:
|
|
74
|
+
*
|
|
75
|
+
* - **Resync.** Bytes that are not a record are skipped and a {@link SGPT_DEFECT.RESYNC} names how
|
|
76
|
+
* many. Everything after the damage is still decoded.
|
|
77
|
+
* - **Truncation.** The stream ends inside a record. A {@link SGPT_DEFECT.TRUNCATED} says so, and
|
|
78
|
+
* the records before it stand. This is the ordinary end state of an interrupted session, not a
|
|
79
|
+
* sign that anything went wrong with the writing.
|
|
80
|
+
*
|
|
81
|
+
* @param {BinaryBuffer} buffer
|
|
82
|
+
* @param {number} end offset one past the last readable byte
|
|
83
|
+
* @param {SGPTDefect[]} defects appended to
|
|
84
|
+
* @returns {SGPTRecordRef[]} in stream order
|
|
85
|
+
*
|
|
86
|
+
* @author Alex Goldring
|
|
87
|
+
* @copyright Company Named Limited (c) 2026
|
|
88
|
+
*/
|
|
89
|
+
export function sgpt_read_records(buffer, end, defects) {
|
|
90
|
+
assert.defined(buffer, 'buffer');
|
|
91
|
+
assert.isNonNegativeInteger(end, 'end');
|
|
92
|
+
assert.isArray(defects, 'defects');
|
|
93
|
+
|
|
94
|
+
const bytes = buffer.raw_bytes;
|
|
95
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
96
|
+
|
|
97
|
+
const result = [];
|
|
98
|
+
|
|
99
|
+
let offset = SGPT_HEADER_SIZE;
|
|
100
|
+
|
|
101
|
+
while (offset < end) {
|
|
102
|
+
|
|
103
|
+
const record = try_read_record_at(bytes, view, offset, end);
|
|
104
|
+
|
|
105
|
+
if (record !== null) {
|
|
106
|
+
result.push(record);
|
|
107
|
+
|
|
108
|
+
offset = record.payload_offset + record.payload_byte_length;
|
|
109
|
+
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Nothing valid here. Scan for somewhere that is.
|
|
114
|
+
const damaged_from = offset;
|
|
115
|
+
|
|
116
|
+
let scan = offset + 1;
|
|
117
|
+
let recovered = null;
|
|
118
|
+
|
|
119
|
+
while (scan < end) {
|
|
120
|
+
recovered = try_read_record_at(bytes, view, scan, end);
|
|
121
|
+
|
|
122
|
+
if (recovered !== null) {
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
scan++;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (recovered === null) {
|
|
130
|
+
// Ran out without finding another record. Everything from here on is either a partial
|
|
131
|
+
// final record or trailing damage; either way there is nothing more to decode.
|
|
132
|
+
defects.push(new SGPTDefect(
|
|
133
|
+
SGPT_DEFECT.TRUNCATED,
|
|
134
|
+
`stream ends inside a record; ${end - damaged_from} unreadable bytes at the tail`,
|
|
135
|
+
damaged_from
|
|
136
|
+
));
|
|
137
|
+
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
defects.push(new SGPTDefect(
|
|
142
|
+
SGPT_DEFECT.RESYNC,
|
|
143
|
+
`skipped ${scan - damaged_from} bytes that are not a record`,
|
|
144
|
+
damaged_from
|
|
145
|
+
));
|
|
146
|
+
|
|
147
|
+
result.push(recovered);
|
|
148
|
+
|
|
149
|
+
offset = recovered.payload_offset + recovered.payload_byte_length;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return result;
|
|
153
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Encode a `TOPO` payload.
|
|
3
|
+
*
|
|
4
|
+
* @param {BinaryBuffer} buffer
|
|
5
|
+
* @param {GPUProfileTopology} topology
|
|
6
|
+
* @param {function(string): number} intern
|
|
7
|
+
* @returns {void}
|
|
8
|
+
*
|
|
9
|
+
* @author Alex Goldring
|
|
10
|
+
* @copyright Company Named Limited (c) 2026
|
|
11
|
+
*/
|
|
12
|
+
export function sgpt_write_topology(buffer: BinaryBuffer, topology: GPUProfileTopology, intern: (arg0: string) => number): void;
|
|
13
|
+
/**
|
|
14
|
+
* Every string a topology will need interned, in the order {@link sgpt_write_topology} asks for
|
|
15
|
+
* them.
|
|
16
|
+
*
|
|
17
|
+
* Exists because symbols must be flushed into a `SYMS` record *before* the record referencing them
|
|
18
|
+
* — interning from inside the payload writer puts them in the next flush, behind the record that
|
|
19
|
+
* needs them, and a capture truncated in between resolves none of them.
|
|
20
|
+
*
|
|
21
|
+
* @param {GPUProfileTopology} topology
|
|
22
|
+
* @param {function(string): number} intern
|
|
23
|
+
* @returns {void}
|
|
24
|
+
*/
|
|
25
|
+
export function sgpt_intern_topology_symbols(topology: GPUProfileTopology, intern: (arg0: string) => number): void;
|
|
26
|
+
/**
|
|
27
|
+
* Decode a `TOPO` payload.
|
|
28
|
+
*
|
|
29
|
+
* @param {BinaryBuffer} buffer positioned at the payload
|
|
30
|
+
* @param {string[]} symbols
|
|
31
|
+
* @returns {GPUProfileTopology}
|
|
32
|
+
*/
|
|
33
|
+
export function sgpt_read_topology(buffer: BinaryBuffer, symbols: string[]): GPUProfileTopology;
|
|
34
|
+
/**
|
|
35
|
+
* A content hash of everything that makes one topology different from another.
|
|
36
|
+
*
|
|
37
|
+
* This is what deduplication turns on. A Shade frame graph is nearly identical frame to frame, so
|
|
38
|
+
* the steady state hashes to one value for hundreds of frames and the structure is stored once —
|
|
39
|
+
* the difference between a capture of tens of megabytes and one of a couple.
|
|
40
|
+
*
|
|
41
|
+
* **Cull state is part of the hash.** A frame where a different set of passes was culled genuinely
|
|
42
|
+
* is a different shape, and folding the two together would report passes as having run in frames
|
|
43
|
+
* where they did not.
|
|
44
|
+
*
|
|
45
|
+
* FNV-1a over a canonical string. Not cryptographic and does not need to be: a collision costs a
|
|
46
|
+
* mislabelled structure in a debug tool, and the inputs are pass names and integers rather than
|
|
47
|
+
* anything adversarial.
|
|
48
|
+
*
|
|
49
|
+
* @param {GPUProfileTopology} topology
|
|
50
|
+
* @returns {number} unsigned 32-bit
|
|
51
|
+
*/
|
|
52
|
+
export function sgpt_topology_hash(topology: GPUProfileTopology): number;
|
|
53
|
+
import { GPUProfileTopology } from "./GPUProfileTopology.js";
|
|
54
|
+
//# sourceMappingURL=sgpt_topology_codec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sgpt_topology_codec.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/device/timing/profile/sgpt_topology_codec.js"],"names":[],"mappings":"AA6DA;;;;;;;;;;GAUG;AACH,oEAPW,kBAAkB,iBACT,MAAM,KAAG,MAAM,GACtB,IAAI,CAiFhB;AAED;;;;;;;;;;;GAWG;AACH,uDAJW,kBAAkB,iBACT,MAAM,KAAG,MAAM,GACtB,IAAI,CAqBhB;AAED;;;;;;GAMG;AACH,kEAHW,MAAM,EAAE,GACN,kBAAkB,CA2F9B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,6CAHW,kBAAkB,GAChB,MAAM,CA+BlB;mCAjUM,yBAAyB"}
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
import { assert } from "../../../../core/assert.js";
|
|
2
|
+
import {
|
|
3
|
+
GPUProfilePass,
|
|
4
|
+
GPUProfileResource,
|
|
5
|
+
GPUProfileResourceKind,
|
|
6
|
+
GPUProfileScope,
|
|
7
|
+
GPUProfileTopology
|
|
8
|
+
} from "./GPUProfileTopology.js";
|
|
9
|
+
|
|
10
|
+
const FLAG_CULLED = 1 << 0;
|
|
11
|
+
const FLAG_SIDE_EFFECTS = 1 << 1;
|
|
12
|
+
const FLAG_TRANSIENT = 1 << 2;
|
|
13
|
+
const FLAG_IMPORTED = 1 << 3;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* `-1` means "none" throughout the topology — no scope, no producer. Shifting by one lets those
|
|
17
|
+
* ride in a `uintVar`, which has no negative encoding.
|
|
18
|
+
*
|
|
19
|
+
* @param {BinaryBuffer} buffer
|
|
20
|
+
* @param {number} value
|
|
21
|
+
*/
|
|
22
|
+
function write_optional(buffer, value) {
|
|
23
|
+
buffer.writeUintVar(value + 1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @param {BinaryBuffer} buffer
|
|
28
|
+
* @returns {number}
|
|
29
|
+
*/
|
|
30
|
+
function read_optional(buffer) {
|
|
31
|
+
return buffer.readUintVar() - 1;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @param {BinaryBuffer} buffer
|
|
36
|
+
* @param {number[]} ids
|
|
37
|
+
*/
|
|
38
|
+
function write_ids(buffer, ids) {
|
|
39
|
+
buffer.writeUintVar(ids.length);
|
|
40
|
+
|
|
41
|
+
for (const id of ids) {
|
|
42
|
+
buffer.writeUintVar(id);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @param {BinaryBuffer} buffer
|
|
48
|
+
* @returns {number[]}
|
|
49
|
+
*/
|
|
50
|
+
function read_ids(buffer) {
|
|
51
|
+
const count = buffer.readUintVar();
|
|
52
|
+
|
|
53
|
+
const ids = [];
|
|
54
|
+
|
|
55
|
+
for (let i = 0; i < count; i++) {
|
|
56
|
+
ids.push(buffer.readUintVar());
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return ids;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Encode a `TOPO` payload.
|
|
64
|
+
*
|
|
65
|
+
* @param {BinaryBuffer} buffer
|
|
66
|
+
* @param {GPUProfileTopology} topology
|
|
67
|
+
* @param {function(string): number} intern
|
|
68
|
+
* @returns {void}
|
|
69
|
+
*
|
|
70
|
+
* @author Alex Goldring
|
|
71
|
+
* @copyright Company Named Limited (c) 2026
|
|
72
|
+
*/
|
|
73
|
+
export function sgpt_write_topology(buffer, topology, intern) {
|
|
74
|
+
assert.defined(buffer, 'buffer');
|
|
75
|
+
assert.defined(topology, 'topology');
|
|
76
|
+
assert.isFunction(intern, 'intern');
|
|
77
|
+
|
|
78
|
+
buffer.writeUintVar(topology.id);
|
|
79
|
+
buffer.writeUintVar(intern(topology.name));
|
|
80
|
+
|
|
81
|
+
buffer.writeUintVar(topology.scopes.length);
|
|
82
|
+
|
|
83
|
+
for (const scope of topology.scopes) {
|
|
84
|
+
buffer.writeUintVar(intern(scope.name));
|
|
85
|
+
write_optional(buffer, scope.parent);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
buffer.writeUintVar(topology.passes.length);
|
|
89
|
+
|
|
90
|
+
for (const pass of topology.passes) {
|
|
91
|
+
buffer.writeUintVar(pass.id);
|
|
92
|
+
buffer.writeUintVar(intern(pass.name));
|
|
93
|
+
write_optional(buffer, pass.scope);
|
|
94
|
+
|
|
95
|
+
let flags = 0;
|
|
96
|
+
|
|
97
|
+
if (pass.culled) {
|
|
98
|
+
flags |= FLAG_CULLED;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (pass.has_side_effects) {
|
|
102
|
+
flags |= FLAG_SIDE_EFFECTS;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
buffer.writeUint8(flags);
|
|
106
|
+
buffer.writeUintVar(pass.ref_count);
|
|
107
|
+
|
|
108
|
+
write_ids(buffer, pass.reads);
|
|
109
|
+
write_ids(buffer, pass.writes);
|
|
110
|
+
write_ids(buffer, pass.creates);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
buffer.writeUintVar(topology.resources.length);
|
|
114
|
+
|
|
115
|
+
for (const resource of topology.resources) {
|
|
116
|
+
buffer.writeUintVar(resource.id);
|
|
117
|
+
buffer.writeUintVar(intern(resource.name));
|
|
118
|
+
buffer.writeUintVar(resource.version);
|
|
119
|
+
|
|
120
|
+
let flags = 0;
|
|
121
|
+
|
|
122
|
+
if (resource.transient) {
|
|
123
|
+
flags |= FLAG_TRANSIENT;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (resource.imported) {
|
|
127
|
+
flags |= FLAG_IMPORTED;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
buffer.writeUint8(flags);
|
|
131
|
+
write_optional(buffer, resource.producer);
|
|
132
|
+
|
|
133
|
+
buffer.writeUint8(resource.kind);
|
|
134
|
+
buffer.writeUintVar(resource.usage);
|
|
135
|
+
buffer.writeUintVar(resource.byte_size);
|
|
136
|
+
|
|
137
|
+
if (resource.kind === GPUProfileResourceKind.BUFFER) {
|
|
138
|
+
buffer.writeUintVar(resource.size);
|
|
139
|
+
} else if (resource.kind === GPUProfileResourceKind.TEXTURE) {
|
|
140
|
+
buffer.writeUintVar(resource.resolution[0]);
|
|
141
|
+
buffer.writeUintVar(resource.resolution[1]);
|
|
142
|
+
buffer.writeUintVar(resource.resolution[2]);
|
|
143
|
+
buffer.writeUintVar(resource.mip_level_count);
|
|
144
|
+
buffer.writeUintVar(resource.sample_count);
|
|
145
|
+
buffer.writeUintVar(intern(resource.format));
|
|
146
|
+
buffer.writeUintVar(intern(resource.dimension));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Every string a topology will need interned, in the order {@link sgpt_write_topology} asks for
|
|
153
|
+
* them.
|
|
154
|
+
*
|
|
155
|
+
* Exists because symbols must be flushed into a `SYMS` record *before* the record referencing them
|
|
156
|
+
* — interning from inside the payload writer puts them in the next flush, behind the record that
|
|
157
|
+
* needs them, and a capture truncated in between resolves none of them.
|
|
158
|
+
*
|
|
159
|
+
* @param {GPUProfileTopology} topology
|
|
160
|
+
* @param {function(string): number} intern
|
|
161
|
+
* @returns {void}
|
|
162
|
+
*/
|
|
163
|
+
export function sgpt_intern_topology_symbols(topology, intern) {
|
|
164
|
+
intern(topology.name);
|
|
165
|
+
|
|
166
|
+
for (const scope of topology.scopes) {
|
|
167
|
+
intern(scope.name);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
for (const pass of topology.passes) {
|
|
171
|
+
intern(pass.name);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
for (const resource of topology.resources) {
|
|
175
|
+
intern(resource.name);
|
|
176
|
+
|
|
177
|
+
if (resource.kind === GPUProfileResourceKind.TEXTURE) {
|
|
178
|
+
intern(resource.format);
|
|
179
|
+
intern(resource.dimension);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Decode a `TOPO` payload.
|
|
186
|
+
*
|
|
187
|
+
* @param {BinaryBuffer} buffer positioned at the payload
|
|
188
|
+
* @param {string[]} symbols
|
|
189
|
+
* @returns {GPUProfileTopology}
|
|
190
|
+
*/
|
|
191
|
+
export function sgpt_read_topology(buffer, symbols) {
|
|
192
|
+
assert.defined(buffer, 'buffer');
|
|
193
|
+
assert.isArray(symbols, 'symbols');
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* @param {number} index
|
|
197
|
+
* @returns {string}
|
|
198
|
+
*/
|
|
199
|
+
const resolve = (index) => symbols[index] !== undefined
|
|
200
|
+
? symbols[index]
|
|
201
|
+
: `<unresolved symbol ${index}>`;
|
|
202
|
+
|
|
203
|
+
const topology = new GPUProfileTopology();
|
|
204
|
+
|
|
205
|
+
topology.id = buffer.readUintVar();
|
|
206
|
+
topology.name = resolve(buffer.readUintVar());
|
|
207
|
+
|
|
208
|
+
const scope_count = buffer.readUintVar();
|
|
209
|
+
|
|
210
|
+
for (let i = 0; i < scope_count; i++) {
|
|
211
|
+
const scope = new GPUProfileScope();
|
|
212
|
+
|
|
213
|
+
scope.name = resolve(buffer.readUintVar());
|
|
214
|
+
scope.parent = read_optional(buffer);
|
|
215
|
+
|
|
216
|
+
topology.scopes.push(scope);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const pass_count = buffer.readUintVar();
|
|
220
|
+
|
|
221
|
+
for (let i = 0; i < pass_count; i++) {
|
|
222
|
+
const pass = new GPUProfilePass();
|
|
223
|
+
|
|
224
|
+
pass.id = buffer.readUintVar();
|
|
225
|
+
pass.name = resolve(buffer.readUintVar());
|
|
226
|
+
pass.scope = read_optional(buffer);
|
|
227
|
+
|
|
228
|
+
const flags = buffer.readUint8();
|
|
229
|
+
|
|
230
|
+
pass.culled = (flags & FLAG_CULLED) !== 0;
|
|
231
|
+
pass.has_side_effects = (flags & FLAG_SIDE_EFFECTS) !== 0;
|
|
232
|
+
|
|
233
|
+
pass.ref_count = buffer.readUintVar();
|
|
234
|
+
|
|
235
|
+
pass.reads = read_ids(buffer);
|
|
236
|
+
pass.writes = read_ids(buffer);
|
|
237
|
+
pass.creates = read_ids(buffer);
|
|
238
|
+
|
|
239
|
+
topology.passes.push(pass);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const resource_count = buffer.readUintVar();
|
|
243
|
+
|
|
244
|
+
for (let i = 0; i < resource_count; i++) {
|
|
245
|
+
const resource = new GPUProfileResource();
|
|
246
|
+
|
|
247
|
+
resource.id = buffer.readUintVar();
|
|
248
|
+
resource.name = resolve(buffer.readUintVar());
|
|
249
|
+
resource.version = buffer.readUintVar();
|
|
250
|
+
|
|
251
|
+
const flags = buffer.readUint8();
|
|
252
|
+
|
|
253
|
+
resource.transient = (flags & FLAG_TRANSIENT) !== 0;
|
|
254
|
+
resource.imported = (flags & FLAG_IMPORTED) !== 0;
|
|
255
|
+
|
|
256
|
+
resource.producer = read_optional(buffer);
|
|
257
|
+
|
|
258
|
+
resource.kind = buffer.readUint8();
|
|
259
|
+
resource.usage = buffer.readUintVar();
|
|
260
|
+
resource.byte_size = buffer.readUintVar();
|
|
261
|
+
|
|
262
|
+
if (resource.kind === GPUProfileResourceKind.BUFFER) {
|
|
263
|
+
resource.size = buffer.readUintVar();
|
|
264
|
+
} else if (resource.kind === GPUProfileResourceKind.TEXTURE) {
|
|
265
|
+
resource.resolution = [
|
|
266
|
+
buffer.readUintVar(),
|
|
267
|
+
buffer.readUintVar(),
|
|
268
|
+
buffer.readUintVar()
|
|
269
|
+
];
|
|
270
|
+
resource.mip_level_count = buffer.readUintVar();
|
|
271
|
+
resource.sample_count = buffer.readUintVar();
|
|
272
|
+
resource.format = resolve(buffer.readUintVar());
|
|
273
|
+
resource.dimension = resolve(buffer.readUintVar());
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
topology.resources.push(resource);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
return topology;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* A content hash of everything that makes one topology different from another.
|
|
284
|
+
*
|
|
285
|
+
* This is what deduplication turns on. A Shade frame graph is nearly identical frame to frame, so
|
|
286
|
+
* the steady state hashes to one value for hundreds of frames and the structure is stored once —
|
|
287
|
+
* the difference between a capture of tens of megabytes and one of a couple.
|
|
288
|
+
*
|
|
289
|
+
* **Cull state is part of the hash.** A frame where a different set of passes was culled genuinely
|
|
290
|
+
* is a different shape, and folding the two together would report passes as having run in frames
|
|
291
|
+
* where they did not.
|
|
292
|
+
*
|
|
293
|
+
* FNV-1a over a canonical string. Not cryptographic and does not need to be: a collision costs a
|
|
294
|
+
* mislabelled structure in a debug tool, and the inputs are pass names and integers rather than
|
|
295
|
+
* anything adversarial.
|
|
296
|
+
*
|
|
297
|
+
* @param {GPUProfileTopology} topology
|
|
298
|
+
* @returns {number} unsigned 32-bit
|
|
299
|
+
*/
|
|
300
|
+
export function sgpt_topology_hash(topology) {
|
|
301
|
+
let hash = 2166136261;
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* @param {string} text
|
|
305
|
+
*/
|
|
306
|
+
function feed(text) {
|
|
307
|
+
for (let i = 0; i < text.length; i++) {
|
|
308
|
+
hash ^= text.charCodeAt(i);
|
|
309
|
+
hash = Math.imul(hash, 16777619);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
feed(topology.name);
|
|
314
|
+
|
|
315
|
+
for (const scope of topology.scopes) {
|
|
316
|
+
feed(`S${scope.name}|${scope.parent}`);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
for (const pass of topology.passes) {
|
|
320
|
+
feed(`P${pass.id}|${pass.name}|${pass.scope}|${pass.culled ? 1 : 0}|${pass.has_side_effects ? 1 : 0}`);
|
|
321
|
+
feed(`r${pass.reads.join(',')}w${pass.writes.join(',')}c${pass.creates.join(',')}`);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
for (const resource of topology.resources) {
|
|
325
|
+
feed(`R${resource.id}|${resource.name}|${resource.version}|${resource.kind}|${resource.byte_size}|${resource.usage}|${resource.producer}`);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return hash >>> 0;
|
|
329
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Write the fixed 32-byte header at the front of an `.sgpt` stream.
|
|
3
|
+
*
|
|
4
|
+
* Called once, when the session opens, with the directory fields left at zero — they are not known
|
|
5
|
+
* until the session stops, and a capture that never stops keeps them at zero permanently. That is a
|
|
6
|
+
* supported end state, not a damaged file: see {@link SGPT_HEADER_OFFSET.DIRECTORY_OFFSET}.
|
|
7
|
+
*
|
|
8
|
+
* The checksum covers bytes `[0, 12)` only, deliberately stopping short of the fields that get
|
|
9
|
+
* patched afterwards. A checksum over the whole header would have to be recomputed at stop, which
|
|
10
|
+
* means a capture cut short would carry one that fails — turning the recoverable case into an
|
|
11
|
+
* apparently corrupt file.
|
|
12
|
+
*
|
|
13
|
+
* Leaves `position` at {@link SGPT_HEADER_SIZE}, where the first record goes.
|
|
14
|
+
*
|
|
15
|
+
* @param {BinaryBuffer} buffer positioned at 0
|
|
16
|
+
* @returns {void}
|
|
17
|
+
*
|
|
18
|
+
* @author Alex Goldring
|
|
19
|
+
* @copyright Company Named Limited (c) 2026
|
|
20
|
+
*/
|
|
21
|
+
export function sgpt_write_header(buffer: BinaryBuffer): void;
|
|
22
|
+
//# sourceMappingURL=sgpt_write_header.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sgpt_write_header.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/device/timing/profile/sgpt_write_header.js"],"names":[],"mappings":"AASA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,yDALa,IAAI,CAsBhB"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { assert } from "../../../../core/assert.js";
|
|
2
|
+
import { crc32 } from "../../../../core/binary/hash/crc32.js";
|
|
3
|
+
import { SGPT_FORMAT_VERSION } from "./SGPT_FORMAT_VERSION.js";
|
|
4
|
+
import { SGPT_HEADER_CHECKSUM_COVERAGE } from "./SGPT_HEADER_CHECKSUM_COVERAGE.js";
|
|
5
|
+
import { SGPT_HEADER_OFFSET } from "./SGPT_HEADER_OFFSET.js";
|
|
6
|
+
import { SGPT_HEADER_SIZE } from "./SGPT_HEADER_SIZE.js";
|
|
7
|
+
import { SGPT_MAGIC } from "./SGPT_MAGIC.js";
|
|
8
|
+
import { SGPT_MIN_READER_VERSION } from "./SGPT_MIN_READER_VERSION.js";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Write the fixed 32-byte header at the front of an `.sgpt` stream.
|
|
12
|
+
*
|
|
13
|
+
* Called once, when the session opens, with the directory fields left at zero — they are not known
|
|
14
|
+
* until the session stops, and a capture that never stops keeps them at zero permanently. That is a
|
|
15
|
+
* supported end state, not a damaged file: see {@link SGPT_HEADER_OFFSET.DIRECTORY_OFFSET}.
|
|
16
|
+
*
|
|
17
|
+
* The checksum covers bytes `[0, 12)` only, deliberately stopping short of the fields that get
|
|
18
|
+
* patched afterwards. A checksum over the whole header would have to be recomputed at stop, which
|
|
19
|
+
* means a capture cut short would carry one that fails — turning the recoverable case into an
|
|
20
|
+
* apparently corrupt file.
|
|
21
|
+
*
|
|
22
|
+
* Leaves `position` at {@link SGPT_HEADER_SIZE}, where the first record goes.
|
|
23
|
+
*
|
|
24
|
+
* @param {BinaryBuffer} buffer positioned at 0
|
|
25
|
+
* @returns {void}
|
|
26
|
+
*
|
|
27
|
+
* @author Alex Goldring
|
|
28
|
+
* @copyright Company Named Limited (c) 2026
|
|
29
|
+
*/
|
|
30
|
+
export function sgpt_write_header(buffer) {
|
|
31
|
+
assert.defined(buffer, 'buffer');
|
|
32
|
+
assert.equal(buffer.position, 0, 'header must be written at offset 0');
|
|
33
|
+
|
|
34
|
+
buffer.writeUint32(SGPT_MAGIC);
|
|
35
|
+
buffer.writeUint16(SGPT_FORMAT_VERSION);
|
|
36
|
+
buffer.writeUint16(SGPT_MIN_READER_VERSION);
|
|
37
|
+
buffer.writeUint32(0); // flags; CLOSED is set at stop
|
|
38
|
+
|
|
39
|
+
const checksum = crc32(buffer.raw_bytes, 0, SGPT_HEADER_CHECKSUM_COVERAGE);
|
|
40
|
+
|
|
41
|
+
buffer.writeUint32(checksum);
|
|
42
|
+
|
|
43
|
+
buffer.writeUint64(0n); // directory_offset, patched at stop
|
|
44
|
+
buffer.writeUint64(0n); // directory_byte_length, patched at stop
|
|
45
|
+
|
|
46
|
+
assert.equal(buffer.position, SGPT_HEADER_SIZE, 'header size mismatch');
|
|
47
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Append one framed record, encoding its payload through `write_payload`.
|
|
3
|
+
*
|
|
4
|
+
* The payload is written first, into the same buffer, and the framing is filled in behind it once
|
|
5
|
+
* its length and checksum are known. That ordering is what keeps a record a single pass: the
|
|
6
|
+
* alternative — encode to a scratch buffer, measure, copy — costs an allocation and a copy per
|
|
7
|
+
* frame, every frame, for nothing.
|
|
8
|
+
*
|
|
9
|
+
* A record is complete or it is absent. If `write_payload` throws, `position` is restored to where
|
|
10
|
+
* the record would have begun, so a failed encode leaves no half-record for a reader to trip over.
|
|
11
|
+
*
|
|
12
|
+
* @template T
|
|
13
|
+
* @param {BinaryBuffer} buffer positioned where the record should start
|
|
14
|
+
* @param {number} type one of {@link SGPT_RECORD_TYPE}
|
|
15
|
+
* @param {T} data handed to `write_payload`
|
|
16
|
+
* @param {function(BinaryBuffer, T): void} write_payload
|
|
17
|
+
* @returns {number} bytes written, framing included
|
|
18
|
+
*
|
|
19
|
+
* @author Alex Goldring
|
|
20
|
+
* @copyright Company Named Limited (c) 2026
|
|
21
|
+
*/
|
|
22
|
+
export function sgpt_write_record<T>(buffer: BinaryBuffer, type: number, data: T, write_payload: (arg0: BinaryBuffer, arg1: T) => void): number;
|
|
23
|
+
//# sourceMappingURL=sgpt_write_record.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sgpt_write_record.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/device/timing/profile/sgpt_write_record.js"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,iEARW,MAAM,2DAEqB,IAAI,GAC7B,MAAM,CAwClB"}
|