Add more statistics to the performance debug window
This commit is contained in:
parent
19c14da3aa
commit
5c7423d59c
|
@ -351,7 +351,8 @@ impl DemoApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
let rendering_time = self.renderer.shift_timer_query();
|
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();
|
self.renderer.debug_ui.draw();
|
||||||
|
|
||||||
if !ui_event.is_none() {
|
if !ui_event.is_none() {
|
||||||
|
@ -686,7 +687,6 @@ impl Options {
|
||||||
fn load_scene(input_path: &Path) -> Scene {
|
fn load_scene(input_path: &Path) -> Scene {
|
||||||
let usvg = Tree::from_file(input_path, &UsvgOptions::default()).unwrap();
|
let usvg = Tree::from_file(input_path, &UsvgOptions::default()).unwrap();
|
||||||
let scene = Scene::from_tree(usvg);
|
let scene = Scene::from_tree(usvg);
|
||||||
println!("Scene bounds: {:?}", scene.bounds);
|
|
||||||
println!("{} objects, {} paints", scene.objects.len(), scene.paints.len());
|
println!("{} objects, {} paints", scene.objects.len(), scene.paints.len());
|
||||||
scene
|
scene
|
||||||
}
|
}
|
||||||
|
@ -724,7 +724,7 @@ fn build_scene(scene: &Scene, build_options: BuildOptions, jobs: Option<usize>)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
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();
|
built_scene.shaders = scene.build_shaders();
|
||||||
|
|
||||||
let mut scene_builder = SceneBuilder::new(built_objects, z_buffer, scene.view_box);
|
let mut scene_builder = SceneBuilder::new(built_objects, z_buffer, scene.view_box);
|
||||||
|
|
125
gl/src/debug.rs
125
gl/src/debug.rs
|
@ -21,11 +21,13 @@ use gl::types::{GLfloat, GLint, GLsizei, GLuint};
|
||||||
use gl;
|
use gl;
|
||||||
use pathfinder_geometry::basic::point::Point2DI32;
|
use pathfinder_geometry::basic::point::Point2DI32;
|
||||||
use pathfinder_geometry::basic::rect::RectI32;
|
use pathfinder_geometry::basic::rect::RectI32;
|
||||||
|
use pathfinder_renderer::gpu_data::Stats;
|
||||||
use pathfinder_renderer::paint::ColorU;
|
use pathfinder_renderer::paint::ColorU;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use std::collections::{HashMap, VecDeque};
|
use std::collections::{HashMap, VecDeque};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
|
use std::ops::{Add, Div};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::time::Duration;
|
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 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 };
|
pub static WINDOW_COLOR: ColorU = ColorU { r: 0, g: 0, b: 0, a: 255 - 90 };
|
||||||
|
|
||||||
const PERF_WINDOW_WIDTH: i32 = 300;
|
const PERF_WINDOW_WIDTH: i32 = 375;
|
||||||
const PERF_WINDOW_HEIGHT: i32 = LINE_HEIGHT * 2 + PADDING + 2;
|
const PERF_WINDOW_HEIGHT: i32 = LINE_HEIGHT * 6 + PADDING + 2;
|
||||||
const FONT_ASCENT: i32 = 28;
|
const FONT_ASCENT: i32 = 28;
|
||||||
const LINE_HEIGHT: i32 = 42;
|
const LINE_HEIGHT: i32 = 42;
|
||||||
const ICON_SIZE: i32 = 48;
|
const ICON_SIZE: i32 = 48;
|
||||||
|
@ -99,8 +101,8 @@ pub struct DebugUI {
|
||||||
solid_vertex_array: DebugSolidVertexArray,
|
solid_vertex_array: DebugSolidVertexArray,
|
||||||
font_texture: Texture,
|
font_texture: Texture,
|
||||||
|
|
||||||
cpu_samples: SampleBuffer,
|
cpu_samples: SampleBuffer<CPUSample>,
|
||||||
gpu_samples: SampleBuffer,
|
gpu_samples: SampleBuffer<GPUSample>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DebugUI {
|
impl DebugUI {
|
||||||
|
@ -138,10 +140,13 @@ impl DebugUI {
|
||||||
self.framebuffer_size = window_size;
|
self.framebuffer_size = window_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_sample(&mut self, tile_time: Duration, rendering_time: Option<Duration>) {
|
pub fn add_sample(&mut self,
|
||||||
self.cpu_samples.push(tile_time);
|
stats: Stats,
|
||||||
|
tile_time: Duration,
|
||||||
|
rendering_time: Option<Duration>) {
|
||||||
|
self.cpu_samples.push(CPUSample { stats, elapsed: tile_time });
|
||||||
if let Some(rendering_time) = rendering_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),
|
bottom - PERF_WINDOW_HEIGHT),
|
||||||
Point2DI32::new(PERF_WINDOW_WIDTH, PERF_WINDOW_HEIGHT));
|
Point2DI32::new(PERF_WINDOW_WIDTH, PERF_WINDOW_HEIGHT));
|
||||||
self.draw_solid_rect(window_rect, WINDOW_COLOR);
|
self.draw_solid_rect(window_rect, WINDOW_COLOR);
|
||||||
self.draw_text(&format!("CPU: {:.3} ms", self.cpu_samples.mean_ms()),
|
let origin = window_rect.origin() + Point2DI32::new(PADDING, PADDING + FONT_ASCENT);
|
||||||
Point2DI32::new(window_rect.min_x() + PADDING,
|
|
||||||
window_rect.min_y() + 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);
|
false);
|
||||||
self.draw_text(&format!("GPU: {:.3} ms", self.gpu_samples.mean_ms()),
|
self.draw_text(&format!("Mask Tiles: {}", mean_cpu_sample.stats.mask_tile_count),
|
||||||
Point2DI32::new(
|
origin + Point2DI32::new(0, LINE_HEIGHT * 2),
|
||||||
window_rect.min_x() + PADDING,
|
false);
|
||||||
window_rect.min_y() + PADDING + FONT_ASCENT + LINE_HEIGHT),
|
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);
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -457,32 +474,33 @@ impl DebugSolidVertex {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SampleBuffer {
|
struct SampleBuffer<S> where S: Add<S, Output=S> + Div<u32, Output=S> + Clone + Default {
|
||||||
samples: VecDeque<Duration>,
|
samples: VecDeque<S>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SampleBuffer {
|
impl<S> SampleBuffer<S> where S: Add<S, Output=S> + Div<u32, Output=S> + Clone + Default {
|
||||||
fn new() -> SampleBuffer {
|
fn new() -> SampleBuffer<S> {
|
||||||
SampleBuffer { samples: VecDeque::with_capacity(SAMPLE_BUFFER_SIZE) }
|
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);
|
self.samples.push_back(time);
|
||||||
while self.samples.len() > SAMPLE_BUFFER_SIZE {
|
while self.samples.len() > SAMPLE_BUFFER_SIZE {
|
||||||
self.samples.pop_front();
|
self.samples.pop_front();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mean_ms(&self) -> f64 {
|
fn mean(&self) -> S {
|
||||||
|
let mut mean = Default::default();
|
||||||
if self.samples.is_empty() {
|
if self.samples.is_empty() {
|
||||||
return 0.0;
|
return mean;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut ms = 0.0;
|
|
||||||
for time in &self.samples {
|
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));
|
color.a as f32 * (1.0 / 255.0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
struct CPUSample {
|
||||||
|
elapsed: Duration,
|
||||||
|
stats: Stats,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<CPUSample> 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<u32> 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<GPUSample> for GPUSample {
|
||||||
|
type Output = GPUSample;
|
||||||
|
fn add(self, other: GPUSample) -> GPUSample {
|
||||||
|
GPUSample { elapsed: self.elapsed + other.elapsed }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Div<u32> 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
|
||||||
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ pub struct BuiltObject {
|
||||||
pub struct BuiltScene {
|
pub struct BuiltScene {
|
||||||
pub view_box: RectF32,
|
pub view_box: RectF32,
|
||||||
pub quad: [Point3DF32; 4],
|
pub quad: [Point3DF32; 4],
|
||||||
|
pub object_count: u32,
|
||||||
pub batches: Vec<Batch>,
|
pub batches: Vec<Batch>,
|
||||||
pub solid_tiles: Vec<SolidTileScenePrimitive>,
|
pub solid_tiles: Vec<SolidTileScenePrimitive>,
|
||||||
pub shaders: Vec<ObjectShader>,
|
pub shaders: Vec<ObjectShader>,
|
||||||
|
@ -84,6 +85,14 @@ pub struct MaskTileBatchPrimitive {
|
||||||
pub shader: ShaderId,
|
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
|
// Utilities for built objects
|
||||||
|
|
||||||
impl BuiltObject {
|
impl BuiltObject {
|
||||||
|
@ -251,8 +260,24 @@ impl BuiltObject {
|
||||||
|
|
||||||
impl BuiltScene {
|
impl BuiltScene {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(view_box: RectF32, quad: &[Point3DF32; 4]) -> BuiltScene {
|
pub fn new(view_box: RectF32, quad: &[Point3DF32; 4], object_count: u32) -> BuiltScene {
|
||||||
BuiltScene { view_box, quad: *quad, batches: vec![], solid_tiles: vec![], shaders: vec![] }
|
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(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue