Add a SIMD rect type

This commit is contained in:
Patrick Walton 2019-02-05 10:03:20 -08:00
parent 63b47f1abe
commit fe410e066f
19 changed files with 289 additions and 176 deletions

1
Cargo.lock generated
View File

@ -566,7 +566,6 @@ version = "0.3.0"
name = "pathfinder_svg"
version = "0.1.0"
dependencies = [
"euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
"lyon_path 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pathfinder_geometry 0.3.0",
"pathfinder_renderer 0.1.0",

View File

@ -9,9 +9,10 @@
// except according to those terms.
use clap::{App, Arg};
use euclid::{Point2D, Rect, Size2D};
use euclid::Size2D;
use jemallocator;
use pathfinder_geometry::basic::point::Point3DF32;
use pathfinder_geometry::basic::point::{Point2DF32, Point3DF32};
use pathfinder_geometry::basic::rect::RectF32;
use pathfinder_geometry::basic::transform3d::{Perspective, Transform3DF32};
use pathfinder_gl::renderer::Renderer;
use pathfinder_renderer::builder::SceneBuilder;
@ -211,7 +212,6 @@ impl SceneThread {
fn run(self) {
while let Ok(msg) = self.receiver.recv() {
match msg {
MainToSceneMsg::Exit => return,
MainToSceneMsg::Build(perspective) => {
let start_time = Instant::now();
let built_scene = build_scene(&self.scene, perspective, &self.options);
@ -225,7 +225,6 @@ impl SceneThread {
enum MainToSceneMsg {
Build(Option<Perspective>),
Exit,
}
enum SceneToMainMsg {
@ -285,7 +284,9 @@ fn load_scene(options: &Options, window_size: &Size2D<u32>) -> Scene {
let usvg = Tree::from_file(&options.input_path, &UsvgOptions::default()).unwrap();
let mut scene = Scene::from_tree(usvg);
scene.view_box = Rect::new(Point2D::zero(), window_size.to_f32());
scene.view_box =
RectF32::new(Point2DF32::default(),
Point2DF32::new(window_size.width as f32, window_size.height as f32));
println!(
"Scene bounds: {:?} View box: {:?}",
@ -301,7 +302,7 @@ fn load_scene(options: &Options, window_size: &Size2D<u32>) -> Scene {
}
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,
@ -324,10 +325,10 @@ fn build_scene(scene: &Scene, perspective: Option<Perspective>, options: &Option
}
};
let mut built_scene = BuiltScene::new(&scene.view_box);
let mut built_scene = BuiltScene::new(scene.view_box);
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();
while let Some(batch) = scene_builder.build_batch() {
built_scene.batches.push(batch);

View File

@ -12,5 +12,6 @@
pub mod line_segment;
pub mod point;
pub mod rect;
pub mod transform2d;
pub mod transform3d;

View File

@ -40,10 +40,9 @@ impl Point2DF32 {
Point2D::new(self.0[0], self.0[1])
}
// TODO(pcwalton): Optimize this!
#[inline]
pub fn to_4d(self) -> Point3DF32 {
Point3DF32::new(self.0[0], self.0[1], 0.0, 1.0)
pub fn to_3d(self) -> Point3DF32 {
Point3DF32(self.0.concat_xy_xy(F32x4::new(0.0, 1.0, 0.0, 0.0)))
}
#[inline]

118
geometry/src/basic/rect.rs Normal file
View File

@ -0,0 +1,118 @@
// pathfinder/geometry/src/basic/rect.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.
//! 2D axis-aligned rectangles, optimized with SIMD.
use crate::basic::point::Point2DF32;
use pathfinder_simd::default::F32x4;
#[derive(Clone, Copy, Debug, PartialEq, Default)]
pub struct RectF32(pub F32x4);
impl RectF32 {
#[inline]
pub fn new(origin: Point2DF32, size: Point2DF32) -> RectF32 {
RectF32(origin.0.concat_xy_xy(origin.0 + size.0))
}
#[inline]
pub fn from_points(origin: Point2DF32, lower_right: Point2DF32) -> RectF32 {
RectF32(origin.0.concat_xy_xy(lower_right.0))
}
#[inline]
pub fn origin(&self) -> Point2DF32 {
Point2DF32(self.0)
}
#[inline]
pub fn size(&self) -> Point2DF32 {
Point2DF32(self.0.zwxy() - self.0.xyxy())
}
#[inline]
pub fn upper_right(&self) -> Point2DF32 {
Point2DF32(self.0.zyxw())
}
#[inline]
pub fn lower_left(&self) -> Point2DF32 {
Point2DF32(self.0.xwzy())
}
#[inline]
pub fn lower_right(&self) -> Point2DF32 {
Point2DF32(self.0.zwxy())
}
#[inline]
pub fn contains_point(&self, point: Point2DF32) -> bool {
// self.origin <= point && point <= self.lower_right
self.0.concat_xy_xy(point.0).packed_le(point.0.concat_xy_zw(self.0)).is_all_ones()
}
#[inline]
pub fn contains_rect(&self, other: RectF32) -> bool {
// self.origin <= other.origin && other.lower_right <= self.lower_right
self.0.concat_xy_zw(other.0).packed_le(other.0.concat_xy_zw(self.0)).is_all_ones()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.origin() == self.lower_right()
}
#[inline]
pub fn union_point(&self, point: Point2DF32) -> RectF32 {
RectF32::from_points(self.origin().min(point), self.lower_right().max(point))
}
#[inline]
pub fn union_rect(&self, other: RectF32) -> RectF32 {
RectF32::from_points(self.origin().min(other.origin()),
self.lower_right().max(other.lower_right()))
}
#[inline]
pub fn intersects(&self, other: RectF32) -> bool {
// self.origin < other.lower_right && other.origin < self.lower_right
self.0.concat_xy_xy(other.0).packed_lt(other.0.concat_zw_zw(self.0)).is_all_ones()
}
#[inline]
pub fn intersection(&self, other: RectF32) -> Option<RectF32> {
if !self.intersects(other) {
None
} else {
Some(RectF32::from_points(self.origin().max(other.origin()),
self.lower_right().min(other.lower_right())))
}
}
#[inline]
pub fn min_x(self) -> f32 {
self.0[0]
}
#[inline]
pub fn min_y(self) -> f32 {
self.0[1]
}
#[inline]
pub fn max_x(self) -> f32 {
self.0[2]
}
#[inline]
pub fn max_y(self) -> f32 {
self.0[3]
}
}

View File

@ -11,9 +11,10 @@
//! 2D affine transforms.
use crate::basic::point::Point2DF32;
use crate::basic::rect::RectF32;
use crate::basic::transform3d::Transform3DF32;
use crate::segment::Segment;
use euclid::{Point2D, Rect, Size2D, Transform2D};
use euclid::Transform2D;
use lyon_path::PathEvent;
use pathfinder_simd::default::F32x4;
use std::ops::Sub;
@ -145,19 +146,15 @@ impl Transform2DF32 {
self.matrix.transform_point(point) + self.vector
}
// TODO(pcwalton): SIMD.
#[inline]
pub fn transform_rect(&self, rect: &Rect<f32>) -> Rect<f32> {
let upper_left = self.transform_point(&Point2DF32::from_euclid(rect.origin));
let upper_right = self.transform_point(&Point2DF32::from_euclid(rect.top_right()));
let lower_left = self.transform_point(&Point2DF32::from_euclid(rect.bottom_left()));
let lower_right = self.transform_point(&Point2DF32::from_euclid(rect.bottom_right()));
let min_x = upper_left.x().min(upper_right.x()).min(lower_left.x()).min(lower_right.x());
let min_y = upper_left.y().min(upper_right.y()).min(lower_left.y()).min(lower_right.y());
let max_x = upper_left.x().max(upper_right.x()).max(lower_left.x()).max(lower_right.x());
let max_y = upper_left.y().max(upper_right.y()).max(lower_left.y()).max(lower_right.y());
let (width, height) = (max_x - min_x, max_y - min_y);
Rect::new(Point2D::new(min_x, min_y), Size2D::new(width, height))
pub fn transform_rect(&self, rect: &RectF32) -> RectF32 {
let upper_left = self.transform_point(&rect.origin());
let upper_right = self.transform_point(&rect.upper_right());
let lower_left = self.transform_point(&rect.lower_left());
let lower_right = self.transform_point(&rect.lower_right());
let min_point = upper_left.min(upper_right).min(lower_left).min(lower_right);
let max_point = upper_left.max(upper_right).max(lower_left).max(lower_right);
RectF32::from_points(min_point, max_point)
}
#[inline]

View File

@ -11,9 +11,10 @@
//! 3D transforms that can be applied to paths.
use crate::basic::point::{Point2DF32, Point3DF32};
use crate::basic::rect::RectF32;
use crate::basic::transform2d::Matrix2x2F32;
use crate::segment::Segment;
use euclid::{Point2D, Rect, Size2D};
use euclid::Size2D;
use pathfinder_simd::default::F32x4;
use std::ops::{Add, Neg};
@ -260,7 +261,7 @@ impl Perspective {
#[inline]
pub fn transform_point_2d(&self, point: &Point2DF32) -> Point2DF32 {
let point = self.transform.transform_point(point.to_4d()).perspective_divide().to_2d();
let point = self.transform.transform_point(point.to_3d()).perspective_divide().to_2d();
let window_size = self.window_size.to_f32();
let size_scale = Point2DF32::new(window_size.width * 0.5, window_size.height * 0.5);
(point + Point2DF32::splat(1.0)) * size_scale
@ -268,17 +269,14 @@ impl Perspective {
// TODO(pcwalton): SIMD?
#[inline]
pub fn transform_rect(&self, rect: &Rect<f32>) -> Rect<f32> {
let upper_left = self.transform_point_2d(&Point2DF32::from_euclid(rect.origin));
let upper_right = self.transform_point_2d(&Point2DF32::from_euclid(rect.top_right()));
let lower_left = self.transform_point_2d(&Point2DF32::from_euclid(rect.bottom_left()));
let lower_right = self.transform_point_2d(&Point2DF32::from_euclid(rect.bottom_right()));
let min_x = upper_left.x().min(upper_right.x()).min(lower_left.x()).min(lower_right.x());
let min_y = upper_left.y().min(upper_right.y()).min(lower_left.y()).min(lower_right.y());
let max_x = upper_left.x().max(upper_right.x()).max(lower_left.x()).max(lower_right.x());
let max_y = upper_left.y().max(upper_right.y()).max(lower_left.y()).max(lower_right.y());
let (width, height) = (max_x - min_x, max_y - min_y);
Rect::new(Point2D::new(min_x, min_y), Size2D::new(width, height))
pub fn transform_rect(&self, rect: RectF32) -> RectF32 {
let upper_left = self.transform_point_2d(&rect.origin());
let upper_right = self.transform_point_2d(&rect.upper_right());
let lower_left = self.transform_point_2d(&rect.lower_left());
let lower_right = self.transform_point_2d(&rect.lower_right());
let min_point = upper_left.min(upper_right).min(lower_left).min(lower_right);
let max_point = upper_left.max(upper_right).max(lower_left).max(lower_right);
RectF32::from_points(min_point, max_point)
}
}

View File

@ -10,34 +10,31 @@
use crate::basic::line_segment::LineSegmentF32;
use crate::basic::point::{Point2DF32, Point3DF32};
use crate::basic::rect::RectF32;
use crate::outline::{Contour, PointFlags};
use crate::segment::{CubicSegment, Segment};
use crate::util::lerp;
use arrayvec::ArrayVec;
use euclid::Rect;
use lyon_path::PathEvent;
use smallvec::SmallVec;
use std::mem;
pub struct RectClipper<'a> {
clip_rect: Rect<f32>,
clip_rect: RectF32,
subject: &'a [PathEvent],
}
impl<'a> RectClipper<'a> {
pub fn new<'aa>(clip_rect: &Rect<f32>, subject: &'aa [PathEvent]) -> RectClipper<'aa> {
RectClipper {
clip_rect: *clip_rect,
subject,
}
pub fn new<'aa>(clip_rect: RectF32, subject: &'aa [PathEvent]) -> RectClipper<'aa> {
RectClipper { clip_rect, subject }
}
pub fn clip(&self) -> Vec<PathEvent> {
let mut output = self.subject.to_vec();
self.clip_against(Edge::left(&self.clip_rect), &mut output);
self.clip_against(Edge::top(&self.clip_rect), &mut output);
self.clip_against(Edge::right(&self.clip_rect), &mut output);
self.clip_against(Edge::bottom(&self.clip_rect), &mut output);
self.clip_against(Edge::left(self.clip_rect), &mut output);
self.clip_against(Edge::top(self.clip_rect), &mut output);
self.clip_against(Edge::right(self.clip_rect), &mut output);
self.clip_against(Edge::bottom(self.clip_rect), &mut output);
output
}
@ -125,27 +122,23 @@ impl TEdge for Edge {
impl Edge {
#[inline]
fn left(rect: &Rect<f32>) -> Edge {
Edge(LineSegmentF32::new(&Point2DF32::from_euclid(rect.bottom_left()),
&Point2DF32::from_euclid(rect.origin)))
fn left(rect: RectF32) -> Edge {
Edge(LineSegmentF32::new(&rect.lower_left(), &rect.origin()))
}
#[inline]
fn top(rect: &Rect<f32>) -> Edge {
Edge(LineSegmentF32::new(&Point2DF32::from_euclid(rect.origin),
&Point2DF32::from_euclid(rect.top_right())))
fn top(rect: RectF32) -> Edge {
Edge(LineSegmentF32::new(&rect.origin(), &rect.upper_right()))
}
#[inline]
fn right(rect: &Rect<f32>) -> Edge {
Edge(LineSegmentF32::new(&Point2DF32::from_euclid(rect.top_right()),
&Point2DF32::from_euclid(rect.bottom_right())))
fn right(rect: RectF32) -> Edge {
Edge(LineSegmentF32::new(&rect.upper_right(), &rect.lower_right()))
}
#[inline]
fn bottom(rect: &Rect<f32>) -> Edge {
Edge(LineSegmentF32::new(&Point2DF32::from_euclid(rect.bottom_right()),
&Point2DF32::from_euclid(rect.bottom_left())))
fn bottom(rect: RectF32) -> Edge {
Edge(LineSegmentF32::new(&rect.lower_right(), &rect.lower_left()))
}
}
@ -426,7 +419,7 @@ enum EdgeRelativeLocation {
// Fast axis-aligned box 2D clipping
pub(crate) struct ContourRectClipper {
clip_rect: Rect<f32>,
clip_rect: RectF32,
contour: Contour,
}
@ -441,17 +434,17 @@ impl ContourClipper for ContourRectClipper {
impl ContourRectClipper {
#[inline]
pub(crate) fn new(clip_rect: &Rect<f32>, contour: Contour) -> ContourRectClipper {
ContourRectClipper { clip_rect: *clip_rect, contour }
pub(crate) fn new(clip_rect: RectF32, contour: Contour) -> ContourRectClipper {
ContourRectClipper { clip_rect, contour }
}
pub(crate) fn clip(mut self) -> Contour {
if self.clip_rect.contains_rect(&self.contour.bounds()) {
if self.clip_rect.contains_rect(self.contour.bounds()) {
return self.contour
}
self.clip_against(AxisAlignedEdge::Left(self.clip_rect.origin.x));
self.clip_against(AxisAlignedEdge::Top(self.clip_rect.origin.y));
self.clip_against(AxisAlignedEdge::Left(self.clip_rect.min_x()));
self.clip_against(AxisAlignedEdge::Top(self.clip_rect.min_y()));
self.clip_against(AxisAlignedEdge::Right(self.clip_rect.max_x()));
self.clip_against(AxisAlignedEdge::Bottom(self.clip_rect.max_y()));

View File

@ -12,26 +12,26 @@
use crate::basic::line_segment::LineSegmentF32;
use crate::basic::point::Point2DF32;
use crate::basic::rect::RectF32;
use crate::basic::transform2d::Transform2DF32;
use crate::basic::transform3d::Perspective;
use crate::clip::{ContourPolygonClipper, ContourRectClipper};
use crate::monotonic::MonotonicConversionIter;
use crate::segment::{Segment, SegmentFlags, SegmentKind};
use euclid::{Point2D, Rect, Size2D};
use std::fmt::{self, Debug, Formatter};
use std::mem;
#[derive(Clone)]
pub struct Outline {
pub contours: Vec<Contour>,
bounds: Rect<f32>,
bounds: RectF32,
}
#[derive(Clone)]
pub struct Contour {
pub(crate) points: Vec<Point2DF32>,
pub(crate) flags: Vec<PointFlags>,
pub(crate) bounds: Rect<f32>,
pub(crate) bounds: RectF32,
}
bitflags! {
@ -44,10 +44,7 @@ bitflags! {
impl Outline {
#[inline]
pub fn new() -> Outline {
Outline {
contours: vec![],
bounds: Rect::zero(),
}
Outline { contours: vec![], bounds: RectF32::default() }
}
#[inline]
@ -107,8 +104,8 @@ impl Outline {
}
#[inline]
pub fn bounds(&self) -> &Rect<f32> {
&self.bounds
pub fn bounds(&self) -> RectF32 {
self.bounds
}
pub fn transform(&mut self, transform: &Transform2DF32) {
@ -117,7 +114,7 @@ impl Outline {
contour.transform(transform);
contour.update_bounds(&mut new_bounds);
}
self.bounds = new_bounds.unwrap_or_else(|| Rect::zero());
self.bounds = new_bounds.unwrap_or_else(|| RectF32::default());
}
pub fn apply_perspective(&mut self, perspective: &Perspective) {
@ -126,14 +123,14 @@ impl Outline {
contour.apply_perspective(perspective);
contour.update_bounds(&mut new_bounds);
}
self.bounds = new_bounds.unwrap_or_else(|| Rect::zero());
self.bounds = new_bounds.unwrap_or_else(|| RectF32::default());
}
pub fn prepare_for_tiling(&mut self, view_box: &Rect<f32>) {
pub fn prepare_for_tiling(&mut self, view_box: RectF32) {
for contour in &mut self.contours {
contour.prepare_for_tiling(view_box);
}
self.bounds = self.bounds.intersection(view_box).unwrap_or_else(|| Rect::zero());
self.bounds = self.bounds.intersection(view_box).unwrap_or_else(|| RectF32::default());
}
pub fn clip_against_polygon(&mut self, clip_polygon: &[Point2DF32]) {
@ -145,11 +142,11 @@ impl Outline {
self.contours.push(contour);
}
}
self.bounds = new_bounds.unwrap_or_else(|| Rect::zero());
self.bounds = new_bounds.unwrap_or_else(|| RectF32::default());
}
pub fn clip_against_rect(&mut self, clip_rect: &Rect<f32>) {
if clip_rect.contains_rect(&self.bounds) {
pub fn clip_against_rect(&mut self, clip_rect: RectF32) {
if clip_rect.contains_rect(self.bounds) {
return;
}
@ -161,7 +158,7 @@ impl Outline {
self.contours.push(contour);
}
}
self.bounds = new_bounds.unwrap_or_else(|| Rect::zero());
self.bounds = new_bounds.unwrap_or_else(|| RectF32::default());
}
}
@ -180,7 +177,7 @@ impl Debug for Outline {
impl Contour {
#[inline]
pub fn new() -> Contour {
Contour { points: vec![], flags: vec![], bounds: Rect::zero() }
Contour { points: vec![], flags: vec![], bounds: RectF32::default() }
}
// Replaces this contour with a new one, with arrays preallocated to match `self`.
@ -190,7 +187,7 @@ impl Contour {
mem::replace(self, Contour {
points: Vec::with_capacity(length),
flags: Vec::with_capacity(length),
bounds: Rect::zero(),
bounds: RectF32::default(),
})
}
@ -210,8 +207,8 @@ impl Contour {
}
#[inline]
pub fn bounds(&self) -> &Rect<f32> {
&self.bounds
pub fn bounds(&self) -> RectF32 {
self.bounds
}
#[inline]
@ -362,11 +359,10 @@ impl Contour {
}
}
fn prepare_for_tiling(&mut self, view_box: &Rect<f32>) {
fn prepare_for_tiling(&mut self, view_box: RectF32) {
// Snap points to the view box bounds. This mops up floating point error from the clipping
// process.
let origin_upper_left = Point2DF32::from_euclid(view_box.origin);
let origin_lower_right = Point2DF32::from_euclid(view_box.bottom_right());
let (origin_upper_left, origin_lower_right) = (view_box.origin(), view_box.lower_right());
let (mut last_endpoint_index, mut contour_is_monotonic) = (None, true);
for point_index in 0..(self.points.len() as u32) {
let position = &mut self.points[point_index as usize];
@ -395,7 +391,7 @@ impl Contour {
}
// Update bounds.
self.bounds = self.bounds.intersection(view_box).unwrap_or_else(|| Rect::zero());
self.bounds = self.bounds.intersection(view_box).unwrap_or_else(|| RectF32::default());
}
fn curve_with_endpoints_is_monotonic(&self, start_endpoint_index: u32, end_endpoint_index: u32)
@ -438,10 +434,10 @@ impl Contour {
true
}
fn update_bounds(&self, bounds: &mut Option<Rect<f32>>) {
fn update_bounds(&self, bounds: &mut Option<RectF32>) {
*bounds = Some(match *bounds {
None => self.bounds,
Some(bounds) => bounds.union(&self.bounds),
Some(bounds) => bounds.union_rect(self.bounds),
})
}
}
@ -558,17 +554,10 @@ impl<'a> Iterator for ContourIter<'a> {
}
#[inline]
fn union_rect(bounds: &mut Rect<f32>, new_point: Point2DF32, first: bool) {
fn union_rect(bounds: &mut RectF32, new_point: Point2DF32, first: bool) {
if first {
*bounds = Rect::new(new_point.as_euclid(), Size2D::zero());
return;
*bounds = RectF32::from_points(new_point, new_point);
} else {
*bounds = bounds.union_point(new_point)
}
let (mut min_x, mut min_y) = (bounds.origin.x, bounds.origin.y);
let (mut max_x, mut max_y) = (bounds.max_x(), bounds.max_y());
min_x = min_x.min(new_point.x());
min_y = min_y.min(new_point.y());
max_x = max_x.max(new_point.x());
max_y = max_y.max(new_point.y());
*bounds = Rect::new(Point2D::new(min_x, min_y), Size2D::new(max_x - min_x, max_y - min_y));
}

View File

@ -16,6 +16,7 @@ use crate::scene;
use crate::tiles;
use crate::z_buffer::ZBuffer;
use euclid::Rect;
use pathfinder_geometry::basic::rect::RectF32;
use std::iter;
use std::u16;
@ -31,8 +32,7 @@ pub struct SceneBuilder {
}
impl SceneBuilder {
pub fn new(objects: Vec<BuiltObject>, z_buffer: ZBuffer, view_box: &Rect<f32>)
-> SceneBuilder {
pub fn new(objects: Vec<BuiltObject>, z_buffer: ZBuffer, view_box: RectF32) -> SceneBuilder {
let tile_rect = tiles::round_rect_out_to_tile_bounds(view_box);
SceneBuilder {
objects,

View File

@ -16,12 +16,13 @@ use euclid::Rect;
use fixedbitset::FixedBitSet;
use pathfinder_geometry::basic::line_segment::{LineSegmentF32, LineSegmentU4, LineSegmentU8};
use pathfinder_geometry::basic::point::Point2DF32;
use pathfinder_geometry::basic::rect::RectF32;
use pathfinder_geometry::util;
use pathfinder_simd::default::{F32x4, I32x4};
#[derive(Debug)]
pub struct BuiltObject {
pub bounds: Rect<f32>,
pub bounds: RectF32,
pub tile_rect: Rect<i16>,
pub tiles: Vec<TileObjectPrimitive>,
pub fills: Vec<FillObjectPrimitive>,
@ -31,7 +32,7 @@ pub struct BuiltObject {
#[derive(Debug)]
pub struct BuiltScene {
pub view_box: Rect<f32>,
pub view_box: RectF32,
pub batches: Vec<Batch>,
pub solid_tiles: Vec<SolidTileScenePrimitive>,
pub shaders: Vec<ObjectShader>,
@ -86,9 +87,9 @@ pub struct MaskTileBatchPrimitive {
// Utilities for built objects
impl BuiltObject {
pub fn new(bounds: &Rect<f32>, shader: ShaderId) -> BuiltObject {
pub fn new(bounds: RectF32, shader: ShaderId) -> BuiltObject {
// Compute the tile rect.
let tile_rect = tiles::round_rect_out_to_tile_bounds(&bounds);
let tile_rect = tiles::round_rect_out_to_tile_bounds(bounds);
// Allocate tiles.
let tile_count = tile_rect.size.width as usize * tile_rect.size.height as usize;
@ -102,14 +103,7 @@ impl BuiltObject {
let mut solid_tiles = FixedBitSet::with_capacity(tile_count);
solid_tiles.insert_range(..);
BuiltObject {
bounds: *bounds,
tile_rect,
tiles,
fills: vec![],
solid_tiles,
shader,
}
BuiltObject { bounds, tile_rect, tiles, fills: vec![], solid_tiles, shader }
}
// TODO(pcwalton): SIMD-ify `tile_x` and `tile_y`.
@ -256,13 +250,8 @@ impl BuiltObject {
impl BuiltScene {
#[inline]
pub fn new(view_box: &Rect<f32>) -> BuiltScene {
BuiltScene {
view_box: *view_box,
batches: vec![],
solid_tiles: vec![],
shaders: vec![],
}
pub fn new(view_box: RectF32) -> BuiltScene {
BuiltScene { view_box, batches: vec![], solid_tiles: vec![], shaders: vec![] }
}
}

View File

@ -16,7 +16,8 @@ use crate::tiles::Tiler;
use crate::z_buffer::ZBuffer;
use euclid::Rect;
use hashbrown::HashMap;
use pathfinder_geometry::basic::point::{Point2DF32, Point3DF32};
use pathfinder_geometry::basic::point::Point2DF32;
use pathfinder_geometry::basic::rect::RectF32;
use pathfinder_geometry::basic::transform2d::Transform2DF32;
use pathfinder_geometry::basic::transform3d::Perspective;
use pathfinder_geometry::clip::PolygonClipper3D;
@ -29,8 +30,8 @@ pub struct Scene {
pub objects: Vec<PathObject>,
pub paints: Vec<Paint>,
pub paint_cache: HashMap<Paint, PaintId>,
pub bounds: Rect<f32>,
pub view_box: Rect<f32>,
pub bounds: RectF32,
pub view_box: RectF32,
}
impl Scene {
@ -40,8 +41,8 @@ impl Scene {
objects: vec![],
paints: vec![],
paint_cache: HashMap::new(),
bounds: Rect::zero(),
view_box: Rect::zero(),
bounds: RectF32::default(),
view_box: RectF32::default(),
}
}
@ -68,7 +69,7 @@ impl Scene {
pub fn build_objects_sequentially(&self, build_transform: &BuildTransform, z_buffer: &ZBuffer)
-> Vec<BuiltObject> {
let build_transform = build_transform.prepare(&self.bounds);
let build_transform = build_transform.prepare(self.bounds);
self.objects
.iter()
.enumerate()
@ -76,7 +77,7 @@ impl Scene {
let outline = self.apply_build_transform(&object.outline, &build_transform);
let mut tiler = Tiler::new(
&outline,
&self.view_box,
self.view_box,
object_index as u16,
ShaderId(object.paint.0),
z_buffer,
@ -89,7 +90,7 @@ impl Scene {
pub fn build_objects(&self, build_transform: &BuildTransform, z_buffer: &ZBuffer)
-> Vec<BuiltObject> {
let build_transform = build_transform.prepare(&self.bounds);
let build_transform = build_transform.prepare(self.bounds);
self.objects
.par_iter()
.enumerate()
@ -97,7 +98,7 @@ impl Scene {
let outline = self.apply_build_transform(&object.outline, &build_transform);
let mut tiler = Tiler::new(
&outline,
&self.view_box,
self.view_box,
object_index as u16,
ShaderId(object.paint.0),
z_buffer,
@ -116,17 +117,17 @@ impl Scene {
PreparedBuildTransform::Perspective(ref perspective, ref quad) => {
outline.clip_against_polygon(quad);
outline.apply_perspective(perspective);
outline.prepare_for_tiling(&self.view_box);
outline.prepare_for_tiling(self.view_box);
}
PreparedBuildTransform::Transform2D(ref transform) => {
outline.transform(transform);
outline.clip_against_rect(&self.view_box);
outline.clip_against_rect(self.view_box);
}
PreparedBuildTransform::None => {
outline.clip_against_rect(&self.view_box);
outline.clip_against_rect(self.view_box);
}
}
outline.prepare_for_tiling(&self.view_box);
outline.prepare_for_tiling(self.view_box);
outline
}
}
@ -135,10 +136,10 @@ impl Debug for Scene {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
writeln!(formatter,
"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"{} {} {} {}\">",
self.view_box.origin.x,
self.view_box.origin.y,
self.view_box.size.width,
self.view_box.size.height)?;
self.view_box.origin().x(),
self.view_box.origin().y(),
self.view_box.size().x(),
self.view_box.size().y())?;
for object in &self.objects {
let paint = &self.paints[object.paint.0 as usize];
write!(formatter, " <path")?;
@ -197,7 +198,7 @@ pub enum BuildTransform {
}
impl BuildTransform {
fn prepare(&self, bounds: &Rect<f32>) -> PreparedBuildTransform {
fn prepare(&self, bounds: RectF32) -> PreparedBuildTransform {
let perspective = match self {
BuildTransform::None => return PreparedBuildTransform::None,
BuildTransform::Transform2D(ref transform) => {
@ -207,10 +208,10 @@ impl BuildTransform {
};
let mut points = vec![
Point3DF32::from_euclid_2d(&bounds.origin),
Point3DF32::from_euclid_2d(&bounds.top_right()),
Point3DF32::from_euclid_2d(&bounds.bottom_right()),
Point3DF32::from_euclid_2d(&bounds.bottom_left()),
bounds.origin().to_3d(),
bounds.upper_right().to_3d(),
bounds.lower_right().to_3d(),
bounds.lower_left().to_3d(),
];
//println!("-----");
//println!("bounds={:?} ORIGINAL quad={:?}", self.bounds, points);

View File

@ -54,10 +54,10 @@ impl RiffSerialize for BuiltScene {
writer.write_u32::<LittleEndian>(header_size as u32)?;
writer.write_u32::<LittleEndian>(FILE_VERSION)?;
writer.write_u32::<LittleEndian>(self.batches.len() as u32)?;
writer.write_f32::<LittleEndian>(self.view_box.origin.x)?;
writer.write_f32::<LittleEndian>(self.view_box.origin.y)?;
writer.write_f32::<LittleEndian>(self.view_box.size.width)?;
writer.write_f32::<LittleEndian>(self.view_box.size.height)?;
writer.write_f32::<LittleEndian>(self.view_box.origin().x())?;
writer.write_f32::<LittleEndian>(self.view_box.origin().y())?;
writer.write_f32::<LittleEndian>(self.view_box.size().x())?;
writer.write_f32::<LittleEndian>(self.view_box.size().y())?;
writer.write_all(b"shad")?;
writer.write_u32::<LittleEndian>(shaders_size as u32)?;

View File

@ -15,6 +15,7 @@ use crate::z_buffer::ZBuffer;
use euclid::{Point2D, Rect, Size2D};
use pathfinder_geometry::basic::line_segment::LineSegmentF32;
use pathfinder_geometry::basic::point::Point2DF32;
use pathfinder_geometry::basic::rect::RectF32;
use pathfinder_geometry::outline::{Contour, Outline, PointIndex};
use pathfinder_geometry::segment::Segment;
use pathfinder_geometry::util;
@ -42,16 +43,13 @@ impl<'o, 'z> Tiler<'o, 'z> {
#[allow(clippy::or_fun_call)]
pub fn new(
outline: &'o Outline,
view_box: &Rect<f32>,
view_box: RectF32,
object_index: u16,
shader: ShaderId,
z_buffer: &'z ZBuffer,
) -> Tiler<'o, 'z> {
let bounds = outline
.bounds()
.intersection(&view_box)
.unwrap_or(Rect::zero());
let built_object = BuiltObject::new(&bounds, shader);
let bounds = outline.bounds().intersection(view_box).unwrap_or(RectF32::default());
let built_object = BuiltObject::new(bounds, shader);
Tiler {
outline,
@ -304,11 +302,9 @@ impl<'o, 'z> Tiler<'o, 'z> {
}
}
pub fn round_rect_out_to_tile_bounds(rect: &Rect<f32>) -> Rect<i16> {
let tile_origin = Point2D::new(
(f32::floor(rect.origin.x) as i32 / TILE_WIDTH as i32) as i16,
(f32::floor(rect.origin.y) as i32 / TILE_HEIGHT as i32) as i16,
);
pub fn round_rect_out_to_tile_bounds(rect: RectF32) -> Rect<i16> {
let tile_origin = Point2D::new((f32::floor(rect.min_x()) as i32 / TILE_WIDTH as i32) as i16,
(f32::floor(rect.min_y()) as i32 / TILE_HEIGHT as i32) as i16);
let tile_extent = Point2D::new(
util::alignup_i32(f32::ceil(rect.max_x()) as i32, TILE_WIDTH as i32) as i16,
util::alignup_i32(f32::ceil(rect.max_y()) as i32, TILE_HEIGHT as i32) as i16,
@ -377,7 +373,7 @@ impl ActiveEdge {
}
fn process(&mut self, built_object: &mut BuiltObject, tile_y: i16) {
let tile_bottom = ((i32::from(tile_y) + 1) * TILE_HEIGHT as i32) as f32;
//let tile_bottom = ((i32::from(tile_y) + 1) * TILE_HEIGHT as i32) as f32;
//println!("process_active_edge({:#?}, tile_y={}({}))", self, tile_y, tile_bottom);
let mut segment = self.segment;

View File

@ -14,6 +14,7 @@ use crate::gpu_data::{BuiltObject, SolidTileScenePrimitive};
use crate::scene;
use crate::tiles;
use euclid::Rect;
use pathfinder_geometry::basic::rect::RectF32;
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};
pub struct ZBuffer {
@ -22,7 +23,7 @@ pub struct ZBuffer {
}
impl ZBuffer {
pub fn new(view_box: &Rect<f32>) -> ZBuffer {
pub fn new(view_box: RectF32) -> ZBuffer {
let tile_rect = tiles::round_rect_out_to_tile_bounds(view_box);
let tile_area = tile_rect.size.width as usize * tile_rect.size.height as usize;
ZBuffer {

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::default::F32x4;
use crate::default::{F32x4, U32x4};
impl F32x4 {
// Accessors

View File

@ -12,7 +12,7 @@ use std::arch::x86_64::{self, __m128, __m128i};
use std::cmp::PartialEq;
use std::fmt::{self, Debug, Formatter};
use std::mem;
use std::ops::{Add, AddAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign};
use std::ops::{Add, AddAssign, BitXor, Index, IndexMut, Mul, MulAssign, Neg, Not, Sub, SubAssign};
// 32-bit floats
@ -75,6 +75,16 @@ impl F32x4 {
}
}
#[inline]
pub fn packed_lt(self, other: F32x4) -> U32x4 {
other.packed_gt(self)
}
#[inline]
pub fn packed_le(self, other: F32x4) -> U32x4 {
!self.packed_gt(other)
}
// Conversions
/// Converts these packed floats to integers.
@ -1592,6 +1602,11 @@ impl U32x4 {
}
}
#[inline]
pub fn splat(x: u32) -> U32x4 {
unsafe { U32x4(x86_64::_mm_set1_epi32(x as i32)) }
}
// Basic operations
#[inline]
@ -1634,6 +1649,24 @@ impl PartialEq for U32x4 {
}
}
impl Not for U32x4 {
type Output = U32x4;
#[inline]
fn not(self) -> U32x4 {
self ^ U32x4::splat(!0)
}
}
impl BitXor<U32x4> for U32x4 {
type Output = U32x4;
#[inline]
fn bitxor(self, other: U32x4) -> U32x4 {
unsafe {
U32x4(x86_64::_mm_xor_si128(self.0, other.0))
}
}
}
// 8-bit unsigned integers
#[derive(Clone, Copy)]

View File

@ -5,7 +5,6 @@ edition = "2018"
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
[dependencies]
euclid = "0.19"
lyon_path = "0.12"
usvg = "0.4"

View File

@ -10,10 +10,10 @@
//! Converts a subset of SVG to a Pathfinder scene.
use euclid::{Point2D, Rect, Size2D};
use lyon_path::iterator::PathIter;
use pathfinder_geometry::basic::line_segment::LineSegmentF32;
use pathfinder_geometry::basic::point::Point2DF32;
use pathfinder_geometry::basic::rect::RectF32;
use pathfinder_geometry::basic::transform2d::{Transform2DF32, Transform2DF32PathIter};
use pathfinder_geometry::monotonic::MonotonicConversionIter;
use pathfinder_geometry::outline::Outline;
@ -78,7 +78,7 @@ fn process_node(scene: &mut Scene, node: &Node, transform: &Transform2DF32) {
let path = MonotonicConversionIter::new(path);
let outline = Outline::from_segments(path);
scene.bounds = scene.bounds.union(outline.bounds());
scene.bounds = scene.bounds.union_rect(outline.bounds());
scene.objects.push(PathObject::new(
outline,
style,
@ -101,7 +101,7 @@ fn process_node(scene: &mut Scene, node: &Node, transform: &Transform2DF32) {
let path = MonotonicConversionIter::new(path);
let outline = Outline::from_segments(path);
scene.bounds = scene.bounds.union(outline.bounds());
scene.bounds = scene.bounds.union_rect(outline.bounds());
scene.objects.push(PathObject::new(
outline,
style,
@ -135,12 +135,11 @@ impl PaintExt for Paint {
}
}
fn usvg_rect_to_euclid_rect(rect: &UsvgRect) -> Rect<f32> {
Rect::new(
Point2D::new(rect.x, rect.y),
Size2D::new(rect.width, rect.height),
fn usvg_rect_to_euclid_rect(rect: &UsvgRect) -> RectF32 {
RectF32::new(
Point2DF32::new(rect.x as f32, rect.y as f32),
Point2DF32::new(rect.width as f32, rect.height as f32),
)
.to_f32()
}
fn usvg_transform_to_transform_2d(transform: &UsvgTransform) -> Transform2DF32 {