@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,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How a resource's descriptor was recorded. `NONE` covers an imported resource whose descriptor the
|
|
3
|
+
* graph never saw, which is normal rather than a defect.
|
|
4
|
+
*/
|
|
5
|
+
export type GPUProfileResourceKind = number;
|
|
6
|
+
export namespace GPUProfileResourceKind {
|
|
7
|
+
let NONE: number;
|
|
8
|
+
let BUFFER: number;
|
|
9
|
+
let TEXTURE: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* One frame graph pass, as recorded.
|
|
13
|
+
*
|
|
14
|
+
* @author Alex Goldring
|
|
15
|
+
* @copyright Company Named Limited (c) 2026
|
|
16
|
+
*/
|
|
17
|
+
export class GPUProfilePass {
|
|
18
|
+
/** @type {number} */
|
|
19
|
+
id: number;
|
|
20
|
+
/** @type {string} */
|
|
21
|
+
name: string;
|
|
22
|
+
/**
|
|
23
|
+
* Index into {@link GPUProfileTopology#scopes}, or -1 when recorded at the top level.
|
|
24
|
+
* @type {number}
|
|
25
|
+
*/
|
|
26
|
+
scope: number;
|
|
27
|
+
/**
|
|
28
|
+
* Whether the graph culled this pass. A culled pass is still worth carrying: "why did this run"
|
|
29
|
+
* and "why did this *not* run" are the same question asked from either side.
|
|
30
|
+
* @type {boolean}
|
|
31
|
+
*/
|
|
32
|
+
culled: boolean;
|
|
33
|
+
/** @type {boolean} */
|
|
34
|
+
has_side_effects: boolean;
|
|
35
|
+
/** @type {number} */
|
|
36
|
+
ref_count: number;
|
|
37
|
+
/** @type {number[]} resource node ids */
|
|
38
|
+
reads: number[];
|
|
39
|
+
/** @type {number[]} resource node ids */
|
|
40
|
+
writes: number[];
|
|
41
|
+
/** @type {number[]} resource node ids */
|
|
42
|
+
creates: number[];
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* A named recording region. Scopes nest, and the nesting is the parent chain — this is the
|
|
46
|
+
* hierarchy a flame graph needs, and the graph already has it.
|
|
47
|
+
*
|
|
48
|
+
* @author Alex Goldring
|
|
49
|
+
* @copyright Company Named Limited (c) 2026
|
|
50
|
+
*/
|
|
51
|
+
export class GPUProfileScope {
|
|
52
|
+
/** @type {string} */
|
|
53
|
+
name: string;
|
|
54
|
+
/**
|
|
55
|
+
* Index into {@link GPUProfileTopology#scopes}, or -1 for a top-level scope.
|
|
56
|
+
* @type {number}
|
|
57
|
+
*/
|
|
58
|
+
parent: number;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* One resource **node** — that is, one version of one resource.
|
|
62
|
+
*
|
|
63
|
+
* Keyed by node rather than by registry entry, matching `FrameGraph.exportToJson`. A pass records
|
|
64
|
+
* the node it read or wrote, not the underlying resource, so a registry-keyed model leaves every
|
|
65
|
+
* reference past version 0 dangling.
|
|
66
|
+
*
|
|
67
|
+
* @author Alex Goldring
|
|
68
|
+
* @copyright Company Named Limited (c) 2026
|
|
69
|
+
*/
|
|
70
|
+
export class GPUProfileResource {
|
|
71
|
+
/** @type {number} */
|
|
72
|
+
id: number;
|
|
73
|
+
/** @type {string} */
|
|
74
|
+
name: string;
|
|
75
|
+
/** @type {number} */
|
|
76
|
+
version: number;
|
|
77
|
+
/** @type {boolean} */
|
|
78
|
+
transient: boolean;
|
|
79
|
+
/** @type {boolean} */
|
|
80
|
+
imported: boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Id of the pass that produced this version, or -1 — an imported resource as it stood on
|
|
83
|
+
* import, or one created outside any pass.
|
|
84
|
+
* @type {number}
|
|
85
|
+
*/
|
|
86
|
+
producer: number;
|
|
87
|
+
/** @type {number} one of {@link GPUProfileResourceKind} */
|
|
88
|
+
kind: number;
|
|
89
|
+
/** Bytes. Buffers only. @type {number} */
|
|
90
|
+
size: number;
|
|
91
|
+
/** `GPUBufferUsage` / `GPUTextureUsage` bitmask. @type {number} */
|
|
92
|
+
usage: number;
|
|
93
|
+
/** Texels. Textures only. @type {number[]} */
|
|
94
|
+
resolution: number[];
|
|
95
|
+
/** @type {number} */
|
|
96
|
+
mip_level_count: number;
|
|
97
|
+
/** @type {number} */
|
|
98
|
+
sample_count: number;
|
|
99
|
+
/** @type {string} */
|
|
100
|
+
format: string;
|
|
101
|
+
/** @type {string} */
|
|
102
|
+
dimension: string;
|
|
103
|
+
/**
|
|
104
|
+
* Declared bytes, computed when the capture was recorded.
|
|
105
|
+
*
|
|
106
|
+
* Computed there rather than here because working a texture's footprint out needs its format's
|
|
107
|
+
* block dimensions, and those live in the engine's format table. Carrying the number instead of
|
|
108
|
+
* the inputs means a reader never has to keep a copy of that table in step with the engine's —
|
|
109
|
+
* and a format the reader has never heard of still reports a size.
|
|
110
|
+
*
|
|
111
|
+
* Declared, not allocated: a pooled allocator may serve a larger block, and an aliasing one may
|
|
112
|
+
* serve the same block to two resources whose lifetimes do not overlap.
|
|
113
|
+
*
|
|
114
|
+
* @type {number}
|
|
115
|
+
*/
|
|
116
|
+
byte_size: number;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* The shape of one frame: its passes, its resources, and how they depend on each other.
|
|
120
|
+
*
|
|
121
|
+
* **Stored once and referenced by many frames.** A Shade frame graph is nearly identical frame to
|
|
122
|
+
* frame — the same passes over the same resources — and what varies is the timings and the cull
|
|
123
|
+
* decisions. Recording the whole structure per frame is the difference between a capture of tens
|
|
124
|
+
* of megabytes and one of a couple, so topologies are content-hashed and deduplicated, and a frame
|
|
125
|
+
* stores an id.
|
|
126
|
+
*
|
|
127
|
+
* Cull state is the exception and lives here anyway: it varies with the frame, but it varies
|
|
128
|
+
* *with the topology* — a frame in which a different set of passes was culled is a different
|
|
129
|
+
* shape, and gets its own entry.
|
|
130
|
+
*
|
|
131
|
+
* @author Alex Goldring
|
|
132
|
+
* @copyright Company Named Limited (c) 2026
|
|
133
|
+
*/
|
|
134
|
+
export class GPUProfileTopology {
|
|
135
|
+
/**
|
|
136
|
+
* Position in the capture's topology list. What a frame refers to.
|
|
137
|
+
* @type {number}
|
|
138
|
+
*/
|
|
139
|
+
id: number;
|
|
140
|
+
/** @type {string} */
|
|
141
|
+
name: string;
|
|
142
|
+
/** @type {GPUProfilePass[]} */
|
|
143
|
+
passes: GPUProfilePass[];
|
|
144
|
+
/** @type {GPUProfileScope[]} */
|
|
145
|
+
scopes: GPUProfileScope[];
|
|
146
|
+
/** @type {GPUProfileResource[]} */
|
|
147
|
+
resources: GPUProfileResource[];
|
|
148
|
+
/**
|
|
149
|
+
* Declared bytes across every transient resource, as the graph asked for them.
|
|
150
|
+
*
|
|
151
|
+
* Declared, not allocated: a pooled allocator may hand back a larger block, and an aliased one
|
|
152
|
+
* may hand the same block to two resources whose lifetimes do not overlap. The gap between
|
|
153
|
+
* this and the device's real figure is the aliasing, which is the interesting number.
|
|
154
|
+
*
|
|
155
|
+
* @returns {number}
|
|
156
|
+
*/
|
|
157
|
+
get declared_transient_bytes(): number;
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=GPUProfileTopology.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GPUProfileTopology.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/device/timing/profile/GPUProfileTopology.js"],"names":[],"mappings":";;;;qCAIU,MAAM;;;;;;AAQhB;;;;;GAKG;AACH;IACI,qBAAqB;IACrB,IADW,MAAM,CACV;IAEP,qBAAqB;IACrB,MADW,MAAM,CACP;IAEV;;;OAGG;IACH,OAFU,MAAM,CAEL;IAEX;;;;OAIG;IACH,QAFU,OAAO,CAEF;IAEf,sBAAsB;IACtB,kBADW,OAAO,CACO;IAEzB,qBAAqB;IACrB,WADW,MAAM,CACH;IAEd,yCAAyC;IACzC,OADW,MAAM,EAAE,CACR;IAEX,yCAAyC;IACzC,QADW,MAAM,EAAE,CACP;IAEZ,yCAAyC;IACzC,SADW,MAAM,EAAE,CACN;CAChB;AAED;;;;;;GAMG;AACH;IACI,qBAAqB;IACrB,MADW,MAAM,CACP;IAEV;;;OAGG;IACH,QAFU,MAAM,CAEJ;CACf;AAED;;;;;;;;;GASG;AACH;IACI,qBAAqB;IACrB,IADW,MAAM,CACV;IAEP,qBAAqB;IACrB,MADW,MAAM,CACP;IAEV,qBAAqB;IACrB,SADW,MAAM,CACL;IAEZ,sBAAsB;IACtB,WADW,OAAO,CACA;IAElB,sBAAsB;IACtB,UADW,OAAO,CACD;IAEjB;;;;OAIG;IACH,UAFU,MAAM,CAEF;IAEd,2DAA2D;IAC3D,MADW,MAAM,CACkB;IAEnC,0CAA0C;IAC1C,MADgC,MAAM,CAC7B;IAET,mEAAmE;IACnE,OADyD,MAAM,CACrD;IAEV,8CAA8C;IAC9C,YADkC,MAAM,EAAE,CACnB;IAEvB,qBAAqB;IACrB,iBADW,MAAM,CACG;IAEpB,qBAAqB;IACrB,cADW,MAAM,CACA;IAEjB,qBAAqB;IACrB,QADW,MAAM,CACL;IAEZ,qBAAqB;IACrB,WADW,MAAM,CACF;IAEf;;;;;;;;;;;;OAYG;IACH,WAFU,MAAM,CAEF;CACjB;AAED;;;;;;;;;;;;;;;GAeG;AACH;IACI;;;OAGG;IACH,IAFU,MAAM,CAET;IAEP,qBAAqB;IACrB,MADW,MAAM,CACP;IAEV,+BAA+B;IAC/B,QADW,cAAc,EAAE,CACf;IAEZ,gCAAgC;IAChC,QADW,eAAe,EAAE,CAChB;IAEZ,mCAAmC;IACnC,WADW,kBAAkB,EAAE,CAChB;IAEf;;;;;;;;OAQG;IACH,uCAUC;CACJ"}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How a resource's descriptor was recorded. `NONE` covers an imported resource whose descriptor the
|
|
3
|
+
* graph never saw, which is normal rather than a defect.
|
|
4
|
+
*
|
|
5
|
+
* @enum {number}
|
|
6
|
+
*/
|
|
7
|
+
export const GPUProfileResourceKind = {
|
|
8
|
+
NONE: 0,
|
|
9
|
+
BUFFER: 1,
|
|
10
|
+
TEXTURE: 2
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* One frame graph pass, as recorded.
|
|
15
|
+
*
|
|
16
|
+
* @author Alex Goldring
|
|
17
|
+
* @copyright Company Named Limited (c) 2026
|
|
18
|
+
*/
|
|
19
|
+
export class GPUProfilePass {
|
|
20
|
+
/** @type {number} */
|
|
21
|
+
id = 0;
|
|
22
|
+
|
|
23
|
+
/** @type {string} */
|
|
24
|
+
name = "";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Index into {@link GPUProfileTopology#scopes}, or -1 when recorded at the top level.
|
|
28
|
+
* @type {number}
|
|
29
|
+
*/
|
|
30
|
+
scope = -1;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Whether the graph culled this pass. A culled pass is still worth carrying: "why did this run"
|
|
34
|
+
* and "why did this *not* run" are the same question asked from either side.
|
|
35
|
+
* @type {boolean}
|
|
36
|
+
*/
|
|
37
|
+
culled = false;
|
|
38
|
+
|
|
39
|
+
/** @type {boolean} */
|
|
40
|
+
has_side_effects = false;
|
|
41
|
+
|
|
42
|
+
/** @type {number} */
|
|
43
|
+
ref_count = 0;
|
|
44
|
+
|
|
45
|
+
/** @type {number[]} resource node ids */
|
|
46
|
+
reads = [];
|
|
47
|
+
|
|
48
|
+
/** @type {number[]} resource node ids */
|
|
49
|
+
writes = [];
|
|
50
|
+
|
|
51
|
+
/** @type {number[]} resource node ids */
|
|
52
|
+
creates = [];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* A named recording region. Scopes nest, and the nesting is the parent chain — this is the
|
|
57
|
+
* hierarchy a flame graph needs, and the graph already has it.
|
|
58
|
+
*
|
|
59
|
+
* @author Alex Goldring
|
|
60
|
+
* @copyright Company Named Limited (c) 2026
|
|
61
|
+
*/
|
|
62
|
+
export class GPUProfileScope {
|
|
63
|
+
/** @type {string} */
|
|
64
|
+
name = "";
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Index into {@link GPUProfileTopology#scopes}, or -1 for a top-level scope.
|
|
68
|
+
* @type {number}
|
|
69
|
+
*/
|
|
70
|
+
parent = -1;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* One resource **node** — that is, one version of one resource.
|
|
75
|
+
*
|
|
76
|
+
* Keyed by node rather than by registry entry, matching `FrameGraph.exportToJson`. A pass records
|
|
77
|
+
* the node it read or wrote, not the underlying resource, so a registry-keyed model leaves every
|
|
78
|
+
* reference past version 0 dangling.
|
|
79
|
+
*
|
|
80
|
+
* @author Alex Goldring
|
|
81
|
+
* @copyright Company Named Limited (c) 2026
|
|
82
|
+
*/
|
|
83
|
+
export class GPUProfileResource {
|
|
84
|
+
/** @type {number} */
|
|
85
|
+
id = 0;
|
|
86
|
+
|
|
87
|
+
/** @type {string} */
|
|
88
|
+
name = "";
|
|
89
|
+
|
|
90
|
+
/** @type {number} */
|
|
91
|
+
version = 0;
|
|
92
|
+
|
|
93
|
+
/** @type {boolean} */
|
|
94
|
+
transient = false;
|
|
95
|
+
|
|
96
|
+
/** @type {boolean} */
|
|
97
|
+
imported = false;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Id of the pass that produced this version, or -1 — an imported resource as it stood on
|
|
101
|
+
* import, or one created outside any pass.
|
|
102
|
+
* @type {number}
|
|
103
|
+
*/
|
|
104
|
+
producer = -1;
|
|
105
|
+
|
|
106
|
+
/** @type {number} one of {@link GPUProfileResourceKind} */
|
|
107
|
+
kind = GPUProfileResourceKind.NONE;
|
|
108
|
+
|
|
109
|
+
/** Bytes. Buffers only. @type {number} */
|
|
110
|
+
size = 0;
|
|
111
|
+
|
|
112
|
+
/** `GPUBufferUsage` / `GPUTextureUsage` bitmask. @type {number} */
|
|
113
|
+
usage = 0;
|
|
114
|
+
|
|
115
|
+
/** Texels. Textures only. @type {number[]} */
|
|
116
|
+
resolution = [0, 0, 0];
|
|
117
|
+
|
|
118
|
+
/** @type {number} */
|
|
119
|
+
mip_level_count = 1;
|
|
120
|
+
|
|
121
|
+
/** @type {number} */
|
|
122
|
+
sample_count = 1;
|
|
123
|
+
|
|
124
|
+
/** @type {string} */
|
|
125
|
+
format = "";
|
|
126
|
+
|
|
127
|
+
/** @type {string} */
|
|
128
|
+
dimension = "";
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Declared bytes, computed when the capture was recorded.
|
|
132
|
+
*
|
|
133
|
+
* Computed there rather than here because working a texture's footprint out needs its format's
|
|
134
|
+
* block dimensions, and those live in the engine's format table. Carrying the number instead of
|
|
135
|
+
* the inputs means a reader never has to keep a copy of that table in step with the engine's —
|
|
136
|
+
* and a format the reader has never heard of still reports a size.
|
|
137
|
+
*
|
|
138
|
+
* Declared, not allocated: a pooled allocator may serve a larger block, and an aliasing one may
|
|
139
|
+
* serve the same block to two resources whose lifetimes do not overlap.
|
|
140
|
+
*
|
|
141
|
+
* @type {number}
|
|
142
|
+
*/
|
|
143
|
+
byte_size = 0;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* The shape of one frame: its passes, its resources, and how they depend on each other.
|
|
148
|
+
*
|
|
149
|
+
* **Stored once and referenced by many frames.** A Shade frame graph is nearly identical frame to
|
|
150
|
+
* frame — the same passes over the same resources — and what varies is the timings and the cull
|
|
151
|
+
* decisions. Recording the whole structure per frame is the difference between a capture of tens
|
|
152
|
+
* of megabytes and one of a couple, so topologies are content-hashed and deduplicated, and a frame
|
|
153
|
+
* stores an id.
|
|
154
|
+
*
|
|
155
|
+
* Cull state is the exception and lives here anyway: it varies with the frame, but it varies
|
|
156
|
+
* *with the topology* — a frame in which a different set of passes was culled is a different
|
|
157
|
+
* shape, and gets its own entry.
|
|
158
|
+
*
|
|
159
|
+
* @author Alex Goldring
|
|
160
|
+
* @copyright Company Named Limited (c) 2026
|
|
161
|
+
*/
|
|
162
|
+
export class GPUProfileTopology {
|
|
163
|
+
/**
|
|
164
|
+
* Position in the capture's topology list. What a frame refers to.
|
|
165
|
+
* @type {number}
|
|
166
|
+
*/
|
|
167
|
+
id = 0;
|
|
168
|
+
|
|
169
|
+
/** @type {string} */
|
|
170
|
+
name = "";
|
|
171
|
+
|
|
172
|
+
/** @type {GPUProfilePass[]} */
|
|
173
|
+
passes = [];
|
|
174
|
+
|
|
175
|
+
/** @type {GPUProfileScope[]} */
|
|
176
|
+
scopes = [];
|
|
177
|
+
|
|
178
|
+
/** @type {GPUProfileResource[]} */
|
|
179
|
+
resources = [];
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Declared bytes across every transient resource, as the graph asked for them.
|
|
183
|
+
*
|
|
184
|
+
* Declared, not allocated: a pooled allocator may hand back a larger block, and an aliased one
|
|
185
|
+
* may hand the same block to two resources whose lifetimes do not overlap. The gap between
|
|
186
|
+
* this and the device's real figure is the aliasing, which is the interesting number.
|
|
187
|
+
*
|
|
188
|
+
* @returns {number}
|
|
189
|
+
*/
|
|
190
|
+
get declared_transient_bytes() {
|
|
191
|
+
let total = 0;
|
|
192
|
+
|
|
193
|
+
for (const resource of this.resources) {
|
|
194
|
+
if (resource.transient) {
|
|
195
|
+
total += resource.byte_size;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return total;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a GPU pass was asked to do, as opposed to how long it took.
|
|
3
|
+
*
|
|
4
|
+
* Aggregated per pass rather than per call. Most passes issue one dispatch, for which an aggregate
|
|
5
|
+
* *is* the value; the ones that issue many are the ones where a total is what you wanted anyway.
|
|
6
|
+
* Storing every call would multiply a frame record by the draw count, which is the wrong trade for
|
|
7
|
+
* a format meant to be left running.
|
|
8
|
+
*
|
|
9
|
+
* @author Alex Goldring
|
|
10
|
+
* @copyright Company Named Limited (c) 2026
|
|
11
|
+
*/
|
|
12
|
+
export class GPUProfileWork {
|
|
13
|
+
/**
|
|
14
|
+
* `dispatchWorkgroups` calls, direct only.
|
|
15
|
+
* @type {number}
|
|
16
|
+
*/
|
|
17
|
+
dispatch_count: number;
|
|
18
|
+
/**
|
|
19
|
+
* `dispatchWorkgroupsIndirect` calls.
|
|
20
|
+
*
|
|
21
|
+
* Counted separately because their sizes live in a GPU buffer and are simply not knowable at
|
|
22
|
+
* encode time. Folding them in would make {@link workgroups} read as a total when it is a
|
|
23
|
+
* partial one.
|
|
24
|
+
*
|
|
25
|
+
* @type {number}
|
|
26
|
+
*/
|
|
27
|
+
indirect_dispatch_count: number;
|
|
28
|
+
/**
|
|
29
|
+
* Workgroups summed across the direct dispatches, per axis.
|
|
30
|
+
* @type {number[]}
|
|
31
|
+
*/
|
|
32
|
+
workgroups: number[];
|
|
33
|
+
/**
|
|
34
|
+
* `draw` and `drawIndexed` calls.
|
|
35
|
+
* @type {number}
|
|
36
|
+
*/
|
|
37
|
+
draw_count: number;
|
|
38
|
+
/**
|
|
39
|
+
* `drawIndirect` and `drawIndexedIndirect` calls. Same caveat as
|
|
40
|
+
* {@link indirect_dispatch_count}.
|
|
41
|
+
* @type {number}
|
|
42
|
+
*/
|
|
43
|
+
indirect_draw_count: number;
|
|
44
|
+
/**
|
|
45
|
+
* Vertices summed across direct draws.
|
|
46
|
+
* @type {number}
|
|
47
|
+
*/
|
|
48
|
+
vertex_count: number;
|
|
49
|
+
/**
|
|
50
|
+
* Indices summed across direct indexed draws.
|
|
51
|
+
* @type {number}
|
|
52
|
+
*/
|
|
53
|
+
index_count: number;
|
|
54
|
+
/**
|
|
55
|
+
* Instances summed across direct draws.
|
|
56
|
+
* @type {number}
|
|
57
|
+
*/
|
|
58
|
+
instance_count: number;
|
|
59
|
+
/**
|
|
60
|
+
* Label of the pipeline this pass ran, where the pass was built through
|
|
61
|
+
* `constructComputePass` / `constructRenderPass` and one was therefore known.
|
|
62
|
+
* @type {string}
|
|
63
|
+
*/
|
|
64
|
+
pipeline: string;
|
|
65
|
+
/**
|
|
66
|
+
* `@workgroup_size` of the compute entry point, or `[0, 0, 0]` when it could not be read —
|
|
67
|
+
* an override-expression size, or a pass whose pipeline was never named.
|
|
68
|
+
* @type {number[]}
|
|
69
|
+
*/
|
|
70
|
+
workgroup_size: number[];
|
|
71
|
+
/**
|
|
72
|
+
* Shader invocations this pass asked for: workgroups × workgroup size.
|
|
73
|
+
*
|
|
74
|
+
* Zero when either is unknown, which is a different thing from zero work and is why
|
|
75
|
+
* {@link workgroup_size} is carried rather than assumed. The number worth looking at next to a
|
|
76
|
+
* duration — a dispatch that costs 2 ms over 300 invocations is a dispatch that is the wrong
|
|
77
|
+
* shape.
|
|
78
|
+
*
|
|
79
|
+
* @returns {number}
|
|
80
|
+
*/
|
|
81
|
+
get invocation_count(): number;
|
|
82
|
+
/**
|
|
83
|
+
* Whether anything was recorded at all. A pass with nothing here either did no work, or ran at
|
|
84
|
+
* a capture level below {@link GPUProfileLevel.WORKLOAD}.
|
|
85
|
+
*
|
|
86
|
+
* @returns {boolean}
|
|
87
|
+
*/
|
|
88
|
+
get is_empty(): boolean;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=GPUProfileWork.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GPUProfileWork.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/device/timing/profile/GPUProfileWork.js"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH;IACI;;;OAGG;IACH,gBAFU,MAAM,CAEG;IAEnB;;;;;;;;OAQG;IACH,yBAFU,MAAM,CAEY;IAE5B;;;OAGG;IACH,YAFU,MAAM,EAAE,CAEK;IAEvB;;;OAGG;IACH,YAFU,MAAM,CAED;IAEf;;;;OAIG;IACH,qBAFU,MAAM,CAEQ;IAExB;;;OAGG;IACH,cAFU,MAAM,CAEC;IAEjB;;;OAGG;IACH,aAFU,MAAM,CAEA;IAEhB;;;OAGG;IACH,gBAFU,MAAM,CAEG;IAEnB;;;;OAIG;IACH,UAFU,MAAM,CAEF;IAEd;;;;OAIG;IACH,gBAFU,MAAM,EAAE,CAES;IAE3B;;;;;;;;;OASG;IACH,+BASC;IAED;;;;;OAKG;IACH,wBAMC;CACJ"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a GPU pass was asked to do, as opposed to how long it took.
|
|
3
|
+
*
|
|
4
|
+
* Aggregated per pass rather than per call. Most passes issue one dispatch, for which an aggregate
|
|
5
|
+
* *is* the value; the ones that issue many are the ones where a total is what you wanted anyway.
|
|
6
|
+
* Storing every call would multiply a frame record by the draw count, which is the wrong trade for
|
|
7
|
+
* a format meant to be left running.
|
|
8
|
+
*
|
|
9
|
+
* @author Alex Goldring
|
|
10
|
+
* @copyright Company Named Limited (c) 2026
|
|
11
|
+
*/
|
|
12
|
+
export class GPUProfileWork {
|
|
13
|
+
/**
|
|
14
|
+
* `dispatchWorkgroups` calls, direct only.
|
|
15
|
+
* @type {number}
|
|
16
|
+
*/
|
|
17
|
+
dispatch_count = 0;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* `dispatchWorkgroupsIndirect` calls.
|
|
21
|
+
*
|
|
22
|
+
* Counted separately because their sizes live in a GPU buffer and are simply not knowable at
|
|
23
|
+
* encode time. Folding them in would make {@link workgroups} read as a total when it is a
|
|
24
|
+
* partial one.
|
|
25
|
+
*
|
|
26
|
+
* @type {number}
|
|
27
|
+
*/
|
|
28
|
+
indirect_dispatch_count = 0;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Workgroups summed across the direct dispatches, per axis.
|
|
32
|
+
* @type {number[]}
|
|
33
|
+
*/
|
|
34
|
+
workgroups = [0, 0, 0];
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* `draw` and `drawIndexed` calls.
|
|
38
|
+
* @type {number}
|
|
39
|
+
*/
|
|
40
|
+
draw_count = 0;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* `drawIndirect` and `drawIndexedIndirect` calls. Same caveat as
|
|
44
|
+
* {@link indirect_dispatch_count}.
|
|
45
|
+
* @type {number}
|
|
46
|
+
*/
|
|
47
|
+
indirect_draw_count = 0;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Vertices summed across direct draws.
|
|
51
|
+
* @type {number}
|
|
52
|
+
*/
|
|
53
|
+
vertex_count = 0;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Indices summed across direct indexed draws.
|
|
57
|
+
* @type {number}
|
|
58
|
+
*/
|
|
59
|
+
index_count = 0;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Instances summed across direct draws.
|
|
63
|
+
* @type {number}
|
|
64
|
+
*/
|
|
65
|
+
instance_count = 0;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Label of the pipeline this pass ran, where the pass was built through
|
|
69
|
+
* `constructComputePass` / `constructRenderPass` and one was therefore known.
|
|
70
|
+
* @type {string}
|
|
71
|
+
*/
|
|
72
|
+
pipeline = "";
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* `@workgroup_size` of the compute entry point, or `[0, 0, 0]` when it could not be read —
|
|
76
|
+
* an override-expression size, or a pass whose pipeline was never named.
|
|
77
|
+
* @type {number[]}
|
|
78
|
+
*/
|
|
79
|
+
workgroup_size = [0, 0, 0];
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Shader invocations this pass asked for: workgroups × workgroup size.
|
|
83
|
+
*
|
|
84
|
+
* Zero when either is unknown, which is a different thing from zero work and is why
|
|
85
|
+
* {@link workgroup_size} is carried rather than assumed. The number worth looking at next to a
|
|
86
|
+
* duration — a dispatch that costs 2 ms over 300 invocations is a dispatch that is the wrong
|
|
87
|
+
* shape.
|
|
88
|
+
*
|
|
89
|
+
* @returns {number}
|
|
90
|
+
*/
|
|
91
|
+
get invocation_count() {
|
|
92
|
+
const [wx, wy, wz] = this.workgroups;
|
|
93
|
+
const [sx, sy, sz] = this.workgroup_size;
|
|
94
|
+
|
|
95
|
+
if (sx === 0) {
|
|
96
|
+
return 0;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return wx * sx * Math.max(wy, 1) * Math.max(sy, 1) * Math.max(wz, 1) * Math.max(sz, 1);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Whether anything was recorded at all. A pass with nothing here either did no work, or ran at
|
|
104
|
+
* a capture level below {@link GPUProfileLevel.WORKLOAD}.
|
|
105
|
+
*
|
|
106
|
+
* @returns {boolean}
|
|
107
|
+
*/
|
|
108
|
+
get is_empty() {
|
|
109
|
+
return this.dispatch_count === 0
|
|
110
|
+
&& this.indirect_dispatch_count === 0
|
|
111
|
+
&& this.draw_count === 0
|
|
112
|
+
&& this.indirect_draw_count === 0
|
|
113
|
+
&& this.pipeline === "";
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {number} code one of {@link SGPT_DEFECT}
|
|
3
|
+
* @returns {string}
|
|
4
|
+
*/
|
|
5
|
+
export function sgpt_defect_name(code: number): string;
|
|
6
|
+
/**
|
|
7
|
+
* One thing wrong with an `.sgpt` stream.
|
|
8
|
+
*
|
|
9
|
+
* Collected rather than thrown. A capture of the moment a GPU fell over is a capture that ends
|
|
10
|
+
* mid-record, and a reader that refuses it outright discards the only evidence of what happened.
|
|
11
|
+
* The reader gathers defects, returns everything it could decode alongside them, and lets the
|
|
12
|
+
* inspector say plainly what it is showing and what it could not.
|
|
13
|
+
*
|
|
14
|
+
* @author Alex Goldring
|
|
15
|
+
* @copyright Company Named Limited (c) 2026
|
|
16
|
+
*/
|
|
17
|
+
export class SGPTDefect {
|
|
18
|
+
/**
|
|
19
|
+
* @param {number} code one of {@link SGPT_DEFECT}
|
|
20
|
+
* @param {string} detail
|
|
21
|
+
* @param {number} [offset]
|
|
22
|
+
*/
|
|
23
|
+
constructor(code: number, detail: string, offset?: number);
|
|
24
|
+
/**
|
|
25
|
+
* One of {@link SGPT_DEFECT}.
|
|
26
|
+
* @type {number}
|
|
27
|
+
*/
|
|
28
|
+
code: number;
|
|
29
|
+
/**
|
|
30
|
+
* @type {string}
|
|
31
|
+
*/
|
|
32
|
+
detail: string;
|
|
33
|
+
/**
|
|
34
|
+
* Byte offset in the stream where the problem was found, or -1 when it is not about one place.
|
|
35
|
+
* @type {number}
|
|
36
|
+
*/
|
|
37
|
+
offset: number;
|
|
38
|
+
/**
|
|
39
|
+
* @returns {string}
|
|
40
|
+
*/
|
|
41
|
+
toString(): string;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=SGPTDefect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SGPTDefect.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/device/timing/profile/SGPTDefect.js"],"names":[],"mappings":"AAoDA;;;GAGG;AACH,uCAHW,MAAM,GACJ,MAAM,CAUlB;AA9DD;;;;;;;;;;GAUG;AACH;IAkBI;;;;OAIG;IACH,kBAJW,MAAM,UACN,MAAM,WACN,MAAM,EAMhB;IA1BD;;;OAGG;IACH,MAFU,MAAM,CAEU;IAE1B;;OAEG;IACH,QAFU,MAAM,CAEJ;IAEZ;;;OAGG;IACH,QAFU,MAAM,CAEJ;IAaZ;;OAEG;IACH,YAFa,MAAM,CAMlB;CACJ"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { SGPT_DEFECT } from "./SGPT_DEFECT.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* One thing wrong with an `.sgpt` stream.
|
|
5
|
+
*
|
|
6
|
+
* Collected rather than thrown. A capture of the moment a GPU fell over is a capture that ends
|
|
7
|
+
* mid-record, and a reader that refuses it outright discards the only evidence of what happened.
|
|
8
|
+
* The reader gathers defects, returns everything it could decode alongside them, and lets the
|
|
9
|
+
* inspector say plainly what it is showing and what it could not.
|
|
10
|
+
*
|
|
11
|
+
* @author Alex Goldring
|
|
12
|
+
* @copyright Company Named Limited (c) 2026
|
|
13
|
+
*/
|
|
14
|
+
export class SGPTDefect {
|
|
15
|
+
/**
|
|
16
|
+
* One of {@link SGPT_DEFECT}.
|
|
17
|
+
* @type {number}
|
|
18
|
+
*/
|
|
19
|
+
code = SGPT_DEFECT.HEADER;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @type {string}
|
|
23
|
+
*/
|
|
24
|
+
detail = '';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Byte offset in the stream where the problem was found, or -1 when it is not about one place.
|
|
28
|
+
* @type {number}
|
|
29
|
+
*/
|
|
30
|
+
offset = -1;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @param {number} code one of {@link SGPT_DEFECT}
|
|
34
|
+
* @param {string} detail
|
|
35
|
+
* @param {number} [offset]
|
|
36
|
+
*/
|
|
37
|
+
constructor(code, detail, offset = -1) {
|
|
38
|
+
this.code = code;
|
|
39
|
+
this.detail = detail;
|
|
40
|
+
this.offset = offset;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @returns {string}
|
|
45
|
+
*/
|
|
46
|
+
toString() {
|
|
47
|
+
const where = this.offset >= 0 ? ` at byte ${this.offset}` : '';
|
|
48
|
+
|
|
49
|
+
return `${sgpt_defect_name(this.code)}${where}: ${this.detail}`;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @param {number} code one of {@link SGPT_DEFECT}
|
|
55
|
+
* @returns {string}
|
|
56
|
+
*/
|
|
57
|
+
export function sgpt_defect_name(code) {
|
|
58
|
+
for (const name in SGPT_DEFECT) {
|
|
59
|
+
if (SGPT_DEFECT[name] === code) {
|
|
60
|
+
return name;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return `UNKNOWN(${code})`;
|
|
65
|
+
}
|