feat: profiler which displays frametime graph (#1210)

macos-click-through
LoipesMas 3 years ago committed by GitHub
parent 5f9e22c7e5
commit 9c1481e1c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,4 +1,4 @@
pub mod caching_shaper; pub mod caching_shaper;
mod font_loader; pub mod font_loader;
mod font_options; mod font_options;
mod swash_font; mod swash_font;

@ -1,7 +1,8 @@
pub mod animation_utils; pub mod animation_utils;
pub mod cursor_renderer; pub mod cursor_renderer;
mod fonts; pub mod fonts;
pub mod grid_renderer; pub mod grid_renderer;
pub mod profiler;
mod rendered_window; mod rendered_window;
use std::{ use std::{
@ -34,6 +35,7 @@ pub struct RendererSettings {
floating_opacity: f32, floating_opacity: f32,
floating_blur: bool, floating_blur: bool,
debug_renderer: bool, debug_renderer: bool,
profiler: bool,
} }
impl Default for RendererSettings { impl Default for RendererSettings {
@ -44,6 +46,7 @@ impl Default for RendererSettings {
floating_opacity: 0.7, floating_opacity: 0.7,
floating_blur: true, floating_blur: true,
debug_renderer: false, debug_renderer: false,
profiler: false,
} }
} }
} }
@ -70,6 +73,7 @@ pub struct Renderer {
pub window_regions: Vec<WindowDrawDetails>, pub window_regions: Vec<WindowDrawDetails>,
pub batched_draw_command_receiver: UnboundedReceiver<Vec<DrawCommand>>, pub batched_draw_command_receiver: UnboundedReceiver<Vec<DrawCommand>>,
profiler: profiler::Profiler,
} }
impl Renderer { impl Renderer {
@ -82,6 +86,7 @@ impl Renderer {
let window_regions = Vec::new(); let window_regions = Vec::new();
let batched_draw_command_receiver = EVENT_AGGREGATOR.register_event::<Vec<DrawCommand>>(); let batched_draw_command_receiver = EVENT_AGGREGATOR.register_event::<Vec<DrawCommand>>();
let profiler = profiler::Profiler::new(12.0);
Renderer { Renderer {
rendered_windows, rendered_windows,
@ -90,6 +95,7 @@ impl Renderer {
current_mode, current_mode,
window_regions, window_regions,
batched_draw_command_receiver, batched_draw_command_receiver,
profiler,
} }
} }
@ -172,6 +178,8 @@ impl Renderer {
self.cursor_renderer self.cursor_renderer
.draw(&mut self.grid_renderer, &self.current_mode, root_canvas, dt); .draw(&mut self.grid_renderer, &self.current_mode, root_canvas, dt);
self.profiler.draw(root_canvas, dt);
root_canvas.restore(); root_canvas.restore();
font_changed font_changed

@ -0,0 +1,144 @@
use crate::renderer::animation_utils::lerp;
use crate::settings::SETTINGS;
use std::collections::VecDeque;
use std::sync::Arc;
use std::time::Instant;
use crate::renderer::{fonts::font_loader::*, RendererSettings};
use skia_safe::{Canvas, Color, Paint, Point, Rect, Size};
const FRAMETIMES_COUNT: usize = 48;
pub struct Profiler {
pub font: Arc<FontPair>,
pub position: Point,
pub size: Size,
pub last_draw: Instant,
pub frametimes: VecDeque<f32>,
}
impl Profiler {
pub fn new(font_size: f32) -> Self {
let font_key = FontKey::default();
let mut font_loader = FontLoader::new(font_size);
let font = font_loader.get_or_load(&font_key).unwrap();
Self {
font,
position: Point::new(32.0, 32.0),
size: Size::new(200.0, 120.0),
last_draw: Instant::now(),
frametimes: VecDeque::with_capacity(FRAMETIMES_COUNT),
}
}
pub fn draw(&mut self, root_canvas: &mut Canvas, dt: f32) {
if !SETTINGS.get::<RendererSettings>().profiler {
return;
}
root_canvas.save();
let rect = self.get_rect();
root_canvas.clip_rect(rect, None, Some(false));
let mut paint = Paint::default();
// Draw background
let color = Color::from_argb(200, 30, 30, 30);
paint.set_color(color);
root_canvas.draw_paint(&paint);
// Draw FPS
let color = Color::from_argb(255, 0, 255, 0);
paint.set_color(color);
let mut text_postion = self.position;
text_postion.y += self.font.skia_font.size();
root_canvas.draw_str(
format!("{:.0}FPS", 1.0 / dt.max(f32::EPSILON)),
text_postion,
&self.font.skia_font,
&paint,
);
self.frametimes.push_back(dt * 1000.0); // to msecs
while self.frametimes.len() > FRAMETIMES_COUNT {
self.frametimes.pop_front();
}
self.draw_graph(root_canvas);
root_canvas.restore();
}
fn draw_graph(&self, root_canvas: &mut Canvas) {
let mut paint = Paint::default();
let color = Color::from_argb(255, 0, 100, 200);
paint.set_color(color);
// Get min and max and avg
let mut min_ft = f32::MAX;
let mut max_ft = f32::MIN;
let mut sum = 0.0;
for dt in self.frametimes.iter() {
min_ft = dt.min(min_ft);
max_ft = dt.max(max_ft);
sum += dt;
}
let avg = sum / self.frametimes.len() as f32;
let min_g = min_ft * 0.8;
let max_g = max_ft * 1.1;
let diff = max_g - min_g;
let mut rect = self.get_rect();
rect.bottom -= 8.0; // bottom margin
let graph_height = 80.0;
paint.set_anti_alias(true);
let mut prev_point = (rect.left - 10.0, self.position.y + rect.bottom);
for (i, dt) in self.frametimes.iter().enumerate() {
let x = lerp(
rect.left,
rect.right,
i as f32 / self.frametimes.len() as f32,
);
let y = rect.bottom - graph_height * (*dt - min_g) / diff;
let point = (x, y);
root_canvas.draw_line(prev_point, point, &paint);
prev_point = point;
}
let color = Color::from_argb(255, 0, 255, 0);
paint.set_color(color);
paint.set_anti_alias(false);
// Show min, max, avg
root_canvas.draw_str(
format!("min: {min_ft:.1}ms"),
(rect.left, rect.bottom),
&self.font.skia_font,
&paint,
);
root_canvas.draw_str(
format!("avg: {avg:.1}ms"),
(rect.left, rect.bottom - graph_height * 0.5),
&self.font.skia_font,
&paint,
);
root_canvas.draw_str(
format!("max: {max_ft:.1}ms"),
(rect.left, rect.bottom - graph_height),
&self.font.skia_font,
&paint,
);
}
fn get_rect(&self) -> Rect {
Rect::new(
self.position.x,
self.position.y,
self.position.x + self.size.width,
self.position.y + self.size.height,
)
}
}
Loading…
Cancel
Save