Use a StagingBelt for regular buffer uploads

`Queue::write_buffer` allocates very regularly. A
`StagingBelt` gives us much more control.
This commit is contained in:
Héctor Ramón Jiménez 2024-03-29 03:55:20 +01:00
parent b411ea71e7
commit c69090f74b
No known key found for this signature in database
GPG key ID: 7CC46565708259A7
2 changed files with 39 additions and 9 deletions

View file

@ -101,6 +101,9 @@ async fn run() {
window.request_redraw();
}
WindowEvent::RedrawRequested => {
let mut encoder = device
.create_command_encoder(&CommandEncoderDescriptor { label: None });
viewport.update(
&queue,
Resolution {
@ -113,6 +116,7 @@ async fn run() {
.prepare(
&device,
&queue,
&mut encoder,
&mut font_system,
&mut atlas,
&viewport,
@ -135,8 +139,6 @@ async fn run() {
let frame = surface.get_current_texture().unwrap();
let view = frame.texture.create_view(&TextureViewDescriptor::default());
let mut encoder = device
.create_command_encoder(&CommandEncoderDescriptor { label: None });
{
let mut pass = encoder.begin_render_pass(&RenderPassDescriptor {
label: None,

View file

@ -2,15 +2,17 @@ use crate::{
ColorMode, FontSystem, GlyphDetails, GlyphToRender, GpuCacheStatus, PrepareError, RenderError,
SwashCache, SwashContent, TextArea, TextAtlas, Viewport,
};
use std::{iter, slice, sync::Arc};
use std::{iter, num::NonZeroU64, slice, sync::Arc};
use wgpu::util::StagingBelt;
use wgpu::{
Buffer, BufferDescriptor, BufferUsages, DepthStencilState, Device, Extent3d, ImageCopyTexture,
ImageDataLayout, IndexFormat, MultisampleState, Origin3d, Queue, RenderPass, RenderPipeline,
TextureAspect, COPY_BUFFER_ALIGNMENT,
Buffer, BufferDescriptor, BufferUsages, CommandEncoder, DepthStencilState, Device, Extent3d,
ImageCopyTexture, ImageDataLayout, IndexFormat, MultisampleState, Origin3d, Queue, RenderPass,
RenderPipeline, TextureAspect, COPY_BUFFER_ALIGNMENT,
};
/// A text renderer that uses cached glyphs to render text into an existing render pass.
pub struct TextRenderer {
staging_belt: StagingBelt,
vertex_buffer: Buffer,
vertex_buffer_size: u64,
index_buffer: Buffer,
@ -48,6 +50,7 @@ impl TextRenderer {
let pipeline = atlas.get_or_create_pipeline(device, multisample, depth_stencil);
Self {
staging_belt: StagingBelt::new(vertex_buffer_size),
vertex_buffer,
vertex_buffer_size,
index_buffer,
@ -64,6 +67,7 @@ impl TextRenderer {
&mut self,
device: &Device,
queue: &Queue,
encoder: &mut CommandEncoder,
font_system: &mut FontSystem,
atlas: &mut TextAtlas,
viewport: &Viewport,
@ -71,10 +75,11 @@ impl TextRenderer {
cache: &mut SwashCache,
mut metadata_to_depth: impl FnMut(usize) -> f32,
) -> Result<(), PrepareError> {
self.staging_belt.recall();
self.glyph_vertices.clear();
self.glyph_indices.clear();
let mut glyphs_added = 0;
let mut glyphs_added = 0;
let resolution = viewport.resolution();
for text_area in text_areas {
@ -307,7 +312,15 @@ impl TextRenderer {
};
if self.vertex_buffer_size >= vertices_raw.len() as u64 {
queue.write_buffer(&self.vertex_buffer, 0, vertices_raw);
self.staging_belt
.write_buffer(
encoder,
&self.vertex_buffer,
0,
NonZeroU64::new(vertices_raw.len() as u64).expect("Non-empty vertices"),
device,
)
.copy_from_slice(vertices_raw);
} else {
self.vertex_buffer.destroy();
@ -320,6 +333,9 @@ impl TextRenderer {
self.vertex_buffer = buffer;
self.vertex_buffer_size = buffer_size;
self.staging_belt.finish();
self.staging_belt = StagingBelt::new(buffer_size);
}
let indices = self.glyph_indices.as_slice();
@ -331,7 +347,15 @@ impl TextRenderer {
};
if self.index_buffer_size >= indices_raw.len() as u64 {
queue.write_buffer(&self.index_buffer, 0, indices_raw);
self.staging_belt
.write_buffer(
encoder,
&self.index_buffer,
0,
NonZeroU64::new(indices_raw.len() as u64).expect("Non-empty indices"),
device,
)
.copy_from_slice(indices_raw);
} else {
self.index_buffer.destroy();
@ -346,6 +370,8 @@ impl TextRenderer {
self.index_buffer_size = buffer_size;
}
self.staging_belt.finish();
Ok(())
}
@ -353,6 +379,7 @@ impl TextRenderer {
&mut self,
device: &Device,
queue: &Queue,
encoder: &mut CommandEncoder,
font_system: &mut FontSystem,
atlas: &mut TextAtlas,
viewport: &Viewport,
@ -362,6 +389,7 @@ impl TextRenderer {
self.prepare_with_depth(
device,
queue,
encoder,
font_system,
atlas,
viewport,