Implement preliminary cache grouping for mesh primitives

Due to AA, it's very expensive to render every cached
layer independently.
This commit is contained in:
Héctor Ramón Jiménez 2024-04-03 22:13:00 +02:00
parent 09af6773bd
commit 88b72de282
No known key found for this signature in database
GPG key ID: 7CC46565708259A7
2 changed files with 107 additions and 53 deletions

View file

@ -315,9 +315,10 @@ impl Renderer {
// TODO: Can we avoid collecting here? // TODO: Can we avoid collecting here?
let layers: Vec<_> = self.layers.iter().collect(); let layers: Vec<_> = self.layers.iter().collect();
let mut i = 0;
for layer in &layers { while i < layers.len() {
match layer { match layers[i] {
Layer::Live(live) => { Layer::Live(live) => {
let bounds = live let bounds = live
.bounds .bounds
@ -393,32 +394,54 @@ impl Renderer {
image_layer += 1; image_layer += 1;
} }
}
Layer::Cached(cached) => {
let bounds = cached
.bounds
.map(|bounds| bounds * scale_factor)
.map(Rectangle::snap)
.unwrap_or(Rectangle::with_size(target_size));
if !cached.quads.is_empty() { i += 1;
engine.quad_pipeline.render_cache( }
&cached.quads, Layer::Cached(_) => {
bounds, let group_len = layers[i..]
&mut render_pass, .iter()
); .position(|layer| matches!(layer, Layer::Live(_)))
.unwrap_or(layers.len());
let group = layers[i..i + group_len].iter().map(|layer| {
let Layer::Cached(cached) = layer else {
unreachable!()
};
let bounds = cached
.bounds
.map(|bounds| bounds * scale_factor)
.map(Rectangle::snap)
.unwrap_or(Rectangle::with_size(target_size));
(cached, bounds)
});
for (cached, bounds) in group.clone() {
if !cached.quads.is_empty() {
engine.quad_pipeline.render_cache(
&cached.quads,
bounds,
&mut render_pass,
);
}
} }
if !cached.meshes.is_empty() { let group_has_meshes = group
.clone()
.any(|(cached, _)| !cached.meshes.is_empty());
if group_has_meshes {
let _ = ManuallyDrop::into_inner(render_pass); let _ = ManuallyDrop::into_inner(render_pass);
engine.triangle_pipeline.render_cache( engine.triangle_pipeline.render_cache_group(
device, device,
encoder, encoder,
frame, frame,
target_size, target_size,
&cached.meshes, group.clone().map(|(cached, bounds)| {
bounds, (&cached.meshes, bounds)
}),
scale_factor, scale_factor,
); );
@ -443,24 +466,28 @@ impl Renderer {
)); ));
} }
if !cached.text.is_empty() { for (cached, bounds) in group {
engine.text_pipeline.render_cache( if !cached.text.is_empty() {
&cached.text, engine.text_pipeline.render_cache(
bounds, &cached.text,
&mut render_pass, bounds,
); &mut render_pass,
);
}
#[cfg(any(feature = "svg", feature = "image"))]
if !cached.images.is_empty() {
engine.image_pipeline.render(
image_layer,
bounds,
&mut render_pass,
);
image_layer += 1;
}
} }
#[cfg(any(feature = "svg", feature = "image"))] i += group_len;
if !cached.images.is_empty() {
engine.image_pipeline.render(
image_layer,
bounds,
&mut render_pass,
);
image_layer += 1;
}
} }
} }
} }

View file

@ -136,14 +136,13 @@ impl Pipeline {
self.blit.as_mut(), self.blit.as_mut(),
&self.solid, &self.solid,
&self.gradient, &self.gradient,
&self.layers[layer],
target_size, target_size,
meshes, std::iter::once((&self.layers[layer], meshes, bounds)),
bounds,
scale_factor, scale_factor,
); );
} }
#[allow(dead_code)]
pub fn render_cache( pub fn render_cache(
&mut self, &mut self,
device: &wgpu::Device, device: &wgpu::Device,
@ -165,25 +164,51 @@ impl Pipeline {
self.blit.as_mut(), self.blit.as_mut(),
&self.solid, &self.solid,
&self.gradient, &self.gradient,
layer,
target_size, target_size,
batch, std::iter::once((layer, batch, bounds)),
bounds,
scale_factor, scale_factor,
); );
} }
fn render( pub fn render_cache_group<'a>(
&mut self,
device: &wgpu::Device,
encoder: &mut wgpu::CommandEncoder,
target: &wgpu::TextureView,
target_size: Size<u32>,
group: impl Iterator<Item = (&'a Cache, Rectangle<u32>)>,
scale_factor: f32,
) {
let group = group.filter_map(|(cache, bounds)| {
if let Cache::Uploaded { batch, layer, .. } = cache {
Some((layer, batch, bounds))
} else {
None
}
});
Self::render(
device,
encoder,
target,
self.blit.as_mut(),
&self.solid,
&self.gradient,
target_size,
group,
scale_factor,
);
}
fn render<'a>(
device: &wgpu::Device, device: &wgpu::Device,
encoder: &mut wgpu::CommandEncoder, encoder: &mut wgpu::CommandEncoder,
target: &wgpu::TextureView, target: &wgpu::TextureView,
mut blit: Option<&mut msaa::Blit>, mut blit: Option<&mut msaa::Blit>,
solid: &solid::Pipeline, solid: &solid::Pipeline,
gradient: &gradient::Pipeline, gradient: &gradient::Pipeline,
layer: &Layer,
target_size: Size<u32>, target_size: Size<u32>,
meshes: &Batch, group: impl Iterator<Item = (&'a Layer, &'a Batch, Rectangle<u32>)>,
bounds: Rectangle<u32>,
scale_factor: f32, scale_factor: f32,
) { ) {
{ {
@ -220,14 +245,16 @@ impl Pipeline {
occlusion_query_set: None, occlusion_query_set: None,
}); });
layer.render( for (layer, meshes, bounds) in group {
solid, layer.render(
gradient, solid,
meshes, gradient,
bounds, meshes,
scale_factor, bounds,
&mut render_pass, scale_factor,
); &mut render_pass,
);
}
} }
if let Some(blit) = blit { if let Some(blit) = blit {