From 4f95666cc869297fec8582103bbce774c6e93cb3 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 10 Jan 2019 16:11:15 -0800 Subject: [PATCH] Use SIMD for transforms --- utils/tile-svg/src/main.rs | 118 ++++++++++++++++++++++++++++++++++--- 1 file changed, 111 insertions(+), 7 deletions(-) diff --git a/utils/tile-svg/src/main.rs b/utils/tile-svg/src/main.rs index 1b097c5d..ed5bd997 100644 --- a/utils/tile-svg/src/main.rs +++ b/utils/tile-svg/src/main.rs @@ -25,7 +25,6 @@ use euclid::{Point2D, Rect, Size2D, Transform2D}; use fixedbitset::FixedBitSet; use hashbrown::HashMap; use jemallocator; -use lyon_geom::math::Transform; use lyon_geom::{CubicBezierSegment, QuadraticBezierSegment}; use lyon_path::PathEvent; use lyon_path::iterator::PathIter; @@ -200,7 +199,7 @@ impl Scene { } fn from_tree(tree: Tree) -> Scene { - let global_transform = Transform2D::create_scale(SCALE_FACTOR, SCALE_FACTOR); + let global_transform = Transform2DF32::from_scale(&Point2DF32::splat(SCALE_FACTOR)); let mut scene = Scene::new(); @@ -221,8 +220,8 @@ impl Scene { return scene; - fn process_node(scene: &mut Scene, node: &Node, transform: &Transform2D) { - let node_transform = usvg_transform_to_euclid_transform_2d(&node.transform()); + fn process_node(scene: &mut Scene, node: &Node, transform: &Transform2DF32) { + let node_transform = usvg_transform_to_transform_2d(&node.transform()); let transform = transform.pre_mul(&node_transform); match *node.borrow() { @@ -1721,6 +1720,12 @@ fn usvg_transform_to_euclid_transform_2d(transform: &UsvgTransform) -> Transform transform.e as f32, transform.f as f32) } +fn usvg_transform_to_transform_2d(transform: &UsvgTransform) -> Transform2DF32 { + Transform2DF32::row_major(transform.a as f32, transform.b as f32, + transform.c as f32, transform.d as f32, + transform.e as f32, transform.f as f32) +} + struct UsvgPathToPathEvents where I: Iterator { iter: I, } @@ -1756,24 +1761,51 @@ impl Iterator for UsvgPathToPathEvents where I: Iterator where I: Iterator { inner: I, - transform: Transform2D, + transform: Transform2DF32, } impl Iterator for PathTransformingIter where I: Iterator { type Item = PathEvent; fn next(&mut self) -> Option { - self.inner.next().map(|event| event.transform(&self.transform)) + self.inner.next().map(|event| { + match event { + PathEvent::Close => PathEvent::Close, + PathEvent::Arc(a, b, c, d) => { + // TODO(pcwalton): Transform these! + PathEvent::Arc(a, b, c, d) + } + PathEvent::MoveTo(to) => { + PathEvent::MoveTo(self.transform_euclid(&to)) + } + PathEvent::LineTo(to) => { + PathEvent::LineTo(self.transform_euclid(&to)) + } + PathEvent::QuadraticTo(ctrl, to) => { + PathEvent::QuadraticTo(self.transform_euclid(&ctrl), + self.transform_euclid(&to)) + } + PathEvent::CubicTo(ctrl0, ctrl1, to) => { + PathEvent::CubicTo(self.transform_euclid(&ctrl0), + self.transform_euclid(&ctrl1), + self.transform_euclid(&to)) + } + } + }) } } impl PathTransformingIter where I: Iterator { - fn new(inner: I, transform: &Transform2D) -> PathTransformingIter { + fn new(inner: I, transform: &Transform2DF32) -> PathTransformingIter { PathTransformingIter { inner, transform: *transform, } } + + fn transform_euclid(&self, point: &Point2D) -> Point2D { + self.transform.transform_point(&Point2DF32::from_euclid(*point)).as_euclid() + } } // Monotonic conversion utilities @@ -2310,6 +2342,78 @@ struct LineSegmentU4(u16); #[derive(Clone, Copy, Debug)] struct LineSegmentU8(u32); +// Affine transforms + +#[derive(Clone, Copy)] +struct Transform2DF32 { + // Row-major order. + matrix: ::Vf32, + vector: Point2DF32, +} + +impl Default for Transform2DF32 { + fn default() -> Transform2DF32 { + unsafe { + let mut matrix = ::setzero_ps(); + matrix[0] = 1.0; + matrix[3] = 1.0; + Transform2DF32 { matrix, vector: Point2DF32::default() } + } + } +} + +impl Transform2DF32 { + fn from_scale(scale: &Point2DF32) -> Transform2DF32 { + unsafe { + let mut matrix = Sse41::setzero_ps(); + matrix[0] = scale.x(); + matrix[3] = scale.y(); + Transform2DF32 { matrix, vector: Point2DF32::default() } + } + } + + fn row_major(m11: f32, m12: f32, m21: f32, m22: f32, m31: f32, m32: f32) -> Transform2DF32 { + unsafe { + let mut matrix = Sse41::setzero_ps(); + matrix[0] = m11; + matrix[1] = m12; + matrix[2] = m21; + matrix[3] = m22; + Transform2DF32 { matrix, vector: Point2DF32::new(m31, m32) } + } + } + + fn transform_point(&self, point: &Point2DF32) -> Point2DF32 { + unsafe { + let xxyy = Sse41::shuffle_ps(point.0, point.0, 0b0101_0000); + let x11_x12_y21_y22 = Sse41::mul_ps(xxyy, self.matrix); + let y21_y22 = Sse41::shuffle_ps(x11_x12_y21_y22, x11_x12_y21_y22, 0b0000_1110); + Point2DF32(Sse41::add_ps(Sse41::add_ps(x11_x12_y21_y22, y21_y22), self.vector.0)) + } + } + + fn post_mul(&self, other: &Transform2DF32) -> Transform2DF32 { + unsafe { + // Here `a` is self and `b` is `other`. + let a11a21a11a21 = Sse41::shuffle_ps(self.matrix, self.matrix, 0b1000_1000); + let b11b11b12b12 = Sse41::shuffle_ps(other.matrix, other.matrix, 0b0101_0000); + let lhs = Sse41::mul_ps(a11a21a11a21, b11b11b12b12); + + let a12a22a12a22 = Sse41::shuffle_ps(self.matrix, self.matrix, 0b1101_1101); + let b21b21b22b22 = Sse41::shuffle_ps(other.matrix, other.matrix, 0b1111_1010); + let rhs = Sse41::mul_ps(a12a22a12a22, b21b21b22b22); + + let matrix = Sse41::add_ps(lhs, rhs); + let vector = other.transform_point(&self.vector) + other.vector; + Transform2DF32 { matrix, vector } + } + } + + fn pre_mul(&self, other: &Transform2DF32) -> Transform2DF32 { + other.post_mul(self) + } +} + // Path utilities const TINY_EPSILON: f32 = 0.1;