diff options
author | Brian Salomon <bsalomon@google.com> | 2018-01-12 12:06:06 -0500 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-01-12 19:31:03 +0000 |
commit | 7cdabedc8b73b70e4aa70c5621a4bdc8e00ede44 (patch) | |
tree | 3068170ce9076b048fc322546be948a6f2eb9381 | |
parent | 1001f843a45e95f6df1d44242b6b06c77898e870 (diff) |
Use GrOvalOpFactory ops to draw non-AA rrects, ovals, and arcs.
This improves performance.
Bug: skia:
Change-Id: Ie01170ec084be66ea166b2baffcdb415583aa523
Reviewed-on: https://skia-review.googlesource.com/93321
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
-rw-r--r-- | include/private/GrTypesPriv.h | 16 | ||||
-rw-r--r-- | src/gpu/GrClipStackClip.cpp | 2 | ||||
-rw-r--r-- | src/gpu/GrRenderTargetContext.cpp | 75 | ||||
-rw-r--r-- | src/gpu/GrRenderTargetContext.h | 8 | ||||
-rw-r--r-- | src/gpu/GrXferProcessor.cpp | 8 | ||||
-rw-r--r-- | src/gpu/GrXferProcessor.h | 5 | ||||
-rw-r--r-- | src/gpu/effects/GrCustomXfermode.cpp | 7 | ||||
-rw-r--r-- | src/gpu/effects/GrPorterDuffXferProcessor.cpp | 5 | ||||
-rw-r--r-- | src/gpu/effects/GrPorterDuffXferProcessor.h | 2 | ||||
-rw-r--r-- | src/gpu/ops/GrOvalOpFactory.cpp | 223 | ||||
-rw-r--r-- | src/gpu/ops/GrOvalOpFactory.h | 40 | ||||
-rw-r--r-- | src/gpu/text/GrStencilAndCoverTextContext.cpp | 3 |
12 files changed, 272 insertions, 122 deletions
diff --git a/include/private/GrTypesPriv.h b/include/private/GrTypesPriv.h index cfcbff9af9..a379135532 100644 --- a/include/private/GrTypesPriv.h +++ b/include/private/GrTypesPriv.h @@ -9,11 +9,12 @@ #define GrTypesPriv_DEFINED #include <chrono> +#include "GrSharedEnums.h" #include "GrTypes.h" #include "SkRefCnt.h" -#include "GrSharedEnums.h" class GrCaps; +class GrPaint; // The old libstdc++ uses the draft name "monotonic_clock" rather than "steady_clock". This might // not actually be monotonic, depending on how libstdc++ was built. However, this is only currently @@ -87,7 +88,18 @@ enum class GrFSAAType { */ enum class GrAllowMixedSamples : bool { kNo = false, kYes = true }; -GrAAType GrChooseAAType(GrAA, GrFSAAType, GrAllowMixedSamples, const GrCaps&); +/** + * We have code paths for some shapes that can draw non-AA using boolean fragment shader coverage. + * However, it may not be desirable to use this if it will trigger a dst copy. If the caller + * of GrChooseAAType passes GrAllowNonAABinaryCoverage::kYes and GrAA::kNo then GrChooseAAType will + * consider whether it is efficient to use coverage to implement a non-AA draw and if so return + * will GrAAType::kCoverage. If GrAA::kYes is passed then this value is ignored. + */ +enum class GrAllowNonAABinaryCoverage : bool { kNo = false, kYes = true }; + +/** GrPaint is only required if GrAllowNonAABinaryCoverage and GrAA are both kYes. */ +GrAAType GrChooseAAType(GrAA, GrFSAAType, GrAllowMixedSamples, GrAllowNonAABinaryCoverage, + const GrPaint*, const GrCaps&); /** * Some pixel configs are inherently clamped to [0,1], while others can hold values outside of that diff --git a/src/gpu/GrClipStackClip.cpp b/src/gpu/GrClipStackClip.cpp index ce77369bb7..6e3fe9cb7a 100644 --- a/src/gpu/GrClipStackClip.cpp +++ b/src/gpu/GrClipStackClip.cpp @@ -124,6 +124,8 @@ bool GrClipStackClip::PathNeedsSWRenderer(GrContext* context, canDrawArgs.fAAType = GrChooseAAType(GrAA(element->isAA()), renderTargetContext->fsaaType(), GrAllowMixedSamples::kYes, + GrAllowNonAABinaryCoverage::kNo, + nullptr, *context->caps()); canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings; diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp index b0b117f914..16d8e1bbbd 100644 --- a/src/gpu/GrRenderTargetContext.cpp +++ b/src/gpu/GrRenderTargetContext.cpp @@ -99,6 +99,7 @@ private: ////////////////////////////////////////////////////////////////////////////// GrAAType GrChooseAAType(GrAA aa, GrFSAAType fsaaType, GrAllowMixedSamples allowMixedSamples, + GrAllowNonAABinaryCoverage allowNonAABinaryCoverage, const GrPaint* paint, const GrCaps& caps) { if (GrAA::kNo == aa) { // On some devices we cannot disable MSAA if it is enabled so we make the AA type reflect @@ -106,6 +107,34 @@ GrAAType GrChooseAAType(GrAA aa, GrFSAAType fsaaType, GrAllowMixedSamples allowM if (fsaaType == GrFSAAType::kUnifiedMSAA && !caps.multisampleDisableSupport()) { return GrAAType::kMSAA; } + if (GrAllowNonAABinaryCoverage::kYes == allowNonAABinaryCoverage) { + SkASSERT(paint); + // If we already have a coverage FP then we won't make anything worse. + if (paint->numCoverageFragmentProcessors()) { + return GrAAType::kCoverage; + } + // Shader based blending isn't so expensive with these extensions. + if (caps.shaderCaps()->fbFetchSupport() || caps.textureBarrierSupport()) { + return GrAAType::kCoverage; + } + SkBlendMode mode; + if (GrXPFactory::AsBlendMode(paint->getXPFactory(), &mode)) { + // If we have dual source blending then all Porter-Duff modes can use HW blending + // with coverage. + if (mode <= SkBlendMode::kLastCoeffMode && + caps.shaderCaps()->dualSourceBlendingSupport()) { + return GrAAType::kCoverage; + } + if (SkBlendMode_SupportsCoverageAsAlpha(mode)) { + return GrAAType::kCoverage; + } + // If the mode is "advanced" then either we will already be doing dst copies or we + // have advanced blending support and it is ok to conflate coverage with alpha. + if (mode > SkBlendMode::kLastCoeffMode) { + return GrAAType::kCoverage; + } + } + } return GrAAType::kNone; } switch (fsaaType) { @@ -915,14 +944,16 @@ void GrRenderTargetContext::drawRRect(const GrClip& origClip, AutoCheckFlush acf(this->drawingManager()); const SkStrokeRec stroke = style.strokeRec(); - GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo); + GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo, + GrAllowNonAABinaryCoverage::kYes, &paint); if (GrAAType::kCoverage == aaType) { const GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps(); - std::unique_ptr<GrDrawOp> op = GrOvalOpFactory::MakeRRectOp(std::move(paint), - viewMatrix, - rrect, - stroke, - shaderCaps); + std::unique_ptr<GrDrawOp> op = GrOvalOpFactory::MakeCoverageRRectOp(std::move(paint), + aa, + viewMatrix, + rrect, + stroke, + shaderCaps); if (op) { this->addDrawOp(*clip, std::move(op)); return; @@ -1186,8 +1217,9 @@ bool GrRenderTargetContext::drawFilledDRRect(const GrClip& clip, auto circleBounds = SkRect::MakeLTRB(cx - avgR, cy - avgR, cx + avgR, cy + avgR); SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); stroke.setStrokeStyle(outerR - innerR); - auto op = GrOvalOpFactory::MakeOvalOp(std::move(paint), viewMatrix, circleBounds, - stroke, this->caps()->shaderCaps()); + auto op = GrOvalOpFactory::MakeCoverageOvalOp(std::move(paint), aa, viewMatrix, + circleBounds, stroke, + this->caps()->shaderCaps()); if (op) { this->addDrawOp(clip, std::move(op)); return true; @@ -1328,11 +1360,12 @@ void GrRenderTargetContext::drawOval(const GrClip& clip, AutoCheckFlush acf(this->drawingManager()); const SkStrokeRec& stroke = style.strokeRec(); - GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo); + GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo, + GrAllowNonAABinaryCoverage::kYes, &paint); if (GrAAType::kCoverage == aaType) { const GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps(); - std::unique_ptr<GrDrawOp> op = - GrOvalOpFactory::MakeOvalOp(std::move(paint), viewMatrix, oval, stroke, shaderCaps); + std::unique_ptr<GrDrawOp> op = GrOvalOpFactory::MakeCoverageOvalOp( + std::move(paint), aa, viewMatrix, oval, stroke, shaderCaps); if (op) { this->addDrawOp(clip, std::move(op)); return; @@ -1359,17 +1392,19 @@ void GrRenderTargetContext::drawArc(const GrClip& clip, AutoCheckFlush acf(this->drawingManager()); - GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo); + GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo, + GrAllowNonAABinaryCoverage::kYes, &paint); if (GrAAType::kCoverage == aaType) { const GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps(); - std::unique_ptr<GrDrawOp> op = GrOvalOpFactory::MakeArcOp(std::move(paint), - viewMatrix, - oval, - startAngle, - sweepAngle, - useCenter, - style, - shaderCaps); + std::unique_ptr<GrDrawOp> op = GrOvalOpFactory::MakeCoverageArcOp(std::move(paint), + aa, + viewMatrix, + oval, + startAngle, + sweepAngle, + useCenter, + style, + shaderCaps); if (op) { this->addDrawOp(clip, std::move(op)); return; diff --git a/src/gpu/GrRenderTargetContext.h b/src/gpu/GrRenderTargetContext.h index 2ae52b922c..9e4fb3277c 100644 --- a/src/gpu/GrRenderTargetContext.h +++ b/src/gpu/GrRenderTargetContext.h @@ -386,8 +386,12 @@ protected: private: class TextTarget; - inline GrAAType chooseAAType(GrAA aa, GrAllowMixedSamples allowMixedSamples) { - return GrChooseAAType(aa, this->fsaaType(), allowMixedSamples, *this->caps()); + GrAAType chooseAAType( + GrAA aa, GrAllowMixedSamples allowMixedSamples, + GrAllowNonAABinaryCoverage allowNonAABinaryCoverage = GrAllowNonAABinaryCoverage::kNo, + const GrPaint* paint = nullptr) { + return GrChooseAAType(aa, this->fsaaType(), allowMixedSamples, allowNonAABinaryCoverage, + paint, *this->caps()); } friend class GrAtlasTextBlob; // for access to add[Mesh]DrawOp diff --git a/src/gpu/GrXferProcessor.cpp b/src/gpu/GrXferProcessor.cpp index 8f7377e0b2..39bec98ab5 100644 --- a/src/gpu/GrXferProcessor.cpp +++ b/src/gpu/GrXferProcessor.cpp @@ -193,3 +193,11 @@ sk_sp<const GrXferProcessor> GrXPFactory::MakeXferProcessor(const GrXPFactory* f caps); } } + +bool GrXPFactory::AsBlendMode(const GrXPFactory* factory, SkBlendMode* mode) { + if (factory) { + return factory->asBlendMode(mode); + } + *mode = SkBlendMode::kSrcOver; + return true; +} diff --git a/src/gpu/GrXferProcessor.h b/src/gpu/GrXferProcessor.h index 5ede1ae828..3aac2d3732 100644 --- a/src/gpu/GrXferProcessor.h +++ b/src/gpu/GrXferProcessor.h @@ -301,6 +301,9 @@ public: const GrCaps&, GrPixelConfigIsClamped); + /** If true mode will be the equivalent SkBlendMode for the XPFactory. */ + static bool AsBlendMode(const GrXPFactory*, SkBlendMode* mode); + protected: constexpr GrXPFactory() {} @@ -319,6 +322,8 @@ private: const GrProcessorAnalysisCoverage&, const GrCaps&, GrPixelConfigIsClamped) const = 0; + + virtual bool asBlendMode(SkBlendMode*) const { return false; } }; #if defined(__GNUC__) #pragma GCC diagnostic pop diff --git a/src/gpu/effects/GrCustomXfermode.cpp b/src/gpu/effects/GrCustomXfermode.cpp index bdeda9467c..b43cea9a69 100644 --- a/src/gpu/effects/GrCustomXfermode.cpp +++ b/src/gpu/effects/GrCustomXfermode.cpp @@ -225,6 +225,8 @@ private: const GrCaps&, GrPixelConfigIsClamped) const override; + bool asBlendMode(SkBlendMode* mode) const override; + GR_DECLARE_XP_FACTORY_TEST SkBlendMode fMode; @@ -362,6 +364,11 @@ GrXPFactory::AnalysisProperties CustomXPFactory::analysisProperties( AnalysisProperties::kReadsDstInShader; } +bool CustomXPFactory::asBlendMode(SkBlendMode* mode) const { + *mode = fMode; + return true; +} + GR_DEFINE_XP_FACTORY_TEST(CustomXPFactory); #if GR_TEST_UTILS const GrXPFactory* CustomXPFactory::TestGet(GrProcessorTestData* d) { diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.cpp b/src/gpu/effects/GrPorterDuffXferProcessor.cpp index f4af7a4679..c8f11e0f5d 100644 --- a/src/gpu/effects/GrPorterDuffXferProcessor.cpp +++ b/src/gpu/effects/GrPorterDuffXferProcessor.cpp @@ -861,6 +861,11 @@ GrXPFactory::AnalysisProperties GrPorterDuffXPFactory::analysisProperties( return analysis_properties(color, coverage, caps, dstIsClamped, fBlendMode); } +bool GrPorterDuffXPFactory::asBlendMode(SkBlendMode* mode) const { + *mode = fBlendMode; + return true; +} + GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory); #if GR_TEST_UTILS diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.h b/src/gpu/effects/GrPorterDuffXferProcessor.h index 74ae1533bf..8241a9f1ab 100644 --- a/src/gpu/effects/GrPorterDuffXferProcessor.h +++ b/src/gpu/effects/GrPorterDuffXferProcessor.h @@ -58,6 +58,8 @@ private: const GrCaps&, GrPixelConfigIsClamped) const override; + bool asBlendMode(SkBlendMode* mode) const override; + GR_DECLARE_XP_FACTORY_TEST static void TestGetXPOutputTypes(const GrXferProcessor*, int* outPrimary, int* outSecondary); diff --git a/src/gpu/ops/GrOvalOpFactory.cpp b/src/gpu/ops/GrOvalOpFactory.cpp index 9194f673e6..e5f1abf9f2 100644 --- a/src/gpu/ops/GrOvalOpFactory.cpp +++ b/src/gpu/ops/GrOvalOpFactory.cpp @@ -66,10 +66,12 @@ static inline bool circle_stays_circle(const SkMatrix& m) { return m.isSimilarit class CircleGeometryProcessor : public GrGeometryProcessor { public: - CircleGeometryProcessor(bool stroke, bool clipPlane, bool isectPlane, bool unionPlane, + CircleGeometryProcessor(bool stroke, bool clipPlane, bool isectPlane, bool unionPlane, GrAA aa, const SkMatrix& localMatrix) : INHERITED(kCircleGeometryProcessor_ClassID) - , fLocalMatrix(localMatrix) { + , fLocalMatrix(localMatrix) + , fStroke(stroke) + , fAA(aa) { fInPosition = &this->addVertexAttrib("inPosition", kFloat2_GrVertexAttribType); fInColor = &this->addVertexAttrib("inColor", kUByte4_norm_GrVertexAttribType); fInCircleEdge = &this->addVertexAttrib("inCircleEdge", kFloat4_GrVertexAttribType); @@ -88,7 +90,6 @@ public: } else { fInUnionPlane = nullptr; } - fStroke = stroke; } ~CircleGeometryProcessor() override {} @@ -174,7 +175,16 @@ private: } fragBuilder->codeAppend("edgeAlpha *= clip;"); } - fragBuilder->codeAppendf("%s = half4(edgeAlpha);", args.fOutputCoverage); + if (GrAA::kYes == cgp.fAA) { + fragBuilder->codeAppendf("%s = half4(edgeAlpha);", args.fOutputCoverage); + } else { + // Using a value less than half is a bit of a hack. If 0.5 is used then filling + // a set of abutting arcs that should create a full circle can leave gaps at pixels + // that neither arc quite owns. Generally speaking, double hitting these pixels + // instead of missing them looks better. + fragBuilder->codeAppendf("%s = edgeAlpha > 0.4999 ? half4(1) : half4(0);", + args.fOutputCoverage); + } } static void GenKey(const GrGeometryProcessor& gp, @@ -187,6 +197,7 @@ private: key |= cgp.fInClipPlane ? 0x04 : 0x0; key |= cgp.fInIsectPlane ? 0x08 : 0x0; key |= cgp.fInUnionPlane ? 0x10 : 0x0; + key |= GrAA::kYes == cgp.fAA ? 0x20 : 0x0; b->add32(key); } @@ -208,6 +219,7 @@ private: const Attribute* fInIsectPlane; const Attribute* fInUnionPlane; bool fStroke; + GrAA fAA; GR_DECLARE_GEOMETRY_PROCESSOR_TEST @@ -218,9 +230,10 @@ GR_DEFINE_GEOMETRY_PROCESSOR_TEST(CircleGeometryProcessor); #if GR_TEST_UTILS sk_sp<GrGeometryProcessor> CircleGeometryProcessor::TestCreate(GrProcessorTestData* d) { + GrAA aa = d->fRandom->nextBool() ? GrAA::kYes : GrAA::kNo; return sk_sp<GrGeometryProcessor>(new CircleGeometryProcessor( d->fRandom->nextBool(), d->fRandom->nextBool(), d->fRandom->nextBool(), - d->fRandom->nextBool(), GrTest::TestMatrix(d->fRandom))); + d->fRandom->nextBool(), aa, GrTest::TestMatrix(d->fRandom))); } #endif @@ -236,14 +249,15 @@ sk_sp<GrGeometryProcessor> CircleGeometryProcessor::TestCreate(GrProcessorTestDa class EllipseGeometryProcessor : public GrGeometryProcessor { public: - EllipseGeometryProcessor(bool stroke, const SkMatrix& localMatrix) - : INHERITED(kEllipseGeometryProcessor_ClassID) - , fLocalMatrix(localMatrix) { + EllipseGeometryProcessor(bool stroke, GrAA aa, const SkMatrix& localMatrix) + : INHERITED(kEllipseGeometryProcessor_ClassID) + , fLocalMatrix(localMatrix) + , fStroke(stroke) + , fAA(aa) { fInPosition = &this->addVertexAttrib("inPosition", kFloat2_GrVertexAttribType); fInColor = &this->addVertexAttrib("inColor", kUByte4_norm_GrVertexAttribType); fInEllipseOffset = &this->addVertexAttrib("inEllipseOffset", kHalf2_GrVertexAttribType); fInEllipseRadii = &this->addVertexAttrib("inEllipseRadii", kHalf4_GrVertexAttribType); - fStroke = stroke; } ~EllipseGeometryProcessor() override {} @@ -318,7 +332,12 @@ private: fragBuilder->codeAppend("edgeAlpha *= clamp(0.5+test*invlen, 0.0, 1.0);"); } - fragBuilder->codeAppendf("%s = half4(edgeAlpha);", args.fOutputCoverage); + if (GrAA::kYes == egp.fAA) { + fragBuilder->codeAppendf("%s = half4(edgeAlpha);", args.fOutputCoverage); + } else { + fragBuilder->codeAppendf("%s = edgeAlpha > 0.5 ? half4(1) : half4(0);", + args.fOutputCoverage); + } } static void GenKey(const GrGeometryProcessor& gp, @@ -327,6 +346,7 @@ private: const EllipseGeometryProcessor& egp = gp.cast<EllipseGeometryProcessor>(); uint16_t key = egp.fStroke ? 0x1 : 0x0; key |= egp.fLocalMatrix.hasPerspective() ? 0x2 : 0x0; + key |= GrAA::kYes == egp.fAA ? 0x4 : 0x0; b->add32(key); } @@ -346,6 +366,7 @@ private: const Attribute* fInEllipseRadii; SkMatrix fLocalMatrix; bool fStroke; + GrAA fAA; GR_DECLARE_GEOMETRY_PROCESSOR_TEST @@ -356,8 +377,9 @@ GR_DEFINE_GEOMETRY_PROCESSOR_TEST(EllipseGeometryProcessor); #if GR_TEST_UTILS sk_sp<GrGeometryProcessor> EllipseGeometryProcessor::TestCreate(GrProcessorTestData* d) { - return sk_sp<GrGeometryProcessor>( - new EllipseGeometryProcessor(d->fRandom->nextBool(), GrTest::TestMatrix(d->fRandom))); + GrAA aa = d->fRandom->nextBool() ? GrAA::kYes : GrAA::kNo; + return sk_sp<GrGeometryProcessor>(new EllipseGeometryProcessor(d->fRandom->nextBool(), aa, + GrTest::TestMatrix(d->fRandom))); } #endif @@ -376,14 +398,15 @@ enum class DIEllipseStyle { kStroke = 0, kHairline, kFill }; class DIEllipseGeometryProcessor : public GrGeometryProcessor { public: - DIEllipseGeometryProcessor(const SkMatrix& viewMatrix, DIEllipseStyle style) + DIEllipseGeometryProcessor(const SkMatrix& viewMatrix, DIEllipseStyle style, GrAA aa) : INHERITED(kDIEllipseGeometryProcessor_ClassID) - , fViewMatrix(viewMatrix) { + , fViewMatrix(viewMatrix) + , fStyle(style) + , fAA(aa) { fInPosition = &this->addVertexAttrib("inPosition", kFloat2_GrVertexAttribType); fInColor = &this->addVertexAttrib("inColor", kUByte4_norm_GrVertexAttribType); fInEllipseOffsets0 = &this->addVertexAttrib("inEllipseOffsets0", kHalf2_GrVertexAttribType); fInEllipseOffsets1 = &this->addVertexAttrib("inEllipseOffsets1", kHalf2_GrVertexAttribType); - fStyle = style; } ~DIEllipseGeometryProcessor() override {} @@ -473,8 +496,12 @@ private: fragBuilder->codeAppend("invlen = inversesqrt(dot(grad, grad));"); fragBuilder->codeAppend("edgeAlpha *= clamp(0.5+test*invlen, 0.0, 1.0);"); } - - fragBuilder->codeAppendf("%s = half4(edgeAlpha);", args.fOutputCoverage); + if (GrAA::kYes == diegp.fAA) { + fragBuilder->codeAppendf("%s = half4(edgeAlpha);", args.fOutputCoverage); + } else { + fragBuilder->codeAppendf("%s = edgeAlpha > 0.5 ? half4(1) : half4(0);", + args.fOutputCoverage); + } } static void GenKey(const GrGeometryProcessor& gp, @@ -482,6 +509,7 @@ private: GrProcessorKeyBuilder* b) { const DIEllipseGeometryProcessor& diegp = gp.cast<DIEllipseGeometryProcessor>(); uint16_t key = static_cast<uint16_t>(diegp.fStyle); + key |= GrAA::kYes == diegp.fAA ? 0x80 : 0x0; key |= ComputePosKey(diegp.fViewMatrix) << 10; b->add32(key); } @@ -512,6 +540,7 @@ private: const Attribute* fInEllipseOffsets1; SkMatrix fViewMatrix; DIEllipseStyle fStyle; + GrAA fAA; GR_DECLARE_GEOMETRY_PROCESSOR_TEST @@ -522,8 +551,9 @@ GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DIEllipseGeometryProcessor); #if GR_TEST_UTILS sk_sp<GrGeometryProcessor> DIEllipseGeometryProcessor::TestCreate(GrProcessorTestData* d) { + GrAA aa = d->fRandom->nextBool() ? GrAA::kYes : GrAA::kNo; return sk_sp<GrGeometryProcessor>(new DIEllipseGeometryProcessor( - GrTest::TestMatrix(d->fRandom), (DIEllipseStyle)(d->fRandom->nextRangeU(0, 2)))); + GrTest::TestMatrix(d->fRandom), (DIEllipseStyle)(d->fRandom->nextRangeU(0, 2)), aa)); } #endif @@ -591,7 +621,7 @@ public: bool fUseCenter; }; - static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkMatrix& viewMatrix, + static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, SkPoint center, SkScalar radius, const GrStyle& style, const ArcParams* arcParams = nullptr) { SkASSERT(circle_stays_circle(viewMatrix)); @@ -618,13 +648,13 @@ public: break; } } - return Helper::FactoryHelper<CircleOp>(std::move(paint), viewMatrix, center, radius, style, - arcParams); + return Helper::FactoryHelper<CircleOp>(std::move(paint), aa, viewMatrix, center, radius, + style, arcParams); } - CircleOp(const Helper::MakeArgs& helperArgs, GrColor color, const SkMatrix& viewMatrix, + CircleOp(const Helper::MakeArgs& helperArgs, GrColor color, GrAA aa, const SkMatrix& viewMatrix, SkPoint center, SkScalar radius, const GrStyle& style, const ArcParams* arcParams) - : GrMeshDrawOp(ClassID()), fHelper(helperArgs, GrAAType::kCoverage) { + : GrMeshDrawOp(ClassID()), fHelper(helperArgs, GrAAType::kCoverage), fAA(aa) { const SkStrokeRec& stroke = style.strokeRec(); SkStrokeRec::Style recStyle = stroke.getStyle(); @@ -816,7 +846,7 @@ private: // Setup geometry processor sk_sp<GrGeometryProcessor> gp(new CircleGeometryProcessor( - !fAllFill, fClipPlane, fClipPlaneIsect, fClipPlaneUnion, localMatrix)); + !fAllFill, fClipPlane, fClipPlaneIsect, fClipPlaneUnion, fAA, localMatrix)); struct CircleVertex { SkPoint fPos; @@ -1105,6 +1135,10 @@ private: return false; } + if (fAA != that->fAA) { + return false; + } + // Because we've set up the ops that don't use the planes with noop values // we can just accumulate used planes by later ops. fClipPlane |= that->fClipPlane; @@ -1139,6 +1173,7 @@ private: bool fClipPlane; bool fClipPlaneIsect; bool fClipPlaneUnion; + GrAA fAA; typedef GrMeshDrawOp INHERITED; }; @@ -1160,7 +1195,7 @@ private: public: DEFINE_OP_CLASS_ID - static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkMatrix& viewMatrix, + static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, const SkRect& ellipse, const SkStrokeRec& stroke) { DeviceSpaceParams params; // do any matrix crunching before we reset the draw state for device coords @@ -1219,12 +1254,13 @@ public: params.fXRadius += scaledStroke.fX; params.fYRadius += scaledStroke.fY; } - return Helper::FactoryHelper<EllipseOp>(std::move(paint), viewMatrix, params, stroke); + return Helper::FactoryHelper<EllipseOp>(std::move(paint), aa, viewMatrix, params, stroke); } - EllipseOp(const Helper::MakeArgs& helperArgs, GrColor color, const SkMatrix& viewMatrix, - const DeviceSpaceParams& params, const SkStrokeRec& stroke) - : INHERITED(ClassID()), fHelper(helperArgs, GrAAType::kCoverage) { + EllipseOp(const Helper::MakeArgs& helperArgs, GrColor color, GrAA aa, + const SkMatrix& viewMatrix, const DeviceSpaceParams& params, + const SkStrokeRec& stroke) + : INHERITED(ClassID()), fHelper(helperArgs, GrAAType::kCoverage), fAA(aa) { SkStrokeRec::Style style = stroke.getStyle(); bool isStrokeOnly = SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style; @@ -1284,7 +1320,7 @@ private: } // Setup geometry processor - sk_sp<GrGeometryProcessor> gp(new EllipseGeometryProcessor(fStroked, localMatrix)); + sk_sp<GrGeometryProcessor> gp(new EllipseGeometryProcessor(fStroked, fAA, localMatrix)); QuadHelper helper; size_t vertexStride = gp->getVertexStride(); @@ -1356,6 +1392,10 @@ private: return false; } + if (fAA != that->fAA) { + return false; + } + fEllipses.push_back_n(that->fEllipses.count(), that->fEllipses.begin()); this->joinBounds(*that); return true; @@ -1373,6 +1413,7 @@ private: SkMatrix fViewMatrixIfUsingLocalCoords; Helper fHelper; bool fStroked; + GrAA fAA; SkSTArray<1, Ellipse, true> fEllipses; typedef GrMeshDrawOp INHERITED; @@ -1396,7 +1437,7 @@ private: public: DEFINE_OP_CLASS_ID - static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkMatrix& viewMatrix, + static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, const SkRect& ellipse, const SkStrokeRec& stroke) { DeviceSpaceParams params; params.fCenter = SkPoint::Make(ellipse.centerX(), ellipse.centerY()); @@ -1451,12 +1492,12 @@ public: (params.fInnerXRadius <= 0 || params.fInnerYRadius <= 0)) { params.fStyle = DIEllipseStyle::kFill; } - return Helper::FactoryHelper<DIEllipseOp>(std::move(paint), params, viewMatrix); + return Helper::FactoryHelper<DIEllipseOp>(std::move(paint), aa, params, viewMatrix); } - DIEllipseOp(Helper::MakeArgs& helperArgs, GrColor color, const DeviceSpaceParams& params, - const SkMatrix& viewMatrix) - : INHERITED(ClassID()), fHelper(helperArgs, GrAAType::kCoverage) { + DIEllipseOp(Helper::MakeArgs& helperArgs, GrColor color, GrAA aa, + const DeviceSpaceParams& params, const SkMatrix& viewMatrix) + : INHERITED(ClassID()), fHelper(helperArgs, GrAAType::kCoverage), fAA(aa) { // 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]; @@ -1511,7 +1552,7 @@ private: void onPrepareDraws(Target* target) override { // Setup geometry processor sk_sp<GrGeometryProcessor> gp( - new DIEllipseGeometryProcessor(this->viewMatrix(), this->style())); + new DIEllipseGeometryProcessor(this->viewMatrix(), this->style(), fAA)); size_t vertexStride = gp->getVertexStride(); SkASSERT(vertexStride == sizeof(DIEllipseVertex)); @@ -1576,6 +1617,10 @@ private: return false; } + if (fAA != that->fAA) { + return false; + } + fEllipses.push_back_n(that->fEllipses.count(), that->fEllipses.begin()); this->joinBounds(*that); return true; @@ -1599,6 +1644,7 @@ private: Helper fHelper; SkSTArray<1, Ellipse, true> fEllipses; + GrAA fAA; typedef GrMeshDrawOp INHERITED; }; @@ -1738,17 +1784,19 @@ public: // A devStrokeWidth <= 0 indicates a fill only. If devStrokeWidth > 0 then strokeOnly indicates // whether the rrect is only stroked or stroked and filled. - static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkMatrix& viewMatrix, + static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, const SkRect& devRect, float devRadius, float devStrokeWidth, bool strokeOnly) { - return Helper::FactoryHelper<CircularRRectOp>(std::move(paint), viewMatrix, devRect, + return Helper::FactoryHelper<CircularRRectOp>(std::move(paint), aa, viewMatrix, devRect, devRadius, devStrokeWidth, strokeOnly); } - CircularRRectOp(Helper::MakeArgs& helperArgs, GrColor color, const SkMatrix& viewMatrix, - const SkRect& devRect, float devRadius, float devStrokeWidth, bool strokeOnly) + CircularRRectOp(Helper::MakeArgs& helperArgs, GrColor color, GrAA aa, + const SkMatrix& viewMatrix, const SkRect& devRect, float devRadius, + float devStrokeWidth, bool strokeOnly) : INHERITED(ClassID()) , fViewMatrixIfUsingLocalCoords(viewMatrix) - , fHelper(helperArgs, GrAAType::kCoverage) { + , fHelper(helperArgs, GrAAType::kCoverage) + , fAA(aa) { SkRect bounds = devRect; SkASSERT(!(devStrokeWidth <= 0 && strokeOnly)); SkScalar innerRadius = 0.0f; @@ -1910,7 +1958,7 @@ private: // Setup geometry processor sk_sp<GrGeometryProcessor> gp( - new CircleGeometryProcessor(!fAllFill, false, false, false, localMatrix)); + new CircleGeometryProcessor(!fAllFill, false, false, false, fAA, localMatrix)); size_t vertexStride = gp->getVertexStride(); SkASSERT(sizeof(CircleVertex) == vertexStride); @@ -2029,6 +2077,10 @@ private: return false; } + if (fAA != that->fAA) { + return false; + } + fRRects.push_back_n(that->fRRects.count(), that->fRRects.begin()); this->joinBounds(*that); fVertCount += that->fVertCount; @@ -2050,6 +2102,7 @@ private: int fVertCount; int fIndexCount; bool fAllFill; + GrAA fAA; SkSTArray<1, RRect, true> fRRects; typedef GrMeshDrawOp INHERITED; @@ -2087,7 +2140,7 @@ public: // If devStrokeWidths values are <= 0 indicates then fill only. Otherwise, strokeOnly indicates // whether the rrect is only stroked or stroked and filled. - static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkMatrix& viewMatrix, + static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, const SkRect& devRect, float devXRadius, float devYRadius, SkVector devStrokeWidths, bool strokeOnly) { SkASSERT(devXRadius > 0.5); @@ -2118,15 +2171,15 @@ public: return nullptr; } } - return Helper::FactoryHelper<EllipticalRRectOp>(std::move(paint), viewMatrix, devRect, + return Helper::FactoryHelper<EllipticalRRectOp>(std::move(paint), aa, viewMatrix, devRect, devXRadius, devYRadius, devStrokeWidths, strokeOnly); } - EllipticalRRectOp(Helper::MakeArgs helperArgs, GrColor color, const SkMatrix& viewMatrix, - const SkRect& devRect, float devXRadius, float devYRadius, - SkVector devStrokeHalfWidths, bool strokeOnly) - : INHERITED(ClassID()), fHelper(helperArgs, GrAAType::kCoverage) { + EllipticalRRectOp(Helper::MakeArgs helperArgs, GrColor color, GrAA aa, + const SkMatrix& viewMatrix, const SkRect& devRect, float devXRadius, + float devYRadius, SkVector devStrokeHalfWidths, bool strokeOnly) + : INHERITED(ClassID()), fHelper(helperArgs, GrAAType::kCoverage), fAA(aa) { SkScalar innerXRadius = 0.0f; SkScalar innerYRadius = 0.0f; SkRect bounds = devRect; @@ -2192,7 +2245,7 @@ private: } // Setup geometry processor - sk_sp<GrGeometryProcessor> gp(new EllipseGeometryProcessor(fStroked, localMatrix)); + sk_sp<GrGeometryProcessor> gp(new EllipseGeometryProcessor(fStroked, fAA, localMatrix)); size_t vertexStride = gp->getVertexStride(); SkASSERT(vertexStride == sizeof(EllipseVertex)); @@ -2280,7 +2333,9 @@ private: !fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsingLocalCoords)) { return false; } - + if (fAA != that->fAA) { + return false; + } fRRects.push_back_n(that->fRRects.count(), that->fRRects.begin()); this->joinBounds(*that); return true; @@ -2298,12 +2353,14 @@ private: SkMatrix fViewMatrixIfUsingLocalCoords; Helper fHelper; bool fStroked; + GrAA fAA; SkSTArray<1, RRect, true> fRRects; typedef GrMeshDrawOp INHERITED; }; static std::unique_ptr<GrDrawOp> make_rrect_op(GrPaint&& paint, + GrAA aa, const SkMatrix& viewMatrix, const SkRRect& rrect, const SkStrokeRec& stroke) { @@ -2364,55 +2421,58 @@ static std::unique_ptr<GrDrawOp> make_rrect_op(GrPaint&& paint, // if the corners are circles, use the circle renderer if (isCircular) { - return CircularRRectOp::Make(std::move(paint), viewMatrix, bounds, xRadius, scaledStroke.fX, - isStrokeOnly); + return CircularRRectOp::Make(std::move(paint), aa, viewMatrix, bounds, xRadius, + scaledStroke.fX, isStrokeOnly); // otherwise we use the ellipse renderer } else { - return EllipticalRRectOp::Make(std::move(paint), viewMatrix, bounds, xRadius, yRadius, + return EllipticalRRectOp::Make(std::move(paint), aa, viewMatrix, bounds, xRadius, yRadius, scaledStroke, isStrokeOnly); } } -std::unique_ptr<GrDrawOp> GrOvalOpFactory::MakeRRectOp(GrPaint&& paint, - const SkMatrix& viewMatrix, - const SkRRect& rrect, - const SkStrokeRec& stroke, - const GrShaderCaps* shaderCaps) { +std::unique_ptr<GrDrawOp> GrOvalOpFactory::MakeCoverageRRectOp(GrPaint&& paint, + GrAA aa, + const SkMatrix& viewMatrix, + const SkRRect& rrect, + const SkStrokeRec& stroke, + const GrShaderCaps* shaderCaps) { if (rrect.isOval()) { - return MakeOvalOp(std::move(paint), viewMatrix, rrect.getBounds(), stroke, shaderCaps); + return MakeCoverageOvalOp(std::move(paint), aa, viewMatrix, rrect.getBounds(), stroke, + shaderCaps); } if (!viewMatrix.rectStaysRect() || !rrect.isSimple()) { return nullptr; } - return make_rrect_op(std::move(paint), viewMatrix, rrect, stroke); + return make_rrect_op(std::move(paint), aa, viewMatrix, rrect, stroke); } /////////////////////////////////////////////////////////////////////////////// -std::unique_ptr<GrDrawOp> GrOvalOpFactory::MakeOvalOp(GrPaint&& paint, - const SkMatrix& viewMatrix, - const SkRect& oval, - const SkStrokeRec& stroke, - const GrShaderCaps* shaderCaps) { +std::unique_ptr<GrDrawOp> GrOvalOpFactory::MakeCoverageOvalOp(GrPaint&& paint, + GrAA aa, + const SkMatrix& viewMatrix, + const SkRect& oval, + const SkStrokeRec& stroke, + const GrShaderCaps* shaderCaps) { // we can draw circles SkScalar width = oval.width(); if (width > SK_ScalarNearlyZero && SkScalarNearlyEqual(width, oval.height()) && circle_stays_circle(viewMatrix)) { SkPoint center = {oval.centerX(), oval.centerY()}; - return CircleOp::Make(std::move(paint), viewMatrix, center, width / 2.f, + return CircleOp::Make(std::move(paint), aa, viewMatrix, center, width / 2.f, GrStyle(stroke, nullptr)); } // prefer the device space ellipse op for batchability if (viewMatrix.rectStaysRect()) { - return EllipseOp::Make(std::move(paint), viewMatrix, oval, stroke); + return EllipseOp::Make(std::move(paint), aa, viewMatrix, oval, stroke); } // Otherwise, if we have shader derivative support, render as device-independent if (shaderCaps->shaderDerivativeSupport()) { - return DIEllipseOp::Make(std::move(paint), viewMatrix, oval, stroke); + return DIEllipseOp::Make(std::move(paint), aa, viewMatrix, oval, stroke); } return nullptr; @@ -2420,11 +2480,10 @@ std::unique_ptr<GrDrawOp> GrOvalOpFactory::MakeOvalOp(GrPaint&& paint, /////////////////////////////////////////////////////////////////////////////// -std::unique_ptr<GrDrawOp> GrOvalOpFactory::MakeArcOp(GrPaint&& paint, const SkMatrix& viewMatrix, - const SkRect& oval, SkScalar startAngle, - SkScalar sweepAngle, bool useCenter, - const GrStyle& style, - const GrShaderCaps* shaderCaps) { +std::unique_ptr<GrDrawOp> GrOvalOpFactory::MakeCoverageArcOp( + GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, const SkRect& oval, + SkScalar startAngle, SkScalar sweepAngle, bool useCenter, const GrStyle& style, + const GrShaderCaps* shaderCaps) { SkASSERT(!oval.isEmpty()); SkASSERT(sweepAngle); SkScalar width = oval.width(); @@ -2437,7 +2496,7 @@ std::unique_ptr<GrDrawOp> GrOvalOpFactory::MakeArcOp(GrPaint&& paint, const SkMa SkPoint center = {oval.centerX(), oval.centerY()}; CircleOp::ArcParams arcParams = {SkDegreesToRadians(startAngle), SkDegreesToRadians(sweepAngle), useCenter}; - return CircleOp::Make(std::move(paint), viewMatrix, center, width / 2.f, style, &arcParams); + return CircleOp::Make(std::move(paint), aa, viewMatrix, center, width / 2.f, style, &arcParams); } /////////////////////////////////////////////////////////////////////////////// @@ -2460,14 +2519,15 @@ GR_DRAW_OP_TEST_DEFINE(CircleOp) { SkStrokeRec stroke = GrTest::TestStrokeRec(random); CircleOp::ArcParams arcParamsTmp; const CircleOp::ArcParams* arcParams = nullptr; + GrAA aa = random->nextBool() ? GrAA::kYes : GrAA::kNo; if (random->nextBool()) { arcParamsTmp.fStartAngleRadians = random->nextSScalar1() * SK_ScalarPI * 2; arcParamsTmp.fSweepAngleRadians = random->nextSScalar1() * SK_ScalarPI * 2 - .01f; arcParamsTmp.fUseCenter = random->nextBool(); arcParams = &arcParamsTmp; } - std::unique_ptr<GrDrawOp> op = CircleOp::Make(std::move(paint), viewMatrix, center, radius, - GrStyle(stroke, nullptr), arcParams); + std::unique_ptr<GrDrawOp> op = CircleOp::Make(std::move(paint), aa, viewMatrix, center, + radius, GrStyle(stroke, nullptr), arcParams); if (op) { return op; } @@ -2477,19 +2537,24 @@ GR_DRAW_OP_TEST_DEFINE(CircleOp) { GR_DRAW_OP_TEST_DEFINE(EllipseOp) { SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random); SkRect ellipse = GrTest::TestSquare(random); - return EllipseOp::Make(std::move(paint), viewMatrix, ellipse, GrTest::TestStrokeRec(random)); + GrAA aa = random->nextBool() ? GrAA::kYes : GrAA::kNo; + return EllipseOp::Make(std::move(paint), aa, viewMatrix, ellipse, + GrTest::TestStrokeRec(random)); } GR_DRAW_OP_TEST_DEFINE(DIEllipseOp) { SkMatrix viewMatrix = GrTest::TestMatrix(random); SkRect ellipse = GrTest::TestSquare(random); - return DIEllipseOp::Make(std::move(paint), viewMatrix, ellipse, GrTest::TestStrokeRec(random)); + GrAA aa = random->nextBool() ? GrAA::kYes : GrAA::kNo; + return DIEllipseOp::Make(std::move(paint), aa, viewMatrix, ellipse, + GrTest::TestStrokeRec(random)); } GR_DRAW_OP_TEST_DEFINE(RRectOp) { SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random); const SkRRect& rrect = GrTest::TestRRectSimple(random); - return make_rrect_op(std::move(paint), viewMatrix, rrect, GrTest::TestStrokeRec(random)); + GrAA aa = random->nextBool() ? GrAA::kYes : GrAA::kNo; + return make_rrect_op(std::move(paint), aa, viewMatrix, rrect, GrTest::TestStrokeRec(random)); } #endif diff --git a/src/gpu/ops/GrOvalOpFactory.h b/src/gpu/ops/GrOvalOpFactory.h index 1bdf3ee6f6..d31e09ed9c 100644 --- a/src/gpu/ops/GrOvalOpFactory.h +++ b/src/gpu/ops/GrOvalOpFactory.h @@ -22,29 +22,33 @@ class SkStrokeRec; /* * This namespace wraps helper functions that draw ovals, rrects, and arcs (filled & stroked) + * The ops always use coverage even when their non-AA. */ class GrOvalOpFactory { public: - static std::unique_ptr<GrDrawOp> MakeOvalOp(GrPaint&&, - const SkMatrix&, - const SkRect& oval, - const SkStrokeRec&, - const GrShaderCaps*); + static std::unique_ptr<GrDrawOp> MakeCoverageOvalOp(GrPaint&&, + GrAA, + const SkMatrix&, + const SkRect& oval, + const SkStrokeRec&, + const GrShaderCaps*); - static std::unique_ptr<GrDrawOp> MakeRRectOp(GrPaint&&, - const SkMatrix&, - const SkRRect&, - const SkStrokeRec&, - const GrShaderCaps*); + static std::unique_ptr<GrDrawOp> MakeCoverageRRectOp(GrPaint&&, + GrAA, + const SkMatrix&, + const SkRRect&, + const SkStrokeRec&, + const GrShaderCaps*); - static std::unique_ptr<GrDrawOp> MakeArcOp(GrPaint&&, - const SkMatrix&, - const SkRect& oval, - SkScalar startAngle, - SkScalar sweepAngle, - bool useCenter, - const GrStyle&, - const GrShaderCaps*); + static std::unique_ptr<GrDrawOp> MakeCoverageArcOp(GrPaint&&, + GrAA, + const SkMatrix&, + const SkRect& oval, + SkScalar startAngle, + SkScalar sweepAngle, + bool useCenter, + const GrStyle&, + const GrShaderCaps*); }; #endif // GrOvalOpFactory_DEFINED diff --git a/src/gpu/text/GrStencilAndCoverTextContext.cpp b/src/gpu/text/GrStencilAndCoverTextContext.cpp index 86e5732eb9..951b1dfd65 100644 --- a/src/gpu/text/GrStencilAndCoverTextContext.cpp +++ b/src/gpu/text/GrStencilAndCoverTextContext.cpp @@ -583,7 +583,8 @@ void GrStencilAndCoverTextContext::TextRun::draw(GrContext* ctx, // The run's "font" overrides the anti-aliasing of the passed in SkPaint! GrAAType aaType = GrChooseAAType(this->aa(), renderTargetContext->fsaaType(), - GrAllowMixedSamples::kYes, *renderTargetContext->caps()); + GrAllowMixedSamples::kYes, GrAllowNonAABinaryCoverage::kNo, + nullptr, *renderTargetContext->caps()); std::unique_ptr<GrDrawOp> op = GrDrawPathRangeOp::Make( viewMatrix, fTextRatio, fTextInverseRatio * x, fTextInverseRatio * y, |