Add perf benchmarks and more unit tests for matrix inversion

R=jvanverth@google.com, reed@google.com

Author: shawnsingh@chromium.org

Review URL: https://chromiumcodereview.appspot.com/22886010

git-svn-id: http://skia.googlecode.com/svn/trunk@10836 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/bench/Matrix44Bench.cpp b/bench/Matrix44Bench.cpp
index dd1de59..7baf82a 100644
--- a/bench/Matrix44Bench.cpp
+++ b/bench/Matrix44Bench.cpp
@@ -79,22 +79,91 @@
 class InvertMatrix44Bench : public Matrix44Bench {
 public:
     InvertMatrix44Bench(void* param) : INHERITED(param, "invert") {
-    fM0.set(0, 0, -1.1);
-    fM0.set(0, 1, 2.1);
-    fM0.set(0, 2, -3.1);
-    fM0.set(0, 3, 4.1);
-    fM0.set(1, 0, 5.1);
-    fM0.set(1, 1, -6.1);
-    fM0.set(1, 2, 7.1);
-    fM0.set(1, 3, 8.1);
-    fM0.set(2, 0, -9.1);
-    fM0.set(2, 1, 10.1);
-    fM0.set(2, 2, 11.1);
-    fM0.set(2, 3, -12.1);
-    fM0.set(3, 0, -13.1);
-    fM0.set(3, 1, 14.1);
-    fM0.set(3, 2, -15.1);
-    fM0.set(3, 3, 16.1);
+        fM0.set(0, 0, -1.1);
+        fM0.set(0, 1, 2.1);
+        fM0.set(0, 2, -3.1);
+        fM0.set(0, 3, 4.1);
+        fM0.set(1, 0, 5.1);
+        fM0.set(1, 1, -6.1);
+        fM0.set(1, 2, 7.1);
+        fM0.set(1, 3, 8.1);
+        fM0.set(2, 0, -9.1);
+        fM0.set(2, 1, 10.1);
+        fM0.set(2, 2, 11.1);
+        fM0.set(2, 3, -12.1);
+        fM0.set(3, 0, -13.1);
+        fM0.set(3, 1, 14.1);
+        fM0.set(3, 2, -15.1);
+        fM0.set(3, 3, 16.1);
+    }
+protected:
+    virtual void performTest() {
+        for (int i = 0; i < 10; ++i) {
+            fM0.invert(&fM1);
+        }
+    }
+private:
+    SkMatrix44 fM0, fM1;
+    typedef Matrix44Bench INHERITED;
+};
+
+class InvertAffineMatrix44Bench : public Matrix44Bench {
+public:
+    InvertAffineMatrix44Bench(void* param) : INHERITED(param, "invertaffine") {
+        fM0.set(0, 0, -1.1);
+        fM0.set(0, 1, 2.1);
+        fM0.set(0, 2, -3.1);
+        fM0.set(0, 3, 4.1);
+        fM0.set(1, 0, 5.1);
+        fM0.set(1, 1, -6.1);
+        fM0.set(1, 2, 7.1);
+        fM0.set(1, 3, 8.1);
+        fM0.set(2, 0, -9.1);
+        fM0.set(2, 1, 10.1);
+        fM0.set(2, 2, 11.1);
+        fM0.set(2, 3, -12.1);
+        // bottom row (perspective component) remains (0, 0, 0, 1).
+    }
+protected:
+    virtual void performTest() {
+        for (int i = 0; i < 10; ++i) {
+            fM0.invert(&fM1);
+        }
+    }
+private:
+    SkMatrix44 fM0, fM1;
+    typedef Matrix44Bench INHERITED;
+};
+
+class InvertScaleTranslateMatrix44Bench : public Matrix44Bench {
+public:
+    InvertScaleTranslateMatrix44Bench(void* param) : INHERITED(param, "invertscaletranslate") {
+        fM0.set(0, 0, -1.1);
+        fM0.set(0, 3, 4.1);
+
+        fM0.set(1, 1, -6.1);
+        fM0.set(1, 3, 8.1);
+
+        fM0.set(2, 2, 11.1);
+        fM0.set(2, 3, -12.1);
+    }
+protected:
+    virtual void performTest() {
+        for (int i = 0; i < 10; ++i) {
+            fM0.invert(&fM1);
+        }
+    }
+private:
+    SkMatrix44 fM0, fM1;
+    typedef Matrix44Bench INHERITED;
+};
+
+class InvertTranslateMatrix44Bench : public Matrix44Bench {
+public:
+    InvertTranslateMatrix44Bench(void* param) : INHERITED(param, "inverttranslate") {
+        fM0.set(0, 3, 4.1);
+        fM0.set(1, 3, 8.1);
+        fM0.set(2, 3, -12.1);
     }
 protected:
     virtual void performTest() {
@@ -167,5 +236,8 @@
 DEF_BENCH( return new PreScaleMatrix44Bench(p); )
 DEF_BENCH( return new PostScaleMatrix44Bench(p); )
 DEF_BENCH( return new InvertMatrix44Bench(p); )
+DEF_BENCH( return new InvertAffineMatrix44Bench(p); )
+DEF_BENCH( return new InvertScaleTranslateMatrix44Bench(p); )
+DEF_BENCH( return new InvertTranslateMatrix44Bench(p); )
 DEF_BENCH( return new SetConcatMatrix44Bench(p); )
 DEF_BENCH( return new GetTypeMatrix44Bench(p); )
diff --git a/tests/Matrix44Test.cpp b/tests/Matrix44Test.cpp
index ef8c3fc..e210fb7 100644
--- a/tests/Matrix44Test.cpp
+++ b/tests/Matrix44Test.cpp
@@ -319,6 +319,103 @@
     REPORTER_ASSERT(reporter, nearly_equal_double(0, e.determinant()));
 }
 
+static void test_invert(skiatest::Reporter* reporter) {
+    SkMatrix44 inverse;
+    double inverseData[16];
+
+    SkMatrix44 identity;
+    identity.setIdentity();
+    identity.invert(&inverse);
+    inverse.asRowMajord(inverseData);
+    assert16<double>(reporter, inverseData,
+                     1, 0, 0, 0,
+                     0, 1, 0, 0,
+                     0, 0, 1, 0,
+                     0, 0, 0, 1);
+
+    SkMatrix44 translation;
+    translation.setTranslate(2, 3, 4);
+    translation.invert(&inverse);
+    inverse.asRowMajord(inverseData);
+    assert16<double>(reporter, inverseData,
+                     1, 0, 0, -2,
+                     0, 1, 0, -3,
+                     0, 0, 1, -4,
+                     0, 0, 0, 1);
+
+    SkMatrix44 scale;
+    scale.setScale(2, 4, 8);
+    scale.invert(&inverse);
+    inverse.asRowMajord(inverseData);
+    assert16<double>(reporter, inverseData,
+                     0.5, 0,    0,     0,
+                     0,   0.25, 0,     0,
+                     0,   0,    0.125, 0,
+                     0,   0,    0,     1);
+
+    SkMatrix44 scaleTranslation;
+    scaleTranslation.setScale(10, 100, 1000);
+    scaleTranslation.preTranslate(2, 3, 4);
+    scaleTranslation.invert(&inverse);
+    inverse.asRowMajord(inverseData);
+    assert16<double>(reporter, inverseData,
+                     0.1,  0,    0,   -2,
+                     0,   0.01,  0,   -3,
+                     0,    0,  0.001, -4,
+                     0,    0,    0,   1);
+
+    SkMatrix44 rotation;
+    rotation.setRotateDegreesAbout(0, 0, 1, 90);
+    rotation.invert(&inverse);
+    SkMatrix44 expected;
+    double expectedInverseRotation[16] =
+            {0,  1, 0, 0,
+             -1, 0, 0, 0,
+             0,  0, 1, 0,
+             0,  0, 0, 1};
+    expected.setRowMajord(expectedInverseRotation);
+    REPORTER_ASSERT(reporter, nearly_equal(expected, inverse));
+    
+    SkMatrix44 affine;
+    affine.setRotateDegreesAbout(0, 0, 1, 90);
+    affine.preScale(10, 20, 100);
+    affine.preTranslate(2, 3, 4);
+    affine.invert(&inverse);
+    double expectedInverseAffine[16] =
+            {0,    0.1,  0,   -2,
+             -0.05, 0,   0,   -3,
+             0,     0,  0.01, -4,
+             0,     0,   0,   1};
+    expected.setRowMajord(expectedInverseAffine);
+    REPORTER_ASSERT(reporter, nearly_equal(expected, inverse));
+
+    SkMatrix44 perspective;
+    perspective.setIdentity();
+    perspective.setDouble(3, 2, 1.0);
+    perspective.invert(&inverse);
+    double expectedInversePerspective[16] =
+            {1, 0,  0, 0,
+             0, 1,  0, 0,
+             0, 0,  1, 0,
+             0, 0, -1, 1};
+    expected.setRowMajord(expectedInversePerspective);
+    REPORTER_ASSERT(reporter, nearly_equal(expected, inverse));
+
+    SkMatrix44 affineAndPerspective;
+    affineAndPerspective.setIdentity();
+    affineAndPerspective.setDouble(3, 2, 1.0);
+    affineAndPerspective.preScale(10, 20, 100);
+    affineAndPerspective.preTranslate(2, 3, 4);
+    affineAndPerspective.invert(&inverse);
+    double expectedInverseAffineAndPerspective[16] =
+            {0.1, 0,    2,   -2,
+             0,  0.05,  3,   -3,
+             0,   0,   4.01, -4,
+             0,   0,   -1,    1};
+    expected.setRowMajord(expectedInverseAffineAndPerspective);
+    REPORTER_ASSERT(reporter, nearly_equal(expected, inverse));
+}
+
 static void test_transpose(skiatest::Reporter* reporter) {
     SkMatrix44 a;
     SkMatrix44 b;
@@ -468,6 +565,7 @@
     test_constructor(reporter);
     test_gettype(reporter);
     test_determinant(reporter);
+    test_invert(reporter);
     test_transpose(reporter);
     test_get_set_double(reporter);
     test_set_row_col_major(reporter);