Skip to main content

fae/
profiler.rs

1//! Module for reading the profiling data that `fae` collects. If the
2//! `profiler` feature is disabled, all the functions are no-ops, and
3//! there will be no profiling overhead. Probably not very useful
4//! outside of this crate's development.
5//!
6//! If using this, remember to call
7//! [`profiler::refresh()`](fn.refresh.html) at the start of each
8//! frame!
9
10/// The data collected by `fae` internals. Returned by
11/// [`profiler::read`](fn.read.html).
12#[derive(Clone, Debug)]
13pub struct ProfilingData {
14    /// The amount of glyphs that had to be rasterized during this
15    /// frame (ie. they weren't in the glyph cache, and drawing the
16    /// glyph was slow, as it had to be rasterized).
17    pub glyph_cache_misses: u32,
18    /// The amount of glyphs that didn't have to rasterized during
19    /// this frame (ie. they were in the glyph cache, and drawing the
20    /// glyph was very fast).
21    pub glyph_cache_hits: u32,
22    /// The amount of glyphs that were rendered during this frame.
23    pub glyphs_drawn: u32,
24    /// The amount of quads that were rendered during this frame
25    /// (includes the glyphs, each one is a quad).
26    pub quads_drawn: u32,
27    /// The amount of times a glyph had to be rasterized in the
28    /// application so far.
29    pub glyphs_rasterized: u32,
30}
31
32impl ProfilingData {
33    const fn cleared() -> ProfilingData {
34        ProfilingData {
35            glyph_cache_misses: 0,
36            glyph_cache_hits: 0,
37            glyphs_drawn: 0,
38            quads_drawn: 0,
39            glyphs_rasterized: 0,
40        }
41    }
42}
43
44#[cfg(feature = "profiler")]
45pub use actual::*;
46#[cfg(not(feature = "profiler"))]
47pub use dummy::*;
48
49#[cfg(not(feature = "profiler"))]
50mod dummy {
51    use super::ProfilingData;
52
53    static CLEARED_DATA: ProfilingData = ProfilingData::cleared();
54
55    /// Resets frame-specific counters.
56    pub fn refresh() {}
57    pub(crate) fn write<F: FnOnce(&mut ProfilingData) + Copy>(_f: F) {}
58
59    /// Returns a copy of the last frame's profiling data. If the
60    /// `profiler` feature is disabled, it will always be zeroed.
61    pub fn read() -> ProfilingData {
62        CLEARED_DATA.clone()
63    }
64}
65
66#[cfg(feature = "profiler")]
67mod actual {
68    use super::ProfilingData;
69    use std::sync::Mutex;
70
71    impl ProfilingData {
72        fn copy_from(&mut self, other: &ProfilingData) {
73            *self = other.clone();
74        }
75
76        fn clear(&mut self) {
77            *self = ProfilingData::cleared();
78        }
79    }
80
81    lazy_static::lazy_static! {
82        static ref FRONT: Mutex<ProfilingData> = Mutex::new(ProfilingData::cleared());
83        static ref BACK: Mutex<ProfilingData> = Mutex::new(ProfilingData::cleared());
84    }
85
86    /// Resets frame-specific counters.
87    pub fn refresh() {
88        if let (Ok(ref mut front), Ok(ref mut back)) = (FRONT.lock(), BACK.lock()) {
89            let temp = back.glyphs_rasterized;
90            front.copy_from(back);
91            back.clear();
92            back.glyphs_rasterized = temp;
93        }
94    }
95
96    pub(crate) fn write<F: FnOnce(&mut ProfilingData) + Copy>(f: F) {
97        if let Ok(ref mut instance) = BACK.lock() {
98            f(instance);
99        }
100    }
101
102    /// Returns a copy of the last frame's profiling data. If the
103    /// `profiler` feature is disabled, it will always be zeroed and
104    /// initialized on the spot.
105    pub fn read() -> ProfilingData {
106        if let Ok(instance) = FRONT.lock() {
107            instance.clone()
108        } else {
109            ProfilingData::cleared()
110        }
111    }
112}