From 680ea5dcca37ecf71ab2e5194e907d9414715d22 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Mon, 6 Feb 2023 22:21:27 +0100 Subject: Refactor `quad::Pipeline` to `prepare` and `render` architecture --- wgpu/src/quad.rs | 225 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 119 insertions(+), 106 deletions(-) (limited to 'wgpu/src/quad.rs') diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs index 2f5fcc6b..ebbe7a9d 100644 --- a/wgpu/src/quad.rs +++ b/wgpu/src/quad.rs @@ -1,3 +1,4 @@ +use crate::buffer::Buffer; use crate::Transformation; use iced_graphics::layer; use iced_native::Rectangle; @@ -12,11 +13,11 @@ use tracing::info_span; #[derive(Debug)] pub struct Pipeline { pipeline: wgpu::RenderPipeline, - constants: wgpu::BindGroup, - constants_buffer: wgpu::Buffer, + constant_layout: wgpu::BindGroupLayout, vertices: wgpu::Buffer, indices: wgpu::Buffer, - instances: wgpu::Buffer, + layers: Vec, + current_layer: usize, } impl Pipeline { @@ -38,22 +39,6 @@ impl Pipeline { }], }); - let constants_buffer = device.create_buffer(&wgpu::BufferDescriptor { - label: Some("iced_wgpu::quad uniforms buffer"), - size: mem::size_of::() as wgpu::BufferAddress, - usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, - mapped_at_creation: false, - }); - - let constants = device.create_bind_group(&wgpu::BindGroupDescriptor { - label: Some("iced_wgpu::quad uniforms bind group"), - layout: &constant_layout, - entries: &[wgpu::BindGroupEntry { - binding: 0, - resource: constants_buffer.as_entire_binding(), - }], - }); - let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("iced_wgpu::quad pipeline layout"), @@ -148,118 +133,146 @@ impl Pipeline { usage: wgpu::BufferUsages::INDEX, }); - let instances = device.create_buffer(&wgpu::BufferDescriptor { - label: Some("iced_wgpu::quad instance buffer"), - size: mem::size_of::() as u64 * MAX_INSTANCES as u64, - usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST, - mapped_at_creation: false, - }); - Pipeline { pipeline, - constants, - constants_buffer, + constant_layout, vertices, indices, - instances, + layers: Vec::new(), + current_layer: 0, } } - pub fn draw( + pub fn prepare( &mut self, device: &wgpu::Device, - staging_belt: &mut wgpu::util::StagingBelt, - encoder: &mut wgpu::CommandEncoder, + queue: &wgpu::Queue, instances: &[layer::Quad], transformation: Transformation, scale: f32, - bounds: Rectangle, - target: &wgpu::TextureView, ) { - #[cfg(feature = "tracing")] - let _ = info_span!("Wgpu::Quad", "DRAW").entered(); + if self.layers.len() <= self.current_layer { + self.layers.push(Layer::new(device, &self.constant_layout)); + } - let uniforms = Uniforms::new(transformation, scale); + let layer = &mut self.layers[self.current_layer]; + layer.prepare(device, queue, instances, transformation, scale); - { - let mut constants_buffer = staging_belt.write_buffer( - encoder, - &self.constants_buffer, - 0, - wgpu::BufferSize::new(mem::size_of::() as u64) - .unwrap(), - device, + self.current_layer += 1; + } + + pub fn render<'a>( + &'a self, + layer: usize, + bounds: Rectangle, + 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_index_buffer( + self.indices.slice(..), + wgpu::IndexFormat::Uint16, ); + render_pass.set_vertex_buffer(0, self.vertices.slice(..)); - constants_buffer.copy_from_slice(bytemuck::bytes_of(&uniforms)); + layer.draw(render_pass); } + } - let mut i = 0; - let total = instances.len(); + pub fn end_frame(&mut self) { + self.current_layer = 0; + } +} - while i < total { - let end = (i + MAX_INSTANCES).min(total); - let amount = end - i; +#[derive(Debug)] +struct Layer { + constants: wgpu::BindGroup, + constants_buffer: wgpu::Buffer, + instances: Buffer, + instance_count: usize, +} - let instance_bytes = bytemuck::cast_slice(&instances[i..end]); +impl Layer { + pub fn new( + device: &wgpu::Device, + constant_layout: &wgpu::BindGroupLayout, + ) -> Self { + let constants_buffer = device.create_buffer(&wgpu::BufferDescriptor { + label: Some("iced_wgpu::quad uniforms buffer"), + size: mem::size_of::() as wgpu::BufferAddress, + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, + mapped_at_creation: false, + }); - let mut instance_buffer = staging_belt.write_buffer( - encoder, - &self.instances, - 0, - wgpu::BufferSize::new(instance_bytes.len() as u64).unwrap(), - device, - ); + let constants = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("iced_wgpu::quad uniforms bind group"), + layout: &constant_layout, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: constants_buffer.as_entire_binding(), + }], + }); - instance_buffer.copy_from_slice(instance_bytes); - - #[cfg(feature = "tracing")] - let _ = info_span!("Wgpu::Quad", "BEGIN_RENDER_PASS").enter(); - - { - let mut render_pass = - 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, - }); - - render_pass.set_pipeline(&self.pipeline); - render_pass.set_bind_group(0, &self.constants, &[]); - 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, - bounds.y, - bounds.width, - // TODO: Address anti-aliasing adjustments properly - bounds.height, - ); - - render_pass.draw_indexed( - 0..QUAD_INDICES.len() as u32, - 0, - 0..amount as u32, - ); - } - - i += MAX_INSTANCES; + let instances = Buffer::new( + device, + "iced_wgpu::quad instance buffer", + MAX_INSTANCES, + wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST, + ); + + Self { + constants, + constants_buffer, + instances, + instance_count: 0, } } + + pub fn prepare( + &mut self, + device: &wgpu::Device, + queue: &wgpu::Queue, + instances: &[layer::Quad], + transformation: Transformation, + scale: f32, + ) { + #[cfg(feature = "tracing")] + let _ = info_span!("Wgpu::Quad", "PREPARE").entered(); + + let uniforms = Uniforms::new(transformation, scale); + + queue.write_buffer( + &self.constants_buffer, + 0, + bytemuck::bytes_of(&uniforms), + ); + + let _ = self.instances.resize(device, instances.len()); + self.instances.write(queue, 0, instances); + self.instance_count = instances.len(); + } + + pub fn draw<'a>(&'a self, render_pass: &mut wgpu::RenderPass<'a>) { + #[cfg(feature = "tracing")] + let _ = info_span!("Wgpu::Quad", "DRAW").entered(); + + 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, + ); + } } #[repr(C)] -- cgit From 77b59496b0a138510938aca8367572e08019ddb6 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 7 Feb 2023 19:26:41 +0100 Subject: Fix rendering order for `quad::Pipeline` --- wgpu/src/quad.rs | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'wgpu/src/quad.rs') diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs index ebbe7a9d..e4173b12 100644 --- a/wgpu/src/quad.rs +++ b/wgpu/src/quad.rs @@ -17,7 +17,8 @@ pub struct Pipeline { vertices: wgpu::Buffer, indices: wgpu::Buffer, layers: Vec, - current_layer: usize, + prepare_layer: usize, + render_layer: usize, } impl Pipeline { @@ -139,7 +140,8 @@ impl Pipeline { vertices, indices, layers: Vec::new(), - current_layer: 0, + prepare_layer: 0, + render_layer: 0, } } @@ -151,23 +153,22 @@ impl Pipeline { transformation: Transformation, scale: f32, ) { - if self.layers.len() <= self.current_layer { + if self.layers.len() <= self.prepare_layer { self.layers.push(Layer::new(device, &self.constant_layout)); } - let layer = &mut self.layers[self.current_layer]; + let layer = &mut self.layers[self.prepare_layer]; layer.prepare(device, queue, instances, transformation, scale); - self.current_layer += 1; + self.prepare_layer += 1; } pub fn render<'a>( - &'a self, - layer: usize, + &'a mut self, bounds: Rectangle, render_pass: &mut wgpu::RenderPass<'a>, ) { - if let Some(layer) = self.layers.get(layer) { + if let Some(layer) = self.layers.get(self.render_layer) { render_pass.set_pipeline(&self.pipeline); render_pass.set_scissor_rect( @@ -184,11 +185,14 @@ impl Pipeline { render_pass.set_vertex_buffer(0, self.vertices.slice(..)); layer.draw(render_pass); + + self.render_layer += 1; } } pub fn end_frame(&mut self) { - self.current_layer = 0; + self.prepare_layer = 0; + self.render_layer = 0; } } -- cgit From 34c963f7b39e3f16b55665a978948ead5b869f0f Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 7 Feb 2023 20:08:26 +0100 Subject: Remove unnecessary borrow in `quad::Pipeline` --- wgpu/src/quad.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'wgpu/src/quad.rs') diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs index e4173b12..94bcec92 100644 --- a/wgpu/src/quad.rs +++ b/wgpu/src/quad.rs @@ -218,7 +218,7 @@ impl Layer { let constants = device.create_bind_group(&wgpu::BindGroupDescriptor { label: Some("iced_wgpu::quad uniforms bind group"), - layout: &constant_layout, + layout: constant_layout, entries: &[wgpu::BindGroupEntry { binding: 0, resource: constants_buffer.as_entire_binding(), -- cgit From b8c1809ea101cece6943432fd3597f785c39af09 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 7 Feb 2023 23:55:16 +0100 Subject: Refactor `triangle::Pipeline` into `prepare` and `render` architecture And get rid of the staging belt! :tada: --- wgpu/src/quad.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'wgpu/src/quad.rs') diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs index 94bcec92..c1aa49c4 100644 --- a/wgpu/src/quad.rs +++ b/wgpu/src/quad.rs @@ -1,5 +1,4 @@ -use crate::buffer::Buffer; -use crate::Transformation; +use crate::{Buffer, Transformation}; use iced_graphics::layer; use iced_native::Rectangle; @@ -228,7 +227,7 @@ impl Layer { let instances = Buffer::new( device, "iced_wgpu::quad instance buffer", - MAX_INSTANCES, + INITIAL_INSTANCES, wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST, ); @@ -302,7 +301,7 @@ const QUAD_VERTS: [Vertex; 4] = [ }, ]; -const MAX_INSTANCES: usize = 100_000; +const INITIAL_INSTANCES: usize = 10_000; #[repr(C)] #[derive(Debug, Clone, Copy, Zeroable, Pod)] -- 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/quad.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'wgpu/src/quad.rs') diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs index c1aa49c4..246cc5e1 100644 --- a/wgpu/src/quad.rs +++ b/wgpu/src/quad.rs @@ -17,7 +17,6 @@ pub struct Pipeline { indices: wgpu::Buffer, layers: Vec, prepare_layer: usize, - render_layer: usize, } impl Pipeline { @@ -140,7 +139,6 @@ impl Pipeline { indices, layers: Vec::new(), prepare_layer: 0, - render_layer: 0, } } @@ -163,11 +161,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( @@ -184,14 +183,11 @@ impl Pipeline { render_pass.set_vertex_buffer(0, self.vertices.slice(..)); layer.draw(render_pass); - - self.render_layer += 1; } } pub fn end_frame(&mut self) { self.prepare_layer = 0; - self.render_layer = 0; } } -- cgit