2019-01-14 17:20:36 -05:00
|
|
|
// pathfinder/renderer/src/builder.rs
|
|
|
|
//
|
|
|
|
// Copyright © 2019 The Pathfinder Project Developers.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
|
|
|
//! Packs data onto the GPU.
|
|
|
|
|
2019-04-29 21:16:55 -04:00
|
|
|
use crate::concurrent::executor::Executor;
|
2019-04-15 16:21:24 -04:00
|
|
|
use crate::gpu_data::{AlphaTileBatchPrimitive, RenderCommand};
|
2019-04-11 22:38:31 -04:00
|
|
|
use crate::scene::Scene;
|
2019-04-12 14:55:05 -04:00
|
|
|
use crate::tiles::Tiler;
|
2019-01-14 17:20:36 -05:00
|
|
|
use crate::z_buffer::ZBuffer;
|
2019-04-15 16:21:24 -04:00
|
|
|
use pathfinder_geometry::basic::point::{Point2DF32, Point3DF32};
|
2019-04-12 14:55:05 -04:00
|
|
|
use pathfinder_geometry::basic::rect::RectF32;
|
2019-02-06 21:09:37 -05:00
|
|
|
use pathfinder_geometry::basic::transform2d::Transform2DF32;
|
|
|
|
use pathfinder_geometry::basic::transform3d::Perspective;
|
|
|
|
use pathfinder_geometry::clip::PolygonClipper3D;
|
2019-04-15 16:21:24 -04:00
|
|
|
use std::sync::atomic::AtomicUsize;
|
2019-01-14 17:20:36 -05:00
|
|
|
use std::u16;
|
|
|
|
|
2019-04-15 16:21:24 -04:00
|
|
|
pub trait RenderCommandListener: Send + Sync {
|
|
|
|
fn send(&self, command: RenderCommand);
|
2019-03-29 22:11:38 -04:00
|
|
|
}
|
2019-01-14 17:20:36 -05:00
|
|
|
|
2019-03-29 22:11:38 -04:00
|
|
|
pub struct SceneBuilder<'a> {
|
|
|
|
scene: &'a Scene,
|
|
|
|
built_options: &'a PreparedRenderOptions,
|
2019-01-14 17:20:36 -05:00
|
|
|
|
2019-04-15 16:21:24 -04:00
|
|
|
pub(crate) next_alpha_tile_index: AtomicUsize,
|
|
|
|
pub(crate) z_buffer: ZBuffer,
|
|
|
|
pub(crate) listener: Box<dyn RenderCommandListener>,
|
2019-03-29 22:11:38 -04:00
|
|
|
}
|
2019-01-14 17:20:36 -05:00
|
|
|
|
2019-04-15 16:21:24 -04:00
|
|
|
impl<'a> SceneBuilder<'a> {
|
2019-04-29 19:45:29 -04:00
|
|
|
pub fn new(
|
|
|
|
scene: &'a Scene,
|
|
|
|
built_options: &'a PreparedRenderOptions,
|
|
|
|
listener: Box<dyn RenderCommandListener>,
|
|
|
|
) -> SceneBuilder<'a> {
|
2019-04-15 16:21:24 -04:00
|
|
|
let effective_view_box = scene.effective_view_box(built_options);
|
|
|
|
SceneBuilder {
|
|
|
|
scene,
|
|
|
|
built_options,
|
2019-01-14 17:20:36 -05:00
|
|
|
|
2019-04-15 16:21:24 -04:00
|
|
|
next_alpha_tile_index: AtomicUsize::new(0),
|
|
|
|
z_buffer: ZBuffer::new(effective_view_box),
|
|
|
|
listener,
|
2019-03-29 22:11:38 -04:00
|
|
|
}
|
|
|
|
}
|
2019-01-14 17:20:36 -05:00
|
|
|
|
2019-04-29 21:16:55 -04:00
|
|
|
pub fn build<E>(&mut self, executor: &E) where E: Executor {
|
2019-04-15 16:21:24 -04:00
|
|
|
let effective_view_box = self.scene.effective_view_box(self.built_options);
|
|
|
|
let object_count = self.scene.objects.len();
|
2019-04-29 21:16:55 -04:00
|
|
|
let alpha_tiles = executor.flatten_into_vector(object_count, |object_index| {
|
|
|
|
self.build_object(object_index, effective_view_box, &self.built_options, &self.scene)
|
|
|
|
});
|
2019-04-18 18:09:37 -04:00
|
|
|
self.finish_building(alpha_tiles)
|
2019-04-15 16:21:24 -04:00
|
|
|
}
|
2019-03-29 22:11:38 -04:00
|
|
|
|
2019-04-29 19:45:29 -04:00
|
|
|
fn build_object(
|
|
|
|
&self,
|
|
|
|
object_index: usize,
|
|
|
|
view_box: RectF32,
|
|
|
|
built_options: &PreparedRenderOptions,
|
|
|
|
scene: &Scene,
|
|
|
|
) -> Vec<AlphaTileBatchPrimitive> {
|
2019-04-15 16:21:24 -04:00
|
|
|
let object = &scene.objects[object_index];
|
|
|
|
let outline = scene.apply_render_options(object.outline(), built_options);
|
2019-03-29 22:11:38 -04:00
|
|
|
|
2019-04-15 16:21:24 -04:00
|
|
|
let mut tiler = Tiler::new(self, &outline, view_box, object_index as u16);
|
|
|
|
tiler.generate_tiles();
|
2019-01-14 17:20:36 -05:00
|
|
|
|
2019-04-29 19:45:29 -04:00
|
|
|
self.listener
|
|
|
|
.send(RenderCommand::AddFills(tiler.built_object.fills));
|
2019-04-15 16:21:24 -04:00
|
|
|
tiler.built_object.alpha_tiles
|
2019-03-29 22:11:38 -04:00
|
|
|
}
|
|
|
|
|
2019-04-15 16:21:24 -04:00
|
|
|
fn cull_alpha_tiles(&self, alpha_tiles: &mut Vec<AlphaTileBatchPrimitive>) {
|
|
|
|
for alpha_tile in alpha_tiles {
|
|
|
|
let alpha_tile_coords = alpha_tile.tile_coords();
|
2019-04-29 19:45:29 -04:00
|
|
|
if self
|
|
|
|
.z_buffer
|
|
|
|
.test(alpha_tile_coords, alpha_tile.object_index as u32)
|
|
|
|
{
|
2019-03-29 22:11:38 -04:00
|
|
|
continue;
|
|
|
|
}
|
2019-04-11 21:54:03 -04:00
|
|
|
|
2019-04-15 16:21:24 -04:00
|
|
|
// FIXME(pcwalton): Clean this up.
|
|
|
|
alpha_tile.tile_x_lo = 0xff;
|
|
|
|
alpha_tile.tile_y_lo = 0xff;
|
|
|
|
alpha_tile.tile_hi = 0xff;
|
2019-01-14 17:20:36 -05:00
|
|
|
}
|
|
|
|
}
|
2019-03-29 22:11:38 -04:00
|
|
|
|
2019-04-15 16:21:24 -04:00
|
|
|
fn pack_alpha_tiles(&mut self, alpha_tiles: Vec<AlphaTileBatchPrimitive>) {
|
|
|
|
let object_count = self.scene.objects.len() as u32;
|
|
|
|
let solid_tiles = self.z_buffer.build_solid_tiles(0..object_count);
|
|
|
|
if !solid_tiles.is_empty() {
|
|
|
|
self.listener.send(RenderCommand::SolidTile(solid_tiles));
|
|
|
|
}
|
|
|
|
if !alpha_tiles.is_empty() {
|
|
|
|
self.listener.send(RenderCommand::AlphaTile(alpha_tiles));
|
2019-03-29 22:11:38 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-15 16:21:24 -04:00
|
|
|
fn finish_building(&mut self, mut alpha_tiles: Vec<AlphaTileBatchPrimitive>) {
|
|
|
|
self.listener.send(RenderCommand::FlushFills);
|
|
|
|
self.cull_alpha_tiles(&mut alpha_tiles);
|
|
|
|
self.pack_alpha_tiles(alpha_tiles);
|
2019-03-29 22:11:38 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-06 21:09:37 -05:00
|
|
|
#[derive(Clone, Default)]
|
|
|
|
pub struct RenderOptions {
|
|
|
|
pub transform: RenderTransform,
|
|
|
|
pub dilation: Point2DF32,
|
2019-03-25 19:13:56 -04:00
|
|
|
pub subpixel_aa_enabled: bool,
|
2019-02-06 21:09:37 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl RenderOptions {
|
|
|
|
pub fn prepare(self, bounds: RectF32) -> PreparedRenderOptions {
|
|
|
|
PreparedRenderOptions {
|
|
|
|
transform: self.transform.prepare(bounds),
|
|
|
|
dilation: self.dilation,
|
2019-03-25 19:13:56 -04:00
|
|
|
subpixel_aa_enabled: self.subpixel_aa_enabled,
|
2019-02-06 21:09:37 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub enum RenderTransform {
|
|
|
|
Transform2D(Transform2DF32),
|
|
|
|
Perspective(Perspective),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for RenderTransform {
|
|
|
|
#[inline]
|
|
|
|
fn default() -> RenderTransform {
|
|
|
|
RenderTransform::Transform2D(Transform2DF32::default())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl RenderTransform {
|
|
|
|
fn prepare(&self, bounds: RectF32) -> PreparedRenderTransform {
|
|
|
|
let perspective = match self {
|
|
|
|
RenderTransform::Transform2D(ref transform) => {
|
|
|
|
if transform.is_identity() {
|
|
|
|
return PreparedRenderTransform::None;
|
|
|
|
}
|
|
|
|
return PreparedRenderTransform::Transform2D(*transform);
|
|
|
|
}
|
|
|
|
RenderTransform::Perspective(ref perspective) => *perspective,
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut points = vec![
|
|
|
|
bounds.origin().to_3d(),
|
|
|
|
bounds.upper_right().to_3d(),
|
|
|
|
bounds.lower_right().to_3d(),
|
|
|
|
bounds.lower_left().to_3d(),
|
|
|
|
];
|
2019-04-29 19:43:24 -04:00
|
|
|
debug!("-----");
|
|
|
|
debug!("bounds={:?} ORIGINAL quad={:?}", bounds, points);
|
2019-02-06 21:09:37 -05:00
|
|
|
for point in &mut points {
|
|
|
|
*point = perspective.transform.transform_point(*point);
|
|
|
|
}
|
2019-04-29 19:43:24 -04:00
|
|
|
debug!("... PERSPECTIVE quad={:?}", points);
|
2019-02-18 16:42:30 -05:00
|
|
|
|
|
|
|
// Compute depth.
|
|
|
|
let quad = [
|
|
|
|
points[0].perspective_divide(),
|
|
|
|
points[1].perspective_divide(),
|
|
|
|
points[2].perspective_divide(),
|
|
|
|
points[3].perspective_divide(),
|
|
|
|
];
|
2019-04-29 19:43:24 -04:00
|
|
|
debug!("... PERSPECTIVE-DIVIDED points = {:?}", quad);
|
2019-02-18 16:42:30 -05:00
|
|
|
|
2019-02-06 21:09:37 -05:00
|
|
|
points = PolygonClipper3D::new(points).clip();
|
2019-04-29 19:43:24 -04:00
|
|
|
debug!("... CLIPPED quad={:?}", points);
|
2019-02-06 21:09:37 -05:00
|
|
|
for point in &mut points {
|
|
|
|
*point = point.perspective_divide()
|
|
|
|
}
|
2019-02-18 16:42:30 -05:00
|
|
|
|
2019-02-06 21:09:37 -05:00
|
|
|
let inverse_transform = perspective.transform.inverse();
|
2019-04-29 19:45:29 -04:00
|
|
|
let clip_polygon = points
|
|
|
|
.into_iter()
|
|
|
|
.map(|point| {
|
|
|
|
inverse_transform
|
|
|
|
.transform_point(point)
|
|
|
|
.perspective_divide()
|
|
|
|
.to_2d()
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
return PreparedRenderTransform::Perspective {
|
|
|
|
perspective,
|
|
|
|
clip_polygon,
|
|
|
|
quad,
|
|
|
|
};
|
2019-02-06 21:09:37 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct PreparedRenderOptions {
|
|
|
|
pub transform: PreparedRenderTransform,
|
|
|
|
pub dilation: Point2DF32,
|
2019-03-25 19:13:56 -04:00
|
|
|
pub subpixel_aa_enabled: bool,
|
2019-02-06 21:09:37 -05:00
|
|
|
}
|
|
|
|
|
2019-02-18 16:42:30 -05:00
|
|
|
impl PreparedRenderOptions {
|
|
|
|
#[inline]
|
2019-04-18 18:09:37 -04:00
|
|
|
pub fn bounding_quad(&self) -> [Point3DF32; 4] {
|
2019-02-18 16:42:30 -05:00
|
|
|
match self.transform {
|
|
|
|
PreparedRenderTransform::Perspective { quad, .. } => quad,
|
|
|
|
_ => [Point3DF32::default(); 4],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-06 21:09:37 -05:00
|
|
|
pub enum PreparedRenderTransform {
|
|
|
|
None,
|
|
|
|
Transform2D(Transform2DF32),
|
2019-04-29 19:45:29 -04:00
|
|
|
Perspective {
|
|
|
|
perspective: Perspective,
|
|
|
|
clip_polygon: Vec<Point2DF32>,
|
|
|
|
quad: [Point3DF32; 4],
|
|
|
|
},
|
2019-02-06 21:09:37 -05:00
|
|
|
}
|
2019-03-25 19:13:56 -04:00
|
|
|
|
|
|
|
impl PreparedRenderTransform {
|
|
|
|
#[inline]
|
|
|
|
pub fn is_2d(&self) -> bool {
|
|
|
|
match *self {
|
|
|
|
PreparedRenderTransform::Transform2D(_) => true,
|
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-03-29 22:11:38 -04:00
|
|
|
|
2019-04-29 19:45:29 -04:00
|
|
|
impl<F> RenderCommandListener for F
|
|
|
|
where
|
|
|
|
F: Fn(RenderCommand) + Send + Sync,
|
|
|
|
{
|
2019-03-29 22:11:38 -04:00
|
|
|
#[inline]
|
2019-04-29 19:45:29 -04:00
|
|
|
fn send(&self, command: RenderCommand) {
|
|
|
|
(*self)(command)
|
|
|
|
}
|
2019-03-29 22:11:38 -04:00
|
|
|
}
|
2019-04-18 18:09:37 -04:00
|
|
|
|
|
|
|
#[derive(Clone, Copy, Debug, Default)]
|
|
|
|
pub struct TileStats {
|
|
|
|
pub solid_tile_count: u32,
|
|
|
|
pub alpha_tile_count: u32,
|
|
|
|
}
|