Skip to content

Commit 5297680

Browse files
committed
Use a StagingBelt for regular buffer uploads
`Queue::write_buffer` allocates very regularly, specially on Metal. See: iced-rs/iced#2357 A `StagingBelt` gives us more control and predictability.
1 parent 3e281d1 commit 5297680

2 files changed

Lines changed: 38 additions & 8 deletions

File tree

examples/hello-world.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,14 @@ async fn run() {
9595
window.request_redraw();
9696
}
9797
WindowEvent::RedrawRequested => {
98+
let mut encoder = device
99+
.create_command_encoder(&CommandEncoderDescriptor { label: None });
100+
98101
text_renderer
99102
.prepare(
100103
&device,
101104
&queue,
105+
&mut encoder,
102106
&mut font_system,
103107
&mut atlas,
104108
Resolution {
@@ -124,8 +128,6 @@ async fn run() {
124128

125129
let frame = surface.get_current_texture().unwrap();
126130
let view = frame.texture.create_view(&TextureViewDescriptor::default());
127-
let mut encoder = device
128-
.create_command_encoder(&CommandEncoderDescriptor { label: None });
129131
{
130132
let mut pass = encoder.begin_render_pass(&RenderPassDescriptor {
131133
label: None,

src/text_render.rs

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,19 @@ use crate::{
22
ColorMode, FontSystem, GlyphDetails, GlyphToRender, GpuCacheStatus, Params, PrepareError,
33
RenderError, Resolution, SwashCache, SwashContent, TextArea, TextAtlas,
44
};
5-
use std::{iter, mem::size_of, slice, sync::Arc};
5+
use std::{iter, mem::size_of, num::NonZeroU64, slice, sync::Arc};
66
use wgpu::{
7-
BindGroupDescriptor, BindGroupEntry, Buffer, BufferDescriptor, BufferUsages, DepthStencilState,
8-
Device, Extent3d, ImageCopyTexture, ImageDataLayout, IndexFormat, MultisampleState, Origin3d,
9-
Queue, RenderPass, RenderPipeline, TextureAspect, COPY_BUFFER_ALIGNMENT,
7+
util::StagingBelt, BindGroupDescriptor, BindGroupEntry, Buffer, BufferDescriptor, BufferUsages,
8+
CommandEncoder, DepthStencilState, Device, Extent3d, ImageCopyTexture, ImageDataLayout,
9+
IndexFormat, MultisampleState, Origin3d, Queue, RenderPass, RenderPipeline, TextureAspect,
10+
COPY_BUFFER_ALIGNMENT,
1011
};
1112

1213
/// A text renderer that uses cached glyphs to render text into an existing render pass.
1314
pub struct TextRenderer {
1415
params: Params,
1516
params_buffer: Buffer,
17+
staging_belt: StagingBelt,
1618
vertex_buffer: Buffer,
1719
vertex_buffer_size: u64,
1820
index_buffer: Buffer,
@@ -77,6 +79,7 @@ impl TextRenderer {
7779
Self {
7880
params,
7981
params_buffer,
82+
staging_belt: StagingBelt::new(vertex_buffer_size),
8083
vertex_buffer,
8184
vertex_buffer_size,
8285
index_buffer,
@@ -94,6 +97,7 @@ impl TextRenderer {
9497
&mut self,
9598
device: &Device,
9699
queue: &Queue,
100+
encoder: &mut CommandEncoder,
97101
font_system: &mut FontSystem,
98102
atlas: &mut TextAtlas,
99103
screen_resolution: Resolution,
@@ -111,6 +115,7 @@ impl TextRenderer {
111115
});
112116
}
113117

118+
self.staging_belt.recall();
114119
self.glyph_vertices.clear();
115120
self.glyph_indices.clear();
116121
let mut glyphs_added = 0;
@@ -345,7 +350,15 @@ impl TextRenderer {
345350
};
346351

347352
if self.vertex_buffer_size >= vertices_raw.len() as u64 {
348-
queue.write_buffer(&self.vertex_buffer, 0, vertices_raw);
353+
self.staging_belt
354+
.write_buffer(
355+
encoder,
356+
&self.vertex_buffer,
357+
0,
358+
NonZeroU64::new(vertices_raw.len() as u64).expect("Non-empty vertices"),
359+
device,
360+
)
361+
.copy_from_slice(vertices_raw);
349362
} else {
350363
self.vertex_buffer.destroy();
351364

@@ -358,6 +371,9 @@ impl TextRenderer {
358371

359372
self.vertex_buffer = buffer;
360373
self.vertex_buffer_size = buffer_size;
374+
375+
self.staging_belt.finish();
376+
self.staging_belt = StagingBelt::new(buffer_size);
361377
}
362378

363379
let indices = self.glyph_indices.as_slice();
@@ -369,7 +385,15 @@ impl TextRenderer {
369385
};
370386

371387
if self.index_buffer_size >= indices_raw.len() as u64 {
372-
queue.write_buffer(&self.index_buffer, 0, indices_raw);
388+
self.staging_belt
389+
.write_buffer(
390+
encoder,
391+
&self.index_buffer,
392+
0,
393+
NonZeroU64::new(indices_raw.len() as u64).expect("Non-empty indices"),
394+
device,
395+
)
396+
.copy_from_slice(indices_raw);
373397
} else {
374398
self.index_buffer.destroy();
375399

@@ -384,13 +408,16 @@ impl TextRenderer {
384408
self.index_buffer_size = buffer_size;
385409
}
386410

411+
self.staging_belt.finish();
412+
387413
Ok(())
388414
}
389415

390416
pub fn prepare<'a>(
391417
&mut self,
392418
device: &Device,
393419
queue: &Queue,
420+
encoder: &mut CommandEncoder,
394421
font_system: &mut FontSystem,
395422
atlas: &mut TextAtlas,
396423
screen_resolution: Resolution,
@@ -400,6 +427,7 @@ impl TextRenderer {
400427
self.prepare_with_depth(
401428
device,
402429
queue,
430+
encoder,
403431
font_system,
404432
atlas,
405433
screen_resolution,

0 commit comments

Comments
 (0)