Skip to main content

ass_renderer/debug/
info.rs

1//! Debug information data structures for rendered frames.
2//!
3//! Holds the per-frame debug metadata produced by [`DebugRenderer`](crate::debug::DebugRenderer)
4//! together with the result of comparing two captured frames, plus their
5//! optional `serde` serialization implementations.
6
7#[cfg(feature = "nostd")]
8extern crate alloc;
9#[cfg(feature = "nostd")]
10use alloc::{format, string::String, vec::Vec};
11
12/// Debug information for a rendered frame
13#[derive(Debug, Clone)]
14pub struct FrameDebugInfo {
15    /// Frame timestamp in milliseconds
16    pub timestamp_ms: u32,
17    /// Number of active subtitle events
18    pub active_events: usize,
19    /// Dirty regions that need re-rendering
20    pub dirty_regions: Vec<DirtyRegionInfo>,
21    /// Time taken to render this frame in milliseconds
22    pub render_time_ms: f64,
23    /// Memory used by frame data in bytes
24    pub memory_usage_bytes: usize,
25    /// Number of cache hits during rendering
26    pub cache_hits: usize,
27    /// Number of cache misses during rendering
28    pub cache_misses: usize,
29    /// Name of the rendering backend used
30    pub backend_type: String,
31    /// Checksum of the frame data for comparison
32    pub frame_checksum: u64,
33    /// Number of non-transparent pixels
34    pub non_transparent_pixels: usize,
35    /// Bounding box of rendered content
36    pub bounding_box: Option<BoundingBoxInfo>,
37}
38
39/// Information about a dirty region that needs re-rendering
40#[derive(Debug, Clone)]
41pub struct DirtyRegionInfo {
42    /// X coordinate of the region
43    pub x: u32,
44    /// Y coordinate of the region
45    pub y: u32,
46    /// Width of the region
47    pub width: u32,
48    /// Height of the region
49    pub height: u32,
50    /// Reason why this region is dirty
51    pub reason: String,
52}
53
54/// Bounding box information for rendered content
55#[derive(Debug, Clone, PartialEq)]
56pub struct BoundingBoxInfo {
57    /// Minimum X coordinate
58    pub min_x: u32,
59    /// Minimum Y coordinate
60    pub min_y: u32,
61    /// Maximum X coordinate
62    pub max_x: u32,
63    /// Maximum Y coordinate
64    pub max_y: u32,
65}
66
67/// Result of comparing two frames
68#[derive(Debug)]
69pub struct FrameComparison {
70    /// Whether the frame checksums match
71    pub checksum_match: bool,
72    /// Difference in non-transparent pixel count
73    pub pixel_diff: u32,
74    /// Difference in render time (milliseconds)
75    pub render_time_diff: f64,
76    /// Whether the bounding boxes differ
77    pub bbox_changed: bool,
78}
79
80// Make FrameDebugInfo serializable
81#[cfg(feature = "serde")]
82impl serde::Serialize for FrameDebugInfo {
83    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
84    where
85        S: serde::Serializer,
86    {
87        use serde::ser::SerializeStruct;
88
89        let mut state = serializer.serialize_struct("FrameDebugInfo", 11)?;
90        state.serialize_field("timestamp_ms", &self.timestamp_ms)?;
91        state.serialize_field("active_events", &self.active_events)?;
92        state.serialize_field("dirty_regions", &self.dirty_regions)?;
93        state.serialize_field("render_time_ms", &self.render_time_ms)?;
94        state.serialize_field("memory_usage_bytes", &self.memory_usage_bytes)?;
95        state.serialize_field("cache_hits", &self.cache_hits)?;
96        state.serialize_field("cache_misses", &self.cache_misses)?;
97        state.serialize_field("backend_type", &self.backend_type)?;
98        state.serialize_field("frame_checksum", &format!("0x{:016x}", self.frame_checksum))?;
99        state.serialize_field("non_transparent_pixels", &self.non_transparent_pixels)?;
100        state.serialize_field("bounding_box", &self.bounding_box)?;
101        state.end()
102    }
103}
104
105#[cfg(feature = "serde")]
106impl serde::Serialize for DirtyRegionInfo {
107    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
108    where
109        S: serde::Serializer,
110    {
111        use serde::ser::SerializeStruct;
112
113        let mut state = serializer.serialize_struct("DirtyRegionInfo", 5)?;
114        state.serialize_field("x", &self.x)?;
115        state.serialize_field("y", &self.y)?;
116        state.serialize_field("width", &self.width)?;
117        state.serialize_field("height", &self.height)?;
118        state.serialize_field("reason", &self.reason)?;
119        state.end()
120    }
121}
122
123#[cfg(feature = "serde")]
124impl serde::Serialize for BoundingBoxInfo {
125    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
126    where
127        S: serde::Serializer,
128    {
129        use serde::ser::SerializeStruct;
130
131        let mut state = serializer.serialize_struct("BoundingBoxInfo", 4)?;
132        state.serialize_field("min_x", &self.min_x)?;
133        state.serialize_field("min_y", &self.min_y)?;
134        state.serialize_field("max_x", &self.max_x)?;
135        state.serialize_field("max_y", &self.max_y)?;
136        state.end()
137    }
138}