From d59bafced1de07329b56aa04f5e398c1cc70e5e6 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Tue, 10 Jan 2017 13:37:01 -0800 Subject: [PATCH] Implement batch creation --- src/batch.rs | 100 +++++++++++++++++++++++----- src/{buffers.rs => glyph_buffer.rs} | 54 ++++++++++----- src/lib.rs | 2 +- 3 files changed, 122 insertions(+), 34 deletions(-) rename src/{buffers.rs => glyph_buffer.rs} (55%) diff --git a/src/batch.rs b/src/batch.rs index b9532447..fcb52cf0 100644 --- a/src/batch.rs +++ b/src/batch.rs @@ -8,6 +8,79 @@ // option. This file may not be copied, modified, or distributed // 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, + pub images: Vec, + 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 { + 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)] pub struct GlyphRange { pub start: u16, @@ -45,22 +118,15 @@ impl Iterator for GlyphRangeIter { } } -#[derive(Clone, Debug)] -pub struct FontGlyphRange { - pub font_id: u32, - pub ranges: Vec, -} - -#[derive(Clone)] -pub struct FontGlyphRanges { - pub fonts: Vec, -} - -impl FontGlyphRanges { - pub fn new() -> FontGlyphRanges { - FontGlyphRanges { - fonts: vec![], - } - } +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub struct ImageDescriptor { + atlas_x: u32, + atlas_y: u32, + point_size: f32, + glyph_index: u32, + start_point_in_glyph: u32, + start_point_in_batch: u32, + point_count: u32, } diff --git a/src/buffers.rs b/src/glyph_buffer.rs similarity index 55% rename from src/buffers.rs rename to src/glyph_buffer.rs index 4785266f..afc5cded 100644 --- a/src/buffers.rs +++ b/src/glyph_buffer.rs @@ -8,38 +8,30 @@ // option. This file may not be copied, modified, or distributed // 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::loca::LocaTable; -pub struct GlyphBuffers { +pub struct GlyphBufferBuilder { pub coordinates: Vec<(i16, i16)>, pub operations: Vec, pub descriptors: Vec, - pub cached_coordinates_buffer: Option, - pub cached_operations_buffer: Option, - pub cached_descriptors_buffer: Option, } -impl GlyphBuffers { +impl GlyphBufferBuilder { #[inline] - pub fn new() -> GlyphBuffers { - GlyphBuffers { + pub fn new() -> GlyphBufferBuilder { + GlyphBufferBuilder { coordinates: vec![], operations: 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) -> 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 operations = if point_index % 4 == 0 { 0 @@ -70,8 +62,29 @@ impl GlyphBuffers { self.operations.push(operations) } + // TODO(pcwalton): Add a glyph descriptor. + Ok(()) } + + pub fn finish(&self, device: &mut Device) -> Result { + 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)] @@ -82,6 +95,15 @@ pub struct GlyphDescriptor { pub height: i16, pub units_per_em: 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 { + 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 + } } diff --git a/src/lib.rs b/src/lib.rs index b52b6f60..890153df 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,8 +25,8 @@ extern crate test; pub mod atlas; pub mod batch; -pub mod buffers; pub mod charmap; +pub mod glyph_buffer; pub mod otf; pub mod rasterizer; mod util;