Do scene building just-in-time on a per-outline basis as part of tiling

This commit is contained in:
Patrick Walton 2019-02-02 11:36:42 -08:00
parent f19757e4cf
commit b0e91369e5
3 changed files with 49 additions and 98 deletions

View File

@ -16,7 +16,7 @@ use pathfinder_geometry::transform3d::{Perspective, Transform3DF32};
use pathfinder_gl::renderer::Renderer; use pathfinder_gl::renderer::Renderer;
use pathfinder_renderer::builder::SceneBuilder; use pathfinder_renderer::builder::SceneBuilder;
use pathfinder_renderer::gpu_data::BuiltScene; use pathfinder_renderer::gpu_data::BuiltScene;
use pathfinder_renderer::scene::Scene; use pathfinder_renderer::scene::{BuildTransform, Scene};
use pathfinder_renderer::z_buffer::ZBuffer; use pathfinder_renderer::z_buffer::ZBuffer;
use pathfinder_svg::SceneExt; use pathfinder_svg::SceneExt;
use rayon::ThreadPoolBuilder; use rayon::ThreadPoolBuilder;
@ -111,7 +111,6 @@ fn main() {
if !first_frame { if !first_frame {
if let Ok(SceneToMainMsg::Render { if let Ok(SceneToMainMsg::Render {
built_scene, built_scene,
prepare_time,
tile_time tile_time
}) = scene_thread_proxy.receiver.recv() { }) = scene_thread_proxy.receiver.recv() {
unsafe { unsafe {
@ -120,7 +119,7 @@ fn main() {
renderer.render_scene(&built_scene); renderer.render_scene(&built_scene);
let rendering_time = renderer.shift_timer_query(); let rendering_time = renderer.shift_timer_query();
renderer.debug_renderer.draw(prepare_time, tile_time, rendering_time); renderer.debug_renderer.draw(tile_time, rendering_time);
} }
} }
} }
@ -214,29 +213,10 @@ impl SceneThread {
match msg { match msg {
MainToSceneMsg::Exit => return, MainToSceneMsg::Exit => return,
MainToSceneMsg::Build(perspective) => { MainToSceneMsg::Build(perspective) => {
// FIXME(pcwalton): Stop cloning scenes? let start_time = Instant::now();
let mut start_time = Instant::now(); let built_scene = build_scene(&self.scene, perspective, &self.options);
let mut scene = self.scene.clone();
match perspective {
Some(perspective) => {
match self.options.jobs {
Some(1) => scene.apply_perspective_sequentially(&perspective),
_ => scene.apply_perspective(&perspective),
}
}
None => scene.prepare(),
}
let prepare_time = Instant::now() - start_time;
start_time = Instant::now();
let built_scene = build_scene(&scene, &self.options);
let tile_time = Instant::now() - start_time; let tile_time = Instant::now() - start_time;
self.sender.send(SceneToMainMsg::Render { built_scene, tile_time }).unwrap();
self.sender.send(SceneToMainMsg::Render {
built_scene,
prepare_time,
tile_time,
}).unwrap();
} }
} }
} }
@ -251,7 +231,6 @@ enum MainToSceneMsg {
enum SceneToMainMsg { enum SceneToMainMsg {
Render { Render {
built_scene: BuiltScene, built_scene: BuiltScene,
prepare_time: Duration,
tile_time: Duration, tile_time: Duration,
} }
} }
@ -324,13 +303,18 @@ fn load_scene(options: &Options, window_size: &Size2D<u32>) -> Scene {
scene scene
} }
fn build_scene(scene: &Scene, options: &Options) -> BuiltScene { fn build_scene(scene: &Scene, perspective: Option<Perspective>, options: &Options) -> BuiltScene {
let z_buffer = ZBuffer::new(&scene.view_box); let z_buffer = ZBuffer::new(&scene.view_box);
let build_transform = match perspective {
None => BuildTransform::None,
Some(perspective) => BuildTransform::Perspective(perspective),
};
let built_objects = panic::catch_unwind(|| { let built_objects = panic::catch_unwind(|| {
match options.jobs { match options.jobs {
Some(1) => scene.build_objects_sequentially(&z_buffer), Some(1) => scene.build_objects_sequentially(&build_transform, &z_buffer),
_ => scene.build_objects(&z_buffer), _ => scene.build_objects(&build_transform, &z_buffer),
} }
}); });

View File

@ -31,7 +31,7 @@ const DEBUG_FONT_VERTEX_SIZE: GLint = 8;
const DEBUG_SOLID_VERTEX_SIZE: GLint = 4; const DEBUG_SOLID_VERTEX_SIZE: GLint = 4;
const WINDOW_WIDTH: i16 = 400; const WINDOW_WIDTH: i16 = 400;
const WINDOW_HEIGHT: i16 = LINE_HEIGHT * 3 + PADDING + 3; const WINDOW_HEIGHT: i16 = LINE_HEIGHT * 2 + PADDING + 2;
const PADDING: i16 = 12; const PADDING: i16 = 12;
const FONT_ASCENT: i16 = 28; const FONT_ASCENT: i16 = 28;
const LINE_HEIGHT: i16 = 42; const LINE_HEIGHT: i16 = 42;
@ -112,26 +112,20 @@ impl DebugRenderer {
self.framebuffer_size = *window_size; self.framebuffer_size = *window_size;
} }
pub fn draw(&self, pub fn draw(&self, tile_time: Duration, rendering_time: Option<Duration>) {
prepare_time: Duration,
tile_time: Duration,
rendering_time: Option<Duration>) {
let window_rect = let window_rect =
Rect::new(Point2D::new(self.framebuffer_size.width as i16 - PADDING - WINDOW_WIDTH, Rect::new(Point2D::new(self.framebuffer_size.width as i16 - PADDING - WINDOW_WIDTH,
self.framebuffer_size.height as i16 - PADDING - WINDOW_HEIGHT), self.framebuffer_size.height as i16 - PADDING - WINDOW_HEIGHT),
Size2D::new(WINDOW_WIDTH, WINDOW_HEIGHT)); Size2D::new(WINDOW_WIDTH, WINDOW_HEIGHT));
self.draw_solid_rect(&window_rect, WINDOW_COLOR); self.draw_solid_rect(&window_rect, WINDOW_COLOR);
self.draw_text(&format!("Preparation: {:.3} ms", duration_ms(prepare_time)),
&Point2D::new(window_rect.origin.x + PADDING,
window_rect.origin.y + PADDING + FONT_ASCENT));
self.draw_text(&format!("Tiling: {:.3} ms", duration_ms(tile_time)), self.draw_text(&format!("Tiling: {:.3} ms", duration_ms(tile_time)),
&Point2D::new(window_rect.origin.x + PADDING, &Point2D::new(window_rect.origin.x + PADDING,
window_rect.origin.y + PADDING + FONT_ASCENT + LINE_HEIGHT)); window_rect.origin.y + PADDING + FONT_ASCENT));
if let Some(rendering_time) = rendering_time { if let Some(rendering_time) = rendering_time {
self.draw_text(&format!("Rendering: {:.3} ms", duration_ms(rendering_time)), self.draw_text(&format!("Rendering: {:.3} ms", duration_ms(rendering_time)),
&Point2D::new( &Point2D::new(
window_rect.origin.x + PADDING, window_rect.origin.x + PADDING,
window_rect.origin.y + PADDING + FONT_ASCENT + LINE_HEIGHT * 2)); window_rect.origin.y + PADDING + FONT_ASCENT + LINE_HEIGHT));
} }
} }

View File

@ -21,8 +21,7 @@ use pathfinder_geometry::outline::Outline;
use pathfinder_geometry::point::{Point2DF32, Point3DF32}; use pathfinder_geometry::point::{Point2DF32, Point3DF32};
use pathfinder_geometry::transform3d::Perspective; use pathfinder_geometry::transform3d::Perspective;
use pathfinder_geometry::transform::Transform2DF32; use pathfinder_geometry::transform::Transform2DF32;
use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator}; use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
use rayon::iter::{IntoParallelRefMutIterator, ParallelIterator};
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
#[derive(Clone)] #[derive(Clone)]
@ -67,13 +66,15 @@ impl Scene {
.collect() .collect()
} }
pub fn build_objects_sequentially(&self, z_buffer: &ZBuffer) -> Vec<BuiltObject> { pub fn build_objects_sequentially(&self, build_transform: &BuildTransform, z_buffer: &ZBuffer)
-> Vec<BuiltObject> {
self.objects self.objects
.iter() .iter()
.enumerate() .enumerate()
.map(|(object_index, object)| { .map(|(object_index, object)| {
let outline = self.apply_build_transform(&object.outline, build_transform);
let mut tiler = Tiler::new( let mut tiler = Tiler::new(
&object.outline, &outline,
&self.view_box, &self.view_box,
object_index as u16, object_index as u16,
ShaderId(object.paint.0), ShaderId(object.paint.0),
@ -85,13 +86,15 @@ impl Scene {
.collect() .collect()
} }
pub fn build_objects(&self, z_buffer: &ZBuffer) -> Vec<BuiltObject> { pub fn build_objects(&self, build_transform: &BuildTransform, z_buffer: &ZBuffer)
-> Vec<BuiltObject> {
self.objects self.objects
.par_iter() .par_iter()
.enumerate() .enumerate()
.map(|(object_index, object)| { .map(|(object_index, object)| {
let outline = self.apply_build_transform(&object.outline, build_transform);
let mut tiler = Tiler::new( let mut tiler = Tiler::new(
&object.outline, &outline,
&self.view_box, &self.view_box,
object_index as u16, object_index as u16,
ShaderId(object.paint.0), ShaderId(object.paint.0),
@ -103,34 +106,25 @@ impl Scene {
.collect() .collect()
} }
fn update_bounds(&mut self) { fn apply_build_transform(&self, outline: &Outline, build_transform: &BuildTransform)
let mut bounds = Rect::zero(); -> Outline {
for (object_index, object) in self.objects.iter_mut().enumerate() { // FIXME(pcwalton): Don't clone?
if object_index == 0 { let mut outline = (*outline).clone();
bounds = *object.outline.bounds(); match *build_transform {
} else { BuildTransform::Perspective(ref perspective) => {
bounds = bounds.union(object.outline.bounds()); // FIXME(pcwalton): Do this only once!
let quad = self.apply_perspective_to_quad(perspective);
outline.clip_against_polygon(&quad);
outline.apply_perspective(perspective);
} }
BuildTransform::Transform2D(ref transform) => {
outline.transform(transform);
}
BuildTransform::None => {}
} }
outline.clip_against_rect(&self.view_box);
self.bounds = bounds; outline.make_monotonic();
} outline
pub fn prepare(&mut self) {
for object in &mut self.objects {
object.outline.clip_against_rect(&self.view_box);
object.outline.make_monotonic();
}
}
pub fn transform(&mut self, transform: &Transform2DF32) {
for object in &mut self.objects {
object.outline.transform(transform);
object.outline.clip_against_rect(&self.view_box);
object.outline.make_monotonic();
}
self.update_bounds();
} }
fn apply_perspective_to_quad(&self, perspective: &Perspective) -> Vec<Point2DF32> { fn apply_perspective_to_quad(&self, perspective: &Perspective) -> Vec<Point2DF32> {
@ -141,33 +135,6 @@ impl Scene {
.collect() .collect()
} }
pub fn apply_perspective_sequentially(&mut self, perspective: &Perspective) {
let quad = self.apply_perspective_to_quad(perspective);
for object in &mut self.objects {
object.outline.clip_against_polygon(&quad);
object.outline.apply_perspective(perspective);
object.outline.clip_against_rect(&self.view_box);
object.outline.make_monotonic();
}
self.update_bounds();
}
pub fn apply_perspective(&mut self, perspective: &Perspective) {
let quad = self.apply_perspective_to_quad(perspective);
let view_box = &self.view_box;
self.objects.par_iter_mut().for_each(|object| {
object.outline.clip_against_polygon(&quad);
object.outline.apply_perspective(perspective);
object.outline.clip_against_rect(&view_box);
object.outline.make_monotonic();
});
self.update_bounds();
}
fn clip_bounding_quad_with_perspective(&self, perspective: &Perspective) -> Vec<Point3DF32> { fn clip_bounding_quad_with_perspective(&self, perspective: &Perspective) -> Vec<Point3DF32> {
let mut points = vec![ let mut points = vec![
Point3DF32::from_euclid_2d(&self.bounds.origin), Point3DF32::from_euclid_2d(&self.bounds.origin),
@ -245,3 +212,9 @@ pub fn scene_tile_index(tile_x: i16, tile_y: i16, tile_rect: Rect<i16>) -> u32 {
(tile_y - tile_rect.origin.y) as u32 * tile_rect.size.width as u32 (tile_y - tile_rect.origin.y) as u32 * tile_rect.size.width as u32
+ (tile_x - tile_rect.origin.x) as u32 + (tile_x - tile_rect.origin.x) as u32
} }
pub enum BuildTransform {
None,
Transform2D(Transform2DF32),
Perspective(Perspective),
}