[oden] It doesn't crash but it doesn't work either

This commit is contained in:
John Doty 2023-08-31 14:46:04 -07:00
parent 71aa3c39f7
commit 8914b1795f
2 changed files with 162 additions and 50 deletions

View file

@ -45,12 +45,9 @@ enum CellCacheKey {
pub struct FontCache {
font: Font,
size: f32,
atlas_width: u16,
atlas_height: u16,
char_width: u16,
char_height: u16,
texture: wgpu::Texture,
view: wgpu::TextureView,
pub view: wgpu::TextureView,
pub sampler: wgpu::Sampler,
cells: Vec<GlyphCell>,
cell_cache: LruCache<CellCacheKey, usize>,
@ -58,7 +55,6 @@ pub struct FontCache {
enum SlotState {
Empty,
Allocated(u16, fontdue::Metrics),
Rendered(u16, fontdue::Metrics),
}
@ -70,8 +66,15 @@ struct GlyphCell {
state: SlotState,
}
pub struct Glyph {
pub x: f32,
pub y: f32,
pub w: f32,
pub h: f32,
}
impl FontCache {
fn new(device: &wgpu::Device, bytes: &[u8], size: f32) -> Self {
pub fn new(device: &wgpu::Device, bytes: &[u8], size: f32) -> Self {
let font = fontdue::Font::from_bytes(bytes, fontdue::FontSettings::default())
.expect("Could not parse font");
@ -90,10 +93,21 @@ impl FontCache {
sample_count: 4,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::R8Unorm,
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
usage: wgpu::TextureUsages::TEXTURE_BINDING
| wgpu::TextureUsages::COPY_DST
| wgpu::TextureUsages::RENDER_ATTACHMENT,
view_formats: &[],
});
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
address_mode_u: wgpu::AddressMode::ClampToEdge,
address_mode_v: wgpu::AddressMode::ClampToEdge,
address_mode_w: wgpu::AddressMode::ClampToEdge,
mag_filter: wgpu::FilterMode::Nearest,
min_filter: wgpu::FilterMode::Nearest,
mipmap_filter: wgpu::FilterMode::Nearest,
..Default::default()
});
// Measure the font to figure out the size of a cell in the cache.
// NOTE: This metric nonsense is bad, probably.
@ -133,59 +147,71 @@ impl FontCache {
);
}
// Set up the binding group and pipeline and whatnot.
FontCache {
font,
size,
atlas_width,
atlas_height,
char_width: char_width as u16,
char_height: char_height as u16,
texture,
view,
sampler,
cells,
cell_cache,
}
}
fn rasterize_character(&mut self, queue: &wgpu::Queue, index: u16, slot: &GlyphCell) {
let (metrics, bitmap) = self.font.rasterize_indexed(index, self.size);
let mut texture = self.texture.as_image_copy();
texture.origin.x = slot.x.into();
texture.origin.y = slot.y.into();
queue.write_texture(
texture,
&bitmap,
wgpu::ImageDataLayout {
offset: 0,
bytes_per_row: Some(metrics.width as u32),
rows_per_image: None,
},
wgpu::Extent3d {
width: metrics.width as u32,
height: metrics.height as u32,
depth_or_array_layers: 1,
},
);
}
fn get_glyph_slot(&mut self, index: u16) -> &mut GlyphCell {
pub fn get_char(&mut self, queue: &wgpu::Queue, c: char) -> Glyph {
let index = self.font.lookup_glyph_index(c);
let key = CellCacheKey::GlyphIndex(index);
if let Some(cell_index) = self.cell_cache.get(&key) {
return &mut self.cells[*cell_index];
}
let cell = match self.cell_cache.get(&key) {
Some(cell_index) => &mut self.cells[*cell_index],
None => {
let (_, cell_index) = self
.cell_cache
.pop_lru()
.expect("did not put all available things in the LRU cache");
self.cell_cache.put(key, cell_index);
let cell = &mut self.cells[cell_index];
cell.state = SlotState::Empty; // This isn't what it used to be.
cell
}
};
if let Some((_, cell_index)) = self.cell_cache.pop_lru() {
self.cell_cache.put(key, cell_index);
let cell = &mut self.cells[cell_index];
cell.state = SlotState::Empty;
return cell;
}
// I mean, technically if we got an LRU hit here it's rendered, but
// convincing the compiler of that is a pain.
let metrics = match cell.state {
SlotState::Rendered(_, metrics) => metrics,
SlotState::Empty => {
let (metrics, bitmap) = self.font.rasterize_indexed(index, self.size);
panic!("Did not put enough things in the LRU cache, why is it empty here?");
let mut texture = self.texture.as_image_copy();
texture.origin.x = cell.x.into();
texture.origin.y = cell.y.into();
queue.write_texture(
texture,
&bitmap,
wgpu::ImageDataLayout {
offset: 0,
bytes_per_row: Some(metrics.width as u32),
rows_per_image: None,
},
wgpu::Extent3d {
width: metrics.width as u32,
height: metrics.height as u32,
depth_or_array_layers: 1,
},
);
cell.state = SlotState::Rendered(index, metrics.clone());
metrics
}
};
Glyph {
x: cell.x as f32 + metrics.bounds.xmin,
y: cell.y as f32 + metrics.bounds.ymin,
w: metrics.bounds.width,
h: metrics.bounds.height,
}
}
}