Draft end-to-end support for the new algorithm. Not working yet.
This commit is contained in:
parent
1cd3a1e6bd
commit
50ad78db2a
|
@ -66,8 +66,8 @@ fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let glyph_buffers = glyph_buffer_builder.finish(&rasterizer.device).unwrap();
|
let glyph_buffers = glyph_buffer_builder.finish().unwrap();
|
||||||
let batch = batch_builder.finish(&rasterizer.device).unwrap();
|
let batch = batch_builder.finish(&glyph_buffer_builder).unwrap();
|
||||||
|
|
||||||
let atlas_size = Size2D::new(WIDTH, HEIGHT);
|
let atlas_size = Size2D::new(WIDTH, HEIGHT);
|
||||||
let coverage_buffer = CoverageBuffer::new(&rasterizer.device, &atlas_size).unwrap();
|
let coverage_buffer = CoverageBuffer::new(&rasterizer.device, &atlas_size).unwrap();
|
||||||
|
|
|
@ -19,14 +19,14 @@ layout(std140) struct GlyphDescriptor {
|
||||||
ivec4 extents;
|
ivec4 extents;
|
||||||
// The number of units per em in this glyph.
|
// The number of units per em in this glyph.
|
||||||
uint unitsPerEm;
|
uint unitsPerEm;
|
||||||
// The number of points in this glyph.
|
// The index of the first point in the VBO.
|
||||||
uint pointCount;
|
|
||||||
// The index of the first point.
|
|
||||||
uint startPoint;
|
uint startPoint;
|
||||||
|
// The index of the first element in the IBO.
|
||||||
|
uint startIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Information about the position of each glyph in the atlas.
|
// Information about the position of each glyph in the atlas.
|
||||||
layout(std140) struct ImageInfo {
|
layout(std140) struct ImageDescriptor {
|
||||||
// The left/top/right/bottom positions of the glyph in the atlas.
|
// The left/top/right/bottom positions of the glyph in the atlas.
|
||||||
uvec4 atlasRect;
|
uvec4 atlasRect;
|
||||||
// The font size in pixels.
|
// The font size in pixels.
|
||||||
|
@ -42,17 +42,17 @@ layout(std140) uniform ubGlyphDescriptors {
|
||||||
GlyphDescriptor uGlyphs[MAX_GLYPHS];
|
GlyphDescriptor uGlyphs[MAX_GLYPHS];
|
||||||
};
|
};
|
||||||
|
|
||||||
layout(std140) uniform ubImageInfo {
|
layout(std140) uniform ubImageDescriptors {
|
||||||
ImageInfo uImageInfo[MAX_GLYPHS];
|
ImageDescriptor uImages[MAX_GLYPHS];
|
||||||
};
|
};
|
||||||
|
|
||||||
// The position of each vertex in glyph space.
|
// The position of each vertex in glyph space.
|
||||||
in ivec2 aPosition;
|
in ivec2 aPosition;
|
||||||
|
|
||||||
// Which image the vertex belongs to.
|
// Which glyph the vertex belongs to.
|
||||||
//
|
//
|
||||||
// TODO(pcwalton): See if this is faster as a binary search on the vertex ID.
|
// TODO(pcwalton): See if this is faster as a binary search on the vertex ID.
|
||||||
in uint aImageIndex;
|
in uint aGlyphIndex;
|
||||||
|
|
||||||
// The vertex ID, passed along onto the TCS.
|
// The vertex ID, passed along onto the TCS.
|
||||||
flat out uint vVertexID;
|
flat out uint vVertexID;
|
||||||
|
@ -60,13 +60,13 @@ flat out uint vVertexID;
|
||||||
void main() {
|
void main() {
|
||||||
vVertexID = gl_VertexID;
|
vVertexID = gl_VertexID;
|
||||||
|
|
||||||
ImageInfo imageInfo = uImageInfo[aImageIndex];
|
ImageDescriptor image = uImages[aGlyphIndex];
|
||||||
GlyphDescriptor glyph = uGlyphs[imageInfo.glyphIndex];
|
GlyphDescriptor glyph = uGlyphs[aGlyphIndex];
|
||||||
|
|
||||||
float emsPerUnit = 1.0f / float(glyph.unitsPerEm);
|
float emsPerUnit = 1.0f / float(glyph.unitsPerEm);
|
||||||
|
|
||||||
vec2 glyphPos = vec2(aPosition.x - glyphInfo.extents.x, glyphInfo.extents.w - aPosition.y);
|
vec2 glyphPos = vec2(aPosition.x - glyph.extents.x, glyph.extents.w - aPosition.y);
|
||||||
vec2 atlasPos = glyphPos * emsPerUnit * imageInfo.pointSize + vec2(imageInfo.atlasRect.xy);
|
vec2 atlasPos = glyphPos * emsPerUnit * image.pointSize + vec2(image.atlasRect.xy);
|
||||||
|
|
||||||
gl_Position = vec4(atlasPos, 0.0f, 1.0f);
|
gl_Position = vec4(atlasPos, 0.0f, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
99
src/batch.rs
99
src/batch.rs
|
@ -9,18 +9,17 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use atlas::Atlas;
|
use atlas::Atlas;
|
||||||
use compute_shader::buffer::{Buffer, BufferData, HostAllocatedData, Protection};
|
use gl::types::{GLsizei, GLsizeiptr, GLuint};
|
||||||
use compute_shader::device::Device;
|
use gl;
|
||||||
use glyph_buffer::GlyphBufferBuilder;
|
use glyph_buffer::GlyphBufferBuilder;
|
||||||
|
use std::mem;
|
||||||
|
use std::os::raw::c_void;
|
||||||
use std::u16;
|
use std::u16;
|
||||||
|
|
||||||
const POINTS_PER_SEGMENT: u32 = 32;
|
|
||||||
|
|
||||||
pub struct BatchBuilder {
|
pub struct BatchBuilder {
|
||||||
pub atlas: Atlas,
|
pub atlas: Atlas,
|
||||||
pub indices: Vec<u32>,
|
|
||||||
pub images: Vec<ImageDescriptor>,
|
pub images: Vec<ImageDescriptor>,
|
||||||
pub point_count: u32,
|
pub glyph_indices: Vec<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BatchBuilder {
|
impl BatchBuilder {
|
||||||
|
@ -29,12 +28,12 @@ impl BatchBuilder {
|
||||||
pub fn new(available_width: u32, shelf_height: u32) -> BatchBuilder {
|
pub fn new(available_width: u32, shelf_height: u32) -> BatchBuilder {
|
||||||
BatchBuilder {
|
BatchBuilder {
|
||||||
atlas: Atlas::new(available_width, shelf_height),
|
atlas: Atlas::new(available_width, shelf_height),
|
||||||
indices: vec![],
|
|
||||||
images: vec![],
|
images: vec![],
|
||||||
point_count: 0,
|
glyph_indices: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// FIXME(pcwalton): Support the same glyph drawn at multiple point sizes.
|
||||||
pub fn add_glyph(&mut self,
|
pub fn add_glyph(&mut self,
|
||||||
glyph_buffer_builder: &GlyphBufferBuilder,
|
glyph_buffer_builder: &GlyphBufferBuilder,
|
||||||
glyph_index: u32,
|
glyph_index: u32,
|
||||||
|
@ -47,35 +46,83 @@ impl BatchBuilder {
|
||||||
let pixel_size = descriptor.pixel_rect(point_size).size.ceil().cast().unwrap();
|
let pixel_size = descriptor.pixel_rect(point_size).size.ceil().cast().unwrap();
|
||||||
let atlas_origin = try!(self.atlas.place(&pixel_size));
|
let atlas_origin = try!(self.atlas.place(&pixel_size));
|
||||||
|
|
||||||
self.images.push(ImageDescriptor {
|
while self.images.len() < glyph_index as usize + 1 {
|
||||||
|
self.images.push(ImageDescriptor::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
self.images[glyph_index as usize] = ImageDescriptor {
|
||||||
atlas_x: atlas_origin.x,
|
atlas_x: atlas_origin.x,
|
||||||
atlas_y: atlas_origin.y,
|
atlas_y: atlas_origin.y,
|
||||||
point_size: point_size,
|
point_size: point_size,
|
||||||
glyph_index: glyph_index,
|
glyph_index: glyph_index,
|
||||||
start_point_in_batch: self.point_count,
|
};
|
||||||
point_count: descriptor.point_count as u32,
|
|
||||||
});
|
|
||||||
|
|
||||||
self.point_count += descriptor.point_count as u32;
|
self.glyph_indices.push(glyph_index);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn finish(&mut self, device: &Device) -> Result<Batch, ()> {
|
pub fn finish(&mut self, glyph_buffer_builder: &GlyphBufferBuilder) -> Result<Batch, ()> {
|
||||||
let indices = BufferData::HostAllocated(HostAllocatedData::new(&self.indices));
|
self.glyph_indices.sort();
|
||||||
let images = BufferData::HostAllocated(HostAllocatedData::new(&self.images));
|
|
||||||
Ok(Batch {
|
let (mut current_range, mut counts, mut start_indices) = (None, vec![], vec![]);
|
||||||
indices: try!(device.create_buffer(Protection::ReadOnly, indices).map_err(drop)),
|
for &glyph_index in &self.glyph_indices {
|
||||||
images: try!(device.create_buffer(Protection::ReadOnly, images).map_err(drop)),
|
let first_index = glyph_buffer_builder.descriptors[glyph_index as usize].start_index as
|
||||||
point_count: self.point_count,
|
usize;
|
||||||
})
|
let last_index = match glyph_buffer_builder.descriptors.get(glyph_index as usize + 1) {
|
||||||
|
Some(ref descriptor) => descriptor.start_index as usize,
|
||||||
|
None => glyph_buffer_builder.indices.len(),
|
||||||
|
};
|
||||||
|
|
||||||
|
match current_range {
|
||||||
|
Some((current_first, current_last)) if first_index == current_last => {
|
||||||
|
current_range = Some((current_first, last_index))
|
||||||
|
}
|
||||||
|
Some((current_first, current_last)) => {
|
||||||
|
counts.push((current_last - current_first) as GLsizei);
|
||||||
|
start_indices.push(current_first);
|
||||||
|
current_range = Some((first_index, last_index))
|
||||||
|
}
|
||||||
|
None => current_range = Some((first_index, last_index)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some((current_first, current_last)) = current_range {
|
||||||
|
counts.push((current_last - current_first) as GLsizei);
|
||||||
|
start_indices.push(current_first);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(pcwalton): Try using `glMapBuffer` here.
|
||||||
|
unsafe {
|
||||||
|
let mut images = 0;
|
||||||
|
gl::GenBuffers(1, &mut images);
|
||||||
|
|
||||||
|
gl::BindBuffer(gl::UNIFORM_BUFFER, images);
|
||||||
|
gl::BufferData(gl::UNIFORM_BUFFER,
|
||||||
|
(self.images.len() * mem::size_of::<ImageDescriptor>()) as GLsizeiptr,
|
||||||
|
self.images.as_ptr() as *const ImageDescriptor as *const c_void,
|
||||||
|
gl::DYNAMIC_DRAW);
|
||||||
|
|
||||||
|
Ok(Batch {
|
||||||
|
start_indices: start_indices,
|
||||||
|
counts: counts,
|
||||||
|
images: images,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Batch {
|
pub struct Batch {
|
||||||
pub indices: Buffer,
|
pub start_indices: Vec<usize>,
|
||||||
pub images: Buffer,
|
pub counts: Vec<GLsizei>,
|
||||||
pub point_count: u32,
|
pub images: GLuint,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Batch {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
gl::DeleteBuffers(1, &mut self.images);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
@ -116,13 +163,11 @@ impl Iterator for GlyphRangeIter {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Default, Debug)]
|
||||||
pub struct ImageDescriptor {
|
pub struct ImageDescriptor {
|
||||||
atlas_x: u32,
|
atlas_x: u32,
|
||||||
atlas_y: u32,
|
atlas_y: u32,
|
||||||
point_size: f32,
|
point_size: f32,
|
||||||
glyph_index: u32,
|
glyph_index: u32,
|
||||||
start_point_in_batch: u32,
|
|
||||||
point_count: u32,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,6 @@ use compute_shader::texture::{ExternalTexture, Format, Texture};
|
||||||
use euclid::size::Size2D;
|
use euclid::size::Size2D;
|
||||||
use gl::types::{GLint, GLuint};
|
use gl::types::{GLint, GLuint};
|
||||||
use gl;
|
use gl;
|
||||||
use std::mem;
|
|
||||||
|
|
||||||
pub struct CoverageBuffer {
|
pub struct CoverageBuffer {
|
||||||
pub texture: Texture,
|
pub texture: Texture,
|
||||||
|
|
|
@ -8,8 +8,6 @@
|
||||||
// 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, BufferData, HostAllocatedData, Protection};
|
|
||||||
use compute_shader::device::Device;
|
|
||||||
use euclid::{Point2D, Rect, Size2D};
|
use euclid::{Point2D, Rect, Size2D};
|
||||||
use gl::types::{GLsizeiptr, GLuint};
|
use gl::types::{GLsizeiptr, GLuint};
|
||||||
use gl;
|
use gl;
|
||||||
|
@ -19,14 +17,15 @@ use otf::loca::LocaTable;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::os::raw::c_void;
|
use std::os::raw::c_void;
|
||||||
|
|
||||||
|
static DUMMY_VERTEX: Vertex = Vertex {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
glyph_index: 0,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct GlyphBufferBuilder {
|
pub struct GlyphBufferBuilder {
|
||||||
pub coordinates: Vec<(i16, i16)>,
|
pub vertices: Vec<Vertex>,
|
||||||
|
pub indices: Vec<u32>,
|
||||||
/// TODO(pcwalton): Try omitting this and binary search the glyph descriptors in the vertex
|
|
||||||
/// shader. Might or might not help.
|
|
||||||
pub glyph_indices: Vec<u16>,
|
|
||||||
|
|
||||||
pub operations: Vec<u8>,
|
|
||||||
pub descriptors: Vec<GlyphDescriptor>,
|
pub descriptors: Vec<GlyphDescriptor>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,9 +33,8 @@ impl GlyphBufferBuilder {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new() -> GlyphBufferBuilder {
|
pub fn new() -> GlyphBufferBuilder {
|
||||||
GlyphBufferBuilder {
|
GlyphBufferBuilder {
|
||||||
coordinates: vec![],
|
vertices: vec![DUMMY_VERTEX],
|
||||||
glyph_indices: vec![],
|
indices: vec![],
|
||||||
operations: vec![],
|
|
||||||
descriptors: vec![],
|
descriptors: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,38 +47,31 @@ impl GlyphBufferBuilder {
|
||||||
-> Result<(), ()> {
|
-> Result<(), ()> {
|
||||||
let glyph_index = self.descriptors.len() as u16;
|
let glyph_index = self.descriptors.len() as u16;
|
||||||
|
|
||||||
let mut point_index = self.coordinates.len() / 2;
|
let mut point_index = self.vertices.len() as u32;
|
||||||
|
let start_index = self.indices.len() as u32;
|
||||||
let start_point = point_index;
|
let start_point = point_index;
|
||||||
let mut operations = if point_index % 4 == 0 {
|
let mut last_point_on_curve = true;
|
||||||
0
|
|
||||||
} else {
|
|
||||||
self.operations.pop().unwrap()
|
|
||||||
};
|
|
||||||
|
|
||||||
try!(glyf_table.for_each_point(loca_table, glyph_id, |point| {
|
try!(glyf_table.for_each_point(loca_table, glyph_id, |point| {
|
||||||
self.coordinates.push((point.position.x, point.position.y));
|
self.vertices.push(Vertex {
|
||||||
self.glyph_indices.push(glyph_index);
|
x: point.position.x,
|
||||||
|
y: point.position.y,
|
||||||
|
glyph_index: glyph_index,
|
||||||
|
});
|
||||||
|
|
||||||
let operation = if point.first_point_in_contour {
|
if !point.first_point_in_contour && point.on_curve {
|
||||||
0
|
let indices = if last_point_on_curve {
|
||||||
} else if point.on_curve {
|
[point_index - 2, 0, point_index - 1]
|
||||||
1
|
} else {
|
||||||
} else {
|
[point_index - 3, point_index - 2, point_index - 1]
|
||||||
2
|
};
|
||||||
};
|
self.indices.extend(indices.iter().cloned());
|
||||||
|
}
|
||||||
operations |= operation << (point_index % 4 * 2);
|
|
||||||
|
|
||||||
point_index += 1;
|
point_index += 1;
|
||||||
if point_index % 4 == 0 {
|
last_point_on_curve = point.on_curve
|
||||||
self.operations.push(operation)
|
|
||||||
}
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if point_index % 4 != 0 {
|
|
||||||
self.operations.push(operations)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a glyph descriptor.
|
// Add a glyph descriptor.
|
||||||
let bounding_rect = try!(glyf_table.bounding_rect(loca_table, glyph_id));
|
let bounding_rect = try!(glyf_table.bounding_rect(loca_table, glyph_id));
|
||||||
self.descriptors.push(GlyphDescriptor {
|
self.descriptors.push(GlyphDescriptor {
|
||||||
|
@ -89,26 +80,33 @@ impl GlyphBufferBuilder {
|
||||||
right: bounding_rect.max_x() as i32,
|
right: bounding_rect.max_x() as i32,
|
||||||
top: bounding_rect.max_y() as i32,
|
top: bounding_rect.max_y() as i32,
|
||||||
units_per_em: head_table.units_per_em as u32,
|
units_per_em: head_table.units_per_em as u32,
|
||||||
point_count: (point_index - start_point) as u32,
|
|
||||||
start_point: start_point as u32,
|
start_point: start_point as u32,
|
||||||
|
start_index: start_index,
|
||||||
pad: 0,
|
pad: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn finish(&self, device: &Device) -> Result<GlyphBuffers, ()> {
|
pub fn finish(&self) -> Result<GlyphBuffers, ()> {
|
||||||
// TODO(pcwalton): Try using `glMapBuffer` here. Requires precomputing contours.
|
// TODO(pcwalton): Try using `glMapBuffer` here. Requires precomputing contour types and
|
||||||
|
// counts.
|
||||||
unsafe {
|
unsafe {
|
||||||
let (mut coordinates, mut descriptors) = (0, 0);
|
let (mut vertices, mut indices, mut descriptors) = (0, 0, 0);
|
||||||
gl::GenBuffers(1, &mut coordinates);
|
gl::GenBuffers(1, &mut vertices);
|
||||||
|
gl::GenBuffers(1, &mut indices);
|
||||||
gl::GenBuffers(1, &mut descriptors);
|
gl::GenBuffers(1, &mut descriptors);
|
||||||
|
|
||||||
let length = self.coordinates.len() * mem::size_of::<(i16, i16)>();
|
gl::BindBuffer(gl::ARRAY_BUFFER, vertices);
|
||||||
gl::BindBuffer(gl::ARRAY_BUFFER, coordinates);
|
|
||||||
gl::BufferData(gl::ARRAY_BUFFER,
|
gl::BufferData(gl::ARRAY_BUFFER,
|
||||||
length as GLsizeiptr,
|
(self.vertices.len() * mem::size_of::<Vertex>()) as GLsizeiptr,
|
||||||
self.coordinates.as_ptr() as *const (i16, i16) as *const c_void,
|
self.vertices.as_ptr() as *const Vertex as *const c_void,
|
||||||
|
gl::STATIC_DRAW);
|
||||||
|
|
||||||
|
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, indices);
|
||||||
|
gl::BufferData(gl::ELEMENT_ARRAY_BUFFER,
|
||||||
|
(self.indices.len() * mem::size_of::<u32>()) as GLsizeiptr,
|
||||||
|
self.indices.as_ptr() as *const u32 as *const c_void,
|
||||||
gl::STATIC_DRAW);
|
gl::STATIC_DRAW);
|
||||||
|
|
||||||
let length = self.descriptors.len() * mem::size_of::<GlyphDescriptor>();
|
let length = self.descriptors.len() * mem::size_of::<GlyphDescriptor>();
|
||||||
|
@ -119,7 +117,8 @@ impl GlyphBufferBuilder {
|
||||||
gl::STATIC_DRAW);
|
gl::STATIC_DRAW);
|
||||||
|
|
||||||
Ok(GlyphBuffers {
|
Ok(GlyphBuffers {
|
||||||
coordinates: coordinates,
|
vertices: vertices,
|
||||||
|
indices: indices,
|
||||||
descriptors: descriptors,
|
descriptors: descriptors,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -127,7 +126,8 @@ impl GlyphBufferBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct GlyphBuffers {
|
pub struct GlyphBuffers {
|
||||||
pub coordinates: GLuint,
|
pub vertices: GLuint,
|
||||||
|
pub indices: GLuint,
|
||||||
pub descriptors: GLuint,
|
pub descriptors: GLuint,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,8 +139,8 @@ pub struct GlyphDescriptor {
|
||||||
pub right: i32,
|
pub right: i32,
|
||||||
pub top: i32,
|
pub top: i32,
|
||||||
pub units_per_em: u32,
|
pub units_per_em: u32,
|
||||||
pub point_count: u32,
|
|
||||||
pub start_point: u32,
|
pub start_point: u32,
|
||||||
|
pub start_index: u32,
|
||||||
pub pad: u32,
|
pub pad: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,7 +150,17 @@ impl GlyphDescriptor {
|
||||||
let pixels_per_unit = point_size / self.units_per_em as 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),
|
Rect::new(Point2D::new(self.left as f32, self.bottom as f32),
|
||||||
Size2D::new((self.right - self.left) as f32,
|
Size2D::new((self.right - self.left) as f32,
|
||||||
(self.bottom - self.top) as f32)) * pixels_per_unit
|
(self.top - self.bottom) as f32)) * pixels_per_unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Vertex {
|
||||||
|
x: i16,
|
||||||
|
y: i16,
|
||||||
|
/// TODO(pcwalton): Try omitting this and binary search the glyph descriptors in the vertex
|
||||||
|
/// shader. Might or might not help.
|
||||||
|
glyph_index: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,9 +16,10 @@ use compute_shader::queue::{Queue, Uniform};
|
||||||
use compute_shader::texture::Texture;
|
use compute_shader::texture::Texture;
|
||||||
use coverage::CoverageBuffer;
|
use coverage::CoverageBuffer;
|
||||||
use euclid::rect::Rect;
|
use euclid::rect::Rect;
|
||||||
use gl::types::{GLchar, GLenum, GLint, GLsizei, GLuint};
|
use gl::types::{GLchar, GLenum, GLint, GLsizei, GLuint, GLvoid};
|
||||||
use gl;
|
use gl;
|
||||||
use glyph_buffer::GlyphBuffers;
|
use glyph_buffer::{GlyphBuffers, Vertex};
|
||||||
|
use std::mem;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
// TODO(pcwalton): Don't force that these be compiled in.
|
// TODO(pcwalton): Don't force that these be compiled in.
|
||||||
|
@ -36,11 +37,19 @@ pub struct Rasterizer {
|
||||||
pub queue: Queue,
|
pub queue: Queue,
|
||||||
draw_program: GLuint,
|
draw_program: GLuint,
|
||||||
accum_program: Program,
|
accum_program: Program,
|
||||||
|
draw_vertex_array: GLuint,
|
||||||
|
draw_position_attribute: GLint,
|
||||||
|
draw_image_index_attribute: GLint,
|
||||||
|
draw_atlas_size_uniform: GLint,
|
||||||
|
draw_glyph_descriptors_uniform: GLuint,
|
||||||
|
draw_image_info_uniform: GLuint,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Rasterizer {
|
impl Rasterizer {
|
||||||
pub fn new(device: Device, queue: Queue) -> Result<Rasterizer, ()> {
|
pub fn new(device: Device, queue: Queue) -> Result<Rasterizer, ()> {
|
||||||
let draw_program;
|
let (draw_program, draw_position_attribute, draw_image_index_attribute);
|
||||||
|
let (draw_atlas_size_uniform, draw_glyph_descriptors_uniform, draw_image_info_uniform);
|
||||||
|
let mut draw_vertex_array = 0;
|
||||||
unsafe {
|
unsafe {
|
||||||
let shaders = [
|
let shaders = [
|
||||||
try!(compile_gl_shader(gl::VERTEX_SHADER,
|
try!(compile_gl_shader(gl::VERTEX_SHADER,
|
||||||
|
@ -68,7 +77,22 @@ impl Rasterizer {
|
||||||
gl::LINK_STATUS,
|
gl::LINK_STATUS,
|
||||||
"Program",
|
"Program",
|
||||||
gl::GetProgramiv,
|
gl::GetProgramiv,
|
||||||
gl::GetProgramInfoLog))
|
gl::GetProgramInfoLog));
|
||||||
|
|
||||||
|
gl::GenVertexArrays(1, &mut draw_vertex_array);
|
||||||
|
|
||||||
|
draw_position_attribute =
|
||||||
|
gl::GetAttribLocation(draw_program, b"aPosition\0".as_ptr() as *const GLchar);
|
||||||
|
draw_image_index_attribute =
|
||||||
|
gl::GetAttribLocation(draw_program, b"aImageIndex\0".as_ptr() as *const GLchar);
|
||||||
|
|
||||||
|
draw_atlas_size_uniform =
|
||||||
|
gl::GetUniformLocation(draw_program, b"uAtlasSize\0".as_ptr() as *const GLchar);
|
||||||
|
draw_glyph_descriptors_uniform =
|
||||||
|
gl::GetUniformBlockIndex(draw_program,
|
||||||
|
b"ubGlyphDescriptors\0".as_ptr() as *const GLchar);
|
||||||
|
draw_image_info_uniform =
|
||||||
|
gl::GetUniformBlockIndex(draw_program, b"ubImageInfo\0".as_ptr() as *const GLchar);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(pcwalton): Don't panic if this fails to compile; just return an error.
|
// FIXME(pcwalton): Don't panic if this fails to compile; just return an error.
|
||||||
|
@ -79,6 +103,12 @@ impl Rasterizer {
|
||||||
queue: queue,
|
queue: queue,
|
||||||
draw_program: draw_program,
|
draw_program: draw_program,
|
||||||
accum_program: accum_program,
|
accum_program: accum_program,
|
||||||
|
draw_vertex_array: draw_vertex_array,
|
||||||
|
draw_position_attribute: draw_position_attribute,
|
||||||
|
draw_image_index_attribute: draw_image_index_attribute,
|
||||||
|
draw_atlas_size_uniform: draw_atlas_size_uniform,
|
||||||
|
draw_glyph_descriptors_uniform: draw_glyph_descriptors_uniform,
|
||||||
|
draw_image_info_uniform: draw_image_info_uniform,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +120,57 @@ impl Rasterizer {
|
||||||
coverage_buffer: &CoverageBuffer,
|
coverage_buffer: &CoverageBuffer,
|
||||||
texture: &Texture)
|
texture: &Texture)
|
||||||
-> Result<Event, ()> {
|
-> Result<Event, ()> {
|
||||||
// TODO(pcwalton)
|
unsafe {
|
||||||
|
gl::UseProgram(self.draw_program);
|
||||||
|
gl::BindVertexArray(self.draw_vertex_array);
|
||||||
|
|
||||||
|
// Set up the buffer layout.
|
||||||
|
gl::BindBuffer(gl::ARRAY_BUFFER, glyph_buffers.vertices);
|
||||||
|
gl::VertexAttribIPointer(self.draw_position_attribute as GLuint,
|
||||||
|
2,
|
||||||
|
gl::SHORT,
|
||||||
|
mem::size_of::<Vertex>() as GLint,
|
||||||
|
0 as *const GLvoid);
|
||||||
|
gl::VertexAttribIPointer(self.draw_image_index_attribute as GLuint,
|
||||||
|
1,
|
||||||
|
gl::UNSIGNED_SHORT,
|
||||||
|
mem::size_of::<Vertex>() as GLint,
|
||||||
|
mem::size_of::<(i16, i16)>() as *const GLvoid);
|
||||||
|
gl::EnableVertexAttribArray(self.draw_position_attribute as GLuint);
|
||||||
|
gl::EnableVertexAttribArray(self.draw_image_index_attribute as GLuint);
|
||||||
|
|
||||||
|
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, glyph_buffers.indices);
|
||||||
|
|
||||||
|
gl::BindBufferBase(gl::UNIFORM_BUFFER, 1, glyph_buffers.descriptors);
|
||||||
|
gl::BindBufferBase(gl::UNIFORM_BUFFER, 2, batch.images);
|
||||||
|
gl::UniformBlockBinding(self.draw_program, self.draw_glyph_descriptors_uniform, 1);
|
||||||
|
gl::UniformBlockBinding(self.draw_program, self.draw_image_info_uniform, 2);
|
||||||
|
|
||||||
|
gl::Uniform2ui(self.draw_atlas_size_uniform,
|
||||||
|
atlas_rect.size.width,
|
||||||
|
atlas_rect.size.height);
|
||||||
|
|
||||||
|
gl::PatchParameteri(gl::PATCH_VERTICES, 3);
|
||||||
|
|
||||||
|
// Use blending on our floating point framebuffer to accumulate coverage.
|
||||||
|
gl::Enable(gl::BLEND);
|
||||||
|
gl::BlendEquation(gl::FUNC_ADD);
|
||||||
|
gl::BlendFunc(gl::ONE, gl::ONE);
|
||||||
|
|
||||||
|
// Enable backface culling. See comments in `draw.tcs.glsl` for more information
|
||||||
|
// regarding why this is necessary.
|
||||||
|
gl::CullFace(gl::BACK);
|
||||||
|
gl::FrontFace(gl::CCW);
|
||||||
|
gl::Enable(gl::CULL_FACE);
|
||||||
|
|
||||||
|
// Now draw the glyph ranges.
|
||||||
|
debug_assert!(batch.counts.len() == batch.start_indices.len());
|
||||||
|
gl::MultiDrawElements(gl::PATCHES,
|
||||||
|
batch.counts.as_ptr(),
|
||||||
|
gl::UNSIGNED_INT,
|
||||||
|
batch.start_indices.as_ptr() as *const *const GLvoid,
|
||||||
|
batch.counts.len() as GLsizei);
|
||||||
|
}
|
||||||
|
|
||||||
let atlas_rect_uniform = [
|
let atlas_rect_uniform = [
|
||||||
atlas_rect.origin.x,
|
atlas_rect.origin.x,
|
||||||
|
|
Loading…
Reference in New Issue