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 ----------------------------------- wgpu/src/texture/atlas/allocation.rs | 35 ---- wgpu/src/texture/atlas/allocator.rs | 69 ------- wgpu/src/texture/atlas/entry.rs | 25 --- wgpu/src/texture/atlas/layer.rs | 17 -- 5 files changed, 507 deletions(-) delete mode 100644 wgpu/src/texture/atlas.rs delete mode 100644 wgpu/src/texture/atlas/allocation.rs delete mode 100644 wgpu/src/texture/atlas/allocator.rs delete mode 100644 wgpu/src/texture/atlas/entry.rs delete mode 100644 wgpu/src/texture/atlas/layer.rs (limited to 'wgpu/src/texture') 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(); - } -} diff --git a/wgpu/src/texture/atlas/allocation.rs b/wgpu/src/texture/atlas/allocation.rs deleted file mode 100644 index e17b3f8c..00000000 --- a/wgpu/src/texture/atlas/allocation.rs +++ /dev/null @@ -1,35 +0,0 @@ -use crate::texture::atlas::{self, allocator}; - -#[derive(Debug)] -pub enum Allocation { - Partial { - layer: usize, - region: allocator::Region, - }, - Full { - layer: usize, - }, -} - -impl Allocation { - pub fn position(&self) -> (u32, u32) { - match self { - Allocation::Partial { region, .. } => region.position(), - Allocation::Full { .. } => (0, 0), - } - } - - pub fn size(&self) -> (u32, u32) { - match self { - Allocation::Partial { region, .. } => region.size(), - Allocation::Full { .. } => (atlas::SIZE, atlas::SIZE), - } - } - - pub fn layer(&self) -> usize { - match self { - Allocation::Partial { layer, .. } => *layer, - Allocation::Full { layer } => *layer, - } - } -} diff --git a/wgpu/src/texture/atlas/allocator.rs b/wgpu/src/texture/atlas/allocator.rs deleted file mode 100644 index 7a4ff5b1..00000000 --- a/wgpu/src/texture/atlas/allocator.rs +++ /dev/null @@ -1,69 +0,0 @@ -use guillotiere::{AtlasAllocator, Size}; - -pub struct Allocator { - raw: AtlasAllocator, - allocations: usize, -} - -impl Allocator { - pub fn new(size: u32) -> Allocator { - let raw = AtlasAllocator::new(Size::new(size as i32, size as i32)); - - Allocator { - raw, - allocations: 0, - } - } - - pub fn allocate(&mut self, width: u32, height: u32) -> Option { - let allocation = - self.raw.allocate(Size::new(width as i32, height as i32))?; - - self.allocations += 1; - - Some(Region { allocation }) - } - - pub fn deallocate(&mut self, region: &Region) { - self.raw.deallocate(region.allocation.id); - - self.allocations = self.allocations.saturating_sub(1); - } - - pub fn is_empty(&self) -> bool { - self.allocations == 0 - } -} - -pub struct Region { - allocation: guillotiere::Allocation, -} - -impl Region { - pub fn position(&self) -> (u32, u32) { - let rectangle = &self.allocation.rectangle; - - (rectangle.min.x as u32, rectangle.min.y as u32) - } - - pub fn size(&self) -> (u32, u32) { - let size = self.allocation.rectangle.size(); - - (size.width as u32, size.height as u32) - } -} - -impl std::fmt::Debug for Allocator { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Allocator") - } -} - -impl std::fmt::Debug for Region { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("Region") - .field("id", &self.allocation.id) - .field("rectangle", &self.allocation.rectangle) - .finish() - } -} diff --git a/wgpu/src/texture/atlas/entry.rs b/wgpu/src/texture/atlas/entry.rs deleted file mode 100644 index 2c064665..00000000 --- a/wgpu/src/texture/atlas/entry.rs +++ /dev/null @@ -1,25 +0,0 @@ -use crate::texture::atlas; - -#[derive(Debug)] -pub enum Entry { - Contiguous(atlas::Allocation), - Fragmented { - size: (u32, u32), - fragments: Vec, - }, -} - -impl Entry { - pub fn size(&self) -> (u32, u32) { - match self { - Entry::Contiguous(allocation) => allocation.size(), - Entry::Fragmented { size, .. } => *size, - } - } -} - -#[derive(Debug)] -pub struct Fragment { - pub position: (u32, u32), - pub allocation: atlas::Allocation, -} diff --git a/wgpu/src/texture/atlas/layer.rs b/wgpu/src/texture/atlas/layer.rs deleted file mode 100644 index b025d8a1..00000000 --- a/wgpu/src/texture/atlas/layer.rs +++ /dev/null @@ -1,17 +0,0 @@ -use crate::texture::atlas::Allocator; - -#[derive(Debug)] -pub enum Layer { - Empty, - Busy(Allocator), - Full, -} - -impl Layer { - pub fn is_empty(&self) -> bool { - match self { - Layer::Empty => true, - _ => false, - } - } -} -- cgit