diff --git a/Cargo.lock b/Cargo.lock index 7a708315..674fc365 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", diff --git a/demo3/src/main.rs b/demo3/src/main.rs index 5e26c630..80a33640 100644 --- a/demo3/src/main.rs +++ b/demo3/src/main.rs @@ -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), - Exit, } enum SceneToMainMsg { @@ -285,7 +284,9 @@ fn load_scene(options: &Options, window_size: &Size2D) -> 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) -> Scene { } fn build_scene(scene: &Scene, perspective: Option, 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, 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); diff --git a/geometry/src/basic/mod.rs b/geometry/src/basic/mod.rs index aca609b0..7dc82675 100644 --- a/geometry/src/basic/mod.rs +++ b/geometry/src/basic/mod.rs @@ -12,5 +12,6 @@ pub mod line_segment; pub mod point; +pub mod rect; pub mod transform2d; pub mod transform3d; diff --git a/geometry/src/basic/point.rs b/geometry/src/basic/point.rs index 33e348e3..47b69c63 100644 --- a/geometry/src/basic/point.rs +++ b/geometry/src/basic/point.rs @@ -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] diff --git a/geometry/src/basic/rect.rs b/geometry/src/basic/rect.rs new file mode 100644 index 00000000..d6cc33c4 --- /dev/null +++ b/geometry/src/basic/rect.rs @@ -0,0 +1,118 @@ +// pathfinder/geometry/src/basic/rect.rs +// +// Copyright © 2019 The Pathfinder Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , 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 { + 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] + } +} diff --git a/geometry/src/basic/transform2d.rs b/geometry/src/basic/transform2d.rs index 8926c756..d8a3438d 100644 --- a/geometry/src/basic/transform2d.rs +++ b/geometry/src/basic/transform2d.rs @@ -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) -> Rect { - 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] diff --git a/geometry/src/basic/transform3d.rs b/geometry/src/basic/transform3d.rs index 1455bcd3..513f7602 100644 --- a/geometry/src/basic/transform3d.rs +++ b/geometry/src/basic/transform3d.rs @@ -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) -> Rect { - 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) } } diff --git a/geometry/src/clip.rs b/geometry/src/clip.rs index 00197088..fab35255 100644 --- a/geometry/src/clip.rs +++ b/geometry/src/clip.rs @@ -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, + clip_rect: RectF32, subject: &'a [PathEvent], } impl<'a> RectClipper<'a> { - pub fn new<'aa>(clip_rect: &Rect, 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 { 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) -> 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) -> 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) -> 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) -> 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, + clip_rect: RectF32, contour: Contour, } @@ -441,17 +434,17 @@ impl ContourClipper for ContourRectClipper { impl ContourRectClipper { #[inline] - pub(crate) fn new(clip_rect: &Rect, 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())); diff --git a/geometry/src/outline.rs b/geometry/src/outline.rs index e1c22ff6..acd70bf8 100644 --- a/geometry/src/outline.rs +++ b/geometry/src/outline.rs @@ -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, - bounds: Rect, + bounds: RectF32, } #[derive(Clone)] pub struct Contour { pub(crate) points: Vec, pub(crate) flags: Vec, - pub(crate) bounds: Rect, + 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 { - &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) { + 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) { - 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 { - &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) { + 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>) { + fn update_bounds(&self, bounds: &mut Option) { *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, 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)); } diff --git a/renderer/src/builder.rs b/renderer/src/builder.rs index 16a094a7..a1e5dbef 100644 --- a/renderer/src/builder.rs +++ b/renderer/src/builder.rs @@ -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, z_buffer: ZBuffer, view_box: &Rect) - -> SceneBuilder { + pub fn new(objects: Vec, z_buffer: ZBuffer, view_box: RectF32) -> SceneBuilder { let tile_rect = tiles::round_rect_out_to_tile_bounds(view_box); SceneBuilder { objects, diff --git a/renderer/src/gpu_data.rs b/renderer/src/gpu_data.rs index a3491f5b..0becfcb6 100644 --- a/renderer/src/gpu_data.rs +++ b/renderer/src/gpu_data.rs @@ -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, + pub bounds: RectF32, pub tile_rect: Rect, pub tiles: Vec, pub fills: Vec, @@ -31,7 +32,7 @@ pub struct BuiltObject { #[derive(Debug)] pub struct BuiltScene { - pub view_box: Rect, + pub view_box: RectF32, pub batches: Vec, pub solid_tiles: Vec, pub shaders: Vec, @@ -86,9 +87,9 @@ pub struct MaskTileBatchPrimitive { // Utilities for built objects impl BuiltObject { - pub fn new(bounds: &Rect, 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) -> 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![] } } } diff --git a/renderer/src/scene.rs b/renderer/src/scene.rs index 5b43d38f..d6c7c52f 100644 --- a/renderer/src/scene.rs +++ b/renderer/src/scene.rs @@ -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, pub paints: Vec, pub paint_cache: HashMap, - pub bounds: Rect, - pub view_box: Rect, + 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 { - 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 { - 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, "", - 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, " ) -> 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); diff --git a/renderer/src/serialization.rs b/renderer/src/serialization.rs index d0f9a2f9..d10e95da 100644 --- a/renderer/src/serialization.rs +++ b/renderer/src/serialization.rs @@ -54,10 +54,10 @@ impl RiffSerialize for BuiltScene { writer.write_u32::(header_size as u32)?; writer.write_u32::(FILE_VERSION)?; writer.write_u32::(self.batches.len() as u32)?; - writer.write_f32::(self.view_box.origin.x)?; - writer.write_f32::(self.view_box.origin.y)?; - writer.write_f32::(self.view_box.size.width)?; - writer.write_f32::(self.view_box.size.height)?; + writer.write_f32::(self.view_box.origin().x())?; + writer.write_f32::(self.view_box.origin().y())?; + writer.write_f32::(self.view_box.size().x())?; + writer.write_f32::(self.view_box.size().y())?; writer.write_all(b"shad")?; writer.write_u32::(shaders_size as u32)?; diff --git a/renderer/src/tiles.rs b/renderer/src/tiles.rs index f1c7961d..a48ce5f9 100644 --- a/renderer/src/tiles.rs +++ b/renderer/src/tiles.rs @@ -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, + 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) -> Rect { - 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 { + 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; diff --git a/renderer/src/z_buffer.rs b/renderer/src/z_buffer.rs index d90ee17a..5fbee1c5 100644 --- a/renderer/src/z_buffer.rs +++ b/renderer/src/z_buffer.rs @@ -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) -> 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 { diff --git a/simd/src/extras.rs b/simd/src/extras.rs index f738d852..ade3b42b 100644 --- a/simd/src/extras.rs +++ b/simd/src/extras.rs @@ -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 diff --git a/simd/src/x86.rs b/simd/src/x86.rs index 1f5b7ec4..a2f60225 100644 --- a/simd/src/x86.rs +++ b/simd/src/x86.rs @@ -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 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)] diff --git a/svg/Cargo.toml b/svg/Cargo.toml index e0bef310..fb6a782c 100644 --- a/svg/Cargo.toml +++ b/svg/Cargo.toml @@ -5,7 +5,6 @@ edition = "2018" authors = ["Patrick Walton "] [dependencies] -euclid = "0.19" lyon_path = "0.12" usvg = "0.4" diff --git a/svg/src/lib.rs b/svg/src/lib.rs index 442f788a..755b280f 100644 --- a/svg/src/lib.rs +++ b/svg/src/lib.rs @@ -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 { - 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 {