From 4e7159c22c6be90f61aa715d5eb6811f805cb597 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 28 Feb 2020 14:38:42 +0100 Subject: Stop creating image pipeline when unnecessary --- wgpu/src/texture/atlas.rs | 361 ---------------------------------------------- 1 file changed, 361 deletions(-) delete mode 100644 wgpu/src/texture/atlas.rs (limited to 'wgpu/src/texture/atlas.rs') diff --git a/wgpu/src/texture/atlas.rs b/wgpu/src/texture/atlas.rs deleted file mode 100644 index 86a5ff49..00000000 --- a/wgpu/src/texture/atlas.rs +++ /dev/null @@ -1,361 +0,0 @@ -pub mod entry; - -mod allocation; -mod allocator; -mod layer; - -pub use allocation::Allocation; -pub use entry::Entry; -pub use layer::Layer; - -use allocator::Allocator; - -pub const SIZE: u32 = 2048; - -#[derive(Debug)] -pub struct Atlas { - texture: wgpu::Texture, - texture_view: wgpu::TextureView, - layers: Vec, -} - -impl Atlas { - pub fn new(device: &wgpu::Device) -> Self { - let extent = wgpu::Extent3d { - width: SIZE, - height: SIZE, - depth: 1, - }; - - let texture = device.create_texture(&wgpu::TextureDescriptor { - size: extent, - array_layer_count: 2, - mip_level_count: 1, - sample_count: 1, - dimension: wgpu::TextureDimension::D2, - format: wgpu::TextureFormat::Bgra8UnormSrgb, - usage: wgpu::TextureUsage::COPY_DST - | wgpu::TextureUsage::COPY_SRC - | wgpu::TextureUsage::SAMPLED, - }); - - let texture_view = texture.create_default_view(); - - Atlas { - texture, - texture_view, - layers: vec![Layer::Empty, Layer::Empty], - } - } - - pub fn view(&self) -> &wgpu::TextureView { - &self.texture_view - } - - pub fn layer_count(&self) -> usize { - self.layers.len() - } - - pub fn upload( - &mut self, - width: u32, - height: u32, - data: &[C], - device: &wgpu::Device, - encoder: &mut wgpu::CommandEncoder, - ) -> Option - where - C: Copy + 'static, - { - let entry = { - let current_size = self.layers.len(); - let entry = self.allocate(width, height)?; - - // We grow the internal texture after allocating if necessary - let new_layers = self.layers.len() - current_size; - self.grow(new_layers, device, encoder); - - entry - }; - - log::info!("Allocated atlas entry: {:?}", entry); - - let buffer = device - .create_buffer_mapped(data.len(), wgpu::BufferUsage::COPY_SRC) - .fill_from_slice(data); - - match &entry { - Entry::Contiguous(allocation) => { - self.upload_allocation( - &buffer, - width, - height, - 0, - &allocation, - encoder, - ); - } - Entry::Fragmented { fragments, .. } => { - for fragment in fragments { - let (x, y) = fragment.position; - let offset = (y * width + x) as usize * 4; - - self.upload_allocation( - &buffer, - width, - height, - offset, - &fragment.allocation, - encoder, - ); - } - } - } - - log::info!("Current atlas: {:?}", self); - - Some(entry) - } - - pub fn remove(&mut self, entry: &Entry) { - log::info!("Removing atlas entry: {:?}", entry); - - match entry { - Entry::Contiguous(allocation) => { - self.deallocate(allocation); - } - Entry::Fragmented { fragments, .. } => { - for fragment in fragments { - self.deallocate(&fragment.allocation); - } - } - } - } - - fn allocate(&mut self, width: u32, height: u32) -> Option { - // Allocate one layer if texture fits perfectly - if width == SIZE && height == SIZE { - let mut empty_layers = self - .layers - .iter_mut() - .enumerate() - .filter(|(_, layer)| layer.is_empty()); - - if let Some((i, layer)) = empty_layers.next() { - *layer = Layer::Full; - - return Some(Entry::Contiguous(Allocation::Full { layer: i })); - } - - self.layers.push(Layer::Full); - - return Some(Entry::Contiguous(Allocation::Full { - layer: self.layers.len() - 1, - })); - } - - // Split big textures across multiple layers - if width > SIZE || height > SIZE { - let mut fragments = Vec::new(); - let mut y = 0; - - while y < height { - let height = std::cmp::min(height - y, SIZE); - let mut x = 0; - - while x < width { - let width = std::cmp::min(width - x, SIZE); - - let allocation = self.allocate(width, height)?; - - if let Entry::Contiguous(allocation) = allocation { - fragments.push(entry::Fragment { - position: (x, y), - allocation, - }); - } - - x += width; - } - - y += height; - } - - return Some(Entry::Fragmented { - size: (width, height), - fragments, - }); - } - - // Try allocating on an existing layer - for (i, layer) in self.layers.iter_mut().enumerate() { - match layer { - Layer::Empty => { - let mut allocator = Allocator::new(SIZE); - - if let Some(region) = allocator.allocate(width, height) { - *layer = Layer::Busy(allocator); - - return Some(Entry::Contiguous(Allocation::Partial { - region, - layer: i, - })); - } - } - Layer::Busy(allocator) => { - if let Some(region) = allocator.allocate(width, height) { - return Some(Entry::Contiguous(Allocation::Partial { - region, - layer: i, - })); - } - } - _ => {} - } - } - - // Create new layer with atlas allocator - let mut allocator = Allocator::new(SIZE); - - if let Some(region) = allocator.allocate(width, height) { - self.layers.push(Layer::Busy(allocator)); - - return Some(Entry::Contiguous(Allocation::Partial { - region, - layer: self.layers.len() - 1, - })); - } - - // We ran out of memory (?) - None - } - - fn deallocate(&mut self, allocation: &Allocation) { - log::info!("Deallocating atlas: {:?}", allocation); - - match allocation { - Allocation::Full { layer } => { - self.layers[*layer] = Layer::Empty; - } - Allocation::Partial { layer, region } => { - let layer = &mut self.layers[*layer]; - - if let Layer::Busy(allocator) = layer { - allocator.deallocate(region); - - if allocator.is_empty() { - *layer = Layer::Empty; - } - } - } - } - } - - fn upload_allocation( - &mut self, - buffer: &wgpu::Buffer, - image_width: u32, - image_height: u32, - offset: usize, - allocation: &Allocation, - encoder: &mut wgpu::CommandEncoder, - ) { - let (x, y) = allocation.position(); - let (width, height) = allocation.size(); - let layer = allocation.layer(); - - let extent = wgpu::Extent3d { - width, - height, - depth: 1, - }; - - encoder.copy_buffer_to_texture( - wgpu::BufferCopyView { - buffer, - offset: offset as u64, - row_pitch: 4 * image_width, - image_height, - }, - wgpu::TextureCopyView { - texture: &self.texture, - array_layer: layer as u32, - mip_level: 0, - origin: wgpu::Origin3d { - x: x as f32, - y: y as f32, - z: 0.0, - }, - }, - extent, - ); - } - - fn grow( - &mut self, - amount: usize, - device: &wgpu::Device, - encoder: &mut wgpu::CommandEncoder, - ) { - if amount == 0 { - return; - } - - let new_texture = device.create_texture(&wgpu::TextureDescriptor { - size: wgpu::Extent3d { - width: SIZE, - height: SIZE, - depth: 1, - }, - array_layer_count: self.layers.len() as u32, - mip_level_count: 1, - sample_count: 1, - dimension: wgpu::TextureDimension::D2, - format: wgpu::TextureFormat::Bgra8UnormSrgb, - usage: wgpu::TextureUsage::COPY_DST - | wgpu::TextureUsage::COPY_SRC - | wgpu::TextureUsage::SAMPLED, - }); - - let amount_to_copy = self.layers.len() - amount; - - for (i, layer) in - self.layers.iter_mut().take(amount_to_copy).enumerate() - { - if layer.is_empty() { - continue; - } - - encoder.copy_texture_to_texture( - wgpu::TextureCopyView { - texture: &self.texture, - array_layer: i as u32, - mip_level: 0, - origin: wgpu::Origin3d { - x: 0.0, - y: 0.0, - z: 0.0, - }, - }, - wgpu::TextureCopyView { - texture: &new_texture, - array_layer: i as u32, - mip_level: 0, - origin: wgpu::Origin3d { - x: 0.0, - y: 0.0, - z: 0.0, - }, - }, - wgpu::Extent3d { - width: SIZE, - height: SIZE, - depth: 1, - }, - ); - } - - self.texture = new_texture; - self.texture_view = self.texture.create_default_view(); - } -} -- cgit