primase_core/
unreferenced.rs1use crate::pass::{Pass, PassLog, PassSpec};
5use crate::{Texture, TextureFile, Transform, World};
6
7#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
13pub struct DropUnreferencedTextures;
14
15pub const DROP_UNREFERENCED_TEXTURES: PassSpec = PassSpec {
17 name: "drop-unreferenced-textures",
18 options: &[],
19 make: |_| Ok(Box::new(DropUnreferencedTextures)),
20};
21
22impl Pass for DropUnreferencedTextures {
23 fn name(&self) -> &'static str {
24 "drop-unreferenced-textures"
25 }
26 fn despawns_entities(&self) -> bool {
27 true
28 }
29 fn run(&self, w: &mut World, log: &mut PassLog) -> Result<(), String> {
30 let dropped: Vec<_> = w
31 .unreferenced()
32 .into_iter()
33 .filter(|&e| (w.has::<Texture>(e) || w.has::<TextureFile>(e)) && !w.has::<Transform>(e))
34 .collect();
35 let bytes: usize = dropped
36 .iter()
37 .filter_map(|&e| w.get::<Texture>(e))
38 .flat_map(|t| t.levels.iter().map(Vec::len))
39 .sum();
40 log.count("unreferenced textures dropped", dropped.len() as u64);
41 log.count("bytes of the unreferenced textures' loaded levels", bytes as u64);
42 for e in dropped {
43 crate::ledger::despawn(w, e, log, "textures nothing refers to");
44 }
45 Ok(())
46 }
47}
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52 use crate::pass::{PassManager, PassRegistry, Pipeline, RunReport};
53 use crate::pbr::{PbrMaterial, TextureRef};
54 use crate::{ColorSpace, Name, TexFormat, TexRole};
55
56 fn texture(w: &mut World, name: &str) -> crate::Entity {
57 let e = w.spawn();
58 w.insert(e, Name(name.into()));
59 w.insert(
60 e,
61 Texture {
62 width: 1,
63 height: 1,
64 format: TexFormat::Rgba8Unorm,
65 levels: vec![vec![1, 2, 3, 4]],
66 color_space: ColorSpace::Srgb,
67 role: TexRole::Color,
68 normal: None,
69 },
70 );
71 e
72 }
73
74 #[test]
77 fn a_texture_nothing_refers_to_is_dropped_and_counted() {
78 let mut w = World::new();
79 let bound = texture(&mut w, "bound");
80 let placed = texture(&mut w, "placed");
81 w.insert(placed, Transform::IDENTITY);
82 let loose = texture(&mut w, "loose");
83 let material = w.spawn();
84 w.insert(
85 material,
86 PbrMaterial {
87 base_color_texture: Some(TextureRef::new(bound)),
88 ..Default::default()
89 },
90 );
91 let mut report = RunReport::default();
92 PassManager::new(PassRegistry::new())
93 .with_pass_checks(true)
94 .run(
95 &mut w,
96 &Pipeline {
97 passes: vec![Box::new(DropUnreferencedTextures)],
98 },
99 &mut report,
100 )
101 .unwrap();
102 assert!(w.is_alive(bound) && w.is_alive(placed) && !w.is_alive(loose));
103 let counts = &report.steps[0].log.counts;
104 assert_eq!(counts["unreferenced textures dropped"], 1);
105 assert_eq!(counts["bytes of the unreferenced textures' loaded levels"], 4);
106 }
107}