Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use a StagingBelt for regular buffer uploads #92

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions examples/hello-world.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use glyphon::{
Attrs, Buffer, Cache, Color, Family, FontSystem, Metrics, Resolution, Shaping, SwashCache,
TextArea, TextAtlas, TextBounds, TextRenderer, Viewport,
};
use std::sync::Arc;
use wgpu::{
CommandEncoderDescriptor, CompositeAlphaMode, DeviceDescriptor, Features, Instance,
InstanceDescriptor, Limits, LoadOp, MultisampleState, Operations, PresentMode,
Expand All @@ -15,8 +16,6 @@ use winit::{
window::WindowBuilder,
};

use std::sync::Arc;

fn main() {
pollster::block_on(run());
}
Expand Down Expand Up @@ -109,10 +108,14 @@ async fn run() {
},
);

let mut encoder = device
.create_command_encoder(&CommandEncoderDescriptor { label: None });

text_renderer
.prepare(
&device,
&queue,
&mut encoder,
&mut font_system,
&mut atlas,
&viewport,
Expand All @@ -135,8 +138,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,
Expand Down
28 changes: 23 additions & 5 deletions src/text_render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@ use crate::{
ColorMode, FontSystem, GlyphDetails, GlyphToRender, GpuCacheStatus, PrepareError, RenderError,
SwashCache, SwashContent, TextArea, TextAtlas, Viewport,
};
use std::{slice, sync::Arc};
use std::{num::NonZeroU64, slice, sync::Arc};
use wgpu::{
Buffer, BufferDescriptor, BufferUsages, DepthStencilState, Device, Extent3d, ImageCopyTexture,
ImageDataLayout, MultisampleState, Origin3d, Queue, RenderPass, RenderPipeline, TextureAspect,
COPY_BUFFER_ALIGNMENT,
util::StagingBelt, Buffer, BufferDescriptor, BufferUsages, CommandEncoder, DepthStencilState,
Device, Extent3d, ImageCopyTexture, ImageDataLayout, 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 {
vertex_buffer: Buffer,
vertex_buffer_size: u64,
staging_belt: StagingBelt,
pipeline: Arc<RenderPipeline>,
glyph_vertices: Vec<GlyphToRender>,
}
Expand All @@ -38,6 +39,7 @@ impl TextRenderer {
Self {
vertex_buffer,
vertex_buffer_size,
staging_belt: StagingBelt::new(vertex_buffer_size),
pipeline,
glyph_vertices: Vec::new(),
}
Expand All @@ -48,6 +50,7 @@ impl TextRenderer {
&mut self,
device: &Device,
queue: &Queue,
encoder: &mut CommandEncoder,
font_system: &mut FontSystem,
atlas: &mut TextAtlas,
viewport: &Viewport,
Expand All @@ -56,6 +59,7 @@ impl TextRenderer {
mut metadata_to_depth: impl FnMut(usize) -> f32,
) -> Result<(), PrepareError> {
self.glyph_vertices.clear();
self.staging_belt.recall();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically, for lowest memory usage recall should be called right after the user submits the Queue. But this approach removes the burden of a StagingBelt from the user and keeps it hidden.

Worst case scenario, we allocate some additional chunks. Overhead should be constant.


let resolution = viewport.resolution();

Expand Down Expand Up @@ -271,7 +275,16 @@ 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);
self.staging_belt.finish();
} else {
self.vertex_buffer.destroy();

Expand All @@ -284,6 +297,9 @@ impl TextRenderer {

self.vertex_buffer = buffer;
self.vertex_buffer_size = buffer_size;

self.staging_belt.finish();
self.staging_belt = StagingBelt::new(buffer_size);
Comment on lines +301 to +302
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I can see, we only need to worry about resizing the belt when the vertex buffer grows, since index buffer uploads will never be bigger than the vertex ones.

6 u32 indices (6 * 4 bytes) are generated per each 4 GlyphToRender vertices (4 * 18 bytes).

}

Ok(())
Expand All @@ -293,6 +309,7 @@ impl TextRenderer {
&mut self,
device: &Device,
queue: &Queue,
encoder: &mut CommandEncoder,
font_system: &mut FontSystem,
atlas: &mut TextAtlas,
viewport: &Viewport,
Expand All @@ -302,6 +319,7 @@ impl TextRenderer {
self.prepare_with_depth(
device,
queue,
encoder,
font_system,
atlas,
viewport,
Expand Down
Loading