From 5c7423d59c91130ecae45b9b8a119c05509fee1e Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Mon, 25 Feb 2019 16:12:47 -0800 Subject: [PATCH] Add more statistics to the performance debug window --- demo/common/src/lib.rs | 6 +- gl/src/debug.rs | 125 +++++++++++++++++++++++++++++++-------- renderer/src/gpu_data.rs | 29 ++++++++- 3 files changed, 131 insertions(+), 29 deletions(-) diff --git a/demo/common/src/lib.rs b/demo/common/src/lib.rs index 0fbac7b2..b5266376 100644 --- a/demo/common/src/lib.rs +++ b/demo/common/src/lib.rs @@ -351,7 +351,8 @@ impl DemoApp { } let rendering_time = self.renderer.shift_timer_query(); - self.renderer.debug_ui.add_sample(tile_time, rendering_time); + let stats = built_scene.stats(); + self.renderer.debug_ui.add_sample(stats, tile_time, rendering_time); self.renderer.debug_ui.draw(); if !ui_event.is_none() { @@ -686,7 +687,6 @@ impl Options { fn load_scene(input_path: &Path) -> Scene { let usvg = Tree::from_file(input_path, &UsvgOptions::default()).unwrap(); let scene = Scene::from_tree(usvg); - println!("Scene bounds: {:?}", scene.bounds); println!("{} objects, {} paints", scene.objects.len(), scene.paints.len()); scene } @@ -724,7 +724,7 @@ fn build_scene(scene: &Scene, build_options: BuildOptions, jobs: Option) } }; - let mut built_scene = BuiltScene::new(scene.view_box, &quad); + let mut built_scene = BuiltScene::new(scene.view_box, &quad, scene.objects.len() as u32); built_scene.shaders = scene.build_shaders(); let mut scene_builder = SceneBuilder::new(built_objects, z_buffer, scene.view_box); diff --git a/gl/src/debug.rs b/gl/src/debug.rs index 60e8b255..909df35c 100644 --- a/gl/src/debug.rs +++ b/gl/src/debug.rs @@ -21,11 +21,13 @@ use gl::types::{GLfloat, GLint, GLsizei, GLuint}; use gl; use pathfinder_geometry::basic::point::Point2DI32; use pathfinder_geometry::basic::rect::RectI32; +use pathfinder_renderer::gpu_data::Stats; use pathfinder_renderer::paint::ColorU; use serde_json; use std::collections::{HashMap, VecDeque}; use std::fs::File; use std::io::BufReader; +use std::ops::{Add, Div}; use std::ptr; use std::time::Duration; @@ -42,8 +44,8 @@ pub const BUTTON_TEXT_OFFSET: i32 = PADDING + 36; pub static TEXT_COLOR: ColorU = ColorU { r: 255, g: 255, b: 255, a: 255 }; pub static WINDOW_COLOR: ColorU = ColorU { r: 0, g: 0, b: 0, a: 255 - 90 }; -const PERF_WINDOW_WIDTH: i32 = 300; -const PERF_WINDOW_HEIGHT: i32 = LINE_HEIGHT * 2 + PADDING + 2; +const PERF_WINDOW_WIDTH: i32 = 375; +const PERF_WINDOW_HEIGHT: i32 = LINE_HEIGHT * 6 + PADDING + 2; const FONT_ASCENT: i32 = 28; const LINE_HEIGHT: i32 = 42; const ICON_SIZE: i32 = 48; @@ -99,8 +101,8 @@ pub struct DebugUI { solid_vertex_array: DebugSolidVertexArray, font_texture: Texture, - cpu_samples: SampleBuffer, - gpu_samples: SampleBuffer, + cpu_samples: SampleBuffer, + gpu_samples: SampleBuffer, } impl DebugUI { @@ -138,10 +140,13 @@ impl DebugUI { self.framebuffer_size = window_size; } - pub fn add_sample(&mut self, tile_time: Duration, rendering_time: Option) { - self.cpu_samples.push(tile_time); + pub fn add_sample(&mut self, + stats: Stats, + tile_time: Duration, + rendering_time: Option) { + self.cpu_samples.push(CPUSample { stats, elapsed: tile_time }); if let Some(rendering_time) = rendering_time { - self.gpu_samples.push(rendering_time); + self.gpu_samples.push(GPUSample { elapsed: rendering_time }); } } @@ -153,14 +158,26 @@ impl DebugUI { bottom - PERF_WINDOW_HEIGHT), Point2DI32::new(PERF_WINDOW_WIDTH, PERF_WINDOW_HEIGHT)); self.draw_solid_rect(window_rect, WINDOW_COLOR); - self.draw_text(&format!("CPU: {:.3} ms", self.cpu_samples.mean_ms()), - Point2DI32::new(window_rect.min_x() + PADDING, - window_rect.min_y() + PADDING + FONT_ASCENT), + let origin = window_rect.origin() + Point2DI32::new(PADDING, PADDING + FONT_ASCENT); + + let mean_cpu_sample = self.cpu_samples.mean(); + self.draw_text(&format!("Objects: {}", mean_cpu_sample.stats.object_count), origin, false); + self.draw_text(&format!("Solid Tiles: {}", mean_cpu_sample.stats.solid_tile_count), + origin + Point2DI32::new(0, LINE_HEIGHT * 1), false); - self.draw_text(&format!("GPU: {:.3} ms", self.gpu_samples.mean_ms()), - Point2DI32::new( - window_rect.min_x() + PADDING, - window_rect.min_y() + PADDING + FONT_ASCENT + LINE_HEIGHT), + self.draw_text(&format!("Mask Tiles: {}", mean_cpu_sample.stats.mask_tile_count), + origin + Point2DI32::new(0, LINE_HEIGHT * 2), + false); + self.draw_text(&format!("Fills: {}", mean_cpu_sample.stats.fill_count), + origin + Point2DI32::new(0, LINE_HEIGHT * 3), + false); + self.draw_text(&format!("CPU Time: {:.3} ms", duration_to_ms(mean_cpu_sample.elapsed)), + origin + Point2DI32::new(0, LINE_HEIGHT * 4), + false); + + let mean_gpu_sample = self.gpu_samples.mean(); + self.draw_text(&format!("GPU Time: {:.3} ms", duration_to_ms(mean_gpu_sample.elapsed)), + origin + Point2DI32::new(0, LINE_HEIGHT * 5), false); } @@ -457,32 +474,33 @@ impl DebugSolidVertex { } } -struct SampleBuffer { - samples: VecDeque, +struct SampleBuffer where S: Add + Div + Clone + Default { + samples: VecDeque, } -impl SampleBuffer { - fn new() -> SampleBuffer { +impl SampleBuffer where S: Add + Div + Clone + Default { + fn new() -> SampleBuffer { SampleBuffer { samples: VecDeque::with_capacity(SAMPLE_BUFFER_SIZE) } } - fn push(&mut self, time: Duration) { + fn push(&mut self, time: S) { self.samples.push_back(time); while self.samples.len() > SAMPLE_BUFFER_SIZE { self.samples.pop_front(); } } - fn mean_ms(&self) -> f64 { + fn mean(&self) -> S { + let mut mean = Default::default(); if self.samples.is_empty() { - return 0.0; + return mean; } - let mut ms = 0.0; for time in &self.samples { - ms += time.as_secs() as f64 * 1000.0 + time.subsec_nanos() as f64 / 1000000.0; + mean = mean + (*time).clone(); } - ms / self.samples.len() as f64 + + mean / self.samples.len() as u32 } } @@ -495,3 +513,62 @@ fn set_color_uniform(uniform: &Uniform, color: ColorU) { color.a as f32 * (1.0 / 255.0)); } } + +#[derive(Clone, Default)] +struct CPUSample { + elapsed: Duration, + stats: Stats, +} + +impl Add for CPUSample { + type Output = CPUSample; + fn add(self, other: CPUSample) -> CPUSample { + CPUSample { + elapsed: self.elapsed + other.elapsed, + stats: Stats { + object_count: self.stats.object_count + other.stats.object_count, + solid_tile_count: self.stats.solid_tile_count + other.stats.solid_tile_count, + mask_tile_count: self.stats.mask_tile_count + other.stats.mask_tile_count, + fill_count: self.stats.fill_count + other.stats.fill_count, + }, + } + } +} + +impl Div for CPUSample { + type Output = CPUSample; + fn div(self, divisor: u32) -> CPUSample { + CPUSample { + elapsed: self.elapsed / divisor, + stats: Stats { + object_count: self.stats.object_count / divisor, + solid_tile_count: self.stats.solid_tile_count / divisor, + mask_tile_count: self.stats.mask_tile_count / divisor, + fill_count: self.stats.fill_count / divisor, + }, + } + } +} + +#[derive(Clone, Default)] +struct GPUSample { + elapsed: Duration, +} + +impl Add for GPUSample { + type Output = GPUSample; + fn add(self, other: GPUSample) -> GPUSample { + GPUSample { elapsed: self.elapsed + other.elapsed } + } +} + +impl Div for GPUSample { + type Output = GPUSample; + fn div(self, divisor: u32) -> GPUSample { + GPUSample { elapsed: self.elapsed / divisor } + } +} + +fn duration_to_ms(time: Duration) -> f64 { + time.as_secs() as f64 * 1000.0 + time.subsec_nanos() as f64 / 1000000.0 +} diff --git a/renderer/src/gpu_data.rs b/renderer/src/gpu_data.rs index f86c48bb..f6867f2e 100644 --- a/renderer/src/gpu_data.rs +++ b/renderer/src/gpu_data.rs @@ -33,6 +33,7 @@ pub struct BuiltObject { pub struct BuiltScene { pub view_box: RectF32, pub quad: [Point3DF32; 4], + pub object_count: u32, pub batches: Vec, pub solid_tiles: Vec, pub shaders: Vec, @@ -84,6 +85,14 @@ pub struct MaskTileBatchPrimitive { pub shader: ShaderId, } +#[derive(Clone, Copy, Debug, Default)] +pub struct Stats { + pub object_count: u32, + pub solid_tile_count: u32, + pub mask_tile_count: u32, + pub fill_count: u32, +} + // Utilities for built objects impl BuiltObject { @@ -251,8 +260,24 @@ impl BuiltObject { impl BuiltScene { #[inline] - pub fn new(view_box: RectF32, quad: &[Point3DF32; 4]) -> BuiltScene { - BuiltScene { view_box, quad: *quad, batches: vec![], solid_tiles: vec![], shaders: vec![] } + pub fn new(view_box: RectF32, quad: &[Point3DF32; 4], object_count: u32) -> BuiltScene { + BuiltScene { + view_box, + quad: *quad, + object_count, + batches: vec![], + solid_tiles: vec![], + shaders: vec![], + } + } + + pub fn stats(&self) -> Stats { + Stats { + object_count: self.object_count, + solid_tile_count: self.solid_tiles.len() as u32, + mask_tile_count: self.batches.iter().map(|batch| batch.mask_tiles.len() as u32).sum(), + fill_count: self.batches.iter().map(|batch| batch.fills.len() as u32).sum(), + } } }