From d53ccc857da4d4cda769904342aeb5a82a64f146 Mon Sep 17 00:00:00 2001 From: Bingus <shankern@protonmail.com> Date: Wed, 12 Jul 2023 19:21:05 -0700 Subject: refactored window storage; new helper window events (Destroyed, Created); clippy + fmt; --- wgpu/src/window/compositor.rs | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'wgpu') diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index cd5b20cc..814269f3 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -219,6 +219,10 @@ impl<Theme> graphics::Compositor for Compositor<Theme> { Ok((compositor, Renderer::new(backend))) } + fn renderer(&self) -> Self::Renderer { + Renderer::new(self.create_backend()) + } + fn create_surface<W: HasRawWindowHandle + HasRawDisplayHandle>( &mut self, window: &W, -- cgit From 346af3f8b0baa418fd37b878bc2930ff0bd57cc0 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Mon, 11 Sep 2023 02:47:24 +0200 Subject: Make `FontSystem` global and simplify `Paragraph` API --- wgpu/src/backend.rs | 5 ----- wgpu/src/text.rs | 17 ++++++++--------- 2 files changed, 8 insertions(+), 14 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/backend.rs b/wgpu/src/backend.rs index 65c63f19..3d1755e1 100644 --- a/wgpu/src/backend.rs +++ b/wgpu/src/backend.rs @@ -1,5 +1,4 @@ use crate::core::{Color, Size}; -use crate::graphics; use crate::graphics::backend; use crate::graphics::color; use crate::graphics::{Transformation, Viewport}; @@ -310,10 +309,6 @@ impl crate::graphics::Backend for Backend { } impl backend::Text for Backend { - fn font_system(&self) -> &graphics::text::FontSystem { - self.text_pipeline.font_system() - } - fn load_font(&mut self, font: Cow<'static, [u8]>) { self.text_pipeline.load_font(font); } diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs index bd4f3e06..5c9f4d7e 100644 --- a/wgpu/src/text.rs +++ b/wgpu/src/text.rs @@ -2,7 +2,7 @@ use crate::core::alignment; use crate::core::{Rectangle, Size}; use crate::graphics::color; use crate::graphics::text::cache::{self, Cache}; -use crate::graphics::text::{FontSystem, Paragraph}; +use crate::graphics::text::{font_system, Paragraph}; use crate::layer::Text; use std::borrow::Cow; @@ -10,7 +10,6 @@ use std::cell::RefCell; #[allow(missing_debug_implementations)] pub struct Pipeline { - font_system: FontSystem, renderers: Vec<glyphon::TextRenderer>, atlas: glyphon::TextAtlas, prepare_layer: usize, @@ -24,7 +23,6 @@ impl Pipeline { format: wgpu::TextureFormat, ) -> Self { Pipeline { - font_system: FontSystem::new(), renderers: Vec::new(), atlas: glyphon::TextAtlas::with_color_mode( device, @@ -41,12 +39,11 @@ impl Pipeline { } } - pub fn font_system(&self) -> &FontSystem { - &self.font_system - } - pub fn load_font(&mut self, bytes: Cow<'static, [u8]>) { - self.font_system.load_font(bytes); + font_system() + .write() + .expect("Write font system") + .load_font(bytes); self.cache = RefCell::new(Cache::new()); } @@ -69,7 +66,9 @@ impl Pipeline { )); } - let font_system = self.font_system.get_mut(); + let mut font_system = font_system().write().expect("Write font system"); + let font_system = font_system.raw(); + let renderer = &mut self.renderers[self.prepare_layer]; let cache = self.cache.get_mut(); -- cgit From 6448429103c9c82b90040ac5a5a097bdded23f82 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Tue, 12 Sep 2023 14:51:00 +0200 Subject: Draft `Editor` API and `TextEditor` widget --- wgpu/src/layer.rs | 15 ++++++++++++++- wgpu/src/layer/text.rs | 8 +++++++- wgpu/src/text.rs | 28 +++++++++++++++++++++++++--- 3 files changed, 46 insertions(+), 5 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs index 7a5a0f7c..10b3332d 100644 --- a/wgpu/src/layer.rs +++ b/wgpu/src/layer.rs @@ -120,12 +120,25 @@ impl<'a> Layer<'a> { } => { let layer = &mut layers[current_layer]; - layer.text.push(Text::Managed { + layer.text.push(Text::Paragraph { paragraph: paragraph.clone(), position: *position + translation, color: *color, }); } + Primitive::Editor { + editor, + position, + color, + } => { + let layer = &mut layers[current_layer]; + + layer.text.push(Text::Editor { + editor: editor.clone(), + position: *position + translation, + color: *color, + }); + } Primitive::Text { content, bounds, diff --git a/wgpu/src/layer/text.rs b/wgpu/src/layer/text.rs index b61615d6..d46b39da 100644 --- a/wgpu/src/layer/text.rs +++ b/wgpu/src/layer/text.rs @@ -1,16 +1,22 @@ use crate::core::alignment; use crate::core::text; use crate::core::{Color, Font, Pixels, Point, Rectangle}; +use crate::graphics::text::editor; use crate::graphics::text::paragraph; /// A paragraph of text. #[derive(Debug, Clone)] pub enum Text<'a> { - Managed { + Paragraph { paragraph: paragraph::Weak, position: Point, color: Color, }, + Editor { + editor: editor::Weak, + position: Point, + color: Color, + }, Cached(Cached<'a>), } diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs index 5c9f4d7e..397c38dd 100644 --- a/wgpu/src/text.rs +++ b/wgpu/src/text.rs @@ -2,7 +2,7 @@ use crate::core::alignment; use crate::core::{Rectangle, Size}; use crate::graphics::color; use crate::graphics::text::cache::{self, Cache}; -use crate::graphics::text::{font_system, Paragraph}; +use crate::graphics::text::{font_system, Editor, Paragraph}; use crate::layer::Text; use std::borrow::Cow; @@ -74,15 +74,19 @@ impl Pipeline { enum Allocation { Paragraph(Paragraph), + Editor(Editor), Cache(cache::KeyHash), } let allocations: Vec<_> = sections .iter() .map(|section| match section { - Text::Managed { paragraph, .. } => { + Text::Paragraph { paragraph, .. } => { paragraph.upgrade().map(Allocation::Paragraph) } + Text::Editor { editor, .. } => { + editor.upgrade().map(Allocation::Editor) + } Text::Cached(text) => { let (key, _) = cache.allocate( font_system, @@ -117,7 +121,7 @@ impl Pipeline { vertical_alignment, color, ) = match section { - Text::Managed { + Text::Paragraph { position, color, .. } => { use crate::core::text::Paragraph as _; @@ -135,6 +139,24 @@ impl Pipeline { *color, ) } + Text::Editor { + position, color, .. + } => { + use crate::core::text::Editor as _; + + let Some(Allocation::Editor(editor)) = allocation + else { + return None; + }; + + ( + editor.buffer(), + Rectangle::new(*position, editor.min_bounds()), + alignment::Horizontal::Left, + alignment::Vertical::Top, + *color, + ) + } Text::Cached(text) => { let Some(Allocation::Cache(key)) = allocation else { return None; -- cgit From c7d02e24e6f8265c205a68bd97b2643d40ae30ee Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Thu, 14 Sep 2023 18:57:09 +0200 Subject: Remove `Editor::min_bounds` and use `bounds` instead --- wgpu/src/text.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'wgpu') diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs index 397c38dd..581df0cb 100644 --- a/wgpu/src/text.rs +++ b/wgpu/src/text.rs @@ -151,7 +151,7 @@ impl Pipeline { ( editor.buffer(), - Rectangle::new(*position, editor.min_bounds()), + Rectangle::new(*position, editor.bounds()), alignment::Horizontal::Left, alignment::Vertical::Top, *color, -- cgit From be340a8cd822be1ea0fe4c1b1f3a62ca66d705b4 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Tue, 19 Sep 2023 23:00:20 +0200 Subject: Fix gamma correction for colored glyphs in `iced_wgpu` --- wgpu/src/text.rs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs index 581df0cb..f746be63 100644 --- a/wgpu/src/text.rs +++ b/wgpu/src/text.rs @@ -2,7 +2,7 @@ use crate::core::alignment; use crate::core::{Rectangle, Size}; use crate::graphics::color; use crate::graphics::text::cache::{self, Cache}; -use crate::graphics::text::{font_system, Editor, Paragraph}; +use crate::graphics::text::{font_system, to_color, Editor, Paragraph}; use crate::layer::Text; use std::borrow::Cow; @@ -214,16 +214,7 @@ impl Pipeline { right: (clip_bounds.x + clip_bounds.width) as i32, bottom: (clip_bounds.y + clip_bounds.height) as i32, }, - default_color: { - let [r, g, b, a] = color::pack(color).components(); - - glyphon::Color::rgba( - (r * 255.0) as u8, - (g * 255.0) as u8, - (b * 255.0) as u8, - (a * 255.0) as u8, - ) - }, + default_color: to_color(color), }) }, ); -- cgit From 86b877517feb15b2155c6cfef29246a3f281c8ae Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Fri, 27 Oct 2023 03:21:40 +0200 Subject: Update `wgpu` to `0.18` and `cosmic-text` to `0.10` --- wgpu/src/backend.rs | 8 ++++++-- wgpu/src/color.rs | 4 +++- wgpu/src/triangle.rs | 7 ++++++- wgpu/src/triangle/msaa.rs | 4 +++- 4 files changed, 18 insertions(+), 5 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/backend.rs b/wgpu/src/backend.rs index 65c63f19..32b8a189 100644 --- a/wgpu/src/backend.rs +++ b/wgpu/src/backend.rs @@ -222,10 +222,12 @@ impl Backend { }), None => wgpu::LoadOp::Load, }, - store: true, + store: wgpu::StoreOp::Store, }, })], depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, }, )); @@ -271,11 +273,13 @@ impl Backend { resolve_target: None, ops: wgpu::Operations { load: wgpu::LoadOp::Load, - store: true, + store: wgpu::StoreOp::Store, }, }, )], depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, }, )); } diff --git a/wgpu/src/color.rs b/wgpu/src/color.rs index 20827e3c..4598b0a6 100644 --- a/wgpu/src/color.rs +++ b/wgpu/src/color.rs @@ -143,10 +143,12 @@ pub fn convert( resolve_target: None, ops: wgpu::Operations { load: wgpu::LoadOp::Load, - store: true, + store: wgpu::StoreOp::Store, }, })], depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, }); pass.set_pipeline(&pipeline); diff --git a/wgpu/src/triangle.rs b/wgpu/src/triangle.rs index 644c9f84..69270a73 100644 --- a/wgpu/src/triangle.rs +++ b/wgpu/src/triangle.rs @@ -300,10 +300,15 @@ impl Pipeline { wgpu::RenderPassColorAttachment { view: attachment, resolve_target, - ops: wgpu::Operations { load, store: true }, + ops: wgpu::Operations { + load, + store: wgpu::StoreOp::Store, + }, }, )], depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, }); let layer = &mut self.layers[layer]; diff --git a/wgpu/src/triangle/msaa.rs b/wgpu/src/triangle/msaa.rs index 320b5b12..14abd20b 100644 --- a/wgpu/src/triangle/msaa.rs +++ b/wgpu/src/triangle/msaa.rs @@ -167,10 +167,12 @@ impl Blit { resolve_target: None, ops: wgpu::Operations { load: wgpu::LoadOp::Load, - store: true, + store: wgpu::StoreOp::Store, }, })], depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, }); render_pass.set_pipeline(&self.pipeline); -- cgit From 625cd745f38215b1cb8f629cdc6d2fa41c9a739a Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Fri, 27 Oct 2023 05:04:14 +0200 Subject: Write documentation for the new text APIs --- wgpu/src/layer/text.rs | 7 ++++++- wgpu/src/lib.rs | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/layer/text.rs b/wgpu/src/layer/text.rs index d46b39da..66417cec 100644 --- a/wgpu/src/layer/text.rs +++ b/wgpu/src/layer/text.rs @@ -4,19 +4,24 @@ use crate::core::{Color, Font, Pixels, Point, Rectangle}; use crate::graphics::text::editor; use crate::graphics::text::paragraph; -/// A paragraph of text. +/// A text primitive. #[derive(Debug, Clone)] pub enum Text<'a> { + /// A paragraph. + #[allow(missing_docs)] Paragraph { paragraph: paragraph::Weak, position: Point, color: Color, }, + /// An editor. + #[allow(missing_docs)] Editor { editor: editor::Weak, position: Point, color: Color, }, + /// A cached text. Cached(Cached<'a>), } diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 6d26723e..424dfeb3 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -23,7 +23,7 @@ #![forbid(rust_2018_idioms)] #![deny( missing_debug_implementations, - //missing_docs, + missing_docs, unsafe_code, unused_results, rustdoc::broken_intra_doc_links -- cgit From 5759096a4c33935fcdf5f96606143e4f21159186 Mon Sep 17 00:00:00 2001 From: Remmirad <remmirad@posteo.net> Date: Wed, 31 May 2023 15:46:21 +0200 Subject: Implement texture filtering options --- wgpu/src/image.rs | 69 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 24 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/image.rs b/wgpu/src/image.rs index 553ba330..a0fe7e83 100644 --- a/wgpu/src/image.rs +++ b/wgpu/src/image.rs @@ -7,6 +7,7 @@ mod raster; mod vector; use atlas::Atlas; +use iced_graphics::core::image::{TextureFilter, FilterMethod}; use crate::core::{Rectangle, Size}; use crate::graphics::Transformation; @@ -14,6 +15,7 @@ use crate::layer; use crate::Buffer; use std::cell::RefCell; +use std::collections::HashMap; use std::mem; use bytemuck::{Pod, Zeroable}; @@ -37,7 +39,7 @@ pub struct Pipeline { pipeline: wgpu::RenderPipeline, vertices: wgpu::Buffer, indices: wgpu::Buffer, - sampler: wgpu::Sampler, + sampler: HashMap<TextureFilter,wgpu::Sampler>, texture: wgpu::BindGroup, texture_version: usize, texture_atlas: Atlas, @@ -142,15 +144,32 @@ impl Pipeline { pub fn new(device: &wgpu::Device, format: wgpu::TextureFormat) -> Self { use wgpu::util::DeviceExt; - let sampler = device.create_sampler(&wgpu::SamplerDescriptor { - address_mode_u: wgpu::AddressMode::ClampToEdge, - address_mode_v: wgpu::AddressMode::ClampToEdge, - address_mode_w: wgpu::AddressMode::ClampToEdge, - mag_filter: wgpu::FilterMode::Linear, - min_filter: wgpu::FilterMode::Linear, - mipmap_filter: wgpu::FilterMode::Linear, - ..Default::default() - }); + let to_wgpu = |method: FilterMethod| { + match method { + FilterMethod::Linear => wgpu::FilterMode::Linear, + FilterMethod::Nearest => wgpu::FilterMode::Nearest, + } + }; + + let mut sampler = HashMap::new(); + + let filter = [FilterMethod::Linear, FilterMethod::Nearest]; + for min in 0..filter.len() { + for mag in 0..filter.len() { + let _ = sampler.insert(TextureFilter {min: filter[min], mag: filter[mag]}, + device.create_sampler(&wgpu::SamplerDescriptor { + address_mode_u: wgpu::AddressMode::ClampToEdge, + address_mode_v: wgpu::AddressMode::ClampToEdge, + address_mode_w: wgpu::AddressMode::ClampToEdge, + mag_filter: to_wgpu(filter[mag]), + min_filter: to_wgpu(filter[min]), + mipmap_filter: wgpu::FilterMode::Linear, + ..Default::default() + } + )); + } + } + let constant_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { @@ -355,7 +374,7 @@ impl Pipeline { #[cfg(feature = "tracing")] let _ = info_span!("Wgpu::Image", "DRAW").entered(); - let instances: &mut Vec<Instance> = &mut Vec::new(); + let instances: &mut HashMap<TextureFilter,Vec<Instance>> = &mut HashMap::new(); #[cfg(feature = "image")] let mut raster_cache = self.raster_cache.borrow_mut(); @@ -377,7 +396,7 @@ impl Pipeline { [bounds.x, bounds.y], [bounds.width, bounds.height], atlas_entry, - instances, + instances.entry(handle.filter().clone()).or_insert(Vec::new()), ); } } @@ -405,7 +424,7 @@ impl Pipeline { [bounds.x, bounds.y], size, atlas_entry, - instances, + instances.entry(TextureFilter::default()).or_insert(Vec::new()), ); } } @@ -438,18 +457,20 @@ impl Pipeline { self.texture_version = texture_version; } - if self.layers.len() <= self.prepare_layer { - self.layers.push(Layer::new( - device, - &self.constant_layout, - &self.sampler, - )); + for (filter, instances) in instances.iter_mut() { + if self.layers.len() <= self.prepare_layer { + self.layers.push(Layer::new( + device, + &self.constant_layout, + &self.sampler.get(filter).expect("Sampler is registered"), + )); + } + + let layer = &mut self.layers[self.prepare_layer]; + layer.prepare(device, queue, &instances, transformation); + + self.prepare_layer += 1; } - - let layer = &mut self.layers[self.prepare_layer]; - layer.prepare(device, queue, instances, transformation); - - self.prepare_layer += 1; } pub fn render<'a>( -- cgit From 4b32a488808e371313ce78e727c9d98ab2eb759e Mon Sep 17 00:00:00 2001 From: Remmirad <remmirad@posteo.net> Date: Fri, 4 Aug 2023 13:50:16 +0200 Subject: Fix clippy + fmt --- wgpu/src/image.rs | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/image.rs b/wgpu/src/image.rs index a0fe7e83..a3168001 100644 --- a/wgpu/src/image.rs +++ b/wgpu/src/image.rs @@ -7,7 +7,7 @@ mod raster; mod vector; use atlas::Atlas; -use iced_graphics::core::image::{TextureFilter, FilterMethod}; +use iced_graphics::core::image::{FilterMethod, TextureFilter}; use crate::core::{Rectangle, Size}; use crate::graphics::Transformation; @@ -39,7 +39,7 @@ pub struct Pipeline { pipeline: wgpu::RenderPipeline, vertices: wgpu::Buffer, indices: wgpu::Buffer, - sampler: HashMap<TextureFilter,wgpu::Sampler>, + sampler: HashMap<TextureFilter, wgpu::Sampler>, texture: wgpu::BindGroup, texture_version: usize, texture_atlas: Atlas, @@ -144,11 +144,9 @@ impl Pipeline { pub fn new(device: &wgpu::Device, format: wgpu::TextureFormat) -> Self { use wgpu::util::DeviceExt; - let to_wgpu = |method: FilterMethod| { - match method { - FilterMethod::Linear => wgpu::FilterMode::Linear, - FilterMethod::Nearest => wgpu::FilterMode::Nearest, - } + let to_wgpu = |method: FilterMethod| match method { + FilterMethod::Linear => wgpu::FilterMode::Linear, + FilterMethod::Nearest => wgpu::FilterMode::Nearest, }; let mut sampler = HashMap::new(); @@ -156,7 +154,11 @@ impl Pipeline { let filter = [FilterMethod::Linear, FilterMethod::Nearest]; for min in 0..filter.len() { for mag in 0..filter.len() { - let _ = sampler.insert(TextureFilter {min: filter[min], mag: filter[mag]}, + let _ = sampler.insert( + TextureFilter { + min: filter[min], + mag: filter[mag], + }, device.create_sampler(&wgpu::SamplerDescriptor { address_mode_u: wgpu::AddressMode::ClampToEdge, address_mode_v: wgpu::AddressMode::ClampToEdge, @@ -165,12 +167,11 @@ impl Pipeline { min_filter: to_wgpu(filter[min]), mipmap_filter: wgpu::FilterMode::Linear, ..Default::default() - } - )); + }), + ); } } - let constant_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { label: Some("iced_wgpu::image constants layout"), @@ -374,7 +375,8 @@ impl Pipeline { #[cfg(feature = "tracing")] let _ = info_span!("Wgpu::Image", "DRAW").entered(); - let instances: &mut HashMap<TextureFilter,Vec<Instance>> = &mut HashMap::new(); + let instances: &mut HashMap<TextureFilter, Vec<Instance>> = + &mut HashMap::new(); #[cfg(feature = "image")] let mut raster_cache = self.raster_cache.borrow_mut(); @@ -396,7 +398,9 @@ impl Pipeline { [bounds.x, bounds.y], [bounds.width, bounds.height], atlas_entry, - instances.entry(handle.filter().clone()).or_insert(Vec::new()), + instances + .entry(handle.filter().clone()) + .or_insert(Vec::new()), ); } } @@ -424,7 +428,9 @@ impl Pipeline { [bounds.x, bounds.y], size, atlas_entry, - instances.entry(TextureFilter::default()).or_insert(Vec::new()), + instances + .entry(TextureFilter::default()) + .or_insert(Vec::new()), ); } } @@ -462,13 +468,13 @@ impl Pipeline { self.layers.push(Layer::new( device, &self.constant_layout, - &self.sampler.get(filter).expect("Sampler is registered"), + self.sampler.get(filter).expect("Sampler is registered"), )); } - + let layer = &mut self.layers[self.prepare_layer]; - layer.prepare(device, queue, &instances, transformation); - + layer.prepare(device, queue, instances, transformation); + self.prepare_layer += 1; } } -- cgit From e5d3e75d826e9fad8a0da5dd538aa542059dd034 Mon Sep 17 00:00:00 2001 From: Remmirad <remmirad@posteo.net> Date: Mon, 25 Sep 2023 21:54:50 +0200 Subject: fix design for wgpu backend --- wgpu/src/image.rs | 133 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 77 insertions(+), 56 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/image.rs b/wgpu/src/image.rs index a3168001..0aa7f899 100644 --- a/wgpu/src/image.rs +++ b/wgpu/src/image.rs @@ -8,6 +8,7 @@ mod vector; use atlas::Atlas; use iced_graphics::core::image::{FilterMethod, TextureFilter}; +use wgpu::Sampler; use crate::core::{Rectangle, Size}; use crate::graphics::Transformation; @@ -15,7 +16,6 @@ use crate::layer; use crate::Buffer; use std::cell::RefCell; -use std::collections::HashMap; use std::mem; use bytemuck::{Pod, Zeroable}; @@ -29,6 +29,8 @@ use crate::core::svg; #[cfg(feature = "tracing")] use tracing::info_span; +const SAMPLER_COUNT: usize = 4; + #[derive(Debug)] pub struct Pipeline { #[cfg(feature = "image")] @@ -39,14 +41,14 @@ pub struct Pipeline { pipeline: wgpu::RenderPipeline, vertices: wgpu::Buffer, indices: wgpu::Buffer, - sampler: HashMap<TextureFilter, wgpu::Sampler>, + sampler: [wgpu::Sampler; SAMPLER_COUNT], texture: wgpu::BindGroup, texture_version: usize, texture_atlas: Atlas, texture_layout: wgpu::BindGroupLayout, constant_layout: wgpu::BindGroupLayout, - layers: Vec<Layer>, + layers: Vec<[Option<Layer>; SAMPLER_COUNT]>, prepare_layer: usize, } @@ -149,28 +151,32 @@ impl Pipeline { FilterMethod::Nearest => wgpu::FilterMode::Nearest, }; - let mut sampler = HashMap::new(); + let mut sampler: [Option<Sampler>; SAMPLER_COUNT] = + [None, None, None, None]; let filter = [FilterMethod::Linear, FilterMethod::Nearest]; for min in 0..filter.len() { for mag in 0..filter.len() { - let _ = sampler.insert( - TextureFilter { - min: filter[min], - mag: filter[mag], - }, - device.create_sampler(&wgpu::SamplerDescriptor { - address_mode_u: wgpu::AddressMode::ClampToEdge, - address_mode_v: wgpu::AddressMode::ClampToEdge, - address_mode_w: wgpu::AddressMode::ClampToEdge, - mag_filter: to_wgpu(filter[mag]), - min_filter: to_wgpu(filter[min]), - mipmap_filter: wgpu::FilterMode::Linear, - ..Default::default() - }), - ); + sampler[to_index(&TextureFilter { + min: filter[min], + mag: filter[mag], + })] = Some(device.create_sampler(&wgpu::SamplerDescriptor { + address_mode_u: wgpu::AddressMode::ClampToEdge, + address_mode_v: wgpu::AddressMode::ClampToEdge, + address_mode_w: wgpu::AddressMode::ClampToEdge, + mag_filter: to_wgpu(filter[mag]), + min_filter: to_wgpu(filter[min]), + mipmap_filter: wgpu::FilterMode::Linear, + ..Default::default() + })); } } + let sampler = [ + sampler[0].take().unwrap(), + sampler[1].take().unwrap(), + sampler[2].take().unwrap(), + sampler[3].take().unwrap(), + ]; let constant_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { @@ -375,8 +381,8 @@ impl Pipeline { #[cfg(feature = "tracing")] let _ = info_span!("Wgpu::Image", "DRAW").entered(); - let instances: &mut HashMap<TextureFilter, Vec<Instance>> = - &mut HashMap::new(); + let mut instances: [Vec<Instance>; SAMPLER_COUNT] = + [Vec::new(), Vec::new(), Vec::new(), Vec::new()]; #[cfg(feature = "image")] let mut raster_cache = self.raster_cache.borrow_mut(); @@ -398,9 +404,7 @@ impl Pipeline { [bounds.x, bounds.y], [bounds.width, bounds.height], atlas_entry, - instances - .entry(handle.filter().clone()) - .or_insert(Vec::new()), + &mut instances[to_index(handle.filter())], ); } } @@ -428,9 +432,7 @@ impl Pipeline { [bounds.x, bounds.y], size, atlas_entry, - instances - .entry(TextureFilter::default()) - .or_insert(Vec::new()), + &mut instances[to_index(&TextureFilter::default())], ); } } @@ -463,20 +465,26 @@ impl Pipeline { self.texture_version = texture_version; } - for (filter, instances) in instances.iter_mut() { - if self.layers.len() <= self.prepare_layer { - self.layers.push(Layer::new( - device, - &self.constant_layout, - self.sampler.get(filter).expect("Sampler is registered"), - )); + if self.layers.len() <= self.prepare_layer { + self.layers.push([None, None, None, None]); + } + for (i, instances) in instances.iter_mut().enumerate() { + let layer = &mut self.layers[self.prepare_layer][i]; + if !instances.is_empty() { + if layer.is_none() { + *layer = Some(Layer::new( + device, + &self.constant_layout, + &self.sampler[i], + )) + } } - let layer = &mut self.layers[self.prepare_layer]; - layer.prepare(device, queue, instances, transformation); - - self.prepare_layer += 1; + if let Some(layer) = layer { + layer.prepare(device, queue, instances, transformation); + } } + self.prepare_layer += 1; } pub fn render<'a>( @@ -485,24 +493,29 @@ impl Pipeline { bounds: Rectangle<u32>, render_pass: &mut wgpu::RenderPass<'a>, ) { - if let Some(layer) = self.layers.get(layer) { - render_pass.set_pipeline(&self.pipeline); - - render_pass.set_scissor_rect( - bounds.x, - bounds.y, - bounds.width, - bounds.height, - ); - - render_pass.set_bind_group(1, &self.texture, &[]); - render_pass.set_index_buffer( - self.indices.slice(..), - wgpu::IndexFormat::Uint16, - ); - render_pass.set_vertex_buffer(0, self.vertices.slice(..)); - - layer.render(render_pass); + if let Some(layer_group) = self.layers.get(layer) { + for (i, layer) in layer_group.iter().enumerate() { + if let Some(layer) = layer { + println!("Render {i}"); + render_pass.set_pipeline(&self.pipeline); + + render_pass.set_scissor_rect( + bounds.x, + bounds.y, + bounds.width, + bounds.height, + ); + + render_pass.set_bind_group(1, &self.texture, &[]); + render_pass.set_index_buffer( + self.indices.slice(..), + wgpu::IndexFormat::Uint16, + ); + render_pass.set_vertex_buffer(0, self.vertices.slice(..)); + + layer.render(render_pass); + } + } } } @@ -517,6 +530,14 @@ impl Pipeline { } } +fn to_index(filter: &TextureFilter) -> usize { + let to_index = |m| match m { + FilterMethod::Linear => 0, + FilterMethod::Nearest => 1, + }; + return (to_index(filter.mag) << 1) | (to_index(filter.min)); +} + #[repr(C)] #[derive(Clone, Copy, Zeroable, Pod)] pub struct Vertex { -- cgit From 75c9afc608a4a9ff44d60a8fb6f4a5819f05bf79 Mon Sep 17 00:00:00 2001 From: Remmirad <remmirad@posteo.net> Date: Mon, 25 Sep 2023 22:03:22 +0200 Subject: Remove debug traces --- wgpu/src/image.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/image.rs b/wgpu/src/image.rs index 0aa7f899..6768a714 100644 --- a/wgpu/src/image.rs +++ b/wgpu/src/image.rs @@ -494,9 +494,8 @@ impl Pipeline { render_pass: &mut wgpu::RenderPass<'a>, ) { if let Some(layer_group) = self.layers.get(layer) { - for (i, layer) in layer_group.iter().enumerate() { + for layer in layer_group.iter() { if let Some(layer) = layer { - println!("Render {i}"); render_pass.set_pipeline(&self.pipeline); render_pass.set_scissor_rect( -- cgit From a5125d6fea824df1191777fe3eb53a2f748208b9 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Sat, 11 Nov 2023 07:02:01 +0100 Subject: Refactor texture image filtering - Support only `Linear` or `Nearest` - Simplify `Layer` groups - Move `FilterMethod` to `Image` and `image::Viewer` --- wgpu/src/image.rs | 238 +++++++++++++++++++++++++++--------------------- wgpu/src/layer.rs | 7 +- wgpu/src/layer/image.rs | 3 + 3 files changed, 141 insertions(+), 107 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/image.rs b/wgpu/src/image.rs index 6768a714..1a88c6ae 100644 --- a/wgpu/src/image.rs +++ b/wgpu/src/image.rs @@ -7,8 +7,6 @@ mod raster; mod vector; use atlas::Atlas; -use iced_graphics::core::image::{FilterMethod, TextureFilter}; -use wgpu::Sampler; use crate::core::{Rectangle, Size}; use crate::graphics::Transformation; @@ -29,8 +27,6 @@ use crate::core::svg; #[cfg(feature = "tracing")] use tracing::info_span; -const SAMPLER_COUNT: usize = 4; - #[derive(Debug)] pub struct Pipeline { #[cfg(feature = "image")] @@ -41,30 +37,31 @@ pub struct Pipeline { pipeline: wgpu::RenderPipeline, vertices: wgpu::Buffer, indices: wgpu::Buffer, - sampler: [wgpu::Sampler; SAMPLER_COUNT], + nearest_sampler: wgpu::Sampler, + linear_sampler: wgpu::Sampler, texture: wgpu::BindGroup, texture_version: usize, texture_atlas: Atlas, texture_layout: wgpu::BindGroupLayout, constant_layout: wgpu::BindGroupLayout, - layers: Vec<[Option<Layer>; SAMPLER_COUNT]>, + layers: Vec<Layer>, prepare_layer: usize, } #[derive(Debug)] struct Layer { uniforms: wgpu::Buffer, - constants: wgpu::BindGroup, - instances: Buffer<Instance>, - instance_count: usize, + nearest: Data, + linear: Data, } impl Layer { fn new( device: &wgpu::Device, constant_layout: &wgpu::BindGroupLayout, - sampler: &wgpu::Sampler, + nearest_sampler: &wgpu::Sampler, + linear_sampler: &wgpu::Sampler, ) -> Self { let uniforms = device.create_buffer(&wgpu::BufferDescriptor { label: Some("iced_wgpu::image uniforms buffer"), @@ -73,6 +70,59 @@ impl Layer { mapped_at_creation: false, }); + let nearest = + Data::new(device, constant_layout, nearest_sampler, &uniforms); + + let linear = + Data::new(device, constant_layout, linear_sampler, &uniforms); + + Self { + uniforms, + nearest, + linear, + } + } + + fn prepare( + &mut self, + device: &wgpu::Device, + queue: &wgpu::Queue, + nearest_instances: &[Instance], + linear_instances: &[Instance], + transformation: Transformation, + ) { + queue.write_buffer( + &self.uniforms, + 0, + bytemuck::bytes_of(&Uniforms { + transform: transformation.into(), + }), + ); + + self.nearest.upload(device, queue, nearest_instances); + self.linear.upload(device, queue, linear_instances); + } + + fn render<'a>(&'a self, render_pass: &mut wgpu::RenderPass<'a>) { + self.nearest.render(render_pass); + self.linear.render(render_pass); + } +} + +#[derive(Debug)] +struct Data { + constants: wgpu::BindGroup, + instances: Buffer<Instance>, + instance_count: usize, +} + +impl Data { + pub fn new( + device: &wgpu::Device, + constant_layout: &wgpu::BindGroupLayout, + sampler: &wgpu::Sampler, + uniforms: &wgpu::Buffer, + ) -> Self { let constants = device.create_bind_group(&wgpu::BindGroupDescriptor { label: Some("iced_wgpu::image constants bind group"), layout: constant_layout, @@ -102,28 +152,18 @@ impl Layer { ); Self { - uniforms, constants, instances, instance_count: 0, } } - fn prepare( + fn upload( &mut self, device: &wgpu::Device, queue: &wgpu::Queue, instances: &[Instance], - transformation: Transformation, ) { - queue.write_buffer( - &self.uniforms, - 0, - bytemuck::bytes_of(&Uniforms { - transform: transformation.into(), - }), - ); - let _ = self.instances.resize(device, instances.len()); let _ = self.instances.write(queue, 0, instances); @@ -146,37 +186,25 @@ impl Pipeline { pub fn new(device: &wgpu::Device, format: wgpu::TextureFormat) -> Self { use wgpu::util::DeviceExt; - let to_wgpu = |method: FilterMethod| match method { - FilterMethod::Linear => wgpu::FilterMode::Linear, - FilterMethod::Nearest => wgpu::FilterMode::Nearest, - }; - - let mut sampler: [Option<Sampler>; SAMPLER_COUNT] = - [None, None, None, None]; - - let filter = [FilterMethod::Linear, FilterMethod::Nearest]; - for min in 0..filter.len() { - for mag in 0..filter.len() { - sampler[to_index(&TextureFilter { - min: filter[min], - mag: filter[mag], - })] = Some(device.create_sampler(&wgpu::SamplerDescriptor { - address_mode_u: wgpu::AddressMode::ClampToEdge, - address_mode_v: wgpu::AddressMode::ClampToEdge, - address_mode_w: wgpu::AddressMode::ClampToEdge, - mag_filter: to_wgpu(filter[mag]), - min_filter: to_wgpu(filter[min]), - mipmap_filter: wgpu::FilterMode::Linear, - ..Default::default() - })); - } - } - let sampler = [ - sampler[0].take().unwrap(), - sampler[1].take().unwrap(), - sampler[2].take().unwrap(), - sampler[3].take().unwrap(), - ]; + let nearest_sampler = device.create_sampler(&wgpu::SamplerDescriptor { + address_mode_u: wgpu::AddressMode::ClampToEdge, + address_mode_v: wgpu::AddressMode::ClampToEdge, + address_mode_w: wgpu::AddressMode::ClampToEdge, + min_filter: wgpu::FilterMode::Nearest, + mag_filter: wgpu::FilterMode::Nearest, + mipmap_filter: wgpu::FilterMode::Nearest, + ..Default::default() + }); + + let linear_sampler = device.create_sampler(&wgpu::SamplerDescriptor { + address_mode_u: wgpu::AddressMode::ClampToEdge, + address_mode_v: wgpu::AddressMode::ClampToEdge, + address_mode_w: wgpu::AddressMode::ClampToEdge, + min_filter: wgpu::FilterMode::Linear, + mag_filter: wgpu::FilterMode::Linear, + mipmap_filter: wgpu::FilterMode::Linear, + ..Default::default() + }); let constant_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { @@ -338,7 +366,8 @@ impl Pipeline { pipeline, vertices, indices, - sampler, + nearest_sampler, + linear_sampler, texture, texture_version: texture_atlas.layer_count(), texture_atlas, @@ -381,8 +410,8 @@ impl Pipeline { #[cfg(feature = "tracing")] let _ = info_span!("Wgpu::Image", "DRAW").entered(); - let mut instances: [Vec<Instance>; SAMPLER_COUNT] = - [Vec::new(), Vec::new(), Vec::new(), Vec::new()]; + let nearest_instances: &mut Vec<Instance> = &mut Vec::new(); + let linear_instances: &mut Vec<Instance> = &mut Vec::new(); #[cfg(feature = "image")] let mut raster_cache = self.raster_cache.borrow_mut(); @@ -393,7 +422,11 @@ impl Pipeline { for image in images { match &image { #[cfg(feature = "image")] - layer::Image::Raster { handle, bounds } => { + layer::Image::Raster { + handle, + filter_method, + bounds, + } => { if let Some(atlas_entry) = raster_cache.upload( device, encoder, @@ -404,7 +437,12 @@ impl Pipeline { [bounds.x, bounds.y], [bounds.width, bounds.height], atlas_entry, - &mut instances[to_index(handle.filter())], + match filter_method { + image::FilterMethod::Nearest => { + nearest_instances + } + image::FilterMethod::Linear => linear_instances, + }, ); } } @@ -432,7 +470,7 @@ impl Pipeline { [bounds.x, bounds.y], size, atlas_entry, - &mut instances[to_index(&TextureFilter::default())], + nearest_instances, ); } } @@ -441,7 +479,7 @@ impl Pipeline { } } - if instances.is_empty() { + if nearest_instances.is_empty() && linear_instances.is_empty() { return; } @@ -466,24 +504,24 @@ impl Pipeline { } if self.layers.len() <= self.prepare_layer { - self.layers.push([None, None, None, None]); + self.layers.push(Layer::new( + device, + &self.constant_layout, + &self.nearest_sampler, + &self.linear_sampler, + )); } - for (i, instances) in instances.iter_mut().enumerate() { - let layer = &mut self.layers[self.prepare_layer][i]; - if !instances.is_empty() { - if layer.is_none() { - *layer = Some(Layer::new( - device, - &self.constant_layout, - &self.sampler[i], - )) - } - } - if let Some(layer) = layer { - layer.prepare(device, queue, instances, transformation); - } - } + let layer = &mut self.layers[self.prepare_layer]; + + layer.prepare( + device, + queue, + &nearest_instances, + &linear_instances, + transformation, + ); + self.prepare_layer += 1; } @@ -493,28 +531,24 @@ impl Pipeline { bounds: Rectangle<u32>, render_pass: &mut wgpu::RenderPass<'a>, ) { - if let Some(layer_group) = self.layers.get(layer) { - for layer in layer_group.iter() { - if let Some(layer) = layer { - render_pass.set_pipeline(&self.pipeline); - - render_pass.set_scissor_rect( - bounds.x, - bounds.y, - bounds.width, - bounds.height, - ); - - render_pass.set_bind_group(1, &self.texture, &[]); - render_pass.set_index_buffer( - self.indices.slice(..), - wgpu::IndexFormat::Uint16, - ); - render_pass.set_vertex_buffer(0, self.vertices.slice(..)); - - layer.render(render_pass); - } - } + if let Some(layer) = self.layers.get(layer) { + render_pass.set_pipeline(&self.pipeline); + + render_pass.set_scissor_rect( + bounds.x, + bounds.y, + bounds.width, + bounds.height, + ); + + render_pass.set_bind_group(1, &self.texture, &[]); + render_pass.set_index_buffer( + self.indices.slice(..), + wgpu::IndexFormat::Uint16, + ); + render_pass.set_vertex_buffer(0, self.vertices.slice(..)); + + layer.render(render_pass); } } @@ -529,14 +563,6 @@ impl Pipeline { } } -fn to_index(filter: &TextureFilter) -> usize { - let to_index = |m| match m { - FilterMethod::Linear => 0, - FilterMethod::Nearest => 1, - }; - return (to_index(filter.mag) << 1) | (to_index(filter.min)); -} - #[repr(C)] #[derive(Clone, Copy, Zeroable, Pod)] pub struct Vertex { @@ -571,7 +597,7 @@ struct Instance { } impl Instance { - pub const INITIAL: usize = 1_000; + pub const INITIAL: usize = 20; } #[repr(C)] diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs index b251538e..286801e6 100644 --- a/wgpu/src/layer.rs +++ b/wgpu/src/layer.rs @@ -186,11 +186,16 @@ impl<'a> Layer<'a> { layer.quads.add(quad, background); } - Primitive::Image { handle, bounds } => { + Primitive::Image { + handle, + filter_method, + bounds, + } => { let layer = &mut layers[current_layer]; layer.images.push(Image::Raster { handle: handle.clone(), + filter_method: *filter_method, bounds: *bounds + translation, }); } diff --git a/wgpu/src/layer/image.rs b/wgpu/src/layer/image.rs index 0de589f8..facbe192 100644 --- a/wgpu/src/layer/image.rs +++ b/wgpu/src/layer/image.rs @@ -10,6 +10,9 @@ pub enum Image { /// The handle of a raster image. handle: image::Handle, + /// The filter method of a raster image. + filter_method: image::FilterMethod, + /// The bounds of the image. bounds: Rectangle, }, -- cgit From 9d560c813566ba04be3e23ae1b14861365485b57 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Sat, 11 Nov 2023 07:27:38 +0100 Subject: Fix unnecessary references in `iced_wgpu::image` --- wgpu/src/image.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/image.rs b/wgpu/src/image.rs index 1a88c6ae..b78802c7 100644 --- a/wgpu/src/image.rs +++ b/wgpu/src/image.rs @@ -131,7 +131,7 @@ impl Data { binding: 0, resource: wgpu::BindingResource::Buffer( wgpu::BufferBinding { - buffer: &uniforms, + buffer: uniforms, offset: 0, size: None, }, @@ -517,8 +517,8 @@ impl Pipeline { layer.prepare( device, queue, - &nearest_instances, - &linear_instances, + nearest_instances, + linear_instances, transformation, ); -- cgit From 781ef1f94c4859aeeb852f801b72be095b8ff82b Mon Sep 17 00:00:00 2001 From: Bingus <shankern@protonmail.com> Date: Thu, 14 Sep 2023 13:58:36 -0700 Subject: Added support for custom shader widget for iced_wgpu backend. --- wgpu/src/backend.rs | 64 +++++++++++++++++++++++++++++++++++++++-- wgpu/src/custom.rs | 66 +++++++++++++++++++++++++++++++++++++++++++ wgpu/src/layer.rs | 16 +++++++++++ wgpu/src/lib.rs | 1 + wgpu/src/primitive.rs | 36 +++++++++++++++++++++++ wgpu/src/window/compositor.rs | 2 ++ 6 files changed, 182 insertions(+), 3 deletions(-) create mode 100644 wgpu/src/custom.rs (limited to 'wgpu') diff --git a/wgpu/src/backend.rs b/wgpu/src/backend.rs index 2bd29f42..907611d9 100644 --- a/wgpu/src/backend.rs +++ b/wgpu/src/backend.rs @@ -3,9 +3,7 @@ use crate::graphics::backend; use crate::graphics::color; use crate::graphics::{Transformation, Viewport}; use crate::primitive::{self, Primitive}; -use crate::quad; -use crate::text; -use crate::triangle; +use crate::{custom, quad, text, triangle}; use crate::{Layer, Settings}; #[cfg(feature = "tracing")] @@ -25,6 +23,7 @@ pub struct Backend { quad_pipeline: quad::Pipeline, text_pipeline: text::Pipeline, triangle_pipeline: triangle::Pipeline, + pipeline_storage: custom::Storage, #[cfg(any(feature = "image", feature = "svg"))] image_pipeline: image::Pipeline, @@ -50,6 +49,7 @@ impl Backend { quad_pipeline, text_pipeline, triangle_pipeline, + pipeline_storage: custom::Storage::default(), #[cfg(any(feature = "image", feature = "svg"))] image_pipeline, @@ -66,6 +66,7 @@ impl Backend { queue: &wgpu::Queue, encoder: &mut wgpu::CommandEncoder, clear_color: Option<Color>, + format: wgpu::TextureFormat, frame: &wgpu::TextureView, primitives: &[Primitive], viewport: &Viewport, @@ -88,6 +89,7 @@ impl Backend { self.prepare( device, queue, + format, encoder, scale_factor, target_size, @@ -117,6 +119,7 @@ impl Backend { &mut self, device: &wgpu::Device, queue: &wgpu::Queue, + format: wgpu::TextureFormat, _encoder: &mut wgpu::CommandEncoder, scale_factor: f32, target_size: Size<u32>, @@ -179,6 +182,20 @@ impl Backend { target_size, ); } + + if !layer.shaders.is_empty() { + for shader in &layer.shaders { + shader.primitive.prepare( + format, + device, + queue, + target_size, + scale_factor, + transformation, + &mut self.pipeline_storage, + ); + } + } } } @@ -302,6 +319,47 @@ impl Backend { text_layer += 1; } + + // kill render pass to let custom shaders get mut access to encoder + let _ = ManuallyDrop::into_inner(render_pass); + + if !layer.shaders.is_empty() { + for shader in &layer.shaders { + //This extra check is needed since each custom pipeline must set it's own + //scissor rect, which will panic if bounds.w/h < 1 + let bounds = shader.bounds * scale_factor; + + if bounds.width < 1.0 || bounds.height < 1.0 { + continue; + } + + shader.primitive.render( + &self.pipeline_storage, + bounds.into(), + target, + target_size, + encoder, + ); + } + } + + // recreate and continue processing layers + render_pass = ManuallyDrop::new(encoder.begin_render_pass( + &wgpu::RenderPassDescriptor { + label: Some("iced_wgpu::quad render pass"), + color_attachments: &[Some( + wgpu::RenderPassColorAttachment { + view: target, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Load, + store: true, + }, + }, + )], + depth_stencil_attachment: None, + }, + )); } let _ = ManuallyDrop::into_inner(render_pass); diff --git a/wgpu/src/custom.rs b/wgpu/src/custom.rs new file mode 100644 index 00000000..65dd0496 --- /dev/null +++ b/wgpu/src/custom.rs @@ -0,0 +1,66 @@ +use crate::core::{Rectangle, Size}; +use crate::graphics::Transformation; +use std::any::{Any, TypeId}; +use std::collections::HashMap; +use std::fmt::Debug; + +/// Stores custom, user-provided pipelines. +#[derive(Default, Debug)] +pub struct Storage { + pipelines: HashMap<TypeId, Box<dyn Any>>, +} + +impl Storage { + /// Returns `true` if `Storage` contains a pipeline with type `T`. + pub fn has<T: 'static>(&self) -> bool { + self.pipelines.get(&TypeId::of::<T>()).is_some() + } + + /// Inserts the pipeline `T` in to [`Storage`]. + pub fn store<T: 'static>(&mut self, pipeline: T) { + let _ = self.pipelines.insert(TypeId::of::<T>(), Box::new(pipeline)); + } + + /// Returns a reference to pipeline with type `T` if it exists in [`Storage`]. + pub fn get<T: 'static>(&self) -> Option<&T> { + self.pipelines.get(&TypeId::of::<T>()).map(|pipeline| { + pipeline + .downcast_ref::<T>() + .expect("Pipeline with this type does not exist in Storage.") + }) + } + + /// Returns a mutable reference to pipeline `T` if it exists in [`Storage`]. + pub fn get_mut<T: 'static>(&mut self) -> Option<&mut T> { + self.pipelines.get_mut(&TypeId::of::<T>()).map(|pipeline| { + pipeline + .downcast_mut::<T>() + .expect("Pipeline with this type does not exist in Storage.") + }) + } +} + +/// A set of methods which allows a [`Primitive`] to be rendered. +pub trait Primitive: Debug + Send + Sync + 'static { + /// Processes the [`Primitive`], allowing for GPU buffer allocation. + fn prepare( + &self, + format: wgpu::TextureFormat, + device: &wgpu::Device, + queue: &wgpu::Queue, + target_size: Size<u32>, + scale_factor: f32, + transform: Transformation, + storage: &mut Storage, + ); + + /// Renders the [`Primitive`]. + fn render( + &self, + storage: &Storage, + bounds: Rectangle<u32>, + target: &wgpu::TextureView, + target_size: Size<u32>, + encoder: &mut wgpu::CommandEncoder, + ); +} diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs index 286801e6..d451cbfd 100644 --- a/wgpu/src/layer.rs +++ b/wgpu/src/layer.rs @@ -34,6 +34,9 @@ pub struct Layer<'a> { /// The images of the [`Layer`]. pub images: Vec<Image>, + + /// The custom shader primitives of this [`Layer`]. + pub shaders: Vec<primitive::Shader>, } impl<'a> Layer<'a> { @@ -45,6 +48,7 @@ impl<'a> Layer<'a> { meshes: Vec::new(), text: Vec::new(), images: Vec::new(), + shaders: Vec::new(), } } @@ -308,6 +312,18 @@ impl<'a> Layer<'a> { } } }, + primitive::Custom::Shader(shader) => { + let layer = &mut layers[current_layer]; + + let bounds = Rectangle::new( + Point::new(translation.x, translation.y), + shader.bounds.size(), + ); + + if layer.bounds.intersection(&bounds).is_some() { + layer.shaders.push(shader.clone()); + } + } }, } } diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 424dfeb3..13d8e886 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -29,6 +29,7 @@ rustdoc::broken_intra_doc_links )] #![cfg_attr(docsrs, feature(doc_auto_cfg))] +pub mod custom; pub mod layer; pub mod primitive; pub mod settings; diff --git a/wgpu/src/primitive.rs b/wgpu/src/primitive.rs index 8dbf3008..4347dcda 100644 --- a/wgpu/src/primitive.rs +++ b/wgpu/src/primitive.rs @@ -1,6 +1,10 @@ //! Draw using different graphical primitives. use crate::core::Rectangle; +use crate::custom; use crate::graphics::{Damage, Mesh}; +use std::any::Any; +use std::fmt::Debug; +use std::sync::Arc; /// The graphical primitives supported by `iced_wgpu`. pub type Primitive = crate::graphics::Primitive<Custom>; @@ -10,12 +14,44 @@ pub type Primitive = crate::graphics::Primitive<Custom>; pub enum Custom { /// A mesh primitive. Mesh(Mesh), + /// A custom shader primitive + Shader(Shader), +} + +impl Custom { + /// Create a custom [`Shader`] primitive. + pub fn shader<P: custom::Primitive>( + bounds: Rectangle, + primitive: P, + ) -> Self { + Self::Shader(Shader { + bounds, + primitive: Arc::new(primitive), + }) + } } impl Damage for Custom { fn bounds(&self) -> Rectangle { match self { Self::Mesh(mesh) => mesh.bounds(), + Self::Shader(shader) => shader.bounds, } } } + +#[derive(Clone, Debug)] +/// A custom primitive which can be used to render primitives associated with a custom pipeline. +pub struct Shader { + /// The bounds of the [`Shader`]. + pub bounds: Rectangle, + + /// The [`custom::Primitive`] to render. + pub primitive: Arc<dyn custom::Primitive>, +} + +impl PartialEq for Shader { + fn eq(&self, other: &Self) -> bool { + self.primitive.type_id() == other.primitive.type_id() + } +} diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index 1ddbe5fe..90d64e17 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -178,6 +178,7 @@ pub fn present<Theme, T: AsRef<str>>( &compositor.queue, &mut encoder, Some(background_color), + frame.texture.format(), view, primitives, viewport, @@ -357,6 +358,7 @@ pub fn screenshot<Theme, T: AsRef<str>>( &compositor.queue, &mut encoder, Some(background_color), + texture.format(), &view, primitives, viewport, -- cgit From 36e85215932079fa324cfefb620602ad79f7df3d Mon Sep 17 00:00:00 2001 From: Bingus <shankern@protonmail.com> Date: Mon, 18 Sep 2023 09:04:28 -0700 Subject: Removed `Into` for Rectangle<f32> from u32 --- wgpu/src/backend.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'wgpu') diff --git a/wgpu/src/backend.rs b/wgpu/src/backend.rs index 907611d9..ace2ef95 100644 --- a/wgpu/src/backend.rs +++ b/wgpu/src/backend.rs @@ -335,7 +335,7 @@ impl Backend { shader.primitive.render( &self.pipeline_storage, - bounds.into(), + bounds.snap(), target, target_size, encoder, -- cgit From de9420e7df7d909bca611c360182dec54c5b1aae Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Tue, 14 Nov 2023 11:33:04 +0100 Subject: Fix latest `wgpu` changes --- wgpu/src/backend.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'wgpu') diff --git a/wgpu/src/backend.rs b/wgpu/src/backend.rs index ace2ef95..27ef0b3c 100644 --- a/wgpu/src/backend.rs +++ b/wgpu/src/backend.rs @@ -353,11 +353,13 @@ impl Backend { resolve_target: None, ops: wgpu::Operations { load: wgpu::LoadOp::Load, - store: true, + store: wgpu::StoreOp::Store, }, }, )], depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, }, )); } -- cgit From 46a48af97fa472e1158e07d4deb988c5601197e0 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Tue, 14 Nov 2023 11:34:15 +0100 Subject: Write missing documentation for `custom` module in `iced_wgpu` --- wgpu/src/custom.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'wgpu') diff --git a/wgpu/src/custom.rs b/wgpu/src/custom.rs index 65dd0496..65a6f133 100644 --- a/wgpu/src/custom.rs +++ b/wgpu/src/custom.rs @@ -1,3 +1,4 @@ +//! Draw custom primitives. use crate::core::{Rectangle, Size}; use crate::graphics::Transformation; use std::any::{Any, TypeId}; -- cgit From 9489e29e6619b14ed9f41a8887c4b34158266f71 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Tue, 14 Nov 2023 12:49:49 +0100 Subject: Re-organize `custom` module as `pipeline` module ... and move `Shader` widget to `iced_widget` crate --- wgpu/src/backend.rs | 29 +++++----- wgpu/src/custom.rs | 63 +--------------------- wgpu/src/layer.rs | 19 ++++--- wgpu/src/lib.rs | 1 - wgpu/src/primitive.rs | 43 +++------------ wgpu/src/primitive/pipeline.rs | 117 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 154 insertions(+), 118 deletions(-) create mode 100644 wgpu/src/primitive/pipeline.rs (limited to 'wgpu') diff --git a/wgpu/src/backend.rs b/wgpu/src/backend.rs index 27ef0b3c..f89bcee1 100644 --- a/wgpu/src/backend.rs +++ b/wgpu/src/backend.rs @@ -2,8 +2,11 @@ use crate::core::{Color, Size}; use crate::graphics::backend; use crate::graphics::color; use crate::graphics::{Transformation, Viewport}; +use crate::primitive::pipeline; use crate::primitive::{self, Primitive}; -use crate::{custom, quad, text, triangle}; +use crate::quad; +use crate::text; +use crate::triangle; use crate::{Layer, Settings}; #[cfg(feature = "tracing")] @@ -23,7 +26,7 @@ pub struct Backend { quad_pipeline: quad::Pipeline, text_pipeline: text::Pipeline, triangle_pipeline: triangle::Pipeline, - pipeline_storage: custom::Storage, + pipeline_storage: pipeline::Storage, #[cfg(any(feature = "image", feature = "svg"))] image_pipeline: image::Pipeline, @@ -49,7 +52,7 @@ impl Backend { quad_pipeline, text_pipeline, triangle_pipeline, - pipeline_storage: custom::Storage::default(), + pipeline_storage: pipeline::Storage::default(), #[cfg(any(feature = "image", feature = "svg"))] image_pipeline, @@ -183,9 +186,9 @@ impl Backend { ); } - if !layer.shaders.is_empty() { - for shader in &layer.shaders { - shader.primitive.prepare( + if !layer.pipelines.is_empty() { + for pipeline in &layer.pipelines { + pipeline.primitive.prepare( format, device, queue, @@ -323,19 +326,17 @@ impl Backend { // kill render pass to let custom shaders get mut access to encoder let _ = ManuallyDrop::into_inner(render_pass); - if !layer.shaders.is_empty() { - for shader in &layer.shaders { - //This extra check is needed since each custom pipeline must set it's own - //scissor rect, which will panic if bounds.w/h < 1 - let bounds = shader.bounds * scale_factor; + if !layer.pipelines.is_empty() { + for pipeline in &layer.pipelines { + let bounds = (pipeline.bounds * scale_factor).snap(); - if bounds.width < 1.0 || bounds.height < 1.0 { + if bounds.width < 1 || bounds.height < 1 { continue; } - shader.primitive.render( + pipeline.primitive.render( &self.pipeline_storage, - bounds.snap(), + bounds, target, target_size, encoder, diff --git a/wgpu/src/custom.rs b/wgpu/src/custom.rs index 65a6f133..98e2b396 100644 --- a/wgpu/src/custom.rs +++ b/wgpu/src/custom.rs @@ -1,67 +1,8 @@ //! Draw custom primitives. use crate::core::{Rectangle, Size}; use crate::graphics::Transformation; +use crate::primitive; + use std::any::{Any, TypeId}; use std::collections::HashMap; use std::fmt::Debug; - -/// Stores custom, user-provided pipelines. -#[derive(Default, Debug)] -pub struct Storage { - pipelines: HashMap<TypeId, Box<dyn Any>>, -} - -impl Storage { - /// Returns `true` if `Storage` contains a pipeline with type `T`. - pub fn has<T: 'static>(&self) -> bool { - self.pipelines.get(&TypeId::of::<T>()).is_some() - } - - /// Inserts the pipeline `T` in to [`Storage`]. - pub fn store<T: 'static>(&mut self, pipeline: T) { - let _ = self.pipelines.insert(TypeId::of::<T>(), Box::new(pipeline)); - } - - /// Returns a reference to pipeline with type `T` if it exists in [`Storage`]. - pub fn get<T: 'static>(&self) -> Option<&T> { - self.pipelines.get(&TypeId::of::<T>()).map(|pipeline| { - pipeline - .downcast_ref::<T>() - .expect("Pipeline with this type does not exist in Storage.") - }) - } - - /// Returns a mutable reference to pipeline `T` if it exists in [`Storage`]. - pub fn get_mut<T: 'static>(&mut self) -> Option<&mut T> { - self.pipelines.get_mut(&TypeId::of::<T>()).map(|pipeline| { - pipeline - .downcast_mut::<T>() - .expect("Pipeline with this type does not exist in Storage.") - }) - } -} - -/// A set of methods which allows a [`Primitive`] to be rendered. -pub trait Primitive: Debug + Send + Sync + 'static { - /// Processes the [`Primitive`], allowing for GPU buffer allocation. - fn prepare( - &self, - format: wgpu::TextureFormat, - device: &wgpu::Device, - queue: &wgpu::Queue, - target_size: Size<u32>, - scale_factor: f32, - transform: Transformation, - storage: &mut Storage, - ); - - /// Renders the [`Primitive`]. - fn render( - &self, - storage: &Storage, - bounds: Rectangle<u32>, - target: &wgpu::TextureView, - target_size: Size<u32>, - encoder: &mut wgpu::CommandEncoder, - ); -} diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs index d451cbfd..33aaf670 100644 --- a/wgpu/src/layer.rs +++ b/wgpu/src/layer.rs @@ -35,8 +35,8 @@ pub struct Layer<'a> { /// The images of the [`Layer`]. pub images: Vec<Image>, - /// The custom shader primitives of this [`Layer`]. - pub shaders: Vec<primitive::Shader>, + /// The custom pipelines of this [`Layer`]. + pub pipelines: Vec<primitive::Pipeline>, } impl<'a> Layer<'a> { @@ -48,7 +48,7 @@ impl<'a> Layer<'a> { meshes: Vec::new(), text: Vec::new(), images: Vec::new(), - shaders: Vec::new(), + pipelines: Vec::new(), } } @@ -312,16 +312,21 @@ impl<'a> Layer<'a> { } } }, - primitive::Custom::Shader(shader) => { + primitive::Custom::Pipeline(pipeline) => { let layer = &mut layers[current_layer]; let bounds = Rectangle::new( Point::new(translation.x, translation.y), - shader.bounds.size(), + pipeline.bounds.size(), ); - if layer.bounds.intersection(&bounds).is_some() { - layer.shaders.push(shader.clone()); + if let Some(clip_bounds) = + layer.bounds.intersection(&bounds) + { + layer.pipelines.push(primitive::Pipeline { + bounds: clip_bounds, + primitive: pipeline.primitive.clone(), + }); } } }, diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 13d8e886..424dfeb3 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -29,7 +29,6 @@ rustdoc::broken_intra_doc_links )] #![cfg_attr(docsrs, feature(doc_auto_cfg))] -pub mod custom; pub mod layer; pub mod primitive; pub mod settings; diff --git a/wgpu/src/primitive.rs b/wgpu/src/primitive.rs index 4347dcda..fff927ea 100644 --- a/wgpu/src/primitive.rs +++ b/wgpu/src/primitive.rs @@ -1,10 +1,12 @@ //! Draw using different graphical primitives. +pub mod pipeline; + +pub use pipeline::Pipeline; + use crate::core::Rectangle; -use crate::custom; use crate::graphics::{Damage, Mesh}; -use std::any::Any; + use std::fmt::Debug; -use std::sync::Arc; /// The graphical primitives supported by `iced_wgpu`. pub type Primitive = crate::graphics::Primitive<Custom>; @@ -14,44 +16,15 @@ pub type Primitive = crate::graphics::Primitive<Custom>; pub enum Custom { /// A mesh primitive. Mesh(Mesh), - /// A custom shader primitive - Shader(Shader), -} - -impl Custom { - /// Create a custom [`Shader`] primitive. - pub fn shader<P: custom::Primitive>( - bounds: Rectangle, - primitive: P, - ) -> Self { - Self::Shader(Shader { - bounds, - primitive: Arc::new(primitive), - }) - } + /// A custom pipeline primitive. + Pipeline(Pipeline), } impl Damage for Custom { fn bounds(&self) -> Rectangle { match self { Self::Mesh(mesh) => mesh.bounds(), - Self::Shader(shader) => shader.bounds, + Self::Pipeline(pipeline) => pipeline.bounds, } } } - -#[derive(Clone, Debug)] -/// A custom primitive which can be used to render primitives associated with a custom pipeline. -pub struct Shader { - /// The bounds of the [`Shader`]. - pub bounds: Rectangle, - - /// The [`custom::Primitive`] to render. - pub primitive: Arc<dyn custom::Primitive>, -} - -impl PartialEq for Shader { - fn eq(&self, other: &Self) -> bool { - self.primitive.type_id() == other.primitive.type_id() - } -} diff --git a/wgpu/src/primitive/pipeline.rs b/wgpu/src/primitive/pipeline.rs new file mode 100644 index 00000000..b59aeff1 --- /dev/null +++ b/wgpu/src/primitive/pipeline.rs @@ -0,0 +1,117 @@ +//! Draw primitives using custom pipelines. +use crate::core::{Rectangle, Size}; +use crate::graphics::Transformation; + +use std::any::{Any, TypeId}; +use std::collections::HashMap; +use std::fmt::Debug; +use std::sync::Arc; + +#[derive(Clone, Debug)] +/// A custom primitive which can be used to render primitives associated with a custom pipeline. +pub struct Pipeline { + /// The bounds of the [`Shader`]. + pub bounds: Rectangle, + + /// The [`custom::Primitive`] to render. + pub primitive: Arc<dyn Primitive>, +} + +impl Pipeline { + /// Creates a new [`Pipeline`] with the given [`Primitive`]. + pub fn new(bounds: Rectangle, primitive: impl Primitive) -> Self { + Pipeline { + bounds, + primitive: Arc::new(primitive), + } + } +} + +impl PartialEq for Pipeline { + fn eq(&self, other: &Self) -> bool { + self.primitive.type_id() == other.primitive.type_id() + } +} + +/// A set of methods which allows a [`Primitive`] to be rendered. +pub trait Primitive: Debug + Send + Sync + 'static { + /// Processes the [`Primitive`], allowing for GPU buffer allocation. + fn prepare( + &self, + format: wgpu::TextureFormat, + device: &wgpu::Device, + queue: &wgpu::Queue, + target_size: Size<u32>, + scale_factor: f32, + transform: Transformation, + storage: &mut Storage, + ); + + /// Renders the [`Primitive`]. + fn render( + &self, + storage: &Storage, + bounds: Rectangle<u32>, + target: &wgpu::TextureView, + target_size: Size<u32>, + encoder: &mut wgpu::CommandEncoder, + ); +} + +/// A renderer than can draw custom pipeline primitives. +pub trait Renderer: crate::core::Renderer { + /// Draws a custom pipeline primitive. + fn draw_pipeline_primitive( + &mut self, + bounds: Rectangle, + primitive: impl Primitive, + ); +} + +impl<Theme> Renderer for crate::Renderer<Theme> { + fn draw_pipeline_primitive( + &mut self, + bounds: Rectangle, + primitive: impl Primitive, + ) { + self.draw_primitive(super::Primitive::Custom(super::Custom::Pipeline( + Pipeline::new(bounds, primitive), + ))); + } +} + +/// Stores custom, user-provided pipelines. +#[derive(Default, Debug)] +pub struct Storage { + pipelines: HashMap<TypeId, Box<dyn Any>>, +} + +impl Storage { + /// Returns `true` if `Storage` contains a pipeline with type `T`. + pub fn has<T: 'static>(&self) -> bool { + self.pipelines.get(&TypeId::of::<T>()).is_some() + } + + /// Inserts the pipeline `T` in to [`Storage`]. + pub fn store<T: 'static>(&mut self, pipeline: T) { + let _ = self.pipelines.insert(TypeId::of::<T>(), Box::new(pipeline)); + } + + /// Returns a reference to pipeline with type `T` if it exists in [`Storage`]. + pub fn get<T: 'static>(&self) -> Option<&T> { + self.pipelines.get(&TypeId::of::<T>()).map(|pipeline| { + pipeline + .downcast_ref::<T>() + .expect("Pipeline with this type does not exist in Storage.") + }) + } + + /// Returns a mutable reference to pipeline `T` if it exists in [`Storage`]. + pub fn get_mut<T: 'static>(&mut self) -> Option<&mut T> { + self.pipelines.get_mut(&TypeId::of::<T>()).map(|pipeline| { + pipeline + .downcast_mut::<T>() + .expect("Pipeline with this type does not exist in Storage.") + }) + } +} -- cgit From 280d3736d59b62c4087fe980c187953cc2be83d2 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Tue, 14 Nov 2023 13:23:28 +0100 Subject: Fix broken intra-doc links --- wgpu/src/primitive/pipeline.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/primitive/pipeline.rs b/wgpu/src/primitive/pipeline.rs index b59aeff1..5dbd6697 100644 --- a/wgpu/src/primitive/pipeline.rs +++ b/wgpu/src/primitive/pipeline.rs @@ -10,10 +10,10 @@ use std::sync::Arc; #[derive(Clone, Debug)] /// A custom primitive which can be used to render primitives associated with a custom pipeline. pub struct Pipeline { - /// The bounds of the [`Shader`]. + /// The bounds of the [`Pipeline`]. pub bounds: Rectangle, - /// The [`custom::Primitive`] to render. + /// The [`Primitive`] to render. pub primitive: Arc<dyn Primitive>, } -- cgit From fee3bf0df4e3099ea74def738be8743b2b72d78a Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Tue, 14 Nov 2023 14:47:29 +0100 Subject: Kill current render pass only when custom pipelines are present in layer --- wgpu/src/backend.rs | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/backend.rs b/wgpu/src/backend.rs index f89bcee1..91ae777b 100644 --- a/wgpu/src/backend.rs +++ b/wgpu/src/backend.rs @@ -323,10 +323,9 @@ impl Backend { text_layer += 1; } - // kill render pass to let custom shaders get mut access to encoder - let _ = ManuallyDrop::into_inner(render_pass); - if !layer.pipelines.is_empty() { + let _ = ManuallyDrop::into_inner(render_pass); + for pipeline in &layer.pipelines { let bounds = (pipeline.bounds * scale_factor).snap(); @@ -342,27 +341,26 @@ impl Backend { encoder, ); } - } - // recreate and continue processing layers - render_pass = ManuallyDrop::new(encoder.begin_render_pass( - &wgpu::RenderPassDescriptor { - label: Some("iced_wgpu::quad render pass"), - color_attachments: &[Some( - wgpu::RenderPassColorAttachment { - view: target, - resolve_target: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Load, - store: wgpu::StoreOp::Store, + render_pass = ManuallyDrop::new(encoder.begin_render_pass( + &wgpu::RenderPassDescriptor { + label: Some("iced_wgpu::quad render pass"), + color_attachments: &[Some( + wgpu::RenderPassColorAttachment { + view: target, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Load, + store: wgpu::StoreOp::Store, + }, }, - }, - )], - depth_stencil_attachment: None, - timestamp_writes: None, - occlusion_query_set: None, - }, - )); + )], + depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, + }, + )); + } } let _ = ManuallyDrop::into_inner(render_pass); -- cgit From b1b2467b45e16185cc17df00b4c75700435cd46e Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Tue, 14 Nov 2023 14:50:57 +0100 Subject: Fix render pass label in `iced_wgpu` --- wgpu/src/backend.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/backend.rs b/wgpu/src/backend.rs index 91ae777b..88caad06 100644 --- a/wgpu/src/backend.rs +++ b/wgpu/src/backend.rs @@ -222,7 +222,7 @@ impl Backend { let mut render_pass = ManuallyDrop::new(encoder.begin_render_pass( &wgpu::RenderPassDescriptor { - label: Some("iced_wgpu::quad render pass"), + label: Some("iced_wgpu render pass"), color_attachments: &[Some(wgpu::RenderPassColorAttachment { view: target, resolve_target: None, @@ -285,7 +285,7 @@ impl Backend { render_pass = ManuallyDrop::new(encoder.begin_render_pass( &wgpu::RenderPassDescriptor { - label: Some("iced_wgpu::quad render pass"), + label: Some("iced_wgpu render pass"), color_attachments: &[Some( wgpu::RenderPassColorAttachment { view: target, @@ -344,7 +344,7 @@ impl Backend { render_pass = ManuallyDrop::new(encoder.begin_render_pass( &wgpu::RenderPassDescriptor { - label: Some("iced_wgpu::quad render pass"), + label: Some("iced_wgpu render pass"), color_attachments: &[Some( wgpu::RenderPassColorAttachment { view: target, -- cgit From 8f384c83be242f9318685530ee52dd6c27b2bb62 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Tue, 14 Nov 2023 15:54:10 +0100 Subject: Remove unsused `custom.rs` file in `iced_wgpu` --- wgpu/src/custom.rs | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 wgpu/src/custom.rs (limited to 'wgpu') diff --git a/wgpu/src/custom.rs b/wgpu/src/custom.rs deleted file mode 100644 index 98e2b396..00000000 --- a/wgpu/src/custom.rs +++ /dev/null @@ -1,8 +0,0 @@ -//! Draw custom primitives. -use crate::core::{Rectangle, Size}; -use crate::graphics::Transformation; -use crate::primitive; - -use std::any::{Any, TypeId}; -use std::collections::HashMap; -use std::fmt::Debug; -- cgit From ab7dae554cac801aeed5d9aa4d3850d50be86263 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Tue, 28 Nov 2023 23:13:38 +0100 Subject: Provide actual bounds to `Shader` primitives ... and allow for proper translation and scissoring. --- wgpu/src/backend.rs | 8 ++++---- wgpu/src/layer.rs | 15 +++++++-------- wgpu/src/layer/pipeline.rs | 17 +++++++++++++++++ wgpu/src/primitive/pipeline.rs | 5 ++--- 4 files changed, 30 insertions(+), 15 deletions(-) create mode 100644 wgpu/src/layer/pipeline.rs (limited to 'wgpu') diff --git a/wgpu/src/backend.rs b/wgpu/src/backend.rs index 88caad06..25134d68 100644 --- a/wgpu/src/backend.rs +++ b/wgpu/src/backend.rs @@ -192,9 +192,9 @@ impl Backend { format, device, queue, + pipeline.bounds, target_size, scale_factor, - transformation, &mut self.pipeline_storage, ); } @@ -327,17 +327,17 @@ impl Backend { let _ = ManuallyDrop::into_inner(render_pass); for pipeline in &layer.pipelines { - let bounds = (pipeline.bounds * scale_factor).snap(); + let viewport = (pipeline.viewport * scale_factor).snap(); - if bounds.width < 1 || bounds.height < 1 { + if viewport.width < 1 || viewport.height < 1 { continue; } pipeline.primitive.render( &self.pipeline_storage, - bounds, target, target_size, + viewport, encoder, ); } diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs index 33aaf670..98e49f1a 100644 --- a/wgpu/src/layer.rs +++ b/wgpu/src/layer.rs @@ -1,11 +1,13 @@ //! Organize rendering primitives into a flattened list of layers. mod image; +mod pipeline; mod text; pub mod mesh; pub use image::Image; pub use mesh::Mesh; +pub use pipeline::Pipeline; pub use text::Text; use crate::core; @@ -36,7 +38,7 @@ pub struct Layer<'a> { pub images: Vec<Image>, /// The custom pipelines of this [`Layer`]. - pub pipelines: Vec<primitive::Pipeline>, + pub pipelines: Vec<Pipeline>, } impl<'a> Layer<'a> { @@ -314,17 +316,14 @@ impl<'a> Layer<'a> { }, primitive::Custom::Pipeline(pipeline) => { let layer = &mut layers[current_layer]; - - let bounds = Rectangle::new( - Point::new(translation.x, translation.y), - pipeline.bounds.size(), - ); + let bounds = pipeline.bounds + translation; if let Some(clip_bounds) = layer.bounds.intersection(&bounds) { - layer.pipelines.push(primitive::Pipeline { - bounds: clip_bounds, + layer.pipelines.push(Pipeline { + bounds, + viewport: clip_bounds, primitive: pipeline.primitive.clone(), }); } diff --git a/wgpu/src/layer/pipeline.rs b/wgpu/src/layer/pipeline.rs new file mode 100644 index 00000000..6dfe6750 --- /dev/null +++ b/wgpu/src/layer/pipeline.rs @@ -0,0 +1,17 @@ +use crate::core::Rectangle; +use crate::primitive::pipeline::Primitive; + +use std::sync::Arc; + +#[derive(Clone, Debug)] +/// A custom primitive which can be used to render primitives associated with a custom pipeline. +pub struct Pipeline { + /// The bounds of the [`Pipeline`]. + pub bounds: Rectangle, + + /// The viewport of the [`Pipeline`]. + pub viewport: Rectangle, + + /// The [`Primitive`] to render. + pub primitive: Arc<dyn Primitive>, +} diff --git a/wgpu/src/primitive/pipeline.rs b/wgpu/src/primitive/pipeline.rs index 5dbd6697..302e38f6 100644 --- a/wgpu/src/primitive/pipeline.rs +++ b/wgpu/src/primitive/pipeline.rs @@ -1,6 +1,5 @@ //! Draw primitives using custom pipelines. use crate::core::{Rectangle, Size}; -use crate::graphics::Transformation; use std::any::{Any, TypeId}; use std::collections::HashMap; @@ -41,9 +40,9 @@ pub trait Primitive: Debug + Send + Sync + 'static { format: wgpu::TextureFormat, device: &wgpu::Device, queue: &wgpu::Queue, + bounds: Rectangle, target_size: Size<u32>, scale_factor: f32, - transform: Transformation, storage: &mut Storage, ); @@ -51,9 +50,9 @@ pub trait Primitive: Debug + Send + Sync + 'static { fn render( &self, storage: &Storage, - bounds: Rectangle<u32>, target: &wgpu::TextureView, target_size: Size<u32>, + viewport: Rectangle<u32>, encoder: &mut wgpu::CommandEncoder, ); } -- cgit From 936d480267578d7e80675e78ec1880aaaaab72d6 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Fri, 1 Dec 2023 16:04:27 +0100 Subject: Clip text to `viewport` bounds instead of layout bounds --- wgpu/src/geometry.rs | 15 +++++++++------ wgpu/src/layer.rs | 7 +++++++ wgpu/src/layer/text.rs | 5 +++++ wgpu/src/text.rs | 23 ++++++++++++++--------- 4 files changed, 35 insertions(+), 15 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/geometry.rs b/wgpu/src/geometry.rs index 655362b7..c82b9ffb 100644 --- a/wgpu/src/geometry.rs +++ b/wgpu/src/geometry.rs @@ -328,15 +328,17 @@ impl Frame { Point::new(transformed.x, transformed.y) }; + let bounds = Rectangle { + x: position.x, + y: position.y, + width: f32::INFINITY, + height: f32::INFINITY, + }; + // TODO: Use vectorial text instead of primitive self.primitives.push(Primitive::Text { content: text.content, - bounds: Rectangle { - x: position.x, - y: position.y, - width: f32::INFINITY, - height: f32::INFINITY, - }, + bounds, color: text.color, size: text.size, line_height: text.line_height, @@ -344,6 +346,7 @@ impl Frame { horizontal_alignment: text.horizontal_alignment, vertical_alignment: text.vertical_alignment, shaping: text.shaping, + viewport: bounds, }); } diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs index 98e49f1a..60da3543 100644 --- a/wgpu/src/layer.rs +++ b/wgpu/src/layer.rs @@ -75,6 +75,7 @@ impl<'a> Layer<'a> { horizontal_alignment: alignment::Horizontal::Left, vertical_alignment: alignment::Vertical::Top, shaping: core::text::Shaping::Basic, + viewport: Rectangle::with_size(Size::INFINITY), }; overlay.text.push(Text::Cached(text.clone())); @@ -123,6 +124,7 @@ impl<'a> Layer<'a> { paragraph, position, color, + viewport, } => { let layer = &mut layers[current_layer]; @@ -130,12 +132,14 @@ impl<'a> Layer<'a> { paragraph: paragraph.clone(), position: *position + translation, color: *color, + viewport: *viewport + translation, }); } Primitive::Editor { editor, position, color, + viewport, } => { let layer = &mut layers[current_layer]; @@ -143,6 +147,7 @@ impl<'a> Layer<'a> { editor: editor.clone(), position: *position + translation, color: *color, + viewport: *viewport + translation, }); } Primitive::Text { @@ -155,6 +160,7 @@ impl<'a> Layer<'a> { horizontal_alignment, vertical_alignment, shaping, + viewport, } => { let layer = &mut layers[current_layer]; @@ -168,6 +174,7 @@ impl<'a> Layer<'a> { horizontal_alignment: *horizontal_alignment, vertical_alignment: *vertical_alignment, shaping: *shaping, + viewport: *viewport + translation, })); } Primitive::Quad { diff --git a/wgpu/src/layer/text.rs b/wgpu/src/layer/text.rs index 66417cec..c4ea9185 100644 --- a/wgpu/src/layer/text.rs +++ b/wgpu/src/layer/text.rs @@ -13,6 +13,7 @@ pub enum Text<'a> { paragraph: paragraph::Weak, position: Point, color: Color, + viewport: Rectangle, }, /// An editor. #[allow(missing_docs)] @@ -20,6 +21,7 @@ pub enum Text<'a> { editor: editor::Weak, position: Point, color: Color, + viewport: Rectangle, }, /// A cached text. Cached(Cached<'a>), @@ -53,4 +55,7 @@ pub struct Cached<'a> { /// The shaping strategy of the text. pub shaping: text::Shaping, + + /// The viewport of the text. + pub viewport: Rectangle, } diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs index 08a8bea6..7d73c87b 100644 --- a/wgpu/src/text.rs +++ b/wgpu/src/text.rs @@ -120,9 +120,13 @@ impl Pipeline { horizontal_alignment, vertical_alignment, color, + viewport, ) = match section { Text::Paragraph { - position, color, .. + position, + color, + viewport, + .. } => { use crate::core::text::Paragraph as _; @@ -137,10 +141,14 @@ impl Pipeline { paragraph.horizontal_alignment(), paragraph.vertical_alignment(), *color, + *viewport, ) } Text::Editor { - position, color, .. + position, + color, + viewport, + .. } => { use crate::core::text::Editor as _; @@ -155,6 +163,7 @@ impl Pipeline { alignment::Horizontal::Left, alignment::Vertical::Top, *color, + *viewport, ) } Text::Cached(text) => { @@ -173,6 +182,7 @@ impl Pipeline { text.horizontal_alignment, text.vertical_alignment, text.color, + text.viewport, ) } }; @@ -195,13 +205,8 @@ impl Pipeline { alignment::Vertical::Bottom => bounds.y - bounds.height, }; - let section_bounds = Rectangle { - x: left, - y: top, - ..bounds - }; - - let clip_bounds = layer_bounds.intersection(§ion_bounds)?; + let clip_bounds = + layer_bounds.intersection(&(viewport * scale_factor))?; Some(glyphon::TextArea { buffer, -- cgit From b526ce4958b28208395276dd4078ffe0d780e1d7 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Sat, 2 Dec 2023 15:53:02 +0100 Subject: Rename `viewport` to `clip_bounds` --- wgpu/src/geometry.rs | 2 +- wgpu/src/layer.rs | 14 +++++++------- wgpu/src/layer/text.rs | 8 ++++---- wgpu/src/text.rs | 14 +++++++------- 4 files changed, 19 insertions(+), 19 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/geometry.rs b/wgpu/src/geometry.rs index c82b9ffb..e0bff67e 100644 --- a/wgpu/src/geometry.rs +++ b/wgpu/src/geometry.rs @@ -346,7 +346,7 @@ impl Frame { horizontal_alignment: text.horizontal_alignment, vertical_alignment: text.vertical_alignment, shaping: text.shaping, - viewport: bounds, + clip_bounds: Rectangle::with_size(Size::INFINITY), }); } diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs index 60da3543..557a7633 100644 --- a/wgpu/src/layer.rs +++ b/wgpu/src/layer.rs @@ -75,7 +75,7 @@ impl<'a> Layer<'a> { horizontal_alignment: alignment::Horizontal::Left, vertical_alignment: alignment::Vertical::Top, shaping: core::text::Shaping::Basic, - viewport: Rectangle::with_size(Size::INFINITY), + clip_bounds: Rectangle::with_size(Size::INFINITY), }; overlay.text.push(Text::Cached(text.clone())); @@ -124,7 +124,7 @@ impl<'a> Layer<'a> { paragraph, position, color, - viewport, + clip_bounds, } => { let layer = &mut layers[current_layer]; @@ -132,14 +132,14 @@ impl<'a> Layer<'a> { paragraph: paragraph.clone(), position: *position + translation, color: *color, - viewport: *viewport + translation, + clip_bounds: *clip_bounds + translation, }); } Primitive::Editor { editor, position, color, - viewport, + clip_bounds, } => { let layer = &mut layers[current_layer]; @@ -147,7 +147,7 @@ impl<'a> Layer<'a> { editor: editor.clone(), position: *position + translation, color: *color, - viewport: *viewport + translation, + clip_bounds: *clip_bounds + translation, }); } Primitive::Text { @@ -160,7 +160,7 @@ impl<'a> Layer<'a> { horizontal_alignment, vertical_alignment, shaping, - viewport, + clip_bounds, } => { let layer = &mut layers[current_layer]; @@ -174,7 +174,7 @@ impl<'a> Layer<'a> { horizontal_alignment: *horizontal_alignment, vertical_alignment: *vertical_alignment, shaping: *shaping, - viewport: *viewport + translation, + clip_bounds: *clip_bounds + translation, })); } Primitive::Quad { diff --git a/wgpu/src/layer/text.rs b/wgpu/src/layer/text.rs index c4ea9185..df2f2875 100644 --- a/wgpu/src/layer/text.rs +++ b/wgpu/src/layer/text.rs @@ -13,7 +13,7 @@ pub enum Text<'a> { paragraph: paragraph::Weak, position: Point, color: Color, - viewport: Rectangle, + clip_bounds: Rectangle, }, /// An editor. #[allow(missing_docs)] @@ -21,7 +21,7 @@ pub enum Text<'a> { editor: editor::Weak, position: Point, color: Color, - viewport: Rectangle, + clip_bounds: Rectangle, }, /// A cached text. Cached(Cached<'a>), @@ -56,6 +56,6 @@ pub struct Cached<'a> { /// The shaping strategy of the text. pub shaping: text::Shaping, - /// The viewport of the text. - pub viewport: Rectangle, + /// The clip bounds of the text. + pub clip_bounds: Rectangle, } diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs index 7d73c87b..888b1924 100644 --- a/wgpu/src/text.rs +++ b/wgpu/src/text.rs @@ -120,12 +120,12 @@ impl Pipeline { horizontal_alignment, vertical_alignment, color, - viewport, + clip_bounds, ) = match section { Text::Paragraph { position, color, - viewport, + clip_bounds, .. } => { use crate::core::text::Paragraph as _; @@ -141,13 +141,13 @@ impl Pipeline { paragraph.horizontal_alignment(), paragraph.vertical_alignment(), *color, - *viewport, + *clip_bounds, ) } Text::Editor { position, color, - viewport, + clip_bounds, .. } => { use crate::core::text::Editor as _; @@ -163,7 +163,7 @@ impl Pipeline { alignment::Horizontal::Left, alignment::Vertical::Top, *color, - *viewport, + *clip_bounds, ) } Text::Cached(text) => { @@ -182,7 +182,7 @@ impl Pipeline { text.horizontal_alignment, text.vertical_alignment, text.color, - text.viewport, + text.clip_bounds, ) } }; @@ -206,7 +206,7 @@ impl Pipeline { }; let clip_bounds = - layer_bounds.intersection(&(viewport * scale_factor))?; + layer_bounds.intersection(&(clip_bounds * scale_factor))?; Some(glyphon::TextArea { buffer, -- cgit From b152ecda63238136f77b6eda3c582fa1eff99737 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Sat, 2 Dec 2023 20:49:47 +0100 Subject: Separate `Compositor::new` from `Compositor::create_renderer` --- wgpu/src/window/compositor.rs | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index 21406134..090e0e9f 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -139,16 +139,14 @@ impl<Theme> Compositor<Theme> { pub fn new<Theme, W: HasRawWindowHandle + HasRawDisplayHandle>( settings: Settings, compatible_window: Option<&W>, -) -> Result<(Compositor<Theme>, Backend), Error> { +) -> Result<Compositor<Theme>, Error> { let compositor = futures::executor::block_on(Compositor::request( settings, compatible_window, )) .ok_or(Error::GraphicsAdapterNotFound)?; - let backend = compositor.create_backend(); - - Ok((compositor, backend)) + Ok(compositor) } /// Presents the given primitives with the given [`Compositor`] and [`Backend`]. @@ -214,20 +212,11 @@ impl<Theme> graphics::Compositor for Compositor<Theme> { fn new<W: HasRawWindowHandle + HasRawDisplayHandle>( settings: Self::Settings, compatible_window: Option<&W>, - ) -> Result<(Self, Self::Renderer), Error> { - let (compositor, backend) = new(settings, compatible_window)?; - - Ok(( - compositor, - Renderer::new( - backend, - settings.default_font, - settings.default_text_size, - ), - )) + ) -> Result<Self, Error> { + new(settings, compatible_window) } - fn renderer(&self) -> Self::Renderer { + fn create_renderer(&self) -> Self::Renderer { Renderer::new( self.create_backend(), self.settings.default_font, -- cgit From 603832e66c710ea39a95009ddc905de20c6856bd Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Tue, 5 Dec 2023 02:19:17 +0100 Subject: Introduce `RawText` to `Primitive` in `iced_graphics` This should allow users to directly render a `cosmic_text::Buffer`. --- wgpu/src/layer.rs | 15 +++++++++++++++ wgpu/src/layer/text.rs | 5 ++++- wgpu/src/text.rs | 22 ++++++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) (limited to 'wgpu') diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs index 557a7633..4ad12a88 100644 --- a/wgpu/src/layer.rs +++ b/wgpu/src/layer.rs @@ -177,6 +177,21 @@ impl<'a> Layer<'a> { clip_bounds: *clip_bounds + translation, })); } + graphics::Primitive::RawText(graphics::text::Raw { + buffer, + position, + color, + clip_bounds, + }) => { + let layer = &mut layers[current_layer]; + + layer.text.push(Text::Raw(graphics::text::Raw { + buffer: buffer.clone(), + position: *position + translation, + color: *color, + clip_bounds: *clip_bounds + translation, + })); + } Primitive::Quad { bounds, background, diff --git a/wgpu/src/layer/text.rs b/wgpu/src/layer/text.rs index df2f2875..37ee5247 100644 --- a/wgpu/src/layer/text.rs +++ b/wgpu/src/layer/text.rs @@ -1,6 +1,7 @@ use crate::core::alignment; use crate::core::text; use crate::core::{Color, Font, Pixels, Point, Rectangle}; +use crate::graphics; use crate::graphics::text::editor; use crate::graphics::text::paragraph; @@ -23,8 +24,10 @@ pub enum Text<'a> { color: Color, clip_bounds: Rectangle, }, - /// A cached text. + /// Some cached text. Cached(Cached<'a>), + /// Some raw text. + Raw(graphics::text::Raw), } #[derive(Debug, Clone)] diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs index 888b1924..dca09cb8 100644 --- a/wgpu/src/text.rs +++ b/wgpu/src/text.rs @@ -7,6 +7,7 @@ use crate::layer::Text; use std::borrow::Cow; use std::cell::RefCell; +use std::sync::Arc; #[allow(missing_debug_implementations)] pub struct Pipeline { @@ -76,6 +77,7 @@ impl Pipeline { Paragraph(Paragraph), Editor(Editor), Cache(cache::KeyHash), + Raw(Arc<glyphon::Buffer>), } let allocations: Vec<_> = sections @@ -107,6 +109,7 @@ impl Pipeline { Some(Allocation::Cache(key)) } + Text::Raw(text) => text.buffer.upgrade().map(Allocation::Raw), }) .collect(); @@ -185,6 +188,25 @@ impl Pipeline { text.clip_bounds, ) } + Text::Raw(text) => { + let Some(Allocation::Raw(buffer)) = allocation else { + return None; + }; + + let (width, height) = buffer.size(); + + ( + buffer.as_ref(), + Rectangle::new( + text.position, + Size::new(width, height), + ), + alignment::Horizontal::Left, + alignment::Vertical::Top, + text.color, + text.clip_bounds, + ) + } }; let bounds = bounds * scale_factor; -- cgit From a2a96adf7a19f8b2f7879fc19ff139b930fb102e Mon Sep 17 00:00:00 2001 From: Cory Frenette <cory@frenette.dev> Date: Sun, 10 Dec 2023 22:12:46 -0500 Subject: implement svg text fix for native renderer Signed-off-by: Cory Frenette <cory@frenette.dev> --- wgpu/src/image/vector.rs | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/image/vector.rs b/wgpu/src/image/vector.rs index 6582bb82..1efc5342 100644 --- a/wgpu/src/image/vector.rs +++ b/wgpu/src/image/vector.rs @@ -2,8 +2,9 @@ use crate::core::svg; use crate::core::{Color, Size}; use crate::image::atlas::{self, Atlas}; +use iced_graphics::text; use resvg::tiny_skia; -use resvg::usvg; +use resvg::usvg::{self, TreeTextToPath}; use std::collections::{HashMap, HashSet}; use std::fs; @@ -51,11 +52,23 @@ impl Cache { 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()) + let mut tree = + fs::read_to_string(path).ok().and_then(|contents| { + usvg::Tree::from_str( + &contents, + &usvg::Options::default(), + ) .ok() - }); - + }); + // If there are text nodes in the tree load fonts and convert the text to paths + if let Some(svg_tree) = &mut tree { + if svg_tree.has_text_nodes() { + let mut font_system = text::font_system() + .write() + .expect("Read font system"); + svg_tree.convert_text(font_system.raw().db_mut()); + } + } tree.map(Svg::Loaded).unwrap_or(Svg::NotFound) } svg::Data::Bytes(bytes) => { -- cgit From 33f92b1be78e2f09290e36f0c9b77af899609bd8 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Mon, 11 Dec 2023 10:47:53 +0100 Subject: Fix import styling in `iced_wgpu::image::vector` --- wgpu/src/image/vector.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'wgpu') diff --git a/wgpu/src/image/vector.rs b/wgpu/src/image/vector.rs index 1efc5342..f4819095 100644 --- a/wgpu/src/image/vector.rs +++ b/wgpu/src/image/vector.rs @@ -1,8 +1,8 @@ use crate::core::svg; use crate::core::{Color, Size}; +use crate::graphics::text; use crate::image::atlas::{self, Atlas}; -use iced_graphics::text; use resvg::tiny_skia; use resvg::usvg::{self, TreeTextToPath}; use std::collections::{HashMap, HashSet}; -- cgit From 04e8e529a0e80499b129395664f1806de8102d01 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Mon, 11 Dec 2023 10:48:07 +0100 Subject: Convert SVG text nodes for in-memory SVGs in `iced_wgpu` --- wgpu/src/image/vector.rs | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/image/vector.rs b/wgpu/src/image/vector.rs index f4819095..d9be50d7 100644 --- a/wgpu/src/image/vector.rs +++ b/wgpu/src/image/vector.rs @@ -50,27 +50,15 @@ impl Cache { return self.svgs.get(&handle.id()).unwrap(); } - let svg = match handle.data() { - svg::Data::Path(path) => { - let mut tree = - fs::read_to_string(path).ok().and_then(|contents| { - usvg::Tree::from_str( - &contents, - &usvg::Options::default(), - ) + let mut svg = match handle.data() { + svg::Data::Path(path) => fs::read_to_string(path) + .ok() + .and_then(|contents| { + usvg::Tree::from_str(&contents, &usvg::Options::default()) .ok() - }); - // If there are text nodes in the tree load fonts and convert the text to paths - if let Some(svg_tree) = &mut tree { - if svg_tree.has_text_nodes() { - let mut font_system = text::font_system() - .write() - .expect("Read font system"); - svg_tree.convert_text(font_system.raw().db_mut()); - } - } - tree.map(Svg::Loaded).unwrap_or(Svg::NotFound) - } + }) + .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), @@ -79,6 +67,15 @@ impl Cache { } }; + if let Svg::Loaded(svg) = &mut svg { + if svg.has_text_nodes() { + let mut font_system = + text::font_system().write().expect("Write font system"); + + svg.convert_text(font_system.raw().db_mut()); + } + } + let _ = self.svgs.insert(handle.id(), svg); self.svgs.get(&handle.id()).unwrap() } -- cgit From 3c6bb0a076c4433abe2a381856250c9d9693404e Mon Sep 17 00:00:00 2001 From: Tomáš Zemanovič <tzemanovic@gmail.com> Date: Thu, 11 Jan 2024 14:45:40 +0000 Subject: wgpu: require `Send` on stored pipelines --- wgpu/src/primitive/pipeline.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/primitive/pipeline.rs b/wgpu/src/primitive/pipeline.rs index 302e38f6..c8e45458 100644 --- a/wgpu/src/primitive/pipeline.rs +++ b/wgpu/src/primitive/pipeline.rs @@ -82,7 +82,7 @@ impl<Theme> Renderer for crate::Renderer<Theme> { /// Stores custom, user-provided pipelines. #[derive(Default, Debug)] pub struct Storage { - pipelines: HashMap<TypeId, Box<dyn Any>>, + pipelines: HashMap<TypeId, Box<dyn Any + Send>>, } impl Storage { @@ -92,7 +92,7 @@ impl Storage { } /// Inserts the pipeline `T` in to [`Storage`]. - pub fn store<T: 'static>(&mut self, pipeline: T) { + pub fn store<T: 'static + Send>(&mut self, pipeline: T) { let _ = self.pipelines.insert(TypeId::of::<T>(), Box::new(pipeline)); } -- cgit From 66bea7bb6d4575c1d36d28a10e08dc60a0ea20b0 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Wed, 17 Jan 2024 13:22:02 +0100 Subject: Apply scaling during `Frame::fill_text` in `iced_wgpu` --- wgpu/src/geometry.rs | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/geometry.rs b/wgpu/src/geometry.rs index e0bff67e..36092da0 100644 --- a/wgpu/src/geometry.rs +++ b/wgpu/src/geometry.rs @@ -1,4 +1,5 @@ //! Build and draw geometry. +use crate::core::text::LineHeight; use crate::core::{Point, Rectangle, Size, Vector}; use crate::graphics::color; use crate::graphics::geometry::fill::{self, Fill}; @@ -318,14 +319,41 @@ impl Frame { pub fn fill_text(&mut self, text: impl Into<Text>) { let text = text.into(); - let position = if self.transforms.current.is_identity { - text.position + let (position, size, line_height) = if self + .transforms + .current + .is_identity + { + (text.position, text.size, text.line_height) } else { - let transformed = self.transforms.current.raw.transform_point( + let position = self.transforms.current.raw.transform_point( lyon::math::Point::new(text.position.x, text.position.y), ); - Point::new(transformed.x, transformed.y) + let size = + self.transforms.current.raw.transform_vector( + lyon::math::Vector::new(0.0, text.size.0), + ); + + let line_height = match text.line_height { + LineHeight::Absolute(size) => { + let new_height = self + .transforms + .current + .raw + .transform_vector(lyon::math::Vector::new(0.0, size.0)) + .y; + + LineHeight::Absolute(new_height.into()) + } + LineHeight::Relative(factor) => LineHeight::Relative(factor), + }; + + ( + Point::new(position.x, position.y), + size.y.into(), + line_height, + ) }; let bounds = Rectangle { @@ -340,8 +368,8 @@ impl Frame { content: text.content, bounds, color: text.color, - size: text.size, - line_height: text.line_height, + size, + line_height, font: text.font, horizontal_alignment: text.horizontal_alignment, vertical_alignment: text.vertical_alignment, -- cgit From fda96a9eda261b9fbe499eae1c6eedcfa252c5ea Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Wed, 17 Jan 2024 13:44:30 +0100 Subject: Simplify `Transform` API in `iced_wgpu::geometry` --- wgpu/src/geometry.rs | 136 +++++++++++++++++++++++---------------------------- 1 file changed, 62 insertions(+), 74 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/geometry.rs b/wgpu/src/geometry.rs index 36092da0..04718441 100644 --- a/wgpu/src/geometry.rs +++ b/wgpu/src/geometry.rs @@ -1,6 +1,6 @@ //! Build and draw geometry. use crate::core::text::LineHeight; -use crate::core::{Point, Rectangle, Size, Vector}; +use crate::core::{Pixels, Point, Rectangle, Size, Vector}; use crate::graphics::color; use crate::graphics::geometry::fill::{self, Fill}; use crate::graphics::geometry::{ @@ -116,19 +116,26 @@ struct Transforms { } #[derive(Debug, Clone, Copy)] -struct Transform { - raw: lyon::math::Transform, - is_identity: bool, -} +struct Transform(lyon::math::Transform); impl Transform { - /// Transforms the given [Point] by the transformation matrix. - fn transform_point(&self, point: &mut Point) { + fn is_identity(&self) -> bool { + self.0 == lyon::math::Transform::identity() + } + + fn scale(&self) -> (f32, f32) { + (self.0.m12, self.0.m22) + } + + fn transform_point(&self, point: Point) -> Point { let transformed = self - .raw + .0 .transform_point(euclid::Point2D::new(point.x, point.y)); - point.x = transformed.x; - point.y = transformed.y; + + Point { + x: transformed.x, + y: transformed.y, + } } fn transform_style(&self, style: Style) -> Style { @@ -143,8 +150,8 @@ impl Transform { fn transform_gradient(&self, mut gradient: Gradient) -> Gradient { match &mut gradient { Gradient::Linear(linear) => { - self.transform_point(&mut linear.start); - self.transform_point(&mut linear.end); + linear.start = self.transform_point(linear.start); + linear.end = self.transform_point(linear.end); } } @@ -164,10 +171,7 @@ impl Frame { primitives: Vec::new(), transforms: Transforms { previous: Vec::new(), - current: Transform { - raw: lyon::math::Transform::identity(), - is_identity: true, - }, + current: Transform(lyon::math::Transform::identity()), }, fill_tessellator: tessellation::FillTessellator::new(), stroke_tessellator: tessellation::StrokeTessellator::new(), @@ -210,14 +214,14 @@ impl Frame { let options = tessellation::FillOptions::default() .with_fill_rule(into_fill_rule(rule)); - if self.transforms.current.is_identity { + if self.transforms.current.is_identity() { self.fill_tessellator.tessellate_path( path.raw(), &options, buffer.as_mut(), ) } else { - let path = path.transform(&self.transforms.current.raw); + let path = path.transform(&self.transforms.current.0); self.fill_tessellator.tessellate_path( path.raw(), @@ -242,13 +246,14 @@ impl Frame { .buffers .get_fill(&self.transforms.current.transform_style(style)); - let top_left = - self.transforms.current.raw.transform_point( - lyon::math::Point::new(top_left.x, top_left.y), - ); + let top_left = self + .transforms + .current + .0 + .transform_point(lyon::math::Point::new(top_left.x, top_left.y)); let size = - self.transforms.current.raw.transform_vector( + self.transforms.current.0.transform_vector( lyon::math::Vector::new(size.width, size.height), ); @@ -285,14 +290,14 @@ impl Frame { Cow::Owned(dashed(path, stroke.line_dash)) }; - if self.transforms.current.is_identity { + if self.transforms.current.is_identity() { self.stroke_tessellator.tessellate_path( path.raw(), &options, buffer.as_mut(), ) } else { - let path = path.transform(&self.transforms.current.raw); + let path = path.transform(&self.transforms.current.0); self.stroke_tessellator.tessellate_path( path.raw(), @@ -319,42 +324,28 @@ impl Frame { pub fn fill_text(&mut self, text: impl Into<Text>) { let text = text.into(); - let (position, size, line_height) = if self - .transforms - .current - .is_identity - { - (text.position, text.size, text.line_height) - } else { - let position = self.transforms.current.raw.transform_point( - lyon::math::Point::new(text.position.x, text.position.y), - ); + let (position, size, line_height) = + if self.transforms.current.is_identity() { + (text.position, text.size, text.line_height) + } else { + let (_, scale_y) = self.transforms.current.scale(); - let size = - self.transforms.current.raw.transform_vector( - lyon::math::Vector::new(0.0, text.size.0), - ); - - let line_height = match text.line_height { - LineHeight::Absolute(size) => { - let new_height = self - .transforms - .current - .raw - .transform_vector(lyon::math::Vector::new(0.0, size.0)) - .y; - - LineHeight::Absolute(new_height.into()) - } - LineHeight::Relative(factor) => LineHeight::Relative(factor), - }; + let position = + self.transforms.current.transform_point(text.position); - ( - Point::new(position.x, position.y), - size.y.into(), - line_height, - ) - }; + let size = Pixels(text.size.0 * scale_y); + + let line_height = match text.line_height { + LineHeight::Absolute(size) => { + LineHeight::Absolute(Pixels(size.0 * scale_y)) + } + LineHeight::Relative(factor) => { + LineHeight::Relative(factor) + } + }; + + (position, size, line_height) + }; let bounds = Rectangle { x: position.x, @@ -451,26 +442,24 @@ impl Frame { /// Applies a translation to the current transform of the [`Frame`]. #[inline] pub fn translate(&mut self, translation: Vector) { - self.transforms.current.raw = self - .transforms - .current - .raw - .pre_translate(lyon::math::Vector::new( - translation.x, - translation.y, - )); - self.transforms.current.is_identity = false; + self.transforms.current.0 = + self.transforms + .current + .0 + .pre_translate(lyon::math::Vector::new( + translation.x, + translation.y, + )); } /// Applies a rotation in radians to the current transform of the [`Frame`]. #[inline] pub fn rotate(&mut self, angle: f32) { - self.transforms.current.raw = self + self.transforms.current.0 = self .transforms .current - .raw + .0 .pre_rotate(lyon::math::Angle::radians(angle)); - self.transforms.current.is_identity = false; } /// Applies a uniform scaling to the current transform of the [`Frame`]. @@ -486,9 +475,8 @@ impl Frame { pub fn scale_nonuniform(&mut self, scale: impl Into<Vector>) { let scale = scale.into(); - self.transforms.current.raw = - self.transforms.current.raw.pre_scale(scale.x, scale.y); - self.transforms.current.is_identity = false; + self.transforms.current.0 = + self.transforms.current.0.pre_scale(scale.x, scale.y); } /// Produces the [`Primitive`] representing everything drawn on the [`Frame`]. -- cgit From dd032d9a7a73dc28c12802e1e702d0aebe92e261 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Wed, 17 Jan 2024 14:25:39 +0100 Subject: Implement vectorial text support for `iced_wgpu` --- wgpu/src/geometry.rs | 225 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 188 insertions(+), 37 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/geometry.rs b/wgpu/src/geometry.rs index 04718441..a1583a07 100644 --- a/wgpu/src/geometry.rs +++ b/wgpu/src/geometry.rs @@ -1,6 +1,7 @@ //! Build and draw geometry. +use crate::core::alignment; use crate::core::text::LineHeight; -use crate::core::{Pixels, Point, Rectangle, Size, Vector}; +use crate::core::{Color, Pixels, Point, Rectangle, Size, Vector}; use crate::graphics::color; use crate::graphics::geometry::fill::{self, Fill}; use crate::graphics::geometry::{ @@ -8,6 +9,7 @@ use crate::graphics::geometry::{ }; use crate::graphics::gradient::{self, Gradient}; use crate::graphics::mesh::{self, Mesh}; +use crate::graphics::text::{self, cosmic_text}; use crate::primitive::{self, Primitive}; use lyon::geom::euclid; @@ -123,8 +125,13 @@ impl Transform { self.0 == lyon::math::Transform::identity() } + fn is_scale_translation(&self) -> bool { + self.0.m12.abs() < 2.0 * f32::EPSILON + && self.0.m21.abs() < 2.0 * f32::EPSILON + } + fn scale(&self) -> (f32, f32) { - (self.0.m12, self.0.m22) + (self.0.m11, self.0.m22) } fn transform_point(&self, point: Point) -> Point { @@ -324,49 +331,193 @@ impl Frame { pub fn fill_text(&mut self, text: impl Into<Text>) { let text = text.into(); - let (position, size, line_height) = - if self.transforms.current.is_identity() { - (text.position, text.size, text.line_height) - } else { - let (_, scale_y) = self.transforms.current.scale(); + let (scale_x, scale_y) = self.transforms.current.scale(); + + if self.transforms.current.is_scale_translation() + && scale_x == scale_y + && scale_x > 0.0 + && scale_y > 0.0 + { + let (position, size, line_height) = + if self.transforms.current.is_identity() { + (text.position, text.size, text.line_height) + } else { + let position = + self.transforms.current.transform_point(text.position); + + let size = Pixels(text.size.0 * scale_y); + + let line_height = match text.line_height { + LineHeight::Absolute(size) => { + LineHeight::Absolute(Pixels(size.0 * scale_y)) + } + LineHeight::Relative(factor) => { + LineHeight::Relative(factor) + } + }; + + (position, size, line_height) + }; - let position = - self.transforms.current.transform_point(text.position); + let bounds = Rectangle { + x: position.x, + y: position.y, + width: f32::INFINITY, + height: f32::INFINITY, + }; - let size = Pixels(text.size.0 * scale_y); + // TODO: Honor layering! + self.primitives.push(Primitive::Text { + content: text.content, + bounds, + color: text.color, + size, + line_height, + font: text.font, + horizontal_alignment: text.horizontal_alignment, + vertical_alignment: text.vertical_alignment, + shaping: text.shaping, + clip_bounds: Rectangle::with_size(Size::INFINITY), + }); + } else { + let mut font_system = + text::font_system().write().expect("Write font system"); - let line_height = match text.line_height { - LineHeight::Absolute(size) => { - LineHeight::Absolute(Pixels(size.0 * scale_y)) - } - LineHeight::Relative(factor) => { - LineHeight::Relative(factor) + let mut buffer = cosmic_text::BufferLine::new( + &text.content, + cosmic_text::AttrsList::new(text::to_attributes(text.font)), + text::to_shaping(text.shaping), + ); + + let layout = buffer.layout( + font_system.raw(), + text.size.0, + f32::MAX, + cosmic_text::Wrap::None, + ); + + let translation_x = match text.horizontal_alignment { + alignment::Horizontal::Left => text.position.x, + alignment::Horizontal::Center + | alignment::Horizontal::Right => { + let mut line_width = 0.0f32; + + for line in layout.iter() { + line_width = line_width.max(line.w); } - }; - (position, size, line_height) + if text.horizontal_alignment + == alignment::Horizontal::Center + { + text.position.x - line_width / 2.0 + } else { + text.position.x - line_width + } + } }; - let bounds = Rectangle { - x: position.x, - y: position.y, - width: f32::INFINITY, - height: f32::INFINITY, - }; + let translation_y = { + let line_height = text.line_height.to_absolute(text.size); - // TODO: Use vectorial text instead of primitive - self.primitives.push(Primitive::Text { - content: text.content, - bounds, - color: text.color, - size, - line_height, - font: text.font, - horizontal_alignment: text.horizontal_alignment, - vertical_alignment: text.vertical_alignment, - shaping: text.shaping, - clip_bounds: Rectangle::with_size(Size::INFINITY), - }); + match text.vertical_alignment { + alignment::Vertical::Top => text.position.y, + alignment::Vertical::Center => { + text.position.y - line_height.0 / 2.0 + } + alignment::Vertical::Bottom => { + text.position.y - line_height.0 + } + } + }; + + let mut swash_cache = cosmic_text::SwashCache::new(); + + for run in layout.iter() { + for glyph in run.glyphs.iter() { + let physical_glyph = glyph.physical((0.0, 0.0), 1.0); + + let start_x = translation_x + glyph.x + glyph.x_offset; + let start_y = translation_y + glyph.y_offset + text.size.0; + let offset = Vector::new(start_x, start_y); + + if let Some(commands) = swash_cache.get_outline_commands( + font_system.raw(), + physical_glyph.cache_key, + ) { + let glyph = Path::new(|path| { + use cosmic_text::Command; + + for command in commands { + match command { + Command::MoveTo(p) => { + path.move_to( + Point::new(p.x, -p.y) + offset, + ); + } + Command::LineTo(p) => { + path.line_to( + Point::new(p.x, -p.y) + offset, + ); + } + Command::CurveTo( + control_a, + control_b, + to, + ) => { + path.bezier_curve_to( + Point::new( + control_a.x, + -control_a.y, + ) + offset, + Point::new( + control_b.x, + -control_b.y, + ) + offset, + Point::new(to.x, -to.y) + offset, + ); + } + Command::QuadTo(control, to) => { + path.quadratic_curve_to( + Point::new(control.x, -control.y) + + offset, + Point::new(to.x, -to.y) + offset, + ); + } + Command::Close => { + path.close(); + } + } + } + }); + + self.fill(&glyph, text.color); + } else { + // TODO: Raster image support for `Canvas` + let [r, g, b, a] = text.color.into_rgba8(); + + swash_cache.with_pixels( + font_system.raw(), + physical_glyph.cache_key, + cosmic_text::Color::rgba(r, g, b, a), + |x, y, color| { + self.fill( + &Path::rectangle( + Point::new(x as f32, y as f32) + offset, + Size::new(1.0, 1.0), + ), + Color::from_rgba8( + color.r(), + color.g(), + color.b(), + color.a() as f32 / 255.0, + ), + ); + }, + ) + } + } + } + } } /// Stores the current transform of the [`Frame`] and executes the given -- cgit From 4cb53a6e225f9e533126eb03d3cc34be3fd09f1d Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Wed, 17 Jan 2024 14:48:33 +0100 Subject: Implement vectorial text support for `iced_tiny_skia` --- wgpu/src/geometry.rs | 142 +-------------------------------------------------- 1 file changed, 2 insertions(+), 140 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/geometry.rs b/wgpu/src/geometry.rs index a1583a07..4d7f443e 100644 --- a/wgpu/src/geometry.rs +++ b/wgpu/src/geometry.rs @@ -1,7 +1,6 @@ //! Build and draw geometry. -use crate::core::alignment; use crate::core::text::LineHeight; -use crate::core::{Color, Pixels, Point, Rectangle, Size, Vector}; +use crate::core::{Pixels, Point, Rectangle, Size, Vector}; use crate::graphics::color; use crate::graphics::geometry::fill::{self, Fill}; use crate::graphics::geometry::{ @@ -9,7 +8,6 @@ use crate::graphics::geometry::{ }; use crate::graphics::gradient::{self, Gradient}; use crate::graphics::mesh::{self, Mesh}; -use crate::graphics::text::{self, cosmic_text}; use crate::primitive::{self, Primitive}; use lyon::geom::euclid; @@ -380,143 +378,7 @@ impl Frame { clip_bounds: Rectangle::with_size(Size::INFINITY), }); } else { - let mut font_system = - text::font_system().write().expect("Write font system"); - - let mut buffer = cosmic_text::BufferLine::new( - &text.content, - cosmic_text::AttrsList::new(text::to_attributes(text.font)), - text::to_shaping(text.shaping), - ); - - let layout = buffer.layout( - font_system.raw(), - text.size.0, - f32::MAX, - cosmic_text::Wrap::None, - ); - - let translation_x = match text.horizontal_alignment { - alignment::Horizontal::Left => text.position.x, - alignment::Horizontal::Center - | alignment::Horizontal::Right => { - let mut line_width = 0.0f32; - - for line in layout.iter() { - line_width = line_width.max(line.w); - } - - if text.horizontal_alignment - == alignment::Horizontal::Center - { - text.position.x - line_width / 2.0 - } else { - text.position.x - line_width - } - } - }; - - let translation_y = { - let line_height = text.line_height.to_absolute(text.size); - - match text.vertical_alignment { - alignment::Vertical::Top => text.position.y, - alignment::Vertical::Center => { - text.position.y - line_height.0 / 2.0 - } - alignment::Vertical::Bottom => { - text.position.y - line_height.0 - } - } - }; - - let mut swash_cache = cosmic_text::SwashCache::new(); - - for run in layout.iter() { - for glyph in run.glyphs.iter() { - let physical_glyph = glyph.physical((0.0, 0.0), 1.0); - - let start_x = translation_x + glyph.x + glyph.x_offset; - let start_y = translation_y + glyph.y_offset + text.size.0; - let offset = Vector::new(start_x, start_y); - - if let Some(commands) = swash_cache.get_outline_commands( - font_system.raw(), - physical_glyph.cache_key, - ) { - let glyph = Path::new(|path| { - use cosmic_text::Command; - - for command in commands { - match command { - Command::MoveTo(p) => { - path.move_to( - Point::new(p.x, -p.y) + offset, - ); - } - Command::LineTo(p) => { - path.line_to( - Point::new(p.x, -p.y) + offset, - ); - } - Command::CurveTo( - control_a, - control_b, - to, - ) => { - path.bezier_curve_to( - Point::new( - control_a.x, - -control_a.y, - ) + offset, - Point::new( - control_b.x, - -control_b.y, - ) + offset, - Point::new(to.x, -to.y) + offset, - ); - } - Command::QuadTo(control, to) => { - path.quadratic_curve_to( - Point::new(control.x, -control.y) - + offset, - Point::new(to.x, -to.y) + offset, - ); - } - Command::Close => { - path.close(); - } - } - } - }); - - self.fill(&glyph, text.color); - } else { - // TODO: Raster image support for `Canvas` - let [r, g, b, a] = text.color.into_rgba8(); - - swash_cache.with_pixels( - font_system.raw(), - physical_glyph.cache_key, - cosmic_text::Color::rgba(r, g, b, a), - |x, y, color| { - self.fill( - &Path::rectangle( - Point::new(x as f32, y as f32) + offset, - Size::new(1.0, 1.0), - ), - Color::from_rgba8( - color.r(), - color.g(), - color.b(), - color.a() as f32 / 255.0, - ), - ); - }, - ) - } - } - } + text.draw_with(|path, color| self.fill(&path, color)); } } -- cgit From 7289b6091b61b0aa448a756cfe32211c78a4cce0 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott <idscott@system76.com> Date: Tue, 9 Jan 2024 07:19:15 -0800 Subject: WIP raw-window-handle 0.6 --- wgpu/src/window/compositor.rs | 73 ++++++++++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 29 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index 090e0e9f..e2dc4901 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -6,13 +6,13 @@ use crate::graphics::compositor; use crate::graphics::{Error, Viewport}; use crate::{Backend, Primitive, Renderer, Settings}; -use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle}; +use raw_window_handle::{HasDisplayHandle, HasWindowHandle}; use std::marker::PhantomData; /// A window graphics backend for iced powered by `wgpu`. #[allow(missing_debug_implementations)] -pub struct Compositor<Theme> { +pub struct Compositor<W, Theme> { settings: Settings, instance: wgpu::Instance, adapter: wgpu::Adapter, @@ -20,15 +20,18 @@ pub struct Compositor<Theme> { queue: wgpu::Queue, format: wgpu::TextureFormat, theme: PhantomData<Theme>, + w: PhantomData<W>, } -impl<Theme> Compositor<Theme> { +impl<W: HasWindowHandle + HasDisplayHandle + wgpu::WasmNotSendSync, Theme> + Compositor<W, Theme> +{ /// Requests a new [`Compositor`] with the given [`Settings`]. /// /// Returns `None` if no compatible graphics adapter could be found. - pub async fn request<W: HasRawWindowHandle + HasRawDisplayHandle>( + pub async fn request( settings: Settings, - compatible_window: Option<&W>, + compatible_window: Option<W>, ) -> Option<Self> { let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { backends: settings.internal_backend, @@ -41,6 +44,7 @@ impl<Theme> Compositor<Theme> { if log::max_level() >= log::LevelFilter::Info { let available_adapters: Vec<_> = instance .enumerate_adapters(settings.internal_backend) + .iter() .map(|adapter| adapter.get_info()) .collect(); log::info!("Available adapters: {available_adapters:#?}"); @@ -48,7 +52,7 @@ impl<Theme> Compositor<Theme> { #[allow(unsafe_code)] let compatible_surface = compatible_window - .and_then(|window| unsafe { instance.create_surface(window).ok() }); + .and_then(|window| instance.create_surface(window).ok()); let adapter = instance .request_adapter(&wgpu::RequestAdapterOptions { @@ -100,14 +104,14 @@ impl<Theme> Compositor<Theme> { let (device, queue) = loop { - let limits = limits.next()?; + let required_limits = limits.next()?; let device = adapter.request_device( &wgpu::DeviceDescriptor { label: Some( "iced_wgpu::window::compositor device descriptor", ), - features: wgpu::Features::empty(), - limits, + required_features: wgpu::Features::empty(), + required_limits, }, None, ).await.ok(); @@ -125,6 +129,7 @@ impl<Theme> Compositor<Theme> { queue, format, theme: PhantomData, + w: PhantomData, }) } @@ -136,10 +141,13 @@ impl<Theme> Compositor<Theme> { /// Creates a [`Compositor`] and its [`Backend`] for the given [`Settings`] and /// window. -pub fn new<Theme, W: HasRawWindowHandle + HasRawDisplayHandle>( +pub fn new< + Theme, + W: HasWindowHandle + HasDisplayHandle + wgpu::WasmNotSendSync, +>( settings: Settings, - compatible_window: Option<&W>, -) -> Result<Compositor<Theme>, Error> { + compatible_window: Option<W>, +) -> Result<Compositor<W, Theme>, Error> { let compositor = futures::executor::block_on(Compositor::request( settings, compatible_window, @@ -150,10 +158,10 @@ pub fn new<Theme, W: HasRawWindowHandle + HasRawDisplayHandle>( } /// Presents the given primitives with the given [`Compositor`] and [`Backend`]. -pub fn present<Theme, T: AsRef<str>>( - compositor: &mut Compositor<Theme>, +pub fn present<W, Theme, T: AsRef<str>>( + compositor: &mut Compositor<W, Theme>, backend: &mut Backend, - surface: &mut wgpu::Surface, + surface: &mut wgpu::Surface<'static>, primitives: &[Primitive], viewport: &Viewport, background_color: Color, @@ -204,14 +212,19 @@ pub fn present<Theme, T: AsRef<str>>( } } -impl<Theme> graphics::Compositor for Compositor<Theme> { +impl< + W: HasDisplayHandle + HasWindowHandle + wgpu::WasmNotSendSync + 'static, + Theme, + > graphics::Compositor<W> for Compositor<W, Theme> +{ type Settings = Settings; type Renderer = Renderer<Theme>; - type Surface = wgpu::Surface; + // XXX generic instead of 'static + type Surface = wgpu::Surface<'static>; - fn new<W: HasRawWindowHandle + HasRawDisplayHandle>( + fn new( settings: Self::Settings, - compatible_window: Option<&W>, + compatible_window: Option<W>, ) -> Result<Self, Error> { new(settings, compatible_window) } @@ -224,14 +237,15 @@ impl<Theme> graphics::Compositor for Compositor<Theme> { ) } - fn create_surface<W: HasRawWindowHandle + HasRawDisplayHandle>( + fn create_surface( &mut self, - window: &W, + window: W, width: u32, height: u32, - ) -> wgpu::Surface { - #[allow(unsafe_code)] - let mut surface = unsafe { self.instance.create_surface(window) } + ) -> wgpu::Surface<'static> { + let mut surface = self + .instance + .create_surface(window) .expect("Create surface"); self.configure_surface(&mut surface, width, height); @@ -241,7 +255,7 @@ impl<Theme> graphics::Compositor for Compositor<Theme> { fn configure_surface( &mut self, - surface: &mut Self::Surface, + surface: &mut wgpu::Surface<'static>, width: u32, height: u32, ) { @@ -255,6 +269,7 @@ impl<Theme> graphics::Compositor for Compositor<Theme> { height, alpha_mode: wgpu::CompositeAlphaMode::Auto, view_formats: vec![], + desired_maximum_frame_latency: 2, }, ); } @@ -271,7 +286,7 @@ impl<Theme> graphics::Compositor for Compositor<Theme> { fn present<T: AsRef<str>>( &mut self, renderer: &mut Self::Renderer, - surface: &mut Self::Surface, + surface: &mut wgpu::Surface<'static>, viewport: &Viewport, background_color: Color, overlay: &[T], @@ -292,7 +307,7 @@ impl<Theme> graphics::Compositor for Compositor<Theme> { fn screenshot<T: AsRef<str>>( &mut self, renderer: &mut Self::Renderer, - _surface: &mut Self::Surface, + _surface: &mut wgpu::Surface<'static>, viewport: &Viewport, background_color: Color, overlay: &[T], @@ -313,8 +328,8 @@ impl<Theme> graphics::Compositor for Compositor<Theme> { /// Renders the current surface to an offscreen buffer. /// /// Returns RGBA bytes of the texture data. -pub fn screenshot<Theme, T: AsRef<str>>( - compositor: &Compositor<Theme>, +pub fn screenshot<W, Theme, T: AsRef<str>>( + compositor: &Compositor<W, Theme>, backend: &mut Backend, primitives: &[Primitive], viewport: &Viewport, -- cgit From 8bf238697226e827dc983f9d89afbd0e252c5254 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Thu, 18 Jan 2024 09:55:27 +0100 Subject: Remove `Compositor` window generic And update `glyphon` and `window_clipboard` --- wgpu/Cargo.toml | 1 - wgpu/src/window/compositor.rs | 40 +++++++++++++--------------------------- 2 files changed, 13 insertions(+), 28 deletions(-) (limited to 'wgpu') diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index a460c127..1d3b57a7 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -32,7 +32,6 @@ glyphon.workspace = true guillotiere.workspace = true log.workspace = true once_cell.workspace = true -raw-window-handle.workspace = true wgpu.workspace = true lyon.workspace = true diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index e2dc4901..0c063d0b 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -6,13 +6,11 @@ use crate::graphics::compositor; use crate::graphics::{Error, Viewport}; use crate::{Backend, Primitive, Renderer, Settings}; -use raw_window_handle::{HasDisplayHandle, HasWindowHandle}; - use std::marker::PhantomData; /// A window graphics backend for iced powered by `wgpu`. #[allow(missing_debug_implementations)] -pub struct Compositor<W, Theme> { +pub struct Compositor<Theme> { settings: Settings, instance: wgpu::Instance, adapter: wgpu::Adapter, @@ -20,16 +18,13 @@ pub struct Compositor<W, Theme> { queue: wgpu::Queue, format: wgpu::TextureFormat, theme: PhantomData<Theme>, - w: PhantomData<W>, } -impl<W: HasWindowHandle + HasDisplayHandle + wgpu::WasmNotSendSync, Theme> - Compositor<W, Theme> -{ +impl<Theme> Compositor<Theme> { /// Requests a new [`Compositor`] with the given [`Settings`]. /// /// Returns `None` if no compatible graphics adapter could be found. - pub async fn request( + pub async fn request<W: compositor::Window>( settings: Settings, compatible_window: Option<W>, ) -> Option<Self> { @@ -45,7 +40,7 @@ impl<W: HasWindowHandle + HasDisplayHandle + wgpu::WasmNotSendSync, Theme> let available_adapters: Vec<_> = instance .enumerate_adapters(settings.internal_backend) .iter() - .map(|adapter| adapter.get_info()) + .map(wgpu::Adapter::get_info) .collect(); log::info!("Available adapters: {available_adapters:#?}"); } @@ -129,7 +124,6 @@ impl<W: HasWindowHandle + HasDisplayHandle + wgpu::WasmNotSendSync, Theme> queue, format, theme: PhantomData, - w: PhantomData, }) } @@ -141,13 +135,10 @@ impl<W: HasWindowHandle + HasDisplayHandle + wgpu::WasmNotSendSync, Theme> /// Creates a [`Compositor`] and its [`Backend`] for the given [`Settings`] and /// window. -pub fn new< - Theme, - W: HasWindowHandle + HasDisplayHandle + wgpu::WasmNotSendSync, ->( +pub fn new<W: compositor::Window, Theme>( settings: Settings, compatible_window: Option<W>, -) -> Result<Compositor<W, Theme>, Error> { +) -> Result<Compositor<Theme>, Error> { let compositor = futures::executor::block_on(Compositor::request( settings, compatible_window, @@ -158,8 +149,8 @@ pub fn new< } /// Presents the given primitives with the given [`Compositor`] and [`Backend`]. -pub fn present<W, Theme, T: AsRef<str>>( - compositor: &mut Compositor<W, Theme>, +pub fn present<Theme, T: AsRef<str>>( + compositor: &mut Compositor<Theme>, backend: &mut Backend, surface: &mut wgpu::Surface<'static>, primitives: &[Primitive], @@ -212,17 +203,12 @@ pub fn present<W, Theme, T: AsRef<str>>( } } -impl< - W: HasDisplayHandle + HasWindowHandle + wgpu::WasmNotSendSync + 'static, - Theme, - > graphics::Compositor<W> for Compositor<W, Theme> -{ +impl<Theme> graphics::Compositor for Compositor<Theme> { type Settings = Settings; type Renderer = Renderer<Theme>; - // XXX generic instead of 'static type Surface = wgpu::Surface<'static>; - fn new( + fn new<W: compositor::Window>( settings: Self::Settings, compatible_window: Option<W>, ) -> Result<Self, Error> { @@ -237,7 +223,7 @@ impl< ) } - fn create_surface( + fn create_surface<W: compositor::Window>( &mut self, window: W, width: u32, @@ -328,8 +314,8 @@ impl< /// Renders the current surface to an offscreen buffer. /// /// Returns RGBA bytes of the texture data. -pub fn screenshot<W, Theme, T: AsRef<str>>( - compositor: &Compositor<W, Theme>, +pub fn screenshot<Theme, T: AsRef<str>>( + compositor: &Compositor<Theme>, backend: &mut Backend, primitives: &[Primitive], viewport: &Viewport, -- cgit From 5fc49edc55a0e64c4c46ca55eddafe9d4e8232e1 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Thu, 18 Jan 2024 10:06:30 +0100 Subject: Make `compatible_window` mandatory in `Compositor` --- wgpu/src/window/compositor.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index 0c063d0b..105d83a8 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -137,11 +137,11 @@ impl<Theme> Compositor<Theme> { /// window. pub fn new<W: compositor::Window, Theme>( settings: Settings, - compatible_window: Option<W>, + compatible_window: W, ) -> Result<Compositor<Theme>, Error> { let compositor = futures::executor::block_on(Compositor::request( settings, - compatible_window, + Some(compatible_window), )) .ok_or(Error::GraphicsAdapterNotFound)?; @@ -210,7 +210,7 @@ impl<Theme> graphics::Compositor for Compositor<Theme> { fn new<W: compositor::Window>( settings: Self::Settings, - compatible_window: Option<W>, + compatible_window: W, ) -> Result<Self, Error> { new(settings, compatible_window) } -- cgit From c929e6f5dd30044df4e7400ab633eaf0a53ce3dd Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Thu, 18 Jan 2024 10:56:02 +0100 Subject: Use `Self::Surface` in `Compositor` implementors --- wgpu/src/window/compositor.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'wgpu') diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index 105d83a8..31cf3819 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -228,7 +228,7 @@ impl<Theme> graphics::Compositor for Compositor<Theme> { window: W, width: u32, height: u32, - ) -> wgpu::Surface<'static> { + ) -> Self::Surface { let mut surface = self .instance .create_surface(window) @@ -241,7 +241,7 @@ impl<Theme> graphics::Compositor for Compositor<Theme> { fn configure_surface( &mut self, - surface: &mut wgpu::Surface<'static>, + surface: &mut Self::Surface, width: u32, height: u32, ) { @@ -272,7 +272,7 @@ impl<Theme> graphics::Compositor for Compositor<Theme> { fn present<T: AsRef<str>>( &mut self, renderer: &mut Self::Renderer, - surface: &mut wgpu::Surface<'static>, + surface: &mut Self::Surface, viewport: &Viewport, background_color: Color, overlay: &[T], @@ -293,7 +293,7 @@ impl<Theme> graphics::Compositor for Compositor<Theme> { fn screenshot<T: AsRef<str>>( &mut self, renderer: &mut Self::Renderer, - _surface: &mut wgpu::Surface<'static>, + _surface: &mut Self::Surface, viewport: &Viewport, background_color: Color, overlay: &[T], -- cgit