summaryrefslogtreecommitdiffstats
path: root/wgpu/src/triangle.rs
diff options
context:
space:
mode:
authorLibravatar shan <shankern@protonmail.com>2022-10-04 18:24:46 -0700
committerLibravatar shan <shankern@protonmail.com>2022-10-04 18:24:46 -0700
commit6e7b3ced0b1daf368e44e181ecdb4ae529877eb6 (patch)
treee530025c737d509b640172d595cff0a0809f5a40 /wgpu/src/triangle.rs
parent5d0fffc626928177239336757507b986b081b878 (diff)
downloadiced-6e7b3ced0b1daf368e44e181ecdb4ae529877eb6.tar.gz
iced-6e7b3ced0b1daf368e44e181ecdb4ae529877eb6.tar.bz2
iced-6e7b3ced0b1daf368e44e181ecdb4ae529877eb6.zip
Reworked wgpu buffers, updated glow side to have proper transform location storage, attempting to fix visibility modifiers, implemented some of the feedback received in initial PR.
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();
}
}