diff options
author | 2024-04-03 21:07:54 +0200 | |
---|---|---|
committer | 2024-04-03 21:07:54 +0200 | |
commit | b05e61f5c8ae61c9f3c7cc08cded53901ebbccfd (patch) | |
tree | 3d35a011d94d4936f09b5a9be4031358a09c60da /wgpu/src/quad.rs | |
parent | 99a904112ca111f2ab0e60e30b6c369741b1653b (diff) | |
download | iced-b05e61f5c8ae61c9f3c7cc08cded53901ebbccfd.tar.gz iced-b05e61f5c8ae61c9f3c7cc08cded53901ebbccfd.tar.bz2 iced-b05e61f5c8ae61c9f3c7cc08cded53901ebbccfd.zip |
Redesign `iced_wgpu` layering architecture
Diffstat (limited to 'wgpu/src/quad.rs')
-rw-r--r-- | wgpu/src/quad.rs | 294 |
1 files changed, 214 insertions, 80 deletions
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<u32>, @@ -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<u32>, + 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<u32>, + 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<Gradient>, - /// 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)] |