From b0e91369e5f88f9e0d97cefda55f1b2a87c2591d Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Sat, 2 Feb 2019 11:36:42 -0800 Subject: [PATCH] Do scene building just-in-time on a per-outline basis as part of tiling --- demo3/src/main.rs | 42 +++++++------------- gl/src/debug.rs | 14 ++----- renderer/src/scene.rs | 91 +++++++++++++++---------------------------- 3 files changed, 49 insertions(+), 98 deletions(-) diff --git a/demo3/src/main.rs b/demo3/src/main.rs index 5272c64c..57be958c 100644 --- a/demo3/src/main.rs +++ b/demo3/src/main.rs @@ -16,7 +16,7 @@ use pathfinder_geometry::transform3d::{Perspective, Transform3DF32}; use pathfinder_gl::renderer::Renderer; use pathfinder_renderer::builder::SceneBuilder; 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_svg::SceneExt; use rayon::ThreadPoolBuilder; @@ -111,7 +111,6 @@ fn main() { if !first_frame { if let Ok(SceneToMainMsg::Render { built_scene, - prepare_time, tile_time }) = scene_thread_proxy.receiver.recv() { unsafe { @@ -120,7 +119,7 @@ fn main() { renderer.render_scene(&built_scene); 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 { MainToSceneMsg::Exit => return, MainToSceneMsg::Build(perspective) => { - // FIXME(pcwalton): Stop cloning scenes? - let mut start_time = Instant::now(); - 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 start_time = Instant::now(); + let built_scene = build_scene(&self.scene, perspective, &self.options); let tile_time = Instant::now() - start_time; - - self.sender.send(SceneToMainMsg::Render { - built_scene, - prepare_time, - tile_time, - }).unwrap(); + self.sender.send(SceneToMainMsg::Render { built_scene, tile_time }).unwrap(); } } } @@ -251,7 +231,6 @@ enum MainToSceneMsg { enum SceneToMainMsg { Render { built_scene: BuiltScene, - prepare_time: Duration, tile_time: Duration, } } @@ -324,13 +303,18 @@ fn load_scene(options: &Options, window_size: &Size2D) -> Scene { scene } -fn build_scene(scene: &Scene, options: &Options) -> BuiltScene { +fn build_scene(scene: &Scene, perspective: Option, options: &Options) -> BuiltScene { 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(|| { match options.jobs { - Some(1) => scene.build_objects_sequentially(&z_buffer), - _ => scene.build_objects(&z_buffer), + Some(1) => scene.build_objects_sequentially(&build_transform, &z_buffer), + _ => scene.build_objects(&build_transform, &z_buffer), } }); diff --git a/gl/src/debug.rs b/gl/src/debug.rs index 4ed731fd..a624d224 100644 --- a/gl/src/debug.rs +++ b/gl/src/debug.rs @@ -31,7 +31,7 @@ const DEBUG_FONT_VERTEX_SIZE: GLint = 8; const DEBUG_SOLID_VERTEX_SIZE: GLint = 4; 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 FONT_ASCENT: i16 = 28; const LINE_HEIGHT: i16 = 42; @@ -112,26 +112,20 @@ impl DebugRenderer { self.framebuffer_size = *window_size; } - pub fn draw(&self, - prepare_time: Duration, - tile_time: Duration, - rendering_time: Option) { + pub fn draw(&self, tile_time: Duration, rendering_time: Option) { let window_rect = Rect::new(Point2D::new(self.framebuffer_size.width as i16 - PADDING - WINDOW_WIDTH, self.framebuffer_size.height as i16 - PADDING - WINDOW_HEIGHT), Size2D::new(WINDOW_WIDTH, WINDOW_HEIGHT)); 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)), &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 { self.draw_text(&format!("Rendering: {:.3} ms", duration_ms(rendering_time)), &Point2D::new( window_rect.origin.x + PADDING, - window_rect.origin.y + PADDING + FONT_ASCENT + LINE_HEIGHT * 2)); + window_rect.origin.y + PADDING + FONT_ASCENT + LINE_HEIGHT)); } } diff --git a/renderer/src/scene.rs b/renderer/src/scene.rs index c9a8b257..90d0f3ee 100644 --- a/renderer/src/scene.rs +++ b/renderer/src/scene.rs @@ -21,8 +21,7 @@ use pathfinder_geometry::outline::Outline; use pathfinder_geometry::point::{Point2DF32, Point3DF32}; use pathfinder_geometry::transform3d::Perspective; use pathfinder_geometry::transform::Transform2DF32; -use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator}; -use rayon::iter::{IntoParallelRefMutIterator, ParallelIterator}; +use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator}; use std::fmt::{self, Debug, Formatter}; #[derive(Clone)] @@ -67,13 +66,15 @@ impl Scene { .collect() } - pub fn build_objects_sequentially(&self, z_buffer: &ZBuffer) -> Vec { + pub fn build_objects_sequentially(&self, build_transform: &BuildTransform, z_buffer: &ZBuffer) + -> Vec { self.objects .iter() .enumerate() .map(|(object_index, object)| { + let outline = self.apply_build_transform(&object.outline, build_transform); let mut tiler = Tiler::new( - &object.outline, + &outline, &self.view_box, object_index as u16, ShaderId(object.paint.0), @@ -85,13 +86,15 @@ impl Scene { .collect() } - pub fn build_objects(&self, z_buffer: &ZBuffer) -> Vec { + pub fn build_objects(&self, build_transform: &BuildTransform, z_buffer: &ZBuffer) + -> Vec { self.objects .par_iter() .enumerate() .map(|(object_index, object)| { + let outline = self.apply_build_transform(&object.outline, build_transform); let mut tiler = Tiler::new( - &object.outline, + &outline, &self.view_box, object_index as u16, ShaderId(object.paint.0), @@ -103,34 +106,25 @@ impl Scene { .collect() } - fn update_bounds(&mut self) { - let mut bounds = Rect::zero(); - for (object_index, object) in self.objects.iter_mut().enumerate() { - if object_index == 0 { - bounds = *object.outline.bounds(); - } else { - bounds = bounds.union(object.outline.bounds()); + fn apply_build_transform(&self, outline: &Outline, build_transform: &BuildTransform) + -> Outline { + // FIXME(pcwalton): Don't clone? + let mut outline = (*outline).clone(); + match *build_transform { + BuildTransform::Perspective(ref perspective) => { + // 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 => {} } - - self.bounds = bounds; - } - - 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(); + outline.clip_against_rect(&self.view_box); + outline.make_monotonic(); + outline } fn apply_perspective_to_quad(&self, perspective: &Perspective) -> Vec { @@ -141,33 +135,6 @@ impl Scene { .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 { let mut points = vec![ 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) -> u32 { (tile_y - tile_rect.origin.y) as u32 * tile_rect.size.width as u32 + (tile_x - tile_rect.origin.x) as u32 } + +pub enum BuildTransform { + None, + Transform2D(Transform2DF32), + Perspective(Perspective), +}