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 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/quad.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'wgpu/src/quad.rs') diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs index 246cc5e1..8a568968 100644 --- a/wgpu/src/quad.rs +++ b/wgpu/src/quad.rs @@ -1,5 +1,6 @@ +use crate::layer; use crate::{Buffer, Transformation}; -use iced_graphics::layer; + use iced_native::Rectangle; use bytemuck::{Pod, Zeroable}; -- 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/quad.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'wgpu/src/quad.rs') diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs index 8a568968..b55216d7 100644 --- a/wgpu/src/quad.rs +++ b/wgpu/src/quad.rs @@ -1,7 +1,7 @@ +use crate::core::Rectangle; +use crate::graphics::Transformation; use crate::layer; -use crate::{Buffer, Transformation}; - -use iced_native::Rectangle; +use crate::Buffer; use bytemuck::{Pod, Zeroable}; use std::mem; -- cgit From 703484c5fdd87c64a41d3e627b0c79b43179e124 Mon Sep 17 00:00:00 2001 From: David Huculak Date: Sat, 1 Apr 2023 16:10:28 -0400 Subject: remove colons from shader labels --- 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 2f5fcc6b..1343181e 100644 --- a/wgpu/src/quad.rs +++ b/wgpu/src/quad.rs @@ -63,7 +63,7 @@ impl Pipeline { let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { - label: Some("iced_wgpu::quad::shader"), + label: Some("iced_wgpu quad shader"), source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed( include_str!("shader/quad.wgsl"), )), -- cgit From 6551a0b2ab6c831dd1d3646ecf55180339275e22 Mon Sep 17 00:00:00 2001 From: Bingus Date: Thu, 11 May 2023 09:12:06 -0700 Subject: Added support for gradients as background variants + other optimizations. --- wgpu/src/quad.rs | 481 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 357 insertions(+), 124 deletions(-) (limited to 'wgpu/src/quad.rs') diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs index 8fa7359e..31bf2b85 100644 --- a/wgpu/src/quad.rs +++ b/wgpu/src/quad.rs @@ -1,18 +1,19 @@ use crate::core::Rectangle; use crate::graphics::Transformation; use crate::layer; -use crate::Buffer; -use bytemuck::{Pod, Zeroable}; use std::mem; use wgpu::util::DeviceExt; #[cfg(feature = "tracing")] use tracing::info_span; +const INITIAL_INSTANCES: usize = 10_000; + #[derive(Debug)] pub struct Pipeline { - pipeline: wgpu::RenderPipeline, + solid: solid::Pipeline, + gradient: gradient::Pipeline, constant_layout: wgpu::BindGroupLayout, vertices: wgpu::Buffer, indices: wgpu::Buffer, @@ -39,107 +40,28 @@ impl Pipeline { }], }); - let layout = - device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - label: Some("iced_wgpu::quad pipeline layout"), - push_constant_ranges: &[], - bind_group_layouts: &[&constant_layout], - }); - - let shader = - device.create_shader_module(wgpu::ShaderModuleDescriptor { - label: Some("iced_wgpu quad shader"), - source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed( - include_str!("shader/quad.wgsl"), - )), - }); - - let pipeline = - device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { - label: Some("iced_wgpu::quad pipeline"), - layout: Some(&layout), - vertex: wgpu::VertexState { - module: &shader, - entry_point: "vs_main", - buffers: &[ - wgpu::VertexBufferLayout { - array_stride: mem::size_of::() as u64, - step_mode: wgpu::VertexStepMode::Vertex, - attributes: &[wgpu::VertexAttribute { - shader_location: 0, - format: wgpu::VertexFormat::Float32x2, - offset: 0, - }], - }, - wgpu::VertexBufferLayout { - array_stride: mem::size_of::() as u64, - step_mode: wgpu::VertexStepMode::Instance, - attributes: &wgpu::vertex_attr_array!( - 1 => Float32x2, - 2 => Float32x2, - 3 => Float32x4, - 4 => Float32x4, - 5 => Float32x4, - 6 => Float32, - ), - }, - ], - }, - fragment: Some(wgpu::FragmentState { - module: &shader, - entry_point: "fs_main", - targets: &[Some(wgpu::ColorTargetState { - format, - blend: Some(wgpu::BlendState { - color: wgpu::BlendComponent { - src_factor: wgpu::BlendFactor::SrcAlpha, - dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, - operation: wgpu::BlendOperation::Add, - }, - alpha: wgpu::BlendComponent { - src_factor: wgpu::BlendFactor::One, - dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, - operation: wgpu::BlendOperation::Add, - }, - }), - write_mask: wgpu::ColorWrites::ALL, - })], - }), - primitive: wgpu::PrimitiveState { - topology: wgpu::PrimitiveTopology::TriangleList, - front_face: wgpu::FrontFace::Cw, - ..Default::default() - }, - depth_stencil: None, - multisample: wgpu::MultisampleState { - count: 1, - mask: !0, - alpha_to_coverage_enabled: false, - }, - multiview: None, - }); - let vertices = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { label: Some("iced_wgpu::quad vertex buffer"), - contents: bytemuck::cast_slice(&QUAD_VERTS), + contents: bytemuck::cast_slice(&VERTICES), usage: wgpu::BufferUsages::VERTEX, }); let indices = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { label: Some("iced_wgpu::quad index buffer"), - contents: bytemuck::cast_slice(&QUAD_INDICES), + contents: bytemuck::cast_slice(&INDICES), usage: wgpu::BufferUsages::INDEX, }); - Pipeline { - pipeline, - constant_layout, + Self { vertices, indices, + solid: solid::Pipeline::new(device, format, &constant_layout), + gradient: gradient::Pipeline::new(device, format, &constant_layout), layers: Vec::new(), prepare_layer: 0, + constant_layout, } } @@ -147,7 +69,7 @@ impl Pipeline { &mut self, device: &wgpu::Device, queue: &wgpu::Queue, - instances: &[layer::Quad], + instances: &layer::Quads, transformation: Transformation, scale: f32, ) { @@ -168,22 +90,27 @@ impl Pipeline { 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(..)); - layer.draw(render_pass); + if layer.solid.instance_count > 0 { + render_pass.set_pipeline(&self.solid.pipeline); + layer.solid.draw(&layer.constants, render_pass); + } + + if layer.gradient.instance_count > 0 { + render_pass.set_pipeline(&self.gradient.pipeline); + layer.gradient.draw(&layer.constants, render_pass); + } } } @@ -196,8 +123,8 @@ impl Pipeline { struct Layer { constants: wgpu::BindGroup, constants_buffer: wgpu::Buffer, - instances: Buffer, - instance_count: usize, + solid: solid::Layer, + gradient: gradient::Layer, } impl Layer { @@ -221,18 +148,11 @@ impl Layer { }], }); - let instances = Buffer::new( - device, - "iced_wgpu::quad instance buffer", - INITIAL_INSTANCES, - wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST, - ); - Self { constants, constants_buffer, - instances, - instance_count: 0, + solid: solid::Layer::new(device), + gradient: gradient::Layer::new(device), } } @@ -240,7 +160,7 @@ impl Layer { &mut self, device: &wgpu::Device, queue: &wgpu::Queue, - instances: &[layer::Quad], + instances: &layer::Quads, transformation: Transformation, scale: f32, ) { @@ -255,35 +175,350 @@ impl Layer { bytemuck::bytes_of(&uniforms), ); - let _ = self.instances.resize(device, instances.len()); - self.instances.write(queue, 0, instances); - self.instance_count = instances.len(); + let _ = self.solid.instances.resize(device, instances.solids.len()); + let _ = self + .gradient + .instances + .resize(device, instances.gradients.len()); + let _ = + self.solid + .instances + .write(queue, 0, instances.solids.as_slice()); + self.solid.instance_count = instances.solids.len(); + let _ = self.gradient.instances.write( + queue, + 0, + instances.gradients.as_slice(), + ); + self.gradient.instance_count = instances.gradients.len(); } +} - pub fn draw<'a>(&'a self, render_pass: &mut wgpu::RenderPass<'a>) { - #[cfg(feature = "tracing")] - let _ = info_span!("Wgpu::Quad", "DRAW").entered(); +mod solid { + use crate::buffer::Buffer; + use crate::layer::quad; + use crate::quad::{color_target_state, Vertex, INDICES, INITIAL_INSTANCES}; - render_pass.set_bind_group(0, &self.constants, &[]); - render_pass.set_vertex_buffer(1, self.instances.slice(..)); + #[derive(Debug)] + pub struct Pipeline { + pub pipeline: wgpu::RenderPipeline, + } - render_pass.draw_indexed( - 0..QUAD_INDICES.len() as u32, - 0, - 0..self.instance_count as u32, - ); + #[derive(Debug)] + pub struct Layer { + pub instances: Buffer, + pub instance_count: usize, + } + + impl Layer { + pub fn new(device: &wgpu::Device) -> Self { + let instances = Buffer::new( + device, + "iced_wgpu.quad.solid.buffer", + INITIAL_INSTANCES, + wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST, + ); + + Self { + instances, + instance_count: 0, + } + } + + pub fn draw<'a>( + &'a self, + constants: &'a wgpu::BindGroup, + render_pass: &mut wgpu::RenderPass<'a>, + ) { + #[cfg(feature = "tracing")] + let _ = tracing::info_span!("Wgpu::Quad::Solid", "DRAW").entered(); + + render_pass.set_bind_group(0, constants, &[]); + render_pass.set_vertex_buffer(1, self.instances.slice(..)); + + render_pass.draw_indexed( + 0..INDICES.len() as u32, + 0, + 0..self.instance_count as u32, + ); + } + } + + impl Pipeline { + pub fn new( + device: &wgpu::Device, + format: wgpu::TextureFormat, + constants_layout: &wgpu::BindGroupLayout, + ) -> Self { + let layout = device.create_pipeline_layout( + &wgpu::PipelineLayoutDescriptor { + label: Some("iced_wgpu.quad.solid.pipeline"), + push_constant_ranges: &[], + bind_group_layouts: &[constants_layout], + }, + ); + + let shader = + device.create_shader_module(wgpu::ShaderModuleDescriptor { + label: Some("iced_wgpu.quad.solid.shader"), + source: wgpu::ShaderSource::Wgsl( + std::borrow::Cow::Borrowed(include_str!( + "shader/quad.wgsl" + )), + ), + }); + + let pipeline = device.create_render_pipeline( + &wgpu::RenderPipelineDescriptor { + label: Some("iced_wgpu.quad.solid.pipeline"), + layout: Some(&layout), + vertex: wgpu::VertexState { + module: &shader, + entry_point: "solid_vs_main", + buffers: &[ + Vertex::buffer_layout(), + wgpu::VertexBufferLayout { + array_stride: std::mem::size_of::() + as u64, + step_mode: wgpu::VertexStepMode::Instance, + attributes: &wgpu::vertex_attr_array!( + // Color + 1 => Float32x4, + // Position + 2 => Float32x2, + // Size + 3 => Float32x2, + // Border color + 4 => Float32x4, + // Border radius + 5 => Float32x4, + // Border width + 6 => Float32, + ), + }, + ], + }, + fragment: Some(wgpu::FragmentState { + module: &shader, + entry_point: "solid_fs_main", + targets: &color_target_state(format), + }), + primitive: wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::TriangleList, + front_face: wgpu::FrontFace::Cw, + ..Default::default() + }, + depth_stencil: None, + multisample: wgpu::MultisampleState { + count: 1, + mask: !0, + alpha_to_coverage_enabled: false, + }, + multiview: None, + }, + ); + + Self { pipeline } + } } } +mod gradient { + use crate::buffer::Buffer; + use crate::layer::quad; + use crate::quad::{color_target_state, Vertex, INDICES, INITIAL_INSTANCES}; + + #[derive(Debug)] + pub struct Pipeline { + pub pipeline: wgpu::RenderPipeline, + } + + #[derive(Debug)] + pub struct Layer { + pub instances: Buffer, + pub instance_count: usize, + } + + impl Layer { + pub fn new(device: &wgpu::Device) -> Self { + let instances = Buffer::new( + device, + "iced_wgpu.quad.gradient.buffer", + INITIAL_INSTANCES, + wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST, + ); + + Self { + instances, + instance_count: 0, + } + } + + pub fn draw<'a>( + &'a self, + constants: &'a wgpu::BindGroup, + render_pass: &mut wgpu::RenderPass<'a>, + ) { + #[cfg(feature = "tracing")] + let _ = + tracing::info_span!("Wgpu::Quad::Gradient", "DRAW").entered(); + + render_pass.set_bind_group(0, constants, &[]); + render_pass.set_vertex_buffer(1, self.instances.slice(..)); + + render_pass.draw_indexed( + 0..INDICES.len() as u32, + 0, + 0..self.instance_count as u32, + ); + } + } + + impl Pipeline { + pub fn new( + device: &wgpu::Device, + format: wgpu::TextureFormat, + constants_layout: &wgpu::BindGroupLayout, + ) -> Self { + let layout = device.create_pipeline_layout( + &wgpu::PipelineLayoutDescriptor { + label: Some("iced_wgpu.quad.gradient.pipeline"), + push_constant_ranges: &[], + bind_group_layouts: &[constants_layout], + }, + ); + + let shader = + device.create_shader_module(wgpu::ShaderModuleDescriptor { + label: Some("iced_wgpu.quad.gradient.shader"), + source: wgpu::ShaderSource::Wgsl( + std::borrow::Cow::Borrowed(include_str!( + "shader/quad.wgsl" + )), + ), + }); + + let pipeline = + device.create_render_pipeline( + &wgpu::RenderPipelineDescriptor { + label: Some("iced_wgpu.quad.gradient.pipeline"), + layout: Some(&layout), + vertex: wgpu::VertexState { + module: &shader, + entry_point: "gradient_vs_main", + buffers: &[ + Vertex::buffer_layout(), + wgpu::VertexBufferLayout { + array_stride: std::mem::size_of::< + quad::Gradient, + >( + ) + as u64, + step_mode: wgpu::VertexStepMode::Instance, + attributes: &wgpu::vertex_attr_array!( + // Color 1 + 1 => Float32x4, + // Color 2 + 2 => Float32x4, + // Color 3 + 3 => Float32x4, + // Color 4 + 4 => Float32x4, + // Color 5 + 5 => Float32x4, + // Color 6 + 6 => Float32x4, + // Color 7 + 7 => Float32x4, + // Color 8 + 8 => Float32x4, + // Offsets 1-4 + 9 => Float32x4, + // Offsets 5-8 + 10 => Float32x4, + // Direction + 11 => Float32x4, + // Position & Scale + 12 => Float32x4, + // Border color + 13 => Float32x4, + // Border radius + 14 => Float32x4, + // Border width + 15 => Float32 + ), + }, + ], + }, + fragment: Some(wgpu::FragmentState { + module: &shader, + entry_point: "gradient_fs_main", + targets: &color_target_state(format), + }), + primitive: wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::TriangleList, + front_face: wgpu::FrontFace::Cw, + ..Default::default() + }, + depth_stencil: None, + multisample: wgpu::MultisampleState { + count: 1, + mask: !0, + alpha_to_coverage_enabled: false, + }, + multiview: None, + }, + ); + + Self { pipeline } + } + } +} + +pub(crate) fn color_target_state( + format: wgpu::TextureFormat, +) -> [Option; 1] { + [Some(wgpu::ColorTargetState { + format, + blend: Some(wgpu::BlendState { + color: wgpu::BlendComponent { + src_factor: wgpu::BlendFactor::SrcAlpha, + dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, + operation: wgpu::BlendOperation::Add, + }, + alpha: wgpu::BlendComponent { + src_factor: wgpu::BlendFactor::One, + dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, + operation: wgpu::BlendOperation::Add, + }, + }), + write_mask: wgpu::ColorWrites::ALL, + })] +} + #[repr(C)] -#[derive(Clone, Copy, Zeroable, Pod)] +#[derive(Clone, Copy, bytemuck::Zeroable, bytemuck::Pod)] pub struct Vertex { _position: [f32; 2], } -const QUAD_INDICES: [u16; 6] = [0, 1, 2, 0, 2, 3]; +impl Vertex { + fn buffer_layout<'a>() -> wgpu::VertexBufferLayout<'a> { + wgpu::VertexBufferLayout { + array_stride: mem::size_of::() as u64, + step_mode: wgpu::VertexStepMode::Vertex, + attributes: &[wgpu::VertexAttribute { + shader_location: 0, + format: wgpu::VertexFormat::Float32x2, + offset: 0, + }], + } + } +} + +pub(crate) const INDICES: [u16; 6] = [0, 1, 2, 0, 2, 3]; -const QUAD_VERTS: [Vertex; 4] = [ +pub(crate) const VERTICES: [Vertex; 4] = [ Vertex { _position: [0.0, 0.0], }, @@ -298,10 +533,8 @@ const QUAD_VERTS: [Vertex; 4] = [ }, ]; -const INITIAL_INSTANCES: usize = 10_000; - #[repr(C)] -#[derive(Debug, Clone, Copy, Zeroable, Pod)] +#[derive(Debug, Clone, Copy, bytemuck::Zeroable, bytemuck::Pod)] struct Uniforms { transform: [f32; 16], scale: f32, -- cgit From f557b810f5931e69a9a35353b20fff1b07480715 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 19 May 2023 03:58:25 +0200 Subject: Keep `image` pipeline decoupled from `quad` in `iced_wgpu` --- wgpu/src/quad.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'wgpu/src/quad.rs') diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs index 31bf2b85..83ea8e1f 100644 --- a/wgpu/src/quad.rs +++ b/wgpu/src/quad.rs @@ -475,7 +475,7 @@ mod gradient { } } -pub(crate) fn color_target_state( +fn color_target_state( format: wgpu::TextureFormat, ) -> [Option; 1] { [Some(wgpu::ColorTargetState { @@ -516,9 +516,9 @@ impl Vertex { } } -pub(crate) const INDICES: [u16; 6] = [0, 1, 2, 0, 2, 3]; +const INDICES: [u16; 6] = [0, 1, 2, 0, 2, 3]; -pub(crate) const VERTICES: [Vertex; 4] = [ +const VERTICES: [Vertex; 4] = [ Vertex { _position: [0.0, 0.0], }, -- cgit From e267e075ccd35ae3ca357ae4143796e68c1ad392 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 19 May 2023 04:02:18 +0200 Subject: Avoid redundant `buffer::Buffer` import --- wgpu/src/quad.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'wgpu/src/quad.rs') diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs index 83ea8e1f..e35aebc9 100644 --- a/wgpu/src/quad.rs +++ b/wgpu/src/quad.rs @@ -195,9 +195,9 @@ impl Layer { } mod solid { - use crate::buffer::Buffer; use crate::layer::quad; use crate::quad::{color_target_state, Vertex, INDICES, INITIAL_INSTANCES}; + use crate::Buffer; #[derive(Debug)] pub struct Pipeline { @@ -324,9 +324,9 @@ mod solid { } mod gradient { - use crate::buffer::Buffer; use crate::layer::quad; use crate::quad::{color_target_state, Vertex, INDICES, INITIAL_INSTANCES}; + use crate::Buffer; #[derive(Debug)] pub struct Pipeline { -- cgit From 9d25f98f0f658819048e2455df0d48aea79fb4cc Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 19 May 2023 04:07:53 +0200 Subject: Reduce `INITIAL_INSTANCES` in `wgpu::quad` to `2_000` --- 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 e35aebc9..0125ec0b 100644 --- a/wgpu/src/quad.rs +++ b/wgpu/src/quad.rs @@ -8,7 +8,7 @@ use wgpu::util::DeviceExt; #[cfg(feature = "tracing")] use tracing::info_span; -const INITIAL_INSTANCES: usize = 10_000; +const INITIAL_INSTANCES: usize = 2_000; #[derive(Debug)] pub struct Pipeline { -- cgit From 3f141459a66fe66e6dc25d579d0cda80662f0895 Mon Sep 17 00:00:00 2001 From: Bingus Date: Thu, 25 May 2023 10:27:27 -0700 Subject: Fixed issue where quads of different types were not ordered. --- wgpu/src/quad.rs | 43 ++++++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 11 deletions(-) (limited to 'wgpu/src/quad.rs') diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs index 0125ec0b..a05e5468 100644 --- a/wgpu/src/quad.rs +++ b/wgpu/src/quad.rs @@ -1,6 +1,6 @@ use crate::core::Rectangle; use crate::graphics::Transformation; -use crate::layer; +use crate::layer::{self, quad}; use std::mem; use wgpu::util::DeviceExt; @@ -87,6 +87,7 @@ impl Pipeline { &'a self, layer: usize, bounds: Rectangle, + ordering: &Vec<(quad::Order, usize)>, render_pass: &mut wgpu::RenderPass<'a>, ) { if let Some(layer) = self.layers.get(layer) { @@ -102,14 +103,30 @@ impl Pipeline { ); render_pass.set_vertex_buffer(0, self.vertices.slice(..)); - if layer.solid.instance_count > 0 { - render_pass.set_pipeline(&self.solid.pipeline); - layer.solid.draw(&layer.constants, render_pass); - } - - if layer.gradient.instance_count > 0 { - render_pass.set_pipeline(&self.gradient.pipeline); - layer.gradient.draw(&layer.constants, render_pass); + let mut solid_offset = 0; + let mut gradient_offset = 0; + + for (quad_order, count) in ordering { + match quad_order { + quad::Order::Solid => { + render_pass.set_pipeline(&self.solid.pipeline); + layer.solid.draw( + &layer.constants, + render_pass, + solid_offset..(solid_offset + count), + ); + solid_offset += count; + } + quad::Order::Gradient => { + render_pass.set_pipeline(&self.gradient.pipeline); + layer.gradient.draw( + &layer.constants, + render_pass, + gradient_offset..(gradient_offset + count), + ); + gradient_offset += count; + } + } } } } @@ -198,6 +215,7 @@ mod solid { use crate::layer::quad; use crate::quad::{color_target_state, Vertex, INDICES, INITIAL_INSTANCES}; use crate::Buffer; + use std::ops::Range; #[derive(Debug)] pub struct Pipeline { @@ -229,6 +247,7 @@ mod solid { &'a self, constants: &'a wgpu::BindGroup, render_pass: &mut wgpu::RenderPass<'a>, + range: Range, ) { #[cfg(feature = "tracing")] let _ = tracing::info_span!("Wgpu::Quad::Solid", "DRAW").entered(); @@ -239,7 +258,7 @@ mod solid { render_pass.draw_indexed( 0..INDICES.len() as u32, 0, - 0..self.instance_count as u32, + range.start as u32..range.end as u32, ); } } @@ -327,6 +346,7 @@ mod gradient { use crate::layer::quad; use crate::quad::{color_target_state, Vertex, INDICES, INITIAL_INSTANCES}; use crate::Buffer; + use std::ops::Range; #[derive(Debug)] pub struct Pipeline { @@ -358,6 +378,7 @@ mod gradient { &'a self, constants: &'a wgpu::BindGroup, render_pass: &mut wgpu::RenderPass<'a>, + range: Range, ) { #[cfg(feature = "tracing")] let _ = @@ -369,7 +390,7 @@ mod gradient { render_pass.draw_indexed( 0..INDICES.len() as u32, 0, - 0..self.instance_count as u32, + range.start as u32..range.end as u32, ); } } -- cgit From eb6c663420a28e087c91c39e376db3c294b5aea1 Mon Sep 17 00:00:00 2001 From: Bingus Date: Fri, 26 May 2023 09:55:49 -0700 Subject: Adjusted `Quads` struct to be opaque `quad::Layer`. --- wgpu/src/quad.rs | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) (limited to 'wgpu/src/quad.rs') diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs index a05e5468..065da153 100644 --- a/wgpu/src/quad.rs +++ b/wgpu/src/quad.rs @@ -1,6 +1,6 @@ use crate::core::Rectangle; use crate::graphics::Transformation; -use crate::layer::{self, quad}; +use crate::layer::quad; use std::mem; use wgpu::util::DeviceExt; @@ -69,7 +69,7 @@ impl Pipeline { &mut self, device: &wgpu::Device, queue: &wgpu::Queue, - instances: &layer::Quads, + quads: &quad::Layer, transformation: Transformation, scale: f32, ) { @@ -78,7 +78,7 @@ impl Pipeline { } let layer = &mut self.layers[self.prepare_layer]; - layer.prepare(device, queue, instances, transformation, scale); + layer.prepare(device, queue, quads, transformation, scale); self.prepare_layer += 1; } @@ -87,7 +87,7 @@ impl Pipeline { &'a self, layer: usize, bounds: Rectangle, - ordering: &Vec<(quad::Order, usize)>, + quads: &quad::Layer, render_pass: &mut wgpu::RenderPass<'a>, ) { if let Some(layer) = self.layers.get(layer) { @@ -106,7 +106,7 @@ impl Pipeline { let mut solid_offset = 0; let mut gradient_offset = 0; - for (quad_order, count) in ordering { + for (quad_order, count) in quads.ordering() { match quad_order { quad::Order::Solid => { render_pass.set_pipeline(&self.solid.pipeline); @@ -177,7 +177,7 @@ impl Layer { &mut self, device: &wgpu::Device, queue: &wgpu::Queue, - instances: &layer::Quads, + quads: &quad::Layer, transformation: Transformation, scale: f32, ) { @@ -192,22 +192,15 @@ impl Layer { bytemuck::bytes_of(&uniforms), ); - let _ = self.solid.instances.resize(device, instances.solids.len()); - let _ = self - .gradient - .instances - .resize(device, instances.gradients.len()); - let _ = - self.solid - .instances - .write(queue, 0, instances.solids.as_slice()); - self.solid.instance_count = instances.solids.len(); - let _ = self.gradient.instances.write( - queue, - 0, - instances.gradients.as_slice(), - ); - self.gradient.instance_count = instances.gradients.len(); + let solids = quads.solids(); + let gradients = quads.gradients(); + + let _ = self.solid.instances.resize(device, solids.len()); + let _ = self.gradient.instances.resize(device, gradients.len()); + let _ = self.solid.instances.write(queue, 0, solids); + self.solid.instance_count = solids.len(); + let _ = self.gradient.instances.write(queue, 0, gradients); + self.gradient.instance_count = gradients.len(); } } -- cgit From fe9da174cafffbd77eb351c51ba017cf039a4cf4 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 30 May 2023 00:56:52 +0200 Subject: Move `layer::quad` types to `quad` module Not sure why I split these to begin with! --- wgpu/src/quad.rs | 390 +++++++++++++++---------------------------------------- 1 file changed, 108 insertions(+), 282 deletions(-) (limited to 'wgpu/src/quad.rs') diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs index 065da153..375b0cd7 100644 --- a/wgpu/src/quad.rs +++ b/wgpu/src/quad.rs @@ -1,10 +1,17 @@ -use crate::core::Rectangle; -use crate::graphics::Transformation; -use crate::layer::quad; +mod gradient; +mod solid; -use std::mem; +use gradient::Gradient; +use solid::Solid; + +use crate::core::{Background, Rectangle}; +use crate::graphics::{self, Transformation}; + +use bytemuck::{Pod, Zeroable}; use wgpu::util::DeviceExt; +use std::mem; + #[cfg(feature = "tracing")] use tracing::info_span; @@ -69,7 +76,7 @@ impl Pipeline { &mut self, device: &wgpu::Device, queue: &wgpu::Queue, - quads: &quad::Layer, + quads: &Batch, transformation: Transformation, scale: f32, ) { @@ -87,7 +94,7 @@ impl Pipeline { &'a self, layer: usize, bounds: Rectangle, - quads: &quad::Layer, + quads: &Batch, render_pass: &mut wgpu::RenderPass<'a>, ) { if let Some(layer) = self.layers.get(layer) { @@ -106,9 +113,9 @@ impl Pipeline { let mut solid_offset = 0; let mut gradient_offset = 0; - for (quad_order, count) in quads.ordering() { + for (quad_order, count) in &quads.order { match quad_order { - quad::Order::Solid => { + Order::Solid => { render_pass.set_pipeline(&self.solid.pipeline); layer.solid.draw( &layer.constants, @@ -117,7 +124,7 @@ impl Pipeline { ); solid_offset += count; } - quad::Order::Gradient => { + Order::Gradient => { render_pass.set_pipeline(&self.gradient.pipeline); layer.gradient.draw( &layer.constants, @@ -177,7 +184,7 @@ impl Layer { &mut self, device: &wgpu::Device, queue: &wgpu::Queue, - quads: &quad::Layer, + quads: &Batch, transformation: Transformation, scale: f32, ) { @@ -192,303 +199,122 @@ impl Layer { bytemuck::bytes_of(&uniforms), ); - let solids = quads.solids(); - let gradients = quads.gradients(); + let _ = self.solid.instances.resize(device, quads.solids.len()); + let _ = self + .gradient + .instances + .resize(device, quads.gradients.len()); + + let _ = self.solid.instances.write(queue, 0, &quads.solids); + let _ = self.gradient.instances.write(queue, 0, &quads.gradients); - let _ = self.solid.instances.resize(device, solids.len()); - let _ = self.gradient.instances.resize(device, gradients.len()); - let _ = self.solid.instances.write(queue, 0, solids); - self.solid.instance_count = solids.len(); - let _ = self.gradient.instances.write(queue, 0, gradients); - self.gradient.instance_count = gradients.len(); + self.solid.instance_count = quads.solids.len(); + self.gradient.instance_count = quads.gradients.len(); } } -mod solid { - use crate::layer::quad; - use crate::quad::{color_target_state, Vertex, INDICES, INITIAL_INSTANCES}; - use crate::Buffer; - use std::ops::Range; - - #[derive(Debug)] - pub struct Pipeline { - pub pipeline: wgpu::RenderPipeline, - } +/// 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], - #[derive(Debug)] - pub struct Layer { - pub instances: Buffer, - pub instance_count: usize, - } + /// The size of the [`Quad`]. + pub size: [f32; 2], - impl Layer { - pub fn new(device: &wgpu::Device) -> Self { - let instances = Buffer::new( - device, - "iced_wgpu.quad.solid.buffer", - INITIAL_INSTANCES, - wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST, - ); + /// The border color of the [`Quad`], in __linear RGB__. + pub border_color: [f32; 4], - Self { - instances, - instance_count: 0, - } - } + /// The border radii of the [`Quad`]. + pub border_radius: [f32; 4], - pub fn draw<'a>( - &'a self, - constants: &'a wgpu::BindGroup, - render_pass: &mut wgpu::RenderPass<'a>, - range: Range, - ) { - #[cfg(feature = "tracing")] - let _ = tracing::info_span!("Wgpu::Quad::Solid", "DRAW").entered(); - - render_pass.set_bind_group(0, constants, &[]); - render_pass.set_vertex_buffer(1, self.instances.slice(..)); - - render_pass.draw_indexed( - 0..INDICES.len() as u32, - 0, - range.start as u32..range.end as u32, - ); - } - } + /// The border width of the [`Quad`]. + pub border_width: f32, +} - impl Pipeline { - pub fn new( - device: &wgpu::Device, - format: wgpu::TextureFormat, - constants_layout: &wgpu::BindGroupLayout, - ) -> Self { - let layout = device.create_pipeline_layout( - &wgpu::PipelineLayoutDescriptor { - label: Some("iced_wgpu.quad.solid.pipeline"), - push_constant_ranges: &[], - bind_group_layouts: &[constants_layout], - }, - ); +/// A group of [`Quad`]s rendered together. +#[derive(Default, Debug)] +pub struct Batch { + /// The solid quads of the [`Layer`]. + solids: Vec, - let shader = - device.create_shader_module(wgpu::ShaderModuleDescriptor { - label: Some("iced_wgpu.quad.solid.shader"), - source: wgpu::ShaderSource::Wgsl( - std::borrow::Cow::Borrowed(include_str!( - "shader/quad.wgsl" - )), - ), - }); + /// The gradient quads of the [`Layer`]. + gradients: Vec, - let pipeline = device.create_render_pipeline( - &wgpu::RenderPipelineDescriptor { - label: Some("iced_wgpu.quad.solid.pipeline"), - layout: Some(&layout), - vertex: wgpu::VertexState { - module: &shader, - entry_point: "solid_vs_main", - buffers: &[ - Vertex::buffer_layout(), - wgpu::VertexBufferLayout { - array_stride: std::mem::size_of::() - as u64, - step_mode: wgpu::VertexStepMode::Instance, - attributes: &wgpu::vertex_attr_array!( - // Color - 1 => Float32x4, - // Position - 2 => Float32x2, - // Size - 3 => Float32x2, - // Border color - 4 => Float32x4, - // Border radius - 5 => Float32x4, - // Border width - 6 => Float32, - ), - }, - ], - }, - fragment: Some(wgpu::FragmentState { - module: &shader, - entry_point: "solid_fs_main", - targets: &color_target_state(format), - }), - primitive: wgpu::PrimitiveState { - topology: wgpu::PrimitiveTopology::TriangleList, - front_face: wgpu::FrontFace::Cw, - ..Default::default() - }, - depth_stencil: None, - multisample: wgpu::MultisampleState { - count: 1, - mask: !0, - alpha_to_coverage_enabled: false, - }, - multiview: None, - }, - ); + /// The quad order of the [`Layer`]; stored as a tuple of the quad type & its count. + order: Vec<(Order, usize)>, - Self { pipeline } - } - } + /// The last index of quad ordering. + index: usize, } -mod gradient { - use crate::layer::quad; - use crate::quad::{color_target_state, Vertex, INDICES, INITIAL_INSTANCES}; - use crate::Buffer; - use std::ops::Range; - - #[derive(Debug)] - pub struct Pipeline { - pub pipeline: wgpu::RenderPipeline, - } - - #[derive(Debug)] - pub struct Layer { - pub instances: Buffer, - pub instance_count: usize, +impl Batch { + /// Returns true if there are no quads of any type in [`Quads`]. + pub fn is_empty(&self) -> bool { + self.solids.is_empty() && self.gradients.is_empty() } - impl Layer { - pub fn new(device: &wgpu::Device) -> Self { - let instances = Buffer::new( - device, - "iced_wgpu.quad.gradient.buffer", - INITIAL_INSTANCES, - wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST, - ); + /// Adds a [`Quad`] with the provided `Background` type to the quad [`Layer`]. + pub fn add(&mut self, quad: Quad, background: &Background) { + let quad_order = match background { + Background::Color(color) => { + self.solids.push(Solid { + color: color.into_linear(), + quad, + }); - Self { - instances, - instance_count: 0, + Order::Solid } - } - - pub fn draw<'a>( - &'a self, - constants: &'a wgpu::BindGroup, - render_pass: &mut wgpu::RenderPass<'a>, - range: Range, - ) { - #[cfg(feature = "tracing")] - let _ = - tracing::info_span!("Wgpu::Quad::Gradient", "DRAW").entered(); - - render_pass.set_bind_group(0, constants, &[]); - render_pass.set_vertex_buffer(1, self.instances.slice(..)); - - render_pass.draw_indexed( - 0..INDICES.len() as u32, - 0, - range.start as u32..range.end as u32, - ); - } - } - - impl Pipeline { - pub fn new( - device: &wgpu::Device, - format: wgpu::TextureFormat, - constants_layout: &wgpu::BindGroupLayout, - ) -> Self { - let layout = device.create_pipeline_layout( - &wgpu::PipelineLayoutDescriptor { - label: Some("iced_wgpu.quad.gradient.pipeline"), - push_constant_ranges: &[], - bind_group_layouts: &[constants_layout], - }, - ); - - let shader = - device.create_shader_module(wgpu::ShaderModuleDescriptor { - label: Some("iced_wgpu.quad.gradient.shader"), - source: wgpu::ShaderSource::Wgsl( - std::borrow::Cow::Borrowed(include_str!( - "shader/quad.wgsl" - )), + Background::Gradient(gradient) => { + let quad = Gradient { + gradient: graphics::gradient::pack( + gradient, + Rectangle::new(quad.position.into(), quad.size.into()), ), - }); + quad, + }; - let pipeline = - device.create_render_pipeline( - &wgpu::RenderPipelineDescriptor { - label: Some("iced_wgpu.quad.gradient.pipeline"), - layout: Some(&layout), - vertex: wgpu::VertexState { - module: &shader, - entry_point: "gradient_vs_main", - buffers: &[ - Vertex::buffer_layout(), - wgpu::VertexBufferLayout { - array_stride: std::mem::size_of::< - quad::Gradient, - >( - ) - as u64, - step_mode: wgpu::VertexStepMode::Instance, - attributes: &wgpu::vertex_attr_array!( - // Color 1 - 1 => Float32x4, - // Color 2 - 2 => Float32x4, - // Color 3 - 3 => Float32x4, - // Color 4 - 4 => Float32x4, - // Color 5 - 5 => Float32x4, - // Color 6 - 6 => Float32x4, - // Color 7 - 7 => Float32x4, - // Color 8 - 8 => Float32x4, - // Offsets 1-4 - 9 => Float32x4, - // Offsets 5-8 - 10 => Float32x4, - // Direction - 11 => Float32x4, - // Position & Scale - 12 => Float32x4, - // Border color - 13 => Float32x4, - // Border radius - 14 => Float32x4, - // Border width - 15 => Float32 - ), - }, - ], - }, - fragment: Some(wgpu::FragmentState { - module: &shader, - entry_point: "gradient_fs_main", - targets: &color_target_state(format), - }), - primitive: wgpu::PrimitiveState { - topology: wgpu::PrimitiveTopology::TriangleList, - front_face: wgpu::FrontFace::Cw, - ..Default::default() - }, - depth_stencil: None, - multisample: wgpu::MultisampleState { - count: 1, - mask: !0, - alpha_to_coverage_enabled: false, - }, - multiview: None, - }, - ); + self.gradients.push(quad); + Order::Gradient + } + }; - Self { pipeline } + match (self.order.get_mut(self.index), quad_order) { + (Some((quad_order, count)), Order::Solid) => match quad_order { + Order::Solid => { + *count += 1; + } + Order::Gradient => { + self.order.push((Order::Solid, 1)); + self.index += 1; + } + }, + (Some((quad_order, count)), Order::Gradient) => match quad_order { + Order::Solid => { + self.order.push((Order::Gradient, 1)); + self.index += 1; + } + Order::Gradient => { + *count += 1; + } + }, + (None, _) => { + self.order.push((quad_order, 1)); + } } } } +#[derive(Debug, Copy, Clone)] +/// The identifier of a quad, used for ordering. +enum Order { + /// A solid quad + Solid, + /// A gradient quad + Gradient, +} + fn color_target_state( format: wgpu::TextureFormat, ) -> [Option; 1] { -- cgit From 6d650e7f9987aa72913d20c7e538448b518a6150 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 30 May 2023 00:59:42 +0200 Subject: Rename `quad::Order` to `quad::Kind` --- wgpu/src/quad.rs | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'wgpu/src/quad.rs') diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs index 375b0cd7..48ef565e 100644 --- a/wgpu/src/quad.rs +++ b/wgpu/src/quad.rs @@ -115,7 +115,7 @@ impl Pipeline { for (quad_order, count) in &quads.order { match quad_order { - Order::Solid => { + Kind::Solid => { render_pass.set_pipeline(&self.solid.pipeline); layer.solid.draw( &layer.constants, @@ -124,7 +124,7 @@ impl Pipeline { ); solid_offset += count; } - Order::Gradient => { + Kind::Gradient => { render_pass.set_pipeline(&self.gradient.pipeline); layer.gradient.draw( &layer.constants, @@ -243,7 +243,7 @@ pub struct Batch { gradients: Vec, /// The quad order of the [`Layer`]; stored as a tuple of the quad type & its count. - order: Vec<(Order, usize)>, + order: Vec<(Kind, usize)>, /// The last index of quad ordering. index: usize, @@ -264,7 +264,7 @@ impl Batch { quad, }); - Order::Solid + Kind::Solid } Background::Gradient(gradient) => { let quad = Gradient { @@ -276,26 +276,26 @@ impl Batch { }; self.gradients.push(quad); - Order::Gradient + Kind::Gradient } }; match (self.order.get_mut(self.index), quad_order) { - (Some((quad_order, count)), Order::Solid) => match quad_order { - Order::Solid => { + (Some((quad_order, count)), Kind::Solid) => match quad_order { + Kind::Solid => { *count += 1; } - Order::Gradient => { - self.order.push((Order::Solid, 1)); + Kind::Gradient => { + self.order.push((Kind::Solid, 1)); self.index += 1; } }, - (Some((quad_order, count)), Order::Gradient) => match quad_order { - Order::Solid => { - self.order.push((Order::Gradient, 1)); + (Some((quad_order, count)), Kind::Gradient) => match quad_order { + Kind::Solid => { + self.order.push((Kind::Gradient, 1)); self.index += 1; } - Order::Gradient => { + Kind::Gradient => { *count += 1; } }, @@ -307,8 +307,8 @@ impl Batch { } #[derive(Debug, Copy, Clone)] -/// The identifier of a quad, used for ordering. -enum Order { +/// The kind of a quad. +enum Kind { /// A solid quad Solid, /// A gradient quad -- cgit From cd7d33aa8ebc6fbb6666f34aeda3ee96d0fb51e3 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 30 May 2023 01:14:41 +0200 Subject: Simplify `order` match statement in `quad::Batch::add` --- wgpu/src/quad.rs | 35 +++++++++-------------------------- 1 file changed, 9 insertions(+), 26 deletions(-) (limited to 'wgpu/src/quad.rs') diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs index 48ef565e..e25d02af 100644 --- a/wgpu/src/quad.rs +++ b/wgpu/src/quad.rs @@ -244,9 +244,6 @@ pub struct Batch { /// The quad order of the [`Layer`]; stored as a tuple of the quad type & its count. order: Vec<(Kind, usize)>, - - /// The last index of quad ordering. - index: usize, } impl Batch { @@ -257,7 +254,7 @@ impl Batch { /// Adds a [`Quad`] with the provided `Background` type to the quad [`Layer`]. pub fn add(&mut self, quad: Quad, background: &Background) { - let quad_order = match background { + let kind = match background { Background::Color(color) => { self.solids.push(Solid { color: color.into_linear(), @@ -276,37 +273,23 @@ impl Batch { }; self.gradients.push(quad); + Kind::Gradient } }; - match (self.order.get_mut(self.index), quad_order) { - (Some((quad_order, count)), Kind::Solid) => match quad_order { - Kind::Solid => { - *count += 1; - } - Kind::Gradient => { - self.order.push((Kind::Solid, 1)); - self.index += 1; - } - }, - (Some((quad_order, count)), Kind::Gradient) => match quad_order { - Kind::Solid => { - self.order.push((Kind::Gradient, 1)); - self.index += 1; - } - Kind::Gradient => { - *count += 1; - } - }, - (None, _) => { - self.order.push((quad_order, 1)); + match self.order.last_mut() { + Some((last_kind, count)) if kind == *last_kind => { + *count += 1; + } + _ => { + self.order.push((kind, 1)); } } } } -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] /// The kind of a quad. enum Kind { /// A solid quad -- cgit From 9659e6a848d76df39c1988e33d248d1c1560271f Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 30 May 2023 01:16:30 +0200 Subject: Improve consistency of match branches in `quad::Batch::add` --- wgpu/src/quad.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'wgpu/src/quad.rs') diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs index e25d02af..62472126 100644 --- a/wgpu/src/quad.rs +++ b/wgpu/src/quad.rs @@ -264,15 +264,13 @@ impl Batch { Kind::Solid } Background::Gradient(gradient) => { - let quad = Gradient { + self.gradients.push(Gradient { gradient: graphics::gradient::pack( gradient, Rectangle::new(quad.position.into(), quad.size.into()), ), quad, - }; - - self.gradients.push(quad); + }); Kind::Gradient } -- cgit From 5fdc5affceca9345661ea2d213ccbce99721d09b Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 30 May 2023 01:17:03 +0200 Subject: Rename `quad_order` variable to `kind` in `quad::Pipeline::render` --- wgpu/src/quad.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'wgpu/src/quad.rs') diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs index 62472126..deb6d59a 100644 --- a/wgpu/src/quad.rs +++ b/wgpu/src/quad.rs @@ -113,8 +113,8 @@ impl Pipeline { let mut solid_offset = 0; let mut gradient_offset = 0; - for (quad_order, count) in &quads.order { - match quad_order { + for (kind, count) in &quads.order { + match kind { Kind::Solid => { render_pass.set_pipeline(&self.solid.pipeline); layer.solid.draw( -- cgit From ef547469fdc8fe4faaa9902d9a8c920684f07189 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 30 May 2023 01:33:50 +0200 Subject: Improve boundaries between `quad` submodules in `iced_wgpu` --- wgpu/src/quad.rs | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) (limited to 'wgpu/src/quad.rs') diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs index deb6d59a..9c5ed05f 100644 --- a/wgpu/src/quad.rs +++ b/wgpu/src/quad.rs @@ -116,21 +116,23 @@ impl Pipeline { for (kind, count) in &quads.order { match kind { Kind::Solid => { - render_pass.set_pipeline(&self.solid.pipeline); - layer.solid.draw( - &layer.constants, + self.solid.render( render_pass, + &layer.constants, + &layer.solid, solid_offset..(solid_offset + count), ); + solid_offset += count; } Kind::Gradient => { - render_pass.set_pipeline(&self.gradient.pipeline); - layer.gradient.draw( - &layer.constants, + self.gradient.render( render_pass, + &layer.constants, + &layer.gradient, gradient_offset..(gradient_offset + count), ); + gradient_offset += count; } } @@ -199,17 +201,8 @@ impl Layer { bytemuck::bytes_of(&uniforms), ); - let _ = self.solid.instances.resize(device, quads.solids.len()); - let _ = self - .gradient - .instances - .resize(device, quads.gradients.len()); - - let _ = self.solid.instances.write(queue, 0, &quads.solids); - let _ = self.gradient.instances.write(queue, 0, &quads.gradients); - - self.solid.instance_count = quads.solids.len(); - self.gradient.instance_count = quads.gradients.len(); + self.solid.prepare(device, queue, &quads.solids); + self.gradient.prepare(device, queue, &quads.gradients); } } -- cgit From faa7627ea41b1ce372bae7f0d2ae36e9b15a97a3 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 31 May 2023 21:31:58 +0200 Subject: Introduce `web-colors` feature flag to enable sRGB linear blending This is how browsers perform color management. They treat gamma-corrected sRGB colors as if they were linear RGB. Correctness aside, this mode is introduced for legacy reasons. Most UI/UX tooling uses this color management as well, and many have created an intuition about how color should behave from interacting with a browser. This feature flag should facilitate application development with `iced` in those cases. More details: https://webcolorisstillbroken.com/ --- wgpu/src/quad.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'wgpu/src/quad.rs') diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs index 9c5ed05f..37d0c623 100644 --- a/wgpu/src/quad.rs +++ b/wgpu/src/quad.rs @@ -5,6 +5,7 @@ use gradient::Gradient; use solid::Solid; use crate::core::{Background, Rectangle}; +use crate::graphics::color; use crate::graphics::{self, Transformation}; use bytemuck::{Pod, Zeroable}; @@ -217,7 +218,7 @@ pub struct Quad { pub size: [f32; 2], /// The border color of the [`Quad`], in __linear RGB__. - pub border_color: [f32; 4], + pub border_color: color::Packed, /// The border radii of the [`Quad`]. pub border_radius: [f32; 4], @@ -250,7 +251,7 @@ impl Batch { let kind = match background { Background::Color(color) => { self.solids.push(Solid { - color: color.into_linear(), + color: color::pack(*color), quad, }); -- cgit