diff options
author | 2016-10-06 15:03:34 -0400 | |
---|---|---|
committer | 2016-10-06 19:42:34 +0000 | |
commit | 79839d45f893ad5690fc83c951567b3686e781e6 (patch) | |
tree | 0501886e238f2d021c0372a6570a00e69d90da32 /src/gpu/GrOvalRenderer.cpp | |
parent | d87bd7cfd1dae55fbe4331586aacac3468d59a77 (diff) |
Add distance values to interior of filled RRects
This doesn't compute the correct distance vector but it suffices for gaussian edges.
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2986
Change-Id: I8bd9e37b0f3788c30d85c95a3c0845d093f22554
Reviewed-on: https://skia-review.googlesource.com/2986
Reviewed-by: Jim Van Verth <jvanverth@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
Diffstat (limited to 'src/gpu/GrOvalRenderer.cpp')
-rw-r--r-- | src/gpu/GrOvalRenderer.cpp | 189 |
1 files changed, 118 insertions, 71 deletions
diff --git a/src/gpu/GrOvalRenderer.cpp b/src/gpu/GrOvalRenderer.cpp index 68b3f11d1d..3f759e92fb 100644 --- a/src/gpu/GrOvalRenderer.cpp +++ b/src/gpu/GrOvalRenderer.cpp @@ -1350,6 +1350,10 @@ private: // |_|________|_| // // We don't draw the center quad from the fill rect in this case. +// +// For filled rrects that need to provide a distance vector we resuse the overstroke +// geometry but make the inner rect degenerate (either a point or a horizontal or +// vertical line). static const uint16_t gOverstrokeRRectIndices[] = { // overstroke quads @@ -1391,6 +1395,7 @@ enum RRectType { kFill_RRectType, kStroke_RRectType, kOverstroke_RRectType, + kFillWithDist_RRectType }; static int rrect_type_to_vert_count(RRectType type) { @@ -1398,6 +1403,7 @@ static int rrect_type_to_vert_count(RRectType type) { kVertsPerStandardRRect, kVertsPerStandardRRect, kVertsPerOverstrokeRRect, + kVertsPerOverstrokeRRect, }; return kTypeToVertCount[type]; @@ -1408,6 +1414,7 @@ static int rrect_type_to_index_count(RRectType type) { kIndicesPerFillRRect, kIndicesPerStrokeRRect, kIndicesPerOverstrokeRRect, + kIndicesPerOverstrokeRRect, }; return kTypeToIndexCount[type]; @@ -1418,6 +1425,7 @@ static const uint16_t* rrect_type_to_indices(RRectType type) { gStandardRRectIndices, gStandardRRectIndices, gOverstrokeRRectIndices, + gOverstrokeRRectIndices, }; return kTypeToIndices[type]; @@ -1425,14 +1433,24 @@ static const uint16_t* rrect_type_to_indices(RRectType type) { /////////////////////////////////////////////////////////////////////////////////////////////////// +// For distance computations in the interior of filled rrects we: +// +// add a interior degenerate (point or line) rect +// each vertex of that rect gets -outerRad as its radius +// this makes the computation of the distance to the outer edge be negative +// negative values are caught and then handled differently in the GP's onEmitCode +// each vertex is also given the normalized x & y distance from the interior rect's edge +// the GP takes the min of those depths +1 to get the normalized distance to the outer edge + class RRectCircleRendererBatch : public GrVertexBatch { public: DEFINE_BATCH_CLASS_ID // 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) + RRectCircleRendererBatch(GrColor color, bool needsDistance, const SkMatrix& viewMatrix, + const SkRect& devRect, float devRadius, + float devStrokeWidth, bool strokeOnly) : INHERITED(ClassID()) , fViewMatrixIfUsingLocalCoords(viewMatrix) { SkRect bounds = devRect; @@ -1462,6 +1480,9 @@ public: outerRadius += halfWidth; bounds.outset(halfWidth, halfWidth); } + if (kFill_RRectType == type && needsDistance) { + type = kFillWithDist_RRectType; + } // 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. @@ -1516,6 +1537,81 @@ private: } } + struct CircleVertex { + SkPoint fPos; + GrColor fColor; + SkPoint fOffset; + SkScalar fOuterRadius; + SkScalar fInnerRadius; + // No half plane, we don't use it here. + }; + + static void FillInOverstrokeVerts(CircleVertex** verts, const SkRect& bounds, + SkScalar smInset, SkScalar bigInset, SkScalar xOffset, + SkScalar outerRadius, GrColor color) { + SkASSERT(smInset < bigInset); + + // TL + (*verts)->fPos = SkPoint::Make(bounds.fLeft + smInset, bounds.fTop + smInset); + (*verts)->fColor = color; + (*verts)->fOffset = SkPoint::Make(xOffset, 0); + (*verts)->fOuterRadius = outerRadius; + (*verts)->fInnerRadius = 0; + (*verts)++; + + // TR + (*verts)->fPos = SkPoint::Make(bounds.fRight - smInset, bounds.fTop + smInset); + (*verts)->fColor = color; + (*verts)->fOffset = SkPoint::Make(xOffset, 0); + (*verts)->fOuterRadius = outerRadius; + (*verts)->fInnerRadius = 0; + (*verts)++; + + (*verts)->fPos = SkPoint::Make(bounds.fLeft + bigInset, bounds.fTop + bigInset); + (*verts)->fColor = color; + (*verts)->fOffset = SkPoint::Make(0, 0); + (*verts)->fOuterRadius = outerRadius; + (*verts)->fInnerRadius = 0; + (*verts)++; + + (*verts)->fPos = SkPoint::Make(bounds.fRight - bigInset, bounds.fTop + bigInset); + (*verts)->fColor = color; + (*verts)->fOffset = SkPoint::Make(0, 0); + (*verts)->fOuterRadius = outerRadius; + (*verts)->fInnerRadius = 0; + (*verts)++; + + (*verts)->fPos = SkPoint::Make(bounds.fLeft + bigInset, bounds.fBottom - bigInset); + (*verts)->fColor = color; + (*verts)->fOffset = SkPoint::Make(0, 0); + (*verts)->fOuterRadius = outerRadius; + (*verts)->fInnerRadius = 0; + (*verts)++; + + (*verts)->fPos = SkPoint::Make(bounds.fRight - bigInset, bounds.fBottom - bigInset); + (*verts)->fColor = color; + (*verts)->fOffset = SkPoint::Make(0, 0); + (*verts)->fOuterRadius = outerRadius; + (*verts)->fInnerRadius = 0; + (*verts)++; + + // BL + (*verts)->fPos = SkPoint::Make(bounds.fLeft + smInset, bounds.fBottom - smInset); + (*verts)->fColor = color; + (*verts)->fOffset = SkPoint::Make(xOffset, 0); + (*verts)->fOuterRadius = outerRadius; + (*verts)->fInnerRadius = 0; + (*verts)++; + + // BR + (*verts)->fPos = SkPoint::Make(bounds.fRight - smInset, bounds.fBottom - smInset); + (*verts)->fColor = color; + (*verts)->fOffset = SkPoint::Make(xOffset, 0); + (*verts)->fOuterRadius = outerRadius; + (*verts)->fInnerRadius = 0; + (*verts)++; + } + void onPrepareDraws(Target* target) const override { // Invert the view matrix as a local matrix (if any other processors require coords). SkMatrix localMatrix; @@ -1527,14 +1623,6 @@ private: SkAutoTUnref<GrGeometryProcessor> gp(new CircleGeometryProcessor(!fAllFill, false, false, false, localMatrix)); - struct CircleVertex { - SkPoint fPos; - GrColor fColor; - SkPoint fOffset; - SkScalar fOuterRadius; - SkScalar fInnerRadius; - // No half plane, we don't use it here. - }; int instanceCount = fGeoData.count(); size_t vertexStride = gp->getVertexStride(); @@ -1577,7 +1665,8 @@ private: SkScalar yOuterRadii[4] = {-1, 0, 0, 1 }; // The inner radius in the vertex data must be specified in normalized space. // For fills, specifying -1/outerRadius guarantees an alpha of 1.0 at the inner radius. - SkScalar innerRadius = args.fType != kFill_RRectType + SkScalar innerRadius = args.fType != kFill_RRectType && + args.fType != kFillWithDist_RRectType ? args.fInnerRadius / args.fOuterRadius : -1.0f / args.fOuterRadius; for (int i = 0; i < 4; ++i) { @@ -1618,70 +1707,24 @@ private: // Also, the outer offset is a constant vector pointing to the right, which // guarantees that the distance value along the outer rectangle is constant. if (kOverstroke_RRectType == args.fType) { + SkASSERT(args.fInnerRadius <= 0.0f); + SkScalar overstrokeOuterRadius = outerRadius - args.fInnerRadius; // this is the normalized distance from the outer rectangle of this // geometry to the outer edge SkScalar maxOffset = -args.fInnerRadius / overstrokeOuterRadius; - verts->fPos = SkPoint::Make(bounds.fLeft + outerRadius, yCoords[1]); - verts->fColor = color; - verts->fOffset = SkPoint::Make(maxOffset, 0); - verts->fOuterRadius = overstrokeOuterRadius; - verts->fInnerRadius = 0; - verts++; - - verts->fPos = SkPoint::Make(bounds.fRight - outerRadius, yCoords[1]); - verts->fColor = color; - verts->fOffset = SkPoint::Make(maxOffset, 0); - verts->fOuterRadius = overstrokeOuterRadius; - verts->fInnerRadius = 0; - verts++; - - verts->fPos = SkPoint::Make(bounds.fLeft + overstrokeOuterRadius, - bounds.fTop + overstrokeOuterRadius); - verts->fColor = color; - verts->fOffset = SkPoint::Make(0, 0); - verts->fOuterRadius = overstrokeOuterRadius; - verts->fInnerRadius = 0; - verts++; - - verts->fPos = SkPoint::Make(bounds.fRight - overstrokeOuterRadius, - bounds.fTop + overstrokeOuterRadius); - verts->fColor = color; - verts->fOffset = SkPoint::Make(0, 0); - verts->fOuterRadius = overstrokeOuterRadius; - verts->fInnerRadius = 0; - verts++; - - verts->fPos = SkPoint::Make(bounds.fLeft + overstrokeOuterRadius, - bounds.fBottom - overstrokeOuterRadius); - verts->fColor = color; - verts->fOffset = SkPoint::Make(0, 0); - verts->fOuterRadius = overstrokeOuterRadius; - verts->fInnerRadius = 0; - verts++; + FillInOverstrokeVerts(&verts, bounds, outerRadius, overstrokeOuterRadius, + maxOffset, overstrokeOuterRadius, color); + } - verts->fPos = SkPoint::Make(bounds.fRight - overstrokeOuterRadius, - bounds.fBottom - overstrokeOuterRadius); - verts->fColor = color; - verts->fOffset = SkPoint::Make(0, 0); - verts->fOuterRadius = overstrokeOuterRadius; - verts->fInnerRadius = 0; - verts++; + if (kFillWithDist_RRectType == args.fType) { + SkScalar halfMinDim = 0.5f * SkTMin(bounds.width(), bounds.height()); - verts->fPos = SkPoint::Make(bounds.fLeft + outerRadius, yCoords[2]); - verts->fColor = color; - verts->fOffset = SkPoint::Make(maxOffset, 0); - verts->fOuterRadius = overstrokeOuterRadius; - verts->fInnerRadius = 0; - verts++; + SkScalar xOffset = 1.0f - outerRadius / halfMinDim; - verts->fPos = SkPoint::Make(bounds.fRight - outerRadius, yCoords[2]); - verts->fColor = color; - verts->fOffset = SkPoint::Make(maxOffset, 0); - verts->fOuterRadius = overstrokeOuterRadius; - verts->fInnerRadius = 0; - verts++; + FillInOverstrokeVerts(&verts, bounds, outerRadius, halfMinDim, + xOffset, halfMinDim, color); } const uint16_t* primIndices = rrect_type_to_indices(args.fType); @@ -1971,6 +2014,7 @@ private: }; static GrDrawBatch* create_rrect_batch(GrColor color, + bool needsDistance, const SkMatrix& viewMatrix, const SkRRect& rrect, const SkStrokeRec& stroke) { @@ -2031,8 +2075,8 @@ static GrDrawBatch* create_rrect_batch(GrColor color, // if the corners are circles, use the circle renderer if (isCircular) { - return new RRectCircleRendererBatch(color, viewMatrix, bounds, xRadius, scaledStroke.fX, - isStrokeOnly); + return new RRectCircleRendererBatch(color, needsDistance, viewMatrix, bounds, xRadius, + scaledStroke.fX, isStrokeOnly); // otherwise we use the ellipse renderer } else { return RRectEllipseRendererBatch::Create(color, viewMatrix, bounds, xRadius, yRadius, @@ -2042,6 +2086,7 @@ static GrDrawBatch* create_rrect_batch(GrColor color, } GrDrawBatch* GrOvalRenderer::CreateRRectBatch(GrColor color, + bool needsDistance, const SkMatrix& viewMatrix, const SkRRect& rrect, const SkStrokeRec& stroke, @@ -2054,7 +2099,7 @@ GrDrawBatch* GrOvalRenderer::CreateRRectBatch(GrColor color, return nullptr; } - return create_rrect_batch(color, viewMatrix, rrect, stroke); + return create_rrect_batch(color, needsDistance, viewMatrix, rrect, stroke); } /////////////////////////////////////////////////////////////////////////////// @@ -2165,7 +2210,9 @@ DRAW_BATCH_TEST_DEFINE(RRectBatch) { SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random); GrColor color = GrRandomColor(random); const SkRRect& rrect = GrTest::TestRRectSimple(random); - return create_rrect_batch(color, viewMatrix, rrect, GrTest::TestStrokeRec(random)); + bool needsDistance = random->nextBool(); + return create_rrect_batch(color, needsDistance, viewMatrix, rrect, + GrTest::TestStrokeRec(random)); } #endif |