1use std::collections::BTreeMap;
2
3use serde::{Deserialize, Serialize};
4
5#[allow(missing_docs)]
7#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
8#[serde(rename_all = "camelCase")]
9pub struct SnapshotVersion {
10 pub major: u32,
11 pub minor: u32,
12}
13
14#[allow(missing_docs)]
22#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
23#[serde(rename_all = "camelCase")]
24pub struct FrameGraphSnapshotV1 {
25 pub format: String,
26 pub version: SnapshotVersion,
27 pub producer: SnapshotProducer,
28 pub capture: SnapshotCapture,
29 pub graph: SnapshotGraph,
30 pub memory: SnapshotMemory,
31 pub timings: SnapshotTimings,
32 pub diagnostics: Vec<SnapshotDiagnostic>,
33 pub extensions: BTreeMap<String, serde_json::Value>,
34}
35
36#[allow(missing_docs)]
38#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
39#[serde(rename_all = "camelCase")]
40pub struct SnapshotProducer {
41 pub name: String,
42 #[serde(skip_serializing_if = "Option::is_none")]
43 pub version: Option<String>,
44 #[serde(skip_serializing_if = "Option::is_none")]
45 pub language: Option<String>,
46 #[serde(skip_serializing_if = "Option::is_none")]
47 pub runtime: Option<SnapshotRuntime>,
48}
49
50#[allow(missing_docs)]
52#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
53#[serde(rename_all = "camelCase")]
54pub struct SnapshotRuntime {
55 #[serde(skip_serializing_if = "Option::is_none")]
56 pub implementation: Option<String>,
57 #[serde(skip_serializing_if = "Option::is_none")]
58 pub graphics_api: Option<String>,
59 #[serde(skip_serializing_if = "Option::is_none")]
60 pub backend: Option<String>,
61}
62
63#[allow(missing_docs)]
65#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
66#[serde(rename_all = "camelCase")]
67pub struct SnapshotCapture {
68 pub frame_index: u64,
69 #[serde(skip_serializing_if = "Option::is_none")]
70 pub captured_at: Option<String>,
71 #[serde(skip_serializing_if = "Option::is_none")]
72 pub migration: Option<SnapshotMigration>,
73}
74
75#[allow(missing_docs)]
77#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
78#[serde(rename_all = "camelCase")]
79pub struct SnapshotMigration {
80 pub source_format: SnapshotMigrationSourceFormat,
81 pub unavailable_facts: Vec<SnapshotUnavailableFact>,
82}
83
84#[allow(missing_docs)]
86#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
87#[serde(rename_all = "kebab-case")]
88pub enum SnapshotMigrationSourceFormat {
89 #[serde(rename = "snapshot-v1.1")]
90 SnapshotV1_1,
91 LegacyV0,
92 LegacyCandidateV1,
93}
94
95#[allow(missing_docs)]
97#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
98pub enum SnapshotUnavailableFact {
99 #[serde(rename = "graph.groups")]
100 GraphGroups,
101 #[serde(rename = "graph.textureViews")]
102 GraphTextureViews,
103 #[serde(rename = "graph.nodes.recordingOrder")]
104 GraphNodeRecordingOrder,
105 #[serde(rename = "graph.accesses.regions")]
106 GraphAccessRegions,
107 #[serde(rename = "graph.roots.range")]
108 GraphRootRange,
109 #[serde(rename = "graph.roots.resolution")]
110 GraphRootResolution,
111}
112
113#[allow(missing_docs)]
115#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
116#[serde(rename_all = "camelCase")]
117pub struct SnapshotGraph {
118 pub groups: Vec<SnapshotGroup>,
119 pub nodes: Vec<SnapshotNode>,
120 pub resources: Vec<SnapshotResource>,
121 pub texture_views: Vec<SnapshotTextureView>,
122 pub accesses: Vec<SnapshotAccess>,
123 pub dependencies: Vec<SnapshotDependency>,
124 pub roots: Vec<SnapshotRoot>,
125 pub segments: Vec<SnapshotSegment>,
126}
127
128#[allow(missing_docs)]
130#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
131#[serde(rename_all = "camelCase")]
132pub struct SnapshotGroup {
133 pub id: String,
134 #[serde(skip_serializing_if = "Option::is_none")]
135 pub parent_id: Option<String>,
136 pub label: String,
137 #[serde(skip_serializing_if = "Option::is_none")]
138 pub stable_key: Option<String>,
139}
140
141#[allow(missing_docs)]
143#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
144#[serde(rename_all = "camelCase")]
145pub struct SnapshotNode {
146 pub id: String,
147 #[serde(skip_serializing_if = "Option::is_none")]
148 pub stable_key: Option<String>,
149 #[serde(skip_serializing_if = "Option::is_none")]
150 pub recording_order: Option<u64>,
151 pub kind: SnapshotNodeKind,
152 #[serde(skip_serializing_if = "Option::is_none")]
153 pub label: Option<String>,
154 pub side_effect: bool,
155 #[serde(skip_serializing_if = "Option::is_none")]
156 pub group_id: Option<String>,
157 pub compile_state: SnapshotNodeCompileState,
158}
159
160#[allow(missing_docs)]
162#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
163#[serde(rename_all = "kebab-case")]
164pub enum SnapshotNodeKind {
165 Render,
166 Compute,
167 Copy,
168 ClearBuffer,
169 Command,
170 ExternalSubmission,
171}
172
173#[allow(missing_docs)]
175#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
176#[serde(tag = "status", rename_all = "kebab-case")]
177pub enum SnapshotNodeCompileState {
178 Retained {
179 #[serde(rename = "executionOrder")]
180 execution_order: u64,
181 },
182 Culled {
183 reason: String,
184 },
185}
186
187#[allow(missing_docs)]
189#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
190#[serde(rename_all = "camelCase")]
191pub struct SnapshotResource {
192 pub id: String,
193 #[serde(skip_serializing_if = "Option::is_none")]
194 pub stable_key: Option<String>,
195 pub kind: SnapshotResourceKind,
196 #[serde(skip_serializing_if = "Option::is_none")]
197 pub label: Option<String>,
198 pub origin: SnapshotResourceOrigin,
199 #[serde(skip_serializing_if = "Option::is_none")]
200 pub initial_contents: Option<SnapshotInitialContents>,
201 #[serde(skip_serializing_if = "Option::is_none")]
202 pub group_id: Option<String>,
203 #[serde(skip_serializing_if = "Option::is_none")]
204 pub lifetime: Option<SnapshotLifetime>,
205 #[serde(skip_serializing_if = "Option::is_none")]
206 pub allocation_id: Option<String>,
207 #[serde(skip_serializing_if = "Option::is_none")]
208 pub estimated_byte_size: Option<u64>,
209 #[serde(skip_serializing_if = "Option::is_none")]
210 pub descriptor: Option<SnapshotResourceDescriptor>,
211 pub usage_flags: Vec<SnapshotUsageFlag>,
212}
213
214#[allow(missing_docs)]
216#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
217#[serde(rename_all = "kebab-case")]
218pub enum SnapshotResourceKind {
219 Texture,
220 Buffer,
221}
222
223#[allow(missing_docs)]
225#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
226#[serde(rename_all = "kebab-case")]
227pub enum SnapshotResourceOrigin {
228 Transient,
229 Imported,
230 Surface,
231}
232
233#[allow(missing_docs)]
235#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
236#[serde(rename_all = "kebab-case")]
237pub enum SnapshotInitialContents {
238 Defined,
239 Undefined,
240}
241
242#[allow(missing_docs)]
244#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
245#[serde(rename_all = "camelCase")]
246pub struct SnapshotLifetime {
247 pub first_use: u64,
248 pub last_use: u64,
249}
250
251#[allow(missing_docs)]
253#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
254#[serde(tag = "kind", rename_all = "kebab-case")]
255pub enum SnapshotResourceDescriptor {
256 Texture {
257 format: String,
258 size: SnapshotTextureSize,
259 dimension: String,
260 #[serde(rename = "mipLevelCount")]
261 mip_level_count: u64,
262 #[serde(rename = "sampleCount")]
263 sample_count: u64,
264 #[serde(rename = "viewFormats")]
265 view_formats: Vec<String>,
266 },
267 Buffer {
268 size: u64,
269 },
270}
271
272#[allow(missing_docs)]
274#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
275#[serde(rename_all = "camelCase")]
276pub struct SnapshotTextureSize {
277 pub width: u64,
278 pub height: u64,
279 pub depth_or_array_layers: u64,
280}
281
282#[allow(missing_docs)]
284#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
285#[serde(rename_all = "kebab-case")]
286pub enum SnapshotUsageFlag {
287 MapRead,
288 MapWrite,
289 CopySrc,
290 CopyDst,
291 Index,
292 Vertex,
293 Uniform,
294 Storage,
295 Indirect,
296 QueryResolve,
297 TextureBinding,
298 StorageBinding,
299 RenderAttachment,
300}
301
302#[allow(missing_docs)]
304#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
305#[serde(rename_all = "camelCase")]
306pub struct SnapshotTextureView {
307 pub id: String,
308 #[serde(skip_serializing_if = "Option::is_none")]
309 pub stable_key: Option<String>,
310 pub resource_id: String,
311 #[serde(skip_serializing_if = "Option::is_none")]
312 pub label: Option<String>,
313 pub format: String,
314 pub dimension: String,
315 pub aspect: String,
316 pub base_mip_level: u64,
317 pub mip_level_count: u64,
318 pub base_array_layer: u64,
319 pub array_layer_count: u64,
320 pub swizzle: String,
321}
322
323#[allow(missing_docs)]
325#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
326#[serde(rename_all = "camelCase")]
327pub struct SnapshotAccess {
328 pub id: String,
329 pub node_id: String,
330 pub resource_id: String,
331 pub access: SnapshotAccessKind,
332 #[serde(skip_serializing_if = "Option::is_none")]
333 pub texture_view_id: Option<String>,
334 #[serde(skip_serializing_if = "Option::is_none")]
335 pub texture_region: Option<SnapshotTextureRegion>,
336 #[serde(skip_serializing_if = "Option::is_none")]
337 pub buffer_range: Option<SnapshotBufferRange>,
338 pub mode: SnapshotAccessMode,
339 #[serde(skip_serializing_if = "Option::is_none")]
340 pub contents: Option<SnapshotWriteContents>,
341 pub produces_value: bool,
342}
343
344#[allow(missing_docs)]
346#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
347#[serde(rename_all = "kebab-case")]
348pub enum SnapshotAccessKind {
349 TextureSampled,
350 TextureStorageRead,
351 TextureStorageWrite,
352 TextureColorAttachmentWrite,
353 TextureDepthRead,
354 TextureDepthWrite,
355 TextureCopySrc,
356 TextureCopyDst,
357 BufferUniform,
358 BufferStorageRead,
359 BufferStorageWrite,
360 BufferVertex,
361 BufferIndex,
362 BufferIndirect,
363 BufferCopySrc,
364 BufferCopyDst,
365}
366
367#[allow(missing_docs)]
369#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
370#[serde(rename_all = "kebab-case")]
371pub enum SnapshotAccessMode {
372 Read,
373 Write,
374}
375
376#[allow(missing_docs)]
378#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
379#[serde(rename_all = "kebab-case")]
380pub enum SnapshotWriteContents {
381 Overwrite,
382 Preserve,
383}
384
385#[allow(missing_docs)]
387#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
388#[serde(rename_all = "camelCase")]
389pub struct SnapshotTextureRegion {
390 pub base_mip_level: u64,
391 pub mip_level_count: u64,
392 #[serde(skip_serializing_if = "Option::is_none")]
393 pub base_array_layer: Option<u64>,
394 #[serde(skip_serializing_if = "Option::is_none")]
395 pub array_layer_count: Option<u64>,
396 #[serde(skip_serializing_if = "Option::is_none")]
397 pub base_depth_slice: Option<u64>,
398 #[serde(skip_serializing_if = "Option::is_none")]
399 pub depth_slice_count: Option<u64>,
400 pub aspect: String,
401}
402
403#[allow(missing_docs)]
405#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
406#[serde(rename_all = "camelCase")]
407pub struct SnapshotBufferRange {
408 pub offset: u64,
409 #[serde(skip_serializing_if = "Option::is_none")]
410 pub size: Option<u64>,
411}
412
413#[allow(missing_docs)]
415#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
416#[serde(rename_all = "camelCase")]
417pub struct SnapshotDependency {
418 pub from_node_id: String,
419 pub to_node_id: String,
420 pub resource_id: String,
421 pub kind: SnapshotDependencyKind,
422}
423
424#[allow(missing_docs)]
426#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
427#[serde(rename_all = "kebab-case")]
428pub enum SnapshotDependencyKind {
429 Value,
430 Ordering,
431}
432
433#[allow(missing_docs)]
435#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
436#[serde(tag = "reason")]
437pub enum SnapshotRoot {
438 #[serde(rename = "present")]
439 Present(SnapshotResourceRoot),
440 #[serde(rename = "output")]
441 Output(SnapshotResourceRoot),
442 #[serde(rename = "readback")]
443 Readback(SnapshotResourceRoot),
444 #[serde(rename = "side-effect")]
445 SideEffect {
446 #[serde(rename = "nodeId")]
447 node_id: String,
448 },
449 #[serde(rename = "debug-capture")]
450 DebugCapture(SnapshotResourceRoot),
451 #[serde(rename = "persistent-state")]
452 PersistentState(SnapshotResourceRoot),
453}
454
455impl SnapshotRoot {
456 pub fn resource(&self) -> Option<&SnapshotResourceRoot> {
458 match self {
459 Self::SideEffect { .. } => None,
460 Self::Present(root)
461 | Self::Output(root)
462 | Self::Readback(root)
463 | Self::DebugCapture(root)
464 | Self::PersistentState(root) => Some(root),
465 }
466 }
467 pub fn node_id(&self) -> Option<&str> {
469 match self {
470 Self::SideEffect { node_id } => Some(node_id),
471 _ => None,
472 }
473 }
474 pub fn reason(&self) -> SnapshotRootReason {
476 match self {
477 Self::SideEffect { .. } => SnapshotRootReason::SideEffect,
478 Self::Present(_) => SnapshotRootReason::Present,
479 Self::Output(_) => SnapshotRootReason::Output,
480 Self::Readback(_) => SnapshotRootReason::Readback,
481 Self::DebugCapture(_) => SnapshotRootReason::DebugCapture,
482 Self::PersistentState(_) => SnapshotRootReason::PersistentState,
483 }
484 }
485}
486
487#[allow(missing_docs)]
489#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
490#[serde(rename_all = "camelCase")]
491pub struct SnapshotResourceRoot {
492 pub resource_id: String,
493 #[serde(skip_serializing_if = "Option::is_none")]
494 pub range: Option<SnapshotResourceRange>,
495 #[serde(skip_serializing_if = "Option::is_none")]
496 pub resolution: Option<SnapshotRootResolution>,
497}
498
499#[allow(missing_docs)]
501#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
502#[serde(tag = "kind", rename_all = "camelCase")]
503pub enum SnapshotResourceRange {
504 Buffer { offset: u64, size: u64 },
505 Texture { regions: Vec<SnapshotTextureRegion> },
506}
507
508#[allow(missing_docs)]
510#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
511#[serde(rename_all = "camelCase")]
512pub struct SnapshotRootResolution {
513 pub producer_node_ids: Vec<String>,
514 pub uses_initial_contents: bool,
515}
516
517#[allow(missing_docs)]
519#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
520#[serde(rename_all = "kebab-case")]
521pub enum SnapshotRootReason {
522 Present,
523 Output,
524 Readback,
525 SideEffect,
526 DebugCapture,
527 PersistentState,
528}
529
530#[derive(Clone, Copy, Debug, PartialEq, Eq)]
532pub enum SnapshotDecodeSource {
533 SnapshotV1_1,
535 V1,
537 LegacyV0,
539 LegacyCandidateV1,
541}
542
543#[derive(Clone, Debug, PartialEq)]
545pub struct SnapshotDecodeResult {
546 pub snapshot: FrameGraphSnapshotV1,
548 pub source: SnapshotDecodeSource,
550 pub migrated: bool,
552 pub issues: Vec<crate::SnapshotIssue>,
554}
555
556#[allow(missing_docs)]
558#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
559#[serde(rename_all = "camelCase")]
560pub struct SnapshotSegment {
561 pub id: String,
562 pub order: u64,
563 pub kind: SnapshotSegmentKind,
564 pub node_ids: Vec<String>,
565}
566
567#[allow(missing_docs)]
569#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
570#[serde(rename_all = "kebab-case")]
571pub enum SnapshotSegmentKind {
572 FrameGraph,
573 ExternalSubmission,
574}
575
576#[allow(missing_docs)]
578#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
579#[serde(rename_all = "camelCase")]
580pub struct SnapshotMemory {
581 pub allocation_report: SnapshotAllocationReport,
582 pub pool_report: SnapshotPoolReport,
583}
584
585#[allow(missing_docs)]
587#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
588#[serde(tag = "status", rename_all = "kebab-case")]
589pub enum SnapshotAllocationReport {
590 Available {
591 allocations: Vec<SnapshotAllocation>,
592 },
593 Unavailable {
594 reason: String,
595 },
596}
597
598#[allow(missing_docs)]
600#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
601#[serde(rename_all = "camelCase")]
602pub struct SnapshotAllocation {
603 pub id: String,
604 pub kind: SnapshotResourceKind,
605 pub compatibility_class_id: String,
606 #[serde(skip_serializing_if = "Option::is_none")]
607 pub estimated_byte_size: Option<u64>,
608}
609
610#[allow(missing_docs)]
612#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
613#[serde(tag = "status", rename_all = "kebab-case")]
614pub enum SnapshotPoolReport {
615 Available {
616 #[serde(rename = "acquireCount")]
617 acquire_count: u64,
618 #[serde(rename = "reuseCount")]
619 reuse_count: u64,
620 #[serde(rename = "createdCount")]
621 created_count: u64,
622 #[serde(rename = "retainedCount")]
623 retained_count: u64,
624 #[serde(
625 rename = "estimatedRetainedBytes",
626 skip_serializing_if = "Option::is_none"
627 )]
628 estimated_retained_bytes: Option<u64>,
629 },
630 Unavailable {
631 reason: String,
632 },
633}
634
635#[allow(missing_docs)]
637#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
638#[serde(rename_all = "camelCase")]
639pub struct SnapshotTimings {
640 pub cpu: SnapshotCpuTimings,
641 pub gpu: SnapshotGpuTimings,
642}
643
644#[allow(missing_docs)]
646#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
647#[serde(tag = "status", rename_all = "kebab-case")]
648pub enum SnapshotCpuTimings {
649 Available {
650 #[serde(rename = "executionDurationMicros")]
651 execution_duration_micros: f64,
652 nodes: Vec<SnapshotCpuNodeTiming>,
653 },
654 Unavailable {
655 reason: String,
656 },
657}
658
659#[allow(missing_docs)]
661#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
662#[serde(rename_all = "camelCase")]
663pub struct SnapshotCpuNodeTiming {
664 pub node_id: String,
665 pub duration_micros: f64,
666}
667
668#[allow(missing_docs)]
670#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
671#[serde(tag = "status", rename_all = "kebab-case")]
672pub enum SnapshotGpuTimings {
673 Available {
674 #[serde(rename = "frameSpanMicros")]
675 frame_span_micros: f64,
676 nodes: Vec<SnapshotGpuNodeTiming>,
677 },
678 Unavailable {
679 reason: String,
680 },
681}
682
683#[allow(missing_docs)]
685#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
686#[serde(rename_all = "camelCase")]
687pub struct SnapshotGpuNodeTiming {
688 pub node_id: String,
689 pub duration_micros: f64,
690}
691
692#[allow(missing_docs)]
694#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
695#[serde(rename_all = "camelCase")]
696pub struct SnapshotDiagnostic {
697 pub severity: SnapshotDiagnosticSeverity,
698 pub code: String,
699 pub message: String,
700 #[serde(skip_serializing_if = "Option::is_none")]
701 pub node_id: Option<String>,
702 #[serde(skip_serializing_if = "Option::is_none")]
703 pub resource_id: Option<String>,
704}
705
706#[allow(missing_docs)]
708#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
709#[serde(rename_all = "kebab-case")]
710pub enum SnapshotDiagnosticSeverity {
711 Info,
712 Warning,
713 Error,
714}