From 2bb53ad6e7ea2689f2f56662e5840a8d363b3108 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 29 Mar 2024 04:02:24 +0100 Subject: Use a `StagingBelt` in `iced_wgpu` for regular buffer uploads --- wgpu/src/quad.rs | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) (limited to 'wgpu/src/quad.rs') diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs index b932f54f..0717a031 100644 --- a/wgpu/src/quad.rs +++ b/wgpu/src/quad.rs @@ -57,7 +57,8 @@ impl Pipeline { pub fn prepare( &mut self, device: &wgpu::Device, - queue: &wgpu::Queue, + encoder: &mut wgpu::CommandEncoder, + belt: &mut wgpu::util::StagingBelt, quads: &Batch, transformation: Transformation, scale: f32, @@ -67,7 +68,7 @@ impl Pipeline { } let layer = &mut self.layers[self.prepare_layer]; - layer.prepare(device, queue, quads, transformation, scale); + layer.prepare(device, encoder, belt, quads, transformation, scale); self.prepare_layer += 1; } @@ -162,7 +163,8 @@ impl Layer { pub fn prepare( &mut self, device: &wgpu::Device, - queue: &wgpu::Queue, + encoder: &mut wgpu::CommandEncoder, + belt: &mut wgpu::util::StagingBelt, quads: &Batch, transformation: Transformation, scale: f32, @@ -171,15 +173,25 @@ impl Layer { let _ = info_span!("Wgpu::Quad", "PREPARE").entered(); let uniforms = Uniforms::new(transformation, scale); + let bytes = bytemuck::bytes_of(&uniforms); - queue.write_buffer( + belt.write_buffer( + encoder, &self.constants_buffer, 0, - bytemuck::bytes_of(&uniforms), - ); + (bytes.len() as u64).try_into().expect("Sized uniforms"), + device, + ) + .copy_from_slice(bytes); - self.solid.prepare(device, queue, &quads.solids); - self.gradient.prepare(device, queue, &quads.gradients); + if !quads.solids.is_empty() { + self.solid.prepare(device, encoder, belt, &quads.solids); + } + + if !quads.gradients.is_empty() { + self.gradient + .prepare(device, encoder, belt, &quads.gradients); + } } } -- cgit From b05e61f5c8ae61c9f3c7cc08cded53901ebbccfd Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 3 Apr 2024 21:07:54 +0200 Subject: Redesign `iced_wgpu` layering architecture --- wgpu/src/quad.rs | 294 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 214 insertions(+), 80 deletions(-) (limited to 'wgpu/src/quad.rs') diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs index 0717a031..16d50b04 100644 --- a/wgpu/src/quad.rs +++ b/wgpu/src/quad.rs @@ -12,11 +12,37 @@ use bytemuck::{Pod, Zeroable}; use std::mem; -#[cfg(feature = "tracing")] -use tracing::info_span; - const INITIAL_INSTANCES: usize = 2_000; +/// The properties of a quad. +#[derive(Clone, Copy, Debug, Pod, Zeroable)] +#[repr(C)] +pub struct Quad { + /// The position of the [`Quad`]. + pub position: [f32; 2], + + /// The size of the [`Quad`]. + pub size: [f32; 2], + + /// The border color of the [`Quad`], in __linear RGB__. + pub border_color: color::Packed, + + /// The border radii of the [`Quad`]. + pub border_radius: [f32; 4], + + /// The border width of the [`Quad`]. + pub border_width: f32, + + /// The shadow color of the [`Quad`]. + pub shadow_color: color::Packed, + + /// The shadow offset of the [`Quad`]. + pub shadow_offset: [f32; 2], + + /// The shadow blur radius of the [`Quad`]. + pub shadow_blur_radius: f32, +} + #[derive(Debug)] pub struct Pipeline { solid: solid::Pipeline, @@ -54,7 +80,7 @@ impl Pipeline { } } - pub fn prepare( + pub fn prepare_batch( &mut self, device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder, @@ -73,7 +99,64 @@ impl Pipeline { self.prepare_layer += 1; } - pub fn render<'a>( + pub fn prepare_cache( + &self, + device: &wgpu::Device, + encoder: &mut wgpu::CommandEncoder, + belt: &mut wgpu::util::StagingBelt, + cache: &mut Cache, + transformation: Transformation, + scale: f32, + ) { + match cache { + Cache::Staged(_) => { + let Cache::Staged(batch) = + std::mem::replace(cache, Cache::Staged(Batch::default())) + else { + unreachable!() + }; + + let mut layer = Layer::new(device, &self.constant_layout); + layer.prepare( + device, + encoder, + belt, + &batch, + transformation, + scale, + ); + + *cache = Cache::Uploaded { + layer, + batch, + needs_reupload: false, + } + } + + Cache::Uploaded { + batch, + layer, + needs_reupload, + } => { + if *needs_reupload { + layer.prepare( + device, + encoder, + belt, + batch, + transformation, + scale, + ); + + *needs_reupload = false; + } else { + layer.update(device, encoder, belt, transformation, scale); + } + } + } + } + + pub fn render_batch<'a>( &'a self, layer: usize, bounds: Rectangle, @@ -81,38 +164,59 @@ impl Pipeline { render_pass: &mut wgpu::RenderPass<'a>, ) { if let Some(layer) = self.layers.get(layer) { - render_pass.set_scissor_rect( - bounds.x, - bounds.y, - bounds.width, - bounds.height, - ); - - let mut solid_offset = 0; - let mut gradient_offset = 0; - - for (kind, count) in &quads.order { - match kind { - Kind::Solid => { - self.solid.render( - render_pass, - &layer.constants, - &layer.solid, - solid_offset..(solid_offset + count), - ); - - solid_offset += count; - } - Kind::Gradient => { - self.gradient.render( - render_pass, - &layer.constants, - &layer.gradient, - gradient_offset..(gradient_offset + count), - ); - - gradient_offset += count; - } + self.render(bounds, layer, &quads.order, render_pass); + } + } + + pub fn render_cache<'a>( + &'a self, + cache: &'a Cache, + bounds: Rectangle, + render_pass: &mut wgpu::RenderPass<'a>, + ) { + if let Cache::Uploaded { layer, batch, .. } = cache { + self.render(bounds, layer, &batch.order, render_pass); + } + } + + fn render<'a>( + &'a self, + bounds: Rectangle, + layer: &'a Layer, + order: &Order, + render_pass: &mut wgpu::RenderPass<'a>, + ) { + render_pass.set_scissor_rect( + bounds.x, + bounds.y, + bounds.width, + bounds.height, + ); + + let mut solid_offset = 0; + let mut gradient_offset = 0; + + for (kind, count) in order { + match kind { + Kind::Solid => { + self.solid.render( + render_pass, + &layer.constants, + &layer.solid, + solid_offset..(solid_offset + count), + ); + + solid_offset += count; + } + Kind::Gradient => { + self.gradient.render( + render_pass, + &layer.constants, + &layer.gradient, + gradient_offset..(gradient_offset + count), + ); + + gradient_offset += count; } } } @@ -124,7 +228,49 @@ impl Pipeline { } #[derive(Debug)] -struct Layer { +pub enum Cache { + Staged(Batch), + Uploaded { + batch: Batch, + layer: Layer, + needs_reupload: bool, + }, +} + +impl Cache { + pub fn is_empty(&self) -> bool { + match self { + Cache::Staged(batch) | Cache::Uploaded { batch, .. } => { + batch.is_empty() + } + } + } + + pub fn update(&mut self, new_batch: Batch) { + match self { + Self::Staged(batch) => { + *batch = new_batch; + } + Self::Uploaded { + batch, + needs_reupload, + .. + } => { + *batch = new_batch; + *needs_reupload = true; + } + } + } +} + +impl Default for Cache { + fn default() -> Self { + Self::Staged(Batch::default()) + } +} + +#[derive(Debug)] +pub struct Layer { constants: wgpu::BindGroup, constants_buffer: wgpu::Buffer, solid: solid::Layer, @@ -169,9 +315,26 @@ impl Layer { transformation: Transformation, scale: f32, ) { - #[cfg(feature = "tracing")] - let _ = info_span!("Wgpu::Quad", "PREPARE").entered(); + self.update(device, encoder, belt, transformation, scale); + + if !quads.solids.is_empty() { + self.solid.prepare(device, encoder, belt, &quads.solids); + } + + if !quads.gradients.is_empty() { + self.gradient + .prepare(device, encoder, belt, &quads.gradients); + } + } + pub fn update( + &mut self, + device: &wgpu::Device, + encoder: &mut wgpu::CommandEncoder, + belt: &mut wgpu::util::StagingBelt, + transformation: Transformation, + scale: f32, + ) { let uniforms = Uniforms::new(transformation, scale); let bytes = bytemuck::bytes_of(&uniforms); @@ -183,47 +346,9 @@ impl Layer { device, ) .copy_from_slice(bytes); - - if !quads.solids.is_empty() { - self.solid.prepare(device, encoder, belt, &quads.solids); - } - - if !quads.gradients.is_empty() { - self.gradient - .prepare(device, encoder, belt, &quads.gradients); - } } } -/// The properties of a quad. -#[derive(Clone, Copy, Debug, Pod, Zeroable)] -#[repr(C)] -pub struct Quad { - /// The position of the [`Quad`]. - pub position: [f32; 2], - - /// The size of the [`Quad`]. - pub size: [f32; 2], - - /// The border color of the [`Quad`], in __linear RGB__. - pub border_color: color::Packed, - - /// The border radii of the [`Quad`]. - pub border_radius: [f32; 4], - - /// The border width of the [`Quad`]. - pub border_width: f32, - - /// The shadow color of the [`Quad`]. - pub shadow_color: [f32; 4], - - /// The shadow offset of the [`Quad`]. - pub shadow_offset: [f32; 2], - - /// The shadow blur radius of the [`Quad`]. - pub shadow_blur_radius: f32, -} - /// A group of [`Quad`]s rendered together. #[derive(Default, Debug)] pub struct Batch { @@ -233,10 +358,13 @@ pub struct Batch { /// The gradient quads of the [`Layer`]. gradients: Vec, - /// The quad order of the [`Layer`]; stored as a tuple of the quad type & its count. - order: Vec<(Kind, usize)>, + /// The quad order of the [`Layer`]. + order: Order, } +/// The quad order of a [`Layer`]; stored as a tuple of the quad type & its count. +type Order = Vec<(Kind, usize)>; + impl Batch { /// Returns true if there are no quads of any type in [`Quads`]. pub fn is_empty(&self) -> bool { @@ -276,6 +404,12 @@ impl Batch { } } } + + pub fn clear(&mut self) { + self.solids.clear(); + self.gradients.clear(); + self.order.clear(); + } } #[derive(Debug, Copy, Clone, PartialEq, Eq)] -- cgit From 6d3e1d835e1688fbc58622a03a784ed25ed3f0e1 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 5 Apr 2024 23:59:21 +0200 Subject: Decouple caching from layering and simplify everything --- wgpu/src/quad.rs | 188 ++++++++++--------------------------------------------- 1 file changed, 34 insertions(+), 154 deletions(-) (limited to 'wgpu/src/quad.rs') diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs index 16d50b04..de432d2f 100644 --- a/wgpu/src/quad.rs +++ b/wgpu/src/quad.rs @@ -80,7 +80,7 @@ impl Pipeline { } } - pub fn prepare_batch( + pub fn prepare( &mut self, device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder, @@ -99,64 +99,7 @@ impl Pipeline { self.prepare_layer += 1; } - pub fn prepare_cache( - &self, - device: &wgpu::Device, - encoder: &mut wgpu::CommandEncoder, - belt: &mut wgpu::util::StagingBelt, - cache: &mut Cache, - transformation: Transformation, - scale: f32, - ) { - match cache { - Cache::Staged(_) => { - let Cache::Staged(batch) = - std::mem::replace(cache, Cache::Staged(Batch::default())) - else { - unreachable!() - }; - - let mut layer = Layer::new(device, &self.constant_layout); - layer.prepare( - device, - encoder, - belt, - &batch, - transformation, - scale, - ); - - *cache = Cache::Uploaded { - layer, - batch, - needs_reupload: false, - } - } - - Cache::Uploaded { - batch, - layer, - needs_reupload, - } => { - if *needs_reupload { - layer.prepare( - device, - encoder, - belt, - batch, - transformation, - scale, - ); - - *needs_reupload = false; - } else { - layer.update(device, encoder, belt, transformation, scale); - } - } - } - } - - pub fn render_batch<'a>( + pub fn render<'a>( &'a self, layer: usize, bounds: Rectangle, @@ -164,59 +107,38 @@ impl Pipeline { render_pass: &mut wgpu::RenderPass<'a>, ) { if let Some(layer) = self.layers.get(layer) { - self.render(bounds, layer, &quads.order, render_pass); - } - } - - pub fn render_cache<'a>( - &'a self, - cache: &'a Cache, - bounds: Rectangle, - render_pass: &mut wgpu::RenderPass<'a>, - ) { - if let Cache::Uploaded { layer, batch, .. } = cache { - self.render(bounds, layer, &batch.order, render_pass); - } - } - - fn render<'a>( - &'a self, - bounds: Rectangle, - layer: &'a Layer, - order: &Order, - render_pass: &mut wgpu::RenderPass<'a>, - ) { - render_pass.set_scissor_rect( - bounds.x, - bounds.y, - bounds.width, - bounds.height, - ); - - let mut solid_offset = 0; - let mut gradient_offset = 0; - - for (kind, count) in order { - match kind { - Kind::Solid => { - self.solid.render( - render_pass, - &layer.constants, - &layer.solid, - solid_offset..(solid_offset + count), - ); - - solid_offset += count; - } - Kind::Gradient => { - self.gradient.render( - render_pass, - &layer.constants, - &layer.gradient, - gradient_offset..(gradient_offset + count), - ); - - gradient_offset += count; + render_pass.set_scissor_rect( + bounds.x, + bounds.y, + bounds.width, + bounds.height, + ); + + let mut solid_offset = 0; + let mut gradient_offset = 0; + + for (kind, count) in &quads.order { + match kind { + Kind::Solid => { + self.solid.render( + render_pass, + &layer.constants, + &layer.solid, + solid_offset..(solid_offset + count), + ); + + solid_offset += count; + } + Kind::Gradient => { + self.gradient.render( + render_pass, + &layer.constants, + &layer.gradient, + gradient_offset..(gradient_offset + count), + ); + + gradient_offset += count; + } } } } @@ -227,48 +149,6 @@ impl Pipeline { } } -#[derive(Debug)] -pub enum Cache { - Staged(Batch), - Uploaded { - batch: Batch, - layer: Layer, - needs_reupload: bool, - }, -} - -impl Cache { - pub fn is_empty(&self) -> bool { - match self { - Cache::Staged(batch) | Cache::Uploaded { batch, .. } => { - batch.is_empty() - } - } - } - - pub fn update(&mut self, new_batch: Batch) { - match self { - Self::Staged(batch) => { - *batch = new_batch; - } - Self::Uploaded { - batch, - needs_reupload, - .. - } => { - *batch = new_batch; - *needs_reupload = true; - } - } - } -} - -impl Default for Cache { - fn default() -> Self { - Self::Staged(Batch::default()) - } -} - #[derive(Debug)] pub struct Layer { constants: wgpu::BindGroup, -- cgit