Pack vertices a little tighter
This commit is contained in:
parent
3b92ed0798
commit
4471a74144
|
@ -15,6 +15,7 @@ precision highp float;
|
|||
uniform vec2 uFramebufferSize;
|
||||
uniform vec2 uTileSize;
|
||||
uniform vec2 uStencilTextureSize;
|
||||
uniform vec2 uViewBoxOrigin;
|
||||
|
||||
in vec2 aTessCoord;
|
||||
in vec2 aTileOrigin;
|
||||
|
@ -33,7 +34,7 @@ vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth) {
|
|||
|
||||
void main() {
|
||||
uint tileIndex = uint(gl_InstanceID);
|
||||
vec2 position = aTileOrigin + uTileSize * aTessCoord;
|
||||
vec2 position = (aTileOrigin + aTessCoord) * uTileSize + uViewBoxOrigin;
|
||||
vec2 texCoord = computeTileOffset(tileIndex, uStencilTextureSize.x) + aTessCoord * uTileSize;
|
||||
vTexCoord = texCoord / uStencilTextureSize;
|
||||
vBackdrop = aBackdrop;
|
||||
|
|
|
@ -54,9 +54,15 @@ export class Point2D {
|
|||
}
|
||||
}
|
||||
|
||||
export interface Size2D {
|
||||
export class Size2D {
|
||||
width: number;
|
||||
height: number;
|
||||
|
||||
constructor(width: number, height: number) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
Object.freeze(this);
|
||||
}
|
||||
}
|
||||
|
||||
export class Rect {
|
||||
|
|
|
@ -14,6 +14,7 @@ precision highp float;
|
|||
|
||||
uniform vec2 uFramebufferSize;
|
||||
uniform vec2 uTileSize;
|
||||
uniform vec2 uViewBoxOrigin;
|
||||
|
||||
in vec2 aTessCoord;
|
||||
in vec2 aTileOrigin;
|
||||
|
@ -22,7 +23,7 @@ in vec4 aColor;
|
|||
out vec4 vColor;
|
||||
|
||||
void main() {
|
||||
vec2 position = aTileOrigin + uTileSize * aTessCoord;
|
||||
vec2 position = (aTileOrigin + aTessCoord) * uTileSize + uViewBoxOrigin;
|
||||
vColor = aColor;
|
||||
gl_Position = vec4((position / uFramebufferSize * 2.0 - 1.0) * vec2(1.0, -1.0), 0.0, 1.0);
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ import OPAQUE_FRAGMENT_SHADER_SOURCE from "./opaque.fs.glsl";
|
|||
import STENCIL_VERTEX_SHADER_SOURCE from "./stencil.vs.glsl";
|
||||
import STENCIL_FRAGMENT_SHADER_SOURCE from "./stencil.fs.glsl";
|
||||
import AREA_LUT from "../resources/textures/area-lut.png";
|
||||
import {Matrix2D, Size2D} from "./geometry";
|
||||
import {Matrix2D, Size2D, Rect, Point2D} from "./geometry";
|
||||
import {SVGPath, TILE_SIZE} from "./tiling";
|
||||
import {staticCast, unwrapNull} from "./util";
|
||||
|
||||
|
@ -34,8 +34,8 @@ const QUAD_VERTEX_POSITIONS: Uint8Array = new Uint8Array([
|
|||
]);
|
||||
|
||||
const FILL_INSTANCE_SIZE: number = 20;
|
||||
const SOLID_TILE_INSTANCE_SIZE: number = 12;
|
||||
const MASK_TILE_INSTANCE_SIZE: number = 16;
|
||||
const SOLID_TILE_INSTANCE_SIZE: number = 8;
|
||||
const MASK_TILE_INSTANCE_SIZE: number = 12;
|
||||
|
||||
interface Color {
|
||||
r: number;
|
||||
|
@ -58,10 +58,11 @@ class App {
|
|||
private stencilFramebuffer: WebGLFramebuffer;
|
||||
private fillProgram: Program<'FramebufferSize' | 'TileSize' | 'AreaLUT',
|
||||
'TessCoord' | 'From' | 'To' | 'TileIndex'>;
|
||||
private solidTileProgram: Program<'FramebufferSize' | 'TileSize',
|
||||
private solidTileProgram: Program<'FramebufferSize' | 'TileSize' | 'ViewBoxOrigin',
|
||||
'TessCoord' | 'TileOrigin' | 'Color'>;
|
||||
private maskTileProgram:
|
||||
Program<'FramebufferSize' | 'TileSize' | 'StencilTexture' | 'StencilTextureSize',
|
||||
Program<'FramebufferSize' | 'TileSize' | 'StencilTexture' | 'StencilTextureSize' |
|
||||
'ViewBoxOrigin',
|
||||
'TessCoord' | 'TileOrigin' | 'Backdrop' | 'Color'>;
|
||||
private quadVertexBuffer: WebGLBuffer;
|
||||
private fillVertexBuffer: WebGLBuffer;
|
||||
|
@ -71,6 +72,8 @@ class App {
|
|||
private maskTileVertexBuffer: WebGLBuffer;
|
||||
private maskVertexArray: WebGLVertexArrayObject;
|
||||
|
||||
private viewBox: Rect;
|
||||
|
||||
private fillPrimitiveCount: number;
|
||||
private solidTileCount: number;
|
||||
private maskTileCount: number;
|
||||
|
@ -136,7 +139,8 @@ class App {
|
|||
'FramebufferSize',
|
||||
'TileSize',
|
||||
'StencilTexture',
|
||||
'StencilTextureSize'
|
||||
'StencilTextureSize',
|
||||
'ViewBoxOrigin',
|
||||
],
|
||||
[
|
||||
'TessCoord',
|
||||
|
@ -150,7 +154,7 @@ class App {
|
|||
const solidTileProgram = new Program(gl,
|
||||
OPAQUE_VERTEX_SHADER_SOURCE,
|
||||
OPAQUE_FRAGMENT_SHADER_SOURCE,
|
||||
['FramebufferSize', 'TileSize'],
|
||||
['FramebufferSize', 'TileSize', 'ViewBoxOrigin'],
|
||||
['TessCoord', 'TileOrigin', 'Color']);
|
||||
this.solidTileProgram = solidTileProgram;
|
||||
|
||||
|
@ -224,7 +228,7 @@ class App {
|
|||
gl.bindBuffer(gl.ARRAY_BUFFER, this.solidTileVertexBuffer);
|
||||
gl.vertexAttribPointer(solidTileProgram.attributes.TileOrigin,
|
||||
2,
|
||||
gl.FLOAT,
|
||||
gl.SHORT,
|
||||
false,
|
||||
SOLID_TILE_INSTANCE_SIZE,
|
||||
0);
|
||||
|
@ -234,7 +238,7 @@ class App {
|
|||
gl.UNSIGNED_BYTE,
|
||||
true,
|
||||
SOLID_TILE_INSTANCE_SIZE,
|
||||
8);
|
||||
4);
|
||||
gl.vertexAttribDivisor(solidTileProgram.attributes.Color, 1);
|
||||
gl.enableVertexAttribArray(solidTileProgram.attributes.TessCoord);
|
||||
gl.enableVertexAttribArray(solidTileProgram.attributes.TileOrigin);
|
||||
|
@ -254,7 +258,7 @@ class App {
|
|||
gl.bindBuffer(gl.ARRAY_BUFFER, this.maskTileVertexBuffer);
|
||||
gl.vertexAttribPointer(maskTileProgram.attributes.TileOrigin,
|
||||
2,
|
||||
gl.FLOAT,
|
||||
gl.SHORT,
|
||||
false,
|
||||
MASK_TILE_INSTANCE_SIZE,
|
||||
0);
|
||||
|
@ -264,20 +268,22 @@ class App {
|
|||
gl.FLOAT,
|
||||
false,
|
||||
MASK_TILE_INSTANCE_SIZE,
|
||||
8);
|
||||
4);
|
||||
gl.vertexAttribDivisor(maskTileProgram.attributes.Backdrop, 1);
|
||||
gl.vertexAttribPointer(maskTileProgram.attributes.Color,
|
||||
4,
|
||||
gl.UNSIGNED_BYTE,
|
||||
true,
|
||||
MASK_TILE_INSTANCE_SIZE,
|
||||
12);
|
||||
8);
|
||||
gl.vertexAttribDivisor(maskTileProgram.attributes.Color, 1);
|
||||
gl.enableVertexAttribArray(maskTileProgram.attributes.TessCoord);
|
||||
gl.enableVertexAttribArray(maskTileProgram.attributes.TileOrigin);
|
||||
gl.enableVertexAttribArray(maskTileProgram.attributes.Backdrop);
|
||||
gl.enableVertexAttribArray(maskTileProgram.attributes.Color);
|
||||
|
||||
this.viewBox = new Rect(new Point2D(0.0, 0.0), new Size2D(0.0, 0.0));
|
||||
|
||||
// Set up event handlers.
|
||||
this.canvas.addEventListener('click', event => this.onClick(event), false);
|
||||
|
||||
|
@ -289,6 +295,8 @@ class App {
|
|||
redraw(): void {
|
||||
const gl = this.gl, canvas = this.canvas;
|
||||
|
||||
console.log("viewBox", this.viewBox);
|
||||
|
||||
// Start timer.
|
||||
let timerQuery = null;
|
||||
if (this.disjointTimerQueryExt != null) {
|
||||
|
@ -333,6 +341,9 @@ class App {
|
|||
framebufferSize.width,
|
||||
framebufferSize.height);
|
||||
gl.uniform2f(this.solidTileProgram.uniforms.TileSize, TILE_SIZE.width, TILE_SIZE.height);
|
||||
gl.uniform2f(this.solidTileProgram.uniforms.ViewBoxOrigin,
|
||||
this.viewBox.origin.x,
|
||||
this.viewBox.origin.y);
|
||||
gl.disable(gl.BLEND);
|
||||
gl.drawArraysInstanced(gl.TRIANGLE_FAN, 0, 4, this.solidTileCount);
|
||||
|
||||
|
@ -349,6 +360,9 @@ class App {
|
|||
gl.uniform2f(this.maskTileProgram.uniforms.StencilTextureSize,
|
||||
STENCIL_FRAMEBUFFER_SIZE.width,
|
||||
STENCIL_FRAMEBUFFER_SIZE.height);
|
||||
gl.uniform2f(this.maskTileProgram.uniforms.ViewBoxOrigin,
|
||||
this.viewBox.origin.x,
|
||||
this.viewBox.origin.y);
|
||||
gl.blendEquation(gl.FUNC_ADD);
|
||||
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
||||
gl.enable(gl.BLEND);
|
||||
|
@ -402,11 +416,20 @@ class App {
|
|||
const arrayBuffer = staticCast(reader.result, ArrayBuffer);
|
||||
const root = new RIFFChunk(new DataView(arrayBuffer));
|
||||
for (const subchunk of root.subchunks()) {
|
||||
const id = subchunk.stringID();
|
||||
if (id === 'head') {
|
||||
const headerData = subchunk.contents();
|
||||
this.viewBox = new Rect(new Point2D(headerData.getFloat32(0, true),
|
||||
headerData.getFloat32(4, true)),
|
||||
new Size2D(headerData.getFloat32(8, true),
|
||||
headerData.getFloat32(12, true)));
|
||||
continue;
|
||||
}
|
||||
|
||||
let bindPoint, buffer;
|
||||
let countFieldName: 'fillPrimitiveCount' | 'totalTileCount' | 'solidTileCount' |
|
||||
'maskTileCount';
|
||||
let instanceSize;
|
||||
const id = subchunk.stringID();
|
||||
switch (id) {
|
||||
case 'fill':
|
||||
bindPoint = gl.ARRAY_BUFFER;
|
||||
|
|
|
@ -74,7 +74,7 @@ fn main() {
|
|||
println!("Scene bounds: {:?}", scene.bounds);
|
||||
|
||||
let start_time = Instant::now();
|
||||
let mut built_scene = BuiltScene::new();
|
||||
let mut built_scene = BuiltScene::new(&scene.view_box);
|
||||
for _ in 0..runs {
|
||||
built_scene = scene.build();
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ struct Scene {
|
|||
objects: Vec<PathObject>,
|
||||
styles: Vec<ComputedStyle>,
|
||||
bounds: Rect<f32>,
|
||||
view_box: Option<Rect<f32>>,
|
||||
view_box: Rect<f32>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -154,7 +154,7 @@ struct StyleId(u32);
|
|||
|
||||
impl Scene {
|
||||
fn new() -> Scene {
|
||||
Scene { objects: vec![], styles: vec![], bounds: Rect::zero(), view_box: None }
|
||||
Scene { objects: vec![], styles: vec![], bounds: Rect::zero(), view_box: Rect::zero() }
|
||||
}
|
||||
|
||||
fn from_path(path: &Path) -> Scene {
|
||||
|
@ -213,7 +213,7 @@ impl Scene {
|
|||
elements.next().unwrap()),
|
||||
Size2D::new(elements.next().unwrap(),
|
||||
elements.next().unwrap()));
|
||||
scene.view_box = Some(global_transform.transform_rect(&view_box));
|
||||
scene.view_box = global_transform.transform_rect(&view_box);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -311,7 +311,7 @@ impl Scene {
|
|||
}
|
||||
|
||||
fn build(&self) -> BuiltScene {
|
||||
let mut built_scene = BuiltScene::new();
|
||||
let mut built_scene = BuiltScene::new(&self.view_box);
|
||||
for object in &self.objects {
|
||||
let mut tiler = Tiler::from_outline(&object.outline,
|
||||
object.color,
|
||||
|
@ -935,7 +935,7 @@ struct Tiler<'o, 'p> {
|
|||
fill_color: ColorU,
|
||||
built_scene: &'p mut BuiltScene,
|
||||
|
||||
view_box: Option<Rect<f32>>,
|
||||
view_box: Rect<f32>,
|
||||
|
||||
point_queue: SortedVector<QueuedEndpoint>,
|
||||
active_edges: SortedVector<ActiveEdge>,
|
||||
|
@ -948,7 +948,7 @@ struct Tiler<'o, 'p> {
|
|||
impl<'o, 'p> Tiler<'o, 'p> {
|
||||
fn from_outline(outline: &'o Outline,
|
||||
fill_color: ColorU,
|
||||
view_box: &Option<Rect<f32>>,
|
||||
view_box: &Rect<f32>,
|
||||
built_scene: &'p mut BuiltScene)
|
||||
-> Tiler<'o, 'p> {
|
||||
Tiler {
|
||||
|
@ -974,13 +974,11 @@ impl<'o, 'p> Tiler<'o, 'p> {
|
|||
|
||||
// Clip to the view box.
|
||||
let mut bounds = self.outline.bounds;
|
||||
if let Some(view_box) = self.view_box {
|
||||
let max_x = f32::min(view_box.max_x(), bounds.max_x());
|
||||
let max_y = f32::min(view_box.max_y(), bounds.max_y());
|
||||
bounds.origin.x = f32::max(view_box.origin.x, bounds.origin.x);
|
||||
let max_x = f32::min(self.view_box.max_x(), bounds.max_x());
|
||||
let max_y = f32::min(self.view_box.max_y(), bounds.max_y());
|
||||
bounds.origin.x = f32::max(self.view_box.origin.x, bounds.origin.x);
|
||||
bounds.size.width = f32::max(0.0, max_x - bounds.origin.x);
|
||||
bounds.size.height = f32::max(0.0, max_y - bounds.origin.y);
|
||||
}
|
||||
|
||||
self.active_edges.clear();
|
||||
|
||||
|
@ -991,11 +989,8 @@ impl<'o, 'p> Tiler<'o, 'p> {
|
|||
|
||||
let tiles_across = ((strip_right_extent - strip_origin.x) / TILE_WIDTH) as usize;
|
||||
|
||||
let view_box_origin_y = match self.view_box {
|
||||
Some(view_box) => view_box.origin.y,
|
||||
None => 0.0,
|
||||
};
|
||||
let mut tile_index_y = (f32::floor(view_box_origin_y / TILE_HEIGHT) * TILE_HEIGHT) as i16;
|
||||
let mut tile_index_y = (f32::floor(self.view_box.origin.y / TILE_HEIGHT) * TILE_HEIGHT)
|
||||
as i16;
|
||||
|
||||
self.strip_tiles.clear();
|
||||
self.strip_tiles.reserve(tiles_across);
|
||||
|
@ -1124,6 +1119,7 @@ impl<'o, 'p> Tiler<'o, 'p> {
|
|||
|
||||
let contour = &outline.contours[point_index.contour_index];
|
||||
|
||||
// TODO(pcwalton): Could use a bitset of processed edges…
|
||||
let prev_endpoint_index = contour.prev_endpoint_index_of(point_index.point_index);
|
||||
let next_endpoint_index = contour.next_endpoint_index_of(point_index.point_index);
|
||||
if contour.point_is_logically_above(point_index.point_index, prev_endpoint_index) {
|
||||
|
@ -1166,7 +1162,6 @@ impl<'o, 'p> Tiler<'o, 'p> {
|
|||
#[inline(never)]
|
||||
fn flush_tiles(&mut self, tile_index_y: i16) {
|
||||
// Flush tiles.
|
||||
let first_tile_index = self.built_scene.mask_tiles.len() as u32;
|
||||
for (tile_index_x, tile) in self.strip_tiles.iter().enumerate() {
|
||||
if self.used_strip_tiles.contains(tile_index_x) {
|
||||
self.built_scene.mask_tiles.push(*tile);
|
||||
|
@ -1286,6 +1281,7 @@ fn process_active_edge(active_edge: &mut Segment,
|
|||
|
||||
#[derive(Debug)]
|
||||
struct BuiltScene {
|
||||
view_box: Rect<f32>,
|
||||
fills: Vec<FillPrimitive>,
|
||||
solid_tiles: Vec<SolidTilePrimitive>,
|
||||
mask_tiles: Vec<MaskTilePrimitive>,
|
||||
|
@ -1322,23 +1318,32 @@ struct ColorU {
|
|||
}
|
||||
|
||||
impl BuiltScene {
|
||||
fn new() -> BuiltScene {
|
||||
BuiltScene { fills: vec![], solid_tiles: vec![], mask_tiles: vec![] }
|
||||
fn new(view_box: &Rect<f32>) -> BuiltScene {
|
||||
BuiltScene { view_box: *view_box, fills: vec![], solid_tiles: vec![], mask_tiles: vec![] }
|
||||
}
|
||||
|
||||
fn write<W>(&self, writer: &mut W) -> io::Result<()> where W: Write {
|
||||
writer.write_all(b"RIFF")?;
|
||||
|
||||
let header_size = 4 * 4;
|
||||
let fill_size = self.fills.len() * mem::size_of::<FillPrimitive>();
|
||||
let solid_tiles_size = self.solid_tiles.len() * mem::size_of::<SolidTilePrimitive>();
|
||||
let mask_tiles_size = self.mask_tiles.len() * mem::size_of::<MaskTilePrimitive>();
|
||||
writer.write_u32::<LittleEndian>((4 +
|
||||
8 + header_size +
|
||||
8 + fill_size +
|
||||
8 + solid_tiles_size +
|
||||
8 + mask_tiles_size) as u32)?;
|
||||
|
||||
writer.write_all(b"PF3S")?;
|
||||
|
||||
writer.write_all(b"head")?;
|
||||
writer.write_u32::<LittleEndian>(header_size as u32)?;
|
||||
writer.write_f32::<LittleEndian>(self.view_box.origin.x)?;
|
||||
writer.write_f32::<LittleEndian>(self.view_box.origin.y)?;
|
||||
writer.write_f32::<LittleEndian>(self.view_box.size.width)?;
|
||||
writer.write_f32::<LittleEndian>(self.view_box.size.height)?;
|
||||
|
||||
writer.write_all(b"fill")?;
|
||||
writer.write_u32::<LittleEndian>(fill_size as u32)?;
|
||||
for fill_primitive in &self.fills {
|
||||
|
|
Loading…
Reference in New Issue