zng_wgt_webrender_debug/
lib.rs1#![doc(html_favicon_url = "https://zng-ui.github.io/res/zng-logo-icon.png")]
2#![doc(html_logo_url = "https://zng-ui.github.io/res/zng-logo.png")]
3#![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#[property(CONTEXT, default(RendererDebug::disabled()))]
20pub fn renderer_debug(child: impl IntoUiNode, debug: impl IntoVar<RendererDebug>) -> 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 && let Some(ext_id) = VIEW_PROCESS.extension_id("zng-view.webrender_debug").ok().flatten()
43 {
44 debug.with(|d| match WINDOWS.view_render_extension(WINDOW.id(), ext_id, d) {
45 Ok(()) => {}
46 Err(e) => tracing::error!("{e}"),
47 });
48 }
49 }
50 _ => {}
51 })
52}
53
54#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
56#[non_exhaustive]
57pub struct RendererDebug {
58 #[serde(with = "serde_debug_flags")]
60 pub flags: DebugFlags,
61 pub profiler_ui: String,
84}
85impl Default for RendererDebug {
86 fn default() -> Self {
88 Self::disabled()
89 }
90}
91impl RendererDebug {
92 pub fn disabled() -> Self {
94 Self {
95 flags: DebugFlags::empty(),
96 profiler_ui: String::new(),
97 }
98 }
99
100 pub fn profiler(ui: impl Into<String>) -> Self {
102 Self {
103 flags: DebugFlags::PROFILER_DBG,
104 profiler_ui: ui.into(),
105 }
106 }
107
108 pub fn flags(flags: DebugFlags) -> Self {
110 Self {
111 flags,
112 profiler_ui: String::new(),
113 }
114 }
115
116 pub fn is_empty(&self) -> bool {
118 self.flags.is_empty() && self.profiler_ui.is_empty()
119 }
120}
121impl_from_and_into_var! {
122 fn from(profiler_default: bool) -> RendererDebug {
123 if profiler_default {
124 Self::profiler("Default")
125 } else {
126 Self::disabled()
127 }
128 }
129
130 fn from(profiler: &str) -> RendererDebug {
131 Self::profiler(profiler)
132 }
133
134 fn from(profiler: Txt) -> RendererDebug {
135 Self::profiler(profiler)
136 }
137
138 fn from(flags: DebugFlags) -> RendererDebug {
139 Self::flags(flags)
140 }
141}
142
143mod serde_debug_flags {
145 use super::*;
146
147 use serde::*;
148
149 bitflags::bitflags! {
150 #[repr(C)]
151 #[derive(Default, Deserialize, Serialize)]
152 #[serde(transparent)]
153 struct DebugFlagsRef: u64 {
154 const PROFILER_DBG = DebugFlags::PROFILER_DBG.bits();
155 const RENDER_TARGET_DBG = DebugFlags::RENDER_TARGET_DBG.bits();
156 const TEXTURE_CACHE_DBG = DebugFlags::TEXTURE_CACHE_DBG.bits();
157 const GPU_TIME_QUERIES = DebugFlags::GPU_TIME_QUERIES.bits();
158 const GPU_SAMPLE_QUERIES = DebugFlags::GPU_SAMPLE_QUERIES.bits();
159 const DISABLE_BATCHING = DebugFlags::DISABLE_BATCHING.bits();
160 const EPOCHS = DebugFlags::EPOCHS.bits();
161 const ECHO_DRIVER_MESSAGES = DebugFlags::ECHO_DRIVER_MESSAGES.bits();
162 const SHOW_OVERDRAW = DebugFlags::SHOW_OVERDRAW.bits();
163 const GPU_CACHE_DBG = DebugFlags::GPU_CACHE_DBG.bits();
164 const TEXTURE_CACHE_DBG_CLEAR_EVICTED = DebugFlags::TEXTURE_CACHE_DBG_CLEAR_EVICTED.bits();
165 const PICTURE_CACHING_DBG = DebugFlags::PICTURE_CACHING_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 const SURFACE_PROMOTION_LOGGING = DebugFlags::SURFACE_PROMOTION_LOGGING.bits();
182 const PICTURE_BORDERS = DebugFlags::PICTURE_BORDERS.bits();
183 const MISSING_SNAPSHOT_PANIC = DebugFlags::MISSING_SNAPSHOT_PANIC.bits();
184 const MISSING_SNAPSHOT_PINK = DebugFlags::MISSING_SNAPSHOT_PINK.bits();
185 const HIGHLIGHT_BACKDROP_FILTERS = DebugFlags::HIGHLIGHT_BACKDROP_FILTERS.bits();
186 }
187 }
188 impl From<DebugFlagsRef> for DebugFlags {
189 fn from(value: DebugFlagsRef) -> Self {
190 DebugFlags::from_bits(value.bits()).unwrap()
191 }
192 }
193 impl From<DebugFlags> for DebugFlagsRef {
194 fn from(value: DebugFlags) -> Self {
195 DebugFlagsRef::from_bits(value.bits()).unwrap()
196 }
197 }
198
199 pub fn serialize<S: serde::Serializer>(flags: &DebugFlags, serializer: S) -> Result<S::Ok, S::Error> {
200 DebugFlagsRef::from(*flags).serialize(serializer)
201 }
202
203 pub fn deserialize<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<DebugFlags, D::Error> {
204 DebugFlagsRef::deserialize(deserializer).map(Into::into)
205 }
206}