From d53ccc857da4d4cda769904342aeb5a82a64f146 Mon Sep 17 00:00:00 2001
From: Bingus <shankern@protonmail.com>
Date: Wed, 12 Jul 2023 19:21:05 -0700
Subject: refactored window storage; new helper window events (Destroyed,
 Created); clippy + fmt;

---
 wgpu/src/window/compositor.rs | 4 ++++
 1 file changed, 4 insertions(+)

(limited to 'wgpu')

diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs
index cd5b20cc..814269f3 100644
--- a/wgpu/src/window/compositor.rs
+++ b/wgpu/src/window/compositor.rs
@@ -219,6 +219,10 @@ impl<Theme> graphics::Compositor for Compositor<Theme> {
         Ok((compositor, Renderer::new(backend)))
     }
 
+    fn renderer(&self) -> Self::Renderer {
+        Renderer::new(self.create_backend())
+    }
+
     fn create_surface<W: HasRawWindowHandle + HasRawDisplayHandle>(
         &mut self,
         window: &W,
-- 
cgit 


From 346af3f8b0baa418fd37b878bc2930ff0bd57cc0 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector@hecrj.dev>
Date: Mon, 11 Sep 2023 02:47:24 +0200
Subject: Make `FontSystem` global and simplify `Paragraph` API

---
 wgpu/src/backend.rs |  5 -----
 wgpu/src/text.rs    | 17 ++++++++---------
 2 files changed, 8 insertions(+), 14 deletions(-)

(limited to 'wgpu')

diff --git a/wgpu/src/backend.rs b/wgpu/src/backend.rs
index 65c63f19..3d1755e1 100644
--- a/wgpu/src/backend.rs
+++ b/wgpu/src/backend.rs
@@ -1,5 +1,4 @@
 use crate::core::{Color, Size};
-use crate::graphics;
 use crate::graphics::backend;
 use crate::graphics::color;
 use crate::graphics::{Transformation, Viewport};
@@ -310,10 +309,6 @@ impl crate::graphics::Backend for Backend {
 }
 
 impl backend::Text for Backend {
-    fn font_system(&self) -> &graphics::text::FontSystem {
-        self.text_pipeline.font_system()
-    }
-
     fn load_font(&mut self, font: Cow<'static, [u8]>) {
         self.text_pipeline.load_font(font);
     }
diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs
index bd4f3e06..5c9f4d7e 100644
--- a/wgpu/src/text.rs
+++ b/wgpu/src/text.rs
@@ -2,7 +2,7 @@ use crate::core::alignment;
 use crate::core::{Rectangle, Size};
 use crate::graphics::color;
 use crate::graphics::text::cache::{self, Cache};
-use crate::graphics::text::{FontSystem, Paragraph};
+use crate::graphics::text::{font_system, Paragraph};
 use crate::layer::Text;
 
 use std::borrow::Cow;
@@ -10,7 +10,6 @@ use std::cell::RefCell;
 
 #[allow(missing_debug_implementations)]
 pub struct Pipeline {
-    font_system: FontSystem,
     renderers: Vec<glyphon::TextRenderer>,
     atlas: glyphon::TextAtlas,
     prepare_layer: usize,
@@ -24,7 +23,6 @@ impl Pipeline {
         format: wgpu::TextureFormat,
     ) -> Self {
         Pipeline {
-            font_system: FontSystem::new(),
             renderers: Vec::new(),
             atlas: glyphon::TextAtlas::with_color_mode(
                 device,
@@ -41,12 +39,11 @@ impl Pipeline {
         }
     }
 
-    pub fn font_system(&self) -> &FontSystem {
-        &self.font_system
-    }
-
     pub fn load_font(&mut self, bytes: Cow<'static, [u8]>) {
-        self.font_system.load_font(bytes);
+        font_system()
+            .write()
+            .expect("Write font system")
+            .load_font(bytes);
 
         self.cache = RefCell::new(Cache::new());
     }
@@ -69,7 +66,9 @@ impl Pipeline {
             ));
         }
 
-        let font_system = self.font_system.get_mut();
+        let mut font_system = font_system().write().expect("Write font system");
+        let font_system = font_system.raw();
+
         let renderer = &mut self.renderers[self.prepare_layer];
         let cache = self.cache.get_mut();
 
-- 
cgit 


From 6448429103c9c82b90040ac5a5a097bdded23f82 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector@hecrj.dev>
Date: Tue, 12 Sep 2023 14:51:00 +0200
Subject: Draft `Editor` API and `TextEditor` widget

---
 wgpu/src/layer.rs      | 15 ++++++++++++++-
 wgpu/src/layer/text.rs |  8 +++++++-
 wgpu/src/text.rs       | 28 +++++++++++++++++++++++++---
 3 files changed, 46 insertions(+), 5 deletions(-)

(limited to 'wgpu')

diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs
index 7a5a0f7c..10b3332d 100644
--- a/wgpu/src/layer.rs
+++ b/wgpu/src/layer.rs
@@ -120,12 +120,25 @@ impl<'a> Layer<'a> {
             } => {
                 let layer = &mut layers[current_layer];
 
-                layer.text.push(Text::Managed {
+                layer.text.push(Text::Paragraph {
                     paragraph: paragraph.clone(),
                     position: *position + translation,
                     color: *color,
                 });
             }
+            Primitive::Editor {
+                editor,
+                position,
+                color,
+            } => {
+                let layer = &mut layers[current_layer];
+
+                layer.text.push(Text::Editor {
+                    editor: editor.clone(),
+                    position: *position + translation,
+                    color: *color,
+                });
+            }
             Primitive::Text {
                 content,
                 bounds,
diff --git a/wgpu/src/layer/text.rs b/wgpu/src/layer/text.rs
index b61615d6..d46b39da 100644
--- a/wgpu/src/layer/text.rs
+++ b/wgpu/src/layer/text.rs
@@ -1,16 +1,22 @@
 use crate::core::alignment;
 use crate::core::text;
 use crate::core::{Color, Font, Pixels, Point, Rectangle};
+use crate::graphics::text::editor;
 use crate::graphics::text::paragraph;
 
 /// A paragraph of text.
 #[derive(Debug, Clone)]
 pub enum Text<'a> {
-    Managed {
+    Paragraph {
         paragraph: paragraph::Weak,
         position: Point,
         color: Color,
     },
+    Editor {
+        editor: editor::Weak,
+        position: Point,
+        color: Color,
+    },
     Cached(Cached<'a>),
 }
 
diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs
index 5c9f4d7e..397c38dd 100644
--- a/wgpu/src/text.rs
+++ b/wgpu/src/text.rs
@@ -2,7 +2,7 @@ use crate::core::alignment;
 use crate::core::{Rectangle, Size};
 use crate::graphics::color;
 use crate::graphics::text::cache::{self, Cache};
-use crate::graphics::text::{font_system, Paragraph};
+use crate::graphics::text::{font_system, Editor, Paragraph};
 use crate::layer::Text;
 
 use std::borrow::Cow;
@@ -74,15 +74,19 @@ impl Pipeline {
 
         enum Allocation {
             Paragraph(Paragraph),
+            Editor(Editor),
             Cache(cache::KeyHash),
         }
 
         let allocations: Vec<_> = sections
             .iter()
             .map(|section| match section {
-                Text::Managed { paragraph, .. } => {
+                Text::Paragraph { paragraph, .. } => {
                     paragraph.upgrade().map(Allocation::Paragraph)
                 }
+                Text::Editor { editor, .. } => {
+                    editor.upgrade().map(Allocation::Editor)
+                }
                 Text::Cached(text) => {
                     let (key, _) = cache.allocate(
                         font_system,
@@ -117,7 +121,7 @@ impl Pipeline {
                     vertical_alignment,
                     color,
                 ) = match section {
-                    Text::Managed {
+                    Text::Paragraph {
                         position, color, ..
                     } => {
                         use crate::core::text::Paragraph as _;
@@ -135,6 +139,24 @@ impl Pipeline {
                             *color,
                         )
                     }
+                    Text::Editor {
+                        position, color, ..
+                    } => {
+                        use crate::core::text::Editor as _;
+
+                        let Some(Allocation::Editor(editor)) = allocation
+                        else {
+                            return None;
+                        };
+
+                        (
+                            editor.buffer(),
+                            Rectangle::new(*position, editor.min_bounds()),
+                            alignment::Horizontal::Left,
+                            alignment::Vertical::Top,
+                            *color,
+                        )
+                    }
                     Text::Cached(text) => {
                         let Some(Allocation::Cache(key)) = allocation else {
                             return None;
-- 
cgit 


From c7d02e24e6f8265c205a68bd97b2643d40ae30ee Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector@hecrj.dev>
Date: Thu, 14 Sep 2023 18:57:09 +0200
Subject: Remove `Editor::min_bounds` and use `bounds` instead

---
 wgpu/src/text.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'wgpu')

diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs
index 397c38dd..581df0cb 100644
--- a/wgpu/src/text.rs
+++ b/wgpu/src/text.rs
@@ -151,7 +151,7 @@ impl Pipeline {
 
                         (
                             editor.buffer(),
-                            Rectangle::new(*position, editor.min_bounds()),
+                            Rectangle::new(*position, editor.bounds()),
                             alignment::Horizontal::Left,
                             alignment::Vertical::Top,
                             *color,
-- 
cgit 


From be340a8cd822be1ea0fe4c1b1f3a62ca66d705b4 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector@hecrj.dev>
Date: Tue, 19 Sep 2023 23:00:20 +0200
Subject: Fix gamma correction for colored glyphs in `iced_wgpu`

---
 wgpu/src/text.rs | 13 ++-----------
 1 file changed, 2 insertions(+), 11 deletions(-)

(limited to 'wgpu')

diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs
index 581df0cb..f746be63 100644
--- a/wgpu/src/text.rs
+++ b/wgpu/src/text.rs
@@ -2,7 +2,7 @@ use crate::core::alignment;
 use crate::core::{Rectangle, Size};
 use crate::graphics::color;
 use crate::graphics::text::cache::{self, Cache};
-use crate::graphics::text::{font_system, Editor, Paragraph};
+use crate::graphics::text::{font_system, to_color, Editor, Paragraph};
 use crate::layer::Text;
 
 use std::borrow::Cow;
@@ -214,16 +214,7 @@ impl Pipeline {
                         right: (clip_bounds.x + clip_bounds.width) as i32,
                         bottom: (clip_bounds.y + clip_bounds.height) as i32,
                     },
-                    default_color: {
-                        let [r, g, b, a] = color::pack(color).components();
-
-                        glyphon::Color::rgba(
-                            (r * 255.0) as u8,
-                            (g * 255.0) as u8,
-                            (b * 255.0) as u8,
-                            (a * 255.0) as u8,
-                        )
-                    },
+                    default_color: to_color(color),
                 })
             },
         );
-- 
cgit 


From 86b877517feb15b2155c6cfef29246a3f281c8ae Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector@hecrj.dev>
Date: Fri, 27 Oct 2023 03:21:40 +0200
Subject: Update `wgpu` to `0.18` and `cosmic-text` to `0.10`

---
 wgpu/src/backend.rs       | 8 ++++++--
 wgpu/src/color.rs         | 4 +++-
 wgpu/src/triangle.rs      | 7 ++++++-
 wgpu/src/triangle/msaa.rs | 4 +++-
 4 files changed, 18 insertions(+), 5 deletions(-)

(limited to 'wgpu')

diff --git a/wgpu/src/backend.rs b/wgpu/src/backend.rs
index 65c63f19..32b8a189 100644
--- a/wgpu/src/backend.rs
+++ b/wgpu/src/backend.rs
@@ -222,10 +222,12 @@ impl Backend {
                             }),
                             None => wgpu::LoadOp::Load,
                         },
-                        store: true,
+                        store: wgpu::StoreOp::Store,
                     },
                 })],
                 depth_stencil_attachment: None,
+                timestamp_writes: None,
+                occlusion_query_set: None,
             },
         ));
 
@@ -271,11 +273,13 @@ impl Backend {
                                 resolve_target: None,
                                 ops: wgpu::Operations {
                                     load: wgpu::LoadOp::Load,
-                                    store: true,
+                                    store: wgpu::StoreOp::Store,
                                 },
                             },
                         )],
                         depth_stencil_attachment: None,
+                        timestamp_writes: None,
+                        occlusion_query_set: None,
                     },
                 ));
             }
diff --git a/wgpu/src/color.rs b/wgpu/src/color.rs
index 20827e3c..4598b0a6 100644
--- a/wgpu/src/color.rs
+++ b/wgpu/src/color.rs
@@ -143,10 +143,12 @@ pub fn convert(
             resolve_target: None,
             ops: wgpu::Operations {
                 load: wgpu::LoadOp::Load,
-                store: true,
+                store: wgpu::StoreOp::Store,
             },
         })],
         depth_stencil_attachment: None,
+        timestamp_writes: None,
+        occlusion_query_set: None,
     });
 
     pass.set_pipeline(&pipeline);
diff --git a/wgpu/src/triangle.rs b/wgpu/src/triangle.rs
index 644c9f84..69270a73 100644
--- a/wgpu/src/triangle.rs
+++ b/wgpu/src/triangle.rs
@@ -300,10 +300,15 @@ impl Pipeline {
                         wgpu::RenderPassColorAttachment {
                             view: attachment,
                             resolve_target,
-                            ops: wgpu::Operations { load, store: true },
+                            ops: wgpu::Operations {
+                                load,
+                                store: wgpu::StoreOp::Store,
+                            },
                         },
                     )],
                     depth_stencil_attachment: None,
+                    timestamp_writes: None,
+                    occlusion_query_set: None,
                 });
 
             let layer = &mut self.layers[layer];
diff --git a/wgpu/src/triangle/msaa.rs b/wgpu/src/triangle/msaa.rs
index 320b5b12..14abd20b 100644
--- a/wgpu/src/triangle/msaa.rs
+++ b/wgpu/src/triangle/msaa.rs
@@ -167,10 +167,12 @@ impl Blit {
                     resolve_target: None,
                     ops: wgpu::Operations {
                         load: wgpu::LoadOp::Load,
-                        store: true,
+                        store: wgpu::StoreOp::Store,
                     },
                 })],
                 depth_stencil_attachment: None,
+                timestamp_writes: None,
+                occlusion_query_set: None,
             });
 
         render_pass.set_pipeline(&self.pipeline);
-- 
cgit 


From 625cd745f38215b1cb8f629cdc6d2fa41c9a739a Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector@hecrj.dev>
Date: Fri, 27 Oct 2023 05:04:14 +0200
Subject: Write documentation for the new text APIs

---
 wgpu/src/layer/text.rs | 7 ++++++-
 wgpu/src/lib.rs        | 2 +-
 2 files changed, 7 insertions(+), 2 deletions(-)

(limited to 'wgpu')

diff --git a/wgpu/src/layer/text.rs b/wgpu/src/layer/text.rs
index d46b39da..66417cec 100644
--- a/wgpu/src/layer/text.rs
+++ b/wgpu/src/layer/text.rs
@@ -4,19 +4,24 @@ use crate::core::{Color, Font, Pixels, Point, Rectangle};
 use crate::graphics::text::editor;
 use crate::graphics::text::paragraph;
 
-/// A paragraph of text.
+/// A text primitive.
 #[derive(Debug, Clone)]
 pub enum Text<'a> {
+    /// A paragraph.
+    #[allow(missing_docs)]
     Paragraph {
         paragraph: paragraph::Weak,
         position: Point,
         color: Color,
     },
+    /// An editor.
+    #[allow(missing_docs)]
     Editor {
         editor: editor::Weak,
         position: Point,
         color: Color,
     },
+    /// A cached text.
     Cached(Cached<'a>),
 }
 
diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs
index 6d26723e..424dfeb3 100644
--- a/wgpu/src/lib.rs
+++ b/wgpu/src/lib.rs
@@ -23,7 +23,7 @@
 #![forbid(rust_2018_idioms)]
 #![deny(
     missing_debug_implementations,
-    //missing_docs,
+    missing_docs,
     unsafe_code,
     unused_results,
     rustdoc::broken_intra_doc_links
-- 
cgit 


From 5759096a4c33935fcdf5f96606143e4f21159186 Mon Sep 17 00:00:00 2001
From: Remmirad <remmirad@posteo.net>
Date: Wed, 31 May 2023 15:46:21 +0200
Subject: Implement texture filtering options

---
 wgpu/src/image.rs | 69 ++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 45 insertions(+), 24 deletions(-)

(limited to 'wgpu')

diff --git a/wgpu/src/image.rs b/wgpu/src/image.rs
index 553ba330..a0fe7e83 100644
--- a/wgpu/src/image.rs
+++ b/wgpu/src/image.rs
@@ -7,6 +7,7 @@ mod raster;
 mod vector;
 
 use atlas::Atlas;
+use iced_graphics::core::image::{TextureFilter, FilterMethod};
 
 use crate::core::{Rectangle, Size};
 use crate::graphics::Transformation;
@@ -14,6 +15,7 @@ use crate::layer;
 use crate::Buffer;
 
 use std::cell::RefCell;
+use std::collections::HashMap;
 use std::mem;
 
 use bytemuck::{Pod, Zeroable};
@@ -37,7 +39,7 @@ pub struct Pipeline {
     pipeline: wgpu::RenderPipeline,
     vertices: wgpu::Buffer,
     indices: wgpu::Buffer,
-    sampler: wgpu::Sampler,
+    sampler: HashMap<TextureFilter,wgpu::Sampler>,
     texture: wgpu::BindGroup,
     texture_version: usize,
     texture_atlas: Atlas,
@@ -142,15 +144,32 @@ impl Pipeline {
     pub fn new(device: &wgpu::Device, format: wgpu::TextureFormat) -> Self {
         use wgpu::util::DeviceExt;
 
-        let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
-            address_mode_u: wgpu::AddressMode::ClampToEdge,
-            address_mode_v: wgpu::AddressMode::ClampToEdge,
-            address_mode_w: wgpu::AddressMode::ClampToEdge,
-            mag_filter: wgpu::FilterMode::Linear,
-            min_filter: wgpu::FilterMode::Linear,
-            mipmap_filter: wgpu::FilterMode::Linear,
-            ..Default::default()
-        });
+        let to_wgpu = |method: FilterMethod| {
+            match method {
+                FilterMethod::Linear => wgpu::FilterMode::Linear,
+                FilterMethod::Nearest => wgpu::FilterMode::Nearest,
+            }
+        };
+
+        let mut sampler = HashMap::new();
+
+        let filter = [FilterMethod::Linear, FilterMethod::Nearest];
+        for min in 0..filter.len() {
+            for mag in 0..filter.len() {
+                let _ = sampler.insert(TextureFilter {min: filter[min], mag: filter[mag]}, 
+                    device.create_sampler(&wgpu::SamplerDescriptor {
+                        address_mode_u: wgpu::AddressMode::ClampToEdge,
+                        address_mode_v: wgpu::AddressMode::ClampToEdge,
+                        address_mode_w: wgpu::AddressMode::ClampToEdge,
+                        mag_filter: to_wgpu(filter[mag]),
+                        min_filter: to_wgpu(filter[min]),
+                        mipmap_filter: wgpu::FilterMode::Linear,
+                        ..Default::default()
+                    }
+                ));
+            }
+        }
+
 
         let constant_layout =
             device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
@@ -355,7 +374,7 @@ impl Pipeline {
         #[cfg(feature = "tracing")]
         let _ = info_span!("Wgpu::Image", "DRAW").entered();
 
-        let instances: &mut Vec<Instance> = &mut Vec::new();
+        let instances: &mut HashMap<TextureFilter,Vec<Instance>> = &mut HashMap::new();
 
         #[cfg(feature = "image")]
         let mut raster_cache = self.raster_cache.borrow_mut();
@@ -377,7 +396,7 @@ impl Pipeline {
                             [bounds.x, bounds.y],
                             [bounds.width, bounds.height],
                             atlas_entry,
-                            instances,
+                            instances.entry(handle.filter().clone()).or_insert(Vec::new()),
                         );
                     }
                 }
@@ -405,7 +424,7 @@ impl Pipeline {
                             [bounds.x, bounds.y],
                             size,
                             atlas_entry,
-                            instances,
+                            instances.entry(TextureFilter::default()).or_insert(Vec::new()),
                         );
                     }
                 }
@@ -438,18 +457,20 @@ impl Pipeline {
             self.texture_version = texture_version;
         }
 
-        if self.layers.len() <= self.prepare_layer {
-            self.layers.push(Layer::new(
-                device,
-                &self.constant_layout,
-                &self.sampler,
-            ));
+        for (filter, instances) in instances.iter_mut() {
+            if self.layers.len() <= self.prepare_layer {
+                self.layers.push(Layer::new(
+                    device,
+                    &self.constant_layout,
+                    &self.sampler.get(filter).expect("Sampler is registered"),
+                ));
+            }
+    
+            let layer = &mut self.layers[self.prepare_layer];
+            layer.prepare(device, queue, &instances, transformation);
+    
+            self.prepare_layer += 1;
         }
-
-        let layer = &mut self.layers[self.prepare_layer];
-        layer.prepare(device, queue, instances, transformation);
-
-        self.prepare_layer += 1;
     }
 
     pub fn render<'a>(
-- 
cgit 


From 4b32a488808e371313ce78e727c9d98ab2eb759e Mon Sep 17 00:00:00 2001
From: Remmirad <remmirad@posteo.net>
Date: Fri, 4 Aug 2023 13:50:16 +0200
Subject: Fix clippy + fmt

---
 wgpu/src/image.rs | 42 ++++++++++++++++++++++++------------------
 1 file changed, 24 insertions(+), 18 deletions(-)

(limited to 'wgpu')

diff --git a/wgpu/src/image.rs b/wgpu/src/image.rs
index a0fe7e83..a3168001 100644
--- a/wgpu/src/image.rs
+++ b/wgpu/src/image.rs
@@ -7,7 +7,7 @@ mod raster;
 mod vector;
 
 use atlas::Atlas;
-use iced_graphics::core::image::{TextureFilter, FilterMethod};
+use iced_graphics::core::image::{FilterMethod, TextureFilter};
 
 use crate::core::{Rectangle, Size};
 use crate::graphics::Transformation;
@@ -39,7 +39,7 @@ pub struct Pipeline {
     pipeline: wgpu::RenderPipeline,
     vertices: wgpu::Buffer,
     indices: wgpu::Buffer,
-    sampler: HashMap<TextureFilter,wgpu::Sampler>,
+    sampler: HashMap<TextureFilter, wgpu::Sampler>,
     texture: wgpu::BindGroup,
     texture_version: usize,
     texture_atlas: Atlas,
@@ -144,11 +144,9 @@ impl Pipeline {
     pub fn new(device: &wgpu::Device, format: wgpu::TextureFormat) -> Self {
         use wgpu::util::DeviceExt;
 
-        let to_wgpu = |method: FilterMethod| {
-            match method {
-                FilterMethod::Linear => wgpu::FilterMode::Linear,
-                FilterMethod::Nearest => wgpu::FilterMode::Nearest,
-            }
+        let to_wgpu = |method: FilterMethod| match method {
+            FilterMethod::Linear => wgpu::FilterMode::Linear,
+            FilterMethod::Nearest => wgpu::FilterMode::Nearest,
         };
 
         let mut sampler = HashMap::new();
@@ -156,7 +154,11 @@ impl Pipeline {
         let filter = [FilterMethod::Linear, FilterMethod::Nearest];
         for min in 0..filter.len() {
             for mag in 0..filter.len() {
-                let _ = sampler.insert(TextureFilter {min: filter[min], mag: filter[mag]}, 
+                let _ = sampler.insert(
+                    TextureFilter {
+                        min: filter[min],
+                        mag: filter[mag],
+                    },
                     device.create_sampler(&wgpu::SamplerDescriptor {
                         address_mode_u: wgpu::AddressMode::ClampToEdge,
                         address_mode_v: wgpu::AddressMode::ClampToEdge,
@@ -165,12 +167,11 @@ impl Pipeline {
                         min_filter: to_wgpu(filter[min]),
                         mipmap_filter: wgpu::FilterMode::Linear,
                         ..Default::default()
-                    }
-                ));
+                    }),
+                );
             }
         }
 
-
         let constant_layout =
             device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
                 label: Some("iced_wgpu::image constants layout"),
@@ -374,7 +375,8 @@ impl Pipeline {
         #[cfg(feature = "tracing")]
         let _ = info_span!("Wgpu::Image", "DRAW").entered();
 
-        let instances: &mut HashMap<TextureFilter,Vec<Instance>> = &mut HashMap::new();
+        let instances: &mut HashMap<TextureFilter, Vec<Instance>> =
+            &mut HashMap::new();
 
         #[cfg(feature = "image")]
         let mut raster_cache = self.raster_cache.borrow_mut();
@@ -396,7 +398,9 @@ impl Pipeline {
                             [bounds.x, bounds.y],
                             [bounds.width, bounds.height],
                             atlas_entry,
-                            instances.entry(handle.filter().clone()).or_insert(Vec::new()),
+                            instances
+                                .entry(handle.filter().clone())
+                                .or_insert(Vec::new()),
                         );
                     }
                 }
@@ -424,7 +428,9 @@ impl Pipeline {
                             [bounds.x, bounds.y],
                             size,
                             atlas_entry,
-                            instances.entry(TextureFilter::default()).or_insert(Vec::new()),
+                            instances
+                                .entry(TextureFilter::default())
+                                .or_insert(Vec::new()),
                         );
                     }
                 }
@@ -462,13 +468,13 @@ impl Pipeline {
                 self.layers.push(Layer::new(
                     device,
                     &self.constant_layout,
-                    &self.sampler.get(filter).expect("Sampler is registered"),
+                    self.sampler.get(filter).expect("Sampler is registered"),
                 ));
             }
-    
+
             let layer = &mut self.layers[self.prepare_layer];
-            layer.prepare(device, queue, &instances, transformation);
-    
+            layer.prepare(device, queue, instances, transformation);
+
             self.prepare_layer += 1;
         }
     }
-- 
cgit 


From e5d3e75d826e9fad8a0da5dd538aa542059dd034 Mon Sep 17 00:00:00 2001
From: Remmirad <remmirad@posteo.net>
Date: Mon, 25 Sep 2023 21:54:50 +0200
Subject: fix design for wgpu backend

---
 wgpu/src/image.rs | 133 +++++++++++++++++++++++++++++++-----------------------
 1 file changed, 77 insertions(+), 56 deletions(-)

(limited to 'wgpu')

diff --git a/wgpu/src/image.rs b/wgpu/src/image.rs
index a3168001..0aa7f899 100644
--- a/wgpu/src/image.rs
+++ b/wgpu/src/image.rs
@@ -8,6 +8,7 @@ mod vector;
 
 use atlas::Atlas;
 use iced_graphics::core::image::{FilterMethod, TextureFilter};
+use wgpu::Sampler;
 
 use crate::core::{Rectangle, Size};
 use crate::graphics::Transformation;
@@ -15,7 +16,6 @@ use crate::layer;
 use crate::Buffer;
 
 use std::cell::RefCell;
-use std::collections::HashMap;
 use std::mem;
 
 use bytemuck::{Pod, Zeroable};
@@ -29,6 +29,8 @@ use crate::core::svg;
 #[cfg(feature = "tracing")]
 use tracing::info_span;
 
+const SAMPLER_COUNT: usize = 4;
+
 #[derive(Debug)]
 pub struct Pipeline {
     #[cfg(feature = "image")]
@@ -39,14 +41,14 @@ pub struct Pipeline {
     pipeline: wgpu::RenderPipeline,
     vertices: wgpu::Buffer,
     indices: wgpu::Buffer,
-    sampler: HashMap<TextureFilter, wgpu::Sampler>,
+    sampler: [wgpu::Sampler; SAMPLER_COUNT],
     texture: wgpu::BindGroup,
     texture_version: usize,
     texture_atlas: Atlas,
     texture_layout: wgpu::BindGroupLayout,
     constant_layout: wgpu::BindGroupLayout,
 
-    layers: Vec<Layer>,
+    layers: Vec<[Option<Layer>; SAMPLER_COUNT]>,
     prepare_layer: usize,
 }
 
@@ -149,28 +151,32 @@ impl Pipeline {
             FilterMethod::Nearest => wgpu::FilterMode::Nearest,
         };
 
-        let mut sampler = HashMap::new();
+        let mut sampler: [Option<Sampler>; SAMPLER_COUNT] =
+            [None, None, None, None];
 
         let filter = [FilterMethod::Linear, FilterMethod::Nearest];
         for min in 0..filter.len() {
             for mag in 0..filter.len() {
-                let _ = sampler.insert(
-                    TextureFilter {
-                        min: filter[min],
-                        mag: filter[mag],
-                    },
-                    device.create_sampler(&wgpu::SamplerDescriptor {
-                        address_mode_u: wgpu::AddressMode::ClampToEdge,
-                        address_mode_v: wgpu::AddressMode::ClampToEdge,
-                        address_mode_w: wgpu::AddressMode::ClampToEdge,
-                        mag_filter: to_wgpu(filter[mag]),
-                        min_filter: to_wgpu(filter[min]),
-                        mipmap_filter: wgpu::FilterMode::Linear,
-                        ..Default::default()
-                    }),
-                );
+                sampler[to_index(&TextureFilter {
+                    min: filter[min],
+                    mag: filter[mag],
+                })] = Some(device.create_sampler(&wgpu::SamplerDescriptor {
+                    address_mode_u: wgpu::AddressMode::ClampToEdge,
+                    address_mode_v: wgpu::AddressMode::ClampToEdge,
+                    address_mode_w: wgpu::AddressMode::ClampToEdge,
+                    mag_filter: to_wgpu(filter[mag]),
+                    min_filter: to_wgpu(filter[min]),
+                    mipmap_filter: wgpu::FilterMode::Linear,
+                    ..Default::default()
+                }));
             }
         }
+        let sampler = [
+            sampler[0].take().unwrap(),
+            sampler[1].take().unwrap(),
+            sampler[2].take().unwrap(),
+            sampler[3].take().unwrap(),
+        ];
 
         let constant_layout =
             device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
@@ -375,8 +381,8 @@ impl Pipeline {
         #[cfg(feature = "tracing")]
         let _ = info_span!("Wgpu::Image", "DRAW").entered();
 
-        let instances: &mut HashMap<TextureFilter, Vec<Instance>> =
-            &mut HashMap::new();
+        let mut instances: [Vec<Instance>; SAMPLER_COUNT] =
+            [Vec::new(), Vec::new(), Vec::new(), Vec::new()];
 
         #[cfg(feature = "image")]
         let mut raster_cache = self.raster_cache.borrow_mut();
@@ -398,9 +404,7 @@ impl Pipeline {
                             [bounds.x, bounds.y],
                             [bounds.width, bounds.height],
                             atlas_entry,
-                            instances
-                                .entry(handle.filter().clone())
-                                .or_insert(Vec::new()),
+                            &mut instances[to_index(handle.filter())],
                         );
                     }
                 }
@@ -428,9 +432,7 @@ impl Pipeline {
                             [bounds.x, bounds.y],
                             size,
                             atlas_entry,
-                            instances
-                                .entry(TextureFilter::default())
-                                .or_insert(Vec::new()),
+                            &mut instances[to_index(&TextureFilter::default())],
                         );
                     }
                 }
@@ -463,20 +465,26 @@ impl Pipeline {
             self.texture_version = texture_version;
         }
 
-        for (filter, instances) in instances.iter_mut() {
-            if self.layers.len() <= self.prepare_layer {
-                self.layers.push(Layer::new(
-                    device,
-                    &self.constant_layout,
-                    self.sampler.get(filter).expect("Sampler is registered"),
-                ));
+        if self.layers.len() <= self.prepare_layer {
+            self.layers.push([None, None, None, None]);
+        }
+        for (i, instances) in instances.iter_mut().enumerate() {
+            let layer = &mut self.layers[self.prepare_layer][i];
+            if !instances.is_empty() {
+                if layer.is_none() {
+                    *layer = Some(Layer::new(
+                        device,
+                        &self.constant_layout,
+                        &self.sampler[i],
+                    ))
+                }
             }
 
-            let layer = &mut self.layers[self.prepare_layer];
-            layer.prepare(device, queue, instances, transformation);
-
-            self.prepare_layer += 1;
+            if let Some(layer) = layer {
+                layer.prepare(device, queue, instances, transformation);
+            }
         }
+        self.prepare_layer += 1;
     }
 
     pub fn render<'a>(
@@ -485,24 +493,29 @@ impl Pipeline {
         bounds: Rectangle<u32>,
         render_pass: &mut wgpu::RenderPass<'a>,
     ) {
-        if let Some(layer) = self.layers.get(layer) {
-            render_pass.set_pipeline(&self.pipeline);
-
-            render_pass.set_scissor_rect(
-                bounds.x,
-                bounds.y,
-                bounds.width,
-                bounds.height,
-            );
-
-            render_pass.set_bind_group(1, &self.texture, &[]);
-            render_pass.set_index_buffer(
-                self.indices.slice(..),
-                wgpu::IndexFormat::Uint16,
-            );
-            render_pass.set_vertex_buffer(0, self.vertices.slice(..));
-
-            layer.render(render_pass);
+        if let Some(layer_group) = self.layers.get(layer) {
+            for (i, layer) in layer_group.iter().enumerate() {
+                if let Some(layer) = layer {
+                    println!("Render {i}");
+                    render_pass.set_pipeline(&self.pipeline);
+
+                    render_pass.set_scissor_rect(
+                        bounds.x,
+                        bounds.y,
+                        bounds.width,
+                        bounds.height,
+                    );
+
+                    render_pass.set_bind_group(1, &self.texture, &[]);
+                    render_pass.set_index_buffer(
+                        self.indices.slice(..),
+                        wgpu::IndexFormat::Uint16,
+                    );
+                    render_pass.set_vertex_buffer(0, self.vertices.slice(..));
+
+                    layer.render(render_pass);
+                }
+            }
         }
     }
 
@@ -517,6 +530,14 @@ impl Pipeline {
     }
 }
 
+fn to_index(filter: &TextureFilter) -> usize {
+    let to_index = |m| match m {
+        FilterMethod::Linear => 0,
+        FilterMethod::Nearest => 1,
+    };
+    return (to_index(filter.mag) << 1) | (to_index(filter.min));
+}
+
 #[repr(C)]
 #[derive(Clone, Copy, Zeroable, Pod)]
 pub struct Vertex {
-- 
cgit 


From 75c9afc608a4a9ff44d60a8fb6f4a5819f05bf79 Mon Sep 17 00:00:00 2001
From: Remmirad <remmirad@posteo.net>
Date: Mon, 25 Sep 2023 22:03:22 +0200
Subject: Remove debug traces

---
 wgpu/src/image.rs | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

(limited to 'wgpu')

diff --git a/wgpu/src/image.rs b/wgpu/src/image.rs
index 0aa7f899..6768a714 100644
--- a/wgpu/src/image.rs
+++ b/wgpu/src/image.rs
@@ -494,9 +494,8 @@ impl Pipeline {
         render_pass: &mut wgpu::RenderPass<'a>,
     ) {
         if let Some(layer_group) = self.layers.get(layer) {
-            for (i, layer) in layer_group.iter().enumerate() {
+            for layer in layer_group.iter() {
                 if let Some(layer) = layer {
-                    println!("Render {i}");
                     render_pass.set_pipeline(&self.pipeline);
 
                     render_pass.set_scissor_rect(
-- 
cgit 


From a5125d6fea824df1191777fe3eb53a2f748208b9 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector@hecrj.dev>
Date: Sat, 11 Nov 2023 07:02:01 +0100
Subject: Refactor texture image filtering

- Support only `Linear` or `Nearest`
- Simplify `Layer` groups
- Move `FilterMethod` to `Image` and `image::Viewer`
---
 wgpu/src/image.rs       | 238 +++++++++++++++++++++++++++---------------------
 wgpu/src/layer.rs       |   7 +-
 wgpu/src/layer/image.rs |   3 +
 3 files changed, 141 insertions(+), 107 deletions(-)

(limited to 'wgpu')

diff --git a/wgpu/src/image.rs b/wgpu/src/image.rs
index 6768a714..1a88c6ae 100644
--- a/wgpu/src/image.rs
+++ b/wgpu/src/image.rs
@@ -7,8 +7,6 @@ mod raster;
 mod vector;
 
 use atlas::Atlas;
-use iced_graphics::core::image::{FilterMethod, TextureFilter};
-use wgpu::Sampler;
 
 use crate::core::{Rectangle, Size};
 use crate::graphics::Transformation;
@@ -29,8 +27,6 @@ use crate::core::svg;
 #[cfg(feature = "tracing")]
 use tracing::info_span;
 
-const SAMPLER_COUNT: usize = 4;
-
 #[derive(Debug)]
 pub struct Pipeline {
     #[cfg(feature = "image")]
@@ -41,30 +37,31 @@ pub struct Pipeline {
     pipeline: wgpu::RenderPipeline,
     vertices: wgpu::Buffer,
     indices: wgpu::Buffer,
-    sampler: [wgpu::Sampler; SAMPLER_COUNT],
+    nearest_sampler: wgpu::Sampler,
+    linear_sampler: wgpu::Sampler,
     texture: wgpu::BindGroup,
     texture_version: usize,
     texture_atlas: Atlas,
     texture_layout: wgpu::BindGroupLayout,
     constant_layout: wgpu::BindGroupLayout,
 
-    layers: Vec<[Option<Layer>; SAMPLER_COUNT]>,
+    layers: Vec<Layer>,
     prepare_layer: usize,
 }
 
 #[derive(Debug)]
 struct Layer {
     uniforms: wgpu::Buffer,
-    constants: wgpu::BindGroup,
-    instances: Buffer<Instance>,
-    instance_count: usize,
+    nearest: Data,
+    linear: Data,
 }
 
 impl Layer {
     fn new(
         device: &wgpu::Device,
         constant_layout: &wgpu::BindGroupLayout,
-        sampler: &wgpu::Sampler,
+        nearest_sampler: &wgpu::Sampler,
+        linear_sampler: &wgpu::Sampler,
     ) -> Self {
         let uniforms = device.create_buffer(&wgpu::BufferDescriptor {
             label: Some("iced_wgpu::image uniforms buffer"),
@@ -73,6 +70,59 @@ impl Layer {
             mapped_at_creation: false,
         });
 
+        let nearest =
+            Data::new(device, constant_layout, nearest_sampler, &uniforms);
+
+        let linear =
+            Data::new(device, constant_layout, linear_sampler, &uniforms);
+
+        Self {
+            uniforms,
+            nearest,
+            linear,
+        }
+    }
+
+    fn prepare(
+        &mut self,
+        device: &wgpu::Device,
+        queue: &wgpu::Queue,
+        nearest_instances: &[Instance],
+        linear_instances: &[Instance],
+        transformation: Transformation,
+    ) {
+        queue.write_buffer(
+            &self.uniforms,
+            0,
+            bytemuck::bytes_of(&Uniforms {
+                transform: transformation.into(),
+            }),
+        );
+
+        self.nearest.upload(device, queue, nearest_instances);
+        self.linear.upload(device, queue, linear_instances);
+    }
+
+    fn render<'a>(&'a self, render_pass: &mut wgpu::RenderPass<'a>) {
+        self.nearest.render(render_pass);
+        self.linear.render(render_pass);
+    }
+}
+
+#[derive(Debug)]
+struct Data {
+    constants: wgpu::BindGroup,
+    instances: Buffer<Instance>,
+    instance_count: usize,
+}
+
+impl Data {
+    pub fn new(
+        device: &wgpu::Device,
+        constant_layout: &wgpu::BindGroupLayout,
+        sampler: &wgpu::Sampler,
+        uniforms: &wgpu::Buffer,
+    ) -> Self {
         let constants = device.create_bind_group(&wgpu::BindGroupDescriptor {
             label: Some("iced_wgpu::image constants bind group"),
             layout: constant_layout,
@@ -102,28 +152,18 @@ impl Layer {
         );
 
         Self {
-            uniforms,
             constants,
             instances,
             instance_count: 0,
         }
     }
 
-    fn prepare(
+    fn upload(
         &mut self,
         device: &wgpu::Device,
         queue: &wgpu::Queue,
         instances: &[Instance],
-        transformation: Transformation,
     ) {
-        queue.write_buffer(
-            &self.uniforms,
-            0,
-            bytemuck::bytes_of(&Uniforms {
-                transform: transformation.into(),
-            }),
-        );
-
         let _ = self.instances.resize(device, instances.len());
         let _ = self.instances.write(queue, 0, instances);
 
@@ -146,37 +186,25 @@ impl Pipeline {
     pub fn new(device: &wgpu::Device, format: wgpu::TextureFormat) -> Self {
         use wgpu::util::DeviceExt;
 
-        let to_wgpu = |method: FilterMethod| match method {
-            FilterMethod::Linear => wgpu::FilterMode::Linear,
-            FilterMethod::Nearest => wgpu::FilterMode::Nearest,
-        };
-
-        let mut sampler: [Option<Sampler>; SAMPLER_COUNT] =
-            [None, None, None, None];
-
-        let filter = [FilterMethod::Linear, FilterMethod::Nearest];
-        for min in 0..filter.len() {
-            for mag in 0..filter.len() {
-                sampler[to_index(&TextureFilter {
-                    min: filter[min],
-                    mag: filter[mag],
-                })] = Some(device.create_sampler(&wgpu::SamplerDescriptor {
-                    address_mode_u: wgpu::AddressMode::ClampToEdge,
-                    address_mode_v: wgpu::AddressMode::ClampToEdge,
-                    address_mode_w: wgpu::AddressMode::ClampToEdge,
-                    mag_filter: to_wgpu(filter[mag]),
-                    min_filter: to_wgpu(filter[min]),
-                    mipmap_filter: wgpu::FilterMode::Linear,
-                    ..Default::default()
-                }));
-            }
-        }
-        let sampler = [
-            sampler[0].take().unwrap(),
-            sampler[1].take().unwrap(),
-            sampler[2].take().unwrap(),
-            sampler[3].take().unwrap(),
-        ];
+        let nearest_sampler = device.create_sampler(&wgpu::SamplerDescriptor {
+            address_mode_u: wgpu::AddressMode::ClampToEdge,
+            address_mode_v: wgpu::AddressMode::ClampToEdge,
+            address_mode_w: wgpu::AddressMode::ClampToEdge,
+            min_filter: wgpu::FilterMode::Nearest,
+            mag_filter: wgpu::FilterMode::Nearest,
+            mipmap_filter: wgpu::FilterMode::Nearest,
+            ..Default::default()
+        });
+
+        let linear_sampler = device.create_sampler(&wgpu::SamplerDescriptor {
+            address_mode_u: wgpu::AddressMode::ClampToEdge,
+            address_mode_v: wgpu::AddressMode::ClampToEdge,
+            address_mode_w: wgpu::AddressMode::ClampToEdge,
+            min_filter: wgpu::FilterMode::Linear,
+            mag_filter: wgpu::FilterMode::Linear,
+            mipmap_filter: wgpu::FilterMode::Linear,
+            ..Default::default()
+        });
 
         let constant_layout =
             device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
@@ -338,7 +366,8 @@ impl Pipeline {
             pipeline,
             vertices,
             indices,
-            sampler,
+            nearest_sampler,
+            linear_sampler,
             texture,
             texture_version: texture_atlas.layer_count(),
             texture_atlas,
@@ -381,8 +410,8 @@ impl Pipeline {
         #[cfg(feature = "tracing")]
         let _ = info_span!("Wgpu::Image", "DRAW").entered();
 
-        let mut instances: [Vec<Instance>; SAMPLER_COUNT] =
-            [Vec::new(), Vec::new(), Vec::new(), Vec::new()];
+        let nearest_instances: &mut Vec<Instance> = &mut Vec::new();
+        let linear_instances: &mut Vec<Instance> = &mut Vec::new();
 
         #[cfg(feature = "image")]
         let mut raster_cache = self.raster_cache.borrow_mut();
@@ -393,7 +422,11 @@ impl Pipeline {
         for image in images {
             match &image {
                 #[cfg(feature = "image")]
-                layer::Image::Raster { handle, bounds } => {
+                layer::Image::Raster {
+                    handle,
+                    filter_method,
+                    bounds,
+                } => {
                     if let Some(atlas_entry) = raster_cache.upload(
                         device,
                         encoder,
@@ -404,7 +437,12 @@ impl Pipeline {
                             [bounds.x, bounds.y],
                             [bounds.width, bounds.height],
                             atlas_entry,
-                            &mut instances[to_index(handle.filter())],
+                            match filter_method {
+                                image::FilterMethod::Nearest => {
+                                    nearest_instances
+                                }
+                                image::FilterMethod::Linear => linear_instances,
+                            },
                         );
                     }
                 }
@@ -432,7 +470,7 @@ impl Pipeline {
                             [bounds.x, bounds.y],
                             size,
                             atlas_entry,
-                            &mut instances[to_index(&TextureFilter::default())],
+                            nearest_instances,
                         );
                     }
                 }
@@ -441,7 +479,7 @@ impl Pipeline {
             }
         }
 
-        if instances.is_empty() {
+        if nearest_instances.is_empty() && linear_instances.is_empty() {
             return;
         }
 
@@ -466,24 +504,24 @@ impl Pipeline {
         }
 
         if self.layers.len() <= self.prepare_layer {
-            self.layers.push([None, None, None, None]);
+            self.layers.push(Layer::new(
+                device,
+                &self.constant_layout,
+                &self.nearest_sampler,
+                &self.linear_sampler,
+            ));
         }
-        for (i, instances) in instances.iter_mut().enumerate() {
-            let layer = &mut self.layers[self.prepare_layer][i];
-            if !instances.is_empty() {
-                if layer.is_none() {
-                    *layer = Some(Layer::new(
-                        device,
-                        &self.constant_layout,
-                        &self.sampler[i],
-                    ))
-                }
-            }
 
-            if let Some(layer) = layer {
-                layer.prepare(device, queue, instances, transformation);
-            }
-        }
+        let layer = &mut self.layers[self.prepare_layer];
+
+        layer.prepare(
+            device,
+            queue,
+            &nearest_instances,
+            &linear_instances,
+            transformation,
+        );
+
         self.prepare_layer += 1;
     }
 
@@ -493,28 +531,24 @@ impl Pipeline {
         bounds: Rectangle<u32>,
         render_pass: &mut wgpu::RenderPass<'a>,
     ) {
-        if let Some(layer_group) = self.layers.get(layer) {
-            for layer in layer_group.iter() {
-                if let Some(layer) = layer {
-                    render_pass.set_pipeline(&self.pipeline);
-
-                    render_pass.set_scissor_rect(
-                        bounds.x,
-                        bounds.y,
-                        bounds.width,
-                        bounds.height,
-                    );
-
-                    render_pass.set_bind_group(1, &self.texture, &[]);
-                    render_pass.set_index_buffer(
-                        self.indices.slice(..),
-                        wgpu::IndexFormat::Uint16,
-                    );
-                    render_pass.set_vertex_buffer(0, self.vertices.slice(..));
-
-                    layer.render(render_pass);
-                }
-            }
+        if let Some(layer) = self.layers.get(layer) {
+            render_pass.set_pipeline(&self.pipeline);
+
+            render_pass.set_scissor_rect(
+                bounds.x,
+                bounds.y,
+                bounds.width,
+                bounds.height,
+            );
+
+            render_pass.set_bind_group(1, &self.texture, &[]);
+            render_pass.set_index_buffer(
+                self.indices.slice(..),
+                wgpu::IndexFormat::Uint16,
+            );
+            render_pass.set_vertex_buffer(0, self.vertices.slice(..));
+
+            layer.render(render_pass);
         }
     }
 
@@ -529,14 +563,6 @@ impl Pipeline {
     }
 }
 
-fn to_index(filter: &TextureFilter) -> usize {
-    let to_index = |m| match m {
-        FilterMethod::Linear => 0,
-        FilterMethod::Nearest => 1,
-    };
-    return (to_index(filter.mag) << 1) | (to_index(filter.min));
-}
-
 #[repr(C)]
 #[derive(Clone, Copy, Zeroable, Pod)]
 pub struct Vertex {
@@ -571,7 +597,7 @@ struct Instance {
 }
 
 impl Instance {
-    pub const INITIAL: usize = 1_000;
+    pub const INITIAL: usize = 20;
 }
 
 #[repr(C)]
diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs
index b251538e..286801e6 100644
--- a/wgpu/src/layer.rs
+++ b/wgpu/src/layer.rs
@@ -186,11 +186,16 @@ impl<'a> Layer<'a> {
 
                 layer.quads.add(quad, background);
             }
-            Primitive::Image { handle, bounds } => {
+            Primitive::Image {
+                handle,
+                filter_method,
+                bounds,
+            } => {
                 let layer = &mut layers[current_layer];
 
                 layer.images.push(Image::Raster {
                     handle: handle.clone(),
+                    filter_method: *filter_method,
                     bounds: *bounds + translation,
                 });
             }
diff --git a/wgpu/src/layer/image.rs b/wgpu/src/layer/image.rs
index 0de589f8..facbe192 100644
--- a/wgpu/src/layer/image.rs
+++ b/wgpu/src/layer/image.rs
@@ -10,6 +10,9 @@ pub enum Image {
         /// The handle of a raster image.
         handle: image::Handle,
 
+        /// The filter method of a raster image.
+        filter_method: image::FilterMethod,
+
         /// The bounds of the image.
         bounds: Rectangle,
     },
-- 
cgit 


From 9d560c813566ba04be3e23ae1b14861365485b57 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector@hecrj.dev>
Date: Sat, 11 Nov 2023 07:27:38 +0100
Subject: Fix unnecessary references in `iced_wgpu::image`

---
 wgpu/src/image.rs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

(limited to 'wgpu')

diff --git a/wgpu/src/image.rs b/wgpu/src/image.rs
index 1a88c6ae..b78802c7 100644
--- a/wgpu/src/image.rs
+++ b/wgpu/src/image.rs
@@ -131,7 +131,7 @@ impl Data {
                     binding: 0,
                     resource: wgpu::BindingResource::Buffer(
                         wgpu::BufferBinding {
-                            buffer: &uniforms,
+                            buffer: uniforms,
                             offset: 0,
                             size: None,
                         },
@@ -517,8 +517,8 @@ impl Pipeline {
         layer.prepare(
             device,
             queue,
-            &nearest_instances,
-            &linear_instances,
+            nearest_instances,
+            linear_instances,
             transformation,
         );
 
-- 
cgit 


From 781ef1f94c4859aeeb852f801b72be095b8ff82b Mon Sep 17 00:00:00 2001
From: Bingus <shankern@protonmail.com>
Date: Thu, 14 Sep 2023 13:58:36 -0700
Subject: Added support for custom shader widget for iced_wgpu backend.

---
 wgpu/src/backend.rs           | 64 +++++++++++++++++++++++++++++++++++++++--
 wgpu/src/custom.rs            | 66 +++++++++++++++++++++++++++++++++++++++++++
 wgpu/src/layer.rs             | 16 +++++++++++
 wgpu/src/lib.rs               |  1 +
 wgpu/src/primitive.rs         | 36 +++++++++++++++++++++++
 wgpu/src/window/compositor.rs |  2 ++
 6 files changed, 182 insertions(+), 3 deletions(-)
 create mode 100644 wgpu/src/custom.rs

(limited to 'wgpu')

diff --git a/wgpu/src/backend.rs b/wgpu/src/backend.rs
index 2bd29f42..907611d9 100644
--- a/wgpu/src/backend.rs
+++ b/wgpu/src/backend.rs
@@ -3,9 +3,7 @@ use crate::graphics::backend;
 use crate::graphics::color;
 use crate::graphics::{Transformation, Viewport};
 use crate::primitive::{self, Primitive};
-use crate::quad;
-use crate::text;
-use crate::triangle;
+use crate::{custom, quad, text, triangle};
 use crate::{Layer, Settings};
 
 #[cfg(feature = "tracing")]
@@ -25,6 +23,7 @@ pub struct Backend {
     quad_pipeline: quad::Pipeline,
     text_pipeline: text::Pipeline,
     triangle_pipeline: triangle::Pipeline,
+    pipeline_storage: custom::Storage,
 
     #[cfg(any(feature = "image", feature = "svg"))]
     image_pipeline: image::Pipeline,
@@ -50,6 +49,7 @@ impl Backend {
             quad_pipeline,
             text_pipeline,
             triangle_pipeline,
+            pipeline_storage: custom::Storage::default(),
 
             #[cfg(any(feature = "image", feature = "svg"))]
             image_pipeline,
@@ -66,6 +66,7 @@ impl Backend {
         queue: &wgpu::Queue,
         encoder: &mut wgpu::CommandEncoder,
         clear_color: Option<Color>,
+        format: wgpu::TextureFormat,
         frame: &wgpu::TextureView,
         primitives: &[Primitive],
         viewport: &Viewport,
@@ -88,6 +89,7 @@ impl Backend {
         self.prepare(
             device,
             queue,
+            format,
             encoder,
             scale_factor,
             target_size,
@@ -117,6 +119,7 @@ impl Backend {
         &mut self,
         device: &wgpu::Device,
         queue: &wgpu::Queue,
+        format: wgpu::TextureFormat,
         _encoder: &mut wgpu::CommandEncoder,
         scale_factor: f32,
         target_size: Size<u32>,
@@ -179,6 +182,20 @@ impl Backend {
                     target_size,
                 );
             }
+
+            if !layer.shaders.is_empty() {
+                for shader in &layer.shaders {
+                    shader.primitive.prepare(
+                        format,
+                        device,
+                        queue,
+                        target_size,
+                        scale_factor,
+                        transformation,
+                        &mut self.pipeline_storage,
+                    );
+                }
+            }
         }
     }
 
@@ -302,6 +319,47 @@ impl Backend {
 
                 text_layer += 1;
             }
+
+            // kill render pass to let custom shaders get mut access to encoder
+            let _ = ManuallyDrop::into_inner(render_pass);
+
+            if !layer.shaders.is_empty() {
+                for shader in &layer.shaders {
+                    //This extra check is needed since each custom pipeline must set it's own
+                    //scissor rect, which will panic if bounds.w/h < 1
+                    let bounds = shader.bounds * scale_factor;
+
+                    if bounds.width < 1.0 || bounds.height < 1.0 {
+                        continue;
+                    }
+
+                    shader.primitive.render(
+                        &self.pipeline_storage,
+                        bounds.into(),
+                        target,
+                        target_size,
+                        encoder,
+                    );
+                }
+            }
+
+            // recreate and continue processing layers
+            render_pass = ManuallyDrop::new(encoder.begin_render_pass(
+                &wgpu::RenderPassDescriptor {
+                    label: Some("iced_wgpu::quad render pass"),
+                    color_attachments: &[Some(
+                        wgpu::RenderPassColorAttachment {
+                            view: target,
+                            resolve_target: None,
+                            ops: wgpu::Operations {
+                                load: wgpu::LoadOp::Load,
+                                store: true,
+                            },
+                        },
+                    )],
+                    depth_stencil_attachment: None,
+                },
+            ));
         }
 
         let _ = ManuallyDrop::into_inner(render_pass);
diff --git a/wgpu/src/custom.rs b/wgpu/src/custom.rs
new file mode 100644
index 00000000..65dd0496
--- /dev/null
+++ b/wgpu/src/custom.rs
@@ -0,0 +1,66 @@
+use crate::core::{Rectangle, Size};
+use crate::graphics::Transformation;
+use std::any::{Any, TypeId};
+use std::collections::HashMap;
+use std::fmt::Debug;
+
+/// Stores custom, user-provided pipelines.
+#[derive(Default, Debug)]
+pub struct Storage {
+    pipelines: HashMap<TypeId, Box<dyn Any>>,
+}
+
+impl Storage {
+    /// Returns `true` if `Storage` contains a pipeline with type `T`.
+    pub fn has<T: 'static>(&self) -> bool {
+        self.pipelines.get(&TypeId::of::<T>()).is_some()
+    }
+
+    /// Inserts the pipeline `T` in to [`Storage`].
+    pub fn store<T: 'static>(&mut self, pipeline: T) {
+        let _ = self.pipelines.insert(TypeId::of::<T>(), Box::new(pipeline));
+    }
+
+    /// Returns a reference to pipeline with type `T` if it exists in [`Storage`].
+    pub fn get<T: 'static>(&self) -> Option<&T> {
+        self.pipelines.get(&TypeId::of::<T>()).map(|pipeline| {
+            pipeline
+                .downcast_ref::<T>()
+                .expect("Pipeline with this type does not exist in Storage.")
+        })
+    }
+
+    /// Returns a mutable reference to pipeline `T` if it exists in [`Storage`].
+    pub fn get_mut<T: 'static>(&mut self) -> Option<&mut T> {
+        self.pipelines.get_mut(&TypeId::of::<T>()).map(|pipeline| {
+            pipeline
+                .downcast_mut::<T>()
+                .expect("Pipeline with this type does not exist in Storage.")
+        })
+    }
+}
+
+/// A set of methods which allows a [`Primitive`] to be rendered.
+pub trait Primitive: Debug + Send + Sync + 'static {
+    /// Processes the [`Primitive`], allowing for GPU buffer allocation.
+    fn prepare(
+        &self,
+        format: wgpu::TextureFormat,
+        device: &wgpu::Device,
+        queue: &wgpu::Queue,
+        target_size: Size<u32>,
+        scale_factor: f32,
+        transform: Transformation,
+        storage: &mut Storage,
+    );
+
+    /// Renders the [`Primitive`].
+    fn render(
+        &self,
+        storage: &Storage,
+        bounds: Rectangle<u32>,
+        target: &wgpu::TextureView,
+        target_size: Size<u32>,
+        encoder: &mut wgpu::CommandEncoder,
+    );
+}
diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs
index 286801e6..d451cbfd 100644
--- a/wgpu/src/layer.rs
+++ b/wgpu/src/layer.rs
@@ -34,6 +34,9 @@ pub struct Layer<'a> {
 
     /// The images of the [`Layer`].
     pub images: Vec<Image>,
+
+    /// The custom shader primitives of this [`Layer`].
+    pub shaders: Vec<primitive::Shader>,
 }
 
 impl<'a> Layer<'a> {
@@ -45,6 +48,7 @@ impl<'a> Layer<'a> {
             meshes: Vec::new(),
             text: Vec::new(),
             images: Vec::new(),
+            shaders: Vec::new(),
         }
     }
 
@@ -308,6 +312,18 @@ impl<'a> Layer<'a> {
                         }
                     }
                 },
+                primitive::Custom::Shader(shader) => {
+                    let layer = &mut layers[current_layer];
+
+                    let bounds = Rectangle::new(
+                        Point::new(translation.x, translation.y),
+                        shader.bounds.size(),
+                    );
+
+                    if layer.bounds.intersection(&bounds).is_some() {
+                        layer.shaders.push(shader.clone());
+                    }
+                }
             },
         }
     }
diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs
index 424dfeb3..13d8e886 100644
--- a/wgpu/src/lib.rs
+++ b/wgpu/src/lib.rs
@@ -29,6 +29,7 @@
     rustdoc::broken_intra_doc_links
 )]
 #![cfg_attr(docsrs, feature(doc_auto_cfg))]
+pub mod custom;
 pub mod layer;
 pub mod primitive;
 pub mod settings;
diff --git a/wgpu/src/primitive.rs b/wgpu/src/primitive.rs
index 8dbf3008..4347dcda 100644
--- a/wgpu/src/primitive.rs
+++ b/wgpu/src/primitive.rs
@@ -1,6 +1,10 @@
 //! Draw using different graphical primitives.
 use crate::core::Rectangle;
+use crate::custom;
 use crate::graphics::{Damage, Mesh};
+use std::any::Any;
+use std::fmt::Debug;
+use std::sync::Arc;
 
 /// The graphical primitives supported by `iced_wgpu`.
 pub type Primitive = crate::graphics::Primitive<Custom>;
@@ -10,12 +14,44 @@ pub type Primitive = crate::graphics::Primitive<Custom>;
 pub enum Custom {
     /// A mesh primitive.
     Mesh(Mesh),
+    /// A custom shader primitive
+    Shader(Shader),
+}
+
+impl Custom {
+    /// Create a custom [`Shader`] primitive.
+    pub fn shader<P: custom::Primitive>(
+        bounds: Rectangle,
+        primitive: P,
+    ) -> Self {
+        Self::Shader(Shader {
+            bounds,
+            primitive: Arc::new(primitive),
+        })
+    }
 }
 
 impl Damage for Custom {
     fn bounds(&self) -> Rectangle {
         match self {
             Self::Mesh(mesh) => mesh.bounds(),
+            Self::Shader(shader) => shader.bounds,
         }
     }
 }
+
+#[derive(Clone, Debug)]
+/// A custom primitive which can be used to render primitives associated with a custom pipeline.
+pub struct Shader {
+    /// The bounds of the [`Shader`].
+    pub bounds: Rectangle,
+
+    /// The [`custom::Primitive`] to render.
+    pub primitive: Arc<dyn custom::Primitive>,
+}
+
+impl PartialEq for Shader {
+    fn eq(&self, other: &Self) -> bool {
+        self.primitive.type_id() == other.primitive.type_id()
+    }
+}
diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs
index 1ddbe5fe..90d64e17 100644
--- a/wgpu/src/window/compositor.rs
+++ b/wgpu/src/window/compositor.rs
@@ -178,6 +178,7 @@ pub fn present<Theme, T: AsRef<str>>(
                 &compositor.queue,
                 &mut encoder,
                 Some(background_color),
+                frame.texture.format(),
                 view,
                 primitives,
                 viewport,
@@ -357,6 +358,7 @@ pub fn screenshot<Theme, T: AsRef<str>>(
         &compositor.queue,
         &mut encoder,
         Some(background_color),
+        texture.format(),
         &view,
         primitives,
         viewport,
-- 
cgit 


From 36e85215932079fa324cfefb620602ad79f7df3d Mon Sep 17 00:00:00 2001
From: Bingus <shankern@protonmail.com>
Date: Mon, 18 Sep 2023 09:04:28 -0700
Subject: Removed `Into` for Rectangle<f32> from u32

---
 wgpu/src/backend.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'wgpu')

diff --git a/wgpu/src/backend.rs b/wgpu/src/backend.rs
index 907611d9..ace2ef95 100644
--- a/wgpu/src/backend.rs
+++ b/wgpu/src/backend.rs
@@ -335,7 +335,7 @@ impl Backend {
 
                     shader.primitive.render(
                         &self.pipeline_storage,
-                        bounds.into(),
+                        bounds.snap(),
                         target,
                         target_size,
                         encoder,
-- 
cgit 


From de9420e7df7d909bca611c360182dec54c5b1aae Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector@hecrj.dev>
Date: Tue, 14 Nov 2023 11:33:04 +0100
Subject: Fix latest `wgpu` changes

---
 wgpu/src/backend.rs | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

(limited to 'wgpu')

diff --git a/wgpu/src/backend.rs b/wgpu/src/backend.rs
index ace2ef95..27ef0b3c 100644
--- a/wgpu/src/backend.rs
+++ b/wgpu/src/backend.rs
@@ -353,11 +353,13 @@ impl Backend {
                             resolve_target: None,
                             ops: wgpu::Operations {
                                 load: wgpu::LoadOp::Load,
-                                store: true,
+                                store: wgpu::StoreOp::Store,
                             },
                         },
                     )],
                     depth_stencil_attachment: None,
+                    timestamp_writes: None,
+                    occlusion_query_set: None,
                 },
             ));
         }
-- 
cgit 


From 46a48af97fa472e1158e07d4deb988c5601197e0 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector@hecrj.dev>
Date: Tue, 14 Nov 2023 11:34:15 +0100
Subject: Write missing documentation for `custom` module in `iced_wgpu`

---
 wgpu/src/custom.rs | 1 +
 1 file changed, 1 insertion(+)

(limited to 'wgpu')

diff --git a/wgpu/src/custom.rs b/wgpu/src/custom.rs
index 65dd0496..65a6f133 100644
--- a/wgpu/src/custom.rs
+++ b/wgpu/src/custom.rs
@@ -1,3 +1,4 @@
+//! Draw custom primitives.
 use crate::core::{Rectangle, Size};
 use crate::graphics::Transformation;
 use std::any::{Any, TypeId};
-- 
cgit 


From 9489e29e6619b14ed9f41a8887c4b34158266f71 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector@hecrj.dev>
Date: Tue, 14 Nov 2023 12:49:49 +0100
Subject: Re-organize `custom` module as `pipeline` module

... and move `Shader` widget to `iced_widget` crate
---
 wgpu/src/backend.rs            |  29 +++++-----
 wgpu/src/custom.rs             |  63 +---------------------
 wgpu/src/layer.rs              |  19 ++++---
 wgpu/src/lib.rs                |   1 -
 wgpu/src/primitive.rs          |  43 +++------------
 wgpu/src/primitive/pipeline.rs | 117 +++++++++++++++++++++++++++++++++++++++++
 6 files changed, 154 insertions(+), 118 deletions(-)
 create mode 100644 wgpu/src/primitive/pipeline.rs

(limited to 'wgpu')

diff --git a/wgpu/src/backend.rs b/wgpu/src/backend.rs
index 27ef0b3c..f89bcee1 100644
--- a/wgpu/src/backend.rs
+++ b/wgpu/src/backend.rs
@@ -2,8 +2,11 @@ use crate::core::{Color, Size};
 use crate::graphics::backend;
 use crate::graphics::color;
 use crate::graphics::{Transformation, Viewport};
+use crate::primitive::pipeline;
 use crate::primitive::{self, Primitive};
-use crate::{custom, quad, text, triangle};
+use crate::quad;
+use crate::text;
+use crate::triangle;
 use crate::{Layer, Settings};
 
 #[cfg(feature = "tracing")]
@@ -23,7 +26,7 @@ pub struct Backend {
     quad_pipeline: quad::Pipeline,
     text_pipeline: text::Pipeline,
     triangle_pipeline: triangle::Pipeline,
-    pipeline_storage: custom::Storage,
+    pipeline_storage: pipeline::Storage,
 
     #[cfg(any(feature = "image", feature = "svg"))]
     image_pipeline: image::Pipeline,
@@ -49,7 +52,7 @@ impl Backend {
             quad_pipeline,
             text_pipeline,
             triangle_pipeline,
-            pipeline_storage: custom::Storage::default(),
+            pipeline_storage: pipeline::Storage::default(),
 
             #[cfg(any(feature = "image", feature = "svg"))]
             image_pipeline,
@@ -183,9 +186,9 @@ impl Backend {
                 );
             }
 
-            if !layer.shaders.is_empty() {
-                for shader in &layer.shaders {
-                    shader.primitive.prepare(
+            if !layer.pipelines.is_empty() {
+                for pipeline in &layer.pipelines {
+                    pipeline.primitive.prepare(
                         format,
                         device,
                         queue,
@@ -323,19 +326,17 @@ impl Backend {
             // kill render pass to let custom shaders get mut access to encoder
             let _ = ManuallyDrop::into_inner(render_pass);
 
-            if !layer.shaders.is_empty() {
-                for shader in &layer.shaders {
-                    //This extra check is needed since each custom pipeline must set it's own
-                    //scissor rect, which will panic if bounds.w/h < 1
-                    let bounds = shader.bounds * scale_factor;
+            if !layer.pipelines.is_empty() {
+                for pipeline in &layer.pipelines {
+                    let bounds = (pipeline.bounds * scale_factor).snap();
 
-                    if bounds.width < 1.0 || bounds.height < 1.0 {
+                    if bounds.width < 1 || bounds.height < 1 {
                         continue;
                     }
 
-                    shader.primitive.render(
+                    pipeline.primitive.render(
                         &self.pipeline_storage,
-                        bounds.snap(),
+                        bounds,
                         target,
                         target_size,
                         encoder,
diff --git a/wgpu/src/custom.rs b/wgpu/src/custom.rs
index 65a6f133..98e2b396 100644
--- a/wgpu/src/custom.rs
+++ b/wgpu/src/custom.rs
@@ -1,67 +1,8 @@
 //! Draw custom primitives.
 use crate::core::{Rectangle, Size};
 use crate::graphics::Transformation;
+use crate::primitive;
+
 use std::any::{Any, TypeId};
 use std::collections::HashMap;
 use std::fmt::Debug;
-
-/// Stores custom, user-provided pipelines.
-#[derive(Default, Debug)]
-pub struct Storage {
-    pipelines: HashMap<TypeId, Box<dyn Any>>,
-}
-
-impl Storage {
-    /// Returns `true` if `Storage` contains a pipeline with type `T`.
-    pub fn has<T: 'static>(&self) -> bool {
-        self.pipelines.get(&TypeId::of::<T>()).is_some()
-    }
-
-    /// Inserts the pipeline `T` in to [`Storage`].
-    pub fn store<T: 'static>(&mut self, pipeline: T) {
-        let _ = self.pipelines.insert(TypeId::of::<T>(), Box::new(pipeline));
-    }
-
-    /// Returns a reference to pipeline with type `T` if it exists in [`Storage`].
-    pub fn get<T: 'static>(&self) -> Option<&T> {
-        self.pipelines.get(&TypeId::of::<T>()).map(|pipeline| {
-            pipeline
-                .downcast_ref::<T>()
-                .expect("Pipeline with this type does not exist in Storage.")
-        })
-    }
-
-    /// Returns a mutable reference to pipeline `T` if it exists in [`Storage`].
-    pub fn get_mut<T: 'static>(&mut self) -> Option<&mut T> {
-        self.pipelines.get_mut(&TypeId::of::<T>()).map(|pipeline| {
-            pipeline
-                .downcast_mut::<T>()
-                .expect("Pipeline with this type does not exist in Storage.")
-        })
-    }
-}
-
-/// A set of methods which allows a [`Primitive`] to be rendered.
-pub trait Primitive: Debug + Send + Sync + 'static {
-    /// Processes the [`Primitive`], allowing for GPU buffer allocation.
-    fn prepare(
-        &self,
-        format: wgpu::TextureFormat,
-        device: &wgpu::Device,
-        queue: &wgpu::Queue,
-        target_size: Size<u32>,
-        scale_factor: f32,
-        transform: Transformation,
-        storage: &mut Storage,
-    );
-
-    /// Renders the [`Primitive`].
-    fn render(
-        &self,
-        storage: &Storage,
-        bounds: Rectangle<u32>,
-        target: &wgpu::TextureView,
-        target_size: Size<u32>,
-        encoder: &mut wgpu::CommandEncoder,
-    );
-}
diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs
index d451cbfd..33aaf670 100644
--- a/wgpu/src/layer.rs
+++ b/wgpu/src/layer.rs
@@ -35,8 +35,8 @@ pub struct Layer<'a> {
     /// The images of the [`Layer`].
     pub images: Vec<Image>,
 
-    /// The custom shader primitives of this [`Layer`].
-    pub shaders: Vec<primitive::Shader>,
+    /// The custom pipelines of this [`Layer`].
+    pub pipelines: Vec<primitive::Pipeline>,
 }
 
 impl<'a> Layer<'a> {
@@ -48,7 +48,7 @@ impl<'a> Layer<'a> {
             meshes: Vec::new(),
             text: Vec::new(),
             images: Vec::new(),
-            shaders: Vec::new(),
+            pipelines: Vec::new(),
         }
     }
 
@@ -312,16 +312,21 @@ impl<'a> Layer<'a> {
                         }
                     }
                 },
-                primitive::Custom::Shader(shader) => {
+                primitive::Custom::Pipeline(pipeline) => {
                     let layer = &mut layers[current_layer];
 
                     let bounds = Rectangle::new(
                         Point::new(translation.x, translation.y),
-                        shader.bounds.size(),
+                        pipeline.bounds.size(),
                     );
 
-                    if layer.bounds.intersection(&bounds).is_some() {
-                        layer.shaders.push(shader.clone());
+                    if let Some(clip_bounds) =
+                        layer.bounds.intersection(&bounds)
+                    {
+                        layer.pipelines.push(primitive::Pipeline {
+                            bounds: clip_bounds,
+                            primitive: pipeline.primitive.clone(),
+                        });
                     }
                 }
             },
diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs
index 13d8e886..424dfeb3 100644
--- a/wgpu/src/lib.rs
+++ b/wgpu/src/lib.rs
@@ -29,7 +29,6 @@
     rustdoc::broken_intra_doc_links
 )]
 #![cfg_attr(docsrs, feature(doc_auto_cfg))]
-pub mod custom;
 pub mod layer;
 pub mod primitive;
 pub mod settings;
diff --git a/wgpu/src/primitive.rs b/wgpu/src/primitive.rs
index 4347dcda..fff927ea 100644
--- a/wgpu/src/primitive.rs
+++ b/wgpu/src/primitive.rs
@@ -1,10 +1,12 @@
 //! Draw using different graphical primitives.
+pub mod pipeline;
+
+pub use pipeline::Pipeline;
+
 use crate::core::Rectangle;
-use crate::custom;
 use crate::graphics::{Damage, Mesh};
-use std::any::Any;
+
 use std::fmt::Debug;
-use std::sync::Arc;
 
 /// The graphical primitives supported by `iced_wgpu`.
 pub type Primitive = crate::graphics::Primitive<Custom>;
@@ -14,44 +16,15 @@ pub type Primitive = crate::graphics::Primitive<Custom>;
 pub enum Custom {
     /// A mesh primitive.
     Mesh(Mesh),
-    /// A custom shader primitive
-    Shader(Shader),
-}
-
-impl Custom {
-    /// Create a custom [`Shader`] primitive.
-    pub fn shader<P: custom::Primitive>(
-        bounds: Rectangle,
-        primitive: P,
-    ) -> Self {
-        Self::Shader(Shader {
-            bounds,
-            primitive: Arc::new(primitive),
-        })
-    }
+    /// A custom pipeline primitive.
+    Pipeline(Pipeline),
 }
 
 impl Damage for Custom {
     fn bounds(&self) -> Rectangle {
         match self {
             Self::Mesh(mesh) => mesh.bounds(),
-            Self::Shader(shader) => shader.bounds,
+            Self::Pipeline(pipeline) => pipeline.bounds,
         }
     }
 }
-
-#[derive(Clone, Debug)]
-/// A custom primitive which can be used to render primitives associated with a custom pipeline.
-pub struct Shader {
-    /// The bounds of the [`Shader`].
-    pub bounds: Rectangle,
-
-    /// The [`custom::Primitive`] to render.
-    pub primitive: Arc<dyn custom::Primitive>,
-}
-
-impl PartialEq for Shader {
-    fn eq(&self, other: &Self) -> bool {
-        self.primitive.type_id() == other.primitive.type_id()
-    }
-}
diff --git a/wgpu/src/primitive/pipeline.rs b/wgpu/src/primitive/pipeline.rs
new file mode 100644
index 00000000..b59aeff1
--- /dev/null
+++ b/wgpu/src/primitive/pipeline.rs
@@ -0,0 +1,117 @@
+//! Draw primitives using custom pipelines.
+use crate::core::{Rectangle, Size};
+use crate::graphics::Transformation;
+
+use std::any::{Any, TypeId};
+use std::collections::HashMap;
+use std::fmt::Debug;
+use std::sync::Arc;
+
+#[derive(Clone, Debug)]
+/// A custom primitive which can be used to render primitives associated with a custom pipeline.
+pub struct Pipeline {
+    /// The bounds of the [`Shader`].
+    pub bounds: Rectangle,
+
+    /// The [`custom::Primitive`] to render.
+    pub primitive: Arc<dyn Primitive>,
+}
+
+impl Pipeline {
+    /// Creates a new [`Pipeline`] with the given [`Primitive`].
+    pub fn new(bounds: Rectangle, primitive: impl Primitive) -> Self {
+        Pipeline {
+            bounds,
+            primitive: Arc::new(primitive),
+        }
+    }
+}
+
+impl PartialEq for Pipeline {
+    fn eq(&self, other: &Self) -> bool {
+        self.primitive.type_id() == other.primitive.type_id()
+    }
+}
+
+/// A set of methods which allows a [`Primitive`] to be rendered.
+pub trait Primitive: Debug + Send + Sync + 'static {
+    /// Processes the [`Primitive`], allowing for GPU buffer allocation.
+    fn prepare(
+        &self,
+        format: wgpu::TextureFormat,
+        device: &wgpu::Device,
+        queue: &wgpu::Queue,
+        target_size: Size<u32>,
+        scale_factor: f32,
+        transform: Transformation,
+        storage: &mut Storage,
+    );
+
+    /// Renders the [`Primitive`].
+    fn render(
+        &self,
+        storage: &Storage,
+        bounds: Rectangle<u32>,
+        target: &wgpu::TextureView,
+        target_size: Size<u32>,
+        encoder: &mut wgpu::CommandEncoder,
+    );
+}
+
+/// A renderer than can draw custom pipeline primitives.
+pub trait Renderer: crate::core::Renderer {
+    /// Draws a custom pipeline primitive.
+    fn draw_pipeline_primitive(
+        &mut self,
+        bounds: Rectangle,
+        primitive: impl Primitive,
+    );
+}
+
+impl<Theme> Renderer for crate::Renderer<Theme> {
+    fn draw_pipeline_primitive(
+        &mut self,
+        bounds: Rectangle,
+        primitive: impl Primitive,
+    ) {
+        self.draw_primitive(super::Primitive::Custom(super::Custom::Pipeline(
+            Pipeline::new(bounds, primitive),
+        )));
+    }
+}
+
+/// Stores custom, user-provided pipelines.
+#[derive(Default, Debug)]
+pub struct Storage {
+    pipelines: HashMap<TypeId, Box<dyn Any>>,
+}
+
+impl Storage {
+    /// Returns `true` if `Storage` contains a pipeline with type `T`.
+    pub fn has<T: 'static>(&self) -> bool {
+        self.pipelines.get(&TypeId::of::<T>()).is_some()
+    }
+
+    /// Inserts the pipeline `T` in to [`Storage`].
+    pub fn store<T: 'static>(&mut self, pipeline: T) {
+        let _ = self.pipelines.insert(TypeId::of::<T>(), Box::new(pipeline));
+    }
+
+    /// Returns a reference to pipeline with type `T` if it exists in [`Storage`].
+    pub fn get<T: 'static>(&self) -> Option<&T> {
+        self.pipelines.get(&TypeId::of::<T>()).map(|pipeline| {
+            pipeline
+                .downcast_ref::<T>()
+                .expect("Pipeline with this type does not exist in Storage.")
+        })
+    }
+
+    /// Returns a mutable reference to pipeline `T` if it exists in [`Storage`].
+    pub fn get_mut<T: 'static>(&mut self) -> Option<&mut T> {
+        self.pipelines.get_mut(&TypeId::of::<T>()).map(|pipeline| {
+            pipeline
+                .downcast_mut::<T>()
+                .expect("Pipeline with this type does not exist in Storage.")
+        })
+    }
+}
-- 
cgit 


From 280d3736d59b62c4087fe980c187953cc2be83d2 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector@hecrj.dev>
Date: Tue, 14 Nov 2023 13:23:28 +0100
Subject: Fix broken intra-doc links

---
 wgpu/src/primitive/pipeline.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'wgpu')

diff --git a/wgpu/src/primitive/pipeline.rs b/wgpu/src/primitive/pipeline.rs
index b59aeff1..5dbd6697 100644
--- a/wgpu/src/primitive/pipeline.rs
+++ b/wgpu/src/primitive/pipeline.rs
@@ -10,10 +10,10 @@ use std::sync::Arc;
 #[derive(Clone, Debug)]
 /// A custom primitive which can be used to render primitives associated with a custom pipeline.
 pub struct Pipeline {
-    /// The bounds of the [`Shader`].
+    /// The bounds of the [`Pipeline`].
     pub bounds: Rectangle,
 
-    /// The [`custom::Primitive`] to render.
+    /// The [`Primitive`] to render.
     pub primitive: Arc<dyn Primitive>,
 }
 
-- 
cgit 


From fee3bf0df4e3099ea74def738be8743b2b72d78a Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector@hecrj.dev>
Date: Tue, 14 Nov 2023 14:47:29 +0100
Subject: Kill current render pass only when custom pipelines are present in
 layer

---
 wgpu/src/backend.rs | 42 ++++++++++++++++++++----------------------
 1 file changed, 20 insertions(+), 22 deletions(-)

(limited to 'wgpu')

diff --git a/wgpu/src/backend.rs b/wgpu/src/backend.rs
index f89bcee1..91ae777b 100644
--- a/wgpu/src/backend.rs
+++ b/wgpu/src/backend.rs
@@ -323,10 +323,9 @@ impl Backend {
                 text_layer += 1;
             }
 
-            // kill render pass to let custom shaders get mut access to encoder
-            let _ = ManuallyDrop::into_inner(render_pass);
-
             if !layer.pipelines.is_empty() {
+                let _ = ManuallyDrop::into_inner(render_pass);
+
                 for pipeline in &layer.pipelines {
                     let bounds = (pipeline.bounds * scale_factor).snap();
 
@@ -342,27 +341,26 @@ impl Backend {
                         encoder,
                     );
                 }
-            }
 
-            // recreate and continue processing layers
-            render_pass = ManuallyDrop::new(encoder.begin_render_pass(
-                &wgpu::RenderPassDescriptor {
-                    label: Some("iced_wgpu::quad render pass"),
-                    color_attachments: &[Some(
-                        wgpu::RenderPassColorAttachment {
-                            view: target,
-                            resolve_target: None,
-                            ops: wgpu::Operations {
-                                load: wgpu::LoadOp::Load,
-                                store: wgpu::StoreOp::Store,
+                render_pass = ManuallyDrop::new(encoder.begin_render_pass(
+                    &wgpu::RenderPassDescriptor {
+                        label: Some("iced_wgpu::quad render pass"),
+                        color_attachments: &[Some(
+                            wgpu::RenderPassColorAttachment {
+                                view: target,
+                                resolve_target: None,
+                                ops: wgpu::Operations {
+                                    load: wgpu::LoadOp::Load,
+                                    store: wgpu::StoreOp::Store,
+                                },
                             },
-                        },
-                    )],
-                    depth_stencil_attachment: None,
-                    timestamp_writes: None,
-                    occlusion_query_set: None,
-                },
-            ));
+                        )],
+                        depth_stencil_attachment: None,
+                        timestamp_writes: None,
+                        occlusion_query_set: None,
+                    },
+                ));
+            }
         }
 
         let _ = ManuallyDrop::into_inner(render_pass);
-- 
cgit 


From b1b2467b45e16185cc17df00b4c75700435cd46e Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector@hecrj.dev>
Date: Tue, 14 Nov 2023 14:50:57 +0100
Subject: Fix render pass label in `iced_wgpu`

---
 wgpu/src/backend.rs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

(limited to 'wgpu')

diff --git a/wgpu/src/backend.rs b/wgpu/src/backend.rs
index 91ae777b..88caad06 100644
--- a/wgpu/src/backend.rs
+++ b/wgpu/src/backend.rs
@@ -222,7 +222,7 @@ impl Backend {
 
         let mut render_pass = ManuallyDrop::new(encoder.begin_render_pass(
             &wgpu::RenderPassDescriptor {
-                label: Some("iced_wgpu::quad render pass"),
+                label: Some("iced_wgpu render pass"),
                 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
                     view: target,
                     resolve_target: None,
@@ -285,7 +285,7 @@ impl Backend {
 
                 render_pass = ManuallyDrop::new(encoder.begin_render_pass(
                     &wgpu::RenderPassDescriptor {
-                        label: Some("iced_wgpu::quad render pass"),
+                        label: Some("iced_wgpu render pass"),
                         color_attachments: &[Some(
                             wgpu::RenderPassColorAttachment {
                                 view: target,
@@ -344,7 +344,7 @@ impl Backend {
 
                 render_pass = ManuallyDrop::new(encoder.begin_render_pass(
                     &wgpu::RenderPassDescriptor {
-                        label: Some("iced_wgpu::quad render pass"),
+                        label: Some("iced_wgpu render pass"),
                         color_attachments: &[Some(
                             wgpu::RenderPassColorAttachment {
                                 view: target,
-- 
cgit 


From 8f384c83be242f9318685530ee52dd6c27b2bb62 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector@hecrj.dev>
Date: Tue, 14 Nov 2023 15:54:10 +0100
Subject: Remove unsused `custom.rs` file in `iced_wgpu`

---
 wgpu/src/custom.rs | 8 --------
 1 file changed, 8 deletions(-)
 delete mode 100644 wgpu/src/custom.rs

(limited to 'wgpu')

diff --git a/wgpu/src/custom.rs b/wgpu/src/custom.rs
deleted file mode 100644
index 98e2b396..00000000
--- a/wgpu/src/custom.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-//! Draw custom primitives.
-use crate::core::{Rectangle, Size};
-use crate::graphics::Transformation;
-use crate::primitive;
-
-use std::any::{Any, TypeId};
-use std::collections::HashMap;
-use std::fmt::Debug;
-- 
cgit 


From ab7dae554cac801aeed5d9aa4d3850d50be86263 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector@hecrj.dev>
Date: Tue, 28 Nov 2023 23:13:38 +0100
Subject: Provide actual bounds to `Shader` primitives

... and allow for proper translation and scissoring.
---
 wgpu/src/backend.rs            |  8 ++++----
 wgpu/src/layer.rs              | 15 +++++++--------
 wgpu/src/layer/pipeline.rs     | 17 +++++++++++++++++
 wgpu/src/primitive/pipeline.rs |  5 ++---
 4 files changed, 30 insertions(+), 15 deletions(-)
 create mode 100644 wgpu/src/layer/pipeline.rs

(limited to 'wgpu')

diff --git a/wgpu/src/backend.rs b/wgpu/src/backend.rs
index 88caad06..25134d68 100644
--- a/wgpu/src/backend.rs
+++ b/wgpu/src/backend.rs
@@ -192,9 +192,9 @@ impl Backend {
                         format,
                         device,
                         queue,
+                        pipeline.bounds,
                         target_size,
                         scale_factor,
-                        transformation,
                         &mut self.pipeline_storage,
                     );
                 }
@@ -327,17 +327,17 @@ impl Backend {
                 let _ = ManuallyDrop::into_inner(render_pass);
 
                 for pipeline in &layer.pipelines {
-                    let bounds = (pipeline.bounds * scale_factor).snap();
+                    let viewport = (pipeline.viewport * scale_factor).snap();
 
-                    if bounds.width < 1 || bounds.height < 1 {
+                    if viewport.width < 1 || viewport.height < 1 {
                         continue;
                     }
 
                     pipeline.primitive.render(
                         &self.pipeline_storage,
-                        bounds,
                         target,
                         target_size,
+                        viewport,
                         encoder,
                     );
                 }
diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs
index 33aaf670..98e49f1a 100644
--- a/wgpu/src/layer.rs
+++ b/wgpu/src/layer.rs
@@ -1,11 +1,13 @@
 //! Organize rendering primitives into a flattened list of layers.
 mod image;
+mod pipeline;
 mod text;
 
 pub mod mesh;
 
 pub use image::Image;
 pub use mesh::Mesh;
+pub use pipeline::Pipeline;
 pub use text::Text;
 
 use crate::core;
@@ -36,7 +38,7 @@ pub struct Layer<'a> {
     pub images: Vec<Image>,
 
     /// The custom pipelines of this [`Layer`].
-    pub pipelines: Vec<primitive::Pipeline>,
+    pub pipelines: Vec<Pipeline>,
 }
 
 impl<'a> Layer<'a> {
@@ -314,17 +316,14 @@ impl<'a> Layer<'a> {
                 },
                 primitive::Custom::Pipeline(pipeline) => {
                     let layer = &mut layers[current_layer];
-
-                    let bounds = Rectangle::new(
-                        Point::new(translation.x, translation.y),
-                        pipeline.bounds.size(),
-                    );
+                    let bounds = pipeline.bounds + translation;
 
                     if let Some(clip_bounds) =
                         layer.bounds.intersection(&bounds)
                     {
-                        layer.pipelines.push(primitive::Pipeline {
-                            bounds: clip_bounds,
+                        layer.pipelines.push(Pipeline {
+                            bounds,
+                            viewport: clip_bounds,
                             primitive: pipeline.primitive.clone(),
                         });
                     }
diff --git a/wgpu/src/layer/pipeline.rs b/wgpu/src/layer/pipeline.rs
new file mode 100644
index 00000000..6dfe6750
--- /dev/null
+++ b/wgpu/src/layer/pipeline.rs
@@ -0,0 +1,17 @@
+use crate::core::Rectangle;
+use crate::primitive::pipeline::Primitive;
+
+use std::sync::Arc;
+
+#[derive(Clone, Debug)]
+/// A custom primitive which can be used to render primitives associated with a custom pipeline.
+pub struct Pipeline {
+    /// The bounds of the [`Pipeline`].
+    pub bounds: Rectangle,
+
+    /// The viewport of the [`Pipeline`].
+    pub viewport: Rectangle,
+
+    /// The [`Primitive`] to render.
+    pub primitive: Arc<dyn Primitive>,
+}
diff --git a/wgpu/src/primitive/pipeline.rs b/wgpu/src/primitive/pipeline.rs
index 5dbd6697..302e38f6 100644
--- a/wgpu/src/primitive/pipeline.rs
+++ b/wgpu/src/primitive/pipeline.rs
@@ -1,6 +1,5 @@
 //! Draw primitives using custom pipelines.
 use crate::core::{Rectangle, Size};
-use crate::graphics::Transformation;
 
 use std::any::{Any, TypeId};
 use std::collections::HashMap;
@@ -41,9 +40,9 @@ pub trait Primitive: Debug + Send + Sync + 'static {
         format: wgpu::TextureFormat,
         device: &wgpu::Device,
         queue: &wgpu::Queue,
+        bounds: Rectangle,
         target_size: Size<u32>,
         scale_factor: f32,
-        transform: Transformation,
         storage: &mut Storage,
     );
 
@@ -51,9 +50,9 @@ pub trait Primitive: Debug + Send + Sync + 'static {
     fn render(
         &self,
         storage: &Storage,
-        bounds: Rectangle<u32>,
         target: &wgpu::TextureView,
         target_size: Size<u32>,
+        viewport: Rectangle<u32>,
         encoder: &mut wgpu::CommandEncoder,
     );
 }
-- 
cgit 


From 936d480267578d7e80675e78ec1880aaaaab72d6 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector@hecrj.dev>
Date: Fri, 1 Dec 2023 16:04:27 +0100
Subject: Clip text to `viewport` bounds instead of layout bounds

---
 wgpu/src/geometry.rs   | 15 +++++++++------
 wgpu/src/layer.rs      |  7 +++++++
 wgpu/src/layer/text.rs |  5 +++++
 wgpu/src/text.rs       | 23 ++++++++++++++---------
 4 files changed, 35 insertions(+), 15 deletions(-)

(limited to 'wgpu')

diff --git a/wgpu/src/geometry.rs b/wgpu/src/geometry.rs
index 655362b7..c82b9ffb 100644
--- a/wgpu/src/geometry.rs
+++ b/wgpu/src/geometry.rs
@@ -328,15 +328,17 @@ impl Frame {
             Point::new(transformed.x, transformed.y)
         };
 
+        let bounds = Rectangle {
+            x: position.x,
+            y: position.y,
+            width: f32::INFINITY,
+            height: f32::INFINITY,
+        };
+
         // TODO: Use vectorial text instead of primitive
         self.primitives.push(Primitive::Text {
             content: text.content,
-            bounds: Rectangle {
-                x: position.x,
-                y: position.y,
-                width: f32::INFINITY,
-                height: f32::INFINITY,
-            },
+            bounds,
             color: text.color,
             size: text.size,
             line_height: text.line_height,
@@ -344,6 +346,7 @@ impl Frame {
             horizontal_alignment: text.horizontal_alignment,
             vertical_alignment: text.vertical_alignment,
             shaping: text.shaping,
+            viewport: bounds,
         });
     }
 
diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs
index 98e49f1a..60da3543 100644
--- a/wgpu/src/layer.rs
+++ b/wgpu/src/layer.rs
@@ -75,6 +75,7 @@ impl<'a> Layer<'a> {
                 horizontal_alignment: alignment::Horizontal::Left,
                 vertical_alignment: alignment::Vertical::Top,
                 shaping: core::text::Shaping::Basic,
+                viewport: Rectangle::with_size(Size::INFINITY),
             };
 
             overlay.text.push(Text::Cached(text.clone()));
@@ -123,6 +124,7 @@ impl<'a> Layer<'a> {
                 paragraph,
                 position,
                 color,
+                viewport,
             } => {
                 let layer = &mut layers[current_layer];
 
@@ -130,12 +132,14 @@ impl<'a> Layer<'a> {
                     paragraph: paragraph.clone(),
                     position: *position + translation,
                     color: *color,
+                    viewport: *viewport + translation,
                 });
             }
             Primitive::Editor {
                 editor,
                 position,
                 color,
+                viewport,
             } => {
                 let layer = &mut layers[current_layer];
 
@@ -143,6 +147,7 @@ impl<'a> Layer<'a> {
                     editor: editor.clone(),
                     position: *position + translation,
                     color: *color,
+                    viewport: *viewport + translation,
                 });
             }
             Primitive::Text {
@@ -155,6 +160,7 @@ impl<'a> Layer<'a> {
                 horizontal_alignment,
                 vertical_alignment,
                 shaping,
+                viewport,
             } => {
                 let layer = &mut layers[current_layer];
 
@@ -168,6 +174,7 @@ impl<'a> Layer<'a> {
                     horizontal_alignment: *horizontal_alignment,
                     vertical_alignment: *vertical_alignment,
                     shaping: *shaping,
+                    viewport: *viewport + translation,
                 }));
             }
             Primitive::Quad {
diff --git a/wgpu/src/layer/text.rs b/wgpu/src/layer/text.rs
index 66417cec..c4ea9185 100644
--- a/wgpu/src/layer/text.rs
+++ b/wgpu/src/layer/text.rs
@@ -13,6 +13,7 @@ pub enum Text<'a> {
         paragraph: paragraph::Weak,
         position: Point,
         color: Color,
+        viewport: Rectangle,
     },
     /// An editor.
     #[allow(missing_docs)]
@@ -20,6 +21,7 @@ pub enum Text<'a> {
         editor: editor::Weak,
         position: Point,
         color: Color,
+        viewport: Rectangle,
     },
     /// A cached text.
     Cached(Cached<'a>),
@@ -53,4 +55,7 @@ pub struct Cached<'a> {
 
     /// The shaping strategy of the text.
     pub shaping: text::Shaping,
+
+    /// The viewport of the text.
+    pub viewport: Rectangle,
 }
diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs
index 08a8bea6..7d73c87b 100644
--- a/wgpu/src/text.rs
+++ b/wgpu/src/text.rs
@@ -120,9 +120,13 @@ impl Pipeline {
                     horizontal_alignment,
                     vertical_alignment,
                     color,
+                    viewport,
                 ) = match section {
                     Text::Paragraph {
-                        position, color, ..
+                        position,
+                        color,
+                        viewport,
+                        ..
                     } => {
                         use crate::core::text::Paragraph as _;
 
@@ -137,10 +141,14 @@ impl Pipeline {
                             paragraph.horizontal_alignment(),
                             paragraph.vertical_alignment(),
                             *color,
+                            *viewport,
                         )
                     }
                     Text::Editor {
-                        position, color, ..
+                        position,
+                        color,
+                        viewport,
+                        ..
                     } => {
                         use crate::core::text::Editor as _;
 
@@ -155,6 +163,7 @@ impl Pipeline {
                             alignment::Horizontal::Left,
                             alignment::Vertical::Top,
                             *color,
+                            *viewport,
                         )
                     }
                     Text::Cached(text) => {
@@ -173,6 +182,7 @@ impl Pipeline {
                             text.horizontal_alignment,
                             text.vertical_alignment,
                             text.color,
+                            text.viewport,
                         )
                     }
                 };
@@ -195,13 +205,8 @@ impl Pipeline {
                     alignment::Vertical::Bottom => bounds.y - bounds.height,
                 };
 
-                let section_bounds = Rectangle {
-                    x: left,
-                    y: top,
-                    ..bounds
-                };
-
-                let clip_bounds = layer_bounds.intersection(&section_bounds)?;
+                let clip_bounds =
+                    layer_bounds.intersection(&(viewport * scale_factor))?;
 
                 Some(glyphon::TextArea {
                     buffer,
-- 
cgit 


From b526ce4958b28208395276dd4078ffe0d780e1d7 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector@hecrj.dev>
Date: Sat, 2 Dec 2023 15:53:02 +0100
Subject: Rename `viewport` to `clip_bounds`

---
 wgpu/src/geometry.rs   |  2 +-
 wgpu/src/layer.rs      | 14 +++++++-------
 wgpu/src/layer/text.rs |  8 ++++----
 wgpu/src/text.rs       | 14 +++++++-------
 4 files changed, 19 insertions(+), 19 deletions(-)

(limited to 'wgpu')

diff --git a/wgpu/src/geometry.rs b/wgpu/src/geometry.rs
index c82b9ffb..e0bff67e 100644
--- a/wgpu/src/geometry.rs
+++ b/wgpu/src/geometry.rs
@@ -346,7 +346,7 @@ impl Frame {
             horizontal_alignment: text.horizontal_alignment,
             vertical_alignment: text.vertical_alignment,
             shaping: text.shaping,
-            viewport: bounds,
+            clip_bounds: Rectangle::with_size(Size::INFINITY),
         });
     }
 
diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs
index 60da3543..557a7633 100644
--- a/wgpu/src/layer.rs
+++ b/wgpu/src/layer.rs
@@ -75,7 +75,7 @@ impl<'a> Layer<'a> {
                 horizontal_alignment: alignment::Horizontal::Left,
                 vertical_alignment: alignment::Vertical::Top,
                 shaping: core::text::Shaping::Basic,
-                viewport: Rectangle::with_size(Size::INFINITY),
+                clip_bounds: Rectangle::with_size(Size::INFINITY),
             };
 
             overlay.text.push(Text::Cached(text.clone()));
@@ -124,7 +124,7 @@ impl<'a> Layer<'a> {
                 paragraph,
                 position,
                 color,
-                viewport,
+                clip_bounds,
             } => {
                 let layer = &mut layers[current_layer];
 
@@ -132,14 +132,14 @@ impl<'a> Layer<'a> {
                     paragraph: paragraph.clone(),
                     position: *position + translation,
                     color: *color,
-                    viewport: *viewport + translation,
+                    clip_bounds: *clip_bounds + translation,
                 });
             }
             Primitive::Editor {
                 editor,
                 position,
                 color,
-                viewport,
+                clip_bounds,
             } => {
                 let layer = &mut layers[current_layer];
 
@@ -147,7 +147,7 @@ impl<'a> Layer<'a> {
                     editor: editor.clone(),
                     position: *position + translation,
                     color: *color,
-                    viewport: *viewport + translation,
+                    clip_bounds: *clip_bounds + translation,
                 });
             }
             Primitive::Text {
@@ -160,7 +160,7 @@ impl<'a> Layer<'a> {
                 horizontal_alignment,
                 vertical_alignment,
                 shaping,
-                viewport,
+                clip_bounds,
             } => {
                 let layer = &mut layers[current_layer];
 
@@ -174,7 +174,7 @@ impl<'a> Layer<'a> {
                     horizontal_alignment: *horizontal_alignment,
                     vertical_alignment: *vertical_alignment,
                     shaping: *shaping,
-                    viewport: *viewport + translation,
+                    clip_bounds: *clip_bounds + translation,
                 }));
             }
             Primitive::Quad {
diff --git a/wgpu/src/layer/text.rs b/wgpu/src/layer/text.rs
index c4ea9185..df2f2875 100644
--- a/wgpu/src/layer/text.rs
+++ b/wgpu/src/layer/text.rs
@@ -13,7 +13,7 @@ pub enum Text<'a> {
         paragraph: paragraph::Weak,
         position: Point,
         color: Color,
-        viewport: Rectangle,
+        clip_bounds: Rectangle,
     },
     /// An editor.
     #[allow(missing_docs)]
@@ -21,7 +21,7 @@ pub enum Text<'a> {
         editor: editor::Weak,
         position: Point,
         color: Color,
-        viewport: Rectangle,
+        clip_bounds: Rectangle,
     },
     /// A cached text.
     Cached(Cached<'a>),
@@ -56,6 +56,6 @@ pub struct Cached<'a> {
     /// The shaping strategy of the text.
     pub shaping: text::Shaping,
 
-    /// The viewport of the text.
-    pub viewport: Rectangle,
+    /// The clip bounds of the text.
+    pub clip_bounds: Rectangle,
 }
diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs
index 7d73c87b..888b1924 100644
--- a/wgpu/src/text.rs
+++ b/wgpu/src/text.rs
@@ -120,12 +120,12 @@ impl Pipeline {
                     horizontal_alignment,
                     vertical_alignment,
                     color,
-                    viewport,
+                    clip_bounds,
                 ) = match section {
                     Text::Paragraph {
                         position,
                         color,
-                        viewport,
+                        clip_bounds,
                         ..
                     } => {
                         use crate::core::text::Paragraph as _;
@@ -141,13 +141,13 @@ impl Pipeline {
                             paragraph.horizontal_alignment(),
                             paragraph.vertical_alignment(),
                             *color,
-                            *viewport,
+                            *clip_bounds,
                         )
                     }
                     Text::Editor {
                         position,
                         color,
-                        viewport,
+                        clip_bounds,
                         ..
                     } => {
                         use crate::core::text::Editor as _;
@@ -163,7 +163,7 @@ impl Pipeline {
                             alignment::Horizontal::Left,
                             alignment::Vertical::Top,
                             *color,
-                            *viewport,
+                            *clip_bounds,
                         )
                     }
                     Text::Cached(text) => {
@@ -182,7 +182,7 @@ impl Pipeline {
                             text.horizontal_alignment,
                             text.vertical_alignment,
                             text.color,
-                            text.viewport,
+                            text.clip_bounds,
                         )
                     }
                 };
@@ -206,7 +206,7 @@ impl Pipeline {
                 };
 
                 let clip_bounds =
-                    layer_bounds.intersection(&(viewport * scale_factor))?;
+                    layer_bounds.intersection(&(clip_bounds * scale_factor))?;
 
                 Some(glyphon::TextArea {
                     buffer,
-- 
cgit 


From b152ecda63238136f77b6eda3c582fa1eff99737 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector@hecrj.dev>
Date: Sat, 2 Dec 2023 20:49:47 +0100
Subject: Separate `Compositor::new` from `Compositor::create_renderer`

---
 wgpu/src/window/compositor.rs | 21 +++++----------------
 1 file changed, 5 insertions(+), 16 deletions(-)

(limited to 'wgpu')

diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs
index 21406134..090e0e9f 100644
--- a/wgpu/src/window/compositor.rs
+++ b/wgpu/src/window/compositor.rs
@@ -139,16 +139,14 @@ impl<Theme> Compositor<Theme> {
 pub fn new<Theme, W: HasRawWindowHandle + HasRawDisplayHandle>(
     settings: Settings,
     compatible_window: Option<&W>,
-) -> Result<(Compositor<Theme>, Backend), Error> {
+) -> Result<Compositor<Theme>, Error> {
     let compositor = futures::executor::block_on(Compositor::request(
         settings,
         compatible_window,
     ))
     .ok_or(Error::GraphicsAdapterNotFound)?;
 
-    let backend = compositor.create_backend();
-
-    Ok((compositor, backend))
+    Ok(compositor)
 }
 
 /// Presents the given primitives with the given [`Compositor`] and [`Backend`].
@@ -214,20 +212,11 @@ impl<Theme> graphics::Compositor for Compositor<Theme> {
     fn new<W: HasRawWindowHandle + HasRawDisplayHandle>(
         settings: Self::Settings,
         compatible_window: Option<&W>,
-    ) -> Result<(Self, Self::Renderer), Error> {
-        let (compositor, backend) = new(settings, compatible_window)?;
-
-        Ok((
-            compositor,
-            Renderer::new(
-                backend,
-                settings.default_font,
-                settings.default_text_size,
-            ),
-        ))
+    ) -> Result<Self, Error> {
+        new(settings, compatible_window)
     }
 
-    fn renderer(&self) -> Self::Renderer {
+    fn create_renderer(&self) -> Self::Renderer {
         Renderer::new(
             self.create_backend(),
             self.settings.default_font,
-- 
cgit 


From 603832e66c710ea39a95009ddc905de20c6856bd Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector@hecrj.dev>
Date: Tue, 5 Dec 2023 02:19:17 +0100
Subject: Introduce `RawText` to `Primitive` in `iced_graphics`

This should allow users to directly render a
`cosmic_text::Buffer`.
---
 wgpu/src/layer.rs      | 15 +++++++++++++++
 wgpu/src/layer/text.rs |  5 ++++-
 wgpu/src/text.rs       | 22 ++++++++++++++++++++++
 3 files changed, 41 insertions(+), 1 deletion(-)

(limited to 'wgpu')

diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs
index 557a7633..4ad12a88 100644
--- a/wgpu/src/layer.rs
+++ b/wgpu/src/layer.rs
@@ -177,6 +177,21 @@ impl<'a> Layer<'a> {
                     clip_bounds: *clip_bounds + translation,
                 }));
             }
+            graphics::Primitive::RawText(graphics::text::Raw {
+                buffer,
+                position,
+                color,
+                clip_bounds,
+            }) => {
+                let layer = &mut layers[current_layer];
+
+                layer.text.push(Text::Raw(graphics::text::Raw {
+                    buffer: buffer.clone(),
+                    position: *position + translation,
+                    color: *color,
+                    clip_bounds: *clip_bounds + translation,
+                }));
+            }
             Primitive::Quad {
                 bounds,
                 background,
diff --git a/wgpu/src/layer/text.rs b/wgpu/src/layer/text.rs
index df2f2875..37ee5247 100644
--- a/wgpu/src/layer/text.rs
+++ b/wgpu/src/layer/text.rs
@@ -1,6 +1,7 @@
 use crate::core::alignment;
 use crate::core::text;
 use crate::core::{Color, Font, Pixels, Point, Rectangle};
+use crate::graphics;
 use crate::graphics::text::editor;
 use crate::graphics::text::paragraph;
 
@@ -23,8 +24,10 @@ pub enum Text<'a> {
         color: Color,
         clip_bounds: Rectangle,
     },
-    /// A cached text.
+    /// Some cached text.
     Cached(Cached<'a>),
+    /// Some raw text.
+    Raw(graphics::text::Raw),
 }
 
 #[derive(Debug, Clone)]
diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs
index 888b1924..dca09cb8 100644
--- a/wgpu/src/text.rs
+++ b/wgpu/src/text.rs
@@ -7,6 +7,7 @@ use crate::layer::Text;
 
 use std::borrow::Cow;
 use std::cell::RefCell;
+use std::sync::Arc;
 
 #[allow(missing_debug_implementations)]
 pub struct Pipeline {
@@ -76,6 +77,7 @@ impl Pipeline {
             Paragraph(Paragraph),
             Editor(Editor),
             Cache(cache::KeyHash),
+            Raw(Arc<glyphon::Buffer>),
         }
 
         let allocations: Vec<_> = sections
@@ -107,6 +109,7 @@ impl Pipeline {
 
                     Some(Allocation::Cache(key))
                 }
+                Text::Raw(text) => text.buffer.upgrade().map(Allocation::Raw),
             })
             .collect();
 
@@ -185,6 +188,25 @@ impl Pipeline {
                             text.clip_bounds,
                         )
                     }
+                    Text::Raw(text) => {
+                        let Some(Allocation::Raw(buffer)) = allocation else {
+                            return None;
+                        };
+
+                        let (width, height) = buffer.size();
+
+                        (
+                            buffer.as_ref(),
+                            Rectangle::new(
+                                text.position,
+                                Size::new(width, height),
+                            ),
+                            alignment::Horizontal::Left,
+                            alignment::Vertical::Top,
+                            text.color,
+                            text.clip_bounds,
+                        )
+                    }
                 };
 
                 let bounds = bounds * scale_factor;
-- 
cgit 


From a2a96adf7a19f8b2f7879fc19ff139b930fb102e Mon Sep 17 00:00:00 2001
From: Cory Frenette <cory@frenette.dev>
Date: Sun, 10 Dec 2023 22:12:46 -0500
Subject: implement svg text fix for native renderer

Signed-off-by: Cory Frenette <cory@frenette.dev>
---
 wgpu/src/image/vector.rs | 23 ++++++++++++++++++-----
 1 file changed, 18 insertions(+), 5 deletions(-)

(limited to 'wgpu')

diff --git a/wgpu/src/image/vector.rs b/wgpu/src/image/vector.rs
index 6582bb82..1efc5342 100644
--- a/wgpu/src/image/vector.rs
+++ b/wgpu/src/image/vector.rs
@@ -2,8 +2,9 @@ use crate::core::svg;
 use crate::core::{Color, Size};
 use crate::image::atlas::{self, Atlas};
 
+use iced_graphics::text;
 use resvg::tiny_skia;
-use resvg::usvg;
+use resvg::usvg::{self, TreeTextToPath};
 use std::collections::{HashMap, HashSet};
 use std::fs;
 
@@ -51,11 +52,23 @@ impl Cache {
 
         let svg = match handle.data() {
             svg::Data::Path(path) => {
-                let tree = fs::read_to_string(path).ok().and_then(|contents| {
-                    usvg::Tree::from_str(&contents, &usvg::Options::default())
+                let mut tree =
+                    fs::read_to_string(path).ok().and_then(|contents| {
+                        usvg::Tree::from_str(
+                            &contents,
+                            &usvg::Options::default(),
+                        )
                         .ok()
-                });
-
+                    });
+                // If there are text nodes in the tree load fonts and convert the text to paths
+                if let Some(svg_tree) = &mut tree {
+                    if svg_tree.has_text_nodes() {
+                        let mut font_system = text::font_system()
+                            .write()
+                            .expect("Read font system");
+                        svg_tree.convert_text(font_system.raw().db_mut());
+                    }
+                }
                 tree.map(Svg::Loaded).unwrap_or(Svg::NotFound)
             }
             svg::Data::Bytes(bytes) => {
-- 
cgit 


From 33f92b1be78e2f09290e36f0c9b77af899609bd8 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector@hecrj.dev>
Date: Mon, 11 Dec 2023 10:47:53 +0100
Subject: Fix import styling in `iced_wgpu::image::vector`

---
 wgpu/src/image/vector.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'wgpu')

diff --git a/wgpu/src/image/vector.rs b/wgpu/src/image/vector.rs
index 1efc5342..f4819095 100644
--- a/wgpu/src/image/vector.rs
+++ b/wgpu/src/image/vector.rs
@@ -1,8 +1,8 @@
 use crate::core::svg;
 use crate::core::{Color, Size};
+use crate::graphics::text;
 use crate::image::atlas::{self, Atlas};
 
-use iced_graphics::text;
 use resvg::tiny_skia;
 use resvg::usvg::{self, TreeTextToPath};
 use std::collections::{HashMap, HashSet};
-- 
cgit 


From 04e8e529a0e80499b129395664f1806de8102d01 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector@hecrj.dev>
Date: Mon, 11 Dec 2023 10:48:07 +0100
Subject: Convert SVG text nodes for in-memory SVGs in `iced_wgpu`

---
 wgpu/src/image/vector.rs | 37 +++++++++++++++++--------------------
 1 file changed, 17 insertions(+), 20 deletions(-)

(limited to 'wgpu')

diff --git a/wgpu/src/image/vector.rs b/wgpu/src/image/vector.rs
index f4819095..d9be50d7 100644
--- a/wgpu/src/image/vector.rs
+++ b/wgpu/src/image/vector.rs
@@ -50,27 +50,15 @@ impl Cache {
             return self.svgs.get(&handle.id()).unwrap();
         }
 
-        let svg = match handle.data() {
-            svg::Data::Path(path) => {
-                let mut tree =
-                    fs::read_to_string(path).ok().and_then(|contents| {
-                        usvg::Tree::from_str(
-                            &contents,
-                            &usvg::Options::default(),
-                        )
+        let mut svg = match handle.data() {
+            svg::Data::Path(path) => fs::read_to_string(path)
+                .ok()
+                .and_then(|contents| {
+                    usvg::Tree::from_str(&contents, &usvg::Options::default())
                         .ok()
-                    });
-                // If there are text nodes in the tree load fonts and convert the text to paths
-                if let Some(svg_tree) = &mut tree {
-                    if svg_tree.has_text_nodes() {
-                        let mut font_system = text::font_system()
-                            .write()
-                            .expect("Read font system");
-                        svg_tree.convert_text(font_system.raw().db_mut());
-                    }
-                }
-                tree.map(Svg::Loaded).unwrap_or(Svg::NotFound)
-            }
+                })
+                .map(Svg::Loaded)
+                .unwrap_or(Svg::NotFound),
             svg::Data::Bytes(bytes) => {
                 match usvg::Tree::from_data(bytes, &usvg::Options::default()) {
                     Ok(tree) => Svg::Loaded(tree),
@@ -79,6 +67,15 @@ impl Cache {
             }
         };
 
+        if let Svg::Loaded(svg) = &mut svg {
+            if svg.has_text_nodes() {
+                let mut font_system =
+                    text::font_system().write().expect("Write font system");
+
+                svg.convert_text(font_system.raw().db_mut());
+            }
+        }
+
         let _ = self.svgs.insert(handle.id(), svg);
         self.svgs.get(&handle.id()).unwrap()
     }
-- 
cgit 


From 3c6bb0a076c4433abe2a381856250c9d9693404e Mon Sep 17 00:00:00 2001
From: Tomáš Zemanovič <tzemanovic@gmail.com>
Date: Thu, 11 Jan 2024 14:45:40 +0000
Subject: wgpu: require `Send` on stored pipelines

---
 wgpu/src/primitive/pipeline.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'wgpu')

diff --git a/wgpu/src/primitive/pipeline.rs b/wgpu/src/primitive/pipeline.rs
index 302e38f6..c8e45458 100644
--- a/wgpu/src/primitive/pipeline.rs
+++ b/wgpu/src/primitive/pipeline.rs
@@ -82,7 +82,7 @@ impl<Theme> Renderer for crate::Renderer<Theme> {
 /// Stores custom, user-provided pipelines.
 #[derive(Default, Debug)]
 pub struct Storage {
-    pipelines: HashMap<TypeId, Box<dyn Any>>,
+    pipelines: HashMap<TypeId, Box<dyn Any + Send>>,
 }
 
 impl Storage {
@@ -92,7 +92,7 @@ impl Storage {
     }
 
     /// Inserts the pipeline `T` in to [`Storage`].
-    pub fn store<T: 'static>(&mut self, pipeline: T) {
+    pub fn store<T: 'static + Send>(&mut self, pipeline: T) {
         let _ = self.pipelines.insert(TypeId::of::<T>(), Box::new(pipeline));
     }
 
-- 
cgit 


From 66bea7bb6d4575c1d36d28a10e08dc60a0ea20b0 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector@hecrj.dev>
Date: Wed, 17 Jan 2024 13:22:02 +0100
Subject: Apply scaling during `Frame::fill_text` in `iced_wgpu`

---
 wgpu/src/geometry.rs | 40 ++++++++++++++++++++++++++++++++++------
 1 file changed, 34 insertions(+), 6 deletions(-)

(limited to 'wgpu')

diff --git a/wgpu/src/geometry.rs b/wgpu/src/geometry.rs
index e0bff67e..36092da0 100644
--- a/wgpu/src/geometry.rs
+++ b/wgpu/src/geometry.rs
@@ -1,4 +1,5 @@
 //! Build and draw geometry.
+use crate::core::text::LineHeight;
 use crate::core::{Point, Rectangle, Size, Vector};
 use crate::graphics::color;
 use crate::graphics::geometry::fill::{self, Fill};
@@ -318,14 +319,41 @@ impl Frame {
     pub fn fill_text(&mut self, text: impl Into<Text>) {
         let text = text.into();
 
-        let position = if self.transforms.current.is_identity {
-            text.position
+        let (position, size, line_height) = if self
+            .transforms
+            .current
+            .is_identity
+        {
+            (text.position, text.size, text.line_height)
         } else {
-            let transformed = self.transforms.current.raw.transform_point(
+            let position = self.transforms.current.raw.transform_point(
                 lyon::math::Point::new(text.position.x, text.position.y),
             );
 
-            Point::new(transformed.x, transformed.y)
+            let size =
+                self.transforms.current.raw.transform_vector(
+                    lyon::math::Vector::new(0.0, text.size.0),
+                );
+
+            let line_height = match text.line_height {
+                LineHeight::Absolute(size) => {
+                    let new_height = self
+                        .transforms
+                        .current
+                        .raw
+                        .transform_vector(lyon::math::Vector::new(0.0, size.0))
+                        .y;
+
+                    LineHeight::Absolute(new_height.into())
+                }
+                LineHeight::Relative(factor) => LineHeight::Relative(factor),
+            };
+
+            (
+                Point::new(position.x, position.y),
+                size.y.into(),
+                line_height,
+            )
         };
 
         let bounds = Rectangle {
@@ -340,8 +368,8 @@ impl Frame {
             content: text.content,
             bounds,
             color: text.color,
-            size: text.size,
-            line_height: text.line_height,
+            size,
+            line_height,
             font: text.font,
             horizontal_alignment: text.horizontal_alignment,
             vertical_alignment: text.vertical_alignment,
-- 
cgit 


From fda96a9eda261b9fbe499eae1c6eedcfa252c5ea Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector@hecrj.dev>
Date: Wed, 17 Jan 2024 13:44:30 +0100
Subject: Simplify `Transform` API in `iced_wgpu::geometry`

---
 wgpu/src/geometry.rs | 136 +++++++++++++++++++++++----------------------------
 1 file changed, 62 insertions(+), 74 deletions(-)

(limited to 'wgpu')

diff --git a/wgpu/src/geometry.rs b/wgpu/src/geometry.rs
index 36092da0..04718441 100644
--- a/wgpu/src/geometry.rs
+++ b/wgpu/src/geometry.rs
@@ -1,6 +1,6 @@
 //! Build and draw geometry.
 use crate::core::text::LineHeight;
-use crate::core::{Point, Rectangle, Size, Vector};
+use crate::core::{Pixels, Point, Rectangle, Size, Vector};
 use crate::graphics::color;
 use crate::graphics::geometry::fill::{self, Fill};
 use crate::graphics::geometry::{
@@ -116,19 +116,26 @@ struct Transforms {
 }
 
 #[derive(Debug, Clone, Copy)]
-struct Transform {
-    raw: lyon::math::Transform,
-    is_identity: bool,
-}
+struct Transform(lyon::math::Transform);
 
 impl Transform {
-    /// Transforms the given [Point] by the transformation matrix.
-    fn transform_point(&self, point: &mut Point) {
+    fn is_identity(&self) -> bool {
+        self.0 == lyon::math::Transform::identity()
+    }
+
+    fn scale(&self) -> (f32, f32) {
+        (self.0.m12, self.0.m22)
+    }
+
+    fn transform_point(&self, point: Point) -> Point {
         let transformed = self
-            .raw
+            .0
             .transform_point(euclid::Point2D::new(point.x, point.y));
-        point.x = transformed.x;
-        point.y = transformed.y;
+
+        Point {
+            x: transformed.x,
+            y: transformed.y,
+        }
     }
 
     fn transform_style(&self, style: Style) -> Style {
@@ -143,8 +150,8 @@ impl Transform {
     fn transform_gradient(&self, mut gradient: Gradient) -> Gradient {
         match &mut gradient {
             Gradient::Linear(linear) => {
-                self.transform_point(&mut linear.start);
-                self.transform_point(&mut linear.end);
+                linear.start = self.transform_point(linear.start);
+                linear.end = self.transform_point(linear.end);
             }
         }
 
@@ -164,10 +171,7 @@ impl Frame {
             primitives: Vec::new(),
             transforms: Transforms {
                 previous: Vec::new(),
-                current: Transform {
-                    raw: lyon::math::Transform::identity(),
-                    is_identity: true,
-                },
+                current: Transform(lyon::math::Transform::identity()),
             },
             fill_tessellator: tessellation::FillTessellator::new(),
             stroke_tessellator: tessellation::StrokeTessellator::new(),
@@ -210,14 +214,14 @@ impl Frame {
         let options = tessellation::FillOptions::default()
             .with_fill_rule(into_fill_rule(rule));
 
-        if self.transforms.current.is_identity {
+        if self.transforms.current.is_identity() {
             self.fill_tessellator.tessellate_path(
                 path.raw(),
                 &options,
                 buffer.as_mut(),
             )
         } else {
-            let path = path.transform(&self.transforms.current.raw);
+            let path = path.transform(&self.transforms.current.0);
 
             self.fill_tessellator.tessellate_path(
                 path.raw(),
@@ -242,13 +246,14 @@ impl Frame {
             .buffers
             .get_fill(&self.transforms.current.transform_style(style));
 
-        let top_left =
-            self.transforms.current.raw.transform_point(
-                lyon::math::Point::new(top_left.x, top_left.y),
-            );
+        let top_left = self
+            .transforms
+            .current
+            .0
+            .transform_point(lyon::math::Point::new(top_left.x, top_left.y));
 
         let size =
-            self.transforms.current.raw.transform_vector(
+            self.transforms.current.0.transform_vector(
                 lyon::math::Vector::new(size.width, size.height),
             );
 
@@ -285,14 +290,14 @@ impl Frame {
             Cow::Owned(dashed(path, stroke.line_dash))
         };
 
-        if self.transforms.current.is_identity {
+        if self.transforms.current.is_identity() {
             self.stroke_tessellator.tessellate_path(
                 path.raw(),
                 &options,
                 buffer.as_mut(),
             )
         } else {
-            let path = path.transform(&self.transforms.current.raw);
+            let path = path.transform(&self.transforms.current.0);
 
             self.stroke_tessellator.tessellate_path(
                 path.raw(),
@@ -319,42 +324,28 @@ impl Frame {
     pub fn fill_text(&mut self, text: impl Into<Text>) {
         let text = text.into();
 
-        let (position, size, line_height) = if self
-            .transforms
-            .current
-            .is_identity
-        {
-            (text.position, text.size, text.line_height)
-        } else {
-            let position = self.transforms.current.raw.transform_point(
-                lyon::math::Point::new(text.position.x, text.position.y),
-            );
+        let (position, size, line_height) =
+            if self.transforms.current.is_identity() {
+                (text.position, text.size, text.line_height)
+            } else {
+                let (_, scale_y) = self.transforms.current.scale();
 
-            let size =
-                self.transforms.current.raw.transform_vector(
-                    lyon::math::Vector::new(0.0, text.size.0),
-                );
-
-            let line_height = match text.line_height {
-                LineHeight::Absolute(size) => {
-                    let new_height = self
-                        .transforms
-                        .current
-                        .raw
-                        .transform_vector(lyon::math::Vector::new(0.0, size.0))
-                        .y;
-
-                    LineHeight::Absolute(new_height.into())
-                }
-                LineHeight::Relative(factor) => LineHeight::Relative(factor),
-            };
+                let position =
+                    self.transforms.current.transform_point(text.position);
 
-            (
-                Point::new(position.x, position.y),
-                size.y.into(),
-                line_height,
-            )
-        };
+                let size = Pixels(text.size.0 * scale_y);
+
+                let line_height = match text.line_height {
+                    LineHeight::Absolute(size) => {
+                        LineHeight::Absolute(Pixels(size.0 * scale_y))
+                    }
+                    LineHeight::Relative(factor) => {
+                        LineHeight::Relative(factor)
+                    }
+                };
+
+                (position, size, line_height)
+            };
 
         let bounds = Rectangle {
             x: position.x,
@@ -451,26 +442,24 @@ impl Frame {
     /// Applies a translation to the current transform of the [`Frame`].
     #[inline]
     pub fn translate(&mut self, translation: Vector) {
-        self.transforms.current.raw = self
-            .transforms
-            .current
-            .raw
-            .pre_translate(lyon::math::Vector::new(
-                translation.x,
-                translation.y,
-            ));
-        self.transforms.current.is_identity = false;
+        self.transforms.current.0 =
+            self.transforms
+                .current
+                .0
+                .pre_translate(lyon::math::Vector::new(
+                    translation.x,
+                    translation.y,
+                ));
     }
 
     /// Applies a rotation in radians to the current transform of the [`Frame`].
     #[inline]
     pub fn rotate(&mut self, angle: f32) {
-        self.transforms.current.raw = self
+        self.transforms.current.0 = self
             .transforms
             .current
-            .raw
+            .0
             .pre_rotate(lyon::math::Angle::radians(angle));
-        self.transforms.current.is_identity = false;
     }
 
     /// Applies a uniform scaling to the current transform of the [`Frame`].
@@ -486,9 +475,8 @@ impl Frame {
     pub fn scale_nonuniform(&mut self, scale: impl Into<Vector>) {
         let scale = scale.into();
 
-        self.transforms.current.raw =
-            self.transforms.current.raw.pre_scale(scale.x, scale.y);
-        self.transforms.current.is_identity = false;
+        self.transforms.current.0 =
+            self.transforms.current.0.pre_scale(scale.x, scale.y);
     }
 
     /// Produces the [`Primitive`] representing everything drawn on the [`Frame`].
-- 
cgit 


From dd032d9a7a73dc28c12802e1e702d0aebe92e261 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector@hecrj.dev>
Date: Wed, 17 Jan 2024 14:25:39 +0100
Subject: Implement vectorial text support for `iced_wgpu`

---
 wgpu/src/geometry.rs | 225 ++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 188 insertions(+), 37 deletions(-)

(limited to 'wgpu')

diff --git a/wgpu/src/geometry.rs b/wgpu/src/geometry.rs
index 04718441..a1583a07 100644
--- a/wgpu/src/geometry.rs
+++ b/wgpu/src/geometry.rs
@@ -1,6 +1,7 @@
 //! Build and draw geometry.
+use crate::core::alignment;
 use crate::core::text::LineHeight;
-use crate::core::{Pixels, Point, Rectangle, Size, Vector};
+use crate::core::{Color, Pixels, Point, Rectangle, Size, Vector};
 use crate::graphics::color;
 use crate::graphics::geometry::fill::{self, Fill};
 use crate::graphics::geometry::{
@@ -8,6 +9,7 @@ use crate::graphics::geometry::{
 };
 use crate::graphics::gradient::{self, Gradient};
 use crate::graphics::mesh::{self, Mesh};
+use crate::graphics::text::{self, cosmic_text};
 use crate::primitive::{self, Primitive};
 
 use lyon::geom::euclid;
@@ -123,8 +125,13 @@ impl Transform {
         self.0 == lyon::math::Transform::identity()
     }
 
+    fn is_scale_translation(&self) -> bool {
+        self.0.m12.abs() < 2.0 * f32::EPSILON
+            && self.0.m21.abs() < 2.0 * f32::EPSILON
+    }
+
     fn scale(&self) -> (f32, f32) {
-        (self.0.m12, self.0.m22)
+        (self.0.m11, self.0.m22)
     }
 
     fn transform_point(&self, point: Point) -> Point {
@@ -324,49 +331,193 @@ impl Frame {
     pub fn fill_text(&mut self, text: impl Into<Text>) {
         let text = text.into();
 
-        let (position, size, line_height) =
-            if self.transforms.current.is_identity() {
-                (text.position, text.size, text.line_height)
-            } else {
-                let (_, scale_y) = self.transforms.current.scale();
+        let (scale_x, scale_y) = self.transforms.current.scale();
+
+        if self.transforms.current.is_scale_translation()
+            && scale_x == scale_y
+            && scale_x > 0.0
+            && scale_y > 0.0
+        {
+            let (position, size, line_height) =
+                if self.transforms.current.is_identity() {
+                    (text.position, text.size, text.line_height)
+                } else {
+                    let position =
+                        self.transforms.current.transform_point(text.position);
+
+                    let size = Pixels(text.size.0 * scale_y);
+
+                    let line_height = match text.line_height {
+                        LineHeight::Absolute(size) => {
+                            LineHeight::Absolute(Pixels(size.0 * scale_y))
+                        }
+                        LineHeight::Relative(factor) => {
+                            LineHeight::Relative(factor)
+                        }
+                    };
+
+                    (position, size, line_height)
+                };
 
-                let position =
-                    self.transforms.current.transform_point(text.position);
+            let bounds = Rectangle {
+                x: position.x,
+                y: position.y,
+                width: f32::INFINITY,
+                height: f32::INFINITY,
+            };
 
-                let size = Pixels(text.size.0 * scale_y);
+            // TODO: Honor layering!
+            self.primitives.push(Primitive::Text {
+                content: text.content,
+                bounds,
+                color: text.color,
+                size,
+                line_height,
+                font: text.font,
+                horizontal_alignment: text.horizontal_alignment,
+                vertical_alignment: text.vertical_alignment,
+                shaping: text.shaping,
+                clip_bounds: Rectangle::with_size(Size::INFINITY),
+            });
+        } else {
+            let mut font_system =
+                text::font_system().write().expect("Write font system");
 
-                let line_height = match text.line_height {
-                    LineHeight::Absolute(size) => {
-                        LineHeight::Absolute(Pixels(size.0 * scale_y))
-                    }
-                    LineHeight::Relative(factor) => {
-                        LineHeight::Relative(factor)
+            let mut buffer = cosmic_text::BufferLine::new(
+                &text.content,
+                cosmic_text::AttrsList::new(text::to_attributes(text.font)),
+                text::to_shaping(text.shaping),
+            );
+
+            let layout = buffer.layout(
+                font_system.raw(),
+                text.size.0,
+                f32::MAX,
+                cosmic_text::Wrap::None,
+            );
+
+            let translation_x = match text.horizontal_alignment {
+                alignment::Horizontal::Left => text.position.x,
+                alignment::Horizontal::Center
+                | alignment::Horizontal::Right => {
+                    let mut line_width = 0.0f32;
+
+                    for line in layout.iter() {
+                        line_width = line_width.max(line.w);
                     }
-                };
 
-                (position, size, line_height)
+                    if text.horizontal_alignment
+                        == alignment::Horizontal::Center
+                    {
+                        text.position.x - line_width / 2.0
+                    } else {
+                        text.position.x - line_width
+                    }
+                }
             };
 
-        let bounds = Rectangle {
-            x: position.x,
-            y: position.y,
-            width: f32::INFINITY,
-            height: f32::INFINITY,
-        };
+            let translation_y = {
+                let line_height = text.line_height.to_absolute(text.size);
 
-        // TODO: Use vectorial text instead of primitive
-        self.primitives.push(Primitive::Text {
-            content: text.content,
-            bounds,
-            color: text.color,
-            size,
-            line_height,
-            font: text.font,
-            horizontal_alignment: text.horizontal_alignment,
-            vertical_alignment: text.vertical_alignment,
-            shaping: text.shaping,
-            clip_bounds: Rectangle::with_size(Size::INFINITY),
-        });
+                match text.vertical_alignment {
+                    alignment::Vertical::Top => text.position.y,
+                    alignment::Vertical::Center => {
+                        text.position.y - line_height.0 / 2.0
+                    }
+                    alignment::Vertical::Bottom => {
+                        text.position.y - line_height.0
+                    }
+                }
+            };
+
+            let mut swash_cache = cosmic_text::SwashCache::new();
+
+            for run in layout.iter() {
+                for glyph in run.glyphs.iter() {
+                    let physical_glyph = glyph.physical((0.0, 0.0), 1.0);
+
+                    let start_x = translation_x + glyph.x + glyph.x_offset;
+                    let start_y = translation_y + glyph.y_offset + text.size.0;
+                    let offset = Vector::new(start_x, start_y);
+
+                    if let Some(commands) = swash_cache.get_outline_commands(
+                        font_system.raw(),
+                        physical_glyph.cache_key,
+                    ) {
+                        let glyph = Path::new(|path| {
+                            use cosmic_text::Command;
+
+                            for command in commands {
+                                match command {
+                                    Command::MoveTo(p) => {
+                                        path.move_to(
+                                            Point::new(p.x, -p.y) + offset,
+                                        );
+                                    }
+                                    Command::LineTo(p) => {
+                                        path.line_to(
+                                            Point::new(p.x, -p.y) + offset,
+                                        );
+                                    }
+                                    Command::CurveTo(
+                                        control_a,
+                                        control_b,
+                                        to,
+                                    ) => {
+                                        path.bezier_curve_to(
+                                            Point::new(
+                                                control_a.x,
+                                                -control_a.y,
+                                            ) + offset,
+                                            Point::new(
+                                                control_b.x,
+                                                -control_b.y,
+                                            ) + offset,
+                                            Point::new(to.x, -to.y) + offset,
+                                        );
+                                    }
+                                    Command::QuadTo(control, to) => {
+                                        path.quadratic_curve_to(
+                                            Point::new(control.x, -control.y)
+                                                + offset,
+                                            Point::new(to.x, -to.y) + offset,
+                                        );
+                                    }
+                                    Command::Close => {
+                                        path.close();
+                                    }
+                                }
+                            }
+                        });
+
+                        self.fill(&glyph, text.color);
+                    } else {
+                        // TODO: Raster image support for `Canvas`
+                        let [r, g, b, a] = text.color.into_rgba8();
+
+                        swash_cache.with_pixels(
+                            font_system.raw(),
+                            physical_glyph.cache_key,
+                            cosmic_text::Color::rgba(r, g, b, a),
+                            |x, y, color| {
+                                self.fill(
+                                    &Path::rectangle(
+                                        Point::new(x as f32, y as f32) + offset,
+                                        Size::new(1.0, 1.0),
+                                    ),
+                                    Color::from_rgba8(
+                                        color.r(),
+                                        color.g(),
+                                        color.b(),
+                                        color.a() as f32 / 255.0,
+                                    ),
+                                );
+                            },
+                        )
+                    }
+                }
+            }
+        }
     }
 
     /// Stores the current transform of the [`Frame`] and executes the given
-- 
cgit 


From 4cb53a6e225f9e533126eb03d3cc34be3fd09f1d Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector@hecrj.dev>
Date: Wed, 17 Jan 2024 14:48:33 +0100
Subject: Implement vectorial text support for `iced_tiny_skia`

---
 wgpu/src/geometry.rs | 142 +--------------------------------------------------
 1 file changed, 2 insertions(+), 140 deletions(-)

(limited to 'wgpu')

diff --git a/wgpu/src/geometry.rs b/wgpu/src/geometry.rs
index a1583a07..4d7f443e 100644
--- a/wgpu/src/geometry.rs
+++ b/wgpu/src/geometry.rs
@@ -1,7 +1,6 @@
 //! Build and draw geometry.
-use crate::core::alignment;
 use crate::core::text::LineHeight;
-use crate::core::{Color, Pixels, Point, Rectangle, Size, Vector};
+use crate::core::{Pixels, Point, Rectangle, Size, Vector};
 use crate::graphics::color;
 use crate::graphics::geometry::fill::{self, Fill};
 use crate::graphics::geometry::{
@@ -9,7 +8,6 @@ use crate::graphics::geometry::{
 };
 use crate::graphics::gradient::{self, Gradient};
 use crate::graphics::mesh::{self, Mesh};
-use crate::graphics::text::{self, cosmic_text};
 use crate::primitive::{self, Primitive};
 
 use lyon::geom::euclid;
@@ -380,143 +378,7 @@ impl Frame {
                 clip_bounds: Rectangle::with_size(Size::INFINITY),
             });
         } else {
-            let mut font_system =
-                text::font_system().write().expect("Write font system");
-
-            let mut buffer = cosmic_text::BufferLine::new(
-                &text.content,
-                cosmic_text::AttrsList::new(text::to_attributes(text.font)),
-                text::to_shaping(text.shaping),
-            );
-
-            let layout = buffer.layout(
-                font_system.raw(),
-                text.size.0,
-                f32::MAX,
-                cosmic_text::Wrap::None,
-            );
-
-            let translation_x = match text.horizontal_alignment {
-                alignment::Horizontal::Left => text.position.x,
-                alignment::Horizontal::Center
-                | alignment::Horizontal::Right => {
-                    let mut line_width = 0.0f32;
-
-                    for line in layout.iter() {
-                        line_width = line_width.max(line.w);
-                    }
-
-                    if text.horizontal_alignment
-                        == alignment::Horizontal::Center
-                    {
-                        text.position.x - line_width / 2.0
-                    } else {
-                        text.position.x - line_width
-                    }
-                }
-            };
-
-            let translation_y = {
-                let line_height = text.line_height.to_absolute(text.size);
-
-                match text.vertical_alignment {
-                    alignment::Vertical::Top => text.position.y,
-                    alignment::Vertical::Center => {
-                        text.position.y - line_height.0 / 2.0
-                    }
-                    alignment::Vertical::Bottom => {
-                        text.position.y - line_height.0
-                    }
-                }
-            };
-
-            let mut swash_cache = cosmic_text::SwashCache::new();
-
-            for run in layout.iter() {
-                for glyph in run.glyphs.iter() {
-                    let physical_glyph = glyph.physical((0.0, 0.0), 1.0);
-
-                    let start_x = translation_x + glyph.x + glyph.x_offset;
-                    let start_y = translation_y + glyph.y_offset + text.size.0;
-                    let offset = Vector::new(start_x, start_y);
-
-                    if let Some(commands) = swash_cache.get_outline_commands(
-                        font_system.raw(),
-                        physical_glyph.cache_key,
-                    ) {
-                        let glyph = Path::new(|path| {
-                            use cosmic_text::Command;
-
-                            for command in commands {
-                                match command {
-                                    Command::MoveTo(p) => {
-                                        path.move_to(
-                                            Point::new(p.x, -p.y) + offset,
-                                        );
-                                    }
-                                    Command::LineTo(p) => {
-                                        path.line_to(
-                                            Point::new(p.x, -p.y) + offset,
-                                        );
-                                    }
-                                    Command::CurveTo(
-                                        control_a,
-                                        control_b,
-                                        to,
-                                    ) => {
-                                        path.bezier_curve_to(
-                                            Point::new(
-                                                control_a.x,
-                                                -control_a.y,
-                                            ) + offset,
-                                            Point::new(
-                                                control_b.x,
-                                                -control_b.y,
-                                            ) + offset,
-                                            Point::new(to.x, -to.y) + offset,
-                                        );
-                                    }
-                                    Command::QuadTo(control, to) => {
-                                        path.quadratic_curve_to(
-                                            Point::new(control.x, -control.y)
-                                                + offset,
-                                            Point::new(to.x, -to.y) + offset,
-                                        );
-                                    }
-                                    Command::Close => {
-                                        path.close();
-                                    }
-                                }
-                            }
-                        });
-
-                        self.fill(&glyph, text.color);
-                    } else {
-                        // TODO: Raster image support for `Canvas`
-                        let [r, g, b, a] = text.color.into_rgba8();
-
-                        swash_cache.with_pixels(
-                            font_system.raw(),
-                            physical_glyph.cache_key,
-                            cosmic_text::Color::rgba(r, g, b, a),
-                            |x, y, color| {
-                                self.fill(
-                                    &Path::rectangle(
-                                        Point::new(x as f32, y as f32) + offset,
-                                        Size::new(1.0, 1.0),
-                                    ),
-                                    Color::from_rgba8(
-                                        color.r(),
-                                        color.g(),
-                                        color.b(),
-                                        color.a() as f32 / 255.0,
-                                    ),
-                                );
-                            },
-                        )
-                    }
-                }
-            }
+            text.draw_with(|path, color| self.fill(&path, color));
         }
     }
 
-- 
cgit 


From 7289b6091b61b0aa448a756cfe32211c78a4cce0 Mon Sep 17 00:00:00 2001
From: Ian Douglas Scott <idscott@system76.com>
Date: Tue, 9 Jan 2024 07:19:15 -0800
Subject: WIP raw-window-handle 0.6

---
 wgpu/src/window/compositor.rs | 73 ++++++++++++++++++++++++++-----------------
 1 file changed, 44 insertions(+), 29 deletions(-)

(limited to 'wgpu')

diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs
index 090e0e9f..e2dc4901 100644
--- a/wgpu/src/window/compositor.rs
+++ b/wgpu/src/window/compositor.rs
@@ -6,13 +6,13 @@ use crate::graphics::compositor;
 use crate::graphics::{Error, Viewport};
 use crate::{Backend, Primitive, Renderer, Settings};
 
-use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle};
+use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
 
 use std::marker::PhantomData;
 
 /// A window graphics backend for iced powered by `wgpu`.
 #[allow(missing_debug_implementations)]
-pub struct Compositor<Theme> {
+pub struct Compositor<W, Theme> {
     settings: Settings,
     instance: wgpu::Instance,
     adapter: wgpu::Adapter,
@@ -20,15 +20,18 @@ pub struct Compositor<Theme> {
     queue: wgpu::Queue,
     format: wgpu::TextureFormat,
     theme: PhantomData<Theme>,
+    w: PhantomData<W>,
 }
 
-impl<Theme> Compositor<Theme> {
+impl<W: HasWindowHandle + HasDisplayHandle + wgpu::WasmNotSendSync, Theme>
+    Compositor<W, Theme>
+{
     /// Requests a new [`Compositor`] with the given [`Settings`].
     ///
     /// Returns `None` if no compatible graphics adapter could be found.
-    pub async fn request<W: HasRawWindowHandle + HasRawDisplayHandle>(
+    pub async fn request(
         settings: Settings,
-        compatible_window: Option<&W>,
+        compatible_window: Option<W>,
     ) -> Option<Self> {
         let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
             backends: settings.internal_backend,
@@ -41,6 +44,7 @@ impl<Theme> Compositor<Theme> {
         if log::max_level() >= log::LevelFilter::Info {
             let available_adapters: Vec<_> = instance
                 .enumerate_adapters(settings.internal_backend)
+                .iter()
                 .map(|adapter| adapter.get_info())
                 .collect();
             log::info!("Available adapters: {available_adapters:#?}");
@@ -48,7 +52,7 @@ impl<Theme> Compositor<Theme> {
 
         #[allow(unsafe_code)]
         let compatible_surface = compatible_window
-            .and_then(|window| unsafe { instance.create_surface(window).ok() });
+            .and_then(|window| instance.create_surface(window).ok());
 
         let adapter = instance
             .request_adapter(&wgpu::RequestAdapterOptions {
@@ -100,14 +104,14 @@ impl<Theme> Compositor<Theme> {
 
         let (device, queue) =
             loop {
-                let limits = limits.next()?;
+                let required_limits = limits.next()?;
                 let device = adapter.request_device(
                     &wgpu::DeviceDescriptor {
                         label: Some(
                             "iced_wgpu::window::compositor device descriptor",
                         ),
-                        features: wgpu::Features::empty(),
-                        limits,
+                        required_features: wgpu::Features::empty(),
+                        required_limits,
                     },
                     None,
                 ).await.ok();
@@ -125,6 +129,7 @@ impl<Theme> Compositor<Theme> {
             queue,
             format,
             theme: PhantomData,
+            w: PhantomData,
         })
     }
 
@@ -136,10 +141,13 @@ impl<Theme> Compositor<Theme> {
 
 /// Creates a [`Compositor`] and its [`Backend`] for the given [`Settings`] and
 /// window.
-pub fn new<Theme, W: HasRawWindowHandle + HasRawDisplayHandle>(
+pub fn new<
+    Theme,
+    W: HasWindowHandle + HasDisplayHandle + wgpu::WasmNotSendSync,
+>(
     settings: Settings,
-    compatible_window: Option<&W>,
-) -> Result<Compositor<Theme>, Error> {
+    compatible_window: Option<W>,
+) -> Result<Compositor<W, Theme>, Error> {
     let compositor = futures::executor::block_on(Compositor::request(
         settings,
         compatible_window,
@@ -150,10 +158,10 @@ pub fn new<Theme, W: HasRawWindowHandle + HasRawDisplayHandle>(
 }
 
 /// Presents the given primitives with the given [`Compositor`] and [`Backend`].
-pub fn present<Theme, T: AsRef<str>>(
-    compositor: &mut Compositor<Theme>,
+pub fn present<W, Theme, T: AsRef<str>>(
+    compositor: &mut Compositor<W, Theme>,
     backend: &mut Backend,
-    surface: &mut wgpu::Surface,
+    surface: &mut wgpu::Surface<'static>,
     primitives: &[Primitive],
     viewport: &Viewport,
     background_color: Color,
@@ -204,14 +212,19 @@ pub fn present<Theme, T: AsRef<str>>(
     }
 }
 
-impl<Theme> graphics::Compositor for Compositor<Theme> {
+impl<
+        W: HasDisplayHandle + HasWindowHandle + wgpu::WasmNotSendSync + 'static,
+        Theme,
+    > graphics::Compositor<W> for Compositor<W, Theme>
+{
     type Settings = Settings;
     type Renderer = Renderer<Theme>;
-    type Surface = wgpu::Surface;
+    // XXX generic instead of 'static
+    type Surface = wgpu::Surface<'static>;
 
-    fn new<W: HasRawWindowHandle + HasRawDisplayHandle>(
+    fn new(
         settings: Self::Settings,
-        compatible_window: Option<&W>,
+        compatible_window: Option<W>,
     ) -> Result<Self, Error> {
         new(settings, compatible_window)
     }
@@ -224,14 +237,15 @@ impl<Theme> graphics::Compositor for Compositor<Theme> {
         )
     }
 
-    fn create_surface<W: HasRawWindowHandle + HasRawDisplayHandle>(
+    fn create_surface(
         &mut self,
-        window: &W,
+        window: W,
         width: u32,
         height: u32,
-    ) -> wgpu::Surface {
-        #[allow(unsafe_code)]
-        let mut surface = unsafe { self.instance.create_surface(window) }
+    ) -> wgpu::Surface<'static> {
+        let mut surface = self
+            .instance
+            .create_surface(window)
             .expect("Create surface");
 
         self.configure_surface(&mut surface, width, height);
@@ -241,7 +255,7 @@ impl<Theme> graphics::Compositor for Compositor<Theme> {
 
     fn configure_surface(
         &mut self,
-        surface: &mut Self::Surface,
+        surface: &mut wgpu::Surface<'static>,
         width: u32,
         height: u32,
     ) {
@@ -255,6 +269,7 @@ impl<Theme> graphics::Compositor for Compositor<Theme> {
                 height,
                 alpha_mode: wgpu::CompositeAlphaMode::Auto,
                 view_formats: vec![],
+                desired_maximum_frame_latency: 2,
             },
         );
     }
@@ -271,7 +286,7 @@ impl<Theme> graphics::Compositor for Compositor<Theme> {
     fn present<T: AsRef<str>>(
         &mut self,
         renderer: &mut Self::Renderer,
-        surface: &mut Self::Surface,
+        surface: &mut wgpu::Surface<'static>,
         viewport: &Viewport,
         background_color: Color,
         overlay: &[T],
@@ -292,7 +307,7 @@ impl<Theme> graphics::Compositor for Compositor<Theme> {
     fn screenshot<T: AsRef<str>>(
         &mut self,
         renderer: &mut Self::Renderer,
-        _surface: &mut Self::Surface,
+        _surface: &mut wgpu::Surface<'static>,
         viewport: &Viewport,
         background_color: Color,
         overlay: &[T],
@@ -313,8 +328,8 @@ impl<Theme> graphics::Compositor for Compositor<Theme> {
 /// Renders the current surface to an offscreen buffer.
 ///
 /// Returns RGBA bytes of the texture data.
-pub fn screenshot<Theme, T: AsRef<str>>(
-    compositor: &Compositor<Theme>,
+pub fn screenshot<W, Theme, T: AsRef<str>>(
+    compositor: &Compositor<W, Theme>,
     backend: &mut Backend,
     primitives: &[Primitive],
     viewport: &Viewport,
-- 
cgit 


From 8bf238697226e827dc983f9d89afbd0e252c5254 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector@hecrj.dev>
Date: Thu, 18 Jan 2024 09:55:27 +0100
Subject: Remove `Compositor` window generic

And update `glyphon` and `window_clipboard`
---
 wgpu/Cargo.toml               |  1 -
 wgpu/src/window/compositor.rs | 40 +++++++++++++---------------------------
 2 files changed, 13 insertions(+), 28 deletions(-)

(limited to 'wgpu')

diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml
index a460c127..1d3b57a7 100644
--- a/wgpu/Cargo.toml
+++ b/wgpu/Cargo.toml
@@ -32,7 +32,6 @@ glyphon.workspace = true
 guillotiere.workspace = true
 log.workspace = true
 once_cell.workspace = true
-raw-window-handle.workspace = true
 wgpu.workspace = true
 
 lyon.workspace = true
diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs
index e2dc4901..0c063d0b 100644
--- a/wgpu/src/window/compositor.rs
+++ b/wgpu/src/window/compositor.rs
@@ -6,13 +6,11 @@ use crate::graphics::compositor;
 use crate::graphics::{Error, Viewport};
 use crate::{Backend, Primitive, Renderer, Settings};
 
-use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
-
 use std::marker::PhantomData;
 
 /// A window graphics backend for iced powered by `wgpu`.
 #[allow(missing_debug_implementations)]
-pub struct Compositor<W, Theme> {
+pub struct Compositor<Theme> {
     settings: Settings,
     instance: wgpu::Instance,
     adapter: wgpu::Adapter,
@@ -20,16 +18,13 @@ pub struct Compositor<W, Theme> {
     queue: wgpu::Queue,
     format: wgpu::TextureFormat,
     theme: PhantomData<Theme>,
-    w: PhantomData<W>,
 }
 
-impl<W: HasWindowHandle + HasDisplayHandle + wgpu::WasmNotSendSync, Theme>
-    Compositor<W, Theme>
-{
+impl<Theme> Compositor<Theme> {
     /// Requests a new [`Compositor`] with the given [`Settings`].
     ///
     /// Returns `None` if no compatible graphics adapter could be found.
-    pub async fn request(
+    pub async fn request<W: compositor::Window>(
         settings: Settings,
         compatible_window: Option<W>,
     ) -> Option<Self> {
@@ -45,7 +40,7 @@ impl<W: HasWindowHandle + HasDisplayHandle + wgpu::WasmNotSendSync, Theme>
             let available_adapters: Vec<_> = instance
                 .enumerate_adapters(settings.internal_backend)
                 .iter()
-                .map(|adapter| adapter.get_info())
+                .map(wgpu::Adapter::get_info)
                 .collect();
             log::info!("Available adapters: {available_adapters:#?}");
         }
@@ -129,7 +124,6 @@ impl<W: HasWindowHandle + HasDisplayHandle + wgpu::WasmNotSendSync, Theme>
             queue,
             format,
             theme: PhantomData,
-            w: PhantomData,
         })
     }
 
@@ -141,13 +135,10 @@ impl<W: HasWindowHandle + HasDisplayHandle + wgpu::WasmNotSendSync, Theme>
 
 /// Creates a [`Compositor`] and its [`Backend`] for the given [`Settings`] and
 /// window.
-pub fn new<
-    Theme,
-    W: HasWindowHandle + HasDisplayHandle + wgpu::WasmNotSendSync,
->(
+pub fn new<W: compositor::Window, Theme>(
     settings: Settings,
     compatible_window: Option<W>,
-) -> Result<Compositor<W, Theme>, Error> {
+) -> Result<Compositor<Theme>, Error> {
     let compositor = futures::executor::block_on(Compositor::request(
         settings,
         compatible_window,
@@ -158,8 +149,8 @@ pub fn new<
 }
 
 /// Presents the given primitives with the given [`Compositor`] and [`Backend`].
-pub fn present<W, Theme, T: AsRef<str>>(
-    compositor: &mut Compositor<W, Theme>,
+pub fn present<Theme, T: AsRef<str>>(
+    compositor: &mut Compositor<Theme>,
     backend: &mut Backend,
     surface: &mut wgpu::Surface<'static>,
     primitives: &[Primitive],
@@ -212,17 +203,12 @@ pub fn present<W, Theme, T: AsRef<str>>(
     }
 }
 
-impl<
-        W: HasDisplayHandle + HasWindowHandle + wgpu::WasmNotSendSync + 'static,
-        Theme,
-    > graphics::Compositor<W> for Compositor<W, Theme>
-{
+impl<Theme> graphics::Compositor for Compositor<Theme> {
     type Settings = Settings;
     type Renderer = Renderer<Theme>;
-    // XXX generic instead of 'static
     type Surface = wgpu::Surface<'static>;
 
-    fn new(
+    fn new<W: compositor::Window>(
         settings: Self::Settings,
         compatible_window: Option<W>,
     ) -> Result<Self, Error> {
@@ -237,7 +223,7 @@ impl<
         )
     }
 
-    fn create_surface(
+    fn create_surface<W: compositor::Window>(
         &mut self,
         window: W,
         width: u32,
@@ -328,8 +314,8 @@ impl<
 /// Renders the current surface to an offscreen buffer.
 ///
 /// Returns RGBA bytes of the texture data.
-pub fn screenshot<W, Theme, T: AsRef<str>>(
-    compositor: &Compositor<W, Theme>,
+pub fn screenshot<Theme, T: AsRef<str>>(
+    compositor: &Compositor<Theme>,
     backend: &mut Backend,
     primitives: &[Primitive],
     viewport: &Viewport,
-- 
cgit 


From 5fc49edc55a0e64c4c46ca55eddafe9d4e8232e1 Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector@hecrj.dev>
Date: Thu, 18 Jan 2024 10:06:30 +0100
Subject: Make `compatible_window` mandatory in `Compositor`

---
 wgpu/src/window/compositor.rs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

(limited to 'wgpu')

diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs
index 0c063d0b..105d83a8 100644
--- a/wgpu/src/window/compositor.rs
+++ b/wgpu/src/window/compositor.rs
@@ -137,11 +137,11 @@ impl<Theme> Compositor<Theme> {
 /// window.
 pub fn new<W: compositor::Window, Theme>(
     settings: Settings,
-    compatible_window: Option<W>,
+    compatible_window: W,
 ) -> Result<Compositor<Theme>, Error> {
     let compositor = futures::executor::block_on(Compositor::request(
         settings,
-        compatible_window,
+        Some(compatible_window),
     ))
     .ok_or(Error::GraphicsAdapterNotFound)?;
 
@@ -210,7 +210,7 @@ impl<Theme> graphics::Compositor for Compositor<Theme> {
 
     fn new<W: compositor::Window>(
         settings: Self::Settings,
-        compatible_window: Option<W>,
+        compatible_window: W,
     ) -> Result<Self, Error> {
         new(settings, compatible_window)
     }
-- 
cgit 


From c929e6f5dd30044df4e7400ab633eaf0a53ce3dd Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector@hecrj.dev>
Date: Thu, 18 Jan 2024 10:56:02 +0100
Subject: Use `Self::Surface` in `Compositor` implementors

---
 wgpu/src/window/compositor.rs | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

(limited to 'wgpu')

diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs
index 105d83a8..31cf3819 100644
--- a/wgpu/src/window/compositor.rs
+++ b/wgpu/src/window/compositor.rs
@@ -228,7 +228,7 @@ impl<Theme> graphics::Compositor for Compositor<Theme> {
         window: W,
         width: u32,
         height: u32,
-    ) -> wgpu::Surface<'static> {
+    ) -> Self::Surface {
         let mut surface = self
             .instance
             .create_surface(window)
@@ -241,7 +241,7 @@ impl<Theme> graphics::Compositor for Compositor<Theme> {
 
     fn configure_surface(
         &mut self,
-        surface: &mut wgpu::Surface<'static>,
+        surface: &mut Self::Surface,
         width: u32,
         height: u32,
     ) {
@@ -272,7 +272,7 @@ impl<Theme> graphics::Compositor for Compositor<Theme> {
     fn present<T: AsRef<str>>(
         &mut self,
         renderer: &mut Self::Renderer,
-        surface: &mut wgpu::Surface<'static>,
+        surface: &mut Self::Surface,
         viewport: &Viewport,
         background_color: Color,
         overlay: &[T],
@@ -293,7 +293,7 @@ impl<Theme> graphics::Compositor for Compositor<Theme> {
     fn screenshot<T: AsRef<str>>(
         &mut self,
         renderer: &mut Self::Renderer,
-        _surface: &mut wgpu::Surface<'static>,
+        _surface: &mut Self::Surface,
         viewport: &Viewport,
         background_color: Color,
         overlay: &[T],
-- 
cgit