Reland of Better encapsulate oval/rrect batchs. (patchset #1 id:1 of https://coderevi...
authorbsalomon <bsalomon@google.com>
Fri, 8 Jul 2016 11:42:54 +0000 (04:42 -0700)
committerCommit bot <commit-bot@chromium.org>
Fri, 8 Jul 2016 11:42:54 +0000 (04:42 -0700)
Reason for revert:
Workaround for compiler/stdlib bug landed: https://codereview.chromium.org/2135453002

Original issue's description:
> Revert of Better encapsulate oval/rrect batchs. (patchset #5 id:80001 of https://codereview.chromium.org/2104423003/ )
>
> Reason for revert:
> This CL is suspected to break compilation on arm64.
> https://build.chromium.org/p/chromium.android/builders/Android%20arm64%20Builder%20%28dbg%29/builds/5851/steps/compile/logs/stdio
>
> Original issue's description:
> > Better encapsulate oval/rrect batchs.
> > GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2104423003
> >
> > Committed: https://skia.googlesource.com/skia/+/5fd209e8ee477c703bc5c11b008f247d515fc0fc
> > Committed: https://skia.googlesource.com/skia/+/7f06c6947a3bef78dc57b9252779567c33604c90
> > Committed: https://skia.googlesource.com/skia/+/11bf8b2eae7d1780cb969146422a2ab3b933047a
>
> TBR=robertphillips@google.com,bsalomon@google.com
> # Skipping CQ checks because original CL landed less than 1 days ago.
> NOPRESUBMIT=true
> NOTREECHECKS=true
> NOTRY=true
>
> Committed: https://skia.googlesource.com/skia/+/c79fc33d3e83664ffbd3651df3131c3e9e0b635c

TBR=robertphillips@google.com,hush@chromium.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true

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

src/gpu/GrOvalRenderer.cpp
src/gpu/GrOvalRenderer.h

index 3f73c6b..f5dcfcb 100644 (file)
@@ -524,49 +524,58 @@ sk_sp<GrGeometryProcessor> DIEllipseGeometryProcessor::TestCreate(GrProcessorTes
 
 ///////////////////////////////////////////////////////////////////////////////
 
-GrDrawBatch* GrOvalRenderer::CreateOvalBatch(GrColor color,
-                                             const SkMatrix& viewMatrix,
-                                             const SkRect& oval,
-                                             const SkStrokeRec& stroke,
-                                             GrShaderCaps* shaderCaps) {
-    // we can draw circles
-    if (SkScalarNearlyEqual(oval.width(), oval.height()) && circle_stays_circle(viewMatrix)) {
-        return CreateCircleBatch(color, viewMatrix, oval, stroke);
-    }
-
-    // if we have shader derivative support, render as device-independent
-    if (shaderCaps->shaderDerivativeSupport()) {
-        return CreateDIEllipseBatch(color, viewMatrix, oval, stroke);
-    }
+class CircleBatch : public GrVertexBatch {
+public:
+    DEFINE_BATCH_CLASS_ID
 
-    // otherwise axis-aligned ellipses only
-    if (viewMatrix.rectStaysRect()) {
-        return CreateEllipseBatch(color, viewMatrix, oval, stroke);
-    }
+    CircleBatch(GrColor color, const SkMatrix& viewMatrix, const SkRect& circle,
+                const SkStrokeRec& stroke)
+            : INHERITED(ClassID())
+            , fViewMatrixIfUsingLocalCoords(viewMatrix) {
+        SkPoint center = SkPoint::Make(circle.centerX(), circle.centerY());
+        viewMatrix.mapPoints(&center, 1);
+        SkScalar radius = viewMatrix.mapRadius(SkScalarHalf(circle.width()));
+        SkScalar strokeWidth = viewMatrix.mapRadius(stroke.getWidth());
 
-    return nullptr;
-}
+        SkStrokeRec::Style style = stroke.getStyle();
+        bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
+                            SkStrokeRec::kHairline_Style == style;
+        bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
 
-///////////////////////////////////////////////////////////////////////////////
+        SkScalar innerRadius = 0.0f;
+        SkScalar outerRadius = radius;
+        SkScalar halfWidth = 0;
+        if (hasStroke) {
+            if (SkScalarNearlyZero(strokeWidth)) {
+                halfWidth = SK_ScalarHalf;
+            } else {
+                halfWidth = SkScalarHalf(strokeWidth);
+            }
 
-class CircleBatch : public GrVertexBatch {
-public:
-    DEFINE_BATCH_CLASS_ID
+            outerRadius += halfWidth;
+            if (isStrokeOnly) {
+                innerRadius = radius - halfWidth;
+            }
+        }
 
-    struct Geometry {
-        SkRect fDevBounds;
-        SkScalar fInnerRadius;
-        SkScalar fOuterRadius;
-        GrColor fColor;
-    };
+        // The radii are outset for two reasons. First, it allows the shader to simply perform
+        // simpler computation because the computed alpha is zero, rather than 50%, at the radius.
+        // Second, the outer radius is used to compute the verts of the bounding box that is
+        // rendered and the outset ensures the box will cover all partially covered by the circle.
+        outerRadius += SK_ScalarHalf;
+        innerRadius -= SK_ScalarHalf;
 
-    CircleBatch(const Geometry& geometry, const SkMatrix& viewMatrix, bool stroked)
-        : INHERITED(ClassID())
-        , fStroked(stroked)
-        , fViewMatrixIfUsingLocalCoords(viewMatrix) {
-        fGeoData.push_back(geometry);
-        this->setBounds(geometry.fDevBounds);
+        fGeoData.emplace_back(Geometry {
+            color,
+            innerRadius,
+            outerRadius,
+            SkRect::MakeLTRB(center.fX - outerRadius, center.fY - outerRadius,
+                             center.fX + outerRadius, center.fY + outerRadius)
+        });
+        this->setBounds(fGeoData.back().fDevBounds);
+        fStroked = isStrokeOnly && innerRadius > 0;
     }
+
     const char* name() const override { return "CircleBatch"; }
 
     SkString dumpInfo() const override {
@@ -680,6 +689,13 @@ private:
         return true;
     }
 
+    struct Geometry {
+        GrColor fColor;
+        SkScalar fInnerRadius;
+        SkScalar fOuterRadius;
+        SkRect fDevBounds;
+    };
+
     bool                         fStroked;
     SkMatrix                     fViewMatrixIfUsingLocalCoords;
     SkSTArray<1, Geometry, true> fGeoData;
@@ -687,81 +703,87 @@ private:
     typedef GrVertexBatch INHERITED;
 };
 
-static GrDrawBatch* create_circle_batch(GrColor color,
-                                        const SkMatrix& viewMatrix,
-                                        const SkRect& circle,
-                                        const SkStrokeRec& stroke) {
-    SkPoint center = SkPoint::Make(circle.centerX(), circle.centerY());
-    viewMatrix.mapPoints(&center, 1);
-    SkScalar radius = viewMatrix.mapRadius(SkScalarHalf(circle.width()));
-    SkScalar strokeWidth = viewMatrix.mapRadius(stroke.getWidth());
-
-    SkStrokeRec::Style style = stroke.getStyle();
-    bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
-                        SkStrokeRec::kHairline_Style == style;
-    bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
-
-    SkScalar innerRadius = 0.0f;
-    SkScalar outerRadius = radius;
-    SkScalar halfWidth = 0;
-    if (hasStroke) {
-        if (SkScalarNearlyZero(strokeWidth)) {
-            halfWidth = SK_ScalarHalf;
-        } else {
-            halfWidth = SkScalarHalf(strokeWidth);
-        }
-
-        outerRadius += halfWidth;
-        if (isStrokeOnly) {
-            innerRadius = radius - halfWidth;
-        }
-    }
-
-    // The radii are outset for two reasons. First, it allows the shader to simply perform simpler
-    // computation because the computed alpha is zero, rather than 50%, at the radius.
-    // Second, the outer radius is used to compute the verts of the bounding box that is rendered
-    // and the outset ensures the box will cover all partially covered by the circle.
-    outerRadius += SK_ScalarHalf;
-    innerRadius -= SK_ScalarHalf;
-
-    CircleBatch::Geometry geometry;
-    geometry.fColor = color;
-    geometry.fInnerRadius = innerRadius;
-    geometry.fOuterRadius = outerRadius;
-    geometry.fDevBounds = SkRect::MakeLTRB(center.fX - outerRadius, center.fY - outerRadius,
-                                           center.fX + outerRadius, center.fY + outerRadius);
-
-    return new CircleBatch(geometry, viewMatrix, isStrokeOnly && innerRadius > 0);
-}
-
-GrDrawBatch* GrOvalRenderer::CreateCircleBatch(GrColor color,
-                                               const SkMatrix& viewMatrix,
-                                               const SkRect& circle,
-                                               const SkStrokeRec& stroke) {
-    return create_circle_batch(color, viewMatrix, circle, stroke);
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 
 class EllipseBatch : public GrVertexBatch {
 public:
     DEFINE_BATCH_CLASS_ID
+    static GrDrawBatch* Create(GrColor color, const SkMatrix& viewMatrix, const SkRect& ellipse,
+                               const SkStrokeRec& stroke) {
+        SkASSERT(viewMatrix.rectStaysRect());
+
+        // do any matrix crunching before we reset the draw state for device coords
+        SkPoint center = SkPoint::Make(ellipse.centerX(), ellipse.centerY());
+        viewMatrix.mapPoints(&center, 1);
+        SkScalar ellipseXRadius = SkScalarHalf(ellipse.width());
+        SkScalar ellipseYRadius = SkScalarHalf(ellipse.height());
+        SkScalar xRadius = SkScalarAbs(viewMatrix[SkMatrix::kMScaleX]*ellipseXRadius +
+                                       viewMatrix[SkMatrix::kMSkewY]*ellipseYRadius);
+        SkScalar yRadius = SkScalarAbs(viewMatrix[SkMatrix::kMSkewX]*ellipseXRadius +
+                                       viewMatrix[SkMatrix::kMScaleY]*ellipseYRadius);
+
+        // do (potentially) anisotropic mapping of stroke
+        SkVector scaledStroke;
+        SkScalar strokeWidth = stroke.getWidth();
+        scaledStroke.fX = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMScaleX] +
+                                                   viewMatrix[SkMatrix::kMSkewY]));
+        scaledStroke.fY = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMSkewX] +
+                                                   viewMatrix[SkMatrix::kMScaleY]));
+
+        SkStrokeRec::Style style = stroke.getStyle();
+        bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
+                            SkStrokeRec::kHairline_Style == style;
+        bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
+
+        SkScalar innerXRadius = 0;
+        SkScalar innerYRadius = 0;
+        if (hasStroke) {
+            if (SkScalarNearlyZero(scaledStroke.length())) {
+                scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
+            } else {
+                scaledStroke.scale(SK_ScalarHalf);
+            }
 
-    struct Geometry {
-        SkRect fDevBounds;
-        SkScalar fXRadius;
-        SkScalar fYRadius;
-        SkScalar fInnerXRadius;
-        SkScalar fInnerYRadius;
-        GrColor fColor;
-    };
+            // we only handle thick strokes for near-circular ellipses
+            if (scaledStroke.length() > SK_ScalarHalf &&
+                (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)) {
+                return nullptr;
+            }
 
-    EllipseBatch(const Geometry& geometry, const SkMatrix& viewMatrix, bool stroked)
-        : INHERITED(ClassID())
-        , fStroked(stroked)
-        , fViewMatrixIfUsingLocalCoords(viewMatrix) {
-        fGeoData.push_back(geometry);
-        this->setBounds(geometry.fDevBounds);
+            // we don't handle it if curvature of the stroke is less than curvature of the ellipse
+            if (scaledStroke.fX*(yRadius*yRadius) < (scaledStroke.fY*scaledStroke.fY)*xRadius ||
+                scaledStroke.fY*(xRadius*xRadius) < (scaledStroke.fX*scaledStroke.fX)*yRadius) {
+                return nullptr;
+            }
+
+            // this is legit only if scale & translation (which should be the case at the moment)
+            if (isStrokeOnly) {
+                innerXRadius = xRadius - scaledStroke.fX;
+                innerYRadius = yRadius - scaledStroke.fY;
+            }
+
+            xRadius += scaledStroke.fX;
+            yRadius += scaledStroke.fY;
+        }
+
+        EllipseBatch* batch = new EllipseBatch();
+        batch->fGeoData.emplace_back(Geometry {
+            color,
+            xRadius,
+            yRadius,
+            innerXRadius,
+            innerYRadius,
+            SkRect::MakeLTRB(center.fX - xRadius, center.fY - yRadius,
+                             center.fX + xRadius, center.fY + yRadius)
+        });
+
+        // Outset bounds to include half-pixel width antialiasing.
+        batch->fGeoData[0].fDevBounds.outset(SK_ScalarHalf, SK_ScalarHalf);
+
+        batch->fStroked = isStrokeOnly && innerXRadius > 0 && innerYRadius > 0;
+        batch->fViewMatrixIfUsingLocalCoords = viewMatrix;
+        batch->setBounds(batch->fGeoData.back().fDevBounds);
+        return batch;
     }
 
     const char* name() const override { return "EllipseBatch"; }
@@ -775,6 +797,8 @@ public:
     }
 
 private:
+    EllipseBatch() : INHERITED(ClassID()) {}
+
     void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
         // Handle any overrides that affect our GP.
         if (!overrides.readsCoverage()) {
@@ -874,6 +898,14 @@ private:
         return true;
     }
 
+    struct Geometry {
+        GrColor fColor;
+        SkScalar fXRadius;
+        SkScalar fYRadius;
+        SkScalar fInnerXRadius;
+        SkScalar fInnerYRadius;
+        SkRect fDevBounds;
+    };
 
     bool                         fStroked;
     SkMatrix                     fViewMatrixIfUsingLocalCoords;
@@ -882,110 +914,89 @@ private:
     typedef GrVertexBatch INHERITED;
 };
 
-static GrDrawBatch* create_ellipse_batch(GrColor color,
-                                         const SkMatrix& viewMatrix,
-                                         const SkRect& ellipse,
-                                         const SkStrokeRec& stroke) {
-    SkASSERT(viewMatrix.rectStaysRect());
+/////////////////////////////////////////////////////////////////////////////////////////////////
 
-    // do any matrix crunching before we reset the draw state for device coords
-    SkPoint center = SkPoint::Make(ellipse.centerX(), ellipse.centerY());
-    viewMatrix.mapPoints(&center, 1);
-    SkScalar ellipseXRadius = SkScalarHalf(ellipse.width());
-    SkScalar ellipseYRadius = SkScalarHalf(ellipse.height());
-    SkScalar xRadius = SkScalarAbs(viewMatrix[SkMatrix::kMScaleX]*ellipseXRadius +
-                                   viewMatrix[SkMatrix::kMSkewY]*ellipseYRadius);
-    SkScalar yRadius = SkScalarAbs(viewMatrix[SkMatrix::kMSkewX]*ellipseXRadius +
-                                   viewMatrix[SkMatrix::kMScaleY]*ellipseYRadius);
-
-    // do (potentially) anisotropic mapping of stroke
-    SkVector scaledStroke;
-    SkScalar strokeWidth = stroke.getWidth();
-    scaledStroke.fX = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMScaleX] +
-                                               viewMatrix[SkMatrix::kMSkewY]));
-    scaledStroke.fY = SkScalarAbs(strokeWidth*(viewMatrix[SkMatrix::kMSkewX] +
-                                               viewMatrix[SkMatrix::kMScaleY]));
+class DIEllipseBatch : public GrVertexBatch {
+public:
+    DEFINE_BATCH_CLASS_ID
 
-    SkStrokeRec::Style style = stroke.getStyle();
-    bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
-                        SkStrokeRec::kHairline_Style == style;
-    bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == style;
+    static GrDrawBatch* Create(GrColor color,
+                               const SkMatrix& viewMatrix,
+                               const SkRect& ellipse,
+                               const SkStrokeRec& stroke) {
+        SkPoint center = SkPoint::Make(ellipse.centerX(), ellipse.centerY());
+        SkScalar xRadius = SkScalarHalf(ellipse.width());
+        SkScalar yRadius = SkScalarHalf(ellipse.height());
+
+        SkStrokeRec::Style style = stroke.getStyle();
+        DIEllipseStyle dieStyle = (SkStrokeRec::kStroke_Style == style) ?
+                                  DIEllipseStyle::kStroke :
+                                  (SkStrokeRec::kHairline_Style == style) ?
+                                  DIEllipseStyle::kHairline : DIEllipseStyle::kFill;
+
+        SkScalar innerXRadius = 0;
+        SkScalar innerYRadius = 0;
+        if (SkStrokeRec::kFill_Style != style && SkStrokeRec::kHairline_Style != style) {
+            SkScalar strokeWidth = stroke.getWidth();
+
+            if (SkScalarNearlyZero(strokeWidth)) {
+                strokeWidth = SK_ScalarHalf;
+            } else {
+                strokeWidth *= SK_ScalarHalf;
+            }
 
-    SkScalar innerXRadius = 0;
-    SkScalar innerYRadius = 0;
-    if (hasStroke) {
-        if (SkScalarNearlyZero(scaledStroke.length())) {
-            scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
-        } else {
-            scaledStroke.scale(SK_ScalarHalf);
-        }
+            // we only handle thick strokes for near-circular ellipses
+            if (strokeWidth > SK_ScalarHalf &&
+                (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)) {
+                return nullptr;
+            }
 
-        // we only handle thick strokes for near-circular ellipses
-        if (scaledStroke.length() > SK_ScalarHalf &&
-            (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)) {
-            return nullptr;
-        }
+            // we don't handle it if curvature of the stroke is less than curvature of the ellipse
+            if (strokeWidth*(yRadius*yRadius) < (strokeWidth*strokeWidth)*xRadius ||
+                strokeWidth*(xRadius*xRadius) < (strokeWidth*strokeWidth)*yRadius) {
+                return nullptr;
+            }
 
-        // we don't handle it if curvature of the stroke is less than curvature of the ellipse
-        if (scaledStroke.fX*(yRadius*yRadius) < (scaledStroke.fY*scaledStroke.fY)*xRadius ||
-            scaledStroke.fY*(xRadius*xRadius) < (scaledStroke.fX*scaledStroke.fX)*yRadius) {
-            return nullptr;
-        }
+            // set inner radius (if needed)
+            if (SkStrokeRec::kStroke_Style == style) {
+                innerXRadius = xRadius - strokeWidth;
+                innerYRadius = yRadius - strokeWidth;
+            }
 
-        // this is legit only if scale & translation (which should be the case at the moment)
-        if (isStrokeOnly) {
-            innerXRadius = xRadius - scaledStroke.fX;
-            innerYRadius = yRadius - scaledStroke.fY;
+            xRadius += strokeWidth;
+            yRadius += strokeWidth;
+        }
+        if (DIEllipseStyle::kStroke == dieStyle) {
+            dieStyle = (innerXRadius > 0 && innerYRadius > 0) ? DIEllipseStyle ::kStroke :
+                       DIEllipseStyle ::kFill;
         }
 
-        xRadius += scaledStroke.fX;
-        yRadius += scaledStroke.fY;
-    }
-
-    EllipseBatch::Geometry geometry;
-    geometry.fColor = color;
-    geometry.fXRadius = xRadius;
-    geometry.fYRadius = yRadius;
-    geometry.fInnerXRadius = innerXRadius;
-    geometry.fInnerYRadius = innerYRadius;
-    geometry.fDevBounds = SkRect::MakeLTRB(center.fX - xRadius, center.fY - yRadius,
-                                           center.fX + xRadius, center.fY + yRadius);
-
-    // outset bounds to include half-pixel width antialiasing. 
-    geometry.fDevBounds.outset(SK_ScalarHalf, SK_ScalarHalf);
-
-    return new EllipseBatch(geometry, viewMatrix,
-                            isStrokeOnly && innerXRadius > 0 && innerYRadius > 0);
-}
-
-GrDrawBatch* GrOvalRenderer::CreateEllipseBatch(GrColor color,
-                                                const SkMatrix& viewMatrix,
-                                                const SkRect& ellipse,
-                                                const SkStrokeRec& stroke) {
-    return create_ellipse_batch(color, viewMatrix, ellipse, stroke);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////////////
-
-class DIEllipseBatch : public GrVertexBatch {
-public:
-    DEFINE_BATCH_CLASS_ID
-
-    struct Geometry {
-        SkMatrix fViewMatrix;
-        SkRect fBounds;
-        SkScalar fXRadius;
-        SkScalar fYRadius;
-        SkScalar fInnerXRadius;
-        SkScalar fInnerYRadius;
-        SkScalar fGeoDx;
-        SkScalar fGeoDy;
-        GrColor fColor;
-        DIEllipseStyle fStyle;
-    };
-
-    static GrDrawBatch* Create(const Geometry& geometry, const SkRect& bounds) {
-        return new DIEllipseBatch(geometry, bounds);
+        // This expands the outer rect so that after CTM we end up with a half-pixel border
+        SkScalar a = viewMatrix[SkMatrix::kMScaleX];
+        SkScalar b = viewMatrix[SkMatrix::kMSkewX];
+        SkScalar c = viewMatrix[SkMatrix::kMSkewY];
+        SkScalar d = viewMatrix[SkMatrix::kMScaleY];
+        SkScalar geoDx = SK_ScalarHalf / SkScalarSqrt(a*a + c*c);
+        SkScalar geoDy = SK_ScalarHalf / SkScalarSqrt(b*b + d*d);
+
+        DIEllipseBatch* batch = new DIEllipseBatch();
+        batch->fGeoData.emplace_back(Geometry {
+            viewMatrix,
+            color,
+            xRadius,
+            yRadius,
+            innerXRadius,
+            innerYRadius,
+            geoDx,
+            geoDy,
+            dieStyle,
+            SkRect::MakeLTRB(center.fX - xRadius - geoDx, center.fY - yRadius - geoDy,
+                             center.fX + xRadius + geoDx, center.fY + yRadius + geoDy)
+        });
+        SkRect devBounds = batch->fGeoData.back().fBounds;
+        viewMatrix.mapRect(&devBounds);
+        batch->setBounds(devBounds);
+        return batch;
     }
 
     const char* name() const override { return "DIEllipseBatch"; }
@@ -1000,6 +1011,8 @@ public:
 
 private:
 
+    DIEllipseBatch() : INHERITED(ClassID()) {}
+
     void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
         // Handle any overrides that affect our GP.
         overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
@@ -1062,12 +1075,6 @@ private:
         helper.recordDraw(target, gp);
     }
 
-    DIEllipseBatch(const Geometry& geometry, const SkRect& bounds) : INHERITED(ClassID()) {
-        fGeoData.push_back(geometry);
-
-        this->setBounds(bounds);
-    }
-
     bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
         DIEllipseBatch* that = t->cast<DIEllipseBatch>();
         if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
@@ -1092,96 +1099,25 @@ private:
     const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
     DIEllipseStyle style() const { return fGeoData[0].fStyle; }
 
+    struct Geometry {
+        SkMatrix fViewMatrix;
+        GrColor fColor;
+        SkScalar fXRadius;
+        SkScalar fYRadius;
+        SkScalar fInnerXRadius;
+        SkScalar fInnerYRadius;
+        SkScalar fGeoDx;
+        SkScalar fGeoDy;
+        DIEllipseStyle fStyle;
+        SkRect fBounds;
+    };
+
     bool                         fUsesLocalCoords;
     SkSTArray<1, Geometry, true> fGeoData;
 
     typedef GrVertexBatch INHERITED;
 };
 
-static GrDrawBatch* create_diellipse_batch(GrColor color,
-                                           const SkMatrix& viewMatrix,
-                                           const SkRect& ellipse,
-                                           const SkStrokeRec& stroke) {
-    SkPoint center = SkPoint::Make(ellipse.centerX(), ellipse.centerY());
-    SkScalar xRadius = SkScalarHalf(ellipse.width());
-    SkScalar yRadius = SkScalarHalf(ellipse.height());
-
-    SkStrokeRec::Style style = stroke.getStyle();
-    DIEllipseStyle dieStyle = (SkStrokeRec::kStroke_Style == style) ?
-                                DIEllipseStyle::kStroke :
-                                (SkStrokeRec::kHairline_Style == style) ?
-                                        DIEllipseStyle::kHairline : DIEllipseStyle::kFill;
-
-    SkScalar innerXRadius = 0;
-    SkScalar innerYRadius = 0;
-    if (SkStrokeRec::kFill_Style != style && SkStrokeRec::kHairline_Style != style) {
-        SkScalar strokeWidth = stroke.getWidth();
-
-        if (SkScalarNearlyZero(strokeWidth)) {
-            strokeWidth = SK_ScalarHalf;
-        } else {
-            strokeWidth *= SK_ScalarHalf;
-        }
-
-        // we only handle thick strokes for near-circular ellipses
-        if (strokeWidth > SK_ScalarHalf &&
-            (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)) {
-            return nullptr;
-        }
-
-        // we don't handle it if curvature of the stroke is less than curvature of the ellipse
-        if (strokeWidth*(yRadius*yRadius) < (strokeWidth*strokeWidth)*xRadius ||
-            strokeWidth*(xRadius*xRadius) < (strokeWidth*strokeWidth)*yRadius) {
-            return nullptr;
-        }
-
-        // set inner radius (if needed)
-        if (SkStrokeRec::kStroke_Style == style) {
-            innerXRadius = xRadius - strokeWidth;
-            innerYRadius = yRadius - strokeWidth;
-        }
-
-        xRadius += strokeWidth;
-        yRadius += strokeWidth;
-    }
-    if (DIEllipseStyle::kStroke == dieStyle) {
-        dieStyle = (innerXRadius > 0 && innerYRadius > 0) ? DIEllipseStyle ::kStroke :
-                                                            DIEllipseStyle ::kFill;
-    }
-
-    // This expands the outer rect so that after CTM we end up with a half-pixel border
-    SkScalar a = viewMatrix[SkMatrix::kMScaleX];
-    SkScalar b = viewMatrix[SkMatrix::kMSkewX];
-    SkScalar c = viewMatrix[SkMatrix::kMSkewY];
-    SkScalar d = viewMatrix[SkMatrix::kMScaleY];
-    SkScalar geoDx = SK_ScalarHalf / SkScalarSqrt(a*a + c*c);
-    SkScalar geoDy = SK_ScalarHalf / SkScalarSqrt(b*b + d*d);
-
-    DIEllipseBatch::Geometry geometry;
-    geometry.fViewMatrix = viewMatrix;
-    geometry.fColor = color;
-    geometry.fXRadius = xRadius;
-    geometry.fYRadius = yRadius;
-    geometry.fInnerXRadius = innerXRadius;
-    geometry.fInnerYRadius = innerYRadius;
-    geometry.fGeoDx = geoDx;
-    geometry.fGeoDy = geoDy;
-    geometry.fStyle = dieStyle;
-    geometry.fBounds = SkRect::MakeLTRB(center.fX - xRadius - geoDx, center.fY - yRadius - geoDy,
-                                        center.fX + xRadius + geoDx, center.fY + yRadius + geoDy);
-
-    SkRect devBounds = geometry.fBounds;
-    viewMatrix.mapRect(&devBounds);
-    return DIEllipseBatch::Create(geometry, devBounds);
-}
-
-GrDrawBatch* GrOvalRenderer::CreateDIEllipseBatch(GrColor color,
-                                                  const SkMatrix& viewMatrix,
-                                                  const SkRect& ellipse,
-                                                  const SkStrokeRec& stroke) {
-    return create_diellipse_batch(color, viewMatrix, ellipse, stroke);
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 
 static const uint16_t gRRectIndices[] = {
@@ -1231,20 +1167,46 @@ class RRectCircleRendererBatch : public GrVertexBatch {
 public:
     DEFINE_BATCH_CLASS_ID
 
-    struct Geometry {
-        SkRect fDevBounds;
-        SkScalar fInnerRadius;
-        SkScalar fOuterRadius;
-        GrColor  fColor;
-    };
+    // A devStrokeWidth <= 0 indicates a fill only. If devStrokeWidth > 0 then strokeOnly indicates
+    // whether the rrect is only stroked or stroked and filled.
+    RRectCircleRendererBatch(GrColor color, const SkMatrix& viewMatrix, const SkRect& devRect,
+                             float devRadius, float devStrokeWidth, bool strokeOnly)
+            : INHERITED(ClassID())
+            , fViewMatrixIfUsingLocalCoords(viewMatrix) {
+        SkRect bounds = devRect;
+        SkASSERT(!(devStrokeWidth <= 0 && strokeOnly));
+        SkScalar innerRadius = 0.0f;
+        SkScalar outerRadius = devRadius;
+        SkScalar halfWidth = 0;
+        fStroked = false;
+        if (devStrokeWidth > 0) {
+            if (SkScalarNearlyZero(devStrokeWidth)) {
+                halfWidth = SK_ScalarHalf;
+            } else {
+                halfWidth = SkScalarHalf(devStrokeWidth);
+            }
 
-    RRectCircleRendererBatch(const Geometry& geometry, const SkMatrix& viewMatrix, bool stroked)
-        : INHERITED(ClassID())
-        , fStroked(stroked)
-        , fViewMatrixIfUsingLocalCoords(viewMatrix) {
-        fGeoData.push_back(geometry);
+            if (strokeOnly) {
+                innerRadius = devRadius - halfWidth;
+                fStroked = innerRadius >= 0;
+            }
+            outerRadius += halfWidth;
+            bounds.outset(halfWidth, halfWidth);
+        }
 
-        this->setBounds(geometry.fDevBounds);
+        // The radii are outset for two reasons. First, it allows the shader to simply perform
+        // simpler computation because the computed alpha is zero, rather than 50%, at the radius.
+        // Second, the outer radius is used to compute the verts of the bounding box that is
+        // rendered and the outset ensures the box will cover all partially covered by the rrect
+        // corners.
+        outerRadius += SK_ScalarHalf;
+        innerRadius -= SK_ScalarHalf;
+
+        // Expand the rect so all the pixels will be captured.
+        bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
+
+        fGeoData.emplace_back(Geometry { color, innerRadius, outerRadius, bounds });
+        this->setBounds(bounds);
     }
 
     const char* name() const override { return "RRectCircleBatch"; }
@@ -1366,6 +1328,13 @@ private:
         return true;
     }
 
+    struct Geometry {
+        GrColor  fColor;
+        SkScalar fInnerRadius;
+        SkScalar fOuterRadius;
+        SkRect fDevBounds;
+    };
+
     bool                         fStroked;
     SkMatrix                     fViewMatrixIfUsingLocalCoords;
     SkSTArray<1, Geometry, true> fGeoData;
@@ -1377,21 +1346,64 @@ class RRectEllipseRendererBatch : public GrVertexBatch {
 public:
     DEFINE_BATCH_CLASS_ID
 
-    struct Geometry {
-        SkRect fDevBounds;
-        SkScalar fXRadius;
-        SkScalar fYRadius;
-        SkScalar fInnerXRadius;
-        SkScalar fInnerYRadius;
-        GrColor fColor;
-    };
+    // If devStrokeWidths values are <= 0 indicates then fill only. Otherwise, strokeOnly indicates
+    // whether the rrect is only stroked or stroked and filled.
+    static GrDrawBatch* Create(GrColor color, const SkMatrix& viewMatrix, const SkRect& devRect,
+                               float devXRadius, float devYRadius, SkVector devStrokeWidths,
+                               bool strokeOnly) {
+        SkASSERT(devXRadius > 0.5);
+        SkASSERT(devYRadius > 0.5);
+        SkASSERT((devStrokeWidths.fX > 0) == (devStrokeWidths.fY > 0));
+        SkASSERT(!(strokeOnly && devStrokeWidths.fX <= 0));
+        SkScalar innerXRadius = 0.0f;
+        SkScalar innerYRadius = 0.0f;
+        SkRect bounds = devRect;
+        bool stroked = false;
+        if (devStrokeWidths.fX > 0) {
+            if (SkScalarNearlyZero(devStrokeWidths.length())) {
+                devStrokeWidths.set(SK_ScalarHalf, SK_ScalarHalf);
+            } else {
+                devStrokeWidths.scale(SK_ScalarHalf);
+            }
+
+            // we only handle thick strokes for near-circular ellipses
+            if (devStrokeWidths.length() > SK_ScalarHalf &&
+                (SK_ScalarHalf*devXRadius > devYRadius || SK_ScalarHalf*devYRadius > devXRadius)) {
+                return nullptr;
+            }
+
+            // we don't handle it if curvature of the stroke is less than curvature of the ellipse
+            if (devStrokeWidths.fX*(devYRadius*devYRadius) <
+                (devStrokeWidths.fY*devStrokeWidths.fY)*devXRadius) {
+                return nullptr;
+            }
+            if (devStrokeWidths.fY*(devXRadius*devXRadius) <
+                (devStrokeWidths.fX*devStrokeWidths.fX)*devYRadius) {
+                return nullptr;
+            }
 
-    RRectEllipseRendererBatch(const Geometry& geometry, const SkMatrix& viewMatrix, bool stroked)
-        : INHERITED(ClassID())
-        , fStroked(stroked)
-        , fViewMatrixIfUsingLocalCoords(viewMatrix) {
-        fGeoData.push_back(geometry);
-        this->setBounds(geometry.fDevBounds);
+            // this is legit only if scale & translation (which should be the case at the moment)
+            if (strokeOnly) {
+                innerXRadius = devXRadius - devStrokeWidths.fX;
+                innerYRadius = devYRadius - devStrokeWidths.fY;
+                stroked = (innerXRadius >= 0 && innerYRadius >= 0);
+            }
+
+            devXRadius += devStrokeWidths.fX;
+            devYRadius += devStrokeWidths.fY;
+            bounds.outset(devStrokeWidths.fX, devStrokeWidths.fY);
+        }
+
+        // Expand the rect so all the pixels will be captured.
+        bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
+
+        RRectEllipseRendererBatch* batch = new RRectEllipseRendererBatch();
+        batch->fStroked = stroked;
+        batch->fViewMatrixIfUsingLocalCoords = viewMatrix;
+        batch->fGeoData.emplace_back(
+            Geometry {color, devXRadius, devYRadius, innerXRadius, innerYRadius, bounds});
+        batch->setBounds(bounds);
+        return batch;
     }
 
     const char* name() const override { return "RRectEllipseRendererBatch"; }
@@ -1405,6 +1417,8 @@ public:
     }
 
 private:
+    RRectEllipseRendererBatch() : INHERITED(ClassID()) {}
+
     void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
         // Handle overrides that affect our GP.
         overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
@@ -1524,6 +1538,15 @@ private:
         return true;
     }
 
+    struct Geometry {
+        GrColor fColor;
+        SkScalar fXRadius;
+        SkScalar fYRadius;
+        SkScalar fInnerXRadius;
+        SkScalar fInnerYRadius;
+        SkRect fDevBounds;
+    };
+
     bool                            fStroked;
     SkMatrix                        fViewMatrixIfUsingLocalCoords;
     SkSTArray<1, Geometry, true>    fGeoData;
@@ -1553,8 +1576,8 @@ static GrDrawBatch* create_rrect_batch(GrColor color,
 
     SkStrokeRec::Style style = stroke.getStyle();
 
-    // do (potentially) anisotropic mapping of stroke
-    SkVector scaledStroke;
+    // Do (potentially) anisotropic mapping of stroke. Use -1s to indicate fill-only draws.
+    SkVector scaledStroke = {-1, -1};
     SkScalar strokeWidth = stroke.getWidth();
 
     bool isStrokeOnly = SkStrokeRec::kStroke_Style == style ||
@@ -1588,91 +1611,13 @@ static GrDrawBatch* create_rrect_batch(GrColor color,
 
     // if the corners are circles, use the circle renderer
     if ((!hasStroke || scaledStroke.fX == scaledStroke.fY) && xRadius == yRadius) {
-        SkScalar innerRadius = 0.0f;
-        SkScalar outerRadius = xRadius;
-        SkScalar halfWidth = 0;
-        if (hasStroke) {
-            if (SkScalarNearlyZero(scaledStroke.fX)) {
-                halfWidth = SK_ScalarHalf;
-            } else {
-                halfWidth = SkScalarHalf(scaledStroke.fX);
-            }
-
-            if (isStrokeOnly) {
-                innerRadius = xRadius - halfWidth;
-            }
-            outerRadius += halfWidth;
-            bounds.outset(halfWidth, halfWidth);
-        }
-
-        isStrokeOnly = (isStrokeOnly && innerRadius >= 0);
-
-        // The radii are outset for two reasons. First, it allows the shader to simply perform
-        // simpler computation because the computed alpha is zero, rather than 50%, at the radius.
-        // Second, the outer radius is used to compute the verts of the bounding box that is
-        // rendered and the outset ensures the box will cover all partially covered by the rrect
-        // corners.
-        outerRadius += SK_ScalarHalf;
-        innerRadius -= SK_ScalarHalf;
-
-        // Expand the rect so all the pixels will be captured.
-        bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
-
-        RRectCircleRendererBatch::Geometry geometry;
-        geometry.fColor = color;
-        geometry.fInnerRadius = innerRadius;
-        geometry.fOuterRadius = outerRadius;
-        geometry.fDevBounds = bounds;
-
-        return new RRectCircleRendererBatch(geometry, viewMatrix, isStrokeOnly);
+        return new RRectCircleRendererBatch(color, viewMatrix, bounds, xRadius, scaledStroke.fX,
+                                            isStrokeOnly);
     // otherwise we use the ellipse renderer
     } else {
-        SkScalar innerXRadius = 0.0f;
-        SkScalar innerYRadius = 0.0f;
-        if (hasStroke) {
-            if (SkScalarNearlyZero(scaledStroke.length())) {
-                scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
-            } else {
-                scaledStroke.scale(SK_ScalarHalf);
-            }
-
-            // we only handle thick strokes for near-circular ellipses
-            if (scaledStroke.length() > SK_ScalarHalf &&
-                (SK_ScalarHalf*xRadius > yRadius || SK_ScalarHalf*yRadius > xRadius)) {
-                return nullptr;
-            }
-
-            // we don't handle it if curvature of the stroke is less than curvature of the ellipse
-            if (scaledStroke.fX*(yRadius*yRadius) < (scaledStroke.fY*scaledStroke.fY)*xRadius ||
-                scaledStroke.fY*(xRadius*xRadius) < (scaledStroke.fX*scaledStroke.fX)*yRadius) {
-                return nullptr;
-            }
+        return RRectEllipseRendererBatch::Create(color, viewMatrix, bounds, xRadius, yRadius,
+                                                 scaledStroke, isStrokeOnly);
 
-            // this is legit only if scale & translation (which should be the case at the moment)
-            if (isStrokeOnly) {
-                innerXRadius = xRadius - scaledStroke.fX;
-                innerYRadius = yRadius - scaledStroke.fY;
-            }
-
-            xRadius += scaledStroke.fX;
-            yRadius += scaledStroke.fY;
-            bounds.outset(scaledStroke.fX, scaledStroke.fY);
-        }
-
-        isStrokeOnly = (isStrokeOnly && innerXRadius >= 0 && innerYRadius >= 0);
-
-        // Expand the rect so all the pixels will be captured.
-        bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
-
-        RRectEllipseRendererBatch::Geometry geometry;
-        geometry.fColor = color;
-        geometry.fXRadius = xRadius;
-        geometry.fYRadius = yRadius;
-        geometry.fInnerXRadius = innerXRadius;
-        geometry.fInnerYRadius = innerYRadius;
-        geometry.fDevBounds = bounds;
-
-        return new RRectEllipseRendererBatch(geometry, viewMatrix, isStrokeOnly);
     }
 }
 
@@ -1692,7 +1637,32 @@ GrDrawBatch* GrOvalRenderer::CreateRRectBatch(GrColor color,
     return create_rrect_batch(color, viewMatrix, rrect, stroke);
 }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+GrDrawBatch* GrOvalRenderer::CreateOvalBatch(GrColor color,
+                                             const SkMatrix& viewMatrix,
+                                             const SkRect& oval,
+                                             const SkStrokeRec& stroke,
+                                             GrShaderCaps* shaderCaps) {
+    // we can draw circles
+    if (SkScalarNearlyEqual(oval.width(), oval.height()) && circle_stays_circle(viewMatrix)) {
+        return new CircleBatch(color, viewMatrix, oval, stroke);
+    }
+
+    // if we have shader derivative support, render as device-independent
+    if (shaderCaps->shaderDerivativeSupport()) {
+        return DIEllipseBatch::Create(color, viewMatrix, oval, stroke);
+    }
+
+    // otherwise axis-aligned ellipses only
+    if (viewMatrix.rectStaysRect()) {
+        return EllipseBatch::Create(color, viewMatrix, oval, stroke);
+    }
+
+    return nullptr;
+}
+
+///////////////////////////////////////////////////////////////////////////////
 
 #ifdef GR_TEST_UTILS
 
@@ -1700,21 +1670,21 @@ DRAW_BATCH_TEST_DEFINE(CircleBatch) {
     SkMatrix viewMatrix = GrTest::TestMatrix(random);
     GrColor color = GrRandomColor(random);
     SkRect circle = GrTest::TestSquare(random);
-    return create_circle_batch(color, viewMatrix, circle, GrTest::TestStrokeRec(random));
+    return new CircleBatch(color, viewMatrix, circle, GrTest::TestStrokeRec(random));
 }
 
 DRAW_BATCH_TEST_DEFINE(EllipseBatch) {
     SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random);
     GrColor color = GrRandomColor(random);
     SkRect ellipse = GrTest::TestSquare(random);
-    return create_ellipse_batch(color, viewMatrix, ellipse, GrTest::TestStrokeRec(random));
+    return EllipseBatch::Create(color, viewMatrix, ellipse, GrTest::TestStrokeRec(random));
 }
 
 DRAW_BATCH_TEST_DEFINE(DIEllipseBatch) {
     SkMatrix viewMatrix = GrTest::TestMatrix(random);
     GrColor color = GrRandomColor(random);
     SkRect ellipse = GrTest::TestSquare(random);
-    return create_diellipse_batch(color, viewMatrix, ellipse, GrTest::TestStrokeRec(random));
+    return DIEllipseBatch::Create(color, viewMatrix, ellipse, GrTest::TestStrokeRec(random));
 }
 
 DRAW_BATCH_TEST_DEFINE(RRectBatch) {
index 2b52720..66182b2 100644 (file)
@@ -35,19 +35,6 @@ public:
 
 private:
     GrOvalRenderer();
-
-    static GrDrawBatch* CreateEllipseBatch(GrColor,
-                                           const SkMatrix& viewMatrix,
-                                           const SkRect& ellipse,
-                                           const SkStrokeRec& stroke);
-    static GrDrawBatch* CreateDIEllipseBatch(GrColor,
-                                             const SkMatrix& viewMatrix,
-                                             const SkRect& ellipse,
-                                             const SkStrokeRec& stroke);
-    static GrDrawBatch* CreateCircleBatch(GrColor,
-                                          const SkMatrix& viewMatrix,
-                                          const SkRect& circle,
-                                          const SkStrokeRec& stroke);
 };
 
 #endif // GrOvalRenderer_DEFINED