Skip to main content

ascending_graphics/atlas_set/
migration.rs

1use crate::{Allocation, Atlas, AtlasSet, GraphicsError};
2use std::hash::Hash;
3use wgpu::CommandEncoder;
4
5#[derive(Debug, Default, Clone)]
6/// Used to Migrate Textures from One Texture to Another to Eliminate possible fragmentation.
7pub struct MigrationTask {
8    /// Textures being migrated to an Avaliable Texture not migrating.
9    pub migrating: Vec<usize>,
10    /// Textures that dont need migration and Have extra space to try against.
11    pub avaliable: Vec<usize>,
12}
13
14impl<U: Hash + Eq + Clone, Data: Copy + Default> AtlasSet<U, Data> {
15    fn add_empty_layer(
16        &mut self,
17        task: &mut MigrationTask,
18    ) -> Result<usize, GraphicsError> {
19        if self.layers.len() + 1 == self.max_layers {
20            return Err(GraphicsError::AtlasMaxLayers);
21        }
22
23        let layer = Atlas::new(self.size);
24
25        self.layers.push(layer);
26        task.avaliable.push(self.layers.len() - 1);
27        Ok(self.layers.len() - 1)
28    }
29
30    pub(crate) fn migrate_reallocate(
31        &mut self,
32        task: &mut MigrationTask,
33    ) -> Result<Vec<(usize, Allocation<Data>)>, GraphicsError> {
34        let mut migrated = Vec::with_capacity(32);
35        let migrating: Vec<(usize, Allocation<Data>)>;
36
37        //Tis be fragmented heavily my lord. We need more layers!
38        if task.avaliable.is_empty() {
39            let _ = self.add_empty_layer(task)?;
40        }
41
42        let migrating_layer_id =
43            task.migrating.pop().ok_or(GraphicsError::DefragFailed)?;
44
45        // Lets Gather all the ones we want to Migrate that Exist within the Layer we
46        // are working with in this round.
47        if let Some(layer) = self.layers.get_mut(migrating_layer_id) {
48            migrating = layer
49                .allocated
50                .clone()
51                .into_iter()
52                .filter_map(|alloc_id| {
53                    if let Some((allocation, _hash)) = self.peek(alloc_id) {
54                        Some((alloc_id, *allocation))
55                    } else {
56                        None
57                    }
58                })
59                .collect();
60        } else {
61            migrating = vec![];
62        }
63
64        'outer: for (id, allocation) in migrating {
65            // Try to place object in another created Texture thats not migrating.
66            for layer_id in &task.avaliable {
67                if let Some(layer) = self.layers.get_mut(*layer_id) {
68                    let rect = allocation.allocation.rectangle;
69
70                    if let Some(alloc) = layer
71                        .allocator
72                        .allocate(rect.width() as u32, rect.height() as u32)
73                    {
74                        migrated.push((
75                            id,
76                            Allocation {
77                                allocation: alloc,
78                                layer: *layer_id,
79                                data: allocation.data,
80                            },
81                        ));
82                        continue 'outer;
83                    }
84                }
85            }
86
87            // If failed to place then we do need a new layer.
88            let layer_id = self.add_empty_layer(task)?;
89
90            if let Some(layer) = self.layers.get_mut(layer_id) {
91                let rect = allocation.allocation.rectangle;
92
93                if let Some(alloc) = layer
94                    .allocator
95                    .allocate(rect.width() as u32, rect.height() as u32)
96                {
97                    migrated.push((
98                        id,
99                        Allocation {
100                            allocation: alloc,
101                            layer: layer_id,
102                            data: allocation.data,
103                        },
104                    ));
105                    continue 'outer;
106                }
107            }
108
109            // We reached the end of the line. All hope is lost lets return None.
110            return Err(GraphicsError::DefragFailed);
111        }
112
113        task.avaliable.push(migrating_layer_id);
114        // we can clear this old layer now since we dont care about whats in here now.
115        self.layers
116            .get_mut(migrating_layer_id)
117            .ok_or(GraphicsError::DefragFailed)?
118            .clear();
119        Ok(migrated)
120    }
121
122    pub fn migrate_allocation(
123        &mut self,
124        old_allocation: &Allocation<Data>,
125        allocation: &Allocation<Data>,
126        encoder: &mut CommandEncoder,
127    ) {
128        let (x, y) = allocation.position();
129        let (width, height) = allocation.size();
130        let layer = allocation.layer;
131
132        let (o_x, o_y) = old_allocation.position();
133        let o_layer = old_allocation.layer;
134
135        encoder.copy_texture_to_texture(
136            wgpu::TexelCopyTextureInfo {
137                texture: &self.texture,
138                mip_level: 0,
139                origin: wgpu::Origin3d {
140                    x: o_x,
141                    y: o_y,
142                    z: o_layer as u32,
143                },
144                aspect: wgpu::TextureAspect::All,
145            },
146            wgpu::TexelCopyTextureInfo {
147                texture: &self.texture,
148                mip_level: 0,
149                origin: wgpu::Origin3d {
150                    x,
151                    y,
152                    z: layer as u32,
153                },
154                aspect: wgpu::TextureAspect::All,
155            },
156            wgpu::Extent3d {
157                width,
158                height,
159                depth_or_array_layers: 1,
160            },
161        );
162    }
163}