summaryrefslogtreecommitdiffstats
path: root/wgpu/src/triangle.rs
diff options
context:
space:
mode:
Diffstat (limited to 'wgpu/src/triangle.rs')
-rw-r--r--wgpu/src/triangle.rs303
1 files changed, 143 insertions, 160 deletions
diff --git a/wgpu/src/triangle.rs b/wgpu/src/triangle.rs
index f1770e9a..df5e3132 100644
--- a/wgpu/src/triangle.rs
+++ b/wgpu/src/triangle.rs
@@ -3,11 +3,11 @@ use crate::{settings, Transformation};
use core::fmt;
use std::fmt::Formatter;
-use iced_graphics::layer::Meshes;
+use iced_graphics::layer::{attribute_count_of, Mesh};
use iced_graphics::shader::Shader;
use iced_graphics::Size;
-use crate::buffers::buffer::{needs_recreate, StaticBuffer};
+use crate::buffers::buffer::StaticBuffer;
use crate::triangle::gradient::GradientPipeline;
use crate::triangle::solid::SolidPipeline;
pub use iced_graphics::triangle::{Mesh2D, Vertex2D};
@@ -20,10 +20,9 @@ mod solid;
#[derive(Debug)]
pub(crate) struct Pipeline {
blit: Option<msaa::Blit>,
- // these are optional so we don't allocate any memory to the GPU if
- // application has no triangle meshes.
- vertex_buffer: Option<StaticBuffer>,
- index_buffer: Option<StaticBuffer>,
+ vertex_buffer: StaticBuffer<Vertex2D>,
+ index_buffer: StaticBuffer<u32>,
+ index_strides: Vec<u32>,
pipelines: TrianglePipelines,
}
@@ -69,8 +68,17 @@ impl Pipeline {
) -> Pipeline {
Pipeline {
blit: antialiasing.map(|a| msaa::Blit::new(device, format, a)),
- vertex_buffer: None,
- index_buffer: None,
+ vertex_buffer: StaticBuffer::new(
+ device,
+ "iced_wgpu::triangle vertex buffer",
+ wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
+ ),
+ index_buffer: StaticBuffer::new(
+ device,
+ "iced_wgpu::triangle vertex buffer",
+ wgpu::BufferUsages::INDEX | wgpu::BufferUsages::COPY_DST,
+ ),
+ index_strides: Vec::new(),
pipelines: TrianglePipelines {
solid: SolidPipeline::new(device, format, antialiasing),
gradient: GradientPipeline::new(device, format, antialiasing),
@@ -88,177 +96,152 @@ impl Pipeline {
target_size: Size<u32>,
transformation: Transformation,
scale_factor: f32,
- meshes: &Meshes<'_>,
+ meshes: &[Mesh<'_>],
) {
- //count the total number of vertices & indices we need to handle
- let (total_vertices, total_indices) = meshes.attribute_count();
+ //count the total amount of vertices & indices we need to handle
+ let (total_vertices, total_indices) = attribute_count_of(meshes);
+
+ // Then we ensure the current attribute buffers are big enough, resizing if necessary
+ // with wgpu this means recreating the buffer.
+
+ //We are not currently using the return value of these functions as we have no system in
+ //place to calculate mesh diff, or to know whether or not that would be more performant for
+ //the majority of use cases. Therefore we will write GPU data every frame (for now).
+ let _ = self.vertex_buffer.recreate_if_needed(device, total_vertices);
+ let _ = self.index_buffer.recreate_if_needed(device, total_indices);
+
+ //prepare dynamic buffers & data store for writing
+ self.index_strides.clear();
+ self.pipelines.clear();
+
+ let mut vertex_offset = 0;
+ let mut index_offset = 0;
- //Only create buffers if they need to be re-sized or don't exist
- if needs_recreate(&self.vertex_buffer, total_vertices) {
- //mapped to GPU at creation with total vertices
- self.vertex_buffer = Some(StaticBuffer::new(
+ for mesh in meshes {
+ let transform = transformation
+ * Transformation::translate(mesh.origin.x, mesh.origin.y);
+
+ //write to both buffers
+ let new_vertex_offset = self.vertex_buffer.write(
device,
- "iced_wgpu::triangle vertex buffer",
- //TODO: a more reasonable default to prevent frequent resizing calls
- // before this was 10_000
- (std::mem::size_of::<Vertex2D>() * total_vertices) as u64,
- wgpu::BufferUsages::VERTEX,
- meshes.0.len(),
- ))
- }
+ staging_belt,
+ encoder,
+ vertex_offset,
+ &mesh.buffers.vertices,
+ );
- if needs_recreate(&self.index_buffer, total_indices) {
- //mapped to GPU at creation with total indices
- self.index_buffer = Some(StaticBuffer::new(
+ let new_index_offset = self.index_buffer.write(
device,
- "iced_wgpu::triangle index buffer",
- //TODO: a more reasonable default to prevent frequent resizing calls
- // before this was 10_000
- (std::mem::size_of::<Vertex2D>() * total_indices) as u64,
- wgpu::BufferUsages::INDEX,
- meshes.0.len(),
- ));
- }
+ staging_belt,
+ encoder,
+ index_offset,
+ &mesh.buffers.indices,
+ );
- if let Some(vertex_buffer) = &mut self.vertex_buffer {
- if let Some(index_buffer) = &mut self.index_buffer {
- let mut offset_v = 0;
- let mut offset_i = 0;
- //TODO: store this more efficiently
- let mut indices_lengths = Vec::with_capacity(meshes.0.len());
-
- //iterate through meshes to write all attribute data
- for mesh in meshes.0.iter() {
- let transform = transformation
- * Transformation::translate(
- mesh.origin.x,
- mesh.origin.y,
- );
+ vertex_offset = vertex_offset + new_vertex_offset;
+ index_offset = index_offset + new_index_offset;
- let vertices = bytemuck::cast_slice(&mesh.buffers.vertices);
- let indices = bytemuck::cast_slice(&mesh.buffers.indices);
-
- //TODO: it's (probably) more efficient to reduce this write command and
- // iterate first and then upload
- vertex_buffer.write(offset_v, vertices);
- index_buffer.write(offset_i, indices);
-
- offset_v += vertices.len() as u64;
- offset_i += indices.len() as u64;
- indices_lengths.push(mesh.buffers.indices.len());
-
- match mesh.shader {
- Shader::Solid(color) => {
- self.pipelines.solid.push(transform, color);
- }
- Shader::Gradient(gradient) => {
- self.pipelines.gradient.push(transform, gradient);
- }
- }
+ self.index_strides.push(mesh.buffers.indices.len() as u32);
+
+ //push uniform data to CPU buffers
+ match mesh.shader {
+ Shader::Solid(color) => {
+ self.pipelines.solid.push(transform, color);
}
+ Shader::Gradient(gradient) => {
+ self.pipelines.gradient.push(transform, gradient);
+ }
+ }
+ }
- //done writing to gpu buffer, unmap from host memory since we don't need it
- //anymore
- vertex_buffer.flush();
- index_buffer.flush();
-
- //resize & memcpy uniforms from CPU buffers to GPU buffers for all pipelines
- self.pipelines.write(device, staging_belt, encoder);
-
- //configure the render pass now that the data is uploaded to the GPU
- {
- //configure antialiasing pass
- 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: true },
- },
- )],
- depth_stencil_attachment: None,
+ //write uniform data to GPU
+ self.pipelines.write(device, staging_belt, encoder);
+
+ //configure the render pass now that the data is uploaded to the GPU
+ {
+ //configure antialiasing pass
+ 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: true },
},
- );
-
- //TODO: do this a better way; store it in the respective pipelines perhaps
- // to be more readable
- let mut num_solids = 0;
- let mut num_gradients = 0;
-
- //TODO: try to avoid this extra iteration if possible
- for index in 0..meshes.0.len() {
- let clip_bounds =
- (meshes.0[index].clip_bounds * scale_factor).snap();
-
- render_pass.set_scissor_rect(
- clip_bounds.x,
- clip_bounds.y,
- clip_bounds.width,
- clip_bounds.height,
- );
-
- match meshes.0[index].shader {
- Shader::Solid(_) => {
- self.pipelines.solid.configure_render_pass(
- &mut render_pass,
- num_solids,
- );
- num_solids += 1;
- }
- Shader::Gradient(_) => {
- self.pipelines.gradient.configure_render_pass(
- &mut render_pass,
- num_gradients,
- );
- num_gradients += 1;
- }
- }
-
- render_pass.set_index_buffer(
- index_buffer.slice_from_index::<u32>(index),
- wgpu::IndexFormat::Uint32,
+ )],
+ depth_stencil_attachment: None,
+ });
+
+ //TODO I can't figure out a clean way to encapsulate these into their appropriate
+ // structs without displeasing the borrow checker due to the lifetime requirements of
+ // render_pass & using a mutable reference to each pipeline in a loop...
+ let mut num_solids = 0;
+ let mut num_gradients = 0;
+
+ for (index, mesh) in meshes.iter().enumerate() {
+ let clip_bounds = (mesh.clip_bounds * scale_factor).snap();
+
+ render_pass.set_scissor_rect(
+ clip_bounds.x,
+ clip_bounds.y,
+ clip_bounds.width,
+ clip_bounds.height,
+ );
+
+ match mesh.shader {
+ Shader::Solid(_) => {
+ self.pipelines.solid.configure_render_pass(
+ &mut render_pass,
+ num_solids,
);
-
- render_pass.set_vertex_buffer(
- 0,
- vertex_buffer.slice_from_index::<Vertex2D>(index),
- );
-
- render_pass.draw_indexed(
- 0..(indices_lengths[index] as u32),
- 0,
- 0..1,
+ num_solids += 1;
+ }
+ Shader::Gradient(_) => {
+ self.pipelines.gradient.configure_render_pass(
+ &mut render_pass,
+ num_gradients,
);
+ num_gradients += 1;
}
- }
+ };
+
+ render_pass.set_vertex_buffer(
+ 0,
+ self.vertex_buffer.slice_from_index(index),
+ );
+
+ render_pass.set_index_buffer(
+ self.index_buffer.slice_from_index(index),
+ wgpu::IndexFormat::Uint32,
+ );
+
+ render_pass.draw_indexed(
+ 0..(self.index_strides[index] as u32),
+ 0,
+ 0..1,
+ );
}
}
if let Some(blit) = &mut self.blit {
blit.draw(encoder, target);
}
-
- //cleanup
- self.pipelines.clear();
}
}