Clip and cull Mesh2D primitives in iced_wgpu

This commit is contained in:
Héctor Ramón Jiménez 2020-04-28 04:41:09 +02:00
parent 69c60d372c
commit e65585ae17
5 changed files with 45 additions and 25 deletions

View file

@ -88,6 +88,7 @@ mod rainbow {
Primitive::Translate { Primitive::Translate {
translation: Vector::new(b.x, b.y), translation: Vector::new(b.x, b.y),
content: Box::new(Primitive::Mesh2D { content: Box::new(Primitive::Mesh2D {
size: b.size(),
buffers: Mesh2D { buffers: Mesh2D {
vertices: vec![ vertices: vec![
Vertex2D { Vertex2D {

View file

@ -1,5 +1,5 @@
use iced_native::{ use iced_native::{
image, svg, Background, Color, Font, HorizontalAlignment, Rectangle, image, svg, Background, Color, Font, HorizontalAlignment, Rectangle, Size,
Vector, VerticalAlignment, Vector, VerticalAlignment,
}; };
@ -72,7 +72,7 @@ pub enum Primitive {
}, },
/// A primitive that applies a translation /// A primitive that applies a translation
Translate { Translate {
/// The top-left coordinate of the mesh /// The translation vector
translation: Vector, translation: Vector,
/// The primitive to translate /// The primitive to translate
@ -82,6 +82,11 @@ pub enum Primitive {
/// ///
/// It can be used to render many kinds of geometry freely. /// It can be used to render many kinds of geometry freely.
Mesh2D { Mesh2D {
/// The size of the drawable region of the mesh.
///
/// Any geometry that falls out of this region will be clipped.
size: Size,
/// The vertex and index buffers of the mesh /// The vertex and index buffers of the mesh
buffers: triangle::Mesh2D, buffers: triangle::Mesh2D,
}, },

View file

@ -29,7 +29,7 @@ pub struct Renderer {
struct Layer<'a> { struct Layer<'a> {
bounds: Rectangle<u32>, bounds: Rectangle<u32>,
quads: Vec<Quad>, quads: Vec<Quad>,
meshes: Vec<(Vector, &'a triangle::Mesh2D)>, meshes: Vec<(Vector, Rectangle<u32>, &'a triangle::Mesh2D)>,
text: Vec<wgpu_glyph::Section<'a>>, text: Vec<wgpu_glyph::Section<'a>>,
#[cfg(any(feature = "image", feature = "svg"))] #[cfg(any(feature = "image", feature = "svg"))]
@ -48,6 +48,12 @@ impl<'a> Layer<'a> {
images: Vec::new(), images: Vec::new(),
} }
} }
pub fn intersection(&self, rectangle: Rectangle) -> Option<Rectangle<u32>> {
let layer_bounds: Rectangle<f32> = self.bounds.into();
layer_bounds.intersection(&rectangle).map(Into::into)
}
} }
impl Renderer { impl Renderer {
@ -214,10 +220,20 @@ impl Renderer {
border_color: border_color.into_linear(), border_color: border_color.into_linear(),
}); });
} }
Primitive::Mesh2D { buffers } => { Primitive::Mesh2D { size, buffers } => {
let layer = layers.last_mut().unwrap(); let layer = layers.last_mut().unwrap();
layer.meshes.push((translation, buffers)); // Only draw visible content
if let Some(clip_bounds) = layer.intersection(Rectangle::new(
Point::new(translation.x, translation.y),
*size,
)) {
layer.meshes.push((
translation,
clip_bounds.into(),
buffers,
));
}
} }
Primitive::Clip { Primitive::Clip {
bounds, bounds,
@ -226,16 +242,10 @@ impl Renderer {
} => { } => {
let layer = layers.last_mut().unwrap(); let layer = layers.last_mut().unwrap();
let layer_bounds: Rectangle<f32> = layer.bounds.into();
let clip = Rectangle {
x: bounds.x + translation.x,
y: bounds.y + translation.y,
..*bounds
};
// Only draw visible content // Only draw visible content
if let Some(clip_bounds) = layer_bounds.intersection(&clip) { if let Some(clip_bounds) =
layer.intersection(*bounds + translation)
{
let clip_layer = Layer::new(clip_bounds.into()); let clip_layer = Layer::new(clip_bounds.into());
let new_layer = Layer::new(layer.bounds); let new_layer = Layer::new(layer.bounds);
@ -356,8 +366,8 @@ impl Renderer {
target_width, target_width,
target_height, target_height,
scaled, scaled,
scale_factor,
&layer.meshes, &layer.meshes,
bounds,
); );
} }

View file

@ -201,15 +201,15 @@ impl Pipeline {
target_width: u32, target_width: u32,
target_height: u32, target_height: u32,
transformation: Transformation, transformation: Transformation,
meshes: &[(Vector, &Mesh2D)], scale_factor: f32,
bounds: Rectangle<u32>, meshes: &[(Vector, Rectangle<u32>, &Mesh2D)],
) { ) {
// This looks a bit crazy, but we are just counting how many vertices // This looks a bit crazy, but we are just counting how many vertices
// and indices we will need to handle. // and indices we will need to handle.
// TODO: Improve readability // TODO: Improve readability
let (total_vertices, total_indices) = meshes let (total_vertices, total_indices) = meshes
.iter() .iter()
.map(|(_, mesh)| (mesh.vertices.len(), mesh.indices.len())) .map(|(_, _, mesh)| (mesh.vertices.len(), mesh.indices.len()))
.fold((0, 0), |(total_v, total_i), (v, i)| { .fold((0, 0), |(total_v, total_i), (v, i)| {
(total_v + v, total_i + i) (total_v + v, total_i + i)
}); });
@ -230,7 +230,7 @@ impl Pipeline {
let mut last_index = 0; let mut last_index = 0;
// We upload everything upfront // We upload everything upfront
for (origin, mesh) in meshes { for (origin, _, mesh) in meshes {
let transform = (transformation let transform = (transformation
* Transformation::translate(origin.x, origin.y)) * Transformation::translate(origin.x, origin.y))
.into(); .into();
@ -316,16 +316,19 @@ impl Pipeline {
}); });
render_pass.set_pipeline(&self.pipeline); render_pass.set_pipeline(&self.pipeline);
render_pass.set_scissor_rect(
bounds.x,
bounds.y,
bounds.width,
bounds.height,
);
for (i, (vertex_offset, index_offset, indices)) in for (i, (vertex_offset, index_offset, indices)) in
offsets.into_iter().enumerate() offsets.into_iter().enumerate()
{ {
let bounds = meshes[i].1 * scale_factor;
render_pass.set_scissor_rect(
bounds.x,
bounds.y,
bounds.width,
bounds.height,
);
render_pass.set_bind_group( render_pass.set_bind_group(
0, 0,
&self.constants, &self.constants,

View file

@ -267,6 +267,7 @@ impl Frame {
pub fn into_geometry(mut self) -> Geometry { pub fn into_geometry(mut self) -> Geometry {
if !self.buffers.indices.is_empty() { if !self.buffers.indices.is_empty() {
self.primitives.push(Primitive::Mesh2D { self.primitives.push(Primitive::Mesh2D {
size: self.size,
buffers: triangle::Mesh2D { buffers: triangle::Mesh2D {
vertices: self.buffers.vertices, vertices: self.buffers.vertices,
indices: self.buffers.indices, indices: self.buffers.indices,