Do scene building just-in-time on a per-outline basis as part of tiling
This commit is contained in:
parent
f19757e4cf
commit
b0e91369e5
|
@ -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),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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),
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue