fyrox_impl/renderer/cache/
texture.rs1use crate::{
22 core::log::{Log, MessageKind},
23 renderer::{
24 cache::{TemporaryCache, TimeToLive},
25 framework::{
26 error::FrameworkError,
27 gpu_texture::{Coordinate, GpuTexture, PixelKind},
28 server::GraphicsServer,
29 },
30 },
31 resource::texture::{Texture, TextureResource},
32};
33use fyrox_graphics::gpu_texture::{
34 GpuTextureDescriptor, GpuTextureKind, MagnificationFilter, MinificationFilter, WrapMode,
35};
36use fyrox_texture::{
37 TextureKind, TextureMagnificationFilter, TextureMinificationFilter, TexturePixelKind,
38 TextureWrapMode,
39};
40use std::{cell::RefCell, rc::Rc};
41
42pub(crate) struct TextureRenderData {
43 pub gpu_texture: Rc<RefCell<dyn GpuTexture>>,
44 pub modifications_counter: u64,
45}
46
47#[derive(Default)]
48pub struct TextureCache {
49 cache: TemporaryCache<TextureRenderData>,
50}
51
52fn convert_texture_kind(v: TextureKind) -> GpuTextureKind {
53 match v {
54 TextureKind::Line { length } => GpuTextureKind::Line {
55 length: length as usize,
56 },
57 TextureKind::Rectangle { width, height } => GpuTextureKind::Rectangle {
58 width: width as usize,
59 height: height as usize,
60 },
61 TextureKind::Cube { width, height } => GpuTextureKind::Cube {
62 width: width as usize,
63 height: height as usize,
64 },
65 TextureKind::Volume {
66 width,
67 height,
68 depth,
69 } => GpuTextureKind::Volume {
70 width: width as usize,
71 height: height as usize,
72 depth: depth as usize,
73 },
74 }
75}
76
77fn convert_pixel_kind(texture_kind: TexturePixelKind) -> PixelKind {
78 match texture_kind {
79 TexturePixelKind::R8 => PixelKind::R8,
80 TexturePixelKind::RGB8 => PixelKind::RGB8,
81 TexturePixelKind::RGBA8 => PixelKind::RGBA8,
82 TexturePixelKind::RG8 => PixelKind::RG8,
83 TexturePixelKind::R16 => PixelKind::R16,
84 TexturePixelKind::RG16 => PixelKind::RG16,
85 TexturePixelKind::BGR8 => PixelKind::BGR8,
86 TexturePixelKind::BGRA8 => PixelKind::BGRA8,
87 TexturePixelKind::RGB16 => PixelKind::RGB16,
88 TexturePixelKind::RGBA16 => PixelKind::RGBA16,
89 TexturePixelKind::RGB16F => PixelKind::RGB16F,
90 TexturePixelKind::DXT1RGB => PixelKind::DXT1RGB,
91 TexturePixelKind::DXT1RGBA => PixelKind::DXT1RGBA,
92 TexturePixelKind::DXT3RGBA => PixelKind::DXT3RGBA,
93 TexturePixelKind::DXT5RGBA => PixelKind::DXT5RGBA,
94 TexturePixelKind::R8RGTC => PixelKind::R8RGTC,
95 TexturePixelKind::RG8RGTC => PixelKind::RG8RGTC,
96 TexturePixelKind::RGB32F => PixelKind::RGB32F,
97 TexturePixelKind::RGBA32F => PixelKind::RGBA32F,
98 TexturePixelKind::Luminance8 => PixelKind::L8,
99 TexturePixelKind::LuminanceAlpha8 => PixelKind::LA8,
100 TexturePixelKind::Luminance16 => PixelKind::L16,
101 TexturePixelKind::LuminanceAlpha16 => PixelKind::LA16,
102 TexturePixelKind::R32F => PixelKind::R32F,
103 TexturePixelKind::R16F => PixelKind::R16F,
104 }
105}
106
107fn convert_magnification_filter(v: TextureMagnificationFilter) -> MagnificationFilter {
108 match v {
109 TextureMagnificationFilter::Nearest => MagnificationFilter::Nearest,
110 TextureMagnificationFilter::Linear => MagnificationFilter::Linear,
111 }
112}
113
114fn convert_minification_filter(v: TextureMinificationFilter) -> MinificationFilter {
115 match v {
116 TextureMinificationFilter::Nearest => MinificationFilter::Nearest,
117 TextureMinificationFilter::NearestMipMapNearest => MinificationFilter::NearestMipMapNearest,
118 TextureMinificationFilter::NearestMipMapLinear => MinificationFilter::NearestMipMapLinear,
119 TextureMinificationFilter::Linear => MinificationFilter::Linear,
120 TextureMinificationFilter::LinearMipMapNearest => MinificationFilter::LinearMipMapNearest,
121 TextureMinificationFilter::LinearMipMapLinear => MinificationFilter::LinearMipMapLinear,
122 }
123}
124
125fn convert_wrap_mode(v: TextureWrapMode) -> WrapMode {
126 match v {
127 TextureWrapMode::Repeat => WrapMode::Repeat,
128 TextureWrapMode::ClampToEdge => WrapMode::ClampToEdge,
129 TextureWrapMode::ClampToBorder => WrapMode::ClampToBorder,
130 TextureWrapMode::MirroredRepeat => WrapMode::MirroredRepeat,
131 TextureWrapMode::MirrorClampToEdge => WrapMode::MirrorClampToEdge,
132 }
133}
134
135fn create_gpu_texture(
136 server: &dyn GraphicsServer,
137 texture: &Texture,
138) -> Result<TextureRenderData, FrameworkError> {
139 server
140 .create_texture(GpuTextureDescriptor {
141 kind: convert_texture_kind(texture.kind()),
142 pixel_kind: convert_pixel_kind(texture.pixel_kind()),
143 mag_filter: convert_magnification_filter(texture.magnification_filter()),
144 min_filter: convert_minification_filter(texture.minification_filter()),
145 mip_count: texture.mip_count() as usize,
146 s_wrap_mode: convert_wrap_mode(texture.s_wrap_mode()),
147 t_wrap_mode: convert_wrap_mode(texture.t_wrap_mode()),
148 r_wrap_mode: convert_wrap_mode(texture.r_wrap_mode()),
149 anisotropy: texture.anisotropy_level(),
150 data: Some(texture.data()),
151 base_level: texture.base_level(),
152 max_level: texture.max_level(),
153 min_lod: texture.min_lod(),
154 max_lod: texture.max_lod(),
155 lod_bias: texture.lod_bias(),
156 })
157 .map(|gpu_texture| TextureRenderData {
158 gpu_texture,
159 modifications_counter: texture.modifications_count(),
160 })
161}
162
163impl TextureCache {
164 pub fn upload(
167 &mut self,
168 server: &dyn GraphicsServer,
169 texture: &TextureResource,
170 ) -> Result<(), FrameworkError> {
171 let mut texture = texture.state();
172 if let Some(texture) = texture.data() {
173 self.cache.get_entry_mut_or_insert_with(
174 &texture.cache_index,
175 Default::default(),
176 || create_gpu_texture(server, texture),
177 )?;
178 Ok(())
179 } else {
180 Err(FrameworkError::Custom(
181 "Texture is not loaded yet!".to_string(),
182 ))
183 }
184 }
185
186 pub fn get(
187 &mut self,
188 server: &dyn GraphicsServer,
189 texture_resource: &TextureResource,
190 ) -> Option<&Rc<RefCell<dyn GpuTexture>>> {
191 let mut texture_data_guard = texture_resource.state();
192
193 if let Some(texture) = texture_data_guard.data() {
194 match self.cache.get_mut_or_insert_with(
195 &texture.cache_index,
196 Default::default(),
197 || create_gpu_texture(server, texture),
198 ) {
199 Ok(entry) => {
200 let modifications_count = texture.modifications_count();
204 if entry.modifications_counter != modifications_count {
205 let mut gpu_texture = entry.gpu_texture.borrow_mut();
206 if let Err(e) = gpu_texture.set_data(
207 convert_texture_kind(texture.kind()),
208 convert_pixel_kind(texture.pixel_kind()),
209 texture.mip_count() as usize,
210 Some(texture.data()),
211 ) {
212 Log::writeln(
213 MessageKind::Error,
214 format!("Unable to upload new texture data to GPU. Reason: {e:?}"),
215 )
216 } else {
217 entry.modifications_counter = modifications_count;
218 }
219 }
220
221 let mut gpu_texture = entry.gpu_texture.borrow_mut();
222
223 let new_mag_filter =
224 convert_magnification_filter(texture.magnification_filter());
225 if gpu_texture.magnification_filter() != new_mag_filter {
226 gpu_texture.set_magnification_filter(new_mag_filter);
227 }
228
229 let new_min_filter = convert_minification_filter(texture.minification_filter());
230 if gpu_texture.minification_filter() != new_min_filter {
231 gpu_texture.set_minification_filter(new_min_filter);
232 }
233
234 if gpu_texture.anisotropy().ne(&texture.anisotropy_level()) {
235 gpu_texture.set_anisotropy(texture.anisotropy_level());
236 }
237
238 let new_s_wrap_mode = convert_wrap_mode(texture.s_wrap_mode());
239 if gpu_texture.wrap_mode(Coordinate::S) != new_s_wrap_mode {
240 gpu_texture.set_wrap(Coordinate::S, new_s_wrap_mode);
241 }
242
243 let new_t_wrap_mode = convert_wrap_mode(texture.t_wrap_mode());
244 if gpu_texture.wrap_mode(Coordinate::T) != new_t_wrap_mode {
245 gpu_texture.set_wrap(Coordinate::T, new_t_wrap_mode);
246 }
247
248 let new_r_wrap_mode = convert_wrap_mode(texture.r_wrap_mode());
249 if gpu_texture.wrap_mode(Coordinate::R) != new_r_wrap_mode {
250 gpu_texture.set_wrap(Coordinate::R, new_r_wrap_mode);
251 }
252
253 return Some(&entry.gpu_texture);
254 }
255 Err(e) => {
256 drop(texture_data_guard);
257 Log::writeln(
258 MessageKind::Error,
259 format!(
260 "Failed to create GPU texture from {} texture. Reason: {:?}",
261 texture_resource.kind(),
262 e
263 ),
264 );
265 }
266 }
267 }
268 None
269 }
270
271 pub fn update(&mut self, dt: f32) {
272 self.cache.update(dt)
273 }
274
275 pub fn clear(&mut self) {
276 self.cache.clear();
277 }
278
279 pub fn unload(&mut self, texture: TextureResource) {
280 if let Some(texture) = texture.state().data() {
281 self.cache.remove(&texture.cache_index);
282 }
283 }
284
285 pub fn alive_count(&self) -> usize {
286 self.cache.alive_count()
287 }
288
289 pub fn try_register(
293 &mut self,
294 texture: &TextureResource,
295 gpu_texture: Rc<RefCell<dyn GpuTexture>>,
296 ) {
297 let data = texture.data_ref();
298 let index = data.cache_index.clone();
299 let entry = self.cache.get_mut(&index);
300 if entry.is_none() {
301 self.cache.spawn(
302 TextureRenderData {
303 gpu_texture,
304 modifications_counter: data.modifications_count(),
305 },
306 index,
307 TimeToLive::default(),
308 );
309 }
310 }
311}