commit 9793fb44a87cf3806de26314c18a525eb47e495c
parent cd5cf799ac42a05a4870a3739ac62cf35c2548b8
Author: Nicolas Silva <nical@fastmail.com>
Date: Tue, 9 Dec 2025 08:19:08 +0000
Bug 1998182 - Add a way to list draw calls and other interesting renderer commands in the debugger. r=gw
This adds a new Draw calls panel in the debugger and some infrastructure for adding per-frame logging to be displayed in the debugger UI.
This will be followed up with a timeline widget to chose which frame's log to display.
The goal is to extend this to log and display any information for which it is useful to see changes over time or for which capturing the right frame is tricky.
Differential Revision: https://phabricator.services.mozilla.com/D271238
Diffstat:
12 files changed, 273 insertions(+), 33 deletions(-)
diff --git a/gfx/wr/webrender/src/debugger.rs b/gfx/wr/webrender/src/debugger.rs
@@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use crate::{DebugCommand, RenderApi, ApiMsg};
-use crate::profiler::Profiler;
+use crate::profiler::{Profiler, RenderCommandLog};
use crate::composite::CompositeState;
use std::collections::HashMap;
use std::convert::Infallible;
@@ -11,7 +11,7 @@ use api::crossbeam_channel;
use api::channel::{Sender, unbounded_channel};
use api::{DebugFlags, TextureCacheCategory};
use api::debugger::{DebuggerMessage, SetDebugFlagsMessage, ProfileCounterDescriptor};
-use api::debugger::{UpdateProfileCountersMessage, InitProfileCountersMessage, ProfileCounterId};
+use api::debugger::{FrameLogMessage, InitProfileCountersMessage, ProfileCounterId};
use api::debugger::{CompositorDebugInfo, CompositorDebugTile};
use std::thread;
use base64::prelude::*;
@@ -142,6 +142,7 @@ impl Debugger {
&mut self,
debug_flags: DebugFlags,
profiler: &Profiler,
+ command_log: &Option<RenderCommandLog>,
) {
let mut clients_to_keep = Vec::new();
@@ -149,15 +150,21 @@ impl Debugger {
let msg = SetDebugFlagsMessage {
flags: debug_flags,
};
- if client.send_msg(DebuggerMessage::SetDebugFlags(msg)) {
- let updates = profiler.collect_updates_for_debugger();
-
- let counters = UpdateProfileCountersMessage {
- updates,
- };
- if client.send_msg(DebuggerMessage::UpdateProfileCounters(counters)) {
- clients_to_keep.push(client);
- }
+ let profile_counters = if client.send_msg(DebuggerMessage::SetDebugFlags(msg)) {
+ Some(profiler.collect_updates_for_debugger())
+ } else {
+ None
+ };
+
+ let render_commands = command_log.as_ref().map(|dc| { dc.get().to_vec() });
+
+ let msg = FrameLogMessage {
+ profile_counters,
+ render_commands,
+ };
+
+ if client.send_msg(DebuggerMessage::UpdateFrameLog(msg)) {
+ clients_to_keep.push(client);
}
}
@@ -260,6 +267,21 @@ async fn handle_request(
}
}
}
+ "/render-cmd-log" => {
+ match request.method() {
+ &hyper::Method::POST => {
+ let content = request_to_string(request).await.unwrap();
+ let enabled = serde_json::from_str(&content).expect("bug");
+ api.send_debug_cmd(
+ DebugCommand::SetRenderCommandLog(enabled)
+ );
+ Ok(string_response(format!("{:?}", enabled)))
+ }
+ _ => {
+ Ok(status_response(403))
+ }
+ }
+ }
"/generate-frame" => {
// Force generate a frame-build and composite
api.send_debug_cmd(
diff --git a/gfx/wr/webrender/src/profiler.rs b/gfx/wr/webrender/src/profiler.rs
@@ -19,7 +19,7 @@
//! - A '|' token to start a new column.
//! - A '_' token to start a new row.
-use api::{ColorF, ColorU};
+use api::{ColorF, ColorU, RenderCommandInfo};
#[cfg(feature = "debugger")]
use api::debugger::{ProfileCounterUpdate, ProfileCounterId};
use glyph_rasterizer::profiler::GlyphRasterizeProfiler;
@@ -2044,3 +2044,41 @@ enum Item {
Column,
Row,
}
+
+pub struct RenderCommandLog {
+ items: Vec<RenderCommandInfo>,
+ current_shader: &'static str,
+}
+
+impl RenderCommandLog {
+ pub fn new() -> Self {
+ RenderCommandLog {
+ items: Vec::new(),
+ current_shader: "",
+ }
+ }
+
+ pub fn get(&self) -> &[RenderCommandInfo] {
+ &self.items
+ }
+
+ pub fn clear(&mut self) {
+ self.current_shader = "";
+ self.items.clear();
+ }
+
+ pub fn set_shader(&mut self, shader: &'static str) {
+ self.current_shader = shader;
+ }
+
+ pub fn begin_render_target(&mut self, label: &str, size: DeviceIntSize) {
+ self.items.push(RenderCommandInfo::RenderTarget { kind: label.into(), size })
+ }
+
+ pub fn draw(&mut self, instances: u32) {
+ self.items.push(RenderCommandInfo::DrawCall {
+ shader: self.current_shader.into(),
+ instances,
+ });
+ }
+}
diff --git a/gfx/wr/webrender/src/render_api.rs b/gfx/wr/webrender/src/render_api.rs
@@ -959,6 +959,8 @@ pub enum DebugCommand {
SetFlags(DebugFlags),
/// Get current debug flags
GetDebugFlags(Sender<DebugFlags>),
+ /// Enable/Disable render command logging.
+ SetRenderCommandLog(bool),
/// Save a capture of all the documents state.
SaveCapture(PathBuf, CaptureBits),
/// Load a capture of all the documents state.
diff --git a/gfx/wr/webrender/src/renderer/init.rs b/gfx/wr/webrender/src/renderer/init.rs
@@ -821,6 +821,7 @@ pub fn create_webrender_instance(
pending_result_msg: None,
layer_compositor_frame_state_in_prev_frame: None,
external_composite_debug_items: Vec::new(),
+ command_log: None,
#[cfg(feature = "debugger")]
debugger: Debugger::new(),
};
diff --git a/gfx/wr/webrender/src/renderer/mod.rs b/gfx/wr/webrender/src/renderer/mod.rs
@@ -80,7 +80,7 @@ use crate::internal_types::{TextureCacheAllocInfo, TextureCacheAllocationKind, T
use crate::internal_types::{RenderTargetInfo, Swizzle, DeferredResolveIndex};
use crate::picture::{ResolvedSurfaceTexture, TileId};
use crate::prim_store::DeferredResolve;
-use crate::profiler::{self, GpuProfileTag, TransactionProfile};
+use crate::profiler::{self, RenderCommandLog, GpuProfileTag, TransactionProfile};
use crate::profiler::{Profiler, add_event_marker, add_text_marker, thread_is_being_profiled};
use crate::device::query::GpuProfiler;
use crate::render_target::ResolveOp;
@@ -836,6 +836,7 @@ pub struct Renderer {
frame_counter: u64,
resource_upload_time: f64,
profiler: Profiler,
+ command_log: Option<RenderCommandLog>,
#[cfg(feature = "debugger")]
debugger: Debugger,
@@ -1339,6 +1340,13 @@ impl Renderer {
DebugCommand::GetDebugFlags(tx) => {
tx.send(self.debug_flags).unwrap();
}
+ DebugCommand::SetRenderCommandLog(enabled) => {
+ if enabled && self.command_log.is_none() {
+ self.command_log = Some(RenderCommandLog::new());
+ } else if !enabled {
+ self.command_log = None;
+ }
+ }
#[cfg(feature = "debugger")]
DebugCommand::AddDebugClient(client) => {
self.debugger.add_client(
@@ -1619,6 +1627,10 @@ impl Renderer {
self.profile.end_time_if_started(profiler::FRAME_SEND_TIME);
self.profile.start_time(profiler::RENDERER_TIME);
+ if let Some(log) = &mut self.command_log {
+ log.clear();
+ }
+
self.staging_texture_pool.begin_frame();
let compositor_kind = active_doc.frame.composite_state.compositor_kind;
@@ -1841,6 +1853,7 @@ impl Renderer {
self.debugger.update(
self.debug_flags,
&self.profiler,
+ &self.command_log,
);
// Note: profile counters must be set before this or they will count for next frame.
@@ -2006,6 +2019,7 @@ impl Renderer {
None,
&mut self.renderer_errors,
&mut self.profile,
+ &mut self.command_log,
);
self.draw_instanced_batch(
@@ -2200,6 +2214,10 @@ impl Renderer {
textures: &BatchTextures,
stats: &mut RendererStats,
) {
+ if let Some(history) = &mut self.command_log {
+ history.draw(data.len() as u32);
+ }
+
self.bind_textures(textures);
// If we end up with an empty draw call here, that means we have
@@ -2398,6 +2416,7 @@ impl Renderer {
None,
&mut self.renderer_errors,
&mut self.profile,
+ &mut self.command_log,
);
for (texture_source, prim_instances) in prim_instances_map {
@@ -2428,6 +2447,7 @@ impl Renderer {
None,
&mut self.renderer_errors,
&mut self.profile,
+ &mut self.command_log,
);
}
@@ -2472,6 +2492,7 @@ impl Renderer {
None,
&mut self.renderer_errors,
&mut self.profile,
+ &mut self.command_log,
);
self.draw_instanced_batch(
@@ -2489,6 +2510,7 @@ impl Renderer {
None,
&mut self.renderer_errors,
&mut self.profile,
+ &mut self.command_log,
);
self.device.enable_scissor();
@@ -2514,6 +2536,7 @@ impl Renderer {
None,
&mut self.renderer_errors,
&mut self.profile,
+ &mut self.command_log,
);
for (texture, prim_instances) in &masks.image_mask_instances {
@@ -2535,6 +2558,7 @@ impl Renderer {
None,
&mut self.renderer_errors,
&mut self.profile,
+ &mut self.command_log,
);
for ((scissor_rect, texture), prim_instances) in &masks.image_mask_instances_with_scissor {
@@ -2558,6 +2582,7 @@ impl Renderer {
None,
&mut self.renderer_errors,
&mut self.profile,
+ &mut self.command_log,
);
self.draw_instanced_batch(
@@ -2575,6 +2600,7 @@ impl Renderer {
None,
&mut self.renderer_errors,
&mut self.profile,
+ &mut self.command_log,
);
self.device.enable_scissor();
@@ -2688,6 +2714,7 @@ impl Renderer {
Some(self.texture_resolver.get_texture_size(source).to_f32()),
&mut self.renderer_errors,
&mut self.profile,
+ &mut self.command_log,
);
self.draw_instanced_batch(
@@ -2718,6 +2745,7 @@ impl Renderer {
None,
&mut self.renderer_errors,
&mut self.profile,
+ &mut self.command_log,
);
self.draw_instanced_batch(
@@ -2831,6 +2859,9 @@ impl Renderer {
stats: &mut RendererStats,
) {
profile_scope!("draw_picture_cache_target");
+ if let Some(history) = &mut self.command_log {
+ history.begin_render_target("Picture tile", draw_target.dimensions());
+ }
self.profile.inc(profiler::RENDERED_PICTURE_TILES);
let _gm = self.gpu_profiler.start_marker("picture cache target");
@@ -2885,6 +2916,7 @@ impl Renderer {
None,
&mut self.renderer_errors,
&mut self.profile,
+ &mut self.command_log,
);
self.draw_instanced_batch(
&[instance],
@@ -3002,6 +3034,7 @@ impl Renderer {
&mut self.device, projection, None,
&mut self.renderer_errors,
&mut self.profile,
+ &mut self.command_log,
);
let _timer = self.gpu_profiler.start_timer(batch.key.kind.sampler_tag());
@@ -3104,6 +3137,7 @@ impl Renderer {
None,
&mut self.renderer_errors,
&mut self.profile,
+ &mut self.command_log,
);
self.draw_instanced_batch(
@@ -3229,6 +3263,7 @@ impl Renderer {
None,
&mut self.renderer_errors,
&mut self.profile,
+ &mut self.command_log,
);
( textures, instance )
@@ -3259,6 +3294,7 @@ impl Renderer {
None,
&mut self.renderer_errors,
&mut self.profile,
+ &mut self.command_log,
);
( textures, instance )
@@ -3311,6 +3347,7 @@ impl Renderer {
None,
&mut self.renderer_errors,
&mut self.profile,
+ &mut self.command_log,
);
for item in tiles_iter {
@@ -3486,6 +3523,7 @@ impl Renderer {
shader_params.3,
&mut self.renderer_errors,
&mut self.profile,
+ &mut self.command_log,
);
current_shader_params = shader_params;
@@ -4376,6 +4414,7 @@ impl Renderer {
None,
&mut self.renderer_errors,
&mut self.profile,
+ &mut self.command_log,
);
self.draw_instanced_batch(
&clear_instances,
@@ -4396,6 +4435,15 @@ impl Renderer {
let needs_depth = target.needs_depth();
let texture = self.texture_resolver.get_cache_texture_mut(&texture_id);
+
+ if let Some(history) = &mut self.command_log {
+ let label = match target.target_kind {
+ RenderTargetKind::Color => "color",
+ RenderTargetKind::Alpha => "alpha",
+ };
+ history.begin_render_target(label, texture.get_dimensions());
+ }
+
if needs_depth {
self.device.reuse_render_target::<u8>(
texture,
@@ -4508,6 +4556,7 @@ impl Renderer {
None,
&mut self.renderer_errors,
&mut self.profile,
+ &mut self.command_log,
);
self.draw_instanced_batch(
@@ -4525,6 +4574,7 @@ impl Renderer {
None,
&mut self.renderer_errors,
&mut self.profile,
+ &mut self.command_log,
);
self.draw_instanced_batch(
@@ -4551,6 +4601,7 @@ impl Renderer {
None,
&mut self.renderer_errors,
&mut self.profile,
+ &mut self.command_log,
);
self.draw_instanced_batch(
@@ -4575,6 +4626,7 @@ impl Renderer {
None,
&mut self.renderer_errors,
&mut self.profile,
+ &mut self.command_log,
);
self.draw_instanced_batch(
@@ -4597,6 +4649,7 @@ impl Renderer {
None,
&mut self.renderer_errors,
&mut self.profile,
+ &mut self.command_log,
);
if let Some(ref texture) = self.dither_matrix_texture {
@@ -4623,6 +4676,7 @@ impl Renderer {
None,
&mut self.renderer_errors,
&mut self.profile,
+ &mut self.command_log,
);
if let Some(ref texture) = self.dither_matrix_texture {
@@ -4649,6 +4703,7 @@ impl Renderer {
None,
&mut self.renderer_errors,
&mut self.profile,
+ &mut self.command_log,
);
if let Some(ref texture) = self.dither_matrix_texture {
@@ -4673,8 +4728,14 @@ impl Renderer {
let _timer = self.gpu_profiler.start_timer(GPU_TAG_BLUR);
self.set_blend(false, framebuffer_kind);
- self.shaders.borrow_mut().cs_blur_rgba8()
- .bind(&mut self.device, &projection, None, &mut self.renderer_errors, &mut self.profile);
+ self.shaders.borrow_mut().cs_blur_rgba8().bind(
+ &mut self.device,
+ &projection,
+ None,
+ &mut self.renderer_errors,
+ &mut self.profile,
+ &mut self.command_log,
+ );
if !target.vertical_blurs.is_empty() {
self.draw_blurs(
@@ -4815,6 +4876,7 @@ impl Renderer {
None,
&mut self.renderer_errors,
&mut self.profile,
+ &mut self.command_log,
);
self.draw_instanced_batch(
&list.slow_rectangles,
@@ -4831,6 +4893,7 @@ impl Renderer {
None,
&mut self.renderer_errors,
&mut self.profile,
+ &mut self.command_log,
);
self.draw_instanced_batch(
&list.fast_rectangles,
@@ -4844,8 +4907,14 @@ impl Renderer {
for (mask_texture_id, items) in list.box_shadows.iter() {
let _gm2 = self.gpu_profiler.start_marker("box-shadows");
let textures = BatchTextures::composite_rgb(*mask_texture_id);
- self.shaders.borrow_mut().cs_clip_box_shadow()
- .bind(&mut self.device, projection, None, &mut self.renderer_errors, &mut self.profile);
+ self.shaders.borrow_mut().cs_clip_box_shadow().bind(
+ &mut self.device,
+ projection,
+ None,
+ &mut self.renderer_errors,
+ &mut self.profile,
+ &mut self.command_log,
+ );
self.draw_instanced_batch(
items,
VertexArrayKind::ClipBoxShadow,
@@ -5501,8 +5570,11 @@ impl Renderer {
present_mode: Option<PartialPresentMode>,
) {
profile_scope!("main target");
-
if let Some(device_size) = device_size {
+ if let Some(history) = &mut self.command_log {
+ history.begin_render_target("Window", device_size);
+ }
+
results.stats.color_target_count += 1;
results.picture_cache_debug = mem::replace(
&mut frame.composite_state.picture_cache_debug,
diff --git a/gfx/wr/webrender/src/renderer/shade.rs b/gfx/wr/webrender/src/renderer/shade.rs
@@ -15,7 +15,7 @@ use crate::renderer::{
BlendMode, DebugFlags, RendererError, WebRenderOptions,
TextureSampler, VertexArrayKind, ShaderPrecacheFlags,
};
-use crate::profiler::{self, TransactionProfile, ns_to_ms};
+use crate::profiler::{self, RenderCommandLog, TransactionProfile, ns_to_ms};
use gleam::gl::GlType;
@@ -149,7 +149,11 @@ impl LazilyCompiledShader {
texture_size: Option<DeviceSize>,
renderer_errors: &mut Vec<RendererError>,
profile: &mut TransactionProfile,
+ history: &mut Option<RenderCommandLog>,
) {
+ if let Some(history) = history {
+ history.set_shader(self.name);
+ }
let update_projection = self.cached_projection != *projection;
let program = match self.get_internal(device, ShaderPrecacheFlags::FULL_COMPILE, Some(profile)) {
Ok(program) => program,
diff --git a/gfx/wr/webrender/src/renderer/upload.rs b/gfx/wr/webrender/src/renderer/upload.rs
@@ -577,6 +577,7 @@ fn copy_from_staging_to_cache_using_draw_calls(
None,
&mut renderer.renderer_errors,
&mut renderer.profile,
+ &mut renderer.command_log,
);
prev_dst = Some(copy.dest_texture_id);
diff --git a/gfx/wr/webrender_api/src/debugger.rs b/gfx/wr/webrender_api/src/debugger.rs
@@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-use crate::{DebugFlags, PictureRect, DeviceRect};
+use crate::{DebugFlags, PictureRect, DeviceRect, RenderCommandInfo};
use crate::image::ImageFormat;
// Shared type definitions between the WR crate and the debugger
@@ -33,15 +33,16 @@ pub struct InitProfileCountersMessage {
}
#[derive(Serialize, Deserialize)]
-pub struct UpdateProfileCountersMessage {
- pub updates: Vec<ProfileCounterUpdate>,
+pub struct FrameLogMessage {
+ pub profile_counters: Option<Vec<ProfileCounterUpdate>>,
+ pub render_commands: Option<Vec<RenderCommandInfo>>,
}
#[derive(Serialize, Deserialize)]
pub enum DebuggerMessage {
SetDebugFlags(SetDebugFlagsMessage),
InitProfileCounters(InitProfileCountersMessage),
- UpdateProfileCounters(UpdateProfileCountersMessage),
+ UpdateFrameLog(FrameLogMessage),
}
#[derive(Serialize, Deserialize)]
diff --git a/gfx/wr/webrender_api/src/lib.rs b/gfx/wr/webrender_api/src/lib.rs
@@ -861,3 +861,12 @@ pub enum TextureCacheCategory {
PictureTile,
RenderTarget,
}
+
+/// For debugging purposes
+#[derive(Clone, Debug)]
+#[cfg_attr(feature = "serialize", derive(Serialize))]
+#[cfg_attr(feature = "deserialize", derive(Deserialize))]
+pub enum RenderCommandInfo {
+ RenderTarget { kind: String, size: DeviceIntSize },
+ DrawCall { shader: String, instances: u32 },
+}
diff --git a/gfx/wr/wrshell/Cargo.lock b/gfx/wr/wrshell/Cargo.lock
@@ -5462,9 +5462,9 @@ dependencies = [
[[package]]
name = "zeitstempel"
-version = "0.1.2"
+version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94652f036694517fa67509942c3b60a51a19e1cd9cfd0f456eeb830ae8798d3d"
+checksum = "f523a0d9326c4f3242ad3a9d306baa7fe4572fd532cc891cabecfb714c786c1e"
dependencies = [
"cfg-if",
"libc",
diff --git a/gfx/wr/wrshell/src/gui/draw_calls.rs b/gfx/wr/wrshell/src/gui/draw_calls.rs
@@ -0,0 +1,42 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use super::Gui;
+use webrender_api::RenderCommandInfo;
+
+pub fn ui(app: &mut Gui, ui: &mut egui::Ui) {
+ if ui.checkbox(&mut app.data_model.frame_log.enabled, "Log render commands").changed() {
+ app.net.post_with_content("render-cmd-log", &app.data_model.frame_log.enabled).ok();
+ }
+
+ // TODO: select the frame using a timeline.
+ if let Some(frame) = app.data_model.frame_log.frames.back() {
+ if let Some(cmds) = &frame.render_commands {
+ draw_calls_ui(cmds, ui);
+ }
+ }
+}
+
+pub fn draw_calls_ui(cmds: &[RenderCommandInfo], ui: &mut egui::Ui) {
+ egui::ScrollArea::vertical().show(ui, |ui| {
+ egui::Grid::new("").show(ui, |ui| {
+ for cmd in cmds {
+ match cmd {
+ RenderCommandInfo::RenderTarget { kind, size } => {
+ ui.end_row();
+ ui.label(egui::RichText::new("Target"));
+ ui.label(egui::RichText::new(format!("{kind} {}x{}", size.width, size.height)));
+ }
+ RenderCommandInfo::DrawCall { shader, instances } => {
+ ui.label(egui::RichText::new(" Draw"));
+ ui.label(egui::RichText::new(shader.clone()).strong());
+ let inst = format!("{} instance{}", instances, if *instances > 1 { "s"} else { "" });
+ ui.label(egui::RichText::new(inst).weak());
+ }
+ }
+ ui.end_row();
+ }
+ });
+ });
+}
diff --git a/gfx/wr/wrshell/src/gui/mod.rs b/gfx/wr/wrshell/src/gui/mod.rs
@@ -7,12 +7,13 @@ mod profiler;
mod shell;
mod textures;
mod composite_view;
+mod draw_calls;
use eframe::egui;
-use webrender_api::DebugFlags;
+use webrender_api::{DebugFlags, RenderCommandInfo};
use webrender_api::debugger::{DebuggerMessage, DebuggerTextureContent, ProfileCounterId, CompositorDebugInfo};
use crate::{command, net};
-use std::collections::{HashMap, BTreeMap};
+use std::collections::{HashMap, BTreeMap, VecDeque};
use std::fs;
use std::io::Write;
use std::sync::mpsc;
@@ -25,6 +26,24 @@ enum ApplicationEvent {
NetworkEvent(net::NetworkEvent),
}
+struct LoggedFrame {
+ pub render_commands: Option<Vec<RenderCommandInfo>>,
+}
+
+struct FrameLog {
+ pub frames: VecDeque<LoggedFrame>,
+ pub enabled: bool,
+}
+
+impl FrameLog {
+ pub fn new() -> Self {
+ FrameLog {
+ frames: VecDeque::with_capacity(100),
+ enabled: false,
+ }
+ }
+}
+
struct DataModel {
is_connected: bool,
debug_flags: DebugFlags,
@@ -33,6 +52,7 @@ struct DataModel {
documents: Vec<Document>,
preview_doc_index: Option<usize>,
profile_graphs: HashMap<ProfileCounterId, Graph>,
+ frame_log: FrameLog,
}
impl DataModel {
@@ -45,6 +65,7 @@ impl DataModel {
documents: Vec::new(),
preview_doc_index: None,
profile_graphs: HashMap::new(),
+ frame_log: FrameLog::new(),
}
}
}
@@ -56,6 +77,7 @@ pub enum Tool {
Shell,
Documents,
Preview,
+ DrawCalls,
}
impl egui_tiles::Behavior<Tool> for Gui {
@@ -66,6 +88,7 @@ impl egui_tiles::Behavior<Tool> for Gui {
Tool::Shell => { "Shell" }
Tool::Documents => { "Documents" }
Tool::Preview => { "Preview" }
+ Tool::DrawCalls => { "Draw calls" }
};
title.into()
@@ -82,6 +105,7 @@ impl egui_tiles::Behavior<Tool> for Gui {
Tool::DebugFlags => { debug_flags::ui(self, ui); }
Tool::Profiler => { profiler::ui(self, ui); }
Tool::Shell => { shell::ui(self, ui); }
+ Tool::DrawCalls => { draw_calls::ui(self, ui); }
}
});
@@ -149,12 +173,19 @@ impl Gui {
e
})
.ok()
+ }).and_then(|save| {
+ if save.version == GuiSavedState::VERSION {
+ Some(save)
+ } else {
+ None
+ }
}).unwrap_or_else(|| {
// Create default layout
let mut tiles = egui_tiles::Tiles::default();
let tabs = vec![
tiles.insert_pane(Tool::Profiler),
tiles.insert_pane(Tool::Preview),
+ tiles.insert_pane(Tool::DrawCalls),
];
let side = vec![
tiles.insert_pane(Tool::DebugFlags),
@@ -174,6 +205,7 @@ impl Gui {
let root = tiles.insert_vertical_tile(v);
GuiSavedState {
+ version: GuiSavedState::VERSION,
cmd_history: Vec::new(),
ui_tiles: egui_tiles::Tree::new("WR debugger", root, tiles),
}
@@ -390,14 +422,22 @@ impl Gui {
}
}
}
- DebuggerMessage::UpdateProfileCounters(info) => {
- for counter in &info.updates {
- if let Some(graph) = self.data_model
- .profile_graphs
- .get_mut(&counter.id) {
- graph.push(counter.value);
+ DebuggerMessage::UpdateFrameLog(info) => {
+ if let Some(updates) = info.profile_counters {
+ for counter in &updates {
+ if let Some(graph) = self.data_model
+ .profile_graphs
+ .get_mut(&counter.id) {
+ graph.push(counter.value);
+ }
}
}
+ if self.data_model.frame_log.frames.len() == self.data_model.frame_log.frames.capacity() {
+ self.data_model.frame_log.frames.pop_front();
+ }
+ self.data_model.frame_log.frames.push_back(LoggedFrame {
+ render_commands: info.render_commands.clone(),
+ });
}
}
}
@@ -417,6 +457,7 @@ impl Drop for Gui {
};
let save = GuiSavedState {
+ version: GuiSavedState::VERSION,
ui_tiles: self.ui_tiles.take().unwrap(),
cmd_history: self.cmd_history.drain(range).collect(),
};
@@ -516,6 +557,13 @@ fn config_path() -> std::path::PathBuf {
#[derive(serde::Serialize, serde::Deserialize)]
struct GuiSavedState {
+ version: u32,
cmd_history: Vec<String>,
ui_tiles: egui_tiles::Tree<Tool>,
}
+
+impl GuiSavedState {
+ /// Update this number to reset the configuration. This ensures that new
+ /// panels are added.
+ const VERSION: u32 = 1;
+}