Implement batch creation

This commit is contained in:
Patrick Walton 2017-01-10 13:37:01 -08:00
parent 941aaea676
commit d59bafced1
3 changed files with 122 additions and 34 deletions

View File

@ -8,6 +8,79 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use atlas::Atlas;
use compute_shader::buffer::{Buffer, BufferData, HostAllocatedData, Protection};
use compute_shader::device::Device;
use glyph_buffer::GlyphBufferBuilder;
use std::u16;
const POINTS_PER_SEGMENT: u32 = 32;
pub struct BatchBuilder {
pub atlas: Atlas,
pub indices: Vec<u16>,
pub images: Vec<ImageDescriptor>,
pub point_count: u32,
}
impl BatchBuilder {
/// FIXME(pcwalton): Including the shelf height here may be a bad API.
#[inline]
pub fn new(available_width: u32, shelf_height: u32) -> BatchBuilder {
BatchBuilder {
atlas: Atlas::new(available_width, shelf_height),
indices: vec![],
images: vec![],
point_count: 0,
}
}
pub fn add_glyph(&mut self,
glyph_buffer_builder: &GlyphBufferBuilder,
glyph_index: u32,
point_size: f32)
-> Result<(), ()> {
let descriptor = &glyph_buffer_builder.descriptors[glyph_index as usize];
// FIXME(pcwalton): I think this will check for negative values and panic, which is
// unnecessary.
let pixel_size = descriptor.pixel_rect(point_size).size.ceil().cast().unwrap();
let atlas_origin = try!(self.atlas.place(&pixel_size));
if self.point_count % POINTS_PER_SEGMENT == 0 {
self.indices.push(self.images.len() as u16)
}
self.images.push(ImageDescriptor {
atlas_x: atlas_origin.x,
atlas_y: atlas_origin.y,
point_size: point_size,
glyph_index: glyph_index,
start_point_in_glyph: descriptor.start_point,
start_point_in_batch: self.point_count,
point_count: descriptor.point_count as u32,
});
self.point_count += descriptor.point_count as u32;
Ok(())
}
pub fn finish(&mut self, device: &mut Device) -> Result<Batch, ()> {
let indices = BufferData::HostAllocated(HostAllocatedData::new(&self.indices));
let images = BufferData::HostAllocated(HostAllocatedData::new(&self.images));
Ok(Batch {
indices: try!(device.create_buffer(Protection::ReadOnly, indices).map_err(drop)),
images: try!(device.create_buffer(Protection::ReadOnly, images).map_err(drop)),
})
}
}
pub struct Batch {
pub indices: Buffer,
pub images: Buffer,
}
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct GlyphRange { pub struct GlyphRange {
pub start: u16, pub start: u16,
@ -45,22 +118,15 @@ impl Iterator for GlyphRangeIter {
} }
} }
#[derive(Clone, Debug)] #[repr(C)]
pub struct FontGlyphRange { #[derive(Clone, Copy, Debug)]
pub font_id: u32, pub struct ImageDescriptor {
pub ranges: Vec<GlyphRange>, atlas_x: u32,
} atlas_y: u32,
point_size: f32,
#[derive(Clone)] glyph_index: u32,
pub struct FontGlyphRanges { start_point_in_glyph: u32,
pub fonts: Vec<FontGlyphRange>, start_point_in_batch: u32,
} point_count: u32,
impl FontGlyphRanges {
pub fn new() -> FontGlyphRanges {
FontGlyphRanges {
fonts: vec![],
}
}
} }

View File

@ -8,38 +8,30 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use compute_shader::buffer::Buffer; use compute_shader::buffer::{Buffer, BufferData, HostAllocatedData, Protection};
use compute_shader::device::Device;
use euclid::{Point2D, Rect, Size2D};
use otf::glyf::GlyfTable; use otf::glyf::GlyfTable;
use otf::loca::LocaTable; use otf::loca::LocaTable;
pub struct GlyphBuffers { pub struct GlyphBufferBuilder {
pub coordinates: Vec<(i16, i16)>, pub coordinates: Vec<(i16, i16)>,
pub operations: Vec<u8>, pub operations: Vec<u8>,
pub descriptors: Vec<GlyphDescriptor>, pub descriptors: Vec<GlyphDescriptor>,
pub cached_coordinates_buffer: Option<Buffer>,
pub cached_operations_buffer: Option<Buffer>,
pub cached_descriptors_buffer: Option<Buffer>,
} }
impl GlyphBuffers { impl GlyphBufferBuilder {
#[inline] #[inline]
pub fn new() -> GlyphBuffers { pub fn new() -> GlyphBufferBuilder {
GlyphBuffers { GlyphBufferBuilder {
coordinates: vec![], coordinates: vec![],
operations: vec![], operations: vec![],
descriptors: vec![], descriptors: vec![],
cached_coordinates_buffer: None,
cached_operations_buffer: None,
cached_descriptors_buffer: None,
} }
} }
pub fn add_glyph(&mut self, glyph_id: u32, loca_table: &LocaTable, glyf_table: &GlyfTable) pub fn add_glyph(&mut self, glyph_id: u32, loca_table: &LocaTable, glyf_table: &GlyfTable)
-> Result<(), ()> { -> Result<(), ()> {
self.cached_coordinates_buffer = None;
self.cached_operations_buffer = None;
self.cached_descriptors_buffer = None;
let mut point_index = self.coordinates.len() / 2; let mut point_index = self.coordinates.len() / 2;
let mut operations = if point_index % 4 == 0 { let mut operations = if point_index % 4 == 0 {
0 0
@ -70,8 +62,29 @@ impl GlyphBuffers {
self.operations.push(operations) self.operations.push(operations)
} }
// TODO(pcwalton): Add a glyph descriptor.
Ok(()) Ok(())
} }
pub fn finish(&self, device: &mut Device) -> Result<GlyphBuffers, ()> {
let coordinates = BufferData::HostAllocated(HostAllocatedData::new(&self.coordinates));
let operations = BufferData::HostAllocated(HostAllocatedData::new(&self.operations));
let descriptors = BufferData::HostAllocated(HostAllocatedData::new(&self.descriptors));
Ok(GlyphBuffers {
coordinates: try!(device.create_buffer(Protection::ReadOnly, coordinates)
.map_err(drop)),
operations: try!(device.create_buffer(Protection::ReadOnly, operations).map_err(drop)),
descriptors: try!(device.create_buffer(Protection::ReadOnly, descriptors)
.map_err(drop)),
})
}
}
pub struct GlyphBuffers {
pub coordinates: Buffer,
pub operations: Buffer,
pub descriptors: Buffer,
} }
#[repr(C)] #[repr(C)]
@ -82,6 +95,15 @@ pub struct GlyphDescriptor {
pub height: i16, pub height: i16,
pub units_per_em: u16, pub units_per_em: u16,
pub point_count: u16, pub point_count: u16,
pub index_of_first_point: u32, pub start_point: u32,
}
impl GlyphDescriptor {
#[inline]
pub fn pixel_rect(&self, point_size: f32) -> Rect<f32> {
let pixels_per_unit = point_size / self.units_per_em as f32;
Rect::new(Point2D::new(self.left as f32, self.bottom as f32),
Size2D::new(self.width as f32, self.height as f32)) * pixels_per_unit
}
} }

View File

@ -25,8 +25,8 @@ extern crate test;
pub mod atlas; pub mod atlas;
pub mod batch; pub mod batch;
pub mod buffers;
pub mod charmap; pub mod charmap;
pub mod glyph_buffer;
pub mod otf; pub mod otf;
pub mod rasterizer; pub mod rasterizer;
mod util; mod util;