Skip to content

Commit 97fbd00

Browse files
committed
Add support for tracking RenderAsset memory usage.
1 parent 517bc13 commit 97fbd00

16 files changed

+334
-120
lines changed

.github/workflows/tests.yml

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# TODO: build with all combinations of features.
2+
13
name: tests
24

35
on:

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ edition = "2021"
77
bevy = { version = "0.6", default-features = false }
88
bytesize = "1"
99
datasize = "0.2"
10+
parking_lot = "0.11"
1011

1112
[dev-dependencies]
1213
maplit = "1"

examples/render_resources.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
//!
44
//! Adapted from the official Bevy `many_cubes` example.
55
6-
use bevy::prelude::*;
6+
use bevy::{
7+
prelude::*,
8+
render::{mesh::GpuMesh, texture::GpuImage},
9+
};
710
use bevy_datasize::prelude::*;
811

912
fn main() {
@@ -48,12 +51,14 @@ fn setup(
4851

4952
fn print_sizes(memory_usage: Res<MemoryUsage>) {
5053
let mesh_stats = memory_usage.get_stats::<Mesh>().unwrap();
54+
let gpu_mesh_stats = memory_usage.get_stats::<GpuMesh>().unwrap();
5155
let image_stats = memory_usage.get_stats::<Image>().unwrap();
5256
let material_stats = memory_usage.get_stats::<StandardMaterial>().unwrap();
5357

5458
println!();
5559
println!("Memory usage:");
5660
println!("Meshes: {mesh_stats}");
61+
println!("GPU Meshes: {gpu_mesh_stats}");
5762
println!("Images: {image_stats}");
5863
println!("Materials: {material_stats}");
5964
}

src/app_ext.rs

+139-20
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,32 @@
1+
//! Extension traits for [`App`].
2+
13
use std::any::Any;
24

35
use bevy::{
46
app::App,
57
asset::Asset,
6-
ecs::{component::Component, schedule::IntoSystemDescriptor, system::Resource},
8+
ecs::{
9+
component::Component, schedule::IntoSystemDescriptor, schedule::StageLabel,
10+
system::Resource,
11+
},
12+
prelude::CoreStage,
713
};
814

9-
use crate::{estimator::ForwardingEstimator, systems, DataSize, MemoryUsage};
15+
#[cfg(feature = "bevy_render")]
16+
use bevy::render::{render_asset::RenderAsset, RenderApp, RenderStage};
17+
18+
use crate::{
19+
estimator::{ForwardingEstimator, FromConfig},
20+
systems, DataSize, DataSizeEstimator, MemoryUsage,
21+
};
1022

11-
/// [`App`] extension methods to register types for memory usage tracking.
12-
pub trait RegisterSizedTypes {
23+
/// [`App`] extension methods to register [`DataSize`] types for memory usage
24+
/// tracking.
25+
///
26+
/// For types that do not implement [`DataSize`], you will need to implement a
27+
/// [`DataSizeEstimator`] for them and register them using the methods in
28+
/// [`RegisterTypesWithEstimator`].
29+
pub trait RegisterSizedTypes: RegisterTypesWithEstimator {
1330
/// Registers the given [`Component`] type with the
1431
/// [`MemoryUsagePlugin`][crate::MemoryUsagePlugin].
1532
///
@@ -19,9 +36,7 @@ pub trait RegisterSizedTypes {
1936
where
2037
T: Any + DataSize + Component,
2138
{
22-
self.register_sized_type::<T, _, _>(
23-
systems::update_stats_for_component::<T, ForwardingEstimator>,
24-
)
39+
self.register_component_with_estimator::<T, ForwardingEstimator>()
2540
}
2641

2742
/// Registers the given [`Resource`] type with the
@@ -33,9 +48,7 @@ pub trait RegisterSizedTypes {
3348
where
3449
T: Any + DataSize + Resource,
3550
{
36-
self.register_sized_type::<T, _, _>(
37-
systems::update_stats_for_resource::<T, ForwardingEstimator>,
38-
)
51+
self.register_resource_with_estimator::<T, ForwardingEstimator>()
3952
}
4053

4154
/// Registers the given [`Asset`] type with the
@@ -47,39 +60,145 @@ pub trait RegisterSizedTypes {
4760
where
4861
T: Any + DataSize + Asset,
4962
{
50-
self.register_sized_type::<T, _, _>(
51-
systems::update_stats_for_asset::<T, ForwardingEstimator>,
63+
self.register_asset_with_estimator::<T, ForwardingEstimator>()
64+
}
65+
66+
/// Registers the given [`Asset`] type with the
67+
/// [`MemoryUsagePlugin`][crate::MemoryUsagePlugin].
68+
///
69+
/// The following types will be available to query on the [`MemoryUsage`]
70+
/// resource:
71+
///
72+
/// * `T`
73+
/// * `<T as RenderAsset>::ExtractedAsset`
74+
/// * `<T as RenderAsset>::PreparedAsset`
75+
#[cfg(feature = "bevy_render")]
76+
fn register_sized_render_asset<T>(&mut self) -> &mut Self
77+
where
78+
T: Any + DataSize + RenderAsset,
79+
<T as RenderAsset>::PreparedAsset: Any + DataSize,
80+
{
81+
self.register_render_asset_with_estimator::<T, ForwardingEstimator, ForwardingEstimator>()
82+
}
83+
}
84+
85+
impl RegisterSizedTypes for App {}
86+
87+
/// [`App`] extension methods to register non-[`DataSize`] types for memory
88+
/// usage tracking.
89+
pub trait RegisterTypesWithEstimator: RegisterTypes {
90+
/// Like [`RegisterSizedTypes::register_sized_component`], but uses the
91+
/// given [`DataSizeEstimator`] type.
92+
fn register_component_with_estimator<T, E>(&mut self) -> &mut Self
93+
where
94+
T: Any + Component,
95+
E: DataSizeEstimator<T> + FromConfig + 'static,
96+
{
97+
self.register_type::<T, _, _, _>(
98+
systems::update_stats_for_component::<T, E>,
99+
CoreStage::Update,
52100
)
53101
}
54102

103+
/// Like [`RegisterSizedTypes::register_sized_resource`], but uses the
104+
/// given [`DataSizeEstimator`] type.
105+
fn register_resource_with_estimator<T, E>(&mut self) -> &mut Self
106+
where
107+
T: Any + Resource,
108+
E: DataSizeEstimator<T> + FromConfig + 'static,
109+
{
110+
self.register_type::<T, _, _, _>(
111+
systems::update_stats_for_resource::<T, E>,
112+
CoreStage::Update,
113+
)
114+
}
115+
116+
/// Like [`RegisterSizedTypes::register_sized_asset`], but uses the
117+
/// given [`DataSizeEstimator`] type.
118+
fn register_asset_with_estimator<T, E>(&mut self) -> &mut Self
119+
where
120+
T: Any + Asset,
121+
E: DataSizeEstimator<T> + FromConfig + 'static,
122+
{
123+
self.register_type::<T, _, _, _>(systems::update_stats_for_asset::<T, E>, CoreStage::Update)
124+
}
125+
126+
/// Like [`RegisterSizedTypes::register_sized_asset`], but uses the given
127+
/// [`DataSizeEstimator`] types to estimate the size of the [`RenderAsset`]
128+
/// and its prepared format.
129+
#[cfg(feature = "bevy_render")]
130+
fn register_render_asset_with_estimator<T, E, F>(&mut self) -> &mut Self
131+
where
132+
T: Any + RenderAsset,
133+
E: DataSizeEstimator<T> + FromConfig + 'static,
134+
<T as RenderAsset>::PreparedAsset: Any,
135+
F: DataSizeEstimator<<T as RenderAsset>::PreparedAsset> + FromConfig + 'static;
136+
}
137+
138+
impl RegisterTypesWithEstimator for App {
139+
#[cfg(feature = "bevy_render")]
140+
fn register_render_asset_with_estimator<T, E, F>(&mut self) -> &mut Self
141+
where
142+
T: Any + RenderAsset,
143+
E: DataSizeEstimator<T> + FromConfig + 'static,
144+
<T as RenderAsset>::PreparedAsset: Any,
145+
F: DataSizeEstimator<<T as RenderAsset>::PreparedAsset> + FromConfig + 'static,
146+
{
147+
RegisterTypes::register_type::<T, _, _, _>(
148+
self,
149+
systems::update_stats_for_asset::<T, E>,
150+
CoreStage::Update,
151+
);
152+
153+
if let Ok(render_app) = self.get_sub_app_mut(RenderApp) {
154+
RegisterTypes::register_type::<<T as RenderAsset>::PreparedAsset, _, _, _>(
155+
render_app,
156+
systems::update_stats_for_render_asset::<T, F>,
157+
// TODO: find the appropriate stage for this.
158+
RenderStage::Render,
159+
);
160+
161+
// Also register the type on the main app so there are entries for
162+
// it in the hashmap.
163+
register_type_on_app::<T>(self);
164+
}
165+
166+
self
167+
}
168+
}
169+
170+
/// The lowest-level interface for registering types for memory usage tracking.
171+
pub trait RegisterTypes {
55172
/// Registers a type whose [`MemoryStats`] will be updated with the given
56-
/// `system`.
173+
/// `system`, which will run in the given `stage`.
57174
///
58175
/// The given type `T` will be available to query on the [`MemoryUsage`]
59176
/// resource.
60177
///
61178
/// [`MemoryStats`]: crate::MemoryStats
62-
fn register_sized_type<T, S, Params>(&mut self, system: S) -> &mut Self
179+
fn register_type<T, S, Params, L>(&mut self, system: S, stage: L) -> &mut Self
63180
where
64181
T: Any,
65-
S: IntoSystemDescriptor<Params>;
182+
S: IntoSystemDescriptor<Params>,
183+
L: StageLabel;
66184
}
67185

68-
impl RegisterSizedTypes for App {
69-
fn register_sized_type<T, S, Params>(&mut self, system: S) -> &mut Self
186+
impl RegisterTypes for App {
187+
fn register_type<T, S, Params, L>(&mut self, system: S, stage: L) -> &mut Self
70188
where
71189
T: Any,
72190
S: IntoSystemDescriptor<Params>,
191+
L: StageLabel,
73192
{
74-
register_type::<T>(self);
193+
register_type_on_app::<T>(self);
75194

76-
self.add_system(system);
195+
self.add_system_to_stage(stage, system);
77196

78197
self
79198
}
80199
}
81200

82-
fn register_type<T>(app: &mut App)
201+
fn register_type_on_app<T>(app: &mut App)
83202
where
84203
T: Any,
85204
{

src/builtins/mod.rs

+2-36
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
11
//! Support for Bevy's built-in types.
22
3-
use std::any::Any;
3+
use bevy::app::{PluginGroup, PluginGroupBuilder};
44

5-
use bevy::{
6-
app::{App, PluginGroup, PluginGroupBuilder},
7-
asset::Asset,
8-
ecs::{component::Component, system::Resource},
9-
};
10-
11-
use crate::{systems, DataSizeEstimator, MemoryUsagePlugin, RegisterSizedTypes};
5+
use crate::MemoryUsagePlugin;
126

137
pub mod render;
148
pub mod transform;
@@ -32,31 +26,3 @@ impl PluginGroup for DefaultMemoryUsagePlugins {
3226
group.add(TransformMemoryUsagePlugin);
3327
}
3428
}
35-
36-
pub(crate) trait RegisterTypesWithEstimator: RegisterSizedTypes {
37-
fn register_component_with_estimator<T, E>(&mut self) -> &mut Self
38-
where
39-
T: Any + Component,
40-
E: DataSizeEstimator<T> + Default + 'static,
41-
{
42-
self.register_sized_type::<T, _, _>(systems::update_stats_for_component::<T, E>)
43-
}
44-
45-
fn register_resource_with_estimator<T, E>(&mut self) -> &mut Self
46-
where
47-
T: Any + Resource,
48-
E: DataSizeEstimator<T> + Default + 'static,
49-
{
50-
self.register_sized_type::<T, _, _>(systems::update_stats_for_resource::<T, E>)
51-
}
52-
53-
fn register_asset_with_estimator<T, E>(&mut self) -> &mut Self
54-
where
55-
T: Any + Asset,
56-
E: DataSizeEstimator<T> + Default + 'static,
57-
{
58-
self.register_sized_type::<T, _, _>(systems::update_stats_for_asset::<T, E>)
59-
}
60-
}
61-
62-
impl RegisterTypesWithEstimator for App {}

src/builtins/render/image.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Memory usage tracking for Bevy's [`Image`] type.
22
use bevy::{app::Plugin, render::texture::Image};
33

4-
use crate::{builtins::RegisterTypesWithEstimator, DataSize, DataSizeEstimator};
4+
use crate::{app_ext::RegisterTypesWithEstimator, DataSize, DataSizeEstimator};
55

66
/// Adds memory tracking for [`Image`] assets.
77
#[derive(Debug, Default)]

src/builtins/render/material.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Memory usage tracking for Bevy's [`Image`] type.
22
use bevy::{app::Plugin, pbr::StandardMaterial};
33

4-
use crate::{builtins::RegisterTypesWithEstimator, estimator::ZeroEstimator};
4+
use crate::{app_ext::RegisterTypesWithEstimator, estimator::ZeroEstimator};
55

66
/// Adds memory tracking for [`StandardMaterial`] assets.
77
#[derive(Debug, Default)]

0 commit comments

Comments
 (0)