1use metal::{MTLPixelFormat, TextureDescriptor, TextureRef};
2
3use super::atlas::{AllocId, AtlasAllocator};
4use crate::{
5 geometry::{rect::RectI, vector::Vector2I},
6 ImageData,
7};
8use std::{collections::HashMap, mem};
9
10pub struct ImageCache {
11 prev_frame: HashMap<usize, (AllocId, RectI)>,
12 curr_frame: HashMap<usize, (AllocId, RectI)>,
13 atlases: AtlasAllocator,
14}
15
16impl ImageCache {
17 pub fn new(device: metal::Device, size: Vector2I) -> Self {
18 let descriptor = TextureDescriptor::new();
19 descriptor.set_pixel_format(MTLPixelFormat::BGRA8Unorm);
20 descriptor.set_width(size.x() as u64);
21 descriptor.set_height(size.y() as u64);
22 Self {
23 prev_frame: Default::default(),
24 curr_frame: Default::default(),
25 atlases: AtlasAllocator::new(device, descriptor),
26 }
27 }
28
29 pub fn render(&mut self, image: &ImageData) -> (AllocId, RectI) {
30 let (alloc_id, atlas_bounds) = self
31 .prev_frame
32 .remove(&image.id)
33 .or_else(|| self.curr_frame.get(&image.id).copied())
34 .unwrap_or_else(|| self.atlases.upload(image.size(), image.as_bytes()));
35 self.curr_frame.insert(image.id, (alloc_id, atlas_bounds));
36 (alloc_id, atlas_bounds)
37 }
38
39 pub fn finish_frame(&mut self) {
40 mem::swap(&mut self.prev_frame, &mut self.curr_frame);
41 for (_, (id, _)) in self.curr_frame.drain() {
42 self.atlases.deallocate(id);
43 }
44 }
45
46 pub fn atlas_texture(&self, atlas_id: usize) -> Option<&TextureRef> {
47 self.atlases.texture(atlas_id)
48 }
49}