summaryrefslogtreecommitdiffstats
path: root/wgpu/src/quad.rs
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector@hecrj.dev>2024-04-03 21:07:54 +0200
committerLibravatar Héctor Ramón Jiménez <hector@hecrj.dev>2024-04-03 21:07:54 +0200
commitb05e61f5c8ae61c9f3c7cc08cded53901ebbccfd (patch)
tree3d35a011d94d4936f09b5a9be4031358a09c60da /wgpu/src/quad.rs
parent99a904112ca111f2ab0e60e30b6c369741b1653b (diff)
downloadiced-b05e61f5c8ae61c9f3c7cc08cded53901ebbccfd.tar.gz
iced-b05e61f5c8ae61c9f3c7cc08cded53901ebbccfd.tar.bz2
iced-b05e61f5c8ae61c9f3c7cc08cded53901ebbccfd.zip
Redesign `iced_wgpu` layering architecture
Diffstat (limited to 'wgpu/src/quad.rs')
-rw-r--r--wgpu/src/quad.rs294
1 files changed, 214 insertions, 80 deletions
diff --git a/wgpu/src/quad.rs b/wgpu/src/quad.rs
index 0717a031..16d50b04 100644
--- a/wgpu/src/quad.rs
+++ b/wgpu/src/quad.rs
@@ -12,11 +12,37 @@ use bytemuck::{Pod, Zeroable};
use std::mem;
-#[cfg(feature = "tracing")]
-use tracing::info_span;
-
const INITIAL_INSTANCES: usize = 2_000;
+/// The properties of a quad.
+#[derive(Clone, Copy, Debug, Pod, Zeroable)]
+#[repr(C)]
+pub struct Quad {
+ /// The position of the [`Quad`].
+ pub position: [f32; 2],
+
+ /// The size of the [`Quad`].
+ pub size: [f32; 2],
+
+ /// The border color of the [`Quad`], in __linear RGB__.
+ pub border_color: color::Packed,
+
+ /// The border radii of the [`Quad`].
+ pub border_radius: [f32; 4],
+
+ /// The border width of the [`Quad`].
+ pub border_width: f32,
+
+ /// The shadow color of the [`Quad`].
+ pub shadow_color: color::Packed,
+
+ /// The shadow offset of the [`Quad`].
+ pub shadow_offset: [f32; 2],
+
+ /// The shadow blur radius of the [`Quad`].
+ pub shadow_blur_radius: f32,
+}
+
#[derive(Debug)]
pub struct Pipeline {
solid: solid::Pipeline,
@@ -54,7 +80,7 @@ impl Pipeline {
}
}
- pub fn prepare(
+ pub fn prepare_batch(
&mut self,
device: &wgpu::Device,
encoder: &mut wgpu::CommandEncoder,
@@ -73,7 +99,64 @@ impl Pipeline {
self.prepare_layer += 1;
}
- pub fn render<'a>(
+ pub fn prepare_cache(
+ &self,
+ device: &wgpu::Device,
+ encoder: &mut wgpu::CommandEncoder,
+ belt: &mut wgpu::util::StagingBelt,
+ cache: &mut Cache,
+ transformation: Transformation,
+ scale: f32,
+ ) {
+ match cache {
+ Cache::Staged(_) => {
+ let Cache::Staged(batch) =
+ std::mem::replace(cache, Cache::Staged(Batch::default()))
+ else {
+ unreachable!()
+ };
+
+ let mut layer = Layer::new(device, &self.constant_layout);
+ layer.prepare(
+ device,
+ encoder,
+ belt,
+ &batch,
+ transformation,
+ scale,
+ );
+
+ *cache = Cache::Uploaded {
+ layer,
+ batch,
+ needs_reupload: false,
+ }
+ }
+
+ Cache::Uploaded {
+ batch,
+ layer,
+ needs_reupload,
+ } => {
+ if *needs_reupload {
+ layer.prepare(
+ device,
+ encoder,
+ belt,
+ batch,
+ transformation,
+ scale,
+ );
+
+ *needs_reupload = false;
+ } else {
+ layer.update(device, encoder, belt, transformation, scale);
+ }
+ }
+ }
+ }
+
+ pub fn render_batch<'a>(
&'a self,
layer: usize,
bounds: Rectangle<u32>,
@@ -81,38 +164,59 @@ impl Pipeline {
render_pass: &mut wgpu::RenderPass<'a>,
) {
if let Some(layer) = self.layers.get(layer) {
- render_pass.set_scissor_rect(
- bounds.x,
- bounds.y,
- bounds.width,
- bounds.height,
- );
-
- let mut solid_offset = 0;
- let mut gradient_offset = 0;
-
- for (kind, count) in &quads.order {
- match kind {
- Kind::Solid => {
- self.solid.render(
- render_pass,
- &layer.constants,
- &layer.solid,
- solid_offset..(solid_offset + count),
- );
-
- solid_offset += count;
- }
- Kind::Gradient => {
- self.gradient.render(
- render_pass,
- &layer.constants,
- &layer.gradient,
- gradient_offset..(gradient_offset + count),
- );
-
- gradient_offset += count;
- }
+ self.render(bounds, layer, &quads.order, render_pass);
+ }
+ }
+
+ pub fn render_cache<'a>(
+ &'a self,
+ cache: &'a Cache,
+ bounds: Rectangle<u32>,
+ render_pass: &mut wgpu::RenderPass<'a>,
+ ) {
+ if let Cache::Uploaded { layer, batch, .. } = cache {
+ self.render(bounds, layer, &batch.order, render_pass);
+ }
+ }
+
+ fn render<'a>(
+ &'a self,
+ bounds: Rectangle<u32>,
+ layer: &'a Layer,
+ order: &Order,
+ render_pass: &mut wgpu::RenderPass<'a>,
+ ) {
+ render_pass.set_scissor_rect(
+ bounds.x,
+ bounds.y,
+ bounds.width,
+ bounds.height,
+ );
+
+ let mut solid_offset = 0;
+ let mut gradient_offset = 0;
+
+ for (kind, count) in order {
+ match kind {
+ Kind::Solid => {
+ self.solid.render(
+ render_pass,
+ &layer.constants,
+ &layer.solid,
+ solid_offset..(solid_offset + count),
+ );
+
+ solid_offset += count;
+ }
+ Kind::Gradient => {
+ self.gradient.render(
+ render_pass,
+ &layer.constants,
+ &layer.gradient,
+ gradient_offset..(gradient_offset + count),
+ );
+
+ gradient_offset += count;
}
}
}
@@ -124,7 +228,49 @@ impl Pipeline {
}
#[derive(Debug)]
-struct Layer {
+pub enum Cache {
+ Staged(Batch),
+ Uploaded {
+ batch: Batch,
+ layer: Layer,
+ needs_reupload: bool,
+ },
+}
+
+impl Cache {
+ pub fn is_empty(&self) -> bool {
+ match self {
+ Cache::Staged(batch) | Cache::Uploaded { batch, .. } => {
+ batch.is_empty()
+ }
+ }
+ }
+
+ pub fn update(&mut self, new_batch: Batch) {
+ match self {
+ Self::Staged(batch) => {
+ *batch = new_batch;
+ }
+ Self::Uploaded {
+ batch,
+ needs_reupload,
+ ..
+ } => {
+ *batch = new_batch;
+ *needs_reupload = true;
+ }
+ }
+ }
+}
+
+impl Default for Cache {
+ fn default() -> Self {
+ Self::Staged(Batch::default())
+ }
+}
+
+#[derive(Debug)]
+pub struct Layer {
constants: wgpu::BindGroup,
constants_buffer: wgpu::Buffer,
solid: solid::Layer,
@@ -169,9 +315,26 @@ impl Layer {
transformation: Transformation,
scale: f32,
) {
- #[cfg(feature = "tracing")]
- let _ = info_span!("Wgpu::Quad", "PREPARE").entered();
+ self.update(device, encoder, belt, transformation, scale);
+
+ if !quads.solids.is_empty() {
+ self.solid.prepare(device, encoder, belt, &quads.solids);
+ }
+
+ if !quads.gradients.is_empty() {
+ self.gradient
+ .prepare(device, encoder, belt, &quads.gradients);
+ }
+ }
+ pub fn update(
+ &mut self,
+ device: &wgpu::Device,
+ encoder: &mut wgpu::CommandEncoder,
+ belt: &mut wgpu::util::StagingBelt,
+ transformation: Transformation,
+ scale: f32,
+ ) {
let uniforms = Uniforms::new(transformation, scale);
let bytes = bytemuck::bytes_of(&uniforms);
@@ -183,47 +346,9 @@ impl Layer {
device,
)
.copy_from_slice(bytes);
-
- if !quads.solids.is_empty() {
- self.solid.prepare(device, encoder, belt, &quads.solids);
- }
-
- if !quads.gradients.is_empty() {
- self.gradient
- .prepare(device, encoder, belt, &quads.gradients);
- }
}
}
-/// The properties of a quad.
-#[derive(Clone, Copy, Debug, Pod, Zeroable)]
-#[repr(C)]
-pub struct Quad {
- /// The position of the [`Quad`].
- pub position: [f32; 2],
-
- /// The size of the [`Quad`].
- pub size: [f32; 2],
-
- /// The border color of the [`Quad`], in __linear RGB__.
- pub border_color: color::Packed,
-
- /// The border radii of the [`Quad`].
- pub border_radius: [f32; 4],
-
- /// The border width of the [`Quad`].
- pub border_width: f32,
-
- /// The shadow color of the [`Quad`].
- pub shadow_color: [f32; 4],
-
- /// The shadow offset of the [`Quad`].
- pub shadow_offset: [f32; 2],
-
- /// The shadow blur radius of the [`Quad`].
- pub shadow_blur_radius: f32,
-}
-
/// A group of [`Quad`]s rendered together.
#[derive(Default, Debug)]
pub struct Batch {
@@ -233,10 +358,13 @@ pub struct Batch {
/// The gradient quads of the [`Layer`].
gradients: Vec<Gradient>,
- /// The quad order of the [`Layer`]; stored as a tuple of the quad type & its count.
- order: Vec<(Kind, usize)>,
+ /// The quad order of the [`Layer`].
+ order: Order,
}
+/// The quad order of a [`Layer`]; stored as a tuple of the quad type & its count.
+type Order = Vec<(Kind, usize)>;
+
impl Batch {
/// Returns true if there are no quads of any type in [`Quads`].
pub fn is_empty(&self) -> bool {
@@ -276,6 +404,12 @@ impl Batch {
}
}
}
+
+ pub fn clear(&mut self) {
+ self.solids.clear();
+ self.gradients.clear();
+ self.order.clear();
+ }
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]