Reuse a RenderPass as much as possible in iced_wgpu
This commit is contained in:
parent
b8c1809ea1
commit
730d6a0756
8 changed files with 197 additions and 171 deletions
|
|
@ -250,6 +250,7 @@ pub fn main() {
|
|||
&device,
|
||||
&queue,
|
||||
&mut encoder,
|
||||
None,
|
||||
&view,
|
||||
primitive,
|
||||
&viewport,
|
||||
|
|
|
|||
|
|
@ -59,8 +59,9 @@ path = "../graphics"
|
|||
|
||||
[dependencies.glyphon]
|
||||
version = "0.2"
|
||||
git = "https://github.com/hecrj/glyphon.git"
|
||||
rev = "3c2acb9dea5b9fcb0fa650b3c73b3a3242c62f4a"
|
||||
# git = "https://github.com/hecrj/glyphon.git"
|
||||
# rev = "3c2acb9dea5b9fcb0fa650b3c73b3a3242c62f4a"
|
||||
path = "../../glyphon"
|
||||
|
||||
[dependencies.tracing]
|
||||
version = "0.1.6"
|
||||
|
|
|
|||
|
|
@ -5,8 +5,7 @@ use crate::{Settings, Transformation};
|
|||
|
||||
use iced_graphics::backend;
|
||||
use iced_graphics::layer::Layer;
|
||||
use iced_graphics::{Primitive, Viewport};
|
||||
use iced_native::{Font, Size};
|
||||
use iced_graphics::{Color, Font, Primitive, Size, Viewport};
|
||||
|
||||
#[cfg(feature = "tracing")]
|
||||
use tracing::info_span;
|
||||
|
|
@ -71,6 +70,7 @@ impl Backend {
|
|||
device: &wgpu::Device,
|
||||
queue: &wgpu::Queue,
|
||||
encoder: &mut wgpu::CommandEncoder,
|
||||
clear_color: Option<Color>,
|
||||
frame: &wgpu::TextureView,
|
||||
primitives: &[Primitive],
|
||||
viewport: &Viewport,
|
||||
|
|
@ -87,18 +87,25 @@ impl Backend {
|
|||
let mut layers = Layer::generate(primitives, viewport);
|
||||
layers.push(Layer::overlay(overlay_text, viewport));
|
||||
|
||||
for layer in layers {
|
||||
self.flush(
|
||||
device,
|
||||
queue,
|
||||
scale_factor,
|
||||
transformation,
|
||||
&layer,
|
||||
encoder,
|
||||
frame,
|
||||
target_size,
|
||||
);
|
||||
}
|
||||
self.prepare(
|
||||
device,
|
||||
queue,
|
||||
encoder,
|
||||
scale_factor,
|
||||
transformation,
|
||||
target_size,
|
||||
&layers,
|
||||
);
|
||||
|
||||
self.render(
|
||||
device,
|
||||
encoder,
|
||||
frame,
|
||||
clear_color,
|
||||
scale_factor,
|
||||
target_size,
|
||||
&layers,
|
||||
);
|
||||
|
||||
self.quad_pipeline.end_frame();
|
||||
self.text_pipeline.end_frame();
|
||||
|
|
@ -108,90 +115,153 @@ impl Backend {
|
|||
self.image_pipeline.end_frame(device, queue, encoder);
|
||||
}
|
||||
|
||||
fn flush(
|
||||
fn prepare(
|
||||
&mut self,
|
||||
device: &wgpu::Device,
|
||||
queue: &wgpu::Queue,
|
||||
_encoder: &mut wgpu::CommandEncoder,
|
||||
scale_factor: f32,
|
||||
transformation: Transformation,
|
||||
layer: &Layer<'_>,
|
||||
encoder: &mut wgpu::CommandEncoder,
|
||||
target: &wgpu::TextureView,
|
||||
target_size: Size<u32>,
|
||||
layers: &[Layer<'_>],
|
||||
) {
|
||||
let bounds = (layer.bounds * scale_factor).snap();
|
||||
for layer in layers {
|
||||
let bounds = (layer.bounds * scale_factor).snap();
|
||||
|
||||
if bounds.width < 1 || bounds.height < 1 {
|
||||
return;
|
||||
}
|
||||
if bounds.width < 1 || bounds.height < 1 {
|
||||
return;
|
||||
}
|
||||
|
||||
if !layer.quads.is_empty() {
|
||||
self.quad_pipeline.prepare(
|
||||
device,
|
||||
queue,
|
||||
&layer.quads,
|
||||
transformation,
|
||||
scale_factor,
|
||||
);
|
||||
if !layer.quads.is_empty() {
|
||||
self.quad_pipeline.prepare(
|
||||
device,
|
||||
queue,
|
||||
&layer.quads,
|
||||
transformation,
|
||||
scale_factor,
|
||||
);
|
||||
}
|
||||
|
||||
let mut render_pass =
|
||||
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: Some("iced_wgpu::quad render pass"),
|
||||
color_attachments: &[Some(
|
||||
wgpu::RenderPassColorAttachment {
|
||||
view: target,
|
||||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Load,
|
||||
store: true,
|
||||
},
|
||||
},
|
||||
)],
|
||||
depth_stencil_attachment: None,
|
||||
});
|
||||
|
||||
self.quad_pipeline.render(bounds, &mut render_pass);
|
||||
}
|
||||
|
||||
if !layer.meshes.is_empty() {
|
||||
let scaled = transformation
|
||||
* Transformation::scale(scale_factor, scale_factor);
|
||||
|
||||
self.triangle_pipeline.prepare(
|
||||
device,
|
||||
queue,
|
||||
&layer.meshes,
|
||||
scaled,
|
||||
);
|
||||
|
||||
self.triangle_pipeline.render(
|
||||
device,
|
||||
encoder,
|
||||
target,
|
||||
target_size,
|
||||
&layer.meshes,
|
||||
scale_factor,
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "image", feature = "svg"))]
|
||||
{
|
||||
if !layer.images.is_empty() {
|
||||
if !layer.meshes.is_empty() {
|
||||
let scaled = transformation
|
||||
* Transformation::scale(scale_factor, scale_factor);
|
||||
|
||||
self.image_pipeline.prepare(
|
||||
self.triangle_pipeline.prepare(
|
||||
device,
|
||||
queue,
|
||||
encoder,
|
||||
&layer.images,
|
||||
&layer.meshes,
|
||||
scaled,
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "image", feature = "svg"))]
|
||||
{
|
||||
if !layer.images.is_empty() {
|
||||
let scaled = transformation
|
||||
* Transformation::scale(scale_factor, scale_factor);
|
||||
|
||||
self.image_pipeline.prepare(
|
||||
device,
|
||||
queue,
|
||||
_encoder,
|
||||
&layer.images,
|
||||
scaled,
|
||||
scale_factor,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if !layer.text.is_empty() {
|
||||
self.text_pipeline.prepare(
|
||||
device,
|
||||
queue,
|
||||
&layer.text,
|
||||
layer.bounds,
|
||||
scale_factor,
|
||||
target_size,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render(
|
||||
&mut self,
|
||||
device: &wgpu::Device,
|
||||
encoder: &mut wgpu::CommandEncoder,
|
||||
target: &wgpu::TextureView,
|
||||
clear_color: Option<Color>,
|
||||
scale_factor: f32,
|
||||
target_size: Size<u32>,
|
||||
layers: &[Layer<'_>],
|
||||
) {
|
||||
use std::mem::ManuallyDrop;
|
||||
|
||||
let mut quad_layer = 0;
|
||||
let mut triangle_layer = 0;
|
||||
#[cfg(any(feature = "image", feature = "svg"))]
|
||||
let mut image_layer = 0;
|
||||
let mut text_layer = 0;
|
||||
|
||||
let mut render_pass = ManuallyDrop::new(encoder.begin_render_pass(
|
||||
&wgpu::RenderPassDescriptor {
|
||||
label: Some("iced_wgpu::quad render pass"),
|
||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||
view: target,
|
||||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: match clear_color {
|
||||
Some(background_color) => wgpu::LoadOp::Clear({
|
||||
let [r, g, b, a] =
|
||||
background_color.into_linear();
|
||||
|
||||
wgpu::Color {
|
||||
r: f64::from(r),
|
||||
g: f64::from(g),
|
||||
b: f64::from(b),
|
||||
a: f64::from(a),
|
||||
}
|
||||
}),
|
||||
None => wgpu::LoadOp::Load,
|
||||
},
|
||||
store: true,
|
||||
},
|
||||
})],
|
||||
depth_stencil_attachment: None,
|
||||
},
|
||||
));
|
||||
|
||||
for layer in layers {
|
||||
let bounds = (layer.bounds * scale_factor).snap();
|
||||
|
||||
if bounds.width < 1 || bounds.height < 1 {
|
||||
return;
|
||||
}
|
||||
|
||||
if !layer.quads.is_empty() {
|
||||
self.quad_pipeline
|
||||
.render(quad_layer, bounds, &mut render_pass);
|
||||
|
||||
quad_layer += 1;
|
||||
}
|
||||
|
||||
if !layer.meshes.is_empty() {
|
||||
let _ = ManuallyDrop::into_inner(render_pass);
|
||||
|
||||
self.triangle_pipeline.render(
|
||||
device,
|
||||
encoder,
|
||||
target,
|
||||
triangle_layer,
|
||||
target_size,
|
||||
&layer.meshes,
|
||||
scale_factor,
|
||||
);
|
||||
|
||||
let mut render_pass =
|
||||
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: Some("iced_wgpu::image render pass"),
|
||||
triangle_layer += 1;
|
||||
|
||||
render_pass = ManuallyDrop::new(encoder.begin_render_pass(
|
||||
&wgpu::RenderPassDescriptor {
|
||||
label: Some("iced_wgpu::quad render pass"),
|
||||
color_attachments: &[Some(
|
||||
wgpu::RenderPassColorAttachment {
|
||||
view: target,
|
||||
|
|
@ -203,24 +273,31 @@ impl Backend {
|
|||
},
|
||||
)],
|
||||
depth_stencil_attachment: None,
|
||||
});
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
self.image_pipeline.render(bounds, &mut render_pass);
|
||||
#[cfg(any(feature = "image", feature = "svg"))]
|
||||
{
|
||||
if !layer.images.is_empty() {
|
||||
self.image_pipeline.render(
|
||||
image_layer,
|
||||
bounds,
|
||||
&mut render_pass,
|
||||
);
|
||||
|
||||
image_layer += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if !layer.text.is_empty() {
|
||||
self.text_pipeline.render(text_layer, &mut render_pass);
|
||||
|
||||
text_layer += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if !layer.text.is_empty() {
|
||||
self.text_pipeline.prepare(
|
||||
device,
|
||||
queue,
|
||||
&layer.text,
|
||||
layer.bounds,
|
||||
scale_factor,
|
||||
target_size,
|
||||
);
|
||||
|
||||
self.text_pipeline.render(encoder, target);
|
||||
}
|
||||
let _ = ManuallyDrop::into_inner(render_pass);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@ pub struct Pipeline {
|
|||
|
||||
layers: Vec<Layer>,
|
||||
prepare_layer: usize,
|
||||
render_layer: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -321,7 +320,6 @@ impl Pipeline {
|
|||
|
||||
layers: Vec::new(),
|
||||
prepare_layer: 0,
|
||||
render_layer: 0,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -452,11 +450,12 @@ impl Pipeline {
|
|||
}
|
||||
|
||||
pub fn render<'a>(
|
||||
&'a mut self,
|
||||
&'a self,
|
||||
layer: usize,
|
||||
bounds: Rectangle<u32>,
|
||||
render_pass: &mut wgpu::RenderPass<'a>,
|
||||
) {
|
||||
if let Some(layer) = self.layers.get(self.render_layer) {
|
||||
if let Some(layer) = self.layers.get(layer) {
|
||||
render_pass.set_pipeline(&self.pipeline);
|
||||
|
||||
render_pass.set_scissor_rect(
|
||||
|
|
@ -474,8 +473,6 @@ impl Pipeline {
|
|||
render_pass.set_vertex_buffer(0, self.vertices.slice(..));
|
||||
|
||||
layer.render(render_pass);
|
||||
|
||||
self.render_layer += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -496,7 +493,6 @@ impl Pipeline {
|
|||
.trim(&mut self.texture_atlas, &mut (device, queue, encoder));
|
||||
|
||||
self.prepare_layer = 0;
|
||||
self.render_layer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ pub struct Pipeline {
|
|||
indices: wgpu::Buffer,
|
||||
layers: Vec<Layer>,
|
||||
prepare_layer: usize,
|
||||
render_layer: usize,
|
||||
}
|
||||
|
||||
impl Pipeline {
|
||||
|
|
@ -140,7 +139,6 @@ impl Pipeline {
|
|||
indices,
|
||||
layers: Vec::new(),
|
||||
prepare_layer: 0,
|
||||
render_layer: 0,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -163,11 +161,12 @@ impl Pipeline {
|
|||
}
|
||||
|
||||
pub fn render<'a>(
|
||||
&'a mut self,
|
||||
&'a self,
|
||||
layer: usize,
|
||||
bounds: Rectangle<u32>,
|
||||
render_pass: &mut wgpu::RenderPass<'a>,
|
||||
) {
|
||||
if let Some(layer) = self.layers.get(self.render_layer) {
|
||||
if let Some(layer) = self.layers.get(layer) {
|
||||
render_pass.set_pipeline(&self.pipeline);
|
||||
|
||||
render_pass.set_scissor_rect(
|
||||
|
|
@ -184,14 +183,11 @@ impl Pipeline {
|
|||
render_pass.set_vertex_buffer(0, self.vertices.slice(..));
|
||||
|
||||
layer.draw(render_pass);
|
||||
|
||||
self.render_layer += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn end_frame(&mut self) {
|
||||
self.prepare_layer = 0;
|
||||
self.render_layer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ pub struct Pipeline {
|
|||
system: Option<System>,
|
||||
renderers: Vec<glyphon::TextRenderer>,
|
||||
atlas: glyphon::TextAtlas,
|
||||
layer: usize,
|
||||
prepare_layer: usize,
|
||||
}
|
||||
|
||||
#[ouroboros::self_referencing]
|
||||
|
|
@ -55,7 +55,7 @@ impl Pipeline {
|
|||
),
|
||||
renderers: Vec::new(),
|
||||
atlas: glyphon::TextAtlas::new(device, queue, format),
|
||||
layer: 0,
|
||||
prepare_layer: 0,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -88,12 +88,12 @@ impl Pipeline {
|
|||
target_size: Size<u32>,
|
||||
) {
|
||||
self.system.as_mut().unwrap().with_mut(|fields| {
|
||||
if self.renderers.len() <= self.layer {
|
||||
if self.renderers.len() <= self.prepare_layer {
|
||||
self.renderers
|
||||
.push(glyphon::TextRenderer::new(device, queue));
|
||||
}
|
||||
|
||||
let renderer = &mut self.renderers[self.layer];
|
||||
let renderer = &mut self.renderers[self.prepare_layer];
|
||||
|
||||
let keys: Vec<_> = sections
|
||||
.iter()
|
||||
|
|
@ -179,35 +179,21 @@ impl Pipeline {
|
|||
&mut glyphon::SwashCache::new(fields.fonts),
|
||||
)
|
||||
.expect("Prepare text sections");
|
||||
|
||||
self.prepare_layer += 1;
|
||||
});
|
||||
}
|
||||
|
||||
pub fn render(
|
||||
&mut self,
|
||||
encoder: &mut wgpu::CommandEncoder,
|
||||
target: &wgpu::TextureView,
|
||||
pub fn render<'a>(
|
||||
&'a self,
|
||||
layer: usize,
|
||||
render_pass: &mut wgpu::RenderPass<'a>,
|
||||
) {
|
||||
let mut render_pass =
|
||||
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: None,
|
||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||
view: target,
|
||||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Load,
|
||||
store: true,
|
||||
},
|
||||
})],
|
||||
depth_stencil_attachment: None,
|
||||
});
|
||||
|
||||
let renderer = &mut self.renderers[self.layer];
|
||||
let renderer = &self.renderers[layer];
|
||||
|
||||
renderer
|
||||
.render(&self.atlas, &mut render_pass)
|
||||
.render(&self.atlas, render_pass)
|
||||
.expect("Render text");
|
||||
|
||||
self.layer += 1;
|
||||
}
|
||||
|
||||
pub fn end_frame(&mut self) {
|
||||
|
|
@ -216,7 +202,7 @@ impl Pipeline {
|
|||
.unwrap()
|
||||
.with_render_cache_mut(|cache| cache.trim());
|
||||
|
||||
self.layer = 0;
|
||||
self.prepare_layer = 0;
|
||||
}
|
||||
|
||||
pub fn measure(
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ pub struct Pipeline {
|
|||
|
||||
layers: Vec<Layer>,
|
||||
prepare_layer: usize,
|
||||
render_layer: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -235,7 +234,7 @@ impl Layer {
|
|||
}
|
||||
|
||||
fn render<'a>(
|
||||
&'a mut self,
|
||||
&'a self,
|
||||
solid: &'a solid::Pipeline,
|
||||
#[cfg(not(target_arch = "wasm32"))] gradient: &'a gradient::Pipeline,
|
||||
meshes: &[Mesh<'_>],
|
||||
|
|
@ -331,7 +330,6 @@ impl Pipeline {
|
|||
|
||||
layers: Vec::new(),
|
||||
prepare_layer: 0,
|
||||
render_layer: 0,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -373,6 +371,7 @@ impl Pipeline {
|
|||
device: &wgpu::Device,
|
||||
encoder: &mut wgpu::CommandEncoder,
|
||||
target: &wgpu::TextureView,
|
||||
layer: usize,
|
||||
target_size: Size<u32>,
|
||||
meshes: &[Mesh<'_>],
|
||||
scale_factor: f32,
|
||||
|
|
@ -413,7 +412,7 @@ impl Pipeline {
|
|||
depth_stencil_attachment: None,
|
||||
});
|
||||
|
||||
let layer = &mut self.layers[self.render_layer];
|
||||
let layer = &mut self.layers[layer];
|
||||
|
||||
layer.render(
|
||||
&self.solid,
|
||||
|
|
@ -425,8 +424,6 @@ impl Pipeline {
|
|||
);
|
||||
}
|
||||
|
||||
self.render_layer += 1;
|
||||
|
||||
if let Some(blit) = &mut self.blit {
|
||||
blit.draw(encoder, target);
|
||||
}
|
||||
|
|
@ -434,7 +431,6 @@ impl Pipeline {
|
|||
|
||||
pub fn end_frame(&mut self) {
|
||||
self.prepare_layer = 0;
|
||||
self.render_layer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -190,39 +190,12 @@ impl<Theme> iced_graphics::window::Compositor for Compositor<Theme> {
|
|||
.texture
|
||||
.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
|
||||
let _ =
|
||||
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: Some(
|
||||
"iced_wgpu::window::Compositor render pass",
|
||||
),
|
||||
color_attachments: &[Some(
|
||||
wgpu::RenderPassColorAttachment {
|
||||
view,
|
||||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear({
|
||||
let [r, g, b, a] =
|
||||
background_color.into_linear();
|
||||
|
||||
wgpu::Color {
|
||||
r: f64::from(r),
|
||||
g: f64::from(g),
|
||||
b: f64::from(b),
|
||||
a: f64::from(a),
|
||||
}
|
||||
}),
|
||||
store: true,
|
||||
},
|
||||
},
|
||||
)],
|
||||
depth_stencil_attachment: None,
|
||||
});
|
||||
|
||||
renderer.with_primitives(|backend, primitives| {
|
||||
backend.present(
|
||||
&self.device,
|
||||
&self.queue,
|
||||
&mut encoder,
|
||||
Some(background_color),
|
||||
view,
|
||||
primitives,
|
||||
viewport,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue