Introduce explicit Viewport
sharing (#96)
This commit is contained in:
parent
5aed9e1477
commit
b411ea71e7
5 changed files with 84 additions and 53 deletions
|
@ -1,6 +1,6 @@
|
||||||
use glyphon::{
|
use glyphon::{
|
||||||
Attrs, Buffer, Cache, Color, Family, FontSystem, Metrics, Resolution, Shaping, SwashCache,
|
Attrs, Buffer, Cache, Color, Family, FontSystem, Metrics, Resolution, Shaping, SwashCache,
|
||||||
TextArea, TextAtlas, TextBounds, TextRenderer,
|
TextArea, TextAtlas, TextBounds, TextRenderer, Viewport,
|
||||||
};
|
};
|
||||||
use wgpu::{
|
use wgpu::{
|
||||||
CommandEncoderDescriptor, CompositeAlphaMode, DeviceDescriptor, Features, Instance,
|
CommandEncoderDescriptor, CompositeAlphaMode, DeviceDescriptor, Features, Instance,
|
||||||
|
@ -73,6 +73,7 @@ async fn run() {
|
||||||
let mut font_system = FontSystem::new();
|
let mut font_system = FontSystem::new();
|
||||||
let mut swash_cache = SwashCache::new();
|
let mut swash_cache = SwashCache::new();
|
||||||
let cache = Cache::new(&device);
|
let cache = Cache::new(&device);
|
||||||
|
let mut viewport = Viewport::new(&device, &cache);
|
||||||
let mut atlas = TextAtlas::new(&device, &queue, &cache, swapchain_format);
|
let mut atlas = TextAtlas::new(&device, &queue, &cache, swapchain_format);
|
||||||
let mut text_renderer =
|
let mut text_renderer =
|
||||||
TextRenderer::new(&mut atlas, &device, MultisampleState::default(), None);
|
TextRenderer::new(&mut atlas, &device, MultisampleState::default(), None);
|
||||||
|
@ -100,16 +101,21 @@ async fn run() {
|
||||||
window.request_redraw();
|
window.request_redraw();
|
||||||
}
|
}
|
||||||
WindowEvent::RedrawRequested => {
|
WindowEvent::RedrawRequested => {
|
||||||
|
viewport.update(
|
||||||
|
&queue,
|
||||||
|
Resolution {
|
||||||
|
width: config.width,
|
||||||
|
height: config.height,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
text_renderer
|
text_renderer
|
||||||
.prepare(
|
.prepare(
|
||||||
&device,
|
&device,
|
||||||
&queue,
|
&queue,
|
||||||
&mut font_system,
|
&mut font_system,
|
||||||
&mut atlas,
|
&mut atlas,
|
||||||
Resolution {
|
&viewport,
|
||||||
width: config.width,
|
|
||||||
height: config.height,
|
|
||||||
},
|
|
||||||
[TextArea {
|
[TextArea {
|
||||||
buffer: &buffer,
|
buffer: &buffer,
|
||||||
left: 10.0,
|
left: 10.0,
|
||||||
|
@ -147,7 +153,7 @@ async fn run() {
|
||||||
occlusion_query_set: None,
|
occlusion_query_set: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
text_renderer.render(&atlas, &mut pass).unwrap();
|
text_renderer.render(&atlas, &viewport, &mut pass).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
queue.submit(Some(encoder.finish()));
|
queue.submit(Some(encoder.finish()));
|
||||||
|
|
|
@ -8,11 +8,13 @@ mod cache;
|
||||||
mod error;
|
mod error;
|
||||||
mod text_atlas;
|
mod text_atlas;
|
||||||
mod text_render;
|
mod text_render;
|
||||||
|
mod viewport;
|
||||||
|
|
||||||
pub use cache::Cache;
|
pub use cache::Cache;
|
||||||
pub use error::{PrepareError, RenderError};
|
pub use error::{PrepareError, RenderError};
|
||||||
pub use text_atlas::{ColorMode, TextAtlas};
|
pub use text_atlas::{ColorMode, TextAtlas};
|
||||||
pub use text_render::TextRenderer;
|
pub use text_render::TextRenderer;
|
||||||
|
pub use viewport::Viewport;
|
||||||
|
|
||||||
use text_render::ContentType;
|
use text_render::ContentType;
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ use lru::LruCache;
|
||||||
use rustc_hash::FxHasher;
|
use rustc_hash::FxHasher;
|
||||||
use std::{collections::HashSet, hash::BuildHasherDefault, sync::Arc};
|
use std::{collections::HashSet, hash::BuildHasherDefault, sync::Arc};
|
||||||
use wgpu::{
|
use wgpu::{
|
||||||
BindGroup, Buffer, DepthStencilState, Device, Extent3d, ImageCopyTexture, ImageDataLayout,
|
BindGroup, DepthStencilState, Device, Extent3d, ImageCopyTexture, ImageDataLayout,
|
||||||
MultisampleState, Origin3d, Queue, RenderPipeline, Texture, TextureAspect, TextureDescriptor,
|
MultisampleState, Origin3d, Queue, RenderPipeline, Texture, TextureAspect, TextureDescriptor,
|
||||||
TextureDimension, TextureFormat, TextureUsages, TextureView, TextureViewDescriptor,
|
TextureDimension, TextureFormat, TextureUsages, TextureView, TextureViewDescriptor,
|
||||||
};
|
};
|
||||||
|
@ -350,10 +350,6 @@ impl TextAtlas {
|
||||||
.get_or_create_pipeline(device, self.format, multisample, depth_stencil)
|
.get_or_create_pipeline(device, self.format, multisample, depth_stencil)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn create_uniforms_bind_group(&self, device: &Device, buffer: &Buffer) -> BindGroup {
|
|
||||||
self.cache.create_uniforms_bind_group(device, buffer)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn rebind(&mut self, device: &wgpu::Device) {
|
fn rebind(&mut self, device: &wgpu::Device) {
|
||||||
self.bind_group = self.cache.create_atlas_bind_group(
|
self.bind_group = self.cache.create_atlas_bind_group(
|
||||||
device,
|
device,
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
ColorMode, FontSystem, GlyphDetails, GlyphToRender, GpuCacheStatus, Params, PrepareError,
|
ColorMode, FontSystem, GlyphDetails, GlyphToRender, GpuCacheStatus, PrepareError, RenderError,
|
||||||
RenderError, Resolution, SwashCache, SwashContent, TextArea, TextAtlas,
|
SwashCache, SwashContent, TextArea, TextAtlas, Viewport,
|
||||||
};
|
};
|
||||||
use std::{iter, mem::size_of, slice, sync::Arc};
|
use std::{iter, slice, sync::Arc};
|
||||||
use wgpu::{
|
use wgpu::{
|
||||||
Buffer, BufferDescriptor, BufferUsages, DepthStencilState, Device, Extent3d, ImageCopyTexture,
|
Buffer, BufferDescriptor, BufferUsages, DepthStencilState, Device, Extent3d, ImageCopyTexture,
|
||||||
ImageDataLayout, IndexFormat, MultisampleState, Origin3d, Queue, RenderPass, RenderPipeline,
|
ImageDataLayout, IndexFormat, MultisampleState, Origin3d, Queue, RenderPass, RenderPipeline,
|
||||||
|
@ -11,15 +11,12 @@ use wgpu::{
|
||||||
|
|
||||||
/// 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 {
|
||||||
params: Params,
|
|
||||||
params_buffer: Buffer,
|
|
||||||
vertex_buffer: Buffer,
|
vertex_buffer: Buffer,
|
||||||
vertex_buffer_size: u64,
|
vertex_buffer_size: u64,
|
||||||
index_buffer: Buffer,
|
index_buffer: Buffer,
|
||||||
index_buffer_size: u64,
|
index_buffer_size: u64,
|
||||||
vertices_to_render: u32,
|
vertices_to_render: u32,
|
||||||
pipeline: Arc<RenderPipeline>,
|
pipeline: Arc<RenderPipeline>,
|
||||||
bind_group: wgpu::BindGroup,
|
|
||||||
glyph_vertices: Vec<GlyphToRender>,
|
glyph_vertices: Vec<GlyphToRender>,
|
||||||
glyph_indices: Vec<u32>,
|
glyph_indices: Vec<u32>,
|
||||||
}
|
}
|
||||||
|
@ -48,34 +45,15 @@ impl TextRenderer {
|
||||||
mapped_at_creation: false,
|
mapped_at_creation: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
let params = Params {
|
|
||||||
screen_resolution: Resolution {
|
|
||||||
width: 0,
|
|
||||||
height: 0,
|
|
||||||
},
|
|
||||||
_pad: [0, 0],
|
|
||||||
};
|
|
||||||
|
|
||||||
let params_buffer = device.create_buffer(&BufferDescriptor {
|
|
||||||
label: Some("glyphon params"),
|
|
||||||
size: size_of::<Params>() as u64,
|
|
||||||
usage: BufferUsages::UNIFORM | BufferUsages::COPY_DST,
|
|
||||||
mapped_at_creation: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
let pipeline = atlas.get_or_create_pipeline(device, multisample, depth_stencil);
|
let pipeline = atlas.get_or_create_pipeline(device, multisample, depth_stencil);
|
||||||
let bind_group = atlas.create_uniforms_bind_group(device, ¶ms_buffer);
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
params,
|
|
||||||
params_buffer,
|
|
||||||
vertex_buffer,
|
vertex_buffer,
|
||||||
vertex_buffer_size,
|
vertex_buffer_size,
|
||||||
index_buffer,
|
index_buffer,
|
||||||
index_buffer_size,
|
index_buffer_size,
|
||||||
vertices_to_render: 0,
|
vertices_to_render: 0,
|
||||||
pipeline,
|
pipeline,
|
||||||
bind_group,
|
|
||||||
glyph_vertices: Vec::new(),
|
glyph_vertices: Vec::new(),
|
||||||
glyph_indices: Vec::new(),
|
glyph_indices: Vec::new(),
|
||||||
}
|
}
|
||||||
|
@ -88,26 +66,17 @@ impl TextRenderer {
|
||||||
queue: &Queue,
|
queue: &Queue,
|
||||||
font_system: &mut FontSystem,
|
font_system: &mut FontSystem,
|
||||||
atlas: &mut TextAtlas,
|
atlas: &mut TextAtlas,
|
||||||
screen_resolution: Resolution,
|
viewport: &Viewport,
|
||||||
text_areas: impl IntoIterator<Item = TextArea<'a>>,
|
text_areas: impl IntoIterator<Item = TextArea<'a>>,
|
||||||
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> {
|
||||||
if self.params.screen_resolution != screen_resolution {
|
|
||||||
self.params.screen_resolution = screen_resolution;
|
|
||||||
|
|
||||||
queue.write_buffer(&self.params_buffer, 0, unsafe {
|
|
||||||
slice::from_raw_parts(
|
|
||||||
&self.params as *const Params as *const u8,
|
|
||||||
size_of::<Params>(),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
||||||
|
|
||||||
for text_area in text_areas {
|
for text_area in text_areas {
|
||||||
for run in text_area.buffer.layout_runs() {
|
for run in text_area.buffer.layout_runs() {
|
||||||
for glyph in run.glyphs.iter() {
|
for glyph in run.glyphs.iter() {
|
||||||
|
@ -238,8 +207,8 @@ impl TextRenderer {
|
||||||
|
|
||||||
let bounds_min_x = text_area.bounds.left.max(0);
|
let bounds_min_x = text_area.bounds.left.max(0);
|
||||||
let bounds_min_y = text_area.bounds.top.max(0);
|
let bounds_min_y = text_area.bounds.top.max(0);
|
||||||
let bounds_max_x = text_area.bounds.right.min(screen_resolution.width as i32);
|
let bounds_max_x = text_area.bounds.right.min(resolution.width as i32);
|
||||||
let bounds_max_y = text_area.bounds.bottom.min(screen_resolution.height as i32);
|
let bounds_max_y = text_area.bounds.bottom.min(resolution.height as i32);
|
||||||
|
|
||||||
// Starts beyond right edge or ends beyond left edge
|
// Starts beyond right edge or ends beyond left edge
|
||||||
let max_x = x + width;
|
let max_x = x + width;
|
||||||
|
@ -386,7 +355,7 @@ impl TextRenderer {
|
||||||
queue: &Queue,
|
queue: &Queue,
|
||||||
font_system: &mut FontSystem,
|
font_system: &mut FontSystem,
|
||||||
atlas: &mut TextAtlas,
|
atlas: &mut TextAtlas,
|
||||||
screen_resolution: Resolution,
|
viewport: &Viewport,
|
||||||
text_areas: impl IntoIterator<Item = TextArea<'a>>,
|
text_areas: impl IntoIterator<Item = TextArea<'a>>,
|
||||||
cache: &mut SwashCache,
|
cache: &mut SwashCache,
|
||||||
) -> Result<(), PrepareError> {
|
) -> Result<(), PrepareError> {
|
||||||
|
@ -395,7 +364,7 @@ impl TextRenderer {
|
||||||
queue,
|
queue,
|
||||||
font_system,
|
font_system,
|
||||||
atlas,
|
atlas,
|
||||||
screen_resolution,
|
viewport,
|
||||||
text_areas,
|
text_areas,
|
||||||
cache,
|
cache,
|
||||||
zero_depth,
|
zero_depth,
|
||||||
|
@ -406,6 +375,7 @@ impl TextRenderer {
|
||||||
pub fn render<'pass>(
|
pub fn render<'pass>(
|
||||||
&'pass self,
|
&'pass self,
|
||||||
atlas: &'pass TextAtlas,
|
atlas: &'pass TextAtlas,
|
||||||
|
viewport: &'pass Viewport,
|
||||||
pass: &mut RenderPass<'pass>,
|
pass: &mut RenderPass<'pass>,
|
||||||
) -> Result<(), RenderError> {
|
) -> Result<(), RenderError> {
|
||||||
if self.vertices_to_render == 0 {
|
if self.vertices_to_render == 0 {
|
||||||
|
@ -414,7 +384,7 @@ impl TextRenderer {
|
||||||
|
|
||||||
pass.set_pipeline(&self.pipeline);
|
pass.set_pipeline(&self.pipeline);
|
||||||
pass.set_bind_group(0, &atlas.bind_group, &[]);
|
pass.set_bind_group(0, &atlas.bind_group, &[]);
|
||||||
pass.set_bind_group(1, &self.bind_group, &[]);
|
pass.set_bind_group(1, &viewport.bind_group, &[]);
|
||||||
pass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
|
pass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
|
||||||
pass.set_index_buffer(self.index_buffer.slice(..), IndexFormat::Uint32);
|
pass.set_index_buffer(self.index_buffer.slice(..), IndexFormat::Uint32);
|
||||||
pass.draw_indexed(0..self.vertices_to_render, 0, 0..1);
|
pass.draw_indexed(0..self.vertices_to_render, 0, 0..1);
|
||||||
|
|
57
src/viewport.rs
Normal file
57
src/viewport.rs
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
use crate::{Cache, Params, Resolution};
|
||||||
|
|
||||||
|
use wgpu::{BindGroup, Buffer, BufferDescriptor, BufferUsages, Device, Queue};
|
||||||
|
|
||||||
|
use std::mem;
|
||||||
|
use std::slice;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Viewport {
|
||||||
|
params: Params,
|
||||||
|
params_buffer: Buffer,
|
||||||
|
pub(crate) bind_group: BindGroup,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Viewport {
|
||||||
|
pub fn new(device: &Device, cache: &Cache) -> Self {
|
||||||
|
let params = Params {
|
||||||
|
screen_resolution: Resolution {
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
},
|
||||||
|
_pad: [0, 0],
|
||||||
|
};
|
||||||
|
|
||||||
|
let params_buffer = device.create_buffer(&BufferDescriptor {
|
||||||
|
label: Some("glyphon params"),
|
||||||
|
size: mem::size_of::<Params>() as u64,
|
||||||
|
usage: BufferUsages::UNIFORM | BufferUsages::COPY_DST,
|
||||||
|
mapped_at_creation: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
let bind_group = cache.create_uniforms_bind_group(device, ¶ms_buffer);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
params,
|
||||||
|
params_buffer,
|
||||||
|
bind_group,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(&mut self, queue: &Queue, resolution: Resolution) {
|
||||||
|
if self.params.screen_resolution != resolution {
|
||||||
|
self.params.screen_resolution = resolution;
|
||||||
|
|
||||||
|
queue.write_buffer(&self.params_buffer, 0, unsafe {
|
||||||
|
slice::from_raw_parts(
|
||||||
|
&self.params as *const Params as *const u8,
|
||||||
|
mem::size_of::<Params>(),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resolution(&self) -> Resolution {
|
||||||
|
self.params.screen_resolution
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue