Simplify rendering pipeline, reduce gpu memory usage, remove duplicated data (#86)
This commit is contained in:
parent
b411ea71e7
commit
0fdbd90c55
3 changed files with 38 additions and 104 deletions
13
src/cache.rs
13
src/cache.rs
|
@ -5,9 +5,9 @@ use wgpu::{
|
|||
BindingResource, BindingType, BlendState, Buffer, BufferBindingType, ColorTargetState,
|
||||
ColorWrites, DepthStencilState, Device, FilterMode, FragmentState, MultisampleState,
|
||||
PipelineCompilationOptions, PipelineLayout, PipelineLayoutDescriptor, PrimitiveState,
|
||||
RenderPipeline, RenderPipelineDescriptor, Sampler, SamplerBindingType, SamplerDescriptor,
|
||||
ShaderModule, ShaderModuleDescriptor, ShaderSource, ShaderStages, TextureFormat,
|
||||
TextureSampleType, TextureView, TextureViewDimension, VertexFormat, VertexState,
|
||||
PrimitiveTopology, RenderPipeline, RenderPipelineDescriptor, Sampler, SamplerBindingType,
|
||||
SamplerDescriptor, ShaderModule, ShaderModuleDescriptor, ShaderSource, ShaderStages,
|
||||
TextureFormat, TextureSampleType, TextureView, TextureViewDimension, VertexFormat, VertexState,
|
||||
};
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
@ -56,7 +56,7 @@ impl Cache {
|
|||
|
||||
let vertex_buffer_layout = wgpu::VertexBufferLayout {
|
||||
array_stride: mem::size_of::<GlyphToRender>() as wgpu::BufferAddress,
|
||||
step_mode: wgpu::VertexStepMode::Vertex,
|
||||
step_mode: wgpu::VertexStepMode::Instance,
|
||||
attributes: &[
|
||||
wgpu::VertexAttribute {
|
||||
format: VertexFormat::Sint32x2,
|
||||
|
@ -232,7 +232,10 @@ impl Cache {
|
|||
})],
|
||||
compilation_options: PipelineCompilationOptions::default(),
|
||||
}),
|
||||
primitive: PrimitiveState::default(),
|
||||
primitive: PrimitiveState {
|
||||
topology: PrimitiveTopology::TriangleStrip,
|
||||
..Default::default()
|
||||
},
|
||||
depth_stencil: depth_stencil.clone(),
|
||||
multisample,
|
||||
multiview: None,
|
||||
|
|
|
@ -47,25 +47,17 @@ fn vs_main(in_vert: VertexInput) -> VertexOutput {
|
|||
let height = (in_vert.dim & 0xffff0000u) >> 16u;
|
||||
let color = in_vert.color;
|
||||
var uv = vec2<u32>(in_vert.uv & 0xffffu, (in_vert.uv & 0xffff0000u) >> 16u);
|
||||
let v = in_vert.vertex_idx % 4u;
|
||||
let v = in_vert.vertex_idx;
|
||||
|
||||
switch v {
|
||||
case 1u: {
|
||||
pos.x += i32(width);
|
||||
uv.x += width;
|
||||
}
|
||||
case 2u: {
|
||||
pos.x += i32(width);
|
||||
pos.y += i32(height);
|
||||
uv.x += width;
|
||||
uv.y += height;
|
||||
}
|
||||
case 3u: {
|
||||
pos.y += i32(height);
|
||||
uv.y += height;
|
||||
}
|
||||
default: {}
|
||||
}
|
||||
let corner_position = vec2<u32>(
|
||||
in_vert.vertex_idx & 1u,
|
||||
(in_vert.vertex_idx >> 1u) & 1u,
|
||||
);
|
||||
|
||||
let corner_offset = vec2<u32>(width, height) * corner_position;
|
||||
|
||||
uv = uv + corner_offset;
|
||||
pos = pos + vec2<i32>(corner_offset);
|
||||
|
||||
var vert_output: VertexOutput;
|
||||
|
||||
|
|
|
@ -2,23 +2,19 @@ use crate::{
|
|||
ColorMode, FontSystem, GlyphDetails, GlyphToRender, GpuCacheStatus, PrepareError, RenderError,
|
||||
SwashCache, SwashContent, TextArea, TextAtlas, Viewport,
|
||||
};
|
||||
use std::{iter, slice, sync::Arc};
|
||||
use std::{slice, sync::Arc};
|
||||
use wgpu::{
|
||||
Buffer, BufferDescriptor, BufferUsages, DepthStencilState, Device, Extent3d, ImageCopyTexture,
|
||||
ImageDataLayout, IndexFormat, MultisampleState, Origin3d, Queue, RenderPass, RenderPipeline,
|
||||
TextureAspect, COPY_BUFFER_ALIGNMENT,
|
||||
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,
|
||||
index_buffer: Buffer,
|
||||
index_buffer_size: u64,
|
||||
vertices_to_render: u32,
|
||||
pipeline: Arc<RenderPipeline>,
|
||||
glyph_vertices: Vec<GlyphToRender>,
|
||||
glyph_indices: Vec<u32>,
|
||||
}
|
||||
|
||||
impl TextRenderer {
|
||||
|
@ -37,25 +33,13 @@ impl TextRenderer {
|
|||
mapped_at_creation: false,
|
||||
});
|
||||
|
||||
let index_buffer_size = next_copy_buffer_size(4096);
|
||||
let index_buffer = device.create_buffer(&BufferDescriptor {
|
||||
label: Some("glyphon indices"),
|
||||
size: index_buffer_size,
|
||||
usage: BufferUsages::INDEX | BufferUsages::COPY_DST,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
|
||||
let pipeline = atlas.get_or_create_pipeline(device, multisample, depth_stencil);
|
||||
|
||||
Self {
|
||||
vertex_buffer,
|
||||
vertex_buffer_size,
|
||||
index_buffer,
|
||||
index_buffer_size,
|
||||
vertices_to_render: 0,
|
||||
pipeline,
|
||||
glyph_vertices: Vec::new(),
|
||||
glyph_indices: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,8 +56,6 @@ impl TextRenderer {
|
|||
mut metadata_to_depth: impl FnMut(usize) -> f32,
|
||||
) -> Result<(), PrepareError> {
|
||||
self.glyph_vertices.clear();
|
||||
self.glyph_indices.clear();
|
||||
let mut glyphs_added = 0;
|
||||
|
||||
let resolution = viewport.resolution();
|
||||
|
||||
|
@ -257,8 +239,7 @@ impl TextRenderer {
|
|||
|
||||
let depth = metadata_to_depth(glyph.metadata);
|
||||
|
||||
self.glyph_vertices.extend(
|
||||
iter::repeat(GlyphToRender {
|
||||
self.glyph_vertices.push(GlyphToRender {
|
||||
pos: [x, y],
|
||||
dim: [width as u16, height as u16],
|
||||
uv: [atlas_x, atlas_y],
|
||||
|
@ -271,29 +252,12 @@ impl TextRenderer {
|
|||
} as u16,
|
||||
],
|
||||
depth,
|
||||
})
|
||||
.take(4),
|
||||
);
|
||||
|
||||
let start = 4 * glyphs_added as u32;
|
||||
self.glyph_indices.extend([
|
||||
start,
|
||||
start + 1,
|
||||
start + 2,
|
||||
start,
|
||||
start + 2,
|
||||
start + 3,
|
||||
]);
|
||||
|
||||
glyphs_added += 1;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const VERTICES_PER_GLYPH: u32 = 6;
|
||||
self.vertices_to_render = glyphs_added as u32 * VERTICES_PER_GLYPH;
|
||||
|
||||
let will_render = glyphs_added > 0;
|
||||
let will_render = !self.glyph_vertices.is_empty();
|
||||
if !will_render {
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -322,30 +286,6 @@ impl TextRenderer {
|
|||
self.vertex_buffer_size = buffer_size;
|
||||
}
|
||||
|
||||
let indices = self.glyph_indices.as_slice();
|
||||
let indices_raw = unsafe {
|
||||
slice::from_raw_parts(
|
||||
indices as *const _ as *const u8,
|
||||
std::mem::size_of_val(indices),
|
||||
)
|
||||
};
|
||||
|
||||
if self.index_buffer_size >= indices_raw.len() as u64 {
|
||||
queue.write_buffer(&self.index_buffer, 0, indices_raw);
|
||||
} else {
|
||||
self.index_buffer.destroy();
|
||||
|
||||
let (buffer, buffer_size) = create_oversized_buffer(
|
||||
device,
|
||||
Some("glyphon indices"),
|
||||
indices_raw,
|
||||
BufferUsages::INDEX | BufferUsages::COPY_DST,
|
||||
);
|
||||
|
||||
self.index_buffer = buffer;
|
||||
self.index_buffer_size = buffer_size;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -378,7 +318,7 @@ impl TextRenderer {
|
|||
viewport: &'pass Viewport,
|
||||
pass: &mut RenderPass<'pass>,
|
||||
) -> Result<(), RenderError> {
|
||||
if self.vertices_to_render == 0 {
|
||||
if self.glyph_vertices.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
@ -386,8 +326,7 @@ impl TextRenderer {
|
|||
pass.set_bind_group(0, &atlas.bind_group, &[]);
|
||||
pass.set_bind_group(1, &viewport.bind_group, &[]);
|
||||
pass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
|
||||
pass.set_index_buffer(self.index_buffer.slice(..), IndexFormat::Uint32);
|
||||
pass.draw_indexed(0..self.vertices_to_render, 0, 0..1);
|
||||
pass.draw(0..4, 0..self.glyph_vertices.len() as u32);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue