Add GM reproducing perspective failures

Modeled on https://codepen.io/adamdupuis/pen/qLYzqB, this GM creates a
cube of rectangles with the camera at the center. It animates the FOV
since the original chrome issue was most visible when resizing the page
(which then updated the fov of the perspective css transform).

This draws correctly with the raster backend. There are two issues it
causes with Ganesh:

1. The input coordinates of some of the cube faces have 0 or negative ws.
  - When negative, the current bounds code does not perform clipping and
    just uses the mirrored point, which leads to misleading bounds.
  - When 0, the current bounds code produces infinities, and then GrOpsTask
    discards the op with non-finite bounds.
2. The anti-aliasing code also ignores w <= 0, and so all of its screen
   space math is incorrect.

This causes a mix of completely discarded draws and distorted draws on the
GPU backend.

Bug: skia:9779, chromium:224618
Change-Id: Ib00b909f51cbf7aaba5b89ed830ddc720ad3c73d
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/265763
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Jim Van Verth <jvanverth@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/gm/crbug_224618.cpp b/gm/crbug_224618.cpp
new file mode 100644
index 0000000..4e179eb
--- /dev/null
+++ b/gm/crbug_224618.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2020 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "gm/gm.h"
+#include "include/core/SkCanvas.h"
+#include "include/core/SkColor.h"
+#include "include/core/SkMatrix.h"
+#include "include/core/SkMatrix44.h"
+#include "include/private/SkM44.h"
+#include "tools/timer/TimeUtils.h"
+
+static SkM44 rotate_axis_angle(SkScalar x, SkScalar y, SkScalar z, SkScalar radians) {
+    // SkM44 doesn't expose any rotation factories yet
+    SkMatrix44 m;
+    m.setRotateAboutUnit(x, y, z, radians);
+    return SkM44(m);
+}
+
+// Adapted from https://codepen.io/adamdupuis/pen/qLYzqB
+class CrBug224618GM : public skiagm::GM {
+public:
+    CrBug224618GM() : fTime(0.f) {}
+
+protected:
+    SkString onShortName() override {
+        return SkString("crbug_224618");
+    }
+
+    SkISize onISize() override {
+        return SkISize::Make(kMaxVW, kMaxVW);
+    }
+
+    // This animates the FOV in viewer, to ensure the panorama covering rects are stable across
+    // a variety of perspective matrices
+    bool onAnimate(double nanos) override {
+        fTime = TimeUtils::Scaled(1e-9f * nanos, 0.5f);
+        return true;
+    }
+
+    void onDraw(SkCanvas* canvas) override {
+        SkScalar viewportWidth = SkScalarMod(fTime, 10.f) / 10.f * (kMaxVW - kMinVW) + kMinVW;
+        SkScalar radius = viewportWidth / 2.f; // round?
+        // See https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/perspective
+        SkM44 proj{1.f, 0.f, 0.f, 0.f,
+                   0.f, 1.f, 0.f, 0.f,
+                   0.f, 0.f, 1.f, 0.f,
+                   0.f, 0.f, -1.f / radius, 1.f};
+        SkM44 zoom             = SkM44::Translate(0.f, 0.f, radius);
+        SkM44 postZoom         = SkM44::Translate(0.f, 0.f, -radius - 1.f);
+        SkM44 rotateHorizontal = rotate_axis_angle(0.f, 1.f, 0.f, 2.356194490192345f);
+
+        // w in degrees will need to be converted to radians
+        SkV4 axisAngles[6] = {
+            {0.f, 1.f, 0.f, -90.f}, // rotateY(-90deg)
+            {1.f, 0.f, 0.f, 0.f},   // <none>
+            {0.f, 1.f, 0.f, 90.f},  // rotateY(90deg)
+            {0.f, 1.f, 0.f, 180.f}, // rotateY(180deg)
+            {1.f, 0.f, 0.f, -90.f}, // rotateX(-90deg)
+            {1.f, 0.f, 0.f, 90.f},  // rotateX(90deg)
+        };
+        SkColor faceColors[6] = {
+            SK_ColorRED,
+            SK_ColorGREEN,
+            SK_ColorBLUE,
+            SK_ColorYELLOW,
+            SkColorSetARGB(0xFF, 0xFF, 0xA5, 0x00), // orange css
+            SkColorSetARGB(0xFF, 0x80, 0x00, 0x80)  // purple css
+        };
+        for (int i = 0; i < 6; ++i) {
+            SkM44 model = rotate_axis_angle(axisAngles[i].x, axisAngles[i].y, axisAngles[i].z,
+                                            SkDegreesToRadians(axisAngles[i].w));
+            model = SkM44::Translate(radius, radius) * proj *    // project and place content
+                    zoom * rotateHorizontal * model * postZoom * // main model matrix
+                    SkM44::Translate(-radius, -radius);          // center content
+
+            canvas->save();
+            canvas->experimental_concat44(model);
+
+            SkPaint fillPaint;
+            fillPaint.setAntiAlias(true);
+            fillPaint.setColor(faceColors[i]);
+
+            canvas->drawRect(SkRect::MakeWH(viewportWidth, viewportWidth), fillPaint);
+            canvas->restore();
+        }
+    }
+private:
+    static const int kMaxVW = 800;
+    static const int kMinVW = 300;
+    SkScalar fTime;
+};
+
+DEF_GM(return new CrBug224618GM();)
diff --git a/gn/gm.gni b/gn/gm.gni
index 27a93ea..08cdcdc 100644
--- a/gn/gm.gni
+++ b/gn/gm.gni
@@ -104,6 +104,7 @@
   "$_gm/convexpolyclip.cpp",
   "$_gm/convexpolyeffect.cpp",
   "$_gm/copy_to_4444.cpp",
+  "$_gm/crbug_224618.cpp",
   "$_gm/crbug_691386.cpp",
   "$_gm/crbug_788500.cpp",
   "$_gm/crbug_847759.cpp",