From 4787486af35f35d7788b1e049a82451bb278ad48 Mon Sep 17 00:00:00 2001 From: William Candillon Date: Thu, 19 May 2022 23:11:18 +0200 Subject: [PATCH 1/2] Faster transform processing --- package/cpp/api/JsiSkMatrix.h | 46 ++++++- .../src/renderer/processors/math/Matrix3.ts | 120 +++--------------- package/src/skia/Matrix.ts | 9 +- 3 files changed, 70 insertions(+), 105 deletions(-) diff --git a/package/cpp/api/JsiSkMatrix.h b/package/cpp/api/JsiSkMatrix.h index bbf6f7920b..bbffa08161 100644 --- a/package/cpp/api/JsiSkMatrix.h +++ b/package/cpp/api/JsiSkMatrix.h @@ -25,9 +25,51 @@ class JsiSkMatrix : public JsiSkWrappingSharedPtrHostObject { : JsiSkWrappingSharedPtrHostObject( context, std::make_shared(std::move(m))) {} + + JSI_HOST_FUNCTION(preConcat) { + auto m3 = JsiSkMatrix::fromValue(runtime, arguments[0]); + getObject()->preConcat(*m3); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(preTranslate) { + auto x = arguments[0].asNumber(); + auto y = arguments[1].asNumber(); + getObject()->preTranslate(x, y); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(preScale) { + auto x = arguments[0].asNumber(); + auto y = arguments[1].asNumber(); + getObject()->preScale(x, y); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(preSkew) { + auto x = arguments[0].asNumber(); + auto y = arguments[1].asNumber(); + getObject()->preSkew(x, y); + return jsi::Value::undefined(); + } + + JSI_HOST_FUNCTION(preRotate) { + auto a = arguments[0].asNumber(); + getObject()->preRotate(a); + return jsi::Value::undefined(); + } + + JSI_EXPORT_FUNCTIONS( + JSI_EXPORT_FUNC(JsiSkMatrix, preConcat), + JSI_EXPORT_FUNC(JsiSkMatrix, preTranslate), + JSI_EXPORT_FUNC(JsiSkMatrix, preScale), + JSI_EXPORT_FUNC(JsiSkMatrix, preSkew), + JSI_EXPORT_FUNC(JsiSkMatrix, preRotate), + ) + /** -Returns the underlying object from a host object of this type -*/ + * Returns the underlying object from a host object of this type + */ static std::shared_ptr fromValue(jsi::Runtime &runtime, const jsi::Value &obj) { const auto& object = obj.asObject(runtime); diff --git a/package/src/renderer/processors/math/Matrix3.ts b/package/src/renderer/processors/math/Matrix3.ts index 416f09500f..5efdee6e81 100644 --- a/package/src/renderer/processors/math/Matrix3.ts +++ b/package/src/renderer/processors/math/Matrix3.ts @@ -1,9 +1,5 @@ import { exhaustiveCheck } from "../../typeddash"; -import type { SkMatrix } from "../../../skia/Matrix"; - -export type Vec3 = readonly [number, number, number]; - -export type Matrix3 = readonly [Vec3, Vec3, Vec3]; +import { Skia } from "../../../skia"; type Transform2dName = | "translateX" @@ -34,121 +30,41 @@ export type Transforms2d = readonly ( | Pick )[]; -const identityMatrix: Matrix3 = [ - [1, 0, 0], - [0, 1, 0], - [0, 0, 1], -]; - -const translateXMatrix = (x: number): Matrix3 => [ - [1, 0, x], - [0, 1, 0], - [0, 0, 1], -]; - -const translateYMatrix = (y: number): Matrix3 => [ - [1, 0, 0], - [0, 1, y], - [0, 0, 1], -]; - -const scaleMatrix = (s: number): Matrix3 => [ - [s, 0, 0], - [0, s, 0], - [0, 0, 1], -]; - -const scaleXMatrix = (s: number): Matrix3 => [ - [s, 0, 0], - [0, 1, 0], - [0, 0, 1], -]; - -const scaleYMatrix = (s: number): Matrix3 => [ - [1, 0, 0], - [0, s, 0], - [0, 0, 1], -]; - -const skewXMatrix = (s: number): Matrix3 => [ - [1, Math.tan(s), 0], - [0, 1, 0], - [0, 0, 1], -]; - -const skewYMatrix = (s: number): Matrix3 => [ - [1, 0, 0], - [Math.tan(s), 1, 0], - [0, 0, 1], -]; - -const rotateZMatrix = (r: number): Matrix3 => [ - [Math.cos(r), -1 * Math.sin(r), 0], - [Math.sin(r), Math.cos(r), 0], - [0, 0, 1], -]; - -const dot3 = (row: Vec3, col: Vec3) => - row[0] * col[0] + row[1] * col[1] + row[2] * col[2]; - -const multiply3 = (m1: Matrix3, m2: Matrix3) => { - const col0 = [m2[0][0], m2[1][0], m2[2][0]] as const; - const col1 = [m2[0][1], m2[1][1], m2[2][1]] as const; - const col2 = [m2[0][2], m2[1][2], m2[2][2]] as const; - return [ - [dot3(m1[0], col0), dot3(m1[0], col1), dot3(m1[0], col2)], - [dot3(m1[1], col0), dot3(m1[1], col1), dot3(m1[1], col2)], - [dot3(m1[2], col0), dot3(m1[2], col1), dot3(m1[2], col2)], - ] as const; -}; - -export const matrixVecMul3 = (m: Matrix3, v: Vec3) => - [dot3(m[0], v), dot3(m[1], v), dot3(m[2], v)] as const; - -const skiaMatrix3 = (m: Matrix3): SkMatrix => { - return [ - m[0][0], - m[0][1], - m[0][2], - m[1][0], - m[1][1], - m[1][2], - m[2][0], - m[2][1], - m[2][2], - ]; -}; - export const processTransform2d = (transforms: Transforms2d) => - skiaMatrix3(processTransform(transforms)); - -const processTransform = (transforms: Transforms2d) => transforms.reduce((acc, transform) => { const key = Object.keys(transform)[0] as Transform2dName; const value = (transform as Pick)[key]; if (key === "translateX") { - return multiply3(acc, translateXMatrix(value)); + acc.preTranslate(value, 0); + return acc; } if (key === "translateY") { - return multiply3(acc, translateYMatrix(value)); + acc.preTranslate(0, value); + return acc; } if (key === "scale") { - return multiply3(acc, scaleMatrix(value)); + acc.preScale(value, value); + return acc; } if (key === "scaleX") { - return multiply3(acc, scaleXMatrix(value)); + acc.preScale(value, 0); + return acc; } if (key === "scaleY") { - return multiply3(acc, scaleYMatrix(value)); + acc.preScale(0, value); + return acc; } if (key === "skewX") { - return multiply3(acc, skewXMatrix(value)); + acc.preSkew(value, 0); + return acc; } if (key === "skewY") { - return multiply3(acc, skewYMatrix(value)); + acc.preSkew(0, value); + return acc; } if (key === "rotate" || key === "rotateZ") { - return multiply3(acc, rotateZMatrix(value)); + acc.preRotate((value * 180) / Math.PI); + return acc; } return exhaustiveCheck(key); - }, identityMatrix); + }, Skia.Matrix()); diff --git a/package/src/skia/Matrix.ts b/package/src/skia/Matrix.ts index 39d1d30985..a9f9169297 100644 --- a/package/src/skia/Matrix.ts +++ b/package/src/skia/Matrix.ts @@ -1,3 +1,4 @@ +import type { SkJSIInstance } from "./JsiInstance"; export enum MatrixIndex { ScaleX = 0, SkewX = 1, @@ -10,7 +11,7 @@ export enum MatrixIndex { persp2 = 8, } -export interface SkMatrix { +export interface SkMatrix extends SkJSIInstance<"Matrix"> { 0: number; 1: number; 2: number; @@ -20,4 +21,10 @@ export interface SkMatrix { 6: number; 7: number; 8: number; + + preConcat: (matrix: SkMatrix) => void; + preTranslate: (x: number, y: number) => void; + preScale: (x: number, y: number) => void; + preSkew: (x: number, y: number) => void; + preRotate: (theta: number) => void; } From cf85934bcf7bdb8394628fc59c8bddeea9b8020a Mon Sep 17 00:00:00 2001 From: William Candillon Date: Fri, 20 May 2022 06:53:58 +0200 Subject: [PATCH 2/2] Minor simplification --- .../src/renderer/processors/math/Matrix3.ts | 43 ++++++++++--------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/package/src/renderer/processors/math/Matrix3.ts b/package/src/renderer/processors/math/Matrix3.ts index 5efdee6e81..ad6c99a489 100644 --- a/package/src/renderer/processors/math/Matrix3.ts +++ b/package/src/renderer/processors/math/Matrix3.ts @@ -30,41 +30,44 @@ export type Transforms2d = readonly ( | Pick )[]; -export const processTransform2d = (transforms: Transforms2d) => - transforms.reduce((acc, transform) => { +export const processTransform2d = (transforms: Transforms2d) => { + const m = Skia.Matrix(); + for (const transform of transforms) { const key = Object.keys(transform)[0] as Transform2dName; const value = (transform as Pick)[key]; if (key === "translateX") { - acc.preTranslate(value, 0); - return acc; + m.preTranslate(value, 0); + continue; } if (key === "translateY") { - acc.preTranslate(0, value); - return acc; + m.preTranslate(0, value); + continue; } if (key === "scale") { - acc.preScale(value, value); - return acc; + m.preScale(value, value); + continue; } if (key === "scaleX") { - acc.preScale(value, 0); - return acc; + m.preScale(value, 0); + continue; } if (key === "scaleY") { - acc.preScale(0, value); - return acc; + m.preScale(0, value); + continue; } if (key === "skewX") { - acc.preSkew(value, 0); - return acc; + m.preSkew(value, 0); + continue; } if (key === "skewY") { - acc.preSkew(0, value); - return acc; + m.preSkew(0, value); + continue; } if (key === "rotate" || key === "rotateZ") { - acc.preRotate((value * 180) / Math.PI); - return acc; + m.preRotate((value * 180) / Math.PI); + continue; } - return exhaustiveCheck(key); - }, Skia.Matrix()); + exhaustiveCheck(key); + } + return m; +};