From 363966ee9e7aa81a3679eaea776d2c867aa6c3b0 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 7 Feb 2023 22:53:08 +0100 Subject: Refactor `image::Pipeline` into `prepare` and `render` architecture --- wgpu/src/image/atlas.rs | 49 ++++++++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 25 deletions(-) (limited to 'wgpu/src/image') diff --git a/wgpu/src/image/atlas.rs b/wgpu/src/image/atlas.rs index eafe2f96..7df67abd 100644 --- a/wgpu/src/image/atlas.rs +++ b/wgpu/src/image/atlas.rs @@ -185,13 +185,13 @@ impl Atlas { fn upload_allocation( &mut self, - buffer: &wgpu::Buffer, + data: &[u8], image_width: u32, image_height: u32, padding: u32, offset: usize, allocation: &Allocation, - encoder: &mut wgpu::CommandEncoder, + queue: &wgpu::Queue, ) { let (x, y) = allocation.position(); let Size { width, height } = allocation.size(); @@ -203,15 +203,7 @@ impl Atlas { depth_or_array_layers: 1, }; - encoder.copy_buffer_to_texture( - wgpu::ImageCopyBuffer { - buffer, - layout: wgpu::ImageDataLayout { - offset: offset as u64, - bytes_per_row: NonZeroU32::new(4 * image_width + padding), - rows_per_image: NonZeroU32::new(image_height), - }, - }, + queue.write_texture( wgpu::ImageCopyTexture { texture: &self.texture, mip_level: 0, @@ -222,6 +214,12 @@ impl Atlas { }, aspect: wgpu::TextureAspect::default(), }, + data, + wgpu::ImageDataLayout { + offset: offset as u64, + bytes_per_row: NonZeroU32::new(4 * image_width + padding), + rows_per_image: NonZeroU32::new(image_height), + }, extent, ); } @@ -301,17 +299,19 @@ impl Atlas { impl image::Storage for Atlas { type Entry = Entry; - type State<'a> = (&'a wgpu::Device, &'a mut wgpu::CommandEncoder); + type State<'a> = ( + &'a wgpu::Device, + &'a wgpu::Queue, + &'a mut wgpu::CommandEncoder, + ); fn upload( &mut self, width: u32, height: u32, data: &[u8], - (device, encoder): &mut Self::State<'_>, + (device, queue, encoder): &mut Self::State<'_>, ) -> Option { - use wgpu::util::DeviceExt; - let entry = { let current_size = self.layers.len(); let entry = self.allocate(width, height)?; @@ -344,17 +344,16 @@ impl image::Storage for Atlas { ) } - let buffer = - device.create_buffer_init(&wgpu::util::BufferInitDescriptor { - label: Some("iced_wgpu::image staging buffer"), - contents: &padded_data, - usage: wgpu::BufferUsages::COPY_SRC, - }); - match &entry { Entry::Contiguous(allocation) => { self.upload_allocation( - &buffer, width, height, padding, 0, allocation, encoder, + &padded_data, + width, + height, + padding, + 0, + allocation, + queue, ); } Entry::Fragmented { fragments, .. } => { @@ -363,13 +362,13 @@ impl image::Storage for Atlas { let offset = (y * padded_width as u32 + 4 * x) as usize; self.upload_allocation( - &buffer, + &padded_data, width, height, padding, offset, &fragment.allocation, - encoder, + queue, ); } } -- cgit From 3a0d34c0240f4421737a6a08761f99d6f8140d02 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 4 Mar 2023 05:37:11 +0100 Subject: Create `iced_widget` subcrate and re-organize the whole codebase --- wgpu/src/image/atlas.rs | 4 ++-- wgpu/src/image/atlas/allocation.rs | 3 +-- wgpu/src/image/atlas/allocator.rs | 4 ++-- wgpu/src/image/atlas/entry.rs | 5 ++--- 4 files changed, 7 insertions(+), 9 deletions(-) (limited to 'wgpu/src/image') diff --git a/wgpu/src/image/atlas.rs b/wgpu/src/image/atlas.rs index 7df67abd..0a17ca33 100644 --- a/wgpu/src/image/atlas.rs +++ b/wgpu/src/image/atlas.rs @@ -12,8 +12,8 @@ use allocator::Allocator; pub const SIZE: u32 = 2048; -use iced_graphics::image; -use iced_graphics::Size; +use crate::core::Size; +use crate::graphics::image; use std::num::NonZeroU32; diff --git a/wgpu/src/image/atlas/allocation.rs b/wgpu/src/image/atlas/allocation.rs index 43aba875..11289771 100644 --- a/wgpu/src/image/atlas/allocation.rs +++ b/wgpu/src/image/atlas/allocation.rs @@ -1,7 +1,6 @@ +use crate::core::Size; use crate::image::atlas::{self, allocator}; -use iced_graphics::Size; - #[derive(Debug)] pub enum Allocation { Partial { diff --git a/wgpu/src/image/atlas/allocator.rs b/wgpu/src/image/atlas/allocator.rs index 03effdcb..204a5c26 100644 --- a/wgpu/src/image/atlas/allocator.rs +++ b/wgpu/src/image/atlas/allocator.rs @@ -46,10 +46,10 @@ impl Region { (rectangle.min.x as u32, rectangle.min.y as u32) } - pub fn size(&self) -> iced_graphics::Size { + pub fn size(&self) -> crate::core::Size { let size = self.allocation.rectangle.size(); - iced_graphics::Size::new(size.width as u32, size.height as u32) + crate::core::Size::new(size.width as u32, size.height as u32) } } diff --git a/wgpu/src/image/atlas/entry.rs b/wgpu/src/image/atlas/entry.rs index 69c05a50..4b06bd95 100644 --- a/wgpu/src/image/atlas/entry.rs +++ b/wgpu/src/image/atlas/entry.rs @@ -1,8 +1,7 @@ +use crate::core::Size; +use crate::graphics::image; use crate::image::atlas; -use iced_graphics::image; -use iced_graphics::Size; - #[derive(Debug)] pub enum Entry { Contiguous(atlas::Allocation), -- cgit From 3a26baa564524b0f25c5cb180b592c8b004b68a9 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 7 Mar 2023 03:47:49 +0100 Subject: Remove `image` abstractions in `iced_graphics` --- wgpu/src/image/atlas.rs | 190 ++++++++++++++++++++---------------------- wgpu/src/image/atlas/entry.rs | 6 +- wgpu/src/image/raster.rs | 121 +++++++++++++++++++++++++++ wgpu/src/image/vector.rs | 181 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 396 insertions(+), 102 deletions(-) create mode 100644 wgpu/src/image/raster.rs create mode 100644 wgpu/src/image/vector.rs (limited to 'wgpu/src/image') diff --git a/wgpu/src/image/atlas.rs b/wgpu/src/image/atlas.rs index 0a17ca33..c00b8cef 100644 --- a/wgpu/src/image/atlas.rs +++ b/wgpu/src/image/atlas.rs @@ -13,7 +13,6 @@ use allocator::Allocator; pub const SIZE: u32 = 2048; use crate::core::Size; -use crate::graphics::image; use std::num::NonZeroU32; @@ -64,6 +63,97 @@ impl Atlas { self.layers.len() } + pub fn upload( + &mut self, + device: &wgpu::Device, + queue: &wgpu::Queue, + encoder: &mut wgpu::CommandEncoder, + width: u32, + height: u32, + data: &[u8], + ) -> Option { + 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); + + // It is a webgpu requirement that: + // BufferCopyView.layout.bytes_per_row % wgpu::COPY_BYTES_PER_ROW_ALIGNMENT == 0 + // So we calculate padded_width by rounding width up to the next + // multiple of wgpu::COPY_BYTES_PER_ROW_ALIGNMENT. + let align = wgpu::COPY_BYTES_PER_ROW_ALIGNMENT; + let padding = (align - (4 * width) % align) % align; + let padded_width = (4 * width + padding) as usize; + let padded_data_size = padded_width * height as usize; + + let mut padded_data = vec![0; padded_data_size]; + + for row in 0..height as usize { + let offset = row * padded_width; + + padded_data[offset..offset + 4 * width as usize].copy_from_slice( + &data[row * 4 * width as usize..(row + 1) * 4 * width as usize], + ) + } + + match &entry { + Entry::Contiguous(allocation) => { + self.upload_allocation( + &padded_data, + width, + height, + padding, + 0, + allocation, + queue, + ); + } + Entry::Fragmented { fragments, .. } => { + for fragment in fragments { + let (x, y) = fragment.position; + let offset = (y * padded_width as u32 + 4 * x) as usize; + + self.upload_allocation( + &padded_data, + width, + height, + padding, + offset, + &fragment.allocation, + queue, + ); + } + } + } + + 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 { @@ -296,101 +386,3 @@ impl Atlas { }); } } - -impl image::Storage for Atlas { - type Entry = Entry; - type State<'a> = ( - &'a wgpu::Device, - &'a wgpu::Queue, - &'a mut wgpu::CommandEncoder, - ); - - fn upload( - &mut self, - width: u32, - height: u32, - data: &[u8], - (device, queue, encoder): &mut Self::State<'_>, - ) -> Option { - 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); - - // It is a webgpu requirement that: - // BufferCopyView.layout.bytes_per_row % wgpu::COPY_BYTES_PER_ROW_ALIGNMENT == 0 - // So we calculate padded_width by rounding width up to the next - // multiple of wgpu::COPY_BYTES_PER_ROW_ALIGNMENT. - let align = wgpu::COPY_BYTES_PER_ROW_ALIGNMENT; - let padding = (align - (4 * width) % align) % align; - let padded_width = (4 * width + padding) as usize; - let padded_data_size = padded_width * height as usize; - - let mut padded_data = vec![0; padded_data_size]; - - for row in 0..height as usize { - let offset = row * padded_width; - - padded_data[offset..offset + 4 * width as usize].copy_from_slice( - &data[row * 4 * width as usize..(row + 1) * 4 * width as usize], - ) - } - - match &entry { - Entry::Contiguous(allocation) => { - self.upload_allocation( - &padded_data, - width, - height, - padding, - 0, - allocation, - queue, - ); - } - Entry::Fragmented { fragments, .. } => { - for fragment in fragments { - let (x, y) = fragment.position; - let offset = (y * padded_width as u32 + 4 * x) as usize; - - self.upload_allocation( - &padded_data, - width, - height, - padding, - offset, - &fragment.allocation, - queue, - ); - } - } - } - - log::info!("Current atlas: {:?}", self); - - Some(entry) - } - - fn remove(&mut self, entry: &Entry, _: &mut Self::State<'_>) { - 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); - } - } - } - } -} diff --git a/wgpu/src/image/atlas/entry.rs b/wgpu/src/image/atlas/entry.rs index 4b06bd95..7e4c92a2 100644 --- a/wgpu/src/image/atlas/entry.rs +++ b/wgpu/src/image/atlas/entry.rs @@ -1,5 +1,4 @@ use crate::core::Size; -use crate::graphics::image; use crate::image::atlas; #[derive(Debug)] @@ -11,8 +10,9 @@ pub enum Entry { }, } -impl image::storage::Entry for Entry { - fn size(&self) -> Size { +impl Entry { + #[cfg(feature = "image")] + pub fn size(&self) -> Size { match self { Entry::Contiguous(allocation) => allocation.size(), Entry::Fragmented { size, .. } => *size, diff --git a/wgpu/src/image/raster.rs b/wgpu/src/image/raster.rs new file mode 100644 index 00000000..9b38dce4 --- /dev/null +++ b/wgpu/src/image/raster.rs @@ -0,0 +1,121 @@ +use crate::core::image; +use crate::core::Size; +use crate::graphics; +use crate::graphics::image::image_rs; +use crate::image::atlas::{self, Atlas}; + +use std::collections::{HashMap, HashSet}; + +/// Entry in cache corresponding to an image handle +#[derive(Debug)] +pub enum Memory { + /// Image data on host + Host(image_rs::ImageBuffer, Vec>), + /// Storage entry + Device(atlas::Entry), + /// Image not found + NotFound, + /// Invalid image data + Invalid, +} + +impl Memory { + /// Width and height of image + pub fn dimensions(&self) -> Size { + match self { + Memory::Host(image) => { + let (width, height) = image.dimensions(); + + Size::new(width, height) + } + Memory::Device(entry) => entry.size(), + Memory::NotFound => Size::new(1, 1), + Memory::Invalid => Size::new(1, 1), + } + } +} + +/// Caches image raster data +#[derive(Debug, Default)] +pub struct Cache { + map: HashMap, + hits: HashSet, +} + +impl Cache { + /// Load image + pub fn load(&mut self, handle: &image::Handle) -> &mut Memory { + if self.contains(handle) { + return self.get(handle).unwrap(); + } + + let memory = match graphics::image::load(handle) { + Ok(image) => Memory::Host(image.to_rgba8()), + Err(image_rs::error::ImageError::IoError(_)) => Memory::NotFound, + Err(_) => Memory::Invalid, + }; + + self.insert(handle, memory); + self.get(handle).unwrap() + } + + /// Load image and upload raster data + pub fn upload( + &mut self, + device: &wgpu::Device, + queue: &wgpu::Queue, + encoder: &mut wgpu::CommandEncoder, + handle: &image::Handle, + atlas: &mut Atlas, + ) -> Option<&atlas::Entry> { + let memory = self.load(handle); + + if let Memory::Host(image) = memory { + let (width, height) = image.dimensions(); + + let entry = + atlas.upload(device, queue, encoder, width, height, image)?; + + *memory = Memory::Device(entry); + } + + if let Memory::Device(allocation) = memory { + Some(allocation) + } else { + None + } + } + + /// Trim cache misses from cache + pub fn trim(&mut self, atlas: &mut Atlas) { + let hits = &self.hits; + + self.map.retain(|k, memory| { + let retain = hits.contains(k); + + if !retain { + if let Memory::Device(entry) = memory { + atlas.remove(entry); + } + } + + retain + }); + + self.hits.clear(); + } + + fn get(&mut self, handle: &image::Handle) -> Option<&mut Memory> { + let _ = self.hits.insert(handle.id()); + + self.map.get_mut(&handle.id()) + } + + fn insert(&mut self, handle: &image::Handle, memory: Memory) { + let _ = self.map.insert(handle.id(), memory); + } + + fn contains(&self, handle: &image::Handle) -> bool { + self.map.contains_key(&handle.id()) + } +} diff --git a/wgpu/src/image/vector.rs b/wgpu/src/image/vector.rs new file mode 100644 index 00000000..3624e46b --- /dev/null +++ b/wgpu/src/image/vector.rs @@ -0,0 +1,181 @@ +use crate::core::svg; +use crate::core::{Color, Size}; +use crate::image::atlas::{self, Atlas}; + +use resvg::tiny_skia; +use resvg::usvg; +use std::collections::{HashMap, HashSet}; +use std::fs; + +/// Entry in cache corresponding to an svg handle +pub enum Svg { + /// Parsed svg + Loaded(usvg::Tree), + /// Svg not found or failed to parse + NotFound, +} + +impl Svg { + /// Viewport width and height + pub fn viewport_dimensions(&self) -> Size { + match self { + Svg::Loaded(tree) => { + let size = tree.size; + + Size::new(size.width() as u32, size.height() as u32) + } + Svg::NotFound => Size::new(1, 1), + } + } +} + +/// Caches svg vector and raster data +#[derive(Debug, Default)] +pub struct Cache { + svgs: HashMap, + rasterized: HashMap<(u64, u32, u32, ColorFilter), atlas::Entry>, + svg_hits: HashSet, + rasterized_hits: HashSet<(u64, u32, u32, ColorFilter)>, +} + +type ColorFilter = Option<[u8; 4]>; + +impl Cache { + /// Load svg + pub fn load(&mut self, handle: &svg::Handle) -> &Svg { + if self.svgs.contains_key(&handle.id()) { + return self.svgs.get(&handle.id()).unwrap(); + } + + let svg = match handle.data() { + svg::Data::Path(path) => { + let tree = fs::read_to_string(path).ok().and_then(|contents| { + usvg::Tree::from_str(&contents, &usvg::Options::default()) + .ok() + }); + + tree.map(Svg::Loaded).unwrap_or(Svg::NotFound) + } + svg::Data::Bytes(bytes) => { + match usvg::Tree::from_data(bytes, &usvg::Options::default()) { + Ok(tree) => Svg::Loaded(tree), + Err(_) => Svg::NotFound, + } + } + }; + + let _ = self.svgs.insert(handle.id(), svg); + self.svgs.get(&handle.id()).unwrap() + } + + /// Load svg and upload raster data + pub fn upload( + &mut self, + device: &wgpu::Device, + queue: &wgpu::Queue, + encoder: &mut wgpu::CommandEncoder, + handle: &svg::Handle, + color: Option, + [width, height]: [f32; 2], + scale: f32, + atlas: &mut Atlas, + ) -> Option<&atlas::Entry> { + let id = handle.id(); + + let (width, height) = ( + (scale * width).ceil() as u32, + (scale * height).ceil() as u32, + ); + + let color = color.map(Color::into_rgba8); + let key = (id, width, height, color); + + // TODO: Optimize! + // We currently rerasterize the SVG when its size changes. This is slow + // as heck. A GPU rasterizer like `pathfinder` may perform better. + // It would be cool to be able to smooth resize the `svg` example. + if self.rasterized.contains_key(&key) { + let _ = self.svg_hits.insert(id); + let _ = self.rasterized_hits.insert(key); + + return self.rasterized.get(&key); + } + + match self.load(handle) { + Svg::Loaded(tree) => { + if width == 0 || height == 0 { + return None; + } + + // TODO: Optimize! + // We currently rerasterize the SVG when its size changes. This is slow + // as heck. A GPU rasterizer like `pathfinder` may perform better. + // It would be cool to be able to smooth resize the `svg` example. + let mut img = tiny_skia::Pixmap::new(width, height)?; + + resvg::render( + tree, + if width > height { + usvg::FitTo::Width(width) + } else { + usvg::FitTo::Height(height) + }, + tiny_skia::Transform::default(), + img.as_mut(), + )?; + + let mut rgba = img.take(); + + if let Some(color) = color { + rgba.chunks_exact_mut(4).for_each(|rgba| { + if rgba[3] > 0 { + rgba[0] = color[0]; + rgba[1] = color[1]; + rgba[2] = color[2]; + } + }); + } + + let allocation = atlas + .upload(device, queue, encoder, width, height, &rgba)?; + + log::debug!("allocating {} {}x{}", id, width, height); + + let _ = self.svg_hits.insert(id); + let _ = self.rasterized_hits.insert(key); + let _ = self.rasterized.insert(key, allocation); + + self.rasterized.get(&key) + } + Svg::NotFound => None, + } + } + + /// Load svg and upload raster data + pub fn trim(&mut self, atlas: &mut Atlas) { + let svg_hits = &self.svg_hits; + let rasterized_hits = &self.rasterized_hits; + + self.svgs.retain(|k, _| svg_hits.contains(k)); + self.rasterized.retain(|k, entry| { + let retain = rasterized_hits.contains(k); + + if !retain { + atlas.remove(entry); + } + + retain + }); + self.svg_hits.clear(); + self.rasterized_hits.clear(); + } +} + +impl std::fmt::Debug for Svg { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Svg::Loaded(_) => write!(f, "Svg::Loaded"), + Svg::NotFound => write!(f, "Svg::NotFound"), + } + } +} -- cgit From c0431aedd3bbef4161456f2fa5f29866e8f17fc5 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 8 Apr 2023 04:47:05 +0200 Subject: Update `wgpu` and `cosmic-text` --- wgpu/src/image/atlas.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'wgpu/src/image') diff --git a/wgpu/src/image/atlas.rs b/wgpu/src/image/atlas.rs index c00b8cef..39b6e5d2 100644 --- a/wgpu/src/image/atlas.rs +++ b/wgpu/src/image/atlas.rs @@ -41,6 +41,7 @@ impl Atlas { usage: wgpu::TextureUsages::COPY_DST | wgpu::TextureUsages::COPY_SRC | wgpu::TextureUsages::TEXTURE_BINDING, + view_formats: &[], }); let texture_view = texture.create_view(&wgpu::TextureViewDescriptor { @@ -338,6 +339,7 @@ impl Atlas { usage: wgpu::TextureUsages::COPY_DST | wgpu::TextureUsages::COPY_SRC | wgpu::TextureUsages::TEXTURE_BINDING, + view_formats: &[], }); let amount_to_copy = self.layers.len() - amount; -- cgit From d5453c62e9bdbf0cea030b009c41b892b700496d Mon Sep 17 00:00:00 2001 From: Elham Aryanpur Date: Wed, 12 Apr 2023 23:38:21 +0300 Subject: Update `wgpu` to `0.15` --- wgpu/src/image/atlas.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'wgpu/src/image') diff --git a/wgpu/src/image/atlas.rs b/wgpu/src/image/atlas.rs index eafe2f96..82504147 100644 --- a/wgpu/src/image/atlas.rs +++ b/wgpu/src/image/atlas.rs @@ -39,6 +39,7 @@ impl Atlas { sample_count: 1, dimension: wgpu::TextureDimension::D2, format: wgpu::TextureFormat::Rgba8UnormSrgb, + view_formats: &[], usage: wgpu::TextureUsages::COPY_DST | wgpu::TextureUsages::COPY_SRC | wgpu::TextureUsages::TEXTURE_BINDING, @@ -247,6 +248,7 @@ impl Atlas { sample_count: 1, dimension: wgpu::TextureDimension::D2, format: wgpu::TextureFormat::Rgba8UnormSrgb, + view_formats: &[], usage: wgpu::TextureUsages::COPY_DST | wgpu::TextureUsages::COPY_SRC | wgpu::TextureUsages::TEXTURE_BINDING, -- cgit From 8122904ca46b73ceda54bd73bd68cf4138d22f1b Mon Sep 17 00:00:00 2001 From: David Huculak Date: Thu, 20 Apr 2023 21:28:47 -0400 Subject: wgpu 0.16 --- wgpu/src/image/atlas.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'wgpu/src/image') diff --git a/wgpu/src/image/atlas.rs b/wgpu/src/image/atlas.rs index 82504147..1384949a 100644 --- a/wgpu/src/image/atlas.rs +++ b/wgpu/src/image/atlas.rs @@ -209,8 +209,8 @@ impl Atlas { buffer, layout: wgpu::ImageDataLayout { offset: offset as u64, - bytes_per_row: NonZeroU32::new(4 * image_width + padding), - rows_per_image: NonZeroU32::new(image_height), + bytes_per_row: Some(4 * image_width + padding), + rows_per_image: Some(image_height), }, }, wgpu::ImageCopyTexture { -- cgit From cbb2ba38faadc52b9523918a2fbc2e2a78de9087 Mon Sep 17 00:00:00 2001 From: David Huculak Date: Thu, 20 Apr 2023 21:38:52 -0400 Subject: remove unused import --- wgpu/src/image/atlas.rs | 2 -- 1 file changed, 2 deletions(-) (limited to 'wgpu/src/image') diff --git a/wgpu/src/image/atlas.rs b/wgpu/src/image/atlas.rs index 1384949a..a0fdf146 100644 --- a/wgpu/src/image/atlas.rs +++ b/wgpu/src/image/atlas.rs @@ -15,8 +15,6 @@ pub const SIZE: u32 = 2048; use iced_graphics::image; use iced_graphics::Size; -use std::num::NonZeroU32; - #[derive(Debug)] pub struct Atlas { texture: wgpu::Texture, -- cgit From 9c63eb7df559e58b14188b4096e9bd206444bbf3 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 26 Apr 2023 16:46:27 +0200 Subject: Update `tiny-skia` and `resvg` --- wgpu/src/image/vector.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'wgpu/src/image') diff --git a/wgpu/src/image/vector.rs b/wgpu/src/image/vector.rs index 3624e46b..58bdf64a 100644 --- a/wgpu/src/image/vector.rs +++ b/wgpu/src/image/vector.rs @@ -43,6 +43,8 @@ type ColorFilter = Option<[u8; 4]>; impl Cache { /// Load svg pub fn load(&mut self, handle: &svg::Handle) -> &Svg { + use usvg::TreeParsing; + if self.svgs.contains_key(&handle.id()) { return self.svgs.get(&handle.id()).unwrap(); } @@ -116,9 +118,9 @@ impl Cache { resvg::render( tree, if width > height { - usvg::FitTo::Width(width) + resvg::FitTo::Width(width) } else { - usvg::FitTo::Height(height) + resvg::FitTo::Height(height) }, tiny_skia::Transform::default(), img.as_mut(), -- cgit From f02f0c01ea9b46b3b303c805b4e001a3f10be748 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 11 May 2023 20:18:36 +0200 Subject: Fix race condition when growing an `image::Atlas` --- wgpu/src/image/atlas.rs | 38 +++++++++++++++++++++++++++----------- wgpu/src/image/raster.rs | 4 +--- wgpu/src/image/vector.rs | 5 ++--- 3 files changed, 30 insertions(+), 17 deletions(-) (limited to 'wgpu/src/image') diff --git a/wgpu/src/image/atlas.rs b/wgpu/src/image/atlas.rs index 366fe623..2296710b 100644 --- a/wgpu/src/image/atlas.rs +++ b/wgpu/src/image/atlas.rs @@ -65,7 +65,6 @@ impl Atlas { pub fn upload( &mut self, device: &wgpu::Device, - queue: &wgpu::Queue, encoder: &mut wgpu::CommandEncoder, width: u32, height: u32, @@ -75,6 +74,9 @@ impl Atlas { let current_size = self.layers.len(); let entry = self.allocate(width, height)?; + dbg!(&entry); + dbg!(&self.layers); + // We grow the internal texture after allocating if necessary let new_layers = self.layers.len() - current_size; self.grow(new_layers, device, encoder); @@ -112,7 +114,8 @@ impl Atlas { padding, 0, allocation, - queue, + device, + encoder, ); } Entry::Fragmented { fragments, .. } => { @@ -127,7 +130,8 @@ impl Atlas { padding, offset, &fragment.allocation, - queue, + device, + encoder, ); } } @@ -280,8 +284,11 @@ impl Atlas { padding: u32, offset: usize, allocation: &Allocation, - queue: &wgpu::Queue, + device: &wgpu::Device, + encoder: &mut wgpu::CommandEncoder, ) { + use wgpu::util::DeviceExt; + let (x, y) = allocation.position(); let Size { width, height } = allocation.size(); let layer = allocation.layer(); @@ -292,7 +299,22 @@ impl Atlas { depth_or_array_layers: 1, }; - queue.write_texture( + let buffer = + device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("image upload buffer"), + contents: data, + usage: wgpu::BufferUsages::COPY_SRC, + }); + + encoder.copy_buffer_to_texture( + wgpu::ImageCopyBuffer { + buffer: &buffer, + layout: wgpu::ImageDataLayout { + offset: offset as u64, + bytes_per_row: Some(4 * image_width + padding), + rows_per_image: Some(image_height), + }, + }, wgpu::ImageCopyTexture { texture: &self.texture, mip_level: 0, @@ -303,12 +325,6 @@ impl Atlas { }, aspect: wgpu::TextureAspect::default(), }, - data, - wgpu::ImageDataLayout { - offset: offset as u64, - bytes_per_row: Some(4 * image_width + padding), - rows_per_image: Some(image_height), - }, extent, ); } diff --git a/wgpu/src/image/raster.rs b/wgpu/src/image/raster.rs index 9b38dce4..a6cba76a 100644 --- a/wgpu/src/image/raster.rs +++ b/wgpu/src/image/raster.rs @@ -63,7 +63,6 @@ impl Cache { pub fn upload( &mut self, device: &wgpu::Device, - queue: &wgpu::Queue, encoder: &mut wgpu::CommandEncoder, handle: &image::Handle, atlas: &mut Atlas, @@ -73,8 +72,7 @@ impl Cache { if let Memory::Host(image) = memory { let (width, height) = image.dimensions(); - let entry = - atlas.upload(device, queue, encoder, width, height, image)?; + let entry = atlas.upload(device, encoder, width, height, image)?; *memory = Memory::Device(entry); } diff --git a/wgpu/src/image/vector.rs b/wgpu/src/image/vector.rs index 58bdf64a..6b9be651 100644 --- a/wgpu/src/image/vector.rs +++ b/wgpu/src/image/vector.rs @@ -74,7 +74,6 @@ impl Cache { pub fn upload( &mut self, device: &wgpu::Device, - queue: &wgpu::Queue, encoder: &mut wgpu::CommandEncoder, handle: &svg::Handle, color: Option, @@ -138,8 +137,8 @@ impl Cache { }); } - let allocation = atlas - .upload(device, queue, encoder, width, height, &rgba)?; + let allocation = + atlas.upload(device, encoder, width, height, &rgba)?; log::debug!("allocating {} {}x{}", id, width, height); -- cgit From 0ef5ab6c84643784d37801598c68a259f0ca64ff Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 11 May 2023 20:19:37 +0200 Subject: Remove `dbg!` leftovers in `image::atlas` --- wgpu/src/image/atlas.rs | 3 --- 1 file changed, 3 deletions(-) (limited to 'wgpu/src/image') diff --git a/wgpu/src/image/atlas.rs b/wgpu/src/image/atlas.rs index 2296710b..9b6dcc46 100644 --- a/wgpu/src/image/atlas.rs +++ b/wgpu/src/image/atlas.rs @@ -74,9 +74,6 @@ impl Atlas { let current_size = self.layers.len(); let entry = self.allocate(width, height)?; - dbg!(&entry); - dbg!(&self.layers); - // We grow the internal texture after allocating if necessary let new_layers = self.layers.len() - current_size; self.grow(new_layers, device, encoder); -- cgit From f1b259a28fdb92ce62ceb6fcea9547b52ecc77d3 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 31 May 2023 21:42:39 +0200 Subject: Avoid gamma correction when `web-colors` is enabled for images --- wgpu/src/image/atlas.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'wgpu/src/image') diff --git a/wgpu/src/image/atlas.rs b/wgpu/src/image/atlas.rs index 9b6dcc46..28bc4943 100644 --- a/wgpu/src/image/atlas.rs +++ b/wgpu/src/image/atlas.rs @@ -13,6 +13,7 @@ use allocator::Allocator; pub const SIZE: u32 = 2048; use crate::core::Size; +use crate::graphics::color; #[derive(Debug)] pub struct Atlas { @@ -35,7 +36,11 @@ impl Atlas { mip_level_count: 1, sample_count: 1, dimension: wgpu::TextureDimension::D2, - format: wgpu::TextureFormat::Rgba8UnormSrgb, + format: if color::GAMMA_CORRECTION { + wgpu::TextureFormat::Rgba8UnormSrgb + } else { + wgpu::TextureFormat::Rgba8Unorm + }, usage: wgpu::TextureUsages::COPY_DST | wgpu::TextureUsages::COPY_SRC | wgpu::TextureUsages::TEXTURE_BINDING, -- cgit From c528f2129e5ce3b30e313f731588082c49beb30b Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 31 May 2023 21:45:12 +0200 Subject: Use proper gamma correction mode in `image::Atlas::grow` --- wgpu/src/image/atlas.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'wgpu/src/image') diff --git a/wgpu/src/image/atlas.rs b/wgpu/src/image/atlas.rs index 28bc4943..e3de1290 100644 --- a/wgpu/src/image/atlas.rs +++ b/wgpu/src/image/atlas.rs @@ -351,7 +351,11 @@ impl Atlas { mip_level_count: 1, sample_count: 1, dimension: wgpu::TextureDimension::D2, - format: wgpu::TextureFormat::Rgba8UnormSrgb, + format: if color::GAMMA_CORRECTION { + wgpu::TextureFormat::Rgba8UnormSrgb + } else { + wgpu::TextureFormat::Rgba8Unorm + }, usage: wgpu::TextureUsages::COPY_DST | wgpu::TextureUsages::COPY_SRC | wgpu::TextureUsages::TEXTURE_BINDING, -- cgit From af386fd0a3de432337ee9cdaa4d3661e98bd4105 Mon Sep 17 00:00:00 2001 From: Alec Deason Date: Sat, 10 Jun 2023 13:18:42 -0700 Subject: Upgrade resvg to 0.34 and tiny_skia to 0.10 --- wgpu/src/image/vector.rs | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) (limited to 'wgpu/src/image') diff --git a/wgpu/src/image/vector.rs b/wgpu/src/image/vector.rs index 6b9be651..5bfc1836 100644 --- a/wgpu/src/image/vector.rs +++ b/wgpu/src/image/vector.rs @@ -114,16 +114,27 @@ impl Cache { // It would be cool to be able to smooth resize the `svg` example. let mut img = tiny_skia::Pixmap::new(width, height)?; - resvg::render( - tree, - if width > height { - resvg::FitTo::Width(width) - } else { - resvg::FitTo::Height(height) - }, - tiny_skia::Transform::default(), - img.as_mut(), - )?; + let tree_size = tree.size.to_int_size(); + let target_size; + if width > height { + target_size = tree_size.scale_to_width(width); + } else { + target_size = tree_size.scale_to_height(height); + } + let transform; + if let Some(target_size) = target_size { + let tree_size = tree_size.to_size(); + let target_size = target_size.to_size(); + transform = tiny_skia::Transform::from_scale( + target_size.width() / tree_size.width(), + target_size.height() / tree_size.height(), + ); + } else { + transform = tiny_skia::Transform::default(); + } + + resvg::Tree::from_usvg(tree) + .render(transform, &mut img.as_mut()); let mut rgba = img.take(); -- cgit From 6502cf1111380c66f96bf5677425a902c4662ef5 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 12 Jul 2023 09:07:20 +0200 Subject: Improve code style in `vector` modules --- wgpu/src/image/vector.rs | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'wgpu/src/image') diff --git a/wgpu/src/image/vector.rs b/wgpu/src/image/vector.rs index 5bfc1836..2c03d36b 100644 --- a/wgpu/src/image/vector.rs +++ b/wgpu/src/image/vector.rs @@ -115,23 +115,24 @@ impl Cache { let mut img = tiny_skia::Pixmap::new(width, height)?; let tree_size = tree.size.to_int_size(); - let target_size; - if width > height { - target_size = tree_size.scale_to_width(width); + + let target_size = if width > height { + tree_size.scale_to_width(width) } else { - target_size = tree_size.scale_to_height(height); - } - let transform; - if let Some(target_size) = target_size { + tree_size.scale_to_height(height) + }; + + let transform = if let Some(target_size) = target_size { let tree_size = tree_size.to_size(); let target_size = target_size.to_size(); - transform = tiny_skia::Transform::from_scale( + + tiny_skia::Transform::from_scale( target_size.width() / tree_size.width(), target_size.height() / tree_size.height(), - ); + ) } else { - transform = tiny_skia::Transform::default(); - } + tiny_skia::Transform::default() + }; resvg::Tree::from_usvg(tree) .render(transform, &mut img.as_mut()); -- cgit