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::{ViewExtensionError, WINDOWS, WINDOWS_EXTENSIONS, WindowInstanceState};
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 match_node(child, move |_, op| {
23 if let UiNodeOp::Init = op {
24 if !WINDOW.mode().has_renderer() {
25 return;
26 }
27
28 let win_id = WINDOW.id();
29 debug.with(move |d| send_render_debug(win_id, d));
30 WIDGET.push_var_handle(debug.hook(move |a| {
31 send_render_debug(win_id, a.value());
32 true
33 }));
34 WIDGET.push_var_handle(VIEW_PROCESS_INITED_EVENT.hook(clmv!(debug, |_| {
35 debug.with(|d| send_render_debug(win_id, d));
36 true
37 })));
38 }
39 })
40}
41fn send_render_debug(win_id: WindowId, dbg: &RendererDebug) {
42 if let Some(ext_id) = VIEW_PROCESS.extension_id("zng-view.webrender_debug").ok().flatten() {
43 match WINDOWS_EXTENSIONS.view_render_extension(win_id, ext_id, dbg) {
46 Ok(()) => {}
47 Err(ViewExtensionError::NotOpenInViewProcess(_)) => {
48 if let Some(vars) = WINDOWS.vars(win_id) {
49 let state = vars.instance_state();
51 state
54 .hook(clmv!(dbg, |a| {
55 if matches!(*a.value(), WindowInstanceState::Loaded { has_view: true }) {
56 send_render_debug(win_id, &dbg);
57 return false;
58 }
59 true
60 }))
61 .perm();
62 }
63 }
64 Err(e) => tracing::error!("{e}"),
65 }
66 }
67}
68
69#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
71#[non_exhaustive]
72pub struct RendererDebug {
73 #[serde(with = "serde_debug_flags")]
75 pub flags: DebugFlags,
76 pub profiler_ui: String,
99}
100impl Default for RendererDebug {
101 fn default() -> Self {
103 Self::disabled()
104 }
105}
106impl RendererDebug {
107 pub fn disabled() -> Self {
109 Self {
110 flags: DebugFlags::empty(),
111 profiler_ui: String::new(),
112 }
113 }
114
115 pub fn profiler(ui: impl Into<String>) -> Self {
117 Self {
118 flags: DebugFlags::PROFILER_DBG,
119 profiler_ui: ui.into(),
120 }
121 }
122
123 pub fn flags(flags: DebugFlags) -> Self {
125 Self {
126 flags,
127 profiler_ui: String::new(),
128 }
129 }
130
131 pub fn is_empty(&self) -> bool {
133 self.flags.is_empty() && self.profiler_ui.is_empty()
134 }
135}
136impl_from_and_into_var! {
137 fn from(profiler_default: bool) -> RendererDebug {
138 if profiler_default {
139 Self::profiler("Default")
140 } else {
141 Self::disabled()
142 }
143 }
144
145 fn from(profiler: &str) -> RendererDebug {
146 Self::profiler(profiler)
147 }
148
149 fn from(profiler: Txt) -> RendererDebug {
150 Self::profiler(profiler)
151 }
152
153 fn from(flags: DebugFlags) -> RendererDebug {
154 Self::flags(flags)
155 }
156}
157
158mod serde_debug_flags {
160 use super::*;
161
162 use serde::*;
163
164 bitflags::bitflags! {
165 #[repr(C)]
166 #[derive(Default, Deserialize, Serialize)]
167 #[serde(transparent)]
168 struct DebugFlagsRef: u64 {
169 const PROFILER_DBG = DebugFlags::PROFILER_DBG.bits();
170 const RENDER_TARGET_DBG = DebugFlags::RENDER_TARGET_DBG.bits();
171 const TEXTURE_CACHE_DBG = DebugFlags::TEXTURE_CACHE_DBG.bits();
172 const GPU_TIME_QUERIES = DebugFlags::GPU_TIME_QUERIES.bits();
173 const GPU_SAMPLE_QUERIES = DebugFlags::GPU_SAMPLE_QUERIES.bits();
174 const DISABLE_BATCHING = DebugFlags::DISABLE_BATCHING.bits();
175 const EPOCHS = DebugFlags::EPOCHS.bits();
176 const ECHO_DRIVER_MESSAGES = DebugFlags::ECHO_DRIVER_MESSAGES.bits();
177 const SHOW_OVERDRAW = DebugFlags::SHOW_OVERDRAW.bits();
178 const GPU_CACHE_DBG = DebugFlags::GPU_CACHE_DBG.bits();
179 const TEXTURE_CACHE_DBG_CLEAR_EVICTED = DebugFlags::TEXTURE_CACHE_DBG_CLEAR_EVICTED.bits();
180 const PICTURE_CACHING_DBG = DebugFlags::PICTURE_CACHING_DBG.bits();
181 const ZOOM_DBG = DebugFlags::ZOOM_DBG.bits();
182 const SMALL_SCREEN = DebugFlags::SMALL_SCREEN.bits();
183 const DISABLE_OPAQUE_PASS = DebugFlags::DISABLE_OPAQUE_PASS.bits();
184 const DISABLE_ALPHA_PASS = DebugFlags::DISABLE_ALPHA_PASS.bits();
185 const DISABLE_CLIP_MASKS = DebugFlags::DISABLE_CLIP_MASKS.bits();
186 const DISABLE_TEXT_PRIMS = DebugFlags::DISABLE_TEXT_PRIMS.bits();
187 const DISABLE_GRADIENT_PRIMS = DebugFlags::DISABLE_GRADIENT_PRIMS.bits();
188 const OBSCURE_IMAGES = DebugFlags::OBSCURE_IMAGES.bits();
189 const GLYPH_FLASHING = DebugFlags::GLYPH_FLASHING.bits();
190 const SMART_PROFILER = DebugFlags::SMART_PROFILER.bits();
191 const INVALIDATION_DBG = DebugFlags::INVALIDATION_DBG.bits();
192 const PROFILER_CAPTURE = DebugFlags::PROFILER_CAPTURE.bits();
193 const FORCE_PICTURE_INVALIDATION = DebugFlags::FORCE_PICTURE_INVALIDATION.bits();
194 const WINDOW_VISIBILITY_DBG = DebugFlags::WINDOW_VISIBILITY_DBG.bits();
195 const RESTRICT_BLOB_SIZE = DebugFlags::RESTRICT_BLOB_SIZE.bits();
196 const SURFACE_PROMOTION_LOGGING = DebugFlags::SURFACE_PROMOTION_LOGGING.bits();
197 const PICTURE_BORDERS = DebugFlags::PICTURE_BORDERS.bits();
198 const MISSING_SNAPSHOT_PANIC = DebugFlags::MISSING_SNAPSHOT_PANIC.bits();
199 const MISSING_SNAPSHOT_PINK = DebugFlags::MISSING_SNAPSHOT_PINK.bits();
200 const HIGHLIGHT_BACKDROP_FILTERS = DebugFlags::HIGHLIGHT_BACKDROP_FILTERS.bits();
201 }
202 }
203 impl From<DebugFlagsRef> for DebugFlags {
204 fn from(value: DebugFlagsRef) -> Self {
205 DebugFlags::from_bits(value.bits()).unwrap()
206 }
207 }
208 impl From<DebugFlags> for DebugFlagsRef {
209 fn from(value: DebugFlags) -> Self {
210 DebugFlagsRef::from_bits(value.bits()).unwrap()
211 }
212 }
213
214 pub fn serialize<S: serde::Serializer>(flags: &DebugFlags, serializer: S) -> Result<S::Ok, S::Error> {
215 DebugFlagsRef::from(*flags).serialize(serializer)
216 }
217
218 pub fn deserialize<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<DebugFlags, D::Error> {
219 DebugFlagsRef::deserialize(deserializer).map(Into::into)
220 }
221}