diff options
author | 2020-01-10 16:07:09 +0100 | |
---|---|---|
committer | 2020-02-25 13:26:50 +0100 | |
commit | 743637ebda8c3e4ba30f41e755ee1079ee66a86c (patch) | |
tree | dd0ebecf95e407c879e23c1bb7ab671200dd27e6 /wgpu/src | |
parent | 1bcfc9a5cce0b30c3ad9983e407c06e237b491f3 (diff) | |
download | iced-743637ebda8c3e4ba30f41e755ee1079ee66a86c.tar.gz iced-743637ebda8c3e4ba30f41e755ee1079ee66a86c.tar.bz2 iced-743637ebda8c3e4ba30f41e755ee1079ee66a86c.zip |
Merged image and svg texture atlases into one owned by the image pipeline.
Diffstat (limited to '')
-rw-r--r-- | wgpu/src/image.rs | 92 | ||||
-rw-r--r-- | wgpu/src/image/raster.rs | 79 | ||||
-rw-r--r-- | wgpu/src/image/vector.rs | 78 |
3 files changed, 90 insertions, 159 deletions
diff --git a/wgpu/src/image.rs b/wgpu/src/image.rs index 65780886..aaecd492 100644 --- a/wgpu/src/image.rs +++ b/wgpu/src/image.rs @@ -14,7 +14,10 @@ use std::mem; #[cfg(any(feature = "image", feature = "svg"))] use std::{cell::RefCell, collections::HashMap}; -#[derive(Debug)] +use guillotiere::{AtlasAllocator, Size}; +use debug_stub_derive::*; + +#[derive(DebugStub)] pub struct Pipeline { #[cfg(feature = "image")] raster_cache: RefCell<raster::Cache>, @@ -28,6 +31,9 @@ pub struct Pipeline { instances: wgpu::Buffer, constants: wgpu::BindGroup, texture_layout: wgpu::BindGroupLayout, + #[debug_stub="ReplacementValue"] + allocator: AtlasAllocator, + atlas: wgpu::Texture, } impl Pipeline { @@ -208,12 +214,32 @@ impl Pipeline { usage: wgpu::BufferUsage::VERTEX | wgpu::BufferUsage::COPY_DST, }); + let (width, height) = (512, 512); + + let extent = wgpu::Extent3d { + width, + height, + depth: 1, + }; + + let atlas = device.create_texture(&wgpu::TextureDescriptor { + size: extent, + array_layer_count: 1, + 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, + }); + Pipeline { #[cfg(feature = "image")] - raster_cache: RefCell::new(raster::Cache::new(&device)), + raster_cache: RefCell::new(raster::Cache::new()), #[cfg(feature = "svg")] - vector_cache: RefCell::new(vector::Cache::new(&device)), + vector_cache: RefCell::new(vector::Cache::new()), pipeline, uniforms: uniforms_buffer, @@ -222,6 +248,8 @@ impl Pipeline { instances, constants: constant_bind_group, texture_layout, + allocator: AtlasAllocator::new(Size::new(width as i32, height as i32)), + atlas, } } @@ -276,10 +304,12 @@ impl Pipeline { let mut raster_cache = self.raster_cache.borrow_mut(); if let Memory::Device(allocation) = raster_cache.upload( - _handle, + handle, device, - encoder) - { + encoder, + &mut self.allocator, + &mut self.atlas + ) { let rec = allocation.rectangle; let _ = recs.insert(index, rec); @@ -291,12 +321,15 @@ impl Pipeline { { let mut vector_cache = self.vector_cache.borrow_mut(); + // Upload rasterized svg to texture atlas if let Some(allocation) = vector_cache.upload( _handle, image.scale, _scale, device, encoder, + &mut self.allocator, + &mut self.atlas, ) { let rec = allocation.rectangle; @@ -307,30 +340,34 @@ impl Pipeline { } } - #[cfg(feature = "image")] - let raster_atlas = self.raster_cache.borrow().atlas(device, &self.texture_layout); - - #[cfg(feature = "svg")] - let vector_atlas = self.vector_cache.borrow().atlas(device, &self.texture_layout); + let atlas_width = self.allocator.size().width as f32; + let atlas_height = self.allocator.size().height as f32; + + let texture = device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &self.texture_layout, + bindings: &[wgpu::Binding { + binding: 0, + resource: wgpu::BindingResource::TextureView( + &self.atlas.create_default_view(), + ), + }], + }); #[cfg(any(feature = "image", feature = "svg"))] for (index, image) in instances.iter().enumerate() { if let Some(rec) = recs.get(&index) { - let atlas_size = match image.handle { - #[cfg(feature = "image")] - Handle::Raster(_) => self.raster_cache.borrow().atlas_size(), - #[cfg(feature = "svg")] - Handle::Vector(_) => self.vector_cache.borrow().atlas_size(), - _ => guillotiere::Size::new(0, 0) - }; + let x = rec.min.x as f32 / atlas_width; + let y = rec.min.y as f32 / atlas_height; + let w = (rec.size().width - 1) as f32 / atlas_width; + let h = (rec.size().height - 1) as f32 / atlas_height; let instance_buffer = device .create_buffer_mapped(1, wgpu::BufferUsage::COPY_SRC) .fill_from_slice(&[Instance { _position: image.position, _scale: image.scale, - _position_in_atlas: [rec.min.x as f32 / atlas_size.width as f32, rec.min.y as f32 / atlas_size.height as f32], - _scale_in_atlas: [rec.size().width as f32 / atlas_size.width as f32, rec.size().height as f32 / atlas_size.height as f32] + _position_in_atlas: [x, y], + _scale_in_atlas: [w, h] }]); encoder.copy_buffer_to_buffer( @@ -341,17 +378,6 @@ impl Pipeline { mem::size_of::<Instance>() as u64, ); - let texture = match &image.handle { - #[cfg(feature = "image")] - Handle::Raster(_) => &raster_atlas, - #[cfg(feature = "svg")] - Handle::Vector(_) => &vector_atlas, - #[cfg(feature = "image")] - _ => &raster_atlas, - #[cfg(feature = "svg")] - _ => &vector_atlas, - }; - let mut render_pass = encoder.begin_render_pass( &wgpu::RenderPassDescriptor { color_attachments: &[ @@ -398,10 +424,10 @@ impl Pipeline { pub fn trim_cache(&mut self) { #[cfg(feature = "image")] - self.raster_cache.borrow_mut().trim(); + self.raster_cache.borrow_mut().trim(&mut self.allocator); #[cfg(feature = "svg")] - self.vector_cache.borrow_mut().trim(); + self.vector_cache.borrow_mut().trim(&mut self.allocator); } } diff --git a/wgpu/src/image/raster.rs b/wgpu/src/image/raster.rs index 0418bc0b..651ec078 100644 --- a/wgpu/src/image/raster.rs +++ b/wgpu/src/image/raster.rs @@ -1,13 +1,14 @@ use iced_native::image; use std::{ collections::{HashMap, HashSet}, - fmt, }; use guillotiere::{Allocation, AtlasAllocator, Size}; +use debug_stub_derive::*; +#[derive(DebugStub)] pub enum Memory { Host(::image::ImageBuffer<::image::Bgra<u8>, Vec<u8>>), - Device(Allocation), + Device(#[debug_stub="ReplacementValue"]Allocation), NotFound, Invalid, } @@ -26,49 +27,15 @@ impl Memory { } } +#[derive(Debug)] pub struct Cache { - allocator: AtlasAllocator, - atlas: wgpu::Texture, map: HashMap<u64, Memory>, hits: HashSet<u64>, } -impl fmt::Debug for Cache { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_struct("Vector Cache") - .field("allocator", &String::from("AtlasAllocator")) - .field("atlas", &self.atlas) - .field("map", &String::from("HashMap<u64, Memory>")) - .field("hits", &self.hits) - .finish() - } -} - impl Cache { - pub fn new(device: &wgpu::Device) -> Self { - let (width, height) = (1000, 1000); - - let extent = wgpu::Extent3d { - width, - height, - depth: 1, - }; - - let atlas = device.create_texture(&wgpu::TextureDescriptor { - size: extent, - array_layer_count: 1, - 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, - }); - + pub fn new() -> Self { Self { - allocator: AtlasAllocator::new(Size::new(width as i32, height as i32)), - atlas, map: HashMap::new(), hits: HashSet::new(), } @@ -100,15 +67,13 @@ impl Cache { self.get(handle).unwrap() } - pub fn atlas_size(&self) -> guillotiere::Size { - self.allocator.size() - } - pub fn upload( &mut self, handle: &image::Handle, device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder, + allocator: &mut AtlasAllocator, + atlas: &mut wgpu::Texture, ) -> &Memory { let _ = self.load(handle); @@ -118,19 +83,19 @@ impl Cache { let (width, height) = image.dimensions(); let size = Size::new(width as i32, height as i32); - let old_atlas_size = self.allocator.size(); + let old_atlas_size = allocator.size(); let allocation; loop { - if let Some(a) = self.allocator.allocate(size) { + if let Some(a) = allocator.allocate(size) { allocation = a; break; } - self.allocator.grow(self.allocator.size() * 2); + allocator.grow(allocator.size() * 2); } - let new_atlas_size = self.allocator.size(); + let new_atlas_size = allocator.size(); if new_atlas_size != old_atlas_size { let new_atlas = device.create_texture(&wgpu::TextureDescriptor { @@ -151,7 +116,7 @@ impl Cache { encoder.copy_texture_to_texture( wgpu::TextureCopyView { - texture: &self.atlas, + texture: atlas, array_layer: 0, mip_level: 0, origin: wgpu::Origin3d { @@ -177,7 +142,7 @@ impl Cache { } ); - self.atlas = new_atlas; + *atlas = new_atlas; } let extent = wgpu::Extent3d { @@ -206,7 +171,7 @@ impl Cache { image_height: height, }, wgpu::TextureCopyView { - texture: &self.atlas, + texture: atlas, array_layer: 0, mip_level: 0, origin: wgpu::Origin3d { @@ -224,25 +189,13 @@ impl Cache { memory } - pub fn atlas(&self, device: &wgpu::Device, texture_layout: &wgpu::BindGroupLayout) -> wgpu::BindGroup { - device.create_bind_group(&wgpu::BindGroupDescriptor { - layout: texture_layout, - bindings: &[wgpu::Binding { - binding: 0, - resource: wgpu::BindingResource::TextureView( - &self.atlas.create_default_view(), - ), - }], - }) - } - - pub fn trim(&mut self) { + pub fn trim(&mut self, allocator: &mut AtlasAllocator) { let hits = &self.hits; for (id, mem) in &mut self.map { if let Memory::Device(allocation) = mem { if !hits.contains(&id) { - self.allocator.deallocate(allocation.id); + allocator.deallocate(allocation.id); } } } diff --git a/wgpu/src/image/vector.rs b/wgpu/src/image/vector.rs index 1a9352f2..89477877 100644 --- a/wgpu/src/image/vector.rs +++ b/wgpu/src/image/vector.rs @@ -4,6 +4,7 @@ use std::{ fmt, }; use guillotiere::{Allocation, AtlasAllocator, Size}; +use debug_stub_derive::*; pub enum Svg { Loaded { tree: resvg::usvg::Tree }, @@ -29,57 +30,22 @@ impl fmt::Debug for Svg { } } +#[derive(DebugStub)] pub struct Cache { - allocator: AtlasAllocator, - atlas: wgpu::Texture, svgs: HashMap<u64, Svg>, + #[debug_stub="ReplacementValue"] rasterized: HashMap<(u64, u32, u32), Allocation>, svg_hits: HashSet<u64>, rasterized_hits: HashSet<(u64, u32, u32)>, } -impl fmt::Debug for Cache { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_struct("Vector Cache") - .field("allocator", &String::from("AtlasAllocator")) - .field("atlas", &self.atlas) - .field("svgs", &self.svgs) - .field("rasterized", &String::from("HashMap<(u64, u32, u32), Allocation>")) - .field("svg_hits", &self.svg_hits) - .field("rasterized_hits", &self.rasterized_hits) - .finish() - } -} - impl Cache { - pub fn new(device: &wgpu::Device) -> Self { - let (width, height) = (512, 512); - - let extent = wgpu::Extent3d { - width, - height, - depth: 1, - }; - - let atlas = device.create_texture(&wgpu::TextureDescriptor { - size: extent, - array_layer_count: 1, - 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, - }); - + pub fn new() -> Self { Self { svgs: HashMap::new(), rasterized: HashMap::new(), svg_hits: HashSet::new(), rasterized_hits: HashSet::new(), - allocator: AtlasAllocator::new(Size::new(width as i32, height as i32)), - atlas, } } @@ -99,10 +65,6 @@ impl Cache { self.svgs.get(&handle.id()).unwrap() } - pub fn atlas_size(&self) -> guillotiere::Size { - self.allocator.size() - } - pub fn upload( &mut self, handle: &svg::Handle, @@ -110,6 +72,8 @@ impl Cache { scale: f32, device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder, + allocator: &mut AtlasAllocator, + atlas: &mut wgpu::Texture, ) -> Option<&Allocation> { let id = handle.id(); @@ -138,19 +102,19 @@ impl Cache { } let size = Size::new(width as i32, height as i32); - let old_atlas_size = self.allocator.size(); + let old_atlas_size = allocator.size(); let allocation; loop { - if let Some(a) = self.allocator.allocate(size) { + if let Some(a) = allocator.allocate(size) { allocation = a; break; } - self.allocator.grow(self.allocator.size() * 2); + allocator.grow(allocator.size() * 2); } - let new_atlas_size = self.allocator.size(); + let new_atlas_size = allocator.size(); if new_atlas_size != old_atlas_size { let new_atlas = device.create_texture(&wgpu::TextureDescriptor { @@ -171,7 +135,7 @@ impl Cache { encoder.copy_texture_to_texture( wgpu::TextureCopyView { - texture: &self.atlas, + texture: atlas, array_layer: 0, mip_level: 0, origin: wgpu::Origin3d { @@ -197,7 +161,7 @@ impl Cache { } ); - self.atlas = new_atlas; + *atlas = new_atlas; } // TODO: Optimize! @@ -238,7 +202,7 @@ impl Cache { image_height: height as u32, }, wgpu::TextureCopyView { - texture: &self.atlas, + texture: atlas, array_layer: 0, mip_level: 0, origin: wgpu::Origin3d { @@ -266,25 +230,13 @@ impl Cache { } } - pub fn atlas(&self, device: &wgpu::Device, texture_layout: &wgpu::BindGroupLayout) -> wgpu::BindGroup { - device.create_bind_group(&wgpu::BindGroupDescriptor { - layout: texture_layout, - bindings: &[wgpu::Binding { - binding: 0, - resource: wgpu::BindingResource::TextureView( - &self.atlas.create_default_view(), - ), - }], - }) - } - - pub fn trim(&mut self) { + pub fn trim(&mut self, allocator: &mut AtlasAllocator) { let svg_hits = &self.svg_hits; let rasterized_hits = &self.rasterized_hits; for (k, alloc) in &mut self.rasterized { if !rasterized_hits.contains(&k) { - self.allocator.deallocate(alloc.id); + allocator.deallocate(alloc.id); } } |