Use a StagingBelt in iced_wgpu for regular buffer uploads

This commit is contained in:
Héctor Ramón Jiménez 2024-03-29 04:02:24 +01:00
parent 1df1cf82f4
commit 2bb53ad6e7
No known key found for this signature in database
GPG key ID: 4C07CEC81AFA161F
10 changed files with 113 additions and 41 deletions

View file

@ -30,6 +30,7 @@ pub struct Backend {
pipeline_storage: pipeline::Storage,
#[cfg(any(feature = "image", feature = "svg"))]
image_pipeline: image::Pipeline,
staging_belt: wgpu::util::StagingBelt,
}
impl Backend {
@ -61,6 +62,11 @@ impl Backend {
#[cfg(any(feature = "image", feature = "svg"))]
image_pipeline,
// TODO: Resize belt smartly (?)
// It would be great if the `StagingBelt` API exposed methods
// for introspection to detect when a resize may be worth it.
staging_belt: wgpu::util::StagingBelt::new(1024 * 100),
}
}
@ -105,6 +111,8 @@ impl Backend {
&layers,
);
self.staging_belt.finish();
self.render(
device,
encoder,
@ -123,12 +131,17 @@ impl Backend {
self.image_pipeline.end_frame();
}
///
pub fn recall(&mut self) {
self.staging_belt.recall();
}
fn prepare(
&mut self,
device: &wgpu::Device,
queue: &wgpu::Queue,
format: wgpu::TextureFormat,
_encoder: &mut wgpu::CommandEncoder,
encoder: &mut wgpu::CommandEncoder,
scale_factor: f32,
target_size: Size<u32>,
transformation: Transformation,
@ -144,7 +157,8 @@ impl Backend {
if !layer.quads.is_empty() {
self.quad_pipeline.prepare(
device,
queue,
encoder,
&mut self.staging_belt,
&layer.quads,
transformation,
scale_factor,
@ -157,7 +171,8 @@ impl Backend {
self.triangle_pipeline.prepare(
device,
queue,
encoder,
&mut self.staging_belt,
&layer.meshes,
scaled,
);
@ -171,8 +186,8 @@ impl Backend {
self.image_pipeline.prepare(
device,
queue,
_encoder,
encoder,
&mut self.staging_belt,
&layer.images,
scaled,
scale_factor,
@ -184,6 +199,7 @@ impl Backend {
self.text_pipeline.prepare(
device,
queue,
encoder,
&layer.text,
layer.bounds,
scale_factor,

View file

@ -61,12 +61,22 @@ impl<T: bytemuck::Pod> Buffer<T> {
/// Returns the size of the written bytes.
pub fn write(
&mut self,
queue: &wgpu::Queue,
device: &wgpu::Device,
encoder: &mut wgpu::CommandEncoder,
belt: &mut wgpu::util::StagingBelt,
offset: usize,
contents: &[T],
) -> usize {
let bytes: &[u8] = bytemuck::cast_slice(contents);
queue.write_buffer(&self.raw, offset as u64, bytes);
belt.write_buffer(
encoder,
&self.raw,
offset as u64,
(bytes.len() as u64).try_into().expect("Non-empty write"),
device,
)
.copy_from_slice(bytes);
self.offsets.push(offset as u64);

View file

@ -83,21 +83,31 @@ impl Layer {
fn prepare(
&mut self,
device: &wgpu::Device,
queue: &wgpu::Queue,
encoder: &mut wgpu::CommandEncoder,
belt: &mut wgpu::util::StagingBelt,
nearest_instances: &[Instance],
linear_instances: &[Instance],
transformation: Transformation,
) {
queue.write_buffer(
let uniforms = Uniforms {
transform: transformation.into(),
};
let bytes = bytemuck::bytes_of(&uniforms);
belt.write_buffer(
encoder,
&self.uniforms,
0,
bytemuck::bytes_of(&Uniforms {
transform: transformation.into(),
}),
);
(bytes.len() as u64).try_into().expect("Sized uniforms"),
device,
)
.copy_from_slice(bytes);
self.nearest.upload(device, queue, nearest_instances);
self.linear.upload(device, queue, linear_instances);
self.nearest
.upload(device, encoder, belt, nearest_instances);
self.linear.upload(device, encoder, belt, linear_instances);
}
fn render<'a>(&'a self, render_pass: &mut wgpu::RenderPass<'a>) {
@ -158,7 +168,8 @@ impl Data {
fn upload(
&mut self,
device: &wgpu::Device,
queue: &wgpu::Queue,
encoder: &mut wgpu::CommandEncoder,
belt: &mut wgpu::util::StagingBelt,
instances: &[Instance],
) {
self.instance_count = instances.len();
@ -168,7 +179,7 @@ impl Data {
}
let _ = self.instances.resize(device, instances.len());
let _ = self.instances.write(queue, 0, instances);
let _ = self.instances.write(device, encoder, belt, 0, instances);
}
fn render<'a>(&'a self, render_pass: &mut wgpu::RenderPass<'a>) {
@ -383,8 +394,8 @@ impl Pipeline {
pub fn prepare(
&mut self,
device: &wgpu::Device,
queue: &wgpu::Queue,
encoder: &mut wgpu::CommandEncoder,
belt: &mut wgpu::util::StagingBelt,
images: &[layer::Image],
transformation: Transformation,
_scale: f32,
@ -501,7 +512,8 @@ impl Pipeline {
layer.prepare(
device,
queue,
encoder,
belt,
nearest_instances,
linear_instances,
transformation,

View file

@ -57,7 +57,8 @@ impl Pipeline {
pub fn prepare(
&mut self,
device: &wgpu::Device,
queue: &wgpu::Queue,
encoder: &mut wgpu::CommandEncoder,
belt: &mut wgpu::util::StagingBelt,
quads: &Batch,
transformation: Transformation,
scale: f32,
@ -67,7 +68,7 @@ impl Pipeline {
}
let layer = &mut self.layers[self.prepare_layer];
layer.prepare(device, queue, quads, transformation, scale);
layer.prepare(device, encoder, belt, quads, transformation, scale);
self.prepare_layer += 1;
}
@ -162,7 +163,8 @@ impl Layer {
pub fn prepare(
&mut self,
device: &wgpu::Device,
queue: &wgpu::Queue,
encoder: &mut wgpu::CommandEncoder,
belt: &mut wgpu::util::StagingBelt,
quads: &Batch,
transformation: Transformation,
scale: f32,
@ -171,15 +173,25 @@ impl Layer {
let _ = info_span!("Wgpu::Quad", "PREPARE").entered();
let uniforms = Uniforms::new(transformation, scale);
let bytes = bytemuck::bytes_of(&uniforms);
queue.write_buffer(
belt.write_buffer(
encoder,
&self.constants_buffer,
0,
bytemuck::bytes_of(&uniforms),
);
(bytes.len() as u64).try_into().expect("Sized uniforms"),
device,
)
.copy_from_slice(bytes);
self.solid.prepare(device, queue, &quads.solids);
self.gradient.prepare(device, queue, &quads.gradients);
if !quads.solids.is_empty() {
self.solid.prepare(device, encoder, belt, &quads.solids);
}
if !quads.gradients.is_empty() {
self.gradient
.prepare(device, encoder, belt, &quads.gradients);
}
}
}

View file

@ -46,11 +46,12 @@ impl Layer {
pub fn prepare(
&mut self,
device: &wgpu::Device,
queue: &wgpu::Queue,
encoder: &mut wgpu::CommandEncoder,
belt: &mut wgpu::util::StagingBelt,
instances: &[Gradient],
) {
let _ = self.instances.resize(device, instances.len());
let _ = self.instances.write(queue, 0, instances);
let _ = self.instances.write(device, encoder, belt, 0, instances);
self.instance_count = instances.len();
}

View file

@ -40,11 +40,12 @@ impl Layer {
pub fn prepare(
&mut self,
device: &wgpu::Device,
queue: &wgpu::Queue,
encoder: &mut wgpu::CommandEncoder,
belt: &mut wgpu::util::StagingBelt,
instances: &[Solid],
) {
let _ = self.instances.resize(device, instances.len());
let _ = self.instances.write(queue, 0, instances);
let _ = self.instances.write(device, encoder, belt, 0, instances);
self.instance_count = instances.len();
}

View file

@ -53,6 +53,7 @@ impl Pipeline {
&mut self,
device: &wgpu::Device,
queue: &wgpu::Queue,
encoder: &mut wgpu::CommandEncoder,
sections: &[Text<'_>],
layer_bounds: Rectangle,
scale_factor: f32,
@ -262,6 +263,7 @@ impl Pipeline {
let result = renderer.prepare(
device,
queue,
encoder,
font_system,
&mut self.atlas,
glyphon::Resolution {

View file

@ -48,7 +48,8 @@ impl Layer {
fn prepare(
&mut self,
device: &wgpu::Device,
queue: &wgpu::Queue,
encoder: &mut wgpu::CommandEncoder,
belt: &mut wgpu::util::StagingBelt,
solid: &solid::Pipeline,
gradient: &gradient::Pipeline,
meshes: &[Mesh<'_>],
@ -103,33 +104,47 @@ impl Layer {
let uniforms =
Uniforms::new(transformation * mesh.transformation());
index_offset +=
self.index_buffer.write(queue, index_offset, indices);
index_offset += self.index_buffer.write(
device,
encoder,
belt,
index_offset,
indices,
);
self.index_strides.push(indices.len() as u32);
match mesh {
Mesh::Solid { buffers, .. } => {
solid_vertex_offset += self.solid.vertices.write(
queue,
device,
encoder,
belt,
solid_vertex_offset,
&buffers.vertices,
);
solid_uniform_offset += self.solid.uniforms.write(
queue,
device,
encoder,
belt,
solid_uniform_offset,
&[uniforms],
);
}
Mesh::Gradient { buffers, .. } => {
gradient_vertex_offset += self.gradient.vertices.write(
queue,
device,
encoder,
belt,
gradient_vertex_offset,
&buffers.vertices,
);
gradient_uniform_offset += self.gradient.uniforms.write(
queue,
device,
encoder,
belt,
gradient_uniform_offset,
&[uniforms],
);
@ -237,7 +252,8 @@ impl Pipeline {
pub fn prepare(
&mut self,
device: &wgpu::Device,
queue: &wgpu::Queue,
encoder: &mut wgpu::CommandEncoder,
belt: &mut wgpu::util::StagingBelt,
meshes: &[Mesh<'_>],
transformation: Transformation,
) {
@ -252,7 +268,8 @@ impl Pipeline {
let layer = &mut self.layers[self.prepare_layer];
layer.prepare(
device,
queue,
encoder,
belt,
&self.solid,
&self.gradient,
meshes,

View file

@ -243,6 +243,7 @@ pub fn present<T: AsRef<str>>(
// Submit work
let _submission = compositor.queue.submit(Some(encoder.finish()));
backend.recall();
frame.present();
Ok(())