aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Brian Salomon <bsalomon@google.com>2017-12-20 13:28:55 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-12-20 18:47:36 +0000
commit2fad74a0fdc5eb3f505a052849c3cbeffa6e2d17 (patch)
tree6a3ec7975dc7ff37a6e8ccfe817fc3ccbd723b18
parent939e6719abb657096b5837d67d594256aa69da45 (diff)
Make GrRenderTargetContext::drawPath() use GrShape to identify simpler
geometries. Change-Id: I24230efc8bcb60f00c0c855090e3311ad13d7da8 Reviewed-on: https://skia-review.googlesource.com/85962 Commit-Queue: Brian Salomon <bsalomon@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
-rw-r--r--src/gpu/GrRenderTargetContext.cpp125
-rw-r--r--src/gpu/GrRenderTargetContext.h5
-rw-r--r--src/gpu/GrShape.cpp19
-rw-r--r--src/gpu/GrShape.h3
-rw-r--r--src/gpu/SkGpuDevice.cpp15
-rw-r--r--tests/GrShapeTest.cpp32
6 files changed, 109 insertions, 90 deletions
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index 1c617c9410..4f566ba15b 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -584,11 +584,7 @@ void GrRenderTargetContext::drawRect(const GrClip& clip,
return;
}
}
-
- SkPath path;
- path.setIsVolatile(true);
- path.addRect(rect);
- this->internalDrawPath(clip, std::move(paint), aa, viewMatrix, path, *style);
+ this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, GrShape(rect, *style));
}
int GrRenderTargetContextPriv::maxWindowRectangles() const {
@@ -747,10 +743,8 @@ void GrRenderTargetContext::fillRectToRect(const GrClip& clip,
}
viewAndUnLocalMatrix.postConcat(viewMatrix);
- SkPath path;
- path.setIsVolatile(true);
- path.addRect(localRect);
- this->internalDrawPath(clip, std::move(paint), aa, viewAndUnLocalMatrix, path, GrStyle());
+ this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewAndUnLocalMatrix,
+ GrShape(localRect));
}
static bool must_filter(const SkRect& src, const SkRect& dst, const SkMatrix& ctm) {
@@ -840,7 +834,8 @@ void GrRenderTargetContext::fillRectWithLocalMatrix(const GrClip& clip,
path.setIsVolatile(true);
path.addRect(rectToDraw);
path.transform(localMatrix);
- this->internalDrawPath(clip, std::move(paint), aa, viewAndUnLocalMatrix, path, GrStyle());
+ this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewAndUnLocalMatrix,
+ GrShape(path));
}
void GrRenderTargetContext::drawVertices(const GrClip& clip,
@@ -934,10 +929,8 @@ void GrRenderTargetContext::drawRRect(const GrClip& origClip,
}
}
- SkPath path;
- path.setIsVolatile(true);
- path.addRRect(rrect);
- this->internalDrawPath(*clip, std::move(paint), aa, viewMatrix, path, style);
+ this->drawShapeUsingPathRenderer(*clip, std::move(paint), aa, viewMatrix,
+ GrShape(rrect, style));
}
///////////////////////////////////////////////////////////////////////////////
@@ -1276,8 +1269,7 @@ void GrRenderTargetContext::drawDRRect(const GrClip& clip,
path.addRRect(inner);
path.addRRect(outer);
path.setFillType(SkPath::kEvenOdd_FillType);
-
- this->internalDrawPath(clip, std::move(paint), aa, viewMatrix, path, GrStyle::SimpleFill());
+ this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, GrShape(path));
}
///////////////////////////////////////////////////////////////////////////////
@@ -1347,10 +1339,8 @@ void GrRenderTargetContext::drawOval(const GrClip& clip,
}
}
- SkPath path;
- path.setIsVolatile(true);
- path.addOval(oval);
- this->internalDrawPath(clip, std::move(paint), aa, viewMatrix, path, style);
+ this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix,
+ GrShape(SkRRect::MakeOval(oval), style));
}
void GrRenderTargetContext::drawArc(const GrClip& clip,
@@ -1388,7 +1378,7 @@ void GrRenderTargetContext::drawArc(const GrClip& clip,
SkPath path;
SkPathPriv::CreateDrawArcPath(&path, oval, startAngle, sweepAngle, useCenter,
style.isSimpleFill());
- this->internalDrawPath(clip, std::move(paint), aa, viewMatrix, path, style);
+ this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, GrShape(path, style));
}
void GrRenderTargetContext::drawImageLattice(const GrClip& clip,
@@ -1501,25 +1491,29 @@ void GrRenderTargetContext::drawPath(const GrClip& clip,
GrPaint&& paint,
GrAA aa,
const SkMatrix& viewMatrix,
- const SkPath& path,
+ const SkPath& originalPath,
const GrStyle& style) {
ASSERT_SINGLE_OWNER
RETURN_IF_ABANDONED
SkDEBUGCODE(this->validate();)
GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "drawPath", fContext);
-
- if (path.isEmpty()) {
- if (path.isInverseFillType()) {
- this->drawPaint(clip, std::move(paint), viewMatrix);
- }
- return;
+ GrShape shape(originalPath, style);
+ if (shape.isEmpty()) {
+ if (shape.inverseFilled()) {
+ this->drawPaint(clip, std::move(paint), viewMatrix);
+ }
+ return;
}
AutoCheckFlush acf(this->drawingManager());
GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
- if (GrAAType::kCoverage == aaType && !style.pathEffect()) {
- if (style.isSimpleFill() && !path.isConvex()) {
+ if (GrAAType::kCoverage == aaType) {
+ // TODO: Make GrShape check for nested rects.
+ SkPath path;
+ shape.asPath(&path);
+ SkRect rects[2];
+ if (shape.style().isSimpleFill() && fills_as_nested_rects(viewMatrix, path, rects)) {
// Concave AA paths are expensive - try to avoid them for special cases
SkRect rects[2];
@@ -1533,26 +1527,26 @@ void GrRenderTargetContext::drawPath(const GrClip& clip,
return;
}
}
- SkRect ovalRect;
- bool isOval = path.isOval(&ovalRect);
-
- if (isOval && !path.isInverseFillType()) {
- const GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps();
- std::unique_ptr<GrDrawOp> op = GrOvalOpFactory::MakeOvalOp(
- std::move(paint), viewMatrix, ovalRect, style.strokeRec(), shaderCaps);
- if (op) {
- this->addDrawOp(clip, std::move(op));
+ }
+ if (!shape.style().hasPathEffect()) {
+ SkRRect rrect;
+ // We can ignore the starting point and direction since there is no path effect.
+ bool inverted;
+ if (shape.asRRect(&rrect, nullptr, nullptr, &inverted) && !inverted) {
+ if (rrect.isRect()) {
+ this->drawRect(clip, std::move(paint), aa, viewMatrix, rrect.rect(),
+ &shape.style());
+ return;
+ } else if (rrect.isOval()) {
+ this->drawOval(clip, std::move(paint), aa, viewMatrix, rrect.rect(), shape.style());
return;
}
+ this->drawRRect(clip, std::move(paint), aa, viewMatrix, rrect, shape.style());
+ return;
}
}
- // Note that internalDrawPath may sw-rasterize the path into a scratch texture.
- // Scratch textures can be recycled after they are returned to the texture
- // cache. This presents a potential hazard for buffered drawing. However,
- // the writePixels that uploads to the scratch will perform a flush so we're
- // OK.
- this->internalDrawPath(clip, std::move(paint), aa, viewMatrix, path, style);
+ this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, shape);
}
bool GrRenderTargetContextPriv::drawAndStencilPath(const GrHardClip& clip,
@@ -1633,12 +1627,11 @@ SkBudgeted GrRenderTargetContextPriv::isBudgeted() const {
return fRenderTargetContext->fRenderTargetProxy->isBudgeted();
}
-void GrRenderTargetContext::internalDrawPath(const GrClip& clip,
- GrPaint&& paint,
- GrAA aa,
- const SkMatrix& viewMatrix,
- const SkPath& path,
- const GrStyle& style) {
+void GrRenderTargetContext::drawShapeUsingPathRenderer(const GrClip& clip,
+ GrPaint&& paint,
+ GrAA aa,
+ const SkMatrix& viewMatrix,
+ const GrShape& originalShape) {
ASSERT_SINGLE_OWNER
RETURN_IF_ABANDONED
GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "internalDrawPath", fContext);
@@ -1646,25 +1639,24 @@ void GrRenderTargetContext::internalDrawPath(const GrClip& clip,
SkIRect clipConservativeBounds;
clip.getConservativeBounds(this->width(), this->height(), &clipConservativeBounds, nullptr);
- SkASSERT(!path.isEmpty());
- GrShape shape;
+ GrShape tempShape;
// NVPR cannot handle hairlines, so this would get picked up by a different stencil and
// cover path renderer (i.e. default path renderer). The hairline renderer produces much
// smoother hairlines than MSAA.
- GrAllowMixedSamples allowMixedSamples =
- style.isSimpleHairline() ? GrAllowMixedSamples::kNo : GrAllowMixedSamples::kYes;
+ GrAllowMixedSamples allowMixedSamples = originalShape.style().isSimpleHairline()
+ ? GrAllowMixedSamples::kNo
+ : GrAllowMixedSamples::kYes;
GrAAType aaType = this->chooseAAType(aa, allowMixedSamples);
GrPathRenderer::CanDrawPathArgs canDrawArgs;
canDrawArgs.fCaps = this->drawingManager()->getContext()->caps();
canDrawArgs.fViewMatrix = &viewMatrix;
- canDrawArgs.fShape = &shape;
+ canDrawArgs.fShape = &originalShape;
canDrawArgs.fClipConservativeBounds = &clipConservativeBounds;
canDrawArgs.fHasUserStencilSettings = false;
GrPathRenderer* pr;
static constexpr GrPathRendererChain::DrawType kType = GrPathRendererChain::DrawType::kColor;
- shape = GrShape(path, style);
- if (shape.isEmpty() && !shape.inverseFilled()) {
+ if (originalShape.isEmpty() && !originalShape.inverseFilled()) {
return;
}
@@ -1674,20 +1666,23 @@ void GrRenderTargetContext::internalDrawPath(const GrClip& clip,
pr = this->drawingManager()->getPathRenderer(canDrawArgs, false, kType);
SkScalar styleScale = GrStyle::MatrixToScaleFactor(viewMatrix);
- if (!pr && shape.style().pathEffect()) {
+ if (!pr && originalShape.style().pathEffect()) {
// It didn't work above, so try again with the path effect applied.
- shape = shape.applyStyle(GrStyle::Apply::kPathEffectOnly, styleScale);
- if (shape.isEmpty()) {
+ tempShape = originalShape.applyStyle(GrStyle::Apply::kPathEffectOnly, styleScale);
+ if (tempShape.isEmpty()) {
return;
}
+ canDrawArgs.fShape = &tempShape;
pr = this->drawingManager()->getPathRenderer(canDrawArgs, false, kType);
}
if (!pr) {
- if (shape.style().applies()) {
- shape = shape.applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec, styleScale);
- if (shape.isEmpty()) {
+ if (canDrawArgs.fShape->style().applies()) {
+ tempShape = canDrawArgs.fShape->applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec,
+ styleScale);
+ if (tempShape.isEmpty()) {
return;
}
+ canDrawArgs.fShape = &tempShape;
}
// This time, allow SW renderer
pr = this->drawingManager()->getPathRenderer(canDrawArgs, true, kType);
@@ -1707,7 +1702,7 @@ void GrRenderTargetContext::internalDrawPath(const GrClip& clip,
&clip,
&clipConservativeBounds,
&viewMatrix,
- &shape,
+ canDrawArgs.fShape,
aaType,
this->colorSpaceInfo().isGammaCorrect()};
pr->drawPath(args);
diff --git a/src/gpu/GrRenderTargetContext.h b/src/gpu/GrRenderTargetContext.h
index 304e6bc0bf..902c488461 100644
--- a/src/gpu/GrRenderTargetContext.h
+++ b/src/gpu/GrRenderTargetContext.h
@@ -30,6 +30,7 @@ class GrFixedClip;
class GrRenderTarget;
class GrRenderTargetContextPriv;
class GrRenderTargetOpList;
+class GrShape;
class GrStyle;
class GrTextureProxy;
struct GrUserStencilSettings;
@@ -432,8 +433,8 @@ private:
const SkRect& rect,
const GrUserStencilSettings* ss);
- void internalDrawPath(
- const GrClip&, GrPaint&&, GrAA, const SkMatrix&, const SkPath&, const GrStyle&);
+ void drawShapeUsingPathRenderer(const GrClip&, GrPaint&&, GrAA, const SkMatrix&,
+ const GrShape&);
// These perform processing specific to Gr[Mesh]DrawOp-derived ops before recording them into
// the op list. They return the id of the opList to which the op was added, or 0, if it was
diff --git a/src/gpu/GrShape.cpp b/src/gpu/GrShape.cpp
index 8c56054135..4c9338409c 100644
--- a/src/gpu/GrShape.cpp
+++ b/src/gpu/GrShape.cpp
@@ -539,11 +539,22 @@ void GrShape::attemptToSimplifyPath() {
void GrShape::attemptToSimplifyRRect() {
SkASSERT(Type::kRRect == fType);
SkASSERT(!fInheritedKey.count());
- // TODO: This isn't valid for strokes.
if (fRRectData.fRRect.isEmpty()) {
- // Dashing ignores the inverseness currently. skbug.com/5421
- fType = fRRectData.fInverted && !fStyle.isDashed() ? Type::kInvertedEmpty : Type::kEmpty;
- return;
+ // An empty filled rrect is equivalent to a filled empty path with inversion preserved.
+ if (fStyle.isSimpleFill()) {
+ fType = fRRectData.fInverted ? Type::kInvertedEmpty : Type::kEmpty;
+ fStyle = GrStyle::SimpleFill();
+ return;
+ }
+ // Dashing a rrect with no width or height is equivalent to filling an emtpy path.
+ // When skbug.com/7387 is fixed this should be modified or removed as a dashed zero length
+ // line will produce cap geometry if the effect begins in an "on" interval.
+ if (fStyle.isDashed() && !fRRectData.fRRect.width() && !fRRectData.fRRect.height()) {
+ // Dashing ignores the inverseness (currently). skbug.com/5421.
+ fType = Type::kEmpty;
+ fStyle = GrStyle::SimpleFill();
+ return;
+ }
}
if (!this->style().hasPathEffect()) {
fRRectData.fDir = kDefaultRRectDir;
diff --git a/src/gpu/GrShape.h b/src/gpu/GrShape.h
index 032c4d5e57..924232e8cf 100644
--- a/src/gpu/GrShape.h
+++ b/src/gpu/GrShape.h
@@ -338,7 +338,8 @@ public:
case Type::kRRect:
if (fRRectData.fRRect.getType() == SkRRect::kOval_Type) {
return SkPath::kConic_SegmentMask;
- } else if (fRRectData.fRRect.getType() == SkRRect::kRect_Type) {
+ } else if (fRRectData.fRRect.getType() == SkRRect::kRect_Type ||
+ fRRectData.fRRect.getType() == SkRRect::kEmpty_Type) {
return SkPath::kLine_SegmentMask;
}
return SkPath::kLine_SegmentMask | SkPath::kConic_SegmentMask;
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 1eebb5d095..f8924802e6 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -622,21 +622,6 @@ void SkGpuDevice::drawPath(const SkPath& origSrcPath,
return;
}
}
- bool isClosed;
- SkRect rect;
- if (origSrcPath.isRect(&rect, &isClosed) && isClosed) {
- this->drawRect(rect, paint);
- return;
- }
- if (origSrcPath.isOval(&rect)) {
- this->drawOval(rect, paint);
- return;
- }
- SkRRect rrect;
- if (origSrcPath.isRRect(&rrect)) {
- this->drawRRect(rrect, paint);
- return;
- }
}
GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPath", fContext.get());
diff --git a/tests/GrShapeTest.cpp b/tests/GrShapeTest.cpp
index 259026c8d0..826d0f864b 100644
--- a/tests/GrShapeTest.cpp
+++ b/tests/GrShapeTest.cpp
@@ -1490,6 +1490,8 @@ DEF_TEST(GrShape_empty_shape, reporter) {
SkPaint stroke;
stroke.setStrokeWidth(2.f);
stroke.setStyle(SkPaint::kStroke_Style);
+ stroke.setStrokeJoin(SkPaint::kRound_Join);
+ stroke.setStrokeCap(SkPaint::kRound_Cap);
TestCase strokeEmptyCase(reporter, emptyPath, stroke);
strokeEmptyCase.compare(reporter, fillEmptyCase, TestCase::kAllSame_ComparisonExpecation);
TestCase strokeInvertedEmptyCase(reporter, invertedEmptyPath, stroke);
@@ -1509,25 +1511,49 @@ DEF_TEST(GrShape_empty_shape, reporter) {
dashAndStrokeInvertexEmptyCase.compare(reporter, fillEmptyCase,
TestCase::kAllSame_ComparisonExpecation);
- // A shape made from an empty rrect should behave the same as an empty path.
- SkRRect emptyRRect = SkRRect::MakeRect(SkRect::MakeEmpty());
+ // A shape made from an empty rrect should behave the same as an empty path when filled but not
+ // when stroked. However, dashing an empty rrect produces an empty path leaving nothing to
+ // stroke - so equivalent to filling an empty path.
+ SkRRect emptyRRect = SkRRect::MakeEmpty();
REPORTER_ASSERT(reporter, emptyRRect.getType() == SkRRect::kEmpty_Type);
+
+ TestCase fillEmptyRRectCase(reporter, emptyRRect, fill);
+ fillEmptyRRectCase.compare(reporter, fillEmptyCase, TestCase::kAllSame_ComparisonExpecation);
+
+ TestCase strokeEmptyRRectCase(reporter, emptyRRect, stroke);
+ strokeEmptyRRectCase.compare(reporter, strokeEmptyCase,
+ TestCase::kAllDifferent_ComparisonExpecation);
+
TestCase dashAndStrokeEmptyRRectCase(reporter, emptyRRect, dashAndStroke);
dashAndStrokeEmptyRRectCase.compare(reporter, fillEmptyCase,
TestCase::kAllSame_ComparisonExpecation);
+
static constexpr SkPath::Direction kDir = SkPath::kCCW_Direction;
static constexpr int kStart = 0;
+
+ TestCase fillInvertedEmptyRRectCase(reporter, emptyRRect, kDir, kStart, true, GrStyle(fill));
+ fillInvertedEmptyRRectCase.compare(reporter, fillInvertedEmptyCase,
+ TestCase::kAllSame_ComparisonExpecation);
+
+ TestCase strokeInvertedEmptyRRectCase(reporter, emptyRRect, kDir, kStart, true,
+ GrStyle(stroke));
+ strokeInvertedEmptyRRectCase.compare(reporter, strokeInvertedEmptyCase,
+ TestCase::kAllDifferent_ComparisonExpecation);
+
TestCase dashAndStrokeEmptyInvertedRRectCase(reporter, emptyRRect, kDir, kStart, true,
GrStyle(dashAndStroke));
- // Dashing ignores inverseness so this is equivalent to the non-inverted empty fill.
dashAndStrokeEmptyInvertedRRectCase.compare(reporter, fillEmptyCase,
TestCase::kAllSame_ComparisonExpecation);
// Same for a rect.
SkRect emptyRect = SkRect::MakeEmpty();
+ TestCase fillEmptyRectCase(reporter, emptyRect, fill);
+ fillEmptyRectCase.compare(reporter, fillEmptyCase, TestCase::kAllSame_ComparisonExpecation);
+
TestCase dashAndStrokeEmptyRectCase(reporter, emptyRect, dashAndStroke);
dashAndStrokeEmptyRectCase.compare(reporter, fillEmptyCase,
TestCase::kAllSame_ComparisonExpecation);
+
TestCase dashAndStrokeEmptyInvertedRectCase(reporter, SkRRect::MakeRect(emptyRect), kDir,
kStart, true, GrStyle(dashAndStroke));
// Dashing ignores inverseness so this is equivalent to the non-inverted empty fill.