From 95ff96f71f8f8069608ad08985e2b1214dd42284 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector0193@gmail.com> Date: Fri, 7 Jul 2023 07:12:37 +0200 Subject: Update `cosmic-text` and `glyphon` --- wgpu/src/backend.rs | 53 +++++++++++++---------------------------------------- wgpu/src/text.rs | 22 ++++++---------------- 2 files changed, 19 insertions(+), 56 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/backend.rs b/wgpu/src/backend.rs index 4a0c54f0..9966a38c 100644 --- a/wgpu/src/backend.rs +++ b/wgpu/src/backend.rs @@ -94,18 +94,11 @@ impl Backend { queue, encoder, scale_factor, + target_size, transformation, &layers, ); - while !self.prepare_text( - device, - queue, - scale_factor, - target_size, - &layers, - ) {} - self.render( device, encoder, @@ -124,44 +117,13 @@ impl Backend { self.image_pipeline.end_frame(); } - fn prepare_text( - &mut self, - device: &wgpu::Device, - queue: &wgpu::Queue, - scale_factor: f32, - target_size: Size<u32>, - layers: &[Layer<'_>], - ) -> bool { - for layer in layers { - let bounds = (layer.bounds * scale_factor).snap(); - - if bounds.width < 1 || bounds.height < 1 { - continue; - } - - if !layer.text.is_empty() - && !self.text_pipeline.prepare( - device, - queue, - &layer.text, - layer.bounds, - scale_factor, - target_size, - ) - { - return false; - } - } - - true - } - fn prepare( &mut self, device: &wgpu::Device, queue: &wgpu::Queue, _encoder: &mut wgpu::CommandEncoder, scale_factor: f32, + target_size: Size<u32>, transformation: Transformation, layers: &[Layer<'_>], ) { @@ -210,6 +172,17 @@ impl Backend { ); } } + + if !layer.text.is_empty() { + self.text_pipeline.prepare( + device, + queue, + &layer.text, + layer.bounds, + scale_factor, + target_size, + ); + } } } diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs index 65d3b818..ef910c39 100644 --- a/wgpu/src/text.rs +++ b/wgpu/src/text.rs @@ -35,7 +35,7 @@ impl Pipeline { .into_iter(), )), renderers: Vec::new(), - atlas: glyphon::TextAtlas::new( + atlas: glyphon::TextAtlas::with_color_mode( device, queue, format, @@ -66,7 +66,7 @@ impl Pipeline { bounds: Rectangle, scale_factor: f32, target_size: Size<u32>, - ) -> bool { + ) { if self.renderers.len() <= self.prepare_layer { self.renderers.push(glyphon::TextRenderer::new( &mut self.atlas, @@ -188,21 +188,11 @@ impl Pipeline { match result { Ok(()) => { self.prepare_layer += 1; - - true } - Err(glyphon::PrepareError::AtlasFull(content_type)) => { - self.prepare_layer = 0; - - #[allow(clippy::needless_bool)] - if self.atlas.grow(device, content_type) { - false - } else { - // If the atlas cannot grow, then all bets are off. - // Instead of panicking, we will just pray that the result - // will be somewhat readable... - true - } + Err(glyphon::PrepareError::AtlasFull) => { + // If the atlas cannot grow, then all bets are off. + // Instead of panicking, we will just pray that the result + // will be somewhat readable... } } } -- cgit From 126aef88e7647c4690055b4c96aee46ecadcf60e Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector0193@gmail.com> Date: Fri, 28 Jul 2023 19:48:39 +0200 Subject: Bump versions :tada: --- wgpu/src/lib.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index deb223ef..d1e4b7af 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -1,25 +1,22 @@ -//! A [`wgpu`] renderer for [`iced_native`]. +//! A [`wgpu`] renderer for [Iced]. //! //!  //! -//! For now, it is the default renderer of [Iced] in native platforms. -//! //! [`wgpu`] supports most modern graphics backends: Vulkan, Metal, DX11, and //! DX12 (OpenGL and WebGL are still WIP). Additionally, it will support the //! incoming [WebGPU API]. //! //! Currently, `iced_wgpu` supports the following primitives: -//! - Text, which is rendered using [`wgpu_glyph`]. No shaping at all. +//! - Text, which is rendered using [`glyphon`]. //! - Quads or rectangles, with rounded borders and a solid background color. //! - Clip areas, useful to implement scrollables or hide overflowing content. //! - Images and SVG, loaded from memory or the file system. //! - Meshes of triangles, useful to draw geometry freely. //! //! [Iced]: https://github.com/iced-rs/iced -//! [`iced_native`]: https://github.com/iced-rs/iced/tree/0.9/native //! [`wgpu`]: https://github.com/gfx-rs/wgpu-rs //! [WebGPU API]: https://gpuweb.github.io/gpuweb/ -//! [`wgpu_glyph`]: https://github.com/hecrj/wgpu_glyph +//! [`glyphon`]: https://github.com/grovesNL/glyphon #![doc( html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg" )] -- cgit From c7e17391c53c9aa076d76982189a5184681aac0c Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector0193@gmail.com> Date: Wed, 2 Aug 2023 22:05:11 +0200 Subject: Fix `iced_wgpu` freezing on empty layers The `render` method would return when an empty layer is encountered without explicitly dropping the `RenderPass` (necessary because we use `ManuallyDrop`), which would then leak memory and freeze `wgpu` until the surface was recreated. --- wgpu/src/backend.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'wgpu/src') diff --git a/wgpu/src/backend.rs b/wgpu/src/backend.rs index 9966a38c..c6a17f2c 100644 --- a/wgpu/src/backend.rs +++ b/wgpu/src/backend.rs @@ -236,7 +236,7 @@ impl Backend { let bounds = (layer.bounds * scale_factor).snap(); if bounds.width < 1 || bounds.height < 1 { - return; + continue; } if !layer.quads.is_empty() { -- cgit From a7609a723ff0102ef8f606ac2c3bbabc30974db9 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector0193@gmail.com> Date: Wed, 2 Aug 2023 22:08:14 +0200 Subject: Avoid empty overlay layer in `iced_wgpu` --- wgpu/src/backend.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'wgpu/src') diff --git a/wgpu/src/backend.rs b/wgpu/src/backend.rs index c6a17f2c..68d1f805 100644 --- a/wgpu/src/backend.rs +++ b/wgpu/src/backend.rs @@ -87,7 +87,10 @@ impl Backend { let transformation = viewport.projection(); let mut layers = Layer::generate(primitives, viewport); - layers.push(Layer::overlay(overlay_text, viewport)); + + if !overlay_text.is_empty() { + layers.push(Layer::overlay(overlay_text, viewport)); + } self.prepare( device, -- cgit From e86363837d8e3a6241a90cb5b895034f07106059 Mon Sep 17 00:00:00 2001 From: lufte <javier@lufte.net> Date: Fri, 18 Aug 2023 18:46:22 -0300 Subject: Make the style attribute available on Font --- wgpu/src/text.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'wgpu/src') diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs index ef910c39..fb13545d 100644 --- a/wgpu/src/text.rs +++ b/wgpu/src/text.rs @@ -339,6 +339,14 @@ fn to_stretch(stretch: font::Stretch) -> glyphon::Stretch { } } +fn to_style(style: font::Style) -> glyphon::Style { + match style { + font::Style::Normal => glyphon::Style::Normal, + font::Style::Italic => glyphon::Style::Italic, + font::Style::Oblique => glyphon::Style::Oblique, + } +} + fn to_shaping(shaping: Shaping) -> glyphon::Shaping { match shaping { Shaping::Basic => glyphon::Shaping::Basic, @@ -420,7 +428,8 @@ impl Cache { glyphon::Attrs::new() .family(to_family(key.font.family)) .weight(to_weight(key.font.weight)) - .stretch(to_stretch(key.font.stretch)), + .stretch(to_stretch(key.font.stretch)) + .style(to_style(key.font.style)), to_shaping(key.shaping), ); -- cgit From ed3454301e663a7cb7d73cd56b57b188f4d14a2f Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector0193@gmail.com> Date: Wed, 30 Aug 2023 04:31:21 +0200 Subject: Implement explicit text caching in the widget state tree --- wgpu/src/backend.rs | 75 +------ wgpu/src/layer.rs | 29 ++- wgpu/src/layer/text.rs | 19 +- wgpu/src/lib.rs | 2 +- wgpu/src/settings.rs | 6 +- wgpu/src/text.rs | 509 +++++++++++------------------------------- wgpu/src/window/compositor.rs | 9 +- 7 files changed, 190 insertions(+), 459 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/backend.rs b/wgpu/src/backend.rs index 68d1f805..65c63f19 100644 --- a/wgpu/src/backend.rs +++ b/wgpu/src/backend.rs @@ -1,5 +1,5 @@ -use crate::core; -use crate::core::{Color, Font, Point, Size}; +use crate::core::{Color, Size}; +use crate::graphics; use crate::graphics::backend; use crate::graphics::color; use crate::graphics::{Transformation, Viewport}; @@ -29,9 +29,6 @@ pub struct Backend { #[cfg(any(feature = "image", feature = "svg"))] image_pipeline: image::Pipeline, - - default_font: Font, - default_text_size: f32, } impl Backend { @@ -57,9 +54,6 @@ impl Backend { #[cfg(any(feature = "image", feature = "svg"))] image_pipeline, - - default_font: settings.default_font, - default_text_size: settings.default_text_size, } } @@ -313,65 +307,11 @@ impl Backend { impl crate::graphics::Backend for Backend { type Primitive = primitive::Custom; - - fn trim_measurements(&mut self) { - self.text_pipeline.trim_measurements(); - } } impl backend::Text for Backend { - const ICON_FONT: Font = Font::with_name("Iced-Icons"); - const CHECKMARK_ICON: char = '\u{f00c}'; - const ARROW_DOWN_ICON: char = '\u{e800}'; - - fn default_font(&self) -> Font { - self.default_font - } - - fn default_size(&self) -> f32 { - self.default_text_size - } - - fn measure( - &self, - contents: &str, - size: f32, - line_height: core::text::LineHeight, - font: Font, - bounds: Size, - shaping: core::text::Shaping, - ) -> Size { - self.text_pipeline.measure( - contents, - size, - line_height, - font, - bounds, - shaping, - ) - } - - fn hit_test( - &self, - contents: &str, - size: f32, - line_height: core::text::LineHeight, - font: Font, - bounds: Size, - shaping: core::text::Shaping, - point: Point, - nearest_only: bool, - ) -> Option<core::text::Hit> { - self.text_pipeline.hit_test( - contents, - size, - line_height, - font, - bounds, - shaping, - point, - nearest_only, - ) + fn font_system(&self) -> &graphics::text::FontSystem { + self.text_pipeline.font_system() } fn load_font(&mut self, font: Cow<'static, [u8]>) { @@ -381,14 +321,17 @@ impl backend::Text for Backend { #[cfg(feature = "image")] impl backend::Image for Backend { - fn dimensions(&self, handle: &core::image::Handle) -> Size<u32> { + fn dimensions(&self, handle: &crate::core::image::Handle) -> Size<u32> { self.image_pipeline.dimensions(handle) } } #[cfg(feature = "svg")] impl backend::Svg for Backend { - fn viewport_dimensions(&self, handle: &core::svg::Handle) -> Size<u32> { + fn viewport_dimensions( + &self, + handle: &crate::core::svg::Handle, + ) -> Size<u32> { self.image_pipeline.viewport_dimensions(handle) } } diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs index b8f32db1..7a5a0f7c 100644 --- a/wgpu/src/layer.rs +++ b/wgpu/src/layer.rs @@ -10,7 +10,7 @@ pub use text::Text; use crate::core; use crate::core::alignment; -use crate::core::{Color, Font, Point, Rectangle, Size, Vector}; +use crate::core::{Color, Font, Pixels, Point, Rectangle, Size, Vector}; use crate::graphics; use crate::graphics::color; use crate::graphics::Viewport; @@ -56,14 +56,14 @@ impl<'a> Layer<'a> { Layer::new(Rectangle::with_size(viewport.logical_size())); for (i, line) in lines.iter().enumerate() { - let text = Text { + let text = text::Cached { content: line.as_ref(), bounds: Rectangle::new( Point::new(11.0, 11.0 + 25.0 * i as f32), Size::INFINITY, ), color: Color::new(0.9, 0.9, 0.9, 1.0), - size: 20.0, + size: Pixels(20.0), line_height: core::text::LineHeight::default(), font: Font::MONOSPACE, horizontal_alignment: alignment::Horizontal::Left, @@ -71,13 +71,13 @@ impl<'a> Layer<'a> { shaping: core::text::Shaping::Basic, }; - overlay.text.push(text); + overlay.text.push(Text::Cached(text.clone())); - overlay.text.push(Text { + overlay.text.push(Text::Cached(text::Cached { bounds: text.bounds + Vector::new(-1.0, -1.0), color: Color::BLACK, ..text - }); + })); } overlay @@ -113,6 +113,19 @@ impl<'a> Layer<'a> { current_layer: usize, ) { match primitive { + Primitive::Paragraph { + paragraph, + position, + color, + } => { + let layer = &mut layers[current_layer]; + + layer.text.push(Text::Managed { + paragraph: paragraph.clone(), + position: *position + translation, + color: *color, + }); + } Primitive::Text { content, bounds, @@ -126,7 +139,7 @@ impl<'a> Layer<'a> { } => { let layer = &mut layers[current_layer]; - layer.text.push(Text { + layer.text.push(Text::Cached(text::Cached { content, bounds: *bounds + translation, size: *size, @@ -136,7 +149,7 @@ impl<'a> Layer<'a> { horizontal_alignment: *horizontal_alignment, vertical_alignment: *vertical_alignment, shaping: *shaping, - }); + })); } Primitive::Quad { bounds, diff --git a/wgpu/src/layer/text.rs b/wgpu/src/layer/text.rs index ba1bdca8..b61615d6 100644 --- a/wgpu/src/layer/text.rs +++ b/wgpu/src/layer/text.rs @@ -1,10 +1,21 @@ use crate::core::alignment; use crate::core::text; -use crate::core::{Color, Font, Rectangle}; +use crate::core::{Color, Font, Pixels, Point, Rectangle}; +use crate::graphics::text::paragraph; /// A paragraph of text. -#[derive(Debug, Clone, Copy)] -pub struct Text<'a> { +#[derive(Debug, Clone)] +pub enum Text<'a> { + Managed { + paragraph: paragraph::Weak, + position: Point, + color: Color, + }, + Cached(Cached<'a>), +} + +#[derive(Debug, Clone)] +pub struct Cached<'a> { /// The content of the [`Text`]. pub content: &'a str, @@ -15,7 +26,7 @@ pub struct Text<'a> { pub color: Color, /// The size of the [`Text`] in logical pixels. - pub size: f32, + pub size: Pixels, /// The line height of the [`Text`]. pub line_height: text::LineHeight, diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index d1e4b7af..cd457072 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -22,7 +22,7 @@ )] #![deny( missing_debug_implementations, - missing_docs, + //missing_docs, unsafe_code, unused_results, clippy::extra_unused_lifetimes, diff --git a/wgpu/src/settings.rs b/wgpu/src/settings.rs index 266a2c87..c9338fec 100644 --- a/wgpu/src/settings.rs +++ b/wgpu/src/settings.rs @@ -1,5 +1,5 @@ //! Configure a renderer. -use crate::core::Font; +use crate::core::{Font, Pixels}; use crate::graphics::Antialiasing; /// The settings of a [`Backend`]. @@ -21,7 +21,7 @@ pub struct Settings { /// The default size of text. /// /// By default, it will be set to `16.0`. - pub default_text_size: f32, + pub default_text_size: Pixels, /// The antialiasing strategy that will be used for triangle primitives. /// @@ -59,7 +59,7 @@ impl Default for Settings { present_mode: wgpu::PresentMode::AutoVsync, internal_backend: wgpu::Backends::all(), default_font: Font::default(), - default_text_size: 16.0, + default_text_size: Pixels(16.0), antialiasing: None, } } diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs index fb13545d..da2062fe 100644 --- a/wgpu/src/text.rs +++ b/wgpu/src/text.rs @@ -1,20 +1,17 @@ use crate::core::alignment; -use crate::core::font::{self, Font}; -use crate::core::text::{Hit, LineHeight, Shaping}; -use crate::core::{Pixels, Point, Rectangle, Size}; +use crate::core::{Rectangle, Size}; use crate::graphics::color; +use crate::graphics::text::cache::{self, Cache}; +use crate::graphics::text::{FontSystem, Paragraph}; use crate::layer::Text; -use rustc_hash::{FxHashMap, FxHashSet}; use std::borrow::Cow; use std::cell::RefCell; -use std::collections::hash_map; -use std::hash::{BuildHasher, Hash, Hasher}; use std::sync::Arc; #[allow(missing_debug_implementations)] pub struct Pipeline { - font_system: RefCell<glyphon::FontSystem>, + font_system: FontSystem, renderers: Vec<glyphon::TextRenderer>, atlas: glyphon::TextAtlas, prepare_layer: usize, @@ -28,12 +25,7 @@ impl Pipeline { format: wgpu::TextureFormat, ) -> Self { Pipeline { - font_system: RefCell::new(glyphon::FontSystem::new_with_fonts( - [glyphon::fontdb::Source::Binary(Arc::new( - include_bytes!("../fonts/Iced-Icons.ttf").as_slice(), - ))] - .into_iter(), - )), + font_system: FontSystem::new(), renderers: Vec::new(), atlas: glyphon::TextAtlas::with_color_mode( device, @@ -50,6 +42,10 @@ impl Pipeline { } } + pub fn font_system(&self) -> &FontSystem { + &self.font_system + } + pub fn load_font(&mut self, bytes: Cow<'static, [u8]>) { let _ = self.font_system.get_mut().db_mut().load_font_source( glyphon::fontdb::Source::Binary(Arc::new(bytes.into_owned())), @@ -80,97 +76,137 @@ impl Pipeline { let renderer = &mut self.renderers[self.prepare_layer]; let cache = self.cache.get_mut(); - if self.prepare_layer == 0 { - cache.trim(Purpose::Drawing); + enum Allocation { + Paragraph(Paragraph), + Cache(cache::KeyHash), } - let keys: Vec<_> = sections + let allocations: Vec<_> = sections .iter() - .map(|section| { - let (key, _) = cache.allocate( - font_system, - Key { - content: section.content, - size: section.size, - line_height: f32::from( - section - .line_height - .to_absolute(Pixels(section.size)), - ), - font: section.font, - bounds: Size { - width: section.bounds.width, - height: section.bounds.height, + .map(|section| match section { + Text::Managed { paragraph, .. } => { + paragraph.upgrade().map(Allocation::Paragraph) + } + Text::Cached(text) => { + let (key, _) = cache.allocate( + font_system, + cache::Key { + content: text.content, + size: text.size.into(), + line_height: f32::from( + text.line_height.to_absolute(text.size), + ), + font: text.font, + bounds: Size { + width: bounds.width, + height: bounds.height, + }, + shaping: text.shaping, }, - shaping: section.shaping, - }, - Purpose::Drawing, - ); + ); - key + Some(Allocation::Cache(key)) + } }) .collect(); - let bounds = bounds * scale_factor; - - let text_areas = - sections - .iter() - .zip(keys.iter()) - .filter_map(|(section, key)| { - let entry = cache.get(key).expect("Get cached buffer"); - - let x = section.bounds.x * scale_factor; - let y = section.bounds.y * scale_factor; - - let max_width = entry.bounds.width * scale_factor; - let total_height = entry.bounds.height * scale_factor; - - let left = match section.horizontal_alignment { - alignment::Horizontal::Left => x, - alignment::Horizontal::Center => x - max_width / 2.0, - alignment::Horizontal::Right => x - max_width, - }; - - let top = match section.vertical_alignment { - alignment::Vertical::Top => y, - alignment::Vertical::Center => y - total_height / 2.0, - alignment::Vertical::Bottom => y - total_height, - }; - - let section_bounds = Rectangle { - x: left, - y: top, - width: section.bounds.width * scale_factor, - height: section.bounds.height * scale_factor, - }; - - let clip_bounds = bounds.intersection(§ion_bounds)?; - - Some(glyphon::TextArea { - buffer: &entry.buffer, - left, - top, - scale: scale_factor, - bounds: glyphon::TextBounds { - left: clip_bounds.x as i32, - top: clip_bounds.y as i32, - 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(section.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, - ) - }, - }) - }); + let layer_bounds = bounds * scale_factor; + + let text_areas = sections.iter().zip(allocations.iter()).filter_map( + |(section, allocation)| { + let ( + buffer, + bounds, + horizontal_alignment, + vertical_alignment, + color, + ) = match section { + Text::Managed { + position, color, .. + } => { + use crate::core::text::Paragraph as _; + + let Some(Allocation::Paragraph(paragraph)) = allocation + else { + return None; + }; + + ( + paragraph.buffer(), + Rectangle::new(*position, paragraph.min_bounds()), + paragraph.horizontal_alignment(), + paragraph.vertical_alignment(), + *color, + ) + } + Text::Cached(text) => { + let Some(Allocation::Cache(key)) = allocation else { + return None; + }; + + let buffer = cache.get(key).expect("Get cached buffer"); + + ( + buffer, + text.bounds, + text.horizontal_alignment, + text.vertical_alignment, + text.color, + ) + } + }; + + let x = bounds.x * scale_factor; + let y = bounds.y * scale_factor; + + let max_width = bounds.width * scale_factor; + let total_height = bounds.height * scale_factor; + + let left = match horizontal_alignment { + alignment::Horizontal::Left => x, + alignment::Horizontal::Center => x - max_width / 2.0, + alignment::Horizontal::Right => x - max_width, + }; + + let top = match vertical_alignment { + alignment::Vertical::Top => y, + alignment::Vertical::Center => y - total_height / 2.0, + alignment::Vertical::Bottom => y - total_height, + }; + + let section_bounds = Rectangle { + x: left, + y: top, + width: max_width, + height: total_height, + }; + + let clip_bounds = layer_bounds.intersection(§ion_bounds)?; + + Some(glyphon::TextArea { + buffer, + left, + top, + scale: scale_factor, + bounds: glyphon::TextBounds { + left: clip_bounds.x as i32, + top: clip_bounds.y as i32, + 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, + ) + }, + }) + }, + ); let result = renderer.prepare( device, @@ -219,287 +255,8 @@ impl Pipeline { pub fn end_frame(&mut self) { self.atlas.trim(); + self.cache.get_mut().trim(); self.prepare_layer = 0; } - - pub fn trim_measurements(&mut self) { - self.cache.get_mut().trim(Purpose::Measuring); - } - - pub fn measure( - &self, - content: &str, - size: f32, - line_height: LineHeight, - font: Font, - bounds: Size, - shaping: Shaping, - ) -> Size { - let mut cache = self.cache.borrow_mut(); - - let line_height = f32::from(line_height.to_absolute(Pixels(size))); - - let (_, entry) = cache.allocate( - &mut self.font_system.borrow_mut(), - Key { - content, - size, - line_height, - font, - bounds, - shaping, - }, - Purpose::Measuring, - ); - - entry.bounds - } - - pub fn hit_test( - &self, - content: &str, - size: f32, - line_height: LineHeight, - font: Font, - bounds: Size, - shaping: Shaping, - point: Point, - _nearest_only: bool, - ) -> Option<Hit> { - let mut cache = self.cache.borrow_mut(); - - let line_height = f32::from(line_height.to_absolute(Pixels(size))); - - let (_, entry) = cache.allocate( - &mut self.font_system.borrow_mut(), - Key { - content, - size, - line_height, - font, - bounds, - shaping, - }, - Purpose::Measuring, - ); - - let cursor = entry.buffer.hit(point.x, point.y)?; - - Some(Hit::CharOffset(cursor.index)) - } } - -fn measure(buffer: &glyphon::Buffer) -> Size { - let (width, total_lines) = buffer - .layout_runs() - .fold((0.0, 0usize), |(width, total_lines), run| { - (run.line_w.max(width), total_lines + 1) - }); - - Size::new(width, total_lines as f32 * buffer.metrics().line_height) -} - -fn to_family(family: font::Family) -> glyphon::Family<'static> { - match family { - font::Family::Name(name) => glyphon::Family::Name(name), - font::Family::SansSerif => glyphon::Family::SansSerif, - font::Family::Serif => glyphon::Family::Serif, - font::Family::Cursive => glyphon::Family::Cursive, - font::Family::Fantasy => glyphon::Family::Fantasy, - font::Family::Monospace => glyphon::Family::Monospace, - } -} - -fn to_weight(weight: font::Weight) -> glyphon::Weight { - match weight { - font::Weight::Thin => glyphon::Weight::THIN, - font::Weight::ExtraLight => glyphon::Weight::EXTRA_LIGHT, - font::Weight::Light => glyphon::Weight::LIGHT, - font::Weight::Normal => glyphon::Weight::NORMAL, - font::Weight::Medium => glyphon::Weight::MEDIUM, - font::Weight::Semibold => glyphon::Weight::SEMIBOLD, - font::Weight::Bold => glyphon::Weight::BOLD, - font::Weight::ExtraBold => glyphon::Weight::EXTRA_BOLD, - font::Weight::Black => glyphon::Weight::BLACK, - } -} - -fn to_stretch(stretch: font::Stretch) -> glyphon::Stretch { - match stretch { - font::Stretch::UltraCondensed => glyphon::Stretch::UltraCondensed, - font::Stretch::ExtraCondensed => glyphon::Stretch::ExtraCondensed, - font::Stretch::Condensed => glyphon::Stretch::Condensed, - font::Stretch::SemiCondensed => glyphon::Stretch::SemiCondensed, - font::Stretch::Normal => glyphon::Stretch::Normal, - font::Stretch::SemiExpanded => glyphon::Stretch::SemiExpanded, - font::Stretch::Expanded => glyphon::Stretch::Expanded, - font::Stretch::ExtraExpanded => glyphon::Stretch::ExtraExpanded, - font::Stretch::UltraExpanded => glyphon::Stretch::UltraExpanded, - } -} - -fn to_style(style: font::Style) -> glyphon::Style { - match style { - font::Style::Normal => glyphon::Style::Normal, - font::Style::Italic => glyphon::Style::Italic, - font::Style::Oblique => glyphon::Style::Oblique, - } -} - -fn to_shaping(shaping: Shaping) -> glyphon::Shaping { - match shaping { - Shaping::Basic => glyphon::Shaping::Basic, - Shaping::Advanced => glyphon::Shaping::Advanced, - } -} - -struct Cache { - entries: FxHashMap<KeyHash, Entry>, - aliases: FxHashMap<KeyHash, KeyHash>, - recently_measured: FxHashSet<KeyHash>, - recently_drawn: FxHashSet<KeyHash>, - hasher: HashBuilder, -} - -struct Entry { - buffer: glyphon::Buffer, - bounds: Size, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum Purpose { - Measuring, - Drawing, -} - -#[cfg(not(target_arch = "wasm32"))] -type HashBuilder = twox_hash::RandomXxHashBuilder64; - -#[cfg(target_arch = "wasm32")] -type HashBuilder = std::hash::BuildHasherDefault<twox_hash::XxHash64>; - -impl Cache { - fn new() -> Self { - Self { - entries: FxHashMap::default(), - aliases: FxHashMap::default(), - recently_measured: FxHashSet::default(), - recently_drawn: FxHashSet::default(), - hasher: HashBuilder::default(), - } - } - - fn get(&self, key: &KeyHash) -> Option<&Entry> { - self.entries.get(key) - } - - fn allocate( - &mut self, - font_system: &mut glyphon::FontSystem, - key: Key<'_>, - purpose: Purpose, - ) -> (KeyHash, &mut Entry) { - let hash = key.hash(self.hasher.build_hasher()); - - let recently_used = match purpose { - Purpose::Measuring => &mut self.recently_measured, - Purpose::Drawing => &mut self.recently_drawn, - }; - - if let Some(hash) = self.aliases.get(&hash) { - let _ = recently_used.insert(*hash); - - return (*hash, self.entries.get_mut(hash).unwrap()); - } - - if let hash_map::Entry::Vacant(entry) = self.entries.entry(hash) { - let metrics = glyphon::Metrics::new(key.size, key.line_height); - let mut buffer = glyphon::Buffer::new(font_system, metrics); - - buffer.set_size( - font_system, - key.bounds.width, - key.bounds.height.max(key.line_height), - ); - buffer.set_text( - font_system, - key.content, - glyphon::Attrs::new() - .family(to_family(key.font.family)) - .weight(to_weight(key.font.weight)) - .stretch(to_stretch(key.font.stretch)) - .style(to_style(key.font.style)), - to_shaping(key.shaping), - ); - - let bounds = measure(&buffer); - let _ = entry.insert(Entry { buffer, bounds }); - - for bounds in [ - bounds, - Size { - width: key.bounds.width, - ..bounds - }, - ] { - if key.bounds != bounds { - let _ = self.aliases.insert( - Key { bounds, ..key }.hash(self.hasher.build_hasher()), - hash, - ); - } - } - } - - let _ = recently_used.insert(hash); - - (hash, self.entries.get_mut(&hash).unwrap()) - } - - fn trim(&mut self, purpose: Purpose) { - self.entries.retain(|key, _| { - self.recently_measured.contains(key) - || self.recently_drawn.contains(key) - }); - self.aliases.retain(|_, value| { - self.recently_measured.contains(value) - || self.recently_drawn.contains(value) - }); - - match purpose { - Purpose::Measuring => { - self.recently_measured.clear(); - } - Purpose::Drawing => { - self.recently_drawn.clear(); - } - } - } -} - -#[derive(Debug, Clone, Copy)] -struct Key<'a> { - content: &'a str, - size: f32, - line_height: f32, - font: Font, - bounds: Size, - shaping: Shaping, -} - -impl Key<'_> { - fn hash<H: Hasher>(self, mut hasher: H) -> KeyHash { - self.content.hash(&mut hasher); - self.size.to_bits().hash(&mut hasher); - self.line_height.to_bits().hash(&mut hasher); - self.font.hash(&mut hasher); - self.bounds.width.to_bits().hash(&mut hasher); - self.bounds.height.to_bits().hash(&mut hasher); - self.shaping.hash(&mut hasher); - - hasher.finish() - } -} - -type KeyHash = u64; diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index cd5b20cc..09e11fdc 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -216,7 +216,14 @@ impl<Theme> graphics::Compositor for Compositor<Theme> { ) -> Result<(Self, Self::Renderer), Error> { let (compositor, backend) = new(settings, compatible_window)?; - Ok((compositor, Renderer::new(backend))) + Ok(( + compositor, + Renderer::new( + backend, + settings.default_font, + settings.default_text_size, + ), + )) } fn create_surface<W: HasRawWindowHandle + HasRawDisplayHandle>( -- cgit From 89acf0217e0acd92a82bff1fd516cd4266c0878a Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector0193@gmail.com> Date: Wed, 30 Aug 2023 05:06:08 +0200 Subject: Use `min_bounds` for cached text --- wgpu/src/text.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs index da2062fe..ee352368 100644 --- a/wgpu/src/text.rs +++ b/wgpu/src/text.rs @@ -59,7 +59,7 @@ impl Pipeline { device: &wgpu::Device, queue: &wgpu::Queue, sections: &[Text<'_>], - bounds: Rectangle, + layer_bounds: Rectangle, scale_factor: f32, target_size: Size<u32>, ) { @@ -98,8 +98,8 @@ impl Pipeline { ), font: text.font, bounds: Size { - width: bounds.width, - height: bounds.height, + width: text.bounds.width, + height: text.bounds.height, }, shaping: text.shaping, }, @@ -110,7 +110,7 @@ impl Pipeline { }) .collect(); - let layer_bounds = bounds * scale_factor; + let layer_bounds = layer_bounds * scale_factor; let text_areas = sections.iter().zip(allocations.iter()).filter_map( |(section, allocation)| { @@ -144,11 +144,14 @@ impl Pipeline { return None; }; - let buffer = cache.get(key).expect("Get cached buffer"); + let entry = cache.get(key).expect("Get cached buffer"); ( - buffer, - text.bounds, + &entry.buffer, + Rectangle::new( + text.bounds.position(), + entry.min_bounds, + ), text.horizontal_alignment, text.vertical_alignment, text.color, -- cgit From 020fb3c37794fcfa2670c3c0ada949aee95855a0 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector0193@gmail.com> Date: Sun, 3 Sep 2023 01:01:33 +0200 Subject: Fix `iced_wgpu` device selection on Wasm --- wgpu/src/window/compositor.rs | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index cd5b20cc..5202c7ef 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -6,8 +6,6 @@ use crate::graphics::compositor; use crate::graphics::{Error, Viewport}; use crate::{Backend, Primitive, Renderer, Settings}; -use futures::stream::{self, StreamExt}; - use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle}; use std::marker::PhantomData; @@ -95,14 +93,17 @@ impl<Theme> Compositor<Theme> { let limits = [wgpu::Limits::default(), wgpu::Limits::downlevel_defaults()]; - let limits = limits.into_iter().map(|limits| wgpu::Limits { - max_bind_groups: 2, - ..limits - }); + let mut limits = limits + .into_iter() + .map(|limits| wgpu::Limits { + max_bind_groups: 2, + ..limits + }) + .into_iter(); - let (device, queue) = stream::iter(limits) - .filter_map(|limits| async { - adapter.request_device( + let (device, queue) = loop { + if let Some(limits) = limits.next() { + let device = adapter.request_device( &wgpu::DeviceDescriptor { label: Some( "iced_wgpu::window::compositor device descriptor", @@ -111,11 +112,15 @@ impl<Theme> Compositor<Theme> { limits, }, None, - ).await.ok() - }) - .boxed() - .next() - .await?; + ).await.ok(); + + if let Some(device) = device { + break Some(device); + } + } + + break None; + }?; Some(Compositor { instance, -- cgit From 0b28080d3ebda4dda24c9ac9c38e3195d3499be7 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector0193@gmail.com> Date: Sun, 3 Sep 2023 01:05:17 +0200 Subject: Remove redundant `into_iter` call in `iced_wgpu` --- wgpu/src/window/compositor.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index 5202c7ef..cacfeef2 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -93,13 +93,10 @@ impl<Theme> Compositor<Theme> { let limits = [wgpu::Limits::default(), wgpu::Limits::downlevel_defaults()]; - let mut limits = limits - .into_iter() - .map(|limits| wgpu::Limits { - max_bind_groups: 2, - ..limits - }) - .into_iter(); + let mut limits = limits.into_iter().map(|limits| wgpu::Limits { + max_bind_groups: 2, + ..limits + }); let (device, queue) = loop { if let Some(limits) = limits.next() { -- cgit From 9b9b37e6f83b5e5a8811feb17b484c6b11fa3b8b Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector0193@gmail.com> Date: Sun, 3 Sep 2023 01:14:22 +0200 Subject: Fix adapter selection loop in `iced_wgpu` --- wgpu/src/window/compositor.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index cacfeef2..9e9c63db 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -98,8 +98,9 @@ impl<Theme> Compositor<Theme> { ..limits }); - let (device, queue) = loop { - if let Some(limits) = limits.next() { + let (device, queue) = + loop { + let limits = limits.next()?; let device = adapter.request_device( &wgpu::DeviceDescriptor { label: Some( @@ -114,10 +115,7 @@ impl<Theme> Compositor<Theme> { if let Some(device) = device { break Some(device); } - } - - break None; - }?; + }?; Some(Compositor { instance, -- cgit From 8129e2c208d9b13dbd32a309058b0547c723dede Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector0193@gmail.com> Date: Sun, 3 Sep 2023 08:08:27 +0200 Subject: Implement `draw_paragraph` in `iced_tiny_skia` --- wgpu/src/text.rs | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs index ee352368..a1ec511b 100644 --- a/wgpu/src/text.rs +++ b/wgpu/src/text.rs @@ -159,29 +159,28 @@ impl Pipeline { } }; - let x = bounds.x * scale_factor; - let y = bounds.y * scale_factor; - - let max_width = bounds.width * scale_factor; - let total_height = bounds.height * scale_factor; + let bounds = bounds * scale_factor; let left = match horizontal_alignment { - alignment::Horizontal::Left => x, - alignment::Horizontal::Center => x - max_width / 2.0, - alignment::Horizontal::Right => x - max_width, + alignment::Horizontal::Left => bounds.x, + alignment::Horizontal::Center => { + bounds.x - bounds.width / 2.0 + } + alignment::Horizontal::Right => bounds.x - bounds.width, }; let top = match vertical_alignment { - alignment::Vertical::Top => y, - alignment::Vertical::Center => y - total_height / 2.0, - alignment::Vertical::Bottom => y - total_height, + alignment::Vertical::Top => bounds.y, + alignment::Vertical::Center => { + bounds.y - bounds.height / 2.0 + } + alignment::Vertical::Bottom => bounds.y - bounds.height, }; let section_bounds = Rectangle { x: left, y: top, - width: max_width, - height: total_height, + ..bounds }; let clip_bounds = layer_bounds.intersection(§ion_bounds)?; -- cgit From 76cec1b1fd533dda37aa53c40ef7665ed3b406b6 Mon Sep 17 00:00:00 2001 From: David Huculak <davidhuculak5@gmail.com> Date: Sun, 3 Sep 2023 19:32:38 -0400 Subject: use @interpolate(flat) attribute as per the WebGPU spec: User-defined vertex outputs and fragment inputs of scalar or vector integer type must always be specified as @interpolate(flat) https://www.w3.org/TR/WGSL/#interpolation --- wgpu/src/shader/quad.wgsl | 22 +++++++++++----------- wgpu/src/shader/triangle.wgsl | 20 ++++++++++---------- 2 files changed, 21 insertions(+), 21 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/shader/quad.wgsl b/wgpu/src/shader/quad.wgsl index fb402158..87055339 100644 --- a/wgpu/src/shader/quad.wgsl +++ b/wgpu/src/shader/quad.wgsl @@ -147,12 +147,12 @@ fn solid_fs_main( struct GradientVertexInput { @location(0) v_pos: vec2<f32>, - @location(1) colors_1: vec4<u32>, - @location(2) colors_2: vec4<u32>, - @location(3) colors_3: vec4<u32>, - @location(4) colors_4: vec4<u32>, - @location(5) offsets: vec4<u32>, - @location(6) direction: vec4<f32>, + @location(1) @interpolate(flat) colors_1: vec4<u32>, + @location(2) @interpolate(flat) colors_2: vec4<u32>, + @location(3) @interpolate(flat) colors_3: vec4<u32>, + @location(4) @interpolate(flat) colors_4: vec4<u32>, + @location(5) @interpolate(flat) offsets: vec4<u32>, + @location(6) @interpolate(flat) direction: vec4<f32>, @location(7) position_and_scale: vec4<f32>, @location(8) border_color: vec4<f32>, @location(9) border_radius: vec4<f32>, @@ -161,11 +161,11 @@ struct GradientVertexInput { struct GradientVertexOutput { @builtin(position) position: vec4<f32>, - @location(1) colors_1: vec4<u32>, - @location(2) colors_2: vec4<u32>, - @location(3) colors_3: vec4<u32>, - @location(4) colors_4: vec4<u32>, - @location(5) offsets: vec4<u32>, + @location(1) @interpolate(flat) colors_1: vec4<u32>, + @location(2) @interpolate(flat) colors_2: vec4<u32>, + @location(3) @interpolate(flat) colors_3: vec4<u32>, + @location(4) @interpolate(flat) colors_4: vec4<u32>, + @location(5) @interpolate(flat) offsets: vec4<u32>, @location(6) direction: vec4<f32>, @location(7) position_and_scale: vec4<f32>, @location(8) border_color: vec4<f32>, diff --git a/wgpu/src/shader/triangle.wgsl b/wgpu/src/shader/triangle.wgsl index 9f512d14..3a2b9845 100644 --- a/wgpu/src/shader/triangle.wgsl +++ b/wgpu/src/shader/triangle.wgsl @@ -38,22 +38,22 @@ fn solid_fs_main(input: SolidVertexOutput) -> @location(0) vec4<f32> { struct GradientVertexInput { @location(0) v_pos: vec2<f32>, - @location(1) colors_1: vec4<u32>, - @location(2) colors_2: vec4<u32>, - @location(3) colors_3: vec4<u32>, - @location(4) colors_4: vec4<u32>, - @location(5) offsets: vec4<u32>, + @location(1) @interpolate(flat) colors_1: vec4<u32>, + @location(2) @interpolate(flat) colors_2: vec4<u32>, + @location(3) @interpolate(flat) colors_3: vec4<u32>, + @location(4) @interpolate(flat) colors_4: vec4<u32>, + @location(5) @interpolate(flat) offsets: vec4<u32>, @location(6) direction: vec4<f32>, } struct GradientVertexOutput { @builtin(position) position: vec4<f32>, @location(0) raw_position: vec2<f32>, - @location(1) colors_1: vec4<u32>, - @location(2) colors_2: vec4<u32>, - @location(3) colors_3: vec4<u32>, - @location(4) colors_4: vec4<u32>, - @location(5) offsets: vec4<u32>, + @location(1) @interpolate(flat) colors_1: vec4<u32>, + @location(2) @interpolate(flat) colors_2: vec4<u32>, + @location(3) @interpolate(flat) colors_3: vec4<u32>, + @location(4) @interpolate(flat) colors_4: vec4<u32>, + @location(5) @interpolate(flat) offsets: vec4<u32>, @location(6) direction: vec4<f32>, } -- cgit From ef429fbea6e39efcfdc58fdd8a2fe365fd5314d9 Mon Sep 17 00:00:00 2001 From: Josh Megnauth <jo.sh@tutanota.com> Date: Mon, 4 Sep 2023 02:58:54 -0400 Subject: Ensure LineHeight > 0.0 for the WGPU renderer --- wgpu/src/text.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs index fb13545d..08a32b5e 100644 --- a/wgpu/src/text.rs +++ b/wgpu/src/text.rs @@ -96,7 +96,8 @@ impl Pipeline { section .line_height .to_absolute(Pixels(section.size)), - ), + ) + .max(f32::MIN_POSITIVE), font: section.font, bounds: Size { width: section.bounds.width, @@ -238,7 +239,8 @@ impl Pipeline { ) -> Size { let mut cache = self.cache.borrow_mut(); - let line_height = f32::from(line_height.to_absolute(Pixels(size))); + let line_height = f32::from(line_height.to_absolute(Pixels(size))) + .max(f32::MIN_POSITIVE); let (_, entry) = cache.allocate( &mut self.font_system.borrow_mut(), @@ -269,7 +271,8 @@ impl Pipeline { ) -> Option<Hit> { let mut cache = self.cache.borrow_mut(); - let line_height = f32::from(line_height.to_absolute(Pixels(size))); + let line_height = f32::from(line_height.to_absolute(Pixels(size))) + .max(f32::MIN_POSITIVE); let (_, entry) = cache.allocate( &mut self.font_system.borrow_mut(), -- cgit From bdf18554feadb631fdae5b427ac7a92a5546ade1 Mon Sep 17 00:00:00 2001 From: Josh Megnauth <jo.sh@tutanota.com> Date: Mon, 4 Sep 2023 23:47:44 -0400 Subject: Check LineHeight > 0.0 before allocating text --- wgpu/src/text.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs index 08a32b5e..9c42be0e 100644 --- a/wgpu/src/text.rs +++ b/wgpu/src/text.rs @@ -96,8 +96,7 @@ impl Pipeline { section .line_height .to_absolute(Pixels(section.size)), - ) - .max(f32::MIN_POSITIVE), + ), font: section.font, bounds: Size { width: section.bounds.width, @@ -239,8 +238,7 @@ impl Pipeline { ) -> Size { let mut cache = self.cache.borrow_mut(); - let line_height = f32::from(line_height.to_absolute(Pixels(size))) - .max(f32::MIN_POSITIVE); + let line_height = f32::from(line_height.to_absolute(Pixels(size))); let (_, entry) = cache.allocate( &mut self.font_system.borrow_mut(), @@ -271,8 +269,7 @@ impl Pipeline { ) -> Option<Hit> { let mut cache = self.cache.borrow_mut(); - let line_height = f32::from(line_height.to_absolute(Pixels(size))) - .max(f32::MIN_POSITIVE); + let line_height = f32::from(line_height.to_absolute(Pixels(size))); let (_, entry) = cache.allocate( &mut self.font_system.borrow_mut(), @@ -417,7 +414,10 @@ impl Cache { } if let hash_map::Entry::Vacant(entry) = self.entries.entry(hash) { - let metrics = glyphon::Metrics::new(key.size, key.line_height); + let metrics = glyphon::Metrics::new( + key.size, + key.line_height.max(f32::MIN_POSITIVE), + ); let mut buffer = glyphon::Buffer::new(font_system, metrics); buffer.set_size( -- cgit From 5371fae21a4c1110a37e7183e794cba234598d9c Mon Sep 17 00:00:00 2001 From: ripytide <james.forsterer@gmail.com> Date: Tue, 5 Sep 2023 10:49:50 +0100 Subject: added a Frame::scale_nonuniform method --- wgpu/src/geometry.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'wgpu/src') diff --git a/wgpu/src/geometry.rs b/wgpu/src/geometry.rs index e421e0b0..2cd07a27 100644 --- a/wgpu/src/geometry.rs +++ b/wgpu/src/geometry.rs @@ -444,7 +444,7 @@ impl Frame { self.transforms.current.is_identity = false; } - /// Applies a scaling to the current transform of the [`Frame`]. + /// Applies a uniform scaling to the current transform of the [`Frame`]. #[inline] pub fn scale(&mut self, scale: f32) { self.transforms.current.raw = @@ -452,6 +452,14 @@ impl Frame { self.transforms.current.is_identity = false; } + /// Applies a non-uniform scaling to the current transform of the [`Frame`]. + #[inline] + pub fn scale_nonuniform(&mut self, scale: Vector) { + self.transforms.current.raw = + self.transforms.current.raw.pre_scale(scale.x, scale.y); + self.transforms.current.is_identity = false; + } + /// Produces the [`Primitive`] representing everything drawn on the [`Frame`]. pub fn into_primitive(self) -> Primitive { Primitive::Group { -- cgit From 87800095e27353557adb39ef42ee6f82a0075bc1 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector0193@gmail.com> Date: Thu, 7 Sep 2023 05:43:03 +0200 Subject: Remove unnecessary `interpolate(flat)` in `quad.wgsl` --- wgpu/src/shader/quad.wgsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'wgpu/src') diff --git a/wgpu/src/shader/quad.wgsl b/wgpu/src/shader/quad.wgsl index 87055339..023b5a6d 100644 --- a/wgpu/src/shader/quad.wgsl +++ b/wgpu/src/shader/quad.wgsl @@ -152,7 +152,7 @@ struct GradientVertexInput { @location(3) @interpolate(flat) colors_3: vec4<u32>, @location(4) @interpolate(flat) colors_4: vec4<u32>, @location(5) @interpolate(flat) offsets: vec4<u32>, - @location(6) @interpolate(flat) direction: vec4<f32>, + @location(6) direction: vec4<f32>, @location(7) position_and_scale: vec4<f32>, @location(8) border_color: vec4<f32>, @location(9) border_radius: vec4<f32>, -- cgit From 1f263051b6c2d2f2a02633d8a6277c772ae8e7f9 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector0193@gmail.com> Date: Thu, 7 Sep 2023 05:45:51 +0200 Subject: Implement `scale` in terms of `scale_nonuniform` --- wgpu/src/geometry.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/geometry.rs b/wgpu/src/geometry.rs index 2cd07a27..64b98469 100644 --- a/wgpu/src/geometry.rs +++ b/wgpu/src/geometry.rs @@ -447,9 +447,7 @@ impl Frame { /// Applies a uniform scaling to the current transform of the [`Frame`]. #[inline] pub fn scale(&mut self, scale: f32) { - self.transforms.current.raw = - self.transforms.current.raw.pre_scale(scale, scale); - self.transforms.current.is_identity = false; + self.scale_nonuniform(Vector { x: scale, y: scale }); } /// Applies a non-uniform scaling to the current transform of the [`Frame`]. -- cgit From 09965b686ea6bf82e6c13ed5331bbeb059848e4f Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector0193@gmail.com> Date: Thu, 7 Sep 2023 05:51:39 +0200 Subject: Make `scale` methods in `Frame` generic over `f32` and `Vector` --- wgpu/src/geometry.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/geometry.rs b/wgpu/src/geometry.rs index 64b98469..c3e16f8c 100644 --- a/wgpu/src/geometry.rs +++ b/wgpu/src/geometry.rs @@ -446,13 +446,17 @@ impl Frame { /// Applies a uniform scaling to the current transform of the [`Frame`]. #[inline] - pub fn scale(&mut self, scale: f32) { + pub fn scale(&mut self, scale: impl Into<f32>) { + let scale = scale.into(); + self.scale_nonuniform(Vector { x: scale, y: scale }); } /// Applies a non-uniform scaling to the current transform of the [`Frame`]. #[inline] - pub fn scale_nonuniform(&mut self, scale: Vector) { + 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; -- cgit From 181708a1c0f4920f7491df4516b0de3f61993391 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Mon, 28 Aug 2023 22:56:47 +0200 Subject: Compute gradients in Oklab color space --- wgpu/src/shader/quad.wgsl | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/shader/quad.wgsl b/wgpu/src/shader/quad.wgsl index 023b5a6d..cba7e5a4 100644 --- a/wgpu/src/shader/quad.wgsl +++ b/wgpu/src/shader/quad.wgsl @@ -230,6 +230,18 @@ fn gradient( let unit = normalize(v1); let coord_offset = dot(unit, v2) / length(v1); + let to_lms: mat3x4<f32> = mat3x4<f32>( + vec4<f32>(0.4121656120, 0.2118591070, 0.0883097947, 0.0), + vec4<f32>(0.5362752080, 0.6807189584, 0.2818474174, 0.0), + vec4<f32>(0.0514575653, 0.1074065790, 0.6302613616, 0.0), + ); + + let to_rgb: mat3x4<f32> = mat3x4<f32>( + vec4<f32>( 4.0767245293, -3.3072168827, 0.2307590544, 0.0), + vec4<f32>(-1.2681437731, 2.6093323231, -0.3411344290, 0.0), + vec4<f32>(-0.0041119885, -0.7034763098, 1.7068625689, 0.0), + ); + //need to store these as a var to use dynamic indexing in a loop //this is already added to wgsl spec but not in wgpu yet var colors_arr = colors; @@ -248,11 +260,15 @@ fn gradient( } if (curr_offset <= coord_offset && coord_offset <= next_offset) { - color = mix(colors_arr[i], colors_arr[i+1], smoothstep( - curr_offset, - next_offset, - coord_offset, - )); + // blend in OKLab + let factor = smoothstep(curr_offset, next_offset, coord_offset); + let lms_a = pow(colors_arr[i] * to_lms, vec3<f32>(1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0)); + let lms_b = pow(colors_arr[i+1] * to_lms, vec3<f32>(1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0)); + let mixed = mix(lms_a, lms_b, factor); + + // back to sRGB + color = to_rgb * (mixed * mixed * mixed); + color.a = mix(colors_arr[i].a, colors_arr[i+1].a, factor); } if (coord_offset >= offsets_arr[last_index]) { -- cgit From 10d0b257f929296b1991a440f62c87487c0076dc Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector0193@gmail.com> Date: Thu, 7 Sep 2023 07:24:32 +0200 Subject: Use Oklab color interpolation only with `color::GAMMA_CORRECTION` --- wgpu/src/quad/gradient.rs | 19 +- wgpu/src/quad/solid.rs | 6 +- wgpu/src/shader/color/linear_rgb.wgsl | 3 + wgpu/src/shader/color/oklab.wgsl | 26 +++ wgpu/src/shader/quad.wgsl | 322 --------------------------------- wgpu/src/shader/quad/gradient.wgsl | 205 +++++++++++++++++++++ wgpu/src/shader/quad/solid.wgsl | 99 ++++++++++ wgpu/src/shader/triangle.wgsl | 160 ---------------- wgpu/src/shader/triangle/gradient.wgsl | 134 ++++++++++++++ wgpu/src/shader/triangle/solid.wgsl | 24 +++ wgpu/src/triangle.rs | 35 +++- 11 files changed, 544 insertions(+), 489 deletions(-) create mode 100644 wgpu/src/shader/color/linear_rgb.wgsl create mode 100644 wgpu/src/shader/color/oklab.wgsl create mode 100644 wgpu/src/shader/quad/gradient.wgsl create mode 100644 wgpu/src/shader/quad/solid.wgsl create mode 100644 wgpu/src/shader/triangle/gradient.wgsl create mode 100644 wgpu/src/shader/triangle/solid.wgsl (limited to 'wgpu/src') diff --git a/wgpu/src/quad/gradient.rs b/wgpu/src/quad/gradient.rs index 6db37252..a8e83d01 100644 --- a/wgpu/src/quad/gradient.rs +++ b/wgpu/src/quad/gradient.rs @@ -1,3 +1,4 @@ +use crate::graphics::color; use crate::graphics::gradient; use crate::quad::{self, Quad}; use crate::Buffer; @@ -78,7 +79,23 @@ impl Pipeline { device.create_shader_module(wgpu::ShaderModuleDescriptor { label: Some("iced_wgpu.quad.gradient.shader"), source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed( - include_str!("../shader/quad.wgsl"), + if color::GAMMA_CORRECTION { + concat!( + include_str!("../shader/quad.wgsl"), + "\n", + include_str!("../shader/quad/gradient.wgsl"), + "\n", + include_str!("../shader/color/oklab.wgsl") + ) + } else { + concat!( + include_str!("../shader/quad.wgsl"), + "\n", + include_str!("../shader/quad/gradient.wgsl"), + "\n", + include_str!("../shader/color/linear_rgb.wgsl") + ) + }, )), }); diff --git a/wgpu/src/quad/solid.rs b/wgpu/src/quad/solid.rs index f8f1e3a5..9bc6b466 100644 --- a/wgpu/src/quad/solid.rs +++ b/wgpu/src/quad/solid.rs @@ -72,7 +72,11 @@ impl Pipeline { device.create_shader_module(wgpu::ShaderModuleDescriptor { label: Some("iced_wgpu.quad.solid.shader"), source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed( - include_str!("../shader/quad.wgsl"), + concat!( + include_str!("../shader/quad.wgsl"), + "\n", + include_str!("../shader/quad/solid.wgsl"), + ), )), }); diff --git a/wgpu/src/shader/color/linear_rgb.wgsl b/wgpu/src/shader/color/linear_rgb.wgsl new file mode 100644 index 00000000..a5cf45d4 --- /dev/null +++ b/wgpu/src/shader/color/linear_rgb.wgsl @@ -0,0 +1,3 @@ +fn interpolate_color(from_: vec4<f32>, to_: vec4<f32>, factor: f32) -> vec4<f32> { + return mix(from_, to_, factor); +} diff --git a/wgpu/src/shader/color/oklab.wgsl b/wgpu/src/shader/color/oklab.wgsl new file mode 100644 index 00000000..0dc37ba6 --- /dev/null +++ b/wgpu/src/shader/color/oklab.wgsl @@ -0,0 +1,26 @@ +const to_lms = mat3x4<f32>( + vec4<f32>(0.4121656120, 0.2118591070, 0.0883097947, 0.0), + vec4<f32>(0.5362752080, 0.6807189584, 0.2818474174, 0.0), + vec4<f32>(0.0514575653, 0.1074065790, 0.6302613616, 0.0), +); + +const to_rgb = mat3x4<f32>( + vec4<f32>( 4.0767245293, -3.3072168827, 0.2307590544, 0.0), + vec4<f32>(-1.2681437731, 2.6093323231, -0.3411344290, 0.0), + vec4<f32>(-0.0041119885, -0.7034763098, 1.7068625689, 0.0), +); + +fn interpolate_color(from_: vec4<f32>, to_: vec4<f32>, factor: f32) -> vec4<f32> { + // To Oklab + let lms_a = pow(from_ * to_lms, vec3<f32>(1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0)); + let lms_b = pow(to_ * to_lms, vec3<f32>(1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0)); + let mixed = mix(lms_a, lms_b, factor); + + // Back to linear RGB + var color = to_rgb * (mixed * mixed * mixed); + + // Alpha interpolation + color.a = mix(from_.a, to_.a, factor); + + return color; +} diff --git a/wgpu/src/shader/quad.wgsl b/wgpu/src/shader/quad.wgsl index cba7e5a4..f919cfe2 100644 --- a/wgpu/src/shader/quad.wgsl +++ b/wgpu/src/shader/quad.wgsl @@ -37,325 +37,3 @@ fn select_border_radius(radi: vec4<f32>, position: vec2<f32>, center: vec2<f32>) rx = select(rx, ry, position.y > center.y); return rx; } - -fn unpack_u32(color: vec2<u32>) -> vec4<f32> { - let rg: vec2<f32> = unpack2x16float(color.x); - let ba: vec2<f32> = unpack2x16float(color.y); - - return vec4<f32>(rg.y, rg.x, ba.y, ba.x); -} - -struct SolidVertexInput { - @location(0) v_pos: vec2<f32>, - @location(1) color: vec4<f32>, - @location(2) pos: vec2<f32>, - @location(3) scale: vec2<f32>, - @location(4) border_color: vec4<f32>, - @location(5) border_radius: vec4<f32>, - @location(6) border_width: f32, -} - -struct SolidVertexOutput { - @builtin(position) position: vec4<f32>, - @location(0) color: vec4<f32>, - @location(1) border_color: vec4<f32>, - @location(2) pos: vec2<f32>, - @location(3) scale: vec2<f32>, - @location(4) border_radius: vec4<f32>, - @location(5) border_width: f32, -} - -@vertex -fn solid_vs_main(input: SolidVertexInput) -> SolidVertexOutput { - var out: SolidVertexOutput; - - var pos: vec2<f32> = input.pos * globals.scale; - var scale: vec2<f32> = input.scale * globals.scale; - - var min_border_radius = min(input.scale.x, input.scale.y) * 0.5; - var border_radius: vec4<f32> = vec4<f32>( - min(input.border_radius.x, min_border_radius), - min(input.border_radius.y, min_border_radius), - min(input.border_radius.z, min_border_radius), - min(input.border_radius.w, min_border_radius) - ); - - var transform: mat4x4<f32> = mat4x4<f32>( - vec4<f32>(scale.x + 1.0, 0.0, 0.0, 0.0), - vec4<f32>(0.0, scale.y + 1.0, 0.0, 0.0), - vec4<f32>(0.0, 0.0, 1.0, 0.0), - vec4<f32>(pos - vec2<f32>(0.5, 0.5), 0.0, 1.0) - ); - - out.position = globals.transform * transform * vec4<f32>(input.v_pos, 0.0, 1.0); - out.color = input.color; - out.border_color = input.border_color; - out.pos = pos; - out.scale = scale; - out.border_radius = border_radius * globals.scale; - out.border_width = input.border_width * globals.scale; - - return out; -} - -@fragment -fn solid_fs_main( - input: SolidVertexOutput -) -> @location(0) vec4<f32> { - var mixed_color: vec4<f32> = input.color; - - var border_radius = select_border_radius( - input.border_radius, - input.position.xy, - (input.pos + input.scale * 0.5).xy - ); - - if (input.border_width > 0.0) { - var internal_border: f32 = max(border_radius - input.border_width, 0.0); - - var internal_distance: f32 = distance_alg( - input.position.xy, - input.pos + vec2<f32>(input.border_width, input.border_width), - input.scale - vec2<f32>(input.border_width * 2.0, input.border_width * 2.0), - internal_border - ); - - var border_mix: f32 = smoothstep( - max(internal_border - 0.5, 0.0), - internal_border + 0.5, - internal_distance - ); - - mixed_color = mix(input.color, input.border_color, vec4<f32>(border_mix, border_mix, border_mix, border_mix)); - } - - var dist: f32 = distance_alg( - vec2<f32>(input.position.x, input.position.y), - input.pos, - input.scale, - border_radius - ); - - var radius_alpha: f32 = 1.0 - smoothstep( - max(border_radius - 0.5, 0.0), - border_radius + 0.5, - dist - ); - - return vec4<f32>(mixed_color.x, mixed_color.y, mixed_color.z, mixed_color.w * radius_alpha); -} - -struct GradientVertexInput { - @location(0) v_pos: vec2<f32>, - @location(1) @interpolate(flat) colors_1: vec4<u32>, - @location(2) @interpolate(flat) colors_2: vec4<u32>, - @location(3) @interpolate(flat) colors_3: vec4<u32>, - @location(4) @interpolate(flat) colors_4: vec4<u32>, - @location(5) @interpolate(flat) offsets: vec4<u32>, - @location(6) direction: vec4<f32>, - @location(7) position_and_scale: vec4<f32>, - @location(8) border_color: vec4<f32>, - @location(9) border_radius: vec4<f32>, - @location(10) border_width: f32, -} - -struct GradientVertexOutput { - @builtin(position) position: vec4<f32>, - @location(1) @interpolate(flat) colors_1: vec4<u32>, - @location(2) @interpolate(flat) colors_2: vec4<u32>, - @location(3) @interpolate(flat) colors_3: vec4<u32>, - @location(4) @interpolate(flat) colors_4: vec4<u32>, - @location(5) @interpolate(flat) offsets: vec4<u32>, - @location(6) direction: vec4<f32>, - @location(7) position_and_scale: vec4<f32>, - @location(8) border_color: vec4<f32>, - @location(9) border_radius: vec4<f32>, - @location(10) border_width: f32, -} - -@vertex -fn gradient_vs_main(input: GradientVertexInput) -> GradientVertexOutput { - var out: GradientVertexOutput; - - var pos: vec2<f32> = input.position_and_scale.xy * globals.scale; - var scale: vec2<f32> = input.position_and_scale.zw * globals.scale; - - var min_border_radius = min(input.position_and_scale.z, input.position_and_scale.w) * 0.5; - var border_radius: vec4<f32> = vec4<f32>( - min(input.border_radius.x, min_border_radius), - min(input.border_radius.y, min_border_radius), - min(input.border_radius.z, min_border_radius), - min(input.border_radius.w, min_border_radius) - ); - - var transform: mat4x4<f32> = mat4x4<f32>( - vec4<f32>(scale.x + 1.0, 0.0, 0.0, 0.0), - vec4<f32>(0.0, scale.y + 1.0, 0.0, 0.0), - vec4<f32>(0.0, 0.0, 1.0, 0.0), - vec4<f32>(pos - vec2<f32>(0.5, 0.5), 0.0, 1.0) - ); - - out.position = globals.transform * transform * vec4<f32>(input.v_pos, 0.0, 1.0); - out.colors_1 = input.colors_1; - out.colors_2 = input.colors_2; - out.colors_3 = input.colors_3; - out.colors_4 = input.colors_4; - out.offsets = input.offsets; - out.direction = input.direction * globals.scale; - out.position_and_scale = vec4<f32>(pos, scale); - out.border_color = input.border_color; - out.border_radius = border_radius * globals.scale; - out.border_width = input.border_width * globals.scale; - - return out; -} - -fn random(coords: vec2<f32>) -> f32 { - return fract(sin(dot(coords, vec2(12.9898,78.233))) * 43758.5453); -} - -/// Returns the current interpolated color with a max 8-stop gradient -fn gradient( - raw_position: vec2<f32>, - direction: vec4<f32>, - colors: array<vec4<f32>, 8>, - offsets: array<f32, 8>, - last_index: i32 -) -> vec4<f32> { - let start = direction.xy; - let end = direction.zw; - - let v1 = end - start; - let v2 = raw_position - start; - let unit = normalize(v1); - let coord_offset = dot(unit, v2) / length(v1); - - let to_lms: mat3x4<f32> = mat3x4<f32>( - vec4<f32>(0.4121656120, 0.2118591070, 0.0883097947, 0.0), - vec4<f32>(0.5362752080, 0.6807189584, 0.2818474174, 0.0), - vec4<f32>(0.0514575653, 0.1074065790, 0.6302613616, 0.0), - ); - - let to_rgb: mat3x4<f32> = mat3x4<f32>( - vec4<f32>( 4.0767245293, -3.3072168827, 0.2307590544, 0.0), - vec4<f32>(-1.2681437731, 2.6093323231, -0.3411344290, 0.0), - vec4<f32>(-0.0041119885, -0.7034763098, 1.7068625689, 0.0), - ); - - //need to store these as a var to use dynamic indexing in a loop - //this is already added to wgsl spec but not in wgpu yet - var colors_arr = colors; - var offsets_arr = offsets; - - var color: vec4<f32>; - - let noise_granularity: f32 = 0.3/255.0; - - for (var i: i32 = 0; i < last_index; i++) { - let curr_offset = offsets_arr[i]; - let next_offset = offsets_arr[i+1]; - - if (coord_offset <= offsets_arr[0]) { - color = colors_arr[0]; - } - - if (curr_offset <= coord_offset && coord_offset <= next_offset) { - // blend in OKLab - let factor = smoothstep(curr_offset, next_offset, coord_offset); - let lms_a = pow(colors_arr[i] * to_lms, vec3<f32>(1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0)); - let lms_b = pow(colors_arr[i+1] * to_lms, vec3<f32>(1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0)); - let mixed = mix(lms_a, lms_b, factor); - - // back to sRGB - color = to_rgb * (mixed * mixed * mixed); - color.a = mix(colors_arr[i].a, colors_arr[i+1].a, factor); - } - - if (coord_offset >= offsets_arr[last_index]) { - color = colors_arr[last_index]; - } - } - - return color + mix(-noise_granularity, noise_granularity, random(raw_position)); -} - -@fragment -fn gradient_fs_main(input: GradientVertexOutput) -> @location(0) vec4<f32> { - let colors = array<vec4<f32>, 8>( - unpack_u32(input.colors_1.xy), - unpack_u32(input.colors_1.zw), - unpack_u32(input.colors_2.xy), - unpack_u32(input.colors_2.zw), - unpack_u32(input.colors_3.xy), - unpack_u32(input.colors_3.zw), - unpack_u32(input.colors_4.xy), - unpack_u32(input.colors_4.zw), - ); - - let offsets_1: vec4<f32> = unpack_u32(input.offsets.xy); - let offsets_2: vec4<f32> = unpack_u32(input.offsets.zw); - - var offsets = array<f32, 8>( - offsets_1.x, - offsets_1.y, - offsets_1.z, - offsets_1.w, - offsets_2.x, - offsets_2.y, - offsets_2.z, - offsets_2.w, - ); - - //TODO could just pass this in to the shader but is probably more performant to just check it here - var last_index = 7; - for (var i: i32 = 0; i <= 7; i++) { - if (offsets[i] > 1.0) { - last_index = i - 1; - break; - } - } - - var mixed_color: vec4<f32> = gradient(input.position.xy, input.direction, colors, offsets, last_index); - - let pos = input.position_and_scale.xy; - let scale = input.position_and_scale.zw; - - var border_radius = select_border_radius( - input.border_radius, - input.position.xy, - (pos + scale * 0.5).xy - ); - - if (input.border_width > 0.0) { - var internal_border: f32 = max(border_radius - input.border_width, 0.0); - - var internal_distance: f32 = distance_alg( - input.position.xy, - pos + vec2<f32>(input.border_width, input.border_width), - scale - vec2<f32>(input.border_width * 2.0, input.border_width * 2.0), - internal_border - ); - - var border_mix: f32 = smoothstep( - max(internal_border - 0.5, 0.0), - internal_border + 0.5, - internal_distance - ); - - mixed_color = mix(mixed_color, input.border_color, vec4<f32>(border_mix, border_mix, border_mix, border_mix)); - } - - var dist: f32 = distance_alg( - input.position.xy, - pos, - scale, - border_radius - ); - - var radius_alpha: f32 = 1.0 - smoothstep( - max(border_radius - 0.5, 0.0), - border_radius + 0.5, - dist); - - return vec4<f32>(mixed_color.x, mixed_color.y, mixed_color.z, mixed_color.w * radius_alpha); -} diff --git a/wgpu/src/shader/quad/gradient.wgsl b/wgpu/src/shader/quad/gradient.wgsl new file mode 100644 index 00000000..0754e97f --- /dev/null +++ b/wgpu/src/shader/quad/gradient.wgsl @@ -0,0 +1,205 @@ +struct GradientVertexInput { + @location(0) v_pos: vec2<f32>, + @location(1) @interpolate(flat) colors_1: vec4<u32>, + @location(2) @interpolate(flat) colors_2: vec4<u32>, + @location(3) @interpolate(flat) colors_3: vec4<u32>, + @location(4) @interpolate(flat) colors_4: vec4<u32>, + @location(5) @interpolate(flat) offsets: vec4<u32>, + @location(6) direction: vec4<f32>, + @location(7) position_and_scale: vec4<f32>, + @location(8) border_color: vec4<f32>, + @location(9) border_radius: vec4<f32>, + @location(10) border_width: f32, +} + +struct GradientVertexOutput { + @builtin(position) position: vec4<f32>, + @location(1) @interpolate(flat) colors_1: vec4<u32>, + @location(2) @interpolate(flat) colors_2: vec4<u32>, + @location(3) @interpolate(flat) colors_3: vec4<u32>, + @location(4) @interpolate(flat) colors_4: vec4<u32>, + @location(5) @interpolate(flat) offsets: vec4<u32>, + @location(6) direction: vec4<f32>, + @location(7) position_and_scale: vec4<f32>, + @location(8) border_color: vec4<f32>, + @location(9) border_radius: vec4<f32>, + @location(10) border_width: f32, +} + +@vertex +fn gradient_vs_main(input: GradientVertexInput) -> GradientVertexOutput { + var out: GradientVertexOutput; + + var pos: vec2<f32> = input.position_and_scale.xy * globals.scale; + var scale: vec2<f32> = input.position_and_scale.zw * globals.scale; + + var min_border_radius = min(input.position_and_scale.z, input.position_and_scale.w) * 0.5; + var border_radius: vec4<f32> = vec4<f32>( + min(input.border_radius.x, min_border_radius), + min(input.border_radius.y, min_border_radius), + min(input.border_radius.z, min_border_radius), + min(input.border_radius.w, min_border_radius) + ); + + var transform: mat4x4<f32> = mat4x4<f32>( + vec4<f32>(scale.x + 1.0, 0.0, 0.0, 0.0), + vec4<f32>(0.0, scale.y + 1.0, 0.0, 0.0), + vec4<f32>(0.0, 0.0, 1.0, 0.0), + vec4<f32>(pos - vec2<f32>(0.5, 0.5), 0.0, 1.0) + ); + + out.position = globals.transform * transform * vec4<f32>(input.v_pos, 0.0, 1.0); + out.colors_1 = input.colors_1; + out.colors_2 = input.colors_2; + out.colors_3 = input.colors_3; + out.colors_4 = input.colors_4; + out.offsets = input.offsets; + out.direction = input.direction * globals.scale; + out.position_and_scale = vec4<f32>(pos, scale); + out.border_color = input.border_color; + out.border_radius = border_radius * globals.scale; + out.border_width = input.border_width * globals.scale; + + return out; +} + +fn random(coords: vec2<f32>) -> f32 { + return fract(sin(dot(coords, vec2(12.9898,78.233))) * 43758.5453); +} + +/// Returns the current interpolated color with a max 8-stop gradient +fn gradient( + raw_position: vec2<f32>, + direction: vec4<f32>, + colors: array<vec4<f32>, 8>, + offsets: array<f32, 8>, + last_index: i32 +) -> vec4<f32> { + let start = direction.xy; + let end = direction.zw; + + let v1 = end - start; + let v2 = raw_position - start; + let unit = normalize(v1); + let coord_offset = dot(unit, v2) / length(v1); + + //need to store these as a var to use dynamic indexing in a loop + //this is already added to wgsl spec but not in wgpu yet + var colors_arr = colors; + var offsets_arr = offsets; + + var color: vec4<f32>; + + let noise_granularity: f32 = 0.3/255.0; + + for (var i: i32 = 0; i < last_index; i++) { + let curr_offset = offsets_arr[i]; + let next_offset = offsets_arr[i+1]; + + if (coord_offset <= offsets_arr[0]) { + color = colors_arr[0]; + } + + if (curr_offset <= coord_offset && coord_offset <= next_offset) { + let from_ = colors_arr[i]; + let to_ = colors_arr[i+1]; + let factor = smoothstep(curr_offset, next_offset, coord_offset); + + color = interpolate_color(from_, to_, factor); + } + + if (coord_offset >= offsets_arr[last_index]) { + color = colors_arr[last_index]; + } + } + + return color + mix(-noise_granularity, noise_granularity, random(raw_position)); +} + +@fragment +fn gradient_fs_main(input: GradientVertexOutput) -> @location(0) vec4<f32> { + let colors = array<vec4<f32>, 8>( + unpack_u32(input.colors_1.xy), + unpack_u32(input.colors_1.zw), + unpack_u32(input.colors_2.xy), + unpack_u32(input.colors_2.zw), + unpack_u32(input.colors_3.xy), + unpack_u32(input.colors_3.zw), + unpack_u32(input.colors_4.xy), + unpack_u32(input.colors_4.zw), + ); + + let offsets_1: vec4<f32> = unpack_u32(input.offsets.xy); + let offsets_2: vec4<f32> = unpack_u32(input.offsets.zw); + + var offsets = array<f32, 8>( + offsets_1.x, + offsets_1.y, + offsets_1.z, + offsets_1.w, + offsets_2.x, + offsets_2.y, + offsets_2.z, + offsets_2.w, + ); + + //TODO could just pass this in to the shader but is probably more performant to just check it here + var last_index = 7; + for (var i: i32 = 0; i <= 7; i++) { + if (offsets[i] > 1.0) { + last_index = i - 1; + break; + } + } + + var mixed_color: vec4<f32> = gradient(input.position.xy, input.direction, colors, offsets, last_index); + + let pos = input.position_and_scale.xy; + let scale = input.position_and_scale.zw; + + var border_radius = select_border_radius( + input.border_radius, + input.position.xy, + (pos + scale * 0.5).xy + ); + + if (input.border_width > 0.0) { + var internal_border: f32 = max(border_radius - input.border_width, 0.0); + + var internal_distance: f32 = distance_alg( + input.position.xy, + pos + vec2<f32>(input.border_width, input.border_width), + scale - vec2<f32>(input.border_width * 2.0, input.border_width * 2.0), + internal_border + ); + + var border_mix: f32 = smoothstep( + max(internal_border - 0.5, 0.0), + internal_border + 0.5, + internal_distance + ); + + mixed_color = mix(mixed_color, input.border_color, vec4<f32>(border_mix, border_mix, border_mix, border_mix)); + } + + var dist: f32 = distance_alg( + input.position.xy, + pos, + scale, + border_radius + ); + + var radius_alpha: f32 = 1.0 - smoothstep( + max(border_radius - 0.5, 0.0), + border_radius + 0.5, + dist); + + return vec4<f32>(mixed_color.x, mixed_color.y, mixed_color.z, mixed_color.w * radius_alpha); +} + +fn unpack_u32(color: vec2<u32>) -> vec4<f32> { + let rg: vec2<f32> = unpack2x16float(color.x); + let ba: vec2<f32> = unpack2x16float(color.y); + + return vec4<f32>(rg.y, rg.x, ba.y, ba.x); +} diff --git a/wgpu/src/shader/quad/solid.wgsl b/wgpu/src/shader/quad/solid.wgsl new file mode 100644 index 00000000..ebd6d877 --- /dev/null +++ b/wgpu/src/shader/quad/solid.wgsl @@ -0,0 +1,99 @@ +struct SolidVertexInput { + @location(0) v_pos: vec2<f32>, + @location(1) color: vec4<f32>, + @location(2) pos: vec2<f32>, + @location(3) scale: vec2<f32>, + @location(4) border_color: vec4<f32>, + @location(5) border_radius: vec4<f32>, + @location(6) border_width: f32, +} + +struct SolidVertexOutput { + @builtin(position) position: vec4<f32>, + @location(0) color: vec4<f32>, + @location(1) border_color: vec4<f32>, + @location(2) pos: vec2<f32>, + @location(3) scale: vec2<f32>, + @location(4) border_radius: vec4<f32>, + @location(5) border_width: f32, +} + +@vertex +fn solid_vs_main(input: SolidVertexInput) -> SolidVertexOutput { + var out: SolidVertexOutput; + + var pos: vec2<f32> = input.pos * globals.scale; + var scale: vec2<f32> = input.scale * globals.scale; + + var min_border_radius = min(input.scale.x, input.scale.y) * 0.5; + var border_radius: vec4<f32> = vec4<f32>( + min(input.border_radius.x, min_border_radius), + min(input.border_radius.y, min_border_radius), + min(input.border_radius.z, min_border_radius), + min(input.border_radius.w, min_border_radius) + ); + + var transform: mat4x4<f32> = mat4x4<f32>( + vec4<f32>(scale.x + 1.0, 0.0, 0.0, 0.0), + vec4<f32>(0.0, scale.y + 1.0, 0.0, 0.0), + vec4<f32>(0.0, 0.0, 1.0, 0.0), + vec4<f32>(pos - vec2<f32>(0.5, 0.5), 0.0, 1.0) + ); + + out.position = globals.transform * transform * vec4<f32>(input.v_pos, 0.0, 1.0); + out.color = input.color; + out.border_color = input.border_color; + out.pos = pos; + out.scale = scale; + out.border_radius = border_radius * globals.scale; + out.border_width = input.border_width * globals.scale; + + return out; +} + +@fragment +fn solid_fs_main( + input: SolidVertexOutput +) -> @location(0) vec4<f32> { + var mixed_color: vec4<f32> = input.color; + + var border_radius = select_border_radius( + input.border_radius, + input.position.xy, + (input.pos + input.scale * 0.5).xy + ); + + if (input.border_width > 0.0) { + var internal_border: f32 = max(border_radius - input.border_width, 0.0); + + var internal_distance: f32 = distance_alg( + input.position.xy, + input.pos + vec2<f32>(input.border_width, input.border_width), + input.scale - vec2<f32>(input.border_width * 2.0, input.border_width * 2.0), + internal_border + ); + + var border_mix: f32 = smoothstep( + max(internal_border - 0.5, 0.0), + internal_border + 0.5, + internal_distance + ); + + mixed_color = mix(input.color, input.border_color, vec4<f32>(border_mix, border_mix, border_mix, border_mix)); + } + + var dist: f32 = distance_alg( + vec2<f32>(input.position.x, input.position.y), + input.pos, + input.scale, + border_radius + ); + + var radius_alpha: f32 = 1.0 - smoothstep( + max(border_radius - 0.5, 0.0), + border_radius + 0.5, + dist + ); + + return vec4<f32>(mixed_color.x, mixed_color.y, mixed_color.z, mixed_color.w * radius_alpha); +} diff --git a/wgpu/src/shader/triangle.wgsl b/wgpu/src/shader/triangle.wgsl index 3a2b9845..e4c19344 100644 --- a/wgpu/src/shader/triangle.wgsl +++ b/wgpu/src/shader/triangle.wgsl @@ -3,163 +3,3 @@ struct Globals { } @group(0) @binding(0) var<uniform> globals: Globals; - -fn unpack_u32(color: vec2<u32>) -> vec4<f32> { - let rg: vec2<f32> = unpack2x16float(color.x); - let ba: vec2<f32> = unpack2x16float(color.y); - - return vec4<f32>(rg.y, rg.x, ba.y, ba.x); -} - -struct SolidVertexInput { - @location(0) position: vec2<f32>, - @location(1) color: vec4<f32>, -} - -struct SolidVertexOutput { - @builtin(position) position: vec4<f32>, - @location(0) color: vec4<f32>, -} - -@vertex -fn solid_vs_main(input: SolidVertexInput) -> SolidVertexOutput { - var out: SolidVertexOutput; - - out.color = input.color; - out.position = globals.transform * vec4<f32>(input.position, 0.0, 1.0); - - return out; -} - -@fragment -fn solid_fs_main(input: SolidVertexOutput) -> @location(0) vec4<f32> { - return input.color; -} - -struct GradientVertexInput { - @location(0) v_pos: vec2<f32>, - @location(1) @interpolate(flat) colors_1: vec4<u32>, - @location(2) @interpolate(flat) colors_2: vec4<u32>, - @location(3) @interpolate(flat) colors_3: vec4<u32>, - @location(4) @interpolate(flat) colors_4: vec4<u32>, - @location(5) @interpolate(flat) offsets: vec4<u32>, - @location(6) direction: vec4<f32>, -} - -struct GradientVertexOutput { - @builtin(position) position: vec4<f32>, - @location(0) raw_position: vec2<f32>, - @location(1) @interpolate(flat) colors_1: vec4<u32>, - @location(2) @interpolate(flat) colors_2: vec4<u32>, - @location(3) @interpolate(flat) colors_3: vec4<u32>, - @location(4) @interpolate(flat) colors_4: vec4<u32>, - @location(5) @interpolate(flat) offsets: vec4<u32>, - @location(6) direction: vec4<f32>, -} - -@vertex -fn gradient_vs_main(input: GradientVertexInput) -> GradientVertexOutput { - var output: GradientVertexOutput; - - output.position = globals.transform * vec4<f32>(input.v_pos, 0.0, 1.0); - output.raw_position = input.v_pos; - output.colors_1 = input.colors_1; - output.colors_2 = input.colors_2; - output.colors_3 = input.colors_3; - output.colors_4 = input.colors_4; - output.offsets = input.offsets; - output.direction = input.direction; - - return output; -} - -fn random(coords: vec2<f32>) -> f32 { - return fract(sin(dot(coords, vec2(12.9898,78.233))) * 43758.5453); -} - -/// Returns the current interpolated color with a max 8-stop gradient -fn gradient( - raw_position: vec2<f32>, - direction: vec4<f32>, - colors: array<vec4<f32>, 8>, - offsets: array<f32, 8>, - last_index: i32 -) -> vec4<f32> { - let start = direction.xy; - let end = direction.zw; - - let v1 = end - start; - let v2 = raw_position - start; - let unit = normalize(v1); - let coord_offset = dot(unit, v2) / length(v1); - - //need to store these as a var to use dynamic indexing in a loop - //this is already added to wgsl spec but not in wgpu yet - var colors_arr = colors; - var offsets_arr = offsets; - - var color: vec4<f32>; - - let noise_granularity: f32 = 0.3/255.0; - - for (var i: i32 = 0; i < last_index; i++) { - let curr_offset = offsets_arr[i]; - let next_offset = offsets_arr[i+1]; - - if (coord_offset <= offsets_arr[0]) { - color = colors_arr[0]; - } - - if (curr_offset <= coord_offset && coord_offset <= next_offset) { - color = mix(colors_arr[i], colors_arr[i+1], smoothstep( - curr_offset, - next_offset, - coord_offset, - )); - } - - if (coord_offset >= offsets_arr[last_index]) { - color = colors_arr[last_index]; - } - } - - return color + mix(-noise_granularity, noise_granularity, random(raw_position)); -} - -@fragment -fn gradient_fs_main(input: GradientVertexOutput) -> @location(0) vec4<f32> { - let colors = array<vec4<f32>, 8>( - unpack_u32(input.colors_1.xy), - unpack_u32(input.colors_1.zw), - unpack_u32(input.colors_2.xy), - unpack_u32(input.colors_2.zw), - unpack_u32(input.colors_3.xy), - unpack_u32(input.colors_3.zw), - unpack_u32(input.colors_4.xy), - unpack_u32(input.colors_4.zw), - ); - - let offsets_1: vec4<f32> = unpack_u32(input.offsets.xy); - let offsets_2: vec4<f32> = unpack_u32(input.offsets.zw); - - var offsets = array<f32, 8>( - offsets_1.x, - offsets_1.y, - offsets_1.z, - offsets_1.w, - offsets_2.x, - offsets_2.y, - offsets_2.z, - offsets_2.w, - ); - - var last_index = 7; - for (var i: i32 = 0; i <= 7; i++) { - if (offsets[i] >= 1.0) { - last_index = i; - break; - } - } - - return gradient(input.raw_position, input.direction, colors, offsets, last_index); -} diff --git a/wgpu/src/shader/triangle/gradient.wgsl b/wgpu/src/shader/triangle/gradient.wgsl new file mode 100644 index 00000000..1a8ae3b5 --- /dev/null +++ b/wgpu/src/shader/triangle/gradient.wgsl @@ -0,0 +1,134 @@ +struct GradientVertexInput { + @location(0) v_pos: vec2<f32>, + @location(1) @interpolate(flat) colors_1: vec4<u32>, + @location(2) @interpolate(flat) colors_2: vec4<u32>, + @location(3) @interpolate(flat) colors_3: vec4<u32>, + @location(4) @interpolate(flat) colors_4: vec4<u32>, + @location(5) @interpolate(flat) offsets: vec4<u32>, + @location(6) direction: vec4<f32>, +} + +struct GradientVertexOutput { + @builtin(position) position: vec4<f32>, + @location(0) raw_position: vec2<f32>, + @location(1) @interpolate(flat) colors_1: vec4<u32>, + @location(2) @interpolate(flat) colors_2: vec4<u32>, + @location(3) @interpolate(flat) colors_3: vec4<u32>, + @location(4) @interpolate(flat) colors_4: vec4<u32>, + @location(5) @interpolate(flat) offsets: vec4<u32>, + @location(6) direction: vec4<f32>, +} + +@vertex +fn gradient_vs_main(input: GradientVertexInput) -> GradientVertexOutput { + var output: GradientVertexOutput; + + output.position = globals.transform * vec4<f32>(input.v_pos, 0.0, 1.0); + output.raw_position = input.v_pos; + output.colors_1 = input.colors_1; + output.colors_2 = input.colors_2; + output.colors_3 = input.colors_3; + output.colors_4 = input.colors_4; + output.offsets = input.offsets; + output.direction = input.direction; + + return output; +} + +/// Returns the current interpolated color with a max 8-stop gradient +fn gradient( + raw_position: vec2<f32>, + direction: vec4<f32>, + colors: array<vec4<f32>, 8>, + offsets: array<f32, 8>, + last_index: i32 +) -> vec4<f32> { + let start = direction.xy; + let end = direction.zw; + + let v1 = end - start; + let v2 = raw_position - start; + let unit = normalize(v1); + let coord_offset = dot(unit, v2) / length(v1); + + //need to store these as a var to use dynamic indexing in a loop + //this is already added to wgsl spec but not in wgpu yet + var colors_arr = colors; + var offsets_arr = offsets; + + var color: vec4<f32>; + + let noise_granularity: f32 = 0.3/255.0; + + for (var i: i32 = 0; i < last_index; i++) { + let curr_offset = offsets_arr[i]; + let next_offset = offsets_arr[i+1]; + + if (coord_offset <= offsets_arr[0]) { + color = colors_arr[0]; + } + + if (curr_offset <= coord_offset && coord_offset <= next_offset) { + let from_ = colors_arr[i]; + let to_ = colors_arr[i+1]; + let factor = smoothstep(curr_offset, next_offset, coord_offset); + + color = interpolate_color(from_, to_, factor); + } + + if (coord_offset >= offsets_arr[last_index]) { + color = colors_arr[last_index]; + } + } + + return color + mix(-noise_granularity, noise_granularity, random(raw_position)); +} + +@fragment +fn gradient_fs_main(input: GradientVertexOutput) -> @location(0) vec4<f32> { + let colors = array<vec4<f32>, 8>( + unpack_u32(input.colors_1.xy), + unpack_u32(input.colors_1.zw), + unpack_u32(input.colors_2.xy), + unpack_u32(input.colors_2.zw), + unpack_u32(input.colors_3.xy), + unpack_u32(input.colors_3.zw), + unpack_u32(input.colors_4.xy), + unpack_u32(input.colors_4.zw), + ); + + let offsets_1: vec4<f32> = unpack_u32(input.offsets.xy); + let offsets_2: vec4<f32> = unpack_u32(input.offsets.zw); + + var offsets = array<f32, 8>( + offsets_1.x, + offsets_1.y, + offsets_1.z, + offsets_1.w, + offsets_2.x, + offsets_2.y, + offsets_2.z, + offsets_2.w, + ); + + var last_index = 7; + for (var i: i32 = 0; i <= 7; i++) { + if (offsets[i] >= 1.0) { + last_index = i; + break; + } + } + + return gradient(input.raw_position, input.direction, colors, offsets, last_index); +} + +fn unpack_u32(color: vec2<u32>) -> vec4<f32> { + let rg: vec2<f32> = unpack2x16float(color.x); + let ba: vec2<f32> = unpack2x16float(color.y); + + return vec4<f32>(rg.y, rg.x, ba.y, ba.x); +} + +fn random(coords: vec2<f32>) -> f32 { + return fract(sin(dot(coords, vec2(12.9898,78.233))) * 43758.5453); +} diff --git a/wgpu/src/shader/triangle/solid.wgsl b/wgpu/src/shader/triangle/solid.wgsl new file mode 100644 index 00000000..9ef81982 --- /dev/null +++ b/wgpu/src/shader/triangle/solid.wgsl @@ -0,0 +1,24 @@ +struct SolidVertexInput { + @location(0) position: vec2<f32>, + @location(1) color: vec4<f32>, +} + +struct SolidVertexOutput { + @builtin(position) position: vec4<f32>, + @location(0) color: vec4<f32>, +} + +@vertex +fn solid_vs_main(input: SolidVertexInput) -> SolidVertexOutput { + var out: SolidVertexOutput; + + out.color = input.color; + out.position = globals.transform * vec4<f32>(input.position, 0.0, 1.0); + + return out; +} + +@fragment +fn solid_fs_main(input: SolidVertexOutput) -> @location(0) vec4<f32> { + return input.color; +} diff --git a/wgpu/src/triangle.rs b/wgpu/src/triangle.rs index d8b23dfe..d430e607 100644 --- a/wgpu/src/triangle.rs +++ b/wgpu/src/triangle.rs @@ -487,8 +487,10 @@ mod solid { device.create_shader_module(wgpu::ShaderModuleDescriptor { label: Some("iced_wgpu.triangle.solid.shader"), source: wgpu::ShaderSource::Wgsl( - std::borrow::Cow::Borrowed(include_str!( - "shader/triangle.wgsl" + std::borrow::Cow::Borrowed(concat!( + include_str!("shader/triangle.wgsl"), + "\n", + include_str!("shader/triangle/solid.wgsl"), )), ), }); @@ -537,6 +539,7 @@ mod solid { } mod gradient { + use crate::graphics::color; use crate::graphics::mesh; use crate::graphics::Antialiasing; use crate::triangle; @@ -633,9 +636,31 @@ mod gradient { device.create_shader_module(wgpu::ShaderModuleDescriptor { label: Some("iced_wgpu.triangle.gradient.shader"), source: wgpu::ShaderSource::Wgsl( - std::borrow::Cow::Borrowed(include_str!( - "shader/triangle.wgsl" - )), + std::borrow::Cow::Borrowed( + if color::GAMMA_CORRECTION { + concat!( + include_str!("shader/triangle.wgsl"), + "\n", + include_str!( + "shader/triangle/gradient.wgsl" + ), + "\n", + include_str!("shader/color/oklab.wgsl") + ) + } else { + concat!( + include_str!("shader/triangle.wgsl"), + "\n", + include_str!( + "shader/triangle/gradient.wgsl" + ), + "\n", + include_str!( + "shader/color/linear_rgb.wgsl" + ) + ) + }, + ), ), }); -- cgit From 3450987355be7fe029db112474d06613929b54c7 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector0193@gmail.com> Date: Sat, 9 Sep 2023 11:21:32 +0200 Subject: Invalidate existing paragraphs when new fonts are loaded --- wgpu/src/text.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs index a1ec511b..bd4f3e06 100644 --- a/wgpu/src/text.rs +++ b/wgpu/src/text.rs @@ -7,7 +7,6 @@ use crate::layer::Text; use std::borrow::Cow; use std::cell::RefCell; -use std::sync::Arc; #[allow(missing_debug_implementations)] pub struct Pipeline { @@ -47,9 +46,7 @@ impl Pipeline { } pub fn load_font(&mut self, bytes: Cow<'static, [u8]>) { - let _ = self.font_system.get_mut().db_mut().load_font_source( - glyphon::fontdb::Source::Binary(Arc::new(bytes.into_owned())), - ); + self.font_system.load_font(bytes); self.cache = RefCell::new(Cache::new()); } -- cgit From 89d9f1d7d2202029028a487df1dd11b0665a7517 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang <matthias.vogelgesang@gmail.com> Date: Sat, 9 Sep 2023 12:24:47 +0200 Subject: Fix majority of unresolved documentation links --- wgpu/src/geometry.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/geometry.rs b/wgpu/src/geometry.rs index c3e16f8c..63a59c05 100644 --- a/wgpu/src/geometry.rs +++ b/wgpu/src/geometry.rs @@ -310,13 +310,11 @@ impl Frame { /// resulting glyphs will not be rotated or scaled properly. /// /// Additionally, all text will be rendered on top of all the layers of - /// a [`Canvas`]. Therefore, it is currently only meant to be used for + /// a `Canvas`. Therefore, it is currently only meant to be used for /// overlays, which is the most common use case. /// /// Support for vectorial text is planned, and should address all these /// limitations. - /// - /// [`Canvas`]: crate::widget::Canvas pub fn fill_text(&mut self, text: impl Into<Text>) { let text = text.into(); -- cgit From f60884f6f8639f75258c264bf4a15591351ef05b Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Sat, 9 Sep 2023 20:58:45 +0200 Subject: Deny `broken_intradoc_links` and verify documentation in CI --- wgpu/src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index d1e4b7af..b9f54560 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -20,6 +20,7 @@ #![doc( html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg" )] +#![forbid(rust_2018_idioms)] #![deny( missing_debug_implementations, missing_docs, @@ -29,9 +30,9 @@ clippy::from_over_into, clippy::needless_borrow, clippy::new_without_default, - clippy::useless_conversion + clippy::useless_conversion, + rustdoc::broken_intra_doc_links )] -#![forbid(rust_2018_idioms)] #![allow(clippy::inherent_to_string, clippy::type_complexity)] #![cfg_attr(docsrs, feature(doc_auto_cfg))] pub mod layer; -- 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/src') 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/src') 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/src') 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 3d6b9637c3b1c9f3c654a3ecef7a247cfd6edef3 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan <YuriAstrakhan@gmail.com> Date: Tue, 19 Sep 2023 01:31:10 -0400 Subject: Chore: Inline format args for ease of reading A minor cleanup to inline all simple cases of format arguments. Makes the format strings just a bit easier to read. --- wgpu/src/image/atlas.rs | 8 ++++---- wgpu/src/image/vector.rs | 2 +- wgpu/src/window/compositor.rs | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/image/atlas.rs b/wgpu/src/image/atlas.rs index e3de1290..1253496b 100644 --- a/wgpu/src/image/atlas.rs +++ b/wgpu/src/image/atlas.rs @@ -86,7 +86,7 @@ impl Atlas { entry }; - log::info!("Allocated atlas entry: {:?}", entry); + log::info!("Allocated atlas entry: {entry:?}"); // It is a webgpu requirement that: // BufferCopyView.layout.bytes_per_row % wgpu::COPY_BYTES_PER_ROW_ALIGNMENT == 0 @@ -139,13 +139,13 @@ impl Atlas { } } - log::info!("Current atlas: {:?}", self); + log::info!("Current atlas: {self:?}"); Some(entry) } pub fn remove(&mut self, entry: &Entry) { - log::info!("Removing atlas entry: {:?}", entry); + log::info!("Removing atlas entry: {entry:?}"); match entry { Entry::Contiguous(allocation) => { @@ -258,7 +258,7 @@ impl Atlas { } fn deallocate(&mut self, allocation: &Allocation) { - log::info!("Deallocating atlas: {:?}", allocation); + log::info!("Deallocating atlas: {allocation:?}"); match allocation { Allocation::Full { layer } => { diff --git a/wgpu/src/image/vector.rs b/wgpu/src/image/vector.rs index 2c03d36b..6582bb82 100644 --- a/wgpu/src/image/vector.rs +++ b/wgpu/src/image/vector.rs @@ -152,7 +152,7 @@ impl Cache { let allocation = atlas.upload(device, encoder, width, height, &rgba)?; - log::debug!("allocating {} {}x{}", id, width, height); + log::debug!("allocating {id} {width}x{height}"); let _ = self.svg_hits.insert(id); let _ = self.rasterized_hits.insert(key); diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index a9521a15..1ddbe5fe 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -35,7 +35,7 @@ impl<Theme> Compositor<Theme> { ..Default::default() }); - log::info!("{:#?}", settings); + log::info!("{settings:#?}"); #[cfg(not(target_arch = "wasm32"))] if log::max_level() >= log::LevelFilter::Info { @@ -43,7 +43,7 @@ impl<Theme> Compositor<Theme> { .enumerate_adapters(settings.internal_backend) .map(|adapter| adapter.get_info()) .collect(); - log::info!("Available adapters: {:#?}", available_adapters); + log::info!("Available adapters: {available_adapters:#?}"); } #[allow(unsafe_code)] @@ -83,7 +83,7 @@ impl<Theme> Compositor<Theme> { }) })?; - log::info!("Selected format: {:?}", format); + log::info!("Selected format: {format:?}"); #[cfg(target_arch = "wasm32")] let limits = [wgpu::Limits::downlevel_webgl2_defaults() -- cgit From c997aad85d7ee6e77085e50e5e599002549d228f Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan <YuriAstrakhan@gmail.com> Date: Tue, 19 Sep 2023 01:46:46 -0400 Subject: Chore: Apply clippy map transformations Convert `.map().unwrap_or()` to `.map_or()` and similar transformations. --- wgpu/src/image/vector.rs | 2 +- wgpu/src/triangle.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/image/vector.rs b/wgpu/src/image/vector.rs index 2c03d36b..1ac82bc7 100644 --- a/wgpu/src/image/vector.rs +++ b/wgpu/src/image/vector.rs @@ -56,7 +56,7 @@ impl Cache { .ok() }); - tree.map(Svg::Loaded).unwrap_or(Svg::NotFound) + tree.map_or(Svg::NotFound, Svg::Loaded) } svg::Data::Bytes(bytes) => { match usvg::Tree::from_data(bytes, &usvg::Options::default()) { diff --git a/wgpu/src/triangle.rs b/wgpu/src/triangle.rs index d430e607..7e1bd9cc 100644 --- a/wgpu/src/triangle.rs +++ b/wgpu/src/triangle.rs @@ -349,7 +349,7 @@ fn multisample_state( antialiasing: Option<Antialiasing>, ) -> wgpu::MultisampleState { wgpu::MultisampleState { - count: antialiasing.map(|a| a.sample_count()).unwrap_or(1), + count: antialiasing.map_or(1, Antialiasing::sample_count), mask: !0, alpha_to_coverage_enabled: false, } -- 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/src') 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 34f07b60273d6cfe13834af54cd0e24d34569387 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Wed, 20 Sep 2023 04:11:52 +0200 Subject: Fix `clippy::semicolon_if_nothing_returned` --- wgpu/src/buffer.rs | 2 +- wgpu/src/geometry.rs | 4 ++-- wgpu/src/image/atlas.rs | 2 +- wgpu/src/layer.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/buffer.rs b/wgpu/src/buffer.rs index 94122187..ef00c58f 100644 --- a/wgpu/src/buffer.rs +++ b/wgpu/src/buffer.rs @@ -87,7 +87,7 @@ impl<T: bytemuck::Pod> Buffer<T> { /// Clears any temporary data (i.e. offsets) from the buffer. pub fn clear(&mut self) { - self.offsets.clear() + self.offsets.clear(); } /// Returns the offset at `index`, if it exists. diff --git a/wgpu/src/geometry.rs b/wgpu/src/geometry.rs index 63a59c05..655362b7 100644 --- a/wgpu/src/geometry.rs +++ b/wgpu/src/geometry.rs @@ -480,7 +480,7 @@ impl Frame { }, size: self.size, }), - )) + )); } } Buffer::Gradient(buffer) => { @@ -493,7 +493,7 @@ impl Frame { }, size: self.size, }), - )) + )); } } } diff --git a/wgpu/src/image/atlas.rs b/wgpu/src/image/atlas.rs index 1253496b..e8ca4bd3 100644 --- a/wgpu/src/image/atlas.rs +++ b/wgpu/src/image/atlas.rs @@ -104,7 +104,7 @@ impl Atlas { padded_data[offset..offset + 4 * width as usize].copy_from_slice( &data[row * 4 * width as usize..(row + 1) * 4 * width as usize], - ) + ); } match &entry { diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs index 7a5a0f7c..d20dbe66 100644 --- a/wgpu/src/layer.rs +++ b/wgpu/src/layer.rs @@ -202,7 +202,7 @@ impl<'a> Layer<'a> { translation, primitive, current_layer, - ) + ); } } Primitive::Clip { bounds, content } => { -- cgit From 42ed90bc6f92b2085d193e7f143430b8d3847c21 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Wed, 20 Sep 2023 04:51:08 +0200 Subject: Fix `clippy::default_trait_access` --- wgpu/src/color.rs | 6 +++--- wgpu/src/text.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/color.rs b/wgpu/src/color.rs index a1025601..20827e3c 100644 --- a/wgpu/src/color.rs +++ b/wgpu/src/color.rs @@ -12,7 +12,7 @@ pub fn convert( let sampler = device.create_sampler(&wgpu::SamplerDescriptor { label: Some("iced_wgpu.offscreen.sampler"), - ..Default::default() + ..wgpu::SamplerDescriptor::default() }); //sampler in 0 @@ -102,10 +102,10 @@ pub fn convert( primitive: wgpu::PrimitiveState { topology: wgpu::PrimitiveTopology::TriangleList, front_face: wgpu::FrontFace::Cw, - ..Default::default() + ..wgpu::PrimitiveState::default() }, depth_stencil: None, - multisample: Default::default(), + multisample: wgpu::MultisampleState::default(), multiview: None, }); diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs index bd4f3e06..2a530cad 100644 --- a/wgpu/src/text.rs +++ b/wgpu/src/text.rs @@ -64,7 +64,7 @@ impl Pipeline { self.renderers.push(glyphon::TextRenderer::new( &mut self.atlas, device, - Default::default(), + wgpu::MultisampleState::default(), None, )); } -- cgit From caed50b277495e4375975f3f4e271b8fcbc0c33f Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Wed, 20 Sep 2023 05:03:25 +0200 Subject: Fix `clippy::match-wildcard-for-single-variants` --- wgpu/src/image/atlas.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'wgpu/src') diff --git a/wgpu/src/image/atlas.rs b/wgpu/src/image/atlas.rs index e8ca4bd3..789e35b4 100644 --- a/wgpu/src/image/atlas.rs +++ b/wgpu/src/image/atlas.rs @@ -237,7 +237,7 @@ impl Atlas { })); } } - _ => {} + Layer::Full => {} } } -- cgit From 14ba939e674ec4d9ca53b506ffa3259d30216e85 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Wed, 20 Sep 2023 05:19:24 +0200 Subject: Fix `clippy::unreadable_literal` --- wgpu/src/triangle.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/triangle.rs b/wgpu/src/triangle.rs index 7e1bd9cc..f8014ceb 100644 --- a/wgpu/src/triangle.rs +++ b/wgpu/src/triangle.rs @@ -329,12 +329,12 @@ impl Pipeline { fn fragment_target( texture_format: wgpu::TextureFormat, -) -> Option<wgpu::ColorTargetState> { - Some(wgpu::ColorTargetState { +) -> wgpu::ColorTargetState { + wgpu::ColorTargetState { format: texture_format, blend: Some(wgpu::BlendState::ALPHA_BLENDING), write_mask: wgpu::ColorWrites::ALL, - }) + } } fn primitive_state() -> wgpu::PrimitiveState { @@ -521,7 +521,7 @@ mod solid { fragment: Some(wgpu::FragmentState { module: &shader, entry_point: "solid_fs_main", - targets: &[triangle::fragment_target(format)], + targets: &[Some(triangle::fragment_target(format))], }), primitive: triangle::primitive_state(), depth_stencil: None, @@ -698,7 +698,7 @@ mod gradient { fragment: Some(wgpu::FragmentState { module: &shader, entry_point: "gradient_fs_main", - targets: &[triangle::fragment_target(format)], + targets: &[Some(triangle::fragment_target(format))], }), primitive: triangle::primitive_state(), depth_stencil: None, -- cgit From b27762554627b8e89f2b840b1a8a512e22d4cd87 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Wed, 20 Sep 2023 16:26:43 +0200 Subject: Revert "Chore: Apply clippy map transformations" This reverts commit c997aad85d7ee6e77085e50e5e599002549d228f. --- wgpu/src/image/vector.rs | 2 +- wgpu/src/triangle.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/image/vector.rs b/wgpu/src/image/vector.rs index e8baae4f..6582bb82 100644 --- a/wgpu/src/image/vector.rs +++ b/wgpu/src/image/vector.rs @@ -56,7 +56,7 @@ impl Cache { .ok() }); - tree.map_or(Svg::NotFound, Svg::Loaded) + tree.map(Svg::Loaded).unwrap_or(Svg::NotFound) } svg::Data::Bytes(bytes) => { match usvg::Tree::from_data(bytes, &usvg::Options::default()) { diff --git a/wgpu/src/triangle.rs b/wgpu/src/triangle.rs index f8014ceb..c55b93bf 100644 --- a/wgpu/src/triangle.rs +++ b/wgpu/src/triangle.rs @@ -349,7 +349,7 @@ fn multisample_state( antialiasing: Option<Antialiasing>, ) -> wgpu::MultisampleState { wgpu::MultisampleState { - count: antialiasing.map_or(1, Antialiasing::sample_count), + count: antialiasing.map(|a| a.sample_count()).unwrap_or(1), mask: !0, alpha_to_coverage_enabled: false, } -- cgit From b8ddd158da1b4e73e67fd090f8d36ed07f191874 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Wed, 20 Sep 2023 16:27:54 +0200 Subject: Simplify `map` call in `iced_wgpu::triangle` --- wgpu/src/triangle.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'wgpu/src') diff --git a/wgpu/src/triangle.rs b/wgpu/src/triangle.rs index c55b93bf..644c9f84 100644 --- a/wgpu/src/triangle.rs +++ b/wgpu/src/triangle.rs @@ -349,7 +349,7 @@ fn multisample_state( antialiasing: Option<Antialiasing>, ) -> wgpu::MultisampleState { wgpu::MultisampleState { - count: antialiasing.map(|a| a.sample_count()).unwrap_or(1), + count: antialiasing.map(Antialiasing::sample_count).unwrap_or(1), mask: !0, alpha_to_coverage_enabled: false, } -- cgit From f137d71e8fb926e784680d56d1cfa6817c3710a1 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez <hector@hecrj.dev> Date: Wed, 20 Sep 2023 16:40:03 +0200 Subject: Centralize `clippy` lints in `.cargo/config.toml` --- wgpu/src/lib.rs | 6 ------ 1 file changed, 6 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 2f483751..6d26723e 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -26,14 +26,8 @@ //missing_docs, unsafe_code, unused_results, - clippy::extra_unused_lifetimes, - clippy::from_over_into, - clippy::needless_borrow, - clippy::new_without_default, - clippy::useless_conversion, rustdoc::broken_intra_doc_links )] -#![allow(clippy::inherent_to_string, clippy::type_complexity)] #![cfg_attr(docsrs, feature(doc_auto_cfg))] pub mod layer; pub mod primitive; -- 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/src') 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/src') 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/src') 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/src') 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/src') 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/src') 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/src') 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/src') 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/src') 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/src') 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/src') 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/src') 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/src') 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/src') 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/src') 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/src') 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/src') 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/src') 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