zng_wgt_webrender_debug/
lib.rs

1#![doc(html_favicon_url = "https://raw.githubusercontent.com/zng-ui/zng/main/examples/image/res/zng-logo-icon.png")]
2#![doc(html_logo_url = "https://raw.githubusercontent.com/zng-ui/zng/main/examples/image/res/zng-logo.png")]
3//!
4//! Webrender debug flags property for use with `zng-view` view-process.
5//!
6//! # Crate
7//!
8#![doc = include_str!(concat!("../", std::env!("CARGO_PKG_README")))]
9
10pub use webrender_api::DebugFlags;
11
12use zng_app::view_process::{VIEW_PROCESS, VIEW_PROCESS_INITED_EVENT};
13use zng_ext_window::WINDOWS;
14use zng_wgt::prelude::*;
15
16/// Sets the Webrender renderer debug flags and profiler UI for the current window.
17///
18/// Fails silently if the view-process does not implement the `"zng-view.webrender_debug"` extension.
19#[property(CONTEXT, default(RendererDebug::disabled()))]
20pub fn renderer_debug(child: impl UiNode, debug: impl IntoVar<RendererDebug>) -> impl UiNode {
21    let debug = debug.into_var();
22    let mut send = false;
23    match_node(child, move |_, op| match op {
24        UiNodeOp::Init => {
25            WIDGET.sub_var(&debug).sub_event(&VIEW_PROCESS_INITED_EVENT);
26            send = debug.with(|d| !d.is_empty());
27        }
28        UiNodeOp::Event { update } => {
29            if VIEW_PROCESS_INITED_EVENT.has(update) {
30                send = true;
31                WIDGET.layout();
32            }
33        }
34        UiNodeOp::Update { .. } => {
35            if debug.is_new() {
36                send = true;
37                WIDGET.layout();
38            }
39        }
40        UiNodeOp::Layout { .. } => {
41            if std::mem::take(&mut send) {
42                if let Some(ext_id) = VIEW_PROCESS.extension_id("zng-view.webrender_debug").ok().flatten() {
43                    debug.with(|d| match WINDOWS.view_render_extension(WINDOW.id(), ext_id, d) {
44                        Ok(()) => {}
45                        Err(e) => tracing::error!("{e}"),
46                    });
47                }
48            }
49        }
50        _ => {}
51    })
52}
53
54/// Webrender renderer debug flags and profiler UI.
55#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
56pub struct RendererDebug {
57    /// Debug flags.
58    #[serde(with = "serde_debug_flags")]
59    pub flags: DebugFlags,
60    /// Profiler UI rendered when [`DebugFlags::PROFILER_DBG`] is set.
61    ///
62    /// # Syntax
63    ///
64    /// Comma-separated list of tokens with trailing and leading spaces trimmed.
65    /// Each tokens can be:
66    /// - A counter name with an optional prefix. The name corresponds to the displayed name.
67    ///   - By default (no prefix) the counter is shown as average + max over half a second.
68    ///   - With a '#' prefix the counter is shown as a graph.
69    ///   - With a '*' prefix the counter is shown as a change indicator.
70    ///   - Some special counters such as GPU time queries have specific visualizations ignoring prefixes.
71    /// - A preset name to append the preset to the UI.
72    /// - An empty token to insert a bit of vertical space.
73    /// - A '|' token to start a new column.
74    /// - A '_' token to start a new row.
75    ///
76    /// # Preset & Counter Names
77    ///
78    /// * `"Default"`: `"FPS,|,Slow indicators,_,Time graphs,|,Frame times, ,Transaction times, ,Frame stats, ,Memory, ,Interners,_,GPU time queries,_,Paint phase graph"`
79    /// * `"Compact"`: `"FPS, ,Frame times, ,Frame stats"`
80    ///
81    /// See the `webrender/src/profiler.rs` file for more details and more counter names.
82    pub profiler_ui: String,
83}
84impl Default for RendererDebug {
85    /// Disabled
86    fn default() -> Self {
87        Self::disabled()
88    }
89}
90impl RendererDebug {
91    /// Default mode, no debugging enabled.
92    pub fn disabled() -> Self {
93        Self {
94            flags: DebugFlags::empty(),
95            profiler_ui: String::new(),
96        }
97    }
98
99    /// Enable profiler UI rendering.
100    pub fn profiler(ui: impl Into<String>) -> Self {
101        Self {
102            flags: DebugFlags::PROFILER_DBG,
103            profiler_ui: ui.into(),
104        }
105    }
106
107    /// Custom flags with no UI string.
108    pub fn flags(flags: DebugFlags) -> Self {
109        Self {
110            flags,
111            profiler_ui: String::new(),
112        }
113    }
114
115    /// If no flag nor profiler UI are set.
116    pub fn is_empty(&self) -> bool {
117        self.flags.is_empty() && self.profiler_ui.is_empty()
118    }
119}
120impl_from_and_into_var! {
121    fn from(profiler_default: bool) -> RendererDebug {
122        if profiler_default {
123            Self::profiler("Default")
124        } else {
125            Self::disabled()
126        }
127    }
128
129    fn from(profiler: &str) -> RendererDebug {
130        Self::profiler(profiler)
131    }
132
133    fn from(profiler: Txt) -> RendererDebug {
134        Self::profiler(profiler)
135    }
136
137    fn from(flags: DebugFlags) -> RendererDebug {
138        Self::flags(flags)
139    }
140}
141
142/// Named DebugFlags in JSON serialization.
143mod serde_debug_flags {
144    use super::*;
145
146    use serde::*;
147
148    bitflags::bitflags! {
149        #[repr(C)]
150        #[derive(Default, Deserialize, Serialize)]
151        #[serde(transparent)]
152        struct DebugFlagsRef: u32 {
153            const PROFILER_DBG = DebugFlags::PROFILER_DBG.bits();
154            const RENDER_TARGET_DBG = DebugFlags::RENDER_TARGET_DBG.bits();
155            const TEXTURE_CACHE_DBG = DebugFlags::TEXTURE_CACHE_DBG.bits();
156            const GPU_TIME_QUERIES = DebugFlags::GPU_TIME_QUERIES.bits();
157            const GPU_SAMPLE_QUERIES = DebugFlags::GPU_SAMPLE_QUERIES.bits();
158            const DISABLE_BATCHING = DebugFlags::DISABLE_BATCHING.bits();
159            const EPOCHS = DebugFlags::EPOCHS.bits();
160            const ECHO_DRIVER_MESSAGES = DebugFlags::ECHO_DRIVER_MESSAGES.bits();
161            const SHOW_OVERDRAW = DebugFlags::SHOW_OVERDRAW.bits();
162            const GPU_CACHE_DBG = DebugFlags::GPU_CACHE_DBG.bits();
163            const TEXTURE_CACHE_DBG_CLEAR_EVICTED = DebugFlags::TEXTURE_CACHE_DBG_CLEAR_EVICTED.bits();
164            const PICTURE_CACHING_DBG = DebugFlags::PICTURE_CACHING_DBG.bits();
165            const PRIMITIVE_DBG = DebugFlags::PRIMITIVE_DBG.bits();
166            const ZOOM_DBG = DebugFlags::ZOOM_DBG.bits();
167            const SMALL_SCREEN = DebugFlags::SMALL_SCREEN.bits();
168            const DISABLE_OPAQUE_PASS = DebugFlags::DISABLE_OPAQUE_PASS.bits();
169            const DISABLE_ALPHA_PASS = DebugFlags::DISABLE_ALPHA_PASS.bits();
170            const DISABLE_CLIP_MASKS = DebugFlags::DISABLE_CLIP_MASKS.bits();
171            const DISABLE_TEXT_PRIMS = DebugFlags::DISABLE_TEXT_PRIMS.bits();
172            const DISABLE_GRADIENT_PRIMS = DebugFlags::DISABLE_GRADIENT_PRIMS.bits();
173            const OBSCURE_IMAGES = DebugFlags::OBSCURE_IMAGES.bits();
174            const GLYPH_FLASHING = DebugFlags::GLYPH_FLASHING.bits();
175            const SMART_PROFILER = DebugFlags::SMART_PROFILER.bits();
176            const INVALIDATION_DBG = DebugFlags::INVALIDATION_DBG.bits();
177            const PROFILER_CAPTURE = DebugFlags::PROFILER_CAPTURE.bits();
178            const FORCE_PICTURE_INVALIDATION = DebugFlags::FORCE_PICTURE_INVALIDATION.bits();
179            const WINDOW_VISIBILITY_DBG = DebugFlags::WINDOW_VISIBILITY_DBG.bits();
180            const RESTRICT_BLOB_SIZE = DebugFlags::RESTRICT_BLOB_SIZE.bits();
181        }
182    }
183    impl From<DebugFlagsRef> for DebugFlags {
184        fn from(value: DebugFlagsRef) -> Self {
185            DebugFlags::from_bits(value.bits()).unwrap()
186        }
187    }
188    impl From<DebugFlags> for DebugFlagsRef {
189        fn from(value: DebugFlags) -> Self {
190            DebugFlagsRef::from_bits(value.bits()).unwrap()
191        }
192    }
193
194    pub fn serialize<S: serde::Serializer>(flags: &DebugFlags, serializer: S) -> Result<S::Ok, S::Error> {
195        DebugFlagsRef::from(*flags).serialize(serializer)
196    }
197
198    pub fn deserialize<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<DebugFlags, D::Error> {
199        DebugFlagsRef::deserialize(deserializer).map(Into::into)
200    }
201}