summaryrefslogtreecommitdiffstats
path: root/wgpu/src/quad.rs
diff options
context:
space:
mode:
Diffstat (limited to 'wgpu/src/quad.rs')
-rw-r--r--wgpu/src/quad.rs304
1 files changed, 176 insertions, 128 deletions
diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs
index 8fa7359e..37d0c623 100644
--- a/wgpu/src/quad.rs
+++ b/wgpu/src/quad.rs
@@ -1,18 +1,27 @@
-use crate::core::Rectangle;
-use crate::graphics::Transformation;
-use crate::layer;
-use crate::Buffer;
+mod gradient;
+mod solid;
+
+use gradient::Gradient;
+use solid::Solid;
+
+use crate::core::{Background, Rectangle};
+use crate::graphics::color;
+use crate::graphics::{self, Transformation};
use bytemuck::{Pod, Zeroable};
-use std::mem;
use wgpu::util::DeviceExt;
+use std::mem;
+
#[cfg(feature = "tracing")]
use tracing::info_span;
+const INITIAL_INSTANCES: usize = 2_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 +48,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::<Vertex>() 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::<layer::Quad>() 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 +77,7 @@ impl Pipeline {
&mut self,
device: &wgpu::Device,
queue: &wgpu::Queue,
- instances: &[layer::Quad],
+ quads: &Batch,
transformation: Transformation,
scale: f32,
) {
@@ -156,7 +86,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;
}
@@ -165,25 +95,49 @@ impl Pipeline {
&'a self,
layer: usize,
bounds: Rectangle<u32>,
+ quads: &Batch,
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);
+ 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;
+ }
+ }
+ }
}
}
@@ -196,8 +150,8 @@ impl Pipeline {
struct Layer {
constants: wgpu::BindGroup,
constants_buffer: wgpu::Buffer,
- instances: Buffer<layer::Quad>,
- instance_count: usize,
+ solid: solid::Layer,
+ gradient: gradient::Layer,
}
impl Layer {
@@ -221,18 +175,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 +187,7 @@ impl Layer {
&mut self,
device: &wgpu::Device,
queue: &wgpu::Queue,
- instances: &[layer::Quad],
+ quads: &Batch,
transformation: Transformation,
scale: f32,
) {
@@ -255,35 +202,138 @@ impl Layer {
bytemuck::bytes_of(&uniforms),
);
- let _ = self.instances.resize(device, instances.len());
- self.instances.write(queue, 0, instances);
- self.instance_count = instances.len();
+ self.solid.prepare(device, queue, &quads.solids);
+ self.gradient.prepare(device, queue, &quads.gradients);
}
+}
- pub fn draw<'a>(&'a self, render_pass: &mut wgpu::RenderPass<'a>) {
- #[cfg(feature = "tracing")]
- let _ = info_span!("Wgpu::Quad", "DRAW").entered();
+/// 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],
- render_pass.set_bind_group(0, &self.constants, &[]);
- render_pass.set_vertex_buffer(1, self.instances.slice(..));
+ /// The size of the [`Quad`].
+ pub size: [f32; 2],
- render_pass.draw_indexed(
- 0..QUAD_INDICES.len() as u32,
- 0,
- 0..self.instance_count as u32,
- );
+ /// 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,
+}
+
+/// A group of [`Quad`]s rendered together.
+#[derive(Default, Debug)]
+pub struct Batch {
+ /// The solid quads of the [`Layer`].
+ solids: Vec<Solid>,
+
+ /// 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)>,
+}
+
+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()
+ }
+
+ /// Adds a [`Quad`] with the provided `Background` type to the quad [`Layer`].
+ pub fn add(&mut self, quad: Quad, background: &Background) {
+ let kind = match background {
+ Background::Color(color) => {
+ self.solids.push(Solid {
+ color: color::pack(*color),
+ quad,
+ });
+
+ Kind::Solid
+ }
+ Background::Gradient(gradient) => {
+ self.gradients.push(Gradient {
+ gradient: graphics::gradient::pack(
+ gradient,
+ Rectangle::new(quad.position.into(), quad.size.into()),
+ ),
+ quad,
+ });
+
+ Kind::Gradient
+ }
+ };
+
+ match self.order.last_mut() {
+ Some((last_kind, count)) if kind == *last_kind => {
+ *count += 1;
+ }
+ _ => {
+ self.order.push((kind, 1));
+ }
+ }
}
}
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+/// The kind of a quad.
+enum Kind {
+ /// A solid quad
+ Solid,
+ /// A gradient quad
+ Gradient,
+}
+
+fn color_target_state(
+ format: wgpu::TextureFormat,
+) -> [Option<wgpu::ColorTargetState>; 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::<Self>() as u64,
+ step_mode: wgpu::VertexStepMode::Vertex,
+ attributes: &[wgpu::VertexAttribute {
+ shader_location: 0,
+ format: wgpu::VertexFormat::Float32x2,
+ offset: 0,
+ }],
+ }
+ }
+}
-const QUAD_VERTS: [Vertex; 4] = [
+const INDICES: [u16; 6] = [0, 1, 2, 0, 2, 3];
+
+const VERTICES: [Vertex; 4] = [
Vertex {
_position: [0.0, 0.0],
},
@@ -298,10 +348,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,