Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_render/src/texture/texture_cache.rs
6596 views
1
use crate::{
2
render_resource::{Texture, TextureView},
3
renderer::RenderDevice,
4
};
5
use bevy_ecs::{prelude::ResMut, resource::Resource};
6
use bevy_platform::collections::{hash_map::Entry, HashMap};
7
use wgpu::{TextureDescriptor, TextureViewDescriptor};
8
9
/// The internal representation of a [`CachedTexture`] used to track whether it was recently used
10
/// and is currently taken.
11
struct CachedTextureMeta {
12
texture: Texture,
13
default_view: TextureView,
14
taken: bool,
15
frames_since_last_use: usize,
16
}
17
18
/// A cached GPU [`Texture`] with corresponding [`TextureView`].
19
///
20
/// This is useful for textures that are created repeatedly (each frame) in the rendering process
21
/// to reduce the amount of GPU memory allocations.
22
#[derive(Clone)]
23
pub struct CachedTexture {
24
pub texture: Texture,
25
pub default_view: TextureView,
26
}
27
28
/// This resource caches textures that are created repeatedly in the rendering process and
29
/// are only required for one frame.
30
#[derive(Resource, Default)]
31
pub struct TextureCache {
32
textures: HashMap<TextureDescriptor<'static>, Vec<CachedTextureMeta>>,
33
}
34
35
impl TextureCache {
36
/// Retrieves a texture that matches the `descriptor`. If no matching one is found a new
37
/// [`CachedTexture`] is created.
38
pub fn get(
39
&mut self,
40
render_device: &RenderDevice,
41
descriptor: TextureDescriptor<'static>,
42
) -> CachedTexture {
43
match self.textures.entry(descriptor) {
44
Entry::Occupied(mut entry) => {
45
for texture in entry.get_mut().iter_mut() {
46
if !texture.taken {
47
texture.frames_since_last_use = 0;
48
texture.taken = true;
49
return CachedTexture {
50
texture: texture.texture.clone(),
51
default_view: texture.default_view.clone(),
52
};
53
}
54
}
55
56
let texture = render_device.create_texture(&entry.key().clone());
57
let default_view = texture.create_view(&TextureViewDescriptor::default());
58
entry.get_mut().push(CachedTextureMeta {
59
texture: texture.clone(),
60
default_view: default_view.clone(),
61
frames_since_last_use: 0,
62
taken: true,
63
});
64
CachedTexture {
65
texture,
66
default_view,
67
}
68
}
69
Entry::Vacant(entry) => {
70
let texture = render_device.create_texture(entry.key());
71
let default_view = texture.create_view(&TextureViewDescriptor::default());
72
entry.insert(vec![CachedTextureMeta {
73
texture: texture.clone(),
74
default_view: default_view.clone(),
75
taken: true,
76
frames_since_last_use: 0,
77
}]);
78
CachedTexture {
79
texture,
80
default_view,
81
}
82
}
83
}
84
}
85
86
/// Returns `true` if the texture cache contains no textures.
87
pub fn is_empty(&self) -> bool {
88
self.textures.is_empty()
89
}
90
91
/// Updates the cache and only retains recently used textures.
92
pub fn update(&mut self) {
93
self.textures.retain(|_, textures| {
94
for texture in textures.iter_mut() {
95
texture.frames_since_last_use += 1;
96
texture.taken = false;
97
}
98
99
textures.retain(|texture| texture.frames_since_last_use < 3);
100
!textures.is_empty()
101
});
102
}
103
}
104
105
/// Updates the [`TextureCache`] to only retains recently used textures.
106
pub fn update_texture_cache_system(mut texture_cache: ResMut<TextureCache>) {
107
texture_cache.update();
108
}
109
110