summaryrefslogtreecommitdiffstats
path: root/wgpu/src/triangle.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/triangle.rs
parent99a904112ca111f2ab0e60e30b6c369741b1653b (diff)
downloadiced-b05e61f5c8ae61c9f3c7cc08cded53901ebbccfd.tar.gz
iced-b05e61f5c8ae61c9f3c7cc08cded53901ebbccfd.tar.bz2
iced-b05e61f5c8ae61c9f3c7cc08cded53901ebbccfd.zip
Redesign `iced_wgpu` layering architecture
Diffstat (limited to 'wgpu/src/triangle.rs')
-rw-r--r--wgpu/src/triangle.rs396
1 files changed, 276 insertions, 120 deletions
diff --git a/wgpu/src/triangle.rs b/wgpu/src/triangle.rs
index b6be54d4..6df97a7b 100644
--- a/wgpu/src/triangle.rs
+++ b/wgpu/src/triangle.rs
@@ -1,14 +1,16 @@
//! Draw meshes of triangles.
mod msaa;
-use crate::core::{Size, Transformation};
+use crate::core::{Rectangle, Size, Transformation};
+use crate::graphics::mesh::{self, Mesh};
use crate::graphics::Antialiasing;
-use crate::layer::mesh::{self, Mesh};
use crate::Buffer;
const INITIAL_INDEX_COUNT: usize = 1_000;
const INITIAL_VERTEX_COUNT: usize = 1_000;
+pub type Batch = Vec<Mesh>;
+
#[derive(Debug)]
pub struct Pipeline {
blit: Option<msaa::Blit>,
@@ -18,8 +20,270 @@ pub struct Pipeline {
prepare_layer: usize,
}
+impl Pipeline {
+ pub fn new(
+ device: &wgpu::Device,
+ format: wgpu::TextureFormat,
+ antialiasing: Option<Antialiasing>,
+ ) -> Pipeline {
+ Pipeline {
+ blit: antialiasing.map(|a| msaa::Blit::new(device, format, a)),
+ solid: solid::Pipeline::new(device, format, antialiasing),
+ gradient: gradient::Pipeline::new(device, format, antialiasing),
+ layers: Vec::new(),
+ prepare_layer: 0,
+ }
+ }
+
+ pub fn prepare_batch(
+ &mut self,
+ device: &wgpu::Device,
+ encoder: &mut wgpu::CommandEncoder,
+ belt: &mut wgpu::util::StagingBelt,
+ meshes: &Batch,
+ transformation: Transformation,
+ ) {
+ if self.layers.len() <= self.prepare_layer {
+ self.layers
+ .push(Layer::new(device, &self.solid, &self.gradient));
+ }
+
+ let layer = &mut self.layers[self.prepare_layer];
+ layer.prepare(
+ device,
+ encoder,
+ belt,
+ &self.solid,
+ &self.gradient,
+ meshes,
+ transformation,
+ );
+
+ self.prepare_layer += 1;
+ }
+
+ pub fn prepare_cache(
+ &mut self,
+ device: &wgpu::Device,
+ encoder: &mut wgpu::CommandEncoder,
+ belt: &mut wgpu::util::StagingBelt,
+ cache: &mut Cache,
+ transformation: Transformation,
+ ) {
+ 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.solid, &self.gradient);
+ layer.prepare(
+ device,
+ encoder,
+ belt,
+ &self.solid,
+ &self.gradient,
+ &batch,
+ transformation,
+ );
+
+ *cache = Cache::Uploaded {
+ layer,
+ batch,
+ needs_reupload: false,
+ }
+ }
+
+ Cache::Uploaded {
+ batch,
+ layer,
+ needs_reupload,
+ } => {
+ if *needs_reupload {
+ layer.prepare(
+ device,
+ encoder,
+ belt,
+ &self.solid,
+ &self.gradient,
+ batch,
+ transformation,
+ );
+
+ *needs_reupload = false;
+ }
+ }
+ }
+ }
+
+ pub fn render_batch(
+ &mut self,
+ device: &wgpu::Device,
+ encoder: &mut wgpu::CommandEncoder,
+ target: &wgpu::TextureView,
+ layer: usize,
+ target_size: Size<u32>,
+ meshes: &Batch,
+ bounds: Rectangle<u32>,
+ scale_factor: f32,
+ ) {
+ Self::render(
+ device,
+ encoder,
+ target,
+ self.blit.as_mut(),
+ &self.solid,
+ &self.gradient,
+ &self.layers[layer],
+ target_size,
+ meshes,
+ bounds,
+ scale_factor,
+ );
+ }
+
+ pub fn render_cache(
+ &mut self,
+ device: &wgpu::Device,
+ encoder: &mut wgpu::CommandEncoder,
+ target: &wgpu::TextureView,
+ target_size: Size<u32>,
+ cache: &Cache,
+ bounds: Rectangle<u32>,
+ scale_factor: f32,
+ ) {
+ let Cache::Uploaded { batch, layer, .. } = cache else {
+ return;
+ };
+
+ Self::render(
+ device,
+ encoder,
+ target,
+ self.blit.as_mut(),
+ &self.solid,
+ &self.gradient,
+ layer,
+ target_size,
+ batch,
+ bounds,
+ scale_factor,
+ );
+ }
+
+ fn render(
+ device: &wgpu::Device,
+ encoder: &mut wgpu::CommandEncoder,
+ target: &wgpu::TextureView,
+ mut blit: Option<&mut msaa::Blit>,
+ solid: &solid::Pipeline,
+ gradient: &gradient::Pipeline,
+ layer: &Layer,
+ target_size: Size<u32>,
+ meshes: &Batch,
+ bounds: Rectangle<u32>,
+ scale_factor: f32,
+ ) {
+ {
+ let (attachment, resolve_target, load) = if let Some(blit) =
+ &mut blit
+ {
+ let (attachment, resolve_target) =
+ blit.targets(device, target_size.width, target_size.height);
+
+ (
+ attachment,
+ Some(resolve_target),
+ wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
+ )
+ } else {
+ (target, None, wgpu::LoadOp::Load)
+ };
+
+ let mut render_pass =
+ encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
+ label: Some("iced_wgpu.triangle.render_pass"),
+ color_attachments: &[Some(
+ wgpu::RenderPassColorAttachment {
+ view: attachment,
+ resolve_target,
+ ops: wgpu::Operations {
+ load,
+ store: wgpu::StoreOp::Store,
+ },
+ },
+ )],
+ depth_stencil_attachment: None,
+ timestamp_writes: None,
+ occlusion_query_set: None,
+ });
+
+ layer.render(
+ solid,
+ gradient,
+ meshes,
+ bounds,
+ scale_factor,
+ &mut render_pass,
+ );
+ }
+
+ if let Some(blit) = blit {
+ blit.draw(encoder, target);
+ }
+ }
+
+ pub fn end_frame(&mut self) {
+ self.prepare_layer = 0;
+ }
+}
+
+#[derive(Debug)]
+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)]
-struct Layer {
+pub struct Layer {
index_buffer: Buffer<u32>,
index_strides: Vec<u32>,
solid: solid::Layer,
@@ -52,7 +316,7 @@ impl Layer {
belt: &mut wgpu::util::StagingBelt,
solid: &solid::Pipeline,
gradient: &gradient::Pipeline,
- meshes: &[Mesh<'_>],
+ meshes: &Batch,
transformation: Transformation,
) {
// Count the total amount of vertices & indices we need to handle
@@ -100,7 +364,6 @@ impl Layer {
for mesh in meshes {
let indices = mesh.indices();
-
let uniforms =
Uniforms::new(transformation * mesh.transformation());
@@ -157,7 +420,8 @@ impl Layer {
&'a self,
solid: &'a solid::Pipeline,
gradient: &'a gradient::Pipeline,
- meshes: &[Mesh<'_>],
+ meshes: &Batch,
+ layer_bounds: Rectangle<u32>,
scale_factor: f32,
render_pass: &mut wgpu::RenderPass<'a>,
) {
@@ -166,7 +430,12 @@ impl Layer {
let mut last_is_solid = None;
for (index, mesh) in meshes.iter().enumerate() {
- let clip_bounds = (mesh.clip_bounds() * scale_factor).snap();
+ let Some(clip_bounds) = Rectangle::<f32>::from(layer_bounds)
+ .intersection(&(mesh.clip_bounds() * scale_factor))
+ .map(Rectangle::snap)
+ else {
+ continue;
+ };
if clip_bounds.width < 1 || clip_bounds.height < 1 {
continue;
@@ -234,119 +503,6 @@ impl Layer {
}
}
-impl Pipeline {
- pub fn new(
- device: &wgpu::Device,
- format: wgpu::TextureFormat,
- antialiasing: Option<Antialiasing>,
- ) -> Pipeline {
- Pipeline {
- blit: antialiasing.map(|a| msaa::Blit::new(device, format, a)),
- solid: solid::Pipeline::new(device, format, antialiasing),
- gradient: gradient::Pipeline::new(device, format, antialiasing),
- layers: Vec::new(),
- prepare_layer: 0,
- }
- }
-
- pub fn prepare(
- &mut self,
- device: &wgpu::Device,
- encoder: &mut wgpu::CommandEncoder,
- belt: &mut wgpu::util::StagingBelt,
- meshes: &[Mesh<'_>],
- transformation: Transformation,
- ) {
- #[cfg(feature = "tracing")]
- let _ = tracing::info_span!("Wgpu::Triangle", "PREPARE").entered();
-
- if self.layers.len() <= self.prepare_layer {
- self.layers
- .push(Layer::new(device, &self.solid, &self.gradient));
- }
-
- let layer = &mut self.layers[self.prepare_layer];
- layer.prepare(
- device,
- encoder,
- belt,
- &self.solid,
- &self.gradient,
- meshes,
- transformation,
- );
-
- self.prepare_layer += 1;
- }
-
- pub fn render(
- &mut self,
- device: &wgpu::Device,
- encoder: &mut wgpu::CommandEncoder,
- target: &wgpu::TextureView,
- layer: usize,
- target_size: Size<u32>,
- meshes: &[Mesh<'_>],
- scale_factor: f32,
- ) {
- #[cfg(feature = "tracing")]
- let _ = tracing::info_span!("Wgpu::Triangle", "DRAW").entered();
-
- {
- let (attachment, resolve_target, load) = if let Some(blit) =
- &mut self.blit
- {
- let (attachment, resolve_target) =
- blit.targets(device, target_size.width, target_size.height);
-
- (
- attachment,
- Some(resolve_target),
- wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
- )
- } else {
- (target, None, wgpu::LoadOp::Load)
- };
-
- let mut render_pass =
- encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
- label: Some("iced_wgpu.triangle.render_pass"),
- color_attachments: &[Some(
- wgpu::RenderPassColorAttachment {
- view: attachment,
- resolve_target,
- ops: wgpu::Operations {
- load,
- store: wgpu::StoreOp::Store,
- },
- },
- )],
- depth_stencil_attachment: None,
- timestamp_writes: None,
- occlusion_query_set: None,
- });
-
- let layer = &mut self.layers[layer];
-
- layer.render(
- &self.solid,
- &self.gradient,
- meshes,
- scale_factor,
- &mut render_pass,
- );
- }
-
- if let Some(blit) = &mut self.blit {
- blit.draw(encoder, target);
- }
- }
-
- pub fn end_frame(&mut self) {
- self.prepare_layer = 0;
- }
-}
-
fn fragment_target(
texture_format: wgpu::TextureFormat,
) -> wgpu::ColorTargetState {