Skip to main content

fyrox_impl/renderer/
stats.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21//! Contains all entities that are used to collect rendering statistics.
22
23use fyrox_core::instant;
24use fyrox_graphics::framebuffer::DrawCallStatistics;
25pub use fyrox_graphics::stats::*;
26use std::fmt::{Display, Formatter};
27use std::ops::AddAssign;
28
29/// Lighting statistics.
30#[derive(Debug, Copy, Clone, Default)]
31pub struct LightingStatistics {
32    /// How many point lights were rendered.
33    pub point_lights_rendered: usize,
34    /// How many point light shadow maps were rendered.
35    pub point_shadow_maps_rendered: usize,
36    /// How many cascaded shadow maps were rendered.
37    pub csm_rendered: usize,
38    /// How many spotlights were rendered.
39    pub spot_lights_rendered: usize,
40    /// How many spotlight shadow maps were rendered.
41    pub spot_shadow_maps_rendered: usize,
42    /// How many directional lights were rendered.
43    pub directional_lights_rendered: usize,
44}
45
46impl AddAssign for LightingStatistics {
47    fn add_assign(&mut self, rhs: Self) {
48        self.point_lights_rendered += rhs.point_lights_rendered;
49        self.point_shadow_maps_rendered += rhs.point_shadow_maps_rendered;
50        self.spot_lights_rendered += rhs.spot_lights_rendered;
51        self.spot_shadow_maps_rendered += rhs.spot_shadow_maps_rendered;
52        self.directional_lights_rendered += rhs.directional_lights_rendered;
53        self.csm_rendered += rhs.csm_rendered;
54    }
55}
56
57impl Display for LightingStatistics {
58    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
59        write!(
60            f,
61            "Lighting Statistics:\n\
62            \tPoint Lights: {}\n\
63            \tSpot Lights: {}\n\
64            \tDirectional Lights: {}\n\
65            \tPoint Shadow Maps: {}\n\
66            \tSpot Shadow Maps: {}\n\
67            \tSpot Shadow Maps: {}\n",
68            self.point_lights_rendered,
69            self.spot_lights_rendered,
70            self.directional_lights_rendered,
71            self.point_shadow_maps_rendered,
72            self.spot_shadow_maps_rendered,
73            self.csm_rendered
74        )
75    }
76}
77
78/// Renderer statistics for a scene.
79#[derive(Debug, Copy, Clone, Default)]
80pub struct SceneStatistics {
81    /// Shows how many pipeline state changes was made during scene rendering.
82    pub pipeline: PipelineStatistics,
83    /// Shows how many lights and shadow maps were rendered.
84    pub lighting: LightingStatistics,
85    /// Shows how many draw calls was made and how many triangles were rendered.
86    pub geometry: RenderPassStatistics,
87}
88
89impl Display for SceneStatistics {
90    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
91        write!(
92            f,
93            "{}\n\
94            {}\n\
95            {}\n",
96            self.geometry, self.lighting, self.pipeline
97        )
98    }
99}
100
101impl AddAssign<DrawCallStatistics> for SceneStatistics {
102    fn add_assign(&mut self, rhs: DrawCallStatistics) {
103        self.geometry += rhs;
104    }
105}
106
107impl AddAssign<PipelineStatistics> for SceneStatistics {
108    fn add_assign(&mut self, rhs: PipelineStatistics) {
109        self.pipeline += rhs;
110    }
111}
112
113impl AddAssign<RenderPassStatistics> for SceneStatistics {
114    fn add_assign(&mut self, rhs: RenderPassStatistics) {
115        self.geometry += rhs;
116    }
117}
118
119impl AddAssign<LightingStatistics> for SceneStatistics {
120    fn add_assign(&mut self, rhs: LightingStatistics) {
121        self.lighting += rhs;
122    }
123}
124
125/// Renderer statistics for one frame, also includes current frames per second
126/// number.
127#[derive(Debug, Copy, Clone)]
128pub struct Statistics {
129    /// Shows how many pipeline state changes was made per frame.
130    pub pipeline: PipelineStatistics,
131    /// Shows how many lights and shadow maps were rendered.
132    pub lighting: LightingStatistics,
133    /// Shows how many draw calls was made and how many triangles were rendered.
134    pub geometry: RenderPassStatistics,
135    /// Real time consumed to render a frame. Time given in **seconds**.
136    pub pure_frame_time: f32,
137    /// Total time renderer took to process single frame, usually includes time the renderer spent
138    /// waiting until the swap of the back and front buffers (can include vsync).
139    /// Time given in **seconds**.
140    pub capped_frame_time: f32,
141    /// The total number of frames been rendered in one second.
142    pub frames_per_second: usize,
143    /// The total number of textures in the textures cache.
144    pub texture_cache_size: usize,
145    /// The total number of vertex+index buffers pairs in the geometry cache.
146    pub geometry_cache_size: usize,
147    /// The total number of shaders in the shaders cache.
148    pub shader_cache_size: usize,
149    /// The total number of uniform buffers in the cache.
150    pub uniform_buffer_cache_size: usize,
151    pub(super) frame_counter: usize,
152    pub(super) frame_start_time: instant::Instant,
153    pub(super) last_fps_commit_time: instant::Instant,
154}
155
156impl std::ops::AddAssign<SceneStatistics> for Statistics {
157    fn add_assign(&mut self, rhs: SceneStatistics) {
158        self.pipeline += rhs.pipeline;
159        self.lighting += rhs.lighting;
160        self.geometry += rhs.geometry;
161    }
162}
163
164impl Display for Statistics {
165    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
166        let fps = self.frames_per_second;
167        let pure_frame_time = self.pure_frame_time * 1000.0;
168        let capped_frame_time = self.capped_frame_time * 1000.0;
169        let geometry_stats = &self.geometry;
170        let lighting_stats = &self.lighting;
171        let pipeline_stats = &self.pipeline;
172        let texture_cache_size = self.texture_cache_size;
173        let geometry_cache_size = self.geometry_cache_size;
174        let shader_cache_size = self.shader_cache_size;
175        let uniform_buffer_cache_size = self.uniform_buffer_cache_size;
176        write!(
177            f,
178            "FPS: {fps}\n\
179            Pure Frame Time: {pure_frame_time:.2} ms\n\
180            Capped Frame Time: {capped_frame_time:.2} ms\n\
181            {geometry_stats}\n\
182            {lighting_stats}\n\
183            {pipeline_stats}\n\
184            Texture Cache Size: {texture_cache_size}\n\
185            Geometry Cache Size: {geometry_cache_size}\n\
186            Shader Cache Size: {shader_cache_size}\n
187            Uniform Buffer Cache Size: {uniform_buffer_cache_size}\n",
188        )
189    }
190}
191
192impl std::ops::AddAssign<RenderPassStatistics> for Statistics {
193    fn add_assign(&mut self, rhs: RenderPassStatistics) {
194        self.geometry += rhs;
195    }
196}
197
198impl Default for Statistics {
199    fn default() -> Self {
200        Self {
201            pipeline: Default::default(),
202            lighting: Default::default(),
203            geometry: Default::default(),
204            pure_frame_time: 0.0,
205            capped_frame_time: 0.0,
206            frames_per_second: 0,
207            texture_cache_size: 0,
208            geometry_cache_size: 0,
209            shader_cache_size: 0,
210            uniform_buffer_cache_size: 0,
211            frame_counter: 0,
212            frame_start_time: instant::Instant::now(),
213            last_fps_commit_time: instant::Instant::now(),
214        }
215    }
216}
217
218impl Statistics {
219    /// Must be called before render anything.
220    pub fn begin_frame(&mut self) {
221        self.frame_start_time = instant::Instant::now();
222        self.geometry = Default::default();
223        self.lighting = Default::default();
224    }
225
226    /// Must be called before SwapBuffers but after all rendering is done.
227    pub fn end_frame(&mut self) {
228        let current_time = instant::Instant::now();
229
230        self.pure_frame_time = current_time
231            .duration_since(self.frame_start_time)
232            .as_secs_f32();
233        self.frame_counter += 1;
234
235        if current_time
236            .duration_since(self.last_fps_commit_time)
237            .as_secs_f32()
238            >= 1.0
239        {
240            self.last_fps_commit_time = current_time;
241            self.frames_per_second = self.frame_counter;
242            self.frame_counter = 0;
243        }
244    }
245
246    /// Must be called after SwapBuffers to get capped frame time.
247    pub fn finalize(&mut self) {
248        self.capped_frame_time = instant::Instant::now()
249            .duration_since(self.frame_start_time)
250            .as_secs_f32();
251    }
252}