From 363966ee9e7aa81a3679eaea776d2c867aa6c3b0 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 7 Feb 2023 22:53:08 +0100 Subject: Refactor `image::Pipeline` into `prepare` and `render` architecture --- wgpu/src/image.rs | 259 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 143 insertions(+), 116 deletions(-) (limited to 'wgpu/src/image.rs') diff --git a/wgpu/src/image.rs b/wgpu/src/image.rs index a5e63b17..f6c39f1a 100644 --- a/wgpu/src/image.rs +++ b/wgpu/src/image.rs @@ -6,7 +6,7 @@ use iced_graphics::image::raster; #[cfg(feature = "svg")] use iced_graphics::image::vector; -use crate::Transformation; +use crate::{Buffer, Transformation}; use atlas::Atlas; use iced_graphics::layer; @@ -34,15 +34,108 @@ pub struct Pipeline { vector_cache: RefCell>, pipeline: wgpu::RenderPipeline, - uniforms: wgpu::Buffer, vertices: wgpu::Buffer, indices: wgpu::Buffer, - instances: wgpu::Buffer, - constants: wgpu::BindGroup, + sampler: wgpu::Sampler, texture: wgpu::BindGroup, texture_version: usize, - texture_layout: wgpu::BindGroupLayout, texture_atlas: Atlas, + texture_layout: wgpu::BindGroupLayout, + constant_layout: wgpu::BindGroupLayout, + + layers: Vec, + prepare_layer: usize, + render_layer: usize, +} + +#[derive(Debug)] +struct Layer { + uniforms: wgpu::Buffer, + constants: wgpu::BindGroup, + instances: Buffer, + instance_count: usize, +} + +impl Layer { + fn new( + device: &wgpu::Device, + constant_layout: &wgpu::BindGroupLayout, + sampler: &wgpu::Sampler, + ) -> Self { + let uniforms = device.create_buffer(&wgpu::BufferDescriptor { + label: Some("iced_wgpu::image uniforms buffer"), + size: mem::size_of::() as u64, + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, + mapped_at_creation: false, + }); + + let constants = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("iced_wgpu::image constants bind group"), + layout: &constant_layout, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::Buffer( + wgpu::BufferBinding { + buffer: &uniforms, + offset: 0, + size: None, + }, + ), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::Sampler(&sampler), + }, + ], + }); + + let instances = Buffer::new( + device, + "iced_wgpu::image instance buffer", + Instance::INITIAL, + wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST, + ); + + Self { + uniforms, + constants, + instances, + instance_count: 0, + } + } + + fn prepare( + &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()); + self.instances.write(queue, 0, instances); + + self.instance_count = instances.len(); + } + + fn render<'a>(&'a self, render_pass: &mut wgpu::RenderPass<'a>) { + render_pass.set_bind_group(0, &self.constants, &[]); + render_pass.set_vertex_buffer(1, self.instances.slice(..)); + + render_pass.draw_indexed( + 0..QUAD_INDICES.len() as u32, + 0, + 0..self.instance_count as u32, + ); + } } impl Pipeline { @@ -86,35 +179,6 @@ impl Pipeline { ], }); - let uniforms_buffer = device.create_buffer(&wgpu::BufferDescriptor { - label: Some("iced_wgpu::image uniforms buffer"), - size: mem::size_of::() as u64, - usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, - mapped_at_creation: false, - }); - - let constant_bind_group = - device.create_bind_group(&wgpu::BindGroupDescriptor { - label: Some("iced_wgpu::image constants bind group"), - layout: &constant_layout, - entries: &[ - wgpu::BindGroupEntry { - binding: 0, - resource: wgpu::BindingResource::Buffer( - wgpu::BufferBinding { - buffer: &uniforms_buffer, - offset: 0, - size: None, - }, - ), - }, - wgpu::BindGroupEntry { - binding: 1, - resource: wgpu::BindingResource::Sampler(&sampler), - }, - ], - }); - let texture_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { label: Some("iced_wgpu::image texture atlas layout"), @@ -225,13 +289,6 @@ impl Pipeline { usage: wgpu::BufferUsages::INDEX, }); - let instances = device.create_buffer(&wgpu::BufferDescriptor { - label: Some("iced_wgpu::image instance buffer"), - size: mem::size_of::() as u64 * Instance::MAX as u64, - usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST, - mapped_at_creation: false, - }); - let texture_atlas = Atlas::new(device); let texture = device.create_bind_group(&wgpu::BindGroupDescriptor { @@ -253,15 +310,18 @@ impl Pipeline { vector_cache: RefCell::new(vector::Cache::default()), pipeline, - uniforms: uniforms_buffer, vertices, indices, - instances, - constants: constant_bind_group, + sampler, texture, texture_version: texture_atlas.layer_count(), - texture_layout, texture_atlas, + texture_layout, + constant_layout, + + layers: Vec::new(), + prepare_layer: 0, + render_layer: 0, } } @@ -281,17 +341,18 @@ impl Pipeline { svg.viewport_dimensions() } - pub fn draw( + pub fn prepare( &mut self, device: &wgpu::Device, - staging_belt: &mut wgpu::util::StagingBelt, + queue: &wgpu::Queue, encoder: &mut wgpu::CommandEncoder, images: &[layer::Image], transformation: Transformation, - bounds: Rectangle, - target: &wgpu::TextureView, _scale: f32, ) { + #[cfg(feature = "tracing")] + let _ = info_span!("Wgpu::Image", "PREPARE").entered(); + #[cfg(feature = "tracing")] let _ = info_span!("Wgpu::Image", "DRAW").entered(); @@ -309,7 +370,7 @@ impl Pipeline { layer::Image::Raster { handle, bounds } => { if let Some(atlas_entry) = raster_cache.upload( handle, - &mut (device, encoder), + &mut (device, queue, encoder), &mut self.texture_atlas, ) { add_instances( @@ -336,7 +397,7 @@ impl Pipeline { *color, size, _scale, - &mut (device, encoder), + &mut (device, queue, encoder), &mut self.texture_atlas, ) { add_instances( @@ -376,68 +437,27 @@ impl Pipeline { self.texture_version = texture_version; } - { - let mut uniforms_buffer = staging_belt.write_buffer( - encoder, - &self.uniforms, - 0, - wgpu::BufferSize::new(mem::size_of::() as u64) - .unwrap(), + if self.layers.len() <= self.prepare_layer { + self.layers.push(Layer::new( device, - ); - - uniforms_buffer.copy_from_slice(bytemuck::bytes_of(&Uniforms { - transform: transformation.into(), - })); + &self.constant_layout, + &self.sampler, + )); } - let mut i = 0; - let total = instances.len(); - - while i < total { - let end = (i + Instance::MAX).min(total); - let amount = end - i; - - let mut instances_buffer = staging_belt.write_buffer( - encoder, - &self.instances, - 0, - wgpu::BufferSize::new( - (amount * std::mem::size_of::()) as u64, - ) - .unwrap(), - device, - ); - - instances_buffer.copy_from_slice(bytemuck::cast_slice( - &instances[i..i + amount], - )); + let layer = &mut self.layers[self.prepare_layer]; + layer.prepare(device, queue, instances, transformation); - let mut render_pass = - encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - label: Some("iced_wgpu::image 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, - }); + self.prepare_layer += 1; + } + pub fn render<'a>( + &'a mut self, + bounds: Rectangle, + render_pass: &mut wgpu::RenderPass<'a>, + ) { + if let Some(layer) = self.layers.get(self.render_layer) { render_pass.set_pipeline(&self.pipeline); - render_pass.set_bind_group(0, &self.constants, &[]); - 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(..)); - render_pass.set_vertex_buffer(1, self.instances.slice(..)); render_pass.set_scissor_rect( bounds.x, @@ -446,30 +466,37 @@ impl Pipeline { bounds.height, ); - render_pass.draw_indexed( - 0..QUAD_INDICES.len() as u32, - 0, - 0..amount as u32, + 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(..)); - i += Instance::MAX; + layer.render(render_pass); + + self.render_layer += 1; } } - pub fn trim_cache( + pub fn end_frame( &mut self, device: &wgpu::Device, + queue: &wgpu::Queue, encoder: &mut wgpu::CommandEncoder, ) { #[cfg(feature = "image")] self.raster_cache .borrow_mut() - .trim(&mut self.texture_atlas, &mut (device, encoder)); + .trim(&mut self.texture_atlas, &mut (device, queue, encoder)); #[cfg(feature = "svg")] self.vector_cache .borrow_mut() - .trim(&mut self.texture_atlas, &mut (device, encoder)); + .trim(&mut self.texture_atlas, &mut (device, queue, encoder)); + + self.prepare_layer = 0; + self.render_layer = 0; } } @@ -507,7 +534,7 @@ struct Instance { } impl Instance { - pub const MAX: usize = 1_000; + pub const INITIAL: usize = 1_000; } #[repr(C)] -- cgit From 23ed352e83dcb8a13acdac1cd4c7e2a9df492ebd Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 7 Feb 2023 22:53:41 +0100 Subject: Fix needless borrows in `image::Pipeline` --- wgpu/src/image.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'wgpu/src/image.rs') diff --git a/wgpu/src/image.rs b/wgpu/src/image.rs index f6c39f1a..5d1ae8d7 100644 --- a/wgpu/src/image.rs +++ b/wgpu/src/image.rs @@ -71,7 +71,7 @@ impl Layer { let constants = device.create_bind_group(&wgpu::BindGroupDescriptor { label: Some("iced_wgpu::image constants bind group"), - layout: &constant_layout, + layout: constant_layout, entries: &[ wgpu::BindGroupEntry { binding: 0, @@ -85,7 +85,7 @@ impl Layer { }, wgpu::BindGroupEntry { binding: 1, - resource: wgpu::BindingResource::Sampler(&sampler), + resource: wgpu::BindingResource::Sampler(sampler), }, ], }); -- cgit From 730d6a07564d014c470e02f233394ec98325d463 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 8 Feb 2023 00:47:16 +0100 Subject: Reuse a `RenderPass` as much as possible in `iced_wgpu` --- wgpu/src/image.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'wgpu/src/image.rs') diff --git a/wgpu/src/image.rs b/wgpu/src/image.rs index 5d1ae8d7..db05d2ff 100644 --- a/wgpu/src/image.rs +++ b/wgpu/src/image.rs @@ -45,7 +45,6 @@ pub struct Pipeline { layers: Vec, prepare_layer: usize, - render_layer: usize, } #[derive(Debug)] @@ -321,7 +320,6 @@ impl Pipeline { layers: Vec::new(), prepare_layer: 0, - render_layer: 0, } } @@ -452,11 +450,12 @@ impl Pipeline { } pub fn render<'a>( - &'a mut self, + &'a self, + layer: usize, bounds: Rectangle, render_pass: &mut wgpu::RenderPass<'a>, ) { - if let Some(layer) = self.layers.get(self.render_layer) { + if let Some(layer) = self.layers.get(layer) { render_pass.set_pipeline(&self.pipeline); render_pass.set_scissor_rect( @@ -474,8 +473,6 @@ impl Pipeline { render_pass.set_vertex_buffer(0, self.vertices.slice(..)); layer.render(render_pass); - - self.render_layer += 1; } } @@ -496,7 +493,6 @@ impl Pipeline { .trim(&mut self.texture_atlas, &mut (device, queue, encoder)); self.prepare_layer = 0; - self.render_layer = 0; } } -- cgit From 5fd5d1cdf8e5354788dc40729c4565ef377d3bba Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 1 Mar 2023 21:34:26 +0100 Subject: Implement `Canvas` support for `iced_tiny_skia` --- wgpu/src/image.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'wgpu/src/image.rs') diff --git a/wgpu/src/image.rs b/wgpu/src/image.rs index db05d2ff..2159a3ec 100644 --- a/wgpu/src/image.rs +++ b/wgpu/src/image.rs @@ -6,10 +6,10 @@ use iced_graphics::image::raster; #[cfg(feature = "svg")] use iced_graphics::image::vector; +use crate::layer; use crate::{Buffer, Transformation}; use atlas::Atlas; -use iced_graphics::layer; use iced_native::{Rectangle, Size}; use std::cell::RefCell; -- cgit From 3a0d34c0240f4421737a6a08761f99d6f8140d02 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 4 Mar 2023 05:37:11 +0100 Subject: Create `iced_widget` subcrate and re-organize the whole codebase --- wgpu/src/image.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'wgpu/src/image.rs') diff --git a/wgpu/src/image.rs b/wgpu/src/image.rs index 2159a3ec..5eaa9a86 100644 --- a/wgpu/src/image.rs +++ b/wgpu/src/image.rs @@ -1,16 +1,17 @@ mod atlas; -#[cfg(feature = "image")] -use iced_graphics::image::raster; - -#[cfg(feature = "svg")] -use iced_graphics::image::vector; +use atlas::Atlas; +use crate::core::{Rectangle, Size}; +use crate::graphics::Transformation; use crate::layer; -use crate::{Buffer, Transformation}; -use atlas::Atlas; +use crate::Buffer; + +#[cfg(feature = "image")] +use crate::graphics::image::raster; -use iced_native::{Rectangle, Size}; +#[cfg(feature = "svg")] +use crate::graphics::image::vector; use std::cell::RefCell; use std::mem; @@ -18,10 +19,10 @@ use std::mem; use bytemuck::{Pod, Zeroable}; #[cfg(feature = "image")] -use iced_native::image; +use crate::core::image; #[cfg(feature = "svg")] -use iced_native::svg; +use crate::core::svg; #[cfg(feature = "tracing")] use tracing::info_span; -- cgit From 3a26baa564524b0f25c5cb180b592c8b004b68a9 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 7 Mar 2023 03:47:49 +0100 Subject: Remove `image` abstractions in `iced_graphics` --- wgpu/src/image.rs | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) (limited to 'wgpu/src/image.rs') diff --git a/wgpu/src/image.rs b/wgpu/src/image.rs index 5eaa9a86..4163e338 100644 --- a/wgpu/src/image.rs +++ b/wgpu/src/image.rs @@ -1,5 +1,11 @@ mod atlas; +#[cfg(feature = "image")] +mod raster; + +#[cfg(feature = "svg")] +mod vector; + use atlas::Atlas; use crate::core::{Rectangle, Size}; @@ -7,12 +13,6 @@ use crate::graphics::Transformation; use crate::layer; use crate::Buffer; -#[cfg(feature = "image")] -use crate::graphics::image::raster; - -#[cfg(feature = "svg")] -use crate::graphics::image::vector; - use std::cell::RefCell; use std::mem; @@ -30,9 +30,9 @@ use tracing::info_span; #[derive(Debug)] pub struct Pipeline { #[cfg(feature = "image")] - raster_cache: RefCell>, + raster_cache: RefCell, #[cfg(feature = "svg")] - vector_cache: RefCell>, + vector_cache: RefCell, pipeline: wgpu::RenderPipeline, vertices: wgpu::Buffer, @@ -368,8 +368,10 @@ impl Pipeline { #[cfg(feature = "image")] layer::Image::Raster { handle, bounds } => { if let Some(atlas_entry) = raster_cache.upload( + device, + queue, + encoder, handle, - &mut (device, queue, encoder), &mut self.texture_atlas, ) { add_instances( @@ -392,11 +394,13 @@ impl Pipeline { let size = [bounds.width, bounds.height]; if let Some(atlas_entry) = vector_cache.upload( + device, + queue, + encoder, handle, *color, size, _scale, - &mut (device, queue, encoder), &mut self.texture_atlas, ) { add_instances( @@ -477,21 +481,12 @@ impl Pipeline { } } - pub fn end_frame( - &mut self, - device: &wgpu::Device, - queue: &wgpu::Queue, - encoder: &mut wgpu::CommandEncoder, - ) { + pub fn end_frame(&mut self) { #[cfg(feature = "image")] - self.raster_cache - .borrow_mut() - .trim(&mut self.texture_atlas, &mut (device, queue, encoder)); + self.raster_cache.borrow_mut().trim(&mut self.texture_atlas); #[cfg(feature = "svg")] - self.vector_cache - .borrow_mut() - .trim(&mut self.texture_atlas, &mut (device, queue, encoder)); + self.vector_cache.borrow_mut().trim(&mut self.texture_atlas); self.prepare_layer = 0; } -- cgit