Skip to content

changes from lapce #11

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

Draft
wants to merge 19 commits into
base: main
Choose a base branch
from
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
wgpu = "0.15.1"
wgpu = "22.0.0"
euclid = "0.22.7"
fontdue = "0.7.2"
rect_packer = "0.2.1"
rand = "0.7.3"
cosmic-text = { git = "https://github.com/lapce/cosmic-text", rev = "25f260eced296296ca22d22a04cbb3026f5fe2a2" }
# cosmic-text = { path = "../cosmic-text" }

[dev-dependencies]
png = "0.17.6"
Expand Down
58 changes: 46 additions & 12 deletions src/atlas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,22 @@ struct ImageData {
data: Vec<u8>,
}

pub enum AtlasContent {
Mask,
Color,
}

pub struct Atlas {
packer: Packer,
new_data: Vec<ImageData>,
pub atlas_texture: wgpu::Texture,
area_used: i32,
did_clear: bool,
content: AtlasContent,
}

impl Atlas {
pub const ATLAS_SIZE: u32 = 1024;
pub const ATLAS_SIZE: u32 = 4096;
pub const RECT_PADDING: i32 = 6;

fn get_packer_config() -> rect_packer::Config {
Expand All @@ -42,21 +48,45 @@ impl Atlas {
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::R8Unorm,
usage: wgpu::TextureUsages::COPY_SRC | wgpu::TextureUsages::COPY_DST | wgpu::TextureUsages::TEXTURE_BINDING,
usage: wgpu::TextureUsages::COPY_SRC
| wgpu::TextureUsages::COPY_DST
| wgpu::TextureUsages::TEXTURE_BINDING,
label: Some("atlas_texture"),
view_formats: &[wgpu::TextureFormat::R8Unorm],
}
}

pub fn new(device: &wgpu::Device) -> Self {
let atlas_texture = device.create_texture(&Self::get_texture_desc());
pub fn new(device: &wgpu::Device, content: AtlasContent) -> Self {
let texture_size = wgpu::Extent3d {
width: Atlas::ATLAS_SIZE,
height: Atlas::ATLAS_SIZE,
depth_or_array_layers: 1,
};
let format = match content {
AtlasContent::Mask => wgpu::TextureFormat::R8Unorm,
AtlasContent::Color => wgpu::TextureFormat::Rgba8Unorm,
};
let desc = wgpu::TextureDescriptor {
size: texture_size,
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format,
usage: wgpu::TextureUsages::COPY_SRC
| wgpu::TextureUsages::COPY_DST
| wgpu::TextureUsages::TEXTURE_BINDING,
label: Some("atlas_texture"),
view_formats: &[format],
};
let atlas_texture = device.create_texture(&desc);

Self {
packer: Packer::new(Atlas::get_packer_config()),
new_data: vec![],
atlas_texture,
area_used: 0,
did_clear: false,
content,
}
}

Expand All @@ -81,7 +111,7 @@ impl Atlas {

let sz = Atlas::ATLAS_SIZE as usize;

let data = vec![0_u8;sz * sz];
let data = vec![0_u8; sz * sz];

let buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("atlas temp buffer"),
Expand All @@ -100,7 +130,7 @@ impl Atlas {
buffer: &buffer,
layout: wgpu::ImageDataLayout {
offset: 0,
bytes_per_row: std::num::NonZeroU32::new(sz as u32),
bytes_per_row: Some((sz * 4) as u32),
rows_per_image: None,
},
},
Expand All @@ -119,14 +149,18 @@ impl Atlas {
for data in &self.new_data {
// Pad data to wgpu::COPY_BYTES_PER_ROW_ALIGNMENT
let align = wgpu::COPY_BYTES_PER_ROW_ALIGNMENT as i32;
let padding = (align - data.rect.width % align) % align;
let padded_width = data.rect.width + padding;
let mut padded_data = vec![];
padded_data.reserve((padded_width * data.rect.height) as usize);
let pixels = match self.content {
AtlasContent::Mask => 1,
AtlasContent::Color => 4,
};
let width = data.rect.width * pixels;
let padding = (align - width % align) % align;
let padded_width = width + padding;
let mut padded_data = Vec::with_capacity((padded_width * data.rect.height) as usize);

let mut i = 0;
for _ in 0..data.rect.height {
for _ in 0..data.rect.width {
for _ in 0..width {
padded_data.push(data.data[i]);
i += 1;
}
Expand Down Expand Up @@ -154,7 +188,7 @@ impl Atlas {
buffer: &buffer,
layout: wgpu::ImageDataLayout {
offset: 0,
bytes_per_row: std::num::NonZeroU32::new(padded_width as u32),
bytes_per_row: Some(padded_width as u32),
rows_per_image: None,
},
},
Expand Down
117 changes: 105 additions & 12 deletions src/glyphs.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::atlas::Atlas;
use crate::atlas::{Atlas, AtlasContent};
use cosmic_text::{SubpixelBin, SwashContent, SwashImage};
use rect_packer::Rect;
use std::collections::HashMap;

Expand All @@ -8,10 +9,29 @@ pub struct GlyphInfo {
pub metrics: fontdue::Metrics,
}

#[derive(Copy, Clone, Debug)]
pub struct AtlasInfo {
pub rect: Option<Rect>,
pub left: i32,
pub top: i32,
pub colored: bool,
}

pub struct GlyphCache {
pub atlas: Atlas,
pub mask_atlas: Atlas,
pub color_atlas: Atlas,
pub font: fontdue::Font,
info: HashMap<(char, u32), GlyphInfo>,
atlas_infos: HashMap<
(
cosmic_text::fontdb::ID,
u16,
u32,
(SubpixelBin, SubpixelBin),
),
AtlasInfo,
>,
svg_infos: HashMap<Vec<u8>, HashMap<(u32, u32), AtlasInfo>>,
}

impl GlyphCache {
Expand All @@ -23,12 +43,84 @@ impl GlyphCache {
let font = include_bytes!("fonts/Anodina-Regular.ttf") as &[u8];

Self {
atlas: Atlas::new(device),
mask_atlas: Atlas::new(device, AtlasContent::Mask),
color_atlas: Atlas::new(device, AtlasContent::Color),
font: fontdue::Font::from_bytes(font, settings).unwrap(),
info: HashMap::new(),
atlas_infos: HashMap::new(),
svg_infos: HashMap::new(),
}
}

pub fn get_svg_mask(
&mut self,
hash: &[u8],
width: u32,
height: u32,
image: impl FnOnce() -> Vec<u8>,
) -> AtlasInfo {
if !self.svg_infos.contains_key(hash) {
self.svg_infos.insert(hash.to_vec(), HashMap::new());
}

{
let svg_infos = self.svg_infos.get(hash).unwrap();
if let Some(info) = svg_infos.get(&(width, height)) {
return *info;
}
}

let data = image();
let rect = self.color_atlas.add_region(&data, width, height);
let info = AtlasInfo {
rect,
left: 0,
top: 0,
colored: true,
};

let svg_infos = self.svg_infos.get_mut(hash).unwrap();
svg_infos.insert((width, height), info);

info
}

pub fn get_glyph_mask(
&mut self,
font_id: cosmic_text::fontdb::ID,
glyph_id: u16,
size: u32,
subpx: (SubpixelBin, SubpixelBin),
image: impl FnOnce() -> SwashImage,
) -> AtlasInfo {
let key = (font_id, glyph_id, size, subpx);
if let Some(rect) = self.atlas_infos.get(&key) {
return *rect;
}

let image = image();
let rect = match image.content {
SwashContent::Mask => self.mask_atlas.add_region(
&image.data,
image.placement.width,
image.placement.height,
),
SwashContent::SubpixelMask | SwashContent::Color => self.color_atlas.add_region(
&image.data,
image.placement.width,
image.placement.height,
),
};
let info = AtlasInfo {
rect,
left: image.placement.left,
top: image.placement.top,
colored: image.content != SwashContent::Mask,
};
self.atlas_infos.insert(key, info);
info
}

pub fn get_glyph(&mut self, c: char, size: f32) -> GlyphInfo {
let factor = 65536.0;

Expand All @@ -53,7 +145,7 @@ impl GlyphCache {
*/

let rect =
self.atlas
self.mask_atlas
.add_region(&data, metrics.width as u32, metrics.height as u32);

let info = GlyphInfo { rect, metrics };
Expand All @@ -65,19 +157,20 @@ impl GlyphCache {
}

pub fn update(&mut self, device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder) {
self.atlas.update(device, encoder);
self.mask_atlas.update(device, encoder);
self.color_atlas.update(device, encoder);
}

pub fn create_view(&self) -> wgpu::TextureView {
self.atlas.create_view()
}

pub fn usage(&self) -> f32 {
self.atlas.usage()
pub fn check_usage(&mut self) {
if self.mask_atlas.usage() > 0.7 || self.color_atlas.usage() > 0.7 {
self.clear();
}
}

pub fn clear(&mut self) {
self.info.clear();
self.atlas.clear();
self.mask_atlas.clear();
self.color_atlas.clear();
self.atlas_infos.clear();
}
}
4 changes: 4 additions & 0 deletions src/gpu_vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ impl<T: Copy> GPUVec<T> {
self.data.clear();
}

pub fn append(&mut self, values: &mut Vec<T>) {
self.data.append(values);
}

pub fn push(&mut self, value: T) {
self.data.push(value);
}
Expand Down
Loading