Attempt to throw away rrect clips of rrects.
authorbsalomon <bsalomon@google.com>
Mon, 15 Aug 2016 21:49:10 +0000 (14:49 -0700)
committerCommit bot <commit-bot@chromium.org>
Mon, 15 Aug 2016 21:49:10 +0000 (14:49 -0700)
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2241273003

Review-Url: https://codereview.chromium.org/2241273003

include/core/SkClipStack.h
include/core/SkRRect.h
include/gpu/GrClip.h
src/core/SkClipStack.cpp
src/gpu/GrClipStackClip.cpp
src/gpu/GrClipStackClip.h
src/gpu/GrDrawContext.cpp

index 3156941..2f2e940 100644 (file)
@@ -158,6 +158,23 @@ public:
             }
         }
 
+        bool contains(const SkRRect& rrect) const {
+            switch (fType) {
+                case kRect_Type:
+                    return this->getRect().contains(rrect.getBounds());
+                case kRRect_Type:
+                    // We don't currently have a generalized rrect-rrect containment.
+                    return fRRect.contains(rrect.getBounds()) || rrect == fRRect;
+                case kPath_Type:
+                    return fPath.get()->conservativelyContainsRect(rrect.getBounds());
+                case kEmpty_Type:
+                    return false;
+                default:
+                    SkDEBUGFAIL("Unexpected type.");
+                    return false;
+            }
+        }
+
         /**
          * Is the clip shape inverse filled.
          */
@@ -312,11 +329,12 @@ public:
                    bool* isIntersectionOfRects = NULL) const;
 
     /**
-     * Returns true if the input rect in device space is entirely contained
-     * by the clip. A return value of false does not guarantee that the rect
+     * Returns true if the input (r)rect in device space is entirely contained
+     * by the clip. A return value of false does not guarantee that the (r)rect
      * is not contained by the clip.
      */
     bool quickContains(const SkRect& devRect) const;
+    bool quickContains(const SkRRect& devRRect) const;
 
     /**
      * Flattens the clip stack into a single SkPath. Returns true if any of
index d025412..64db2f3 100644 (file)
@@ -47,6 +47,10 @@ class SkMatrix;
 */
 class SK_API SkRRect {
 public:
+    SkRRect() { /* unititialized */ }
+    SkRRect(const SkRRect&) = default;
+    SkRRect& operator=(const SkRRect&) = default;
+
     /**
      * Enum to capture the various possible subtypes of RR. Accessed
      * by type(). The subtypes become progressively less restrictive.
@@ -274,6 +278,10 @@ public:
         fRect.offset(dx, dy);
     }
 
+    SkRRect SK_WARN_UNUSED_RESULT makeOffset(SkScalar dx, SkScalar dy) const {
+        return SkRRect(fRect.makeOffset(dx, dy), fRadii, fType);
+    }
+
     /**
      *  Returns true if 'rect' is wholy inside the RR, and both
      *  are not empty.
@@ -322,6 +330,11 @@ public:
     void dumpHex() const { this->dump(true); }
 
 private:
+    SkRRect(const SkRect& rect, const SkVector radii[4], int32_t type)
+        : fRect(rect)
+        , fRadii{radii[0], radii[1], radii[2], radii[3]}
+        , fType(type) {}
+
     SkRect fRect;
     // Radii order is UL, UR, LR, LL. Use Corner enum to index into fRadii[]
     SkVector fRadii[4];
index 9db76f0..a6a0a66 100644 (file)
@@ -66,6 +66,9 @@ private:
 class GrClip {
 public:
     virtual bool quickContains(const SkRect&) const = 0;
+    virtual bool quickContains(const SkRRect& rrect) const {
+        return this->quickContains(rrect.getBounds());
+    }
     virtual void getConservativeBounds(int width, int height, SkIRect* devResult,
                                        bool* isIntersectionOfRects = nullptr) const = 0;
     virtual bool apply(GrContext*, GrDrawContext*, bool useHWAA, bool hasUserStencilSettings,
index 06418b4..12ad3bb 100644 (file)
@@ -646,6 +646,31 @@ bool SkClipStack::quickContains(const SkRect& rect) const {
     return true;
 }
 
+bool SkClipStack::quickContains(const SkRRect& rrect) const {
+
+    Iter iter(*this, Iter::kTop_IterStart);
+    const Element* element = iter.prev();
+    while (element != nullptr) {
+        if (SkRegion::kIntersect_Op != element->getOp() && SkRegion::kReplace_Op != element->getOp())
+            return false;
+        if (element->isInverseFilled()) {
+            // Part of 'rrect' could be trimmed off by the inverse-filled clip element
+            if (SkRect::Intersects(element->getBounds(), rrect.getBounds())) {
+                return false;
+            }
+        } else {
+            if (!element->contains(rrect)) {
+                return false;
+            }
+        }
+        if (SkRegion::kReplace_Op == element->getOp()) {
+            break;
+        }
+        element = iter.prev();
+    }
+    return true;
+}
+
 bool SkClipStack::asPath(SkPath *path) const {
     bool isAA = false;
 
index 6cb216e..a3a0de5 100644 (file)
@@ -30,6 +30,14 @@ bool GrClipStackClip::quickContains(const SkRect& rect) const {
                                                  SkIntToScalar(fOrigin.y())));
 }
 
+bool GrClipStackClip::quickContains(const SkRRect& rrect) const {
+    if (!fStack) {
+        return true;
+    }
+    return fStack->quickContains(rrect.makeOffset(SkIntToScalar(fOrigin.fX),
+                                                  SkIntToScalar(fOrigin.fY)));
+}
+
 void GrClipStackClip::getConservativeBounds(int width, int height, SkIRect* devResult,
                                             bool* isIntersectionOfRects) const {
     if (!fStack) {
index 98675e6..1502547 100644 (file)
@@ -31,6 +31,7 @@ public:
     }
 
     bool quickContains(const SkRect&) const final;
+    bool quickContains(const SkRRect&) const final;
     void getConservativeBounds(int width, int height, SkIRect* devResult,
                                bool* isIntersectionOfRects) const final;
     bool apply(GrContext*, GrDrawContext*, bool useHWAA, bool hasUserStencilSettings,
index 76e0d8a..202be23 100644 (file)
@@ -781,7 +781,7 @@ void GrDrawContext::drawAtlas(const GrClip& clip,
 
 ///////////////////////////////////////////////////////////////////////////////
 
-void GrDrawContext::drawRRect(const GrClip& clip,
+void GrDrawContext::drawRRect(const GrClip& origClip,
                               const GrPaint& paint,
                               const SkMatrix& viewMatrix,
                               const SkRRect& rrect,
@@ -790,11 +790,23 @@ void GrDrawContext::drawRRect(const GrClip& clip,
     RETURN_IF_ABANDONED
     SkDEBUGCODE(this->validate();)
     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawRRect");
-
     if (rrect.isEmpty()) {
        return;
     }
 
+    GrNoClip noclip;
+    const GrClip* clip = &origClip;
+#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
+    // The Android framework frequently clips rrects to themselves where the clip is non-aa and the
+    // draw is aa. Since our lower level clip code works from batch bounds, which are SkRects, it
+    // doesn't detect that the clip can be ignored (modulo antialiasing). The following test
+    // attempts to mitigate the stencil clip cost but will only help when the entire clip stack
+    // can be ignored. We'd prefer to fix this in the framework by removing the clips calls.
+    SkRRect devRRect;
+    if (rrect.transform(viewMatrix, &devRRect) && clip->quickContains(devRRect)) {
+        clip = &noclip;
+    }
+#endif
     SkASSERT(!style.pathEffect()); // this should've been devolved to a path in SkGpuDevice
 
     AutoCheckFlush acf(fDrawingManager);
@@ -809,7 +821,7 @@ void GrDrawContext::drawRRect(const GrClip& clip,
                                                         &useHWAA));
         if (batch) {
             GrPipelineBuilder pipelineBuilder(paint, useHWAA);
-            this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch);
+            this->getDrawTarget()->drawBatch(pipelineBuilder, this, *clip, batch);
             return;
         }
     }
@@ -823,7 +835,7 @@ void GrDrawContext::drawRRect(const GrClip& clip,
                                                                          shaderCaps));
         if (batch) {
             GrPipelineBuilder pipelineBuilder(paint, useHWAA);
-            this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch);
+            this->getDrawTarget()->drawBatch(pipelineBuilder, this, *clip, batch);
             return;
         }
     }
@@ -831,7 +843,7 @@ void GrDrawContext::drawRRect(const GrClip& clip,
     SkPath path;
     path.setIsVolatile(true);
     path.addRRect(rrect);
-    this->internalDrawPath(clip, paint, viewMatrix, path, style);
+    this->internalDrawPath(*clip, paint, viewMatrix, path, style);
 }
 
 bool GrDrawContext::drawFilledDRRect(const GrClip& clip,