Fix DMSAA RRectOp bug with skew matrices
This fixes both the new GM (Justin's reduced repro case) and the original Chrome repro case (viewing a specific PDF).
Bug: 1442854
Change-Id: I5861b39556922617ed4b6569d0db51fa8ab33d79
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/702841
Reviewed-by: Jim Van Verth <jvanverth@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/gm/scaledrects.cpp b/gm/scaledrects.cpp
new file mode 100644
index 0000000..81fb3e7
--- /dev/null
+++ b/gm/scaledrects.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2023 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/SkPaint.h"
+#include "include/core/SkRect.h"
+#include "include/core/SkString.h"
+
+namespace skiagm {
+
+// From crbug.com/1442854. Draws two rects (equivalent in device space) but which vary wildly
+// in their sizes and scales. In both cases the clip is what is actually determining the
+// final drawn geometry. For the red rectangle case the inverted skews were becoming very small and
+// ran afoul of some logic in the DMSAA code that zeroed them out.
+class ScaledRectsGM : public GM {
+public:
+ ScaledRectsGM() {
+ this->setBGColor(0xFFCCCCCC);
+ }
+
+protected:
+ SkString onShortName() override {
+ return SkString("scaledrects");
+ }
+
+ SkISize onISize() override {
+ return SkISize::Make(128, 64);
+ }
+
+ void onDraw(SkCanvas* canvas) override {
+ canvas->clipRect(SkRect::MakeXYWH(10, 50, 100, 10));
+
+ {
+ SkPaint blue;
+ blue.setColor(SK_ColorBLUE);
+
+ canvas->setMatrix(SkMatrix::MakeAll( 3.0f, -0.5f, 0.0f,
+ -0.5f, -3.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f));
+
+ canvas->drawRect(SkRect::MakeXYWH(-1000, -1000, 2000, 2000), blue);
+ }
+
+ {
+ SkPaint red;
+ red.setColor(SK_ColorRED);
+ red.setBlendMode(SkBlendMode::kPlus);
+
+ canvas->setMatrix(SkMatrix::MakeAll(3000.0f, -500.0f, 0.0f,
+ -500.0f, -3000.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f));
+
+ canvas->drawRect(SkRect::MakeXYWH(-1, -1, 2, 2), red);
+ }
+ }
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+DEF_GM(return new ScaledRectsGM;)
+
+} // namespace skiagm
diff --git a/gn/gm.gni b/gn/gm.gni
index a8838b3..9016af8 100644
--- a/gn/gm.gni
+++ b/gn/gm.gni
@@ -330,6 +330,7 @@
"$_gm/savelayer.cpp",
"$_gm/scaledemoji.cpp",
"$_gm/scaledemoji_rendering.cpp",
+ "$_gm/scaledrects.cpp",
"$_gm/scaledstrokes.cpp",
"$_gm/shadermaskfilter.cpp",
"$_gm/shadertext3.cpp",
diff --git a/src/gpu/ganesh/GrDrawingManager.cpp b/src/gpu/ganesh/GrDrawingManager.cpp
index 9207b10..bea464b 100644
--- a/src/gpu/ganesh/GrDrawingManager.cpp
+++ b/src/gpu/ganesh/GrDrawingManager.cpp
@@ -229,11 +229,11 @@
bool GrDrawingManager::executeRenderTasks(GrOpFlushState* flushState) {
#if GR_FLUSH_TIME_OP_SPEW
- SkDebugf("Flushing %d opsTasks\n", fDAG.count());
- for (int i = 0; i < fDAG.count(); ++i) {
+ SkDebugf("Flushing %d opsTasks\n", fDAG.size());
+ for (int i = 0; i < fDAG.size(); ++i) {
if (fDAG[i]) {
SkString label;
- label.printf("task %d/%d", i, fDAG.count());
+ label.printf("task %d/%d", i, fDAG.size());
fDAG[i]->dump(label, {}, true, true);
}
}
diff --git a/src/gpu/ganesh/ops/FillRRectOp.cpp b/src/gpu/ganesh/ops/FillRRectOp.cpp
index 5ed3b34..601aa2c 100644
--- a/src/gpu/ganesh/ops/FillRRectOp.cpp
+++ b/src/gpu/ganesh/ops/FillRRectOp.cpp
@@ -33,6 +33,26 @@
namespace {
+// Note: Just checking m.restStaysRect is not sufficient
+bool skews_are_relevant(const SkMatrix& m) {
+ SkASSERT(!m.hasPerspective());
+
+ if (m[SkMatrix::kMSkewX] == 0.0f && m[SkMatrix::kMSkewY] == 0.0f) {
+ return false;
+ }
+
+ static constexpr float kTol = SK_ScalarNearlyZero;
+ float absScaleX = SkScalarAbs(m[SkMatrix::kMScaleX]);
+ float absSkewX = SkScalarAbs(m[SkMatrix::kMSkewX]);
+ float absScaleY = SkScalarAbs(m[SkMatrix::kMScaleY]);
+ float absSkewY = SkScalarAbs(m[SkMatrix::kMSkewY]);
+
+ // The maximum absolute column sum norm of the upper left 2x2
+ float norm = std::max(absScaleX + absSkewY, absSkewX + absScaleY);
+
+ return absSkewX > kTol * norm || absSkewY > kTol * norm;
+}
+
class FillRRectOpImpl final : public GrMeshDrawOp {
private:
using Helper = GrSimpleMeshDrawOpHelper;
@@ -76,6 +96,10 @@
GrProcessorSet::Analysis finalize(const GrCaps&, const GrAppliedClip*, GrClampType) override;
CombineResult onCombineIfPossible(GrOp*, SkArenaAlloc*, const GrCaps&) override;
+#if GR_TEST_UTILS
+ SkString onDumpInfo() const override;
+#endif
+
void visitProxies(const GrVisitProxyFunc& func) const override {
if (fProgramInfo) {
fProgramInfo->visitFPProxies(func);
@@ -259,8 +283,8 @@
}
clipToView.preConcat(clipMatrix);
SkASSERT(!clipToView.hasPerspective());
- if (!SkScalarNearlyZero(clipToView.getSkewX()) ||
- !SkScalarNearlyZero(clipToView.getSkewY())) {
+
+ if (skews_are_relevant(clipToView)) {
// A rect in "clipMatrix" space is not a rect in "viewMatrix" space.
return ClipResult::kFail;
}
@@ -355,6 +379,24 @@
return CombineResult::kMerged;
}
+#if GR_TEST_UTILS
+SkString FillRRectOpImpl::onDumpInfo() const {
+ SkString str = SkStringPrintf("# instances: %u\n", fInstanceCount);
+ str += fHelper.dumpInfo();
+ int i = 0;
+ for (Instance* tmp = fHeadInstance; tmp; tmp = tmp->fNext, ++i) {
+ str.appendf("%d: Color: [%.2f, %.2f, %.2f, %.2f] ",
+ i, tmp->fColor.fR, tmp->fColor.fG, tmp->fColor.fB, tmp->fColor.fA);
+ SkMatrix m = tmp->fViewMatrix;
+ str.appendf("ViewMatrix: [%.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f] ",
+ m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]);
+ SkRect r = tmp->fRRect.rect();
+ str.appendf("Rect: [%f %f %f %f]\n", r.fLeft, r.fTop, r.fRight, r.fBottom);
+ }
+ return str;
+}
+#endif
+
class FillRRectOpImpl::Processor final : public GrGeometryProcessor {
public:
static GrGeometryProcessor* Make(SkArenaAlloc* arena, GrAAType aaType, ProcessorFlags flags) {
diff --git a/tools/flags/CommonFlagsConfig.cpp b/tools/flags/CommonFlagsConfig.cpp
index 0e9a24de..bdedb97 100644
--- a/tools/flags/CommonFlagsConfig.cpp
+++ b/tools/flags/CommonFlagsConfig.cpp
@@ -123,6 +123,7 @@
{ "mtlf16norm", "gpu", "api=metal,color=f16norm" },
{ "mtlsrgba", "gpu", "api=metal,color=srgba"},
{ "mtl1010102", "gpu", "api=metal,color=1010102" },
+ { "mtl_dmsaa", "gpu", "api=metal,dmsaa=true" },
{ "mtlmsaa4", "gpu", "api=metal,samples=4" },
{ "mtlmsaa8", "gpu", "api=metal,samples=8" },
{ "mtlddl", "gpu", "api=metal,useDDLSink=true" },