This commit is contained in:
Patrick Walton 2019-01-15 11:42:25 -08:00
parent 5bbb5a1b74
commit 0097ffab19
9 changed files with 113 additions and 41 deletions

View File

@ -1,6 +1,6 @@
#version 330 #version 330
// pathfinder/demo2/cover.fs.glsl // pathfinder/demo3/resources/shaders/mask_tile.fs.glsl
// //
// Copyright © 2018 The Pathfinder Project Developers. // Copyright © 2018 The Pathfinder Project Developers.
// //

View File

@ -1,6 +1,6 @@
#version 330 #version 330
// pathfinder/demo2/cover.vs.glsl // pathfinder/demo3/resources/shaders/mask_tile.vs.glsl
// //
// Copyright © 2018 The Pathfinder Project Developers. // Copyright © 2018 The Pathfinder Project Developers.
// //

View File

@ -1,8 +1,8 @@
#version 330 #version 330
// pathfinder/demo2/opaque.vs.glsl // pathfinder/demo3/resources/shaders/solid_tile.vs.glsl
// //
// Copyright © 2018 The Pathfinder Project Developers. // Copyright © 2019 The Pathfinder Project Developers.
// //
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license

View File

@ -12,6 +12,8 @@ use clap::{App, Arg};
use euclid::Size2D; use euclid::Size2D;
use gl::types::{GLchar, GLfloat, GLint, GLsizei, GLsizeiptr, GLuint, GLvoid}; use gl::types::{GLchar, GLfloat, GLint, GLsizei, GLsizeiptr, GLuint, GLvoid};
use jemallocator; use jemallocator;
use pathfinder_geometry::point::Point2DF32;
use pathfinder_geometry::transform::Transform2DF32;
use pathfinder_renderer::builder::SceneBuilder; use pathfinder_renderer::builder::SceneBuilder;
use pathfinder_renderer::gpu_data::{Batch, BuiltScene, SolidTileScenePrimitive}; use pathfinder_renderer::gpu_data::{Batch, BuiltScene, SolidTileScenePrimitive};
use pathfinder_renderer::paint::ObjectShader; use pathfinder_renderer::paint::ObjectShader;
@ -52,7 +54,8 @@ const FILL_COLORS_TEXTURE_WIDTH: u32 = 256;
const FILL_COLORS_TEXTURE_HEIGHT: u32 = 256; const FILL_COLORS_TEXTURE_HEIGHT: u32 = 256;
fn main() { fn main() {
let scene = load_scene(); let options = Options::get();
let base_scene = load_scene(&options);
let sdl_context = sdl2::init().unwrap(); let sdl_context = sdl2::init().unwrap();
let sdl_video = sdl_context.video().unwrap(); let sdl_video = sdl_context.video().unwrap();
@ -68,7 +71,7 @@ fn main() {
.build() .build()
.unwrap(); .unwrap();
let gl_context = window.gl_create_context().unwrap(); let _gl_context = window.gl_create_context().unwrap();
gl::load_with(|name| sdl_video.gl_get_proc_address(name) as *const _); gl::load_with(|name| sdl_video.gl_get_proc_address(name) as *const _);
let mut sdl_event_pump = sdl_context.event_pump().unwrap(); let mut sdl_event_pump = sdl_context.event_pump().unwrap();
@ -77,11 +80,19 @@ fn main() {
let (drawable_width, drawable_height) = window.drawable_size(); let (drawable_width, drawable_height) = window.drawable_size();
let mut renderer = Renderer::new(&Size2D::new(drawable_width, drawable_height)); let mut renderer = Renderer::new(&Size2D::new(drawable_width, drawable_height));
let mut scale = 1.0;
while !exit { while !exit {
let mut scene = base_scene.clone();
scene.transform(&Transform2DF32::from_scale(&Point2DF32::new(scale, scale)));
scale -= 0.1;
let built_scene = build_scene(&scene, &options);
unsafe { unsafe {
gl::ClearColor(1.0, 1.0, 1.0, 1.0); gl::ClearColor(1.0, 1.0, 1.0, 1.0);
gl::Clear(gl::COLOR_BUFFER_BIT); gl::Clear(gl::COLOR_BUFFER_BIT);
renderer.render_scene(&scene); renderer.render_scene(&built_scene);
} }
window.gl_swap_window(); window.gl_swap_window();
@ -97,37 +108,48 @@ fn main() {
} }
} }
fn load_scene() -> BuiltScene { struct Options {
let matches = App::new("tile-svg") jobs: Option<usize>,
.arg( input_path: PathBuf,
Arg::with_name("jobs") }
.short("j")
.long("jobs")
.value_name("THREADS")
.takes_value(true)
.help("Number of threads to use"),
)
.arg(
Arg::with_name("INPUT")
.help("Path to the SVG file to render")
.required(true)
.index(1),
)
.get_matches();
let jobs: Option<usize> = matches
.value_of("jobs")
.map(|string| string.parse().unwrap());
let input_path = PathBuf::from(matches.value_of("INPUT").unwrap());
// Set up Rayon. impl Options {
let mut thread_pool_builder = ThreadPoolBuilder::new(); fn get() -> Options {
if let Some(jobs) = jobs { let matches = App::new("tile-svg")
thread_pool_builder = thread_pool_builder.num_threads(jobs); .arg(
Arg::with_name("jobs")
.short("j")
.long("jobs")
.value_name("THREADS")
.takes_value(true)
.help("Number of threads to use"),
)
.arg(
Arg::with_name("INPUT")
.help("Path to the SVG file to render")
.required(true)
.index(1),
)
.get_matches();
let jobs: Option<usize> = matches
.value_of("jobs")
.map(|string| string.parse().unwrap());
let input_path = PathBuf::from(matches.value_of("INPUT").unwrap());
// Set up Rayon.
let mut thread_pool_builder = ThreadPoolBuilder::new();
if let Some(jobs) = jobs {
thread_pool_builder = thread_pool_builder.num_threads(jobs);
}
thread_pool_builder.build_global().unwrap();
Options { jobs, input_path }
} }
thread_pool_builder.build_global().unwrap(); }
fn load_scene(options: &Options) -> Scene {
// Build scene. // Build scene.
let usvg = Tree::from_file(&input_path, &UsvgOptions::default()).unwrap(); let usvg = Tree::from_file(&options.input_path, &UsvgOptions::default()).unwrap();
let scene = Scene::from_tree(usvg); let scene = Scene::from_tree(usvg);
println!( println!(
@ -140,20 +162,23 @@ fn load_scene() -> BuiltScene {
scene.paints.len() scene.paints.len()
); );
scene
}
fn build_scene(scene: &Scene, options: &Options) -> BuiltScene {
let (mut elapsed_object_build_time, mut elapsed_scene_build_time) = (0.0, 0.0); let (mut elapsed_object_build_time, mut elapsed_scene_build_time) = (0.0, 0.0);
let mut built_scene = BuiltScene::new(&scene.view_box);
let z_buffer = ZBuffer::new(&scene.view_box); let z_buffer = ZBuffer::new(&scene.view_box);
let start_time = Instant::now(); let start_time = Instant::now();
let built_objects = match jobs { let built_objects = match options.jobs {
Some(1) => scene.build_objects_sequentially(&z_buffer), Some(1) => scene.build_objects_sequentially(&z_buffer),
_ => scene.build_objects(&z_buffer), _ => scene.build_objects(&z_buffer),
}; };
elapsed_object_build_time += duration_to_ms(&(Instant::now() - start_time)); elapsed_object_build_time += duration_to_ms(&(Instant::now() - start_time));
let start_time = Instant::now(); let start_time = Instant::now();
built_scene = BuiltScene::new(&scene.view_box); let mut built_scene = BuiltScene::new(&scene.view_box);
built_scene.shaders = scene.build_shaders(); built_scene.shaders = scene.build_shaders();
let mut scene_builder = SceneBuilder::new(built_objects, z_buffer, &scene.view_box); let mut scene_builder = SceneBuilder::new(built_objects, z_buffer, &scene.view_box);
built_scene.solid_tiles = scene_builder.build_solid_tiles(); built_scene.solid_tiles = scene_builder.build_solid_tiles();
@ -191,6 +216,7 @@ struct Renderer {
solid_tile_program: SolidTileProgram, solid_tile_program: SolidTileProgram,
mask_tile_program: MaskTileProgram, mask_tile_program: MaskTileProgram,
area_lut_texture: Texture, area_lut_texture: Texture,
#[allow(dead_code)]
quad_vertex_positions_buffer: Buffer, quad_vertex_positions_buffer: Buffer,
fill_vertex_array: FillVertexArray, fill_vertex_array: FillVertexArray,
mask_tile_vertex_array: MaskTileVertexArray, mask_tile_vertex_array: MaskTileVertexArray,
@ -676,7 +702,9 @@ impl Uniform {
struct Program { struct Program {
gl_program: GLuint, gl_program: GLuint,
#[allow(dead_code)]
vertex_shader: Shader, vertex_shader: Shader,
#[allow(dead_code)]
fragment_shader: Shader, fragment_shader: Shader,
} }

View File

@ -81,6 +81,17 @@ impl LineSegmentF32 {
LineSegmentF32(mid_mid.as_f64x2().interleave(to_to.as_f64x2()).0.as_f32x4())) LineSegmentF32(mid_mid.as_f64x2().interleave(to_to.as_f64x2()).0.as_f32x4()))
} }
// Returns the left segment first, followed by the right segment.
#[inline]
pub fn split_at_x(&self, x: f32) -> (LineSegmentF32, LineSegmentF32) {
let (min_part, max_part) = self.split(self.solve_t_for_x(x));
if min_part.from_x() < max_part.from_x() {
(min_part, max_part)
} else {
(max_part, min_part)
}
}
// Returns the upper segment first, followed by the lower segment. // Returns the upper segment first, followed by the lower segment.
#[inline] #[inline]
pub fn split_at_y(&self, y: f32) -> (LineSegmentF32, LineSegmentF32) { pub fn split_at_y(&self, y: f32) -> (LineSegmentF32, LineSegmentF32) {
@ -121,6 +132,16 @@ impl LineSegmentF32 {
} }
} }
#[inline]
pub fn min_x(&self) -> f32 {
f32::min(self.from_x(), self.to_x())
}
#[inline]
pub fn max_x(&self) -> f32 {
f32::max(self.from_x(), self.to_x())
}
#[inline] #[inline]
pub fn min_y(&self) -> f32 { pub fn min_y(&self) -> f32 {
f32::min(self.from_y(), self.to_y()) f32::min(self.from_y(), self.to_y())

View File

@ -12,17 +12,19 @@
use crate::point::Point2DF32; use crate::point::Point2DF32;
use crate::segment::{Segment, SegmentFlags, SegmentKind}; use crate::segment::{Segment, SegmentFlags, SegmentKind};
use crate::transform::Transform2DF32;
use euclid::{Point2D, Rect}; use euclid::{Point2D, Rect};
use lyon_path::PathEvent; use lyon_path::PathEvent;
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
use std::mem; use std::mem;
#[derive(Debug)] #[derive(Clone, Debug)]
pub struct Outline { pub struct Outline {
pub contours: Vec<Contour>, pub contours: Vec<Contour>,
bounds: Rect<f32>, bounds: Rect<f32>,
} }
#[derive(Clone)]
pub struct Contour { pub struct Contour {
points: Vec<Point2DF32>, points: Vec<Point2DF32>,
flags: Vec<PointFlags>, flags: Vec<PointFlags>,
@ -118,6 +120,11 @@ impl Outline {
pub fn bounds(&self) -> &Rect<f32> { pub fn bounds(&self) -> &Rect<f32> {
&self.bounds &self.bounds
} }
#[inline]
pub fn transform(&mut self, transform: &Transform2DF32) {
self.contours.iter_mut().for_each(|contour| contour.transform(transform));
}
} }
impl Contour { impl Contour {
@ -261,6 +268,13 @@ impl Contour {
point_index + 1 point_index + 1
} }
} }
#[inline]
pub fn transform(&mut self, transform: &Transform2DF32) {
for point in &mut self.points {
*point = transform.transform_point(point)
}
}
} }
impl Debug for Contour { impl Debug for Contour {

View File

@ -59,6 +59,7 @@ pub struct TileObjectPrimitive {
pub backdrop: i16, pub backdrop: i16,
} }
// FIXME(pcwalton): Move `subpx` before `px` and remove `repr(packed)`.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
#[repr(packed)] #[repr(packed)]
pub struct FillBatchPrimitive { pub struct FillBatchPrimitive {

View File

@ -17,9 +17,10 @@ use crate::z_buffer::ZBuffer;
use euclid::Rect; use euclid::Rect;
use hashbrown::HashMap; use hashbrown::HashMap;
use pathfinder_geometry::outline::Outline; use pathfinder_geometry::outline::Outline;
use pathfinder_geometry::transform::Transform2DF32;
use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator}; use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
#[derive(Debug)] #[derive(Clone, Debug)]
pub struct Scene { pub struct Scene {
pub objects: Vec<PathObject>, pub objects: Vec<PathObject>,
pub paints: Vec<Paint>, pub paints: Vec<Paint>,
@ -96,9 +97,16 @@ impl Scene {
}) })
.collect() .collect()
} }
pub fn transform(&mut self, transform: &Transform2DF32) {
// TODO(pcwalton): Transform bounds?
for object in &mut self.objects {
object.outline.transform(transform)
}
}
} }
#[derive(Debug)] #[derive(Clone, Debug)]
pub struct PathObject { pub struct PathObject {
outline: Outline, outline: Outline,
paint: PaintId, paint: PaintId,

View File

@ -177,7 +177,7 @@ impl<'o, 'z> Tiler<'o, 'z> {
} }
// Do final subtile fill, if necessary. // Do final subtile fill, if necessary.
debug_assert!(current_tile_x == segment_tile_x); debug_assert_eq!(current_tile_x, segment_tile_x);
debug_assert!(current_tile_x < self.built_object.tile_rect.max_x()); debug_assert!(current_tile_x < self.built_object.tile_rect.max_x());
let segment_subtile_x = let segment_subtile_x =
segment_x - (i32::from(current_tile_x) * TILE_WIDTH as i32) as f32; segment_x - (i32::from(current_tile_x) * TILE_WIDTH as i32) as f32;