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

View file

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