Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_dev_tools/src/frame_time_graph/mod.rs
9356 views
1
//! Module containing logic for the frame time graph
2
3
use bevy_app::{Plugin, Update};
4
use bevy_asset::{load_internal_asset, uuid_handle, Asset, Assets, Handle};
5
use bevy_diagnostic::{DiagnosticsStore, FrameTimeDiagnosticsPlugin};
6
use bevy_ecs::{
7
schedule::IntoScheduleConfigs,
8
system::{Res, ResMut},
9
};
10
use bevy_math::ops::log2;
11
use bevy_reflect::TypePath;
12
use bevy_render::{
13
render_resource::{AsBindGroup, ShaderType},
14
storage::ShaderBuffer,
15
};
16
use bevy_shader::{Shader, ShaderRef};
17
use bevy_ui_render::prelude::{UiMaterial, UiMaterialPlugin};
18
19
use crate::fps_overlay::{FpsOverlayConfig, FpsOverlaySystems};
20
21
const FRAME_TIME_GRAPH_SHADER_HANDLE: Handle<Shader> =
22
uuid_handle!("4e38163a-5782-47a5-af52-d9161472ab59");
23
24
/// Plugin that sets up everything to render the frame time graph material
25
pub struct FrameTimeGraphPlugin;
26
27
impl Plugin for FrameTimeGraphPlugin {
28
fn build(&self, app: &mut bevy_app::App) {
29
load_internal_asset!(
30
app,
31
FRAME_TIME_GRAPH_SHADER_HANDLE,
32
"frame_time_graph.wgsl",
33
Shader::from_wgsl
34
);
35
36
// TODO: Use plugin dependencies, see https://github.com/bevyengine/bevy/issues/69
37
if !app.is_plugin_added::<FrameTimeDiagnosticsPlugin>() {
38
panic!("Requires FrameTimeDiagnosticsPlugin");
39
// app.add_plugins(FrameTimeDiagnosticsPlugin);
40
}
41
42
app.add_plugins(UiMaterialPlugin::<FrametimeGraphMaterial>::default())
43
.add_systems(
44
Update,
45
update_frame_time_values.in_set(FpsOverlaySystems::UpdateText),
46
);
47
}
48
}
49
50
/// The config values sent to the frame time graph shader
51
#[derive(Debug, Clone, Copy, ShaderType)]
52
pub struct FrameTimeGraphConfigUniform {
53
// minimum expected delta time
54
dt_min: f32,
55
// maximum expected delta time
56
dt_max: f32,
57
dt_min_log2: f32,
58
dt_max_log2: f32,
59
// controls whether or not the bars width are proportional to their delta time
60
proportional_width: u32,
61
}
62
63
impl FrameTimeGraphConfigUniform {
64
/// `proportional_width`: controls whether or not the bars width are proportional to their delta time
65
pub fn new(target_fps: f32, min_fps: f32, proportional_width: bool) -> Self {
66
// we want an upper limit that is above the target otherwise the bars will disappear
67
let dt_min = 1. / (target_fps * 1.2);
68
let dt_max = 1. / min_fps;
69
Self {
70
dt_min,
71
dt_max,
72
dt_min_log2: log2(dt_min),
73
dt_max_log2: log2(dt_max),
74
proportional_width: u32::from(proportional_width),
75
}
76
}
77
}
78
79
/// The material used to render the frame time graph ui node
80
#[derive(AsBindGroup, Asset, TypePath, Debug, Clone)]
81
pub struct FrametimeGraphMaterial {
82
/// The history of the previous frame times value.
83
///
84
/// This should be updated every frame to match the frame time history from the [`DiagnosticsStore`]
85
#[storage(0, read_only)]
86
pub values: Handle<ShaderBuffer>, // Vec<f32>,
87
/// The configuration values used by the shader to control how the graph is rendered
88
#[uniform(1)]
89
pub config: FrameTimeGraphConfigUniform,
90
}
91
92
impl UiMaterial for FrametimeGraphMaterial {
93
fn fragment_shader() -> ShaderRef {
94
FRAME_TIME_GRAPH_SHADER_HANDLE.into()
95
}
96
}
97
98
/// A system that updates the frame time values sent to the frame time graph
99
fn update_frame_time_values(
100
mut frame_time_graph_materials: ResMut<Assets<FrametimeGraphMaterial>>,
101
mut buffers: ResMut<Assets<ShaderBuffer>>,
102
diagnostics_store: Res<DiagnosticsStore>,
103
config: Option<Res<FpsOverlayConfig>>,
104
) {
105
if !config.is_none_or(|c| c.frame_time_graph_config.enabled) {
106
return;
107
}
108
let Some(frame_time) = diagnostics_store.get(&FrameTimeDiagnosticsPlugin::FRAME_TIME) else {
109
return;
110
};
111
let frame_times = frame_time
112
.values()
113
// convert to millis
114
.map(|x| *x as f32 / 1000.0)
115
.collect::<Vec<_>>();
116
for (_, material) in frame_time_graph_materials.iter_mut() {
117
let buffer = buffers.get_mut(&material.values).unwrap();
118
119
buffer.set_data(frame_times.clone());
120
}
121
}
122
123