Cleanup before release

This commit is contained in:
grovesNL 2024-09-16 23:25:27 -06:00 committed by Josh Groves
parent 2daf883cad
commit 692e23ca33
8 changed files with 96 additions and 84 deletions

View file

@ -1,7 +1,7 @@
use glyphon::{ use glyphon::{
Attrs, Buffer, Cache, Color, ContentType, CustomGlyph, RasterizationRequest, RasterizedCustomGlyph, Attrs, Buffer, Cache, Color, ContentType, CustomGlyph, Family, FontSystem, Metrics,
Family, FontSystem, Metrics, Resolution, Shaping, SwashCache, TextArea, TextAtlas, TextBounds, RasterizeCustomGlyphRequest, RasterizedCustomGlyph, Resolution, Shaping, SwashCache, TextArea,
TextRenderer, Viewport, TextAtlas, TextBounds, TextRenderer, Viewport,
}; };
use std::sync::Arc; use std::sync::Arc;
use wgpu::{ use wgpu::{
@ -28,16 +28,13 @@ struct WindowState {
queue: wgpu::Queue, queue: wgpu::Queue,
surface: wgpu::Surface<'static>, surface: wgpu::Surface<'static>,
surface_config: SurfaceConfiguration, surface_config: SurfaceConfiguration,
font_system: FontSystem, font_system: FontSystem,
swash_cache: SwashCache, swash_cache: SwashCache,
viewport: glyphon::Viewport, viewport: glyphon::Viewport,
atlas: glyphon::TextAtlas, atlas: glyphon::TextAtlas,
text_renderer: glyphon::TextRenderer, text_renderer: glyphon::TextRenderer,
text_buffer: glyphon::Buffer, text_buffer: glyphon::Buffer,
rasterize_svg: Box<dyn Fn(RasterizeCustomGlyphRequest) -> Option<RasterizedCustomGlyph>>,
rasterize_svg: Box<dyn Fn(RasterizationRequest) -> Option<RasterizedCustomGlyph>>,
// Make sure that the winit window is last in the struct so that // Make sure that the winit window is last in the struct so that
// it is dropped after the wgpu surface is dropped, otherwise the // it is dropped after the wgpu surface is dropped, otherwise the
// program may crash when closed. This is probably a bug in wgpu. // program may crash when closed. This is probably a bug in wgpu.
@ -106,7 +103,8 @@ impl WindowState {
let svg_0 = resvg::usvg::Tree::from_data(LION_SVG, &Default::default()).unwrap(); let svg_0 = resvg::usvg::Tree::from_data(LION_SVG, &Default::default()).unwrap();
let svg_1 = resvg::usvg::Tree::from_data(EAGLE_SVG, &Default::default()).unwrap(); let svg_1 = resvg::usvg::Tree::from_data(EAGLE_SVG, &Default::default()).unwrap();
let rasterize_svg = move |input: RasterizationRequest| -> Option<RasterizedCustomGlyph> { let rasterize_svg =
move |input: RasterizeCustomGlyphRequest| -> Option<RasterizedCustomGlyph> {
// Select the svg data based on the custom glyph ID. // Select the svg data based on the custom glyph ID.
let (svg, content_type) = match input.id { let (svg, content_type) = match input.id {
0 => (&svg_0, ContentType::Mask), 0 => (&svg_0, ContentType::Mask),

View file

@ -244,6 +244,7 @@ impl winit::application::ApplicationHandler for Application {
bottom: top.floor() as i32 + physical_size.height, bottom: top.floor() as i32 + physical_size.height,
}, },
default_color: FONT_COLOR, default_color: FONT_COLOR,
custom_glyphs: &[],
}; };
let total_lines = b let total_lines = b

View file

@ -1,5 +1,11 @@
use crate::{GlyphToRender, Params}; use crate::{GlyphToRender, Params};
use std::{
borrow::Cow,
mem,
num::NonZeroU64,
ops::Deref,
sync::{Arc, RwLock},
};
use wgpu::{ use wgpu::{
BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayout, BindGroupLayoutEntry, BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayout, BindGroupLayoutEntry,
BindingResource, BindingType, BlendState, Buffer, BufferBindingType, ColorTargetState, BindingResource, BindingType, BlendState, Buffer, BufferBindingType, ColorTargetState,
@ -10,12 +16,8 @@ use wgpu::{
TextureFormat, TextureSampleType, TextureView, TextureViewDimension, VertexFormat, VertexState, TextureFormat, TextureSampleType, TextureView, TextureViewDimension, VertexFormat, VertexState,
}; };
use std::borrow::Cow; /// A cache to share common resources (e.g., pipelines, layouts, shaders) between multiple text
use std::mem; /// renderers.
use std::num::NonZeroU64;
use std::ops::Deref;
use std::sync::{Arc, RwLock};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Cache(Arc<Inner>); pub struct Cache(Arc<Inner>);
@ -38,6 +40,7 @@ struct Inner {
} }
impl Cache { impl Cache {
/// Creates a new `Cache` with the given `device`.
pub fn new(device: &Device) -> Self { pub fn new(device: &Device) -> Self {
let sampler = device.create_sampler(&SamplerDescriptor { let sampler = device.create_sampler(&SamplerDescriptor {
label: Some("glyphon sampler"), label: Some("glyphon sampler"),

View file

@ -19,7 +19,7 @@ pub struct CustomGlyph {
/// The color of this glyph (only relevant if the glyph is rendered with the /// The color of this glyph (only relevant if the glyph is rendered with the
/// type [`ContentType::Mask`]) /// type [`ContentType::Mask`])
/// ///
/// Set to `None` to use [`TextArea::default_color`]. /// Set to `None` to use [`crate::TextArea::default_color`].
pub color: Option<Color>, pub color: Option<Color>,
/// If `true`, then this glyph will be snapped to the nearest whole physical /// If `true`, then this glyph will be snapped to the nearest whole physical
/// pixel and the resulting `SubpixelBin`'s in `RasterizationRequest` will always /// pixel and the resulting `SubpixelBin`'s in `RasterizationRequest` will always
@ -31,7 +31,7 @@ pub struct CustomGlyph {
/// A request to rasterize a custom glyph /// A request to rasterize a custom glyph
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub struct RasterizationRequest { pub struct RasterizeCustomGlyphRequest {
/// The unique identifier of the glyph /// The unique identifier of the glyph
pub id: CustomGlyphId, pub id: CustomGlyphId,
/// The width of the glyph in physical pixels /// The width of the glyph in physical pixels
@ -63,7 +63,11 @@ pub struct RasterizedCustomGlyph {
} }
impl RasterizedCustomGlyph { impl RasterizedCustomGlyph {
pub(crate) fn validate(&self, input: &RasterizationRequest, expected_type: Option<ContentType>) { pub(crate) fn validate(
&self,
input: &RasterizeCustomGlyphRequest,
expected_type: Option<ContentType>,
) {
if let Some(expected_type) = expected_type { if let Some(expected_type) = expected_type {
assert_eq!(self.content_type, expected_type, "Custom glyph rasterizer must always produce the same content type for a given input. Expected {:?}, got {:?}. Input: {:?}", expected_type, self.content_type, input); assert_eq!(self.content_type, expected_type, "Custom glyph rasterizer must always produce the same content type for a given input. Expected {:?}, got {:?}. Input: {:?}", expected_type, self.content_type, input);
} }

View file

@ -13,7 +13,7 @@ mod viewport;
pub use cache::Cache; pub use cache::Cache;
pub use custom_glyph::{ pub use custom_glyph::{
ContentType, CustomGlyph, CustomGlyphId, RasterizationRequest, RasterizedCustomGlyph, ContentType, CustomGlyph, CustomGlyphId, RasterizeCustomGlyphRequest, RasterizedCustomGlyph,
}; };
pub use error::{PrepareError, RenderError}; pub use error::{PrepareError, RenderError};
pub use text_atlas::{ColorMode, TextAtlas}; pub use text_atlas::{ColorMode, TextAtlas};
@ -117,9 +117,8 @@ pub struct TextArea<'a> {
/// The visible bounds of the text area. This is used to clip the text and doesn't have to /// The visible bounds of the text area. This is used to clip the text and doesn't have to
/// match the `left` and `top` values. /// match the `left` and `top` values.
pub bounds: TextBounds, pub bounds: TextBounds,
// The default color of the text area. /// The default color of the text area.
pub default_color: Color, pub default_color: Color,
/// Additional custom glyphs to render.
/// Additional custom glyphs to render
pub custom_glyphs: &'a [CustomGlyph], pub custom_glyphs: &'a [CustomGlyph],
} }

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
text_render::GlyphonCacheKey, Cache, ContentType, RasterizationRequest, RasterizedCustomGlyph, text_render::GlyphonCacheKey, Cache, ContentType, RasterizeCustomGlyphRequest, FontSystem,
FontSystem, GlyphDetails, GpuCacheStatus, SwashCache, GlyphDetails, GpuCacheStatus, RasterizedCustomGlyph, SwashCache,
}; };
use etagere::{size2, Allocation, BucketedAtlasAllocator}; use etagere::{size2, Allocation, BucketedAtlasAllocator};
use lru::LruCache; use lru::LruCache;
@ -124,7 +124,9 @@ impl InnerAtlas {
font_system: &mut FontSystem, font_system: &mut FontSystem,
cache: &mut SwashCache, cache: &mut SwashCache,
scale_factor: f32, scale_factor: f32,
mut rasterize_custom_glyph: impl FnMut(RasterizationRequest) -> Option<RasterizedCustomGlyph>, mut rasterize_custom_glyph: impl FnMut(
RasterizeCustomGlyphRequest,
) -> Option<RasterizedCustomGlyph>,
) -> bool { ) -> bool {
if self.size >= self.max_texture_dimension_2d { if self.size >= self.max_texture_dimension_2d {
return false; return false;
@ -169,7 +171,7 @@ impl InnerAtlas {
(image.data, width, height) (image.data, width, height)
} }
GlyphonCacheKey::Custom(cache_key) => { GlyphonCacheKey::Custom(cache_key) => {
let input = RasterizationRequest { let input = RasterizeCustomGlyphRequest {
id: cache_key.glyph_id, id: cache_key.glyph_id,
width: cache_key.width, width: cache_key.width,
height: cache_key.height, height: cache_key.height,
@ -264,7 +266,7 @@ impl Kind {
} }
} }
/// The color mode of an [`Atlas`]. /// The color mode of a [`TextAtlas`].
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ColorMode { pub enum ColorMode {
/// Accurate color management. /// Accurate color management.
@ -352,7 +354,9 @@ impl TextAtlas {
cache: &mut SwashCache, cache: &mut SwashCache,
content_type: ContentType, content_type: ContentType,
scale_factor: f32, scale_factor: f32,
rasterize_custom_glyph: impl FnMut(RasterizationRequest) -> Option<RasterizedCustomGlyph>, rasterize_custom_glyph: impl FnMut(
RasterizeCustomGlyphRequest,
) -> Option<RasterizedCustomGlyph>,
) -> bool { ) -> bool {
let did_grow = match content_type { let did_grow = match content_type {
ContentType::Mask => self.mask_atlas.grow( ContentType::Mask => self.mask_atlas.grow(

View file

@ -1,7 +1,7 @@
use crate::{ use crate::{
custom_glyph::CustomGlyphCacheKey, ColorMode, ContentType, RasterizationRequest, RasterizedCustomGlyph, custom_glyph::CustomGlyphCacheKey, ColorMode, ContentType, FontSystem, GlyphDetails,
FontSystem, GlyphDetails, GlyphToRender, GpuCacheStatus, PrepareError, RenderError, SwashCache, GlyphToRender, GpuCacheStatus, PrepareError, RasterizeCustomGlyphRequest,
SwashContent, TextArea, TextAtlas, Viewport, RasterizedCustomGlyph, RenderError, SwashCache, SwashContent, TextArea, TextAtlas, Viewport,
}; };
use cosmic_text::{Color, SubpixelBin}; use cosmic_text::{Color, SubpixelBin};
use std::{slice, sync::Arc}; use std::{slice, sync::Arc};
@ -104,7 +104,7 @@ impl TextRenderer {
viewport: &Viewport, viewport: &Viewport,
text_areas: impl IntoIterator<Item = TextArea<'a>>, text_areas: impl IntoIterator<Item = TextArea<'a>>,
cache: &mut SwashCache, cache: &mut SwashCache,
rasterize_custom_glyph: impl FnMut(RasterizationRequest) -> Option<RasterizedCustomGlyph>, rasterize_custom_glyph: impl FnMut(RasterizeCustomGlyphRequest) -> Option<RasterizedCustomGlyph>,
) -> Result<(), PrepareError> { ) -> Result<(), PrepareError> {
self.prepare_with_depth_and_custom( self.prepare_with_depth_and_custom(
device, device,
@ -130,7 +130,9 @@ impl TextRenderer {
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,
mut rasterize_custom_glyph: impl FnMut(RasterizationRequest) -> Option<RasterizedCustomGlyph>, mut rasterize_custom_glyph: impl FnMut(
RasterizeCustomGlyphRequest,
) -> Option<RasterizedCustomGlyph>,
) -> Result<(), PrepareError> { ) -> Result<(), PrepareError> {
self.glyph_vertices.clear(); self.glyph_vertices.clear();
@ -193,7 +195,7 @@ impl TextRenderer {
return None; return None;
} }
let input = RasterizationRequest { let input = RasterizeCustomGlyphRequest {
id: glyph.id, id: glyph.id,
width, width,
height, height,
@ -202,9 +204,7 @@ impl TextRenderer {
scale: text_area.scale, scale: text_area.scale,
}; };
let Some(output) = (rasterize_custom_glyph)(input) else { let output = (rasterize_custom_glyph)(input)?;
return None;
};
output.validate(&input, None); output.validate(&input, None);
@ -268,11 +268,8 @@ impl TextRenderer {
font_system, font_system,
_rasterize_custom_glyph| _rasterize_custom_glyph|
-> Option<GetGlyphImageResult> { -> Option<GetGlyphImageResult> {
let Some(image) = let image =
cache.get_image_uncached(font_system, physical_glyph.cache_key) cache.get_image_uncached(font_system, physical_glyph.cache_key)?;
else {
return None;
};
let content_type = match image.content { let content_type = match image.content {
SwashContent::Color => ContentType::Color, SwashContent::Color => ContentType::Color,
@ -429,7 +426,7 @@ fn prepare_glyph<R>(
mut rasterize_custom_glyph: R, mut rasterize_custom_glyph: R,
) -> Result<Option<GlyphToRender>, PrepareError> ) -> Result<Option<GlyphToRender>, PrepareError>
where where
R: FnMut(RasterizationRequest) -> Option<RasterizedCustomGlyph>, R: FnMut(RasterizeCustomGlyphRequest) -> Option<RasterizedCustomGlyph>,
{ {
if atlas.mask_atlas.glyph_cache.contains(&cache_key) { if atlas.mask_atlas.glyph_cache.contains(&cache_key) {
atlas.mask_atlas.promote(cache_key); atlas.mask_atlas.promote(cache_key);

View file

@ -1,10 +1,13 @@
use crate::{Cache, Params, Resolution}; use crate::{Cache, Params, Resolution};
use std::{mem, slice};
use wgpu::{BindGroup, Buffer, BufferDescriptor, BufferUsages, Device, Queue}; use wgpu::{BindGroup, Buffer, BufferDescriptor, BufferUsages, Device, Queue};
use std::mem; /// Controls the visible area of all text for a given renderer. Any text outside of the visible
use std::slice; /// area will be clipped.
///
/// Many projects will only ever need a single `Viewport`, but it is possible to create multiple
/// `Viewport`s if you want to render text to specific areas within a window (without having to)
/// bound each `TextArea`).
#[derive(Debug)] #[derive(Debug)]
pub struct Viewport { pub struct Viewport {
params: Params, params: Params,
@ -13,6 +16,7 @@ pub struct Viewport {
} }
impl Viewport { impl Viewport {
/// Creates a new `Viewport` with the given `device` and `cache`.
pub fn new(device: &Device, cache: &Cache) -> Self { pub fn new(device: &Device, cache: &Cache) -> Self {
let params = Params { let params = Params {
screen_resolution: Resolution { screen_resolution: Resolution {
@ -38,6 +42,7 @@ impl Viewport {
} }
} }
/// Updates the `Viewport` with the given `resolution`.
pub fn update(&mut self, queue: &Queue, resolution: Resolution) { pub fn update(&mut self, queue: &Queue, resolution: Resolution) {
if self.params.screen_resolution != resolution { if self.params.screen_resolution != resolution {
self.params.screen_resolution = resolution; self.params.screen_resolution = resolution;
@ -51,6 +56,7 @@ impl Viewport {
} }
} }
/// Returns the current resolution of the `Viewport`.
pub fn resolution(&self) -> Resolution { pub fn resolution(&self) -> Resolution {
self.params.screen_resolution self.params.screen_resolution
} }