diff --git a/gn/gpu.gni b/gn/gpu.gni index b2f8555ab4..e66ab77c1d 100644 --- a/gn/gpu.gni +++ b/gn/gpu.gni @@ -261,6 +261,8 @@ skia_gpu_sources = [ "$_src/gpu/ops/GrMSAAPathRenderer.h", "$_src/gpu/ops/GrNonAAFillRectOp.h", "$_src/gpu/ops/GrNonAAFillRectOp.cpp", + "$_src/gpu/ops/GrNewNonAAFillRectOp.h", + "$_src/gpu/ops/GrNewNonAAFillRectOp.cpp", "$_src/gpu/ops/GrNonAAFillRectPerspectiveOp.cpp", "$_src/gpu/ops/GrNonAAStrokeRectOp.cpp", "$_src/gpu/ops/GrNonAAStrokeRectOp.h", @@ -278,6 +280,7 @@ skia_gpu_sources = [ "$_src/gpu/ops/GrSemaphoreOp.h", "$_src/gpu/ops/GrShadowRRectOp.cpp", "$_src/gpu/ops/GrShadowRRectOp.h", + "$_src/gpu/ops/GrSimpleMeshDrawOpHelper.h", "$_src/gpu/ops/GrSmallPathRenderer.cpp", "$_src/gpu/ops/GrSmallPathRenderer.h", "$_src/gpu/ops/GrStencilAndCoverPathRenderer.cpp", diff --git a/src/gpu/GrOpFlushState.h b/src/gpu/GrOpFlushState.h index 4ba87feebf..0fc7b7f834 100644 --- a/src/gpu/GrOpFlushState.h +++ b/src/gpu/GrOpFlushState.h @@ -10,6 +10,7 @@ #include "GrBufferAllocPool.h" #include "GrGpu.h" +#include "SkArenaAlloc.h" #include "ops/GrMeshDrawOp.h" class GrGpuCommandBuffer; @@ -94,6 +95,7 @@ public: void reset() { fVertexPool.reset(); fIndexPool.reset(); + fPipelines.reset(); } /** Additional data required on a per-op basis when executing GrDrawOps. */ @@ -110,16 +112,22 @@ public: return *fOpArgs; } + template + GrPipeline* allocPipeline(Args... args) { + return fPipelines.make(std::forward(args)...); + } + private: - GrGpu* fGpu; - GrResourceProvider* fResourceProvider; - GrGpuCommandBuffer* fCommandBuffer; - GrVertexBufferAllocPool fVertexPool; - GrIndexBufferAllocPool fIndexPool; - SkSTArray<4, GrDrawOp::DeferredUploadFn> fAsapUploads; - GrDrawOpUploadToken fLastIssuedToken; - GrDrawOpUploadToken fLastFlushedToken; - DrawOpArgs* fOpArgs; + GrGpu* fGpu; + GrResourceProvider* fResourceProvider; + GrGpuCommandBuffer* fCommandBuffer; + GrVertexBufferAllocPool fVertexPool; + GrIndexBufferAllocPool fIndexPool; + SkSTArray<4, GrDrawOp::DeferredUploadFn> fAsapUploads; + GrDrawOpUploadToken fLastIssuedToken; + GrDrawOpUploadToken fLastFlushedToken; + DrawOpArgs* fOpArgs; + SkArenaAlloc fPipelines{sizeof(GrPipeline) * 100}; }; /** @@ -182,6 +190,7 @@ public: protected: GrDrawOp* op() { return fOp; } GrOpFlushState* state() { return fState; } + const GrOpFlushState* state() const { return fState; } private: GrOpFlushState* fState; @@ -211,6 +220,19 @@ public: this->state()->putBackVertexSpace(vertices * vertexStride); } + GrRenderTarget* renderTarget() const { return this->state()->drawOpArgs().fRenderTarget; } + + const GrAppliedClip* clip() const { return this->state()->drawOpArgs().fAppliedClip; } + + const GrXferProcessor::DstTexture& dstTexture() const { + return this->state()->drawOpArgs().fDstTexture; + } + + template + GrPipeline* allocPipeline(Args... args) { + return this->state()->allocPipeline(std::forward(args)...); + } + private: GrMeshDrawOp* meshDrawOp() { return static_cast(this->op()); } typedef GrDrawOp::Target INHERITED; diff --git a/src/gpu/GrPaint.cpp b/src/gpu/GrPaint.cpp index 6c5a041c94..9bbeec5bfc 100644 --- a/src/gpu/GrPaint.cpp +++ b/src/gpu/GrPaint.cpp @@ -12,11 +12,11 @@ #include "effects/GrSimpleTextureEffect.h" void GrPaint::setPorterDuffXPFactory(SkBlendMode mode) { - fXPFactory = GrPorterDuffXPFactory::Get(mode); + this->setXPFactory(GrPorterDuffXPFactory::Get(mode)); } void GrPaint::setCoverageSetOpXPFactory(SkRegion::Op regionOp, bool invertCoverage) { - fXPFactory = GrCoverageSetOpXPFactory::Get(regionOp, invertCoverage); + this->setXPFactory(GrCoverageSetOpXPFactory::Get(regionOp, invertCoverage)); } void GrPaint::addColorTextureProcessor(GrResourceProvider* resourceProvider, diff --git a/src/gpu/GrPaint.h b/src/gpu/GrPaint.h index bcf6858df8..6fe561ab33 100644 --- a/src/gpu/GrPaint.h +++ b/src/gpu/GrPaint.h @@ -79,11 +79,14 @@ public: * as such (with linear blending), and sRGB inputs to be filtered and decoded correctly. */ void setGammaCorrect(bool gammaCorrect) { - setDisableOutputConversionToSRGB(!gammaCorrect); - setAllowSRGBInputs(gammaCorrect); + this->setDisableOutputConversionToSRGB(!gammaCorrect); + this->setAllowSRGBInputs(gammaCorrect); } - void setXPFactory(const GrXPFactory* xpFactory) { fXPFactory = xpFactory; } + void setXPFactory(const GrXPFactory* xpFactory) { + fXPFactory = xpFactory; + fTrivial &= !SkToBool(xpFactory); + } void setPorterDuffXPFactory(SkBlendMode mode); @@ -96,6 +99,7 @@ public: SkASSERT(fp); fUsesDistanceVectorField |= fp->usesDistanceVectorField(); fColorFragmentProcessors.push_back(std::move(fp)); + fTrivial = false; } /** @@ -105,6 +109,7 @@ public: SkASSERT(fp); fUsesDistanceVectorField |= fp->usesDistanceVectorField(); fCoverageFragmentProcessors.push_back(std::move(fp)); + fTrivial = false; } /** @@ -143,6 +148,12 @@ public: */ bool isConstantBlendedColor(GrColor* constantColor) const; + /** + * A trivial paint is one that uses src-over and has no fragment processors. + * It may have variable sRGB settings. + **/ + bool isTrivial() const { return fTrivial; } + private: template class MoveOrImpl; @@ -172,6 +183,7 @@ private: bool fDisableOutputConversionToSRGB = false; bool fAllowSRGBInputs = false; bool fUsesDistanceVectorField = false; + bool fTrivial = true; GrColor4f fColor = GrColor4f::OpaqueWhite(); }; diff --git a/src/gpu/GrPipeline.h b/src/gpu/GrPipeline.h index 3bac5f79e0..7fa42d0b8a 100644 --- a/src/gpu/GrPipeline.h +++ b/src/gpu/GrPipeline.h @@ -90,6 +90,8 @@ public: **/ GrPipeline(GrRenderTarget*, SkBlendMode); + GrPipeline(const InitArgs& args) { this->init(args); } + /** (Re)initializes a pipeline. After initialization the pipeline can be used. */ void init(const InitArgs&); diff --git a/src/gpu/GrProcessorSet.cpp b/src/gpu/GrProcessorSet.cpp index 69fa69a324..db732666b7 100644 --- a/src/gpu/GrProcessorSet.cpp +++ b/src/gpu/GrProcessorSet.cpp @@ -11,6 +11,8 @@ #include "GrXferProcessor.h" #include "effects/GrPorterDuffXferProcessor.h" +const GrProcessorSet GrProcessorSet::gEmpty{GrProcessorSet::Empty::kEmpty}; + GrProcessorSet::GrProcessorSet(GrPaint&& paint) : fXP(paint.getXPFactory()) { fFlags = 0; if (paint.numColorFragmentProcessors() <= kMaxColorProcessors) { diff --git a/src/gpu/GrProcessorSet.h b/src/gpu/GrProcessorSet.h index 6ebb00bee2..56cbee1cac 100644 --- a/src/gpu/GrProcessorSet.h +++ b/src/gpu/GrProcessorSet.h @@ -18,6 +18,10 @@ class GrXferProcessor; class GrXPFactory; class GrProcessorSet : private SkNoncopyable { +private: + // Arbitrary constructor arg for empty set and analysis + enum class Empty { kEmpty }; + public: GrProcessorSet(GrPaint&& paint); @@ -80,6 +84,14 @@ public: } private: + constexpr Analysis(Empty) + : fUsesLocalCoords(false) + , fCompatibleWithCoverageAsAlpha(true) + , fRequiresDstTexture(false) + , fCanCombineOverlappedStencilAndCover(true) + , fRequiresBarrierBetweenOverlappingDraws(false) + , fIsInitialized(true) + , fInputColorType(kOriginal_InputColorType) {} enum InputColorType : uint32_t { kOriginal_InputColorType, kOverridden_InputColorType, @@ -122,7 +134,13 @@ public: bool isFinalized() const { return SkToBool(kFinalized_Flag & fFlags); } + static const GrProcessorSet& EmptySet() { return gEmpty; } + static constexpr const Analysis EmptySetAnalysis() { return Analysis(Empty::kEmpty); } + private: + GrProcessorSet(Empty) : fXP((const GrXferProcessor*)nullptr), fFlags(kFinalized_Flag) {} + static const GrProcessorSet gEmpty; + // This absurdly large limit allows Analysis and this to pack fields together. static constexpr int kMaxColorProcessors = UINT8_MAX; @@ -130,6 +148,7 @@ private: union XP { XP(const GrXPFactory* factory) : fFactory(factory) {} + XP(const GrXferProcessor* processor) : fProcessor(processor) {} const GrXPFactory* fFactory; const GrXferProcessor* fProcessor; }; @@ -141,7 +160,7 @@ private: SkAutoSTArray<4, const GrFragmentProcessor*> fFragmentProcessors; XP fXP; - uint8_t fColorFragmentProcessorCnt; + uint8_t fColorFragmentProcessorCnt = 0; uint8_t fFragmentProcessorOffset = 0; uint8_t fFlags; }; diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp index 6e724414d1..e21522fc65 100644 --- a/src/gpu/GrRenderTargetContext.cpp +++ b/src/gpu/GrRenderTargetContext.cpp @@ -6,6 +6,7 @@ */ #include "GrRenderTargetContext.h" +#include "../private/GrAuditTrail.h" #include "GrAppliedClip.h" #include "GrColor.h" #include "GrContextPriv.h" @@ -27,10 +28,11 @@ #include "ops/GrClearOp.h" #include "ops/GrClearStencilClipOp.h" #include "ops/GrDiscardOp.h" -#include "ops/GrDrawOp.h" #include "ops/GrDrawAtlasOp.h" +#include "ops/GrDrawOp.h" #include "ops/GrDrawVerticesOp.h" #include "ops/GrLatticeOp.h" +#include "ops/GrNewNonAAFillRectOp.h" #include "ops/GrOp.h" #include "ops/GrOvalOpFactory.h" #include "ops/GrRectOpFactory.h" @@ -39,7 +41,6 @@ #include "ops/GrStencilPathOp.h" #include "text/GrAtlasTextContext.h" #include "text/GrStencilAndCoverTextContext.h" -#include "../private/GrAuditTrail.h" #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this->drawingManager()->getContext()) #define ASSERT_SINGLE_OWNER \ @@ -1275,7 +1276,13 @@ void GrRenderTargetContext::drawNonAAFilledRect(const GrClip& clip, const GrUserStencilSettings* ss, GrAAType hwOrNoneAAType) { SkASSERT(GrAAType::kCoverage != hwOrNoneAAType); - SkASSERT(hwOrNoneAAType == GrAAType::kNone || this->isStencilBufferMultisampled()); + SkASSERT(GrAAType::kNone == hwOrNoneAAType || this->isStencilBufferMultisampled()); + if (!viewMatrix.hasPerspective() && (!localMatrix || !localMatrix->hasPerspective())) { + std::unique_ptr op = GrNewNonAAFillRectOp::Make( + std::move(paint), viewMatrix, rect, localRect, localMatrix, hwOrNoneAAType, ss); + this->addDrawOp(clip, std::move(op)); + return; + } std::unique_ptr op = GrRectOpFactory::MakeNonAAFill( paint.getColor(), viewMatrix, rect, localRect, localMatrix); GrPipelineBuilder pipelineBuilder(std::move(paint), hwOrNoneAAType); diff --git a/src/gpu/ops/GrMeshDrawOp.cpp b/src/gpu/ops/GrMeshDrawOp.cpp index 92571d6c70..ee7c0a58dc 100644 --- a/src/gpu/ops/GrMeshDrawOp.cpp +++ b/src/gpu/ops/GrMeshDrawOp.cpp @@ -67,8 +67,6 @@ void* GrMeshDrawOp::QuadHelper::init(Target* target, size_t vertexStride, int qu } void GrMeshDrawOp::onExecute(GrOpFlushState* state) { - SkASSERT(!state->drawOpArgs().fAppliedClip); - SkASSERT(!state->drawOpArgs().fDstTexture.texture()); int currUploadIdx = 0; int currMeshIdx = 0; diff --git a/src/gpu/ops/GrNewNonAAFillRectOp.cpp b/src/gpu/ops/GrNewNonAAFillRectOp.cpp new file mode 100644 index 0000000000..15e025a4c8 --- /dev/null +++ b/src/gpu/ops/GrNewNonAAFillRectOp.cpp @@ -0,0 +1,198 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrNewNonAAFillRectOp.h" +#include "GrAppliedClip.h" +#include "GrColor.h" +#include "GrDefaultGeoProcFactory.h" +#include "GrMeshDrawOp.h" +#include "GrOpFlushState.h" +#include "GrPrimitiveProcessor.h" +#include "GrQuad.h" +#include "GrResourceProvider.h" +#include "GrSimpleMeshDrawOpHelper.h" +#include "SkMatrixPriv.h" + +static const int kVertsPerRect = 4; +static const int kIndicesPerRect = 6; + +/** We always use per-vertex colors so that rects can be combined across color changes. Sometimes + we have explicit local coords and sometimes not. We *could* always provide explicit local + coords and just duplicate the positions when the caller hasn't provided a local coord rect, + but we haven't seen a use case which frequently switches between local rect and no local + rect draws. + + The vertex attrib order is always pos, color, [local coords]. + */ +static sk_sp make_gp() { + using namespace GrDefaultGeoProcFactory; + return GrDefaultGeoProcFactory::Make(Color::kPremulGrColorAttribute_Type, Coverage::kSolid_Type, + LocalCoords::kHasExplicit_Type, SkMatrix::I()); +} + +static void tesselate(intptr_t vertices, + size_t vertexStride, + GrColor color, + const SkMatrix* viewMatrix, + const SkRect& rect, + const GrQuad* localQuad) { + SkPoint* positions = reinterpret_cast(vertices); + + positions->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vertexStride); + + if (viewMatrix) { + SkMatrixPriv::MapPointsWithStride(*viewMatrix, positions, vertexStride, kVertsPerRect); + } + + // Setup local coords + // TODO we should only do this if local coords are being read + if (localQuad) { + static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor); + for (int i = 0; i < kVertsPerRect; i++) { + SkPoint* coords = + reinterpret_cast(vertices + kLocalOffset + i * vertexStride); + *coords = localQuad->point(i); + } + } + + static const int kColorOffset = sizeof(SkPoint); + GrColor* vertColor = reinterpret_cast(vertices + kColorOffset); + for (int j = 0; j < 4; ++j) { + *vertColor = color; + vertColor = (GrColor*)((intptr_t)vertColor + vertexStride); + } +} + +class NewNonAAFillRectOp final : public GrMeshDrawOp { +private: + using Helper = GrSimpleMeshDrawOpHelperWithStencil; + +public: + DEFINE_OP_CLASS_ID + NewNonAAFillRectOp() = delete; + + static std::unique_ptr Make(GrPaint&& paint, const SkMatrix& viewMatrix, + const SkRect& rect, const SkRect* localRect, + const SkMatrix* localMatrix, GrAAType aaType, + const GrUserStencilSettings* stencilSettings) { + SkASSERT(GrAAType::kCoverage != aaType); + return Helper::FactoryHelper(std::move(paint), viewMatrix, rect, + localRect, localMatrix, aaType, + stencilSettings); + } + + const char* name() const override { return "NonAAFillRectOp"; } + + SkString dumpInfo() const override { + SkString str; + str.append(GrMeshDrawOp::dumpInfo()); + str.appendf("# combined: %d\n", fRects.count()); + for (int i = 0; i < fRects.count(); ++i) { + const RectInfo& info = fRects[i]; + str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", i, + info.fColor, info.fRect.fLeft, info.fRect.fTop, info.fRect.fRight, + info.fRect.fBottom); + } + return str; + } + + bool xpRequiresDstTexture(const GrCaps& caps, const GrAppliedClip* clip) override { + GrColor* color = &fRects.front().fColor; + return fHelper.xpRequiresDstTexture(caps, clip, GrProcessorAnalysisCoverage::kNone, color); + } + + FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); } + + NewNonAAFillRectOp(const Helper::MakeArgs& args, GrColor color, const SkMatrix& viewMatrix, + const SkRect& rect, const SkRect* localRect, const SkMatrix* localMatrix, + GrAAType aaType, const GrUserStencilSettings* stencilSettings) + : INHERITED(ClassID()), fHelper(args, aaType, stencilSettings) { + SkASSERT(!viewMatrix.hasPerspective() && (!localMatrix || !localMatrix->hasPerspective())); + RectInfo& info = fRects.push_back(); + info.fColor = color; + info.fViewMatrix = viewMatrix; + info.fRect = rect; + if (localRect && localMatrix) { + info.fLocalQuad.setFromMappedRect(*localRect, *localMatrix); + } else if (localRect) { + info.fLocalQuad.set(*localRect); + } else if (localMatrix) { + info.fLocalQuad.setFromMappedRect(rect, *localMatrix); + } else { + info.fLocalQuad.set(rect); + } + this->setTransformedBounds(fRects[0].fRect, viewMatrix, HasAABloat::kNo, IsZeroArea::kNo); + } + +private: + void onPrepareDraws(Target* target) const override { + sk_sp gp = make_gp(); + if (!gp) { + SkDebugf("Couldn't create GrGeometryProcessor\n"); + return; + } + SkASSERT(gp->getVertexStride() == + sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr)); + + size_t vertexStride = gp->getVertexStride(); + int rectCount = fRects.count(); + + sk_sp indexBuffer(target->resourceProvider()->refQuadIndexBuffer()); + PatternHelper helper; + void* vertices = helper.init(target, kTriangles_GrPrimitiveType, vertexStride, + indexBuffer.get(), kVertsPerRect, kIndicesPerRect, rectCount); + if (!vertices || !indexBuffer) { + SkDebugf("Could not allocate vertices\n"); + return; + } + + for (int i = 0; i < rectCount; i++) { + intptr_t verts = + reinterpret_cast(vertices) + i * kVertsPerRect * vertexStride; + tesselate(verts, vertexStride, fRects[i].fColor, &fRects[i].fViewMatrix, + fRects[i].fRect, &fRects[i].fLocalQuad); + } + helper.recordDraw(target, gp.get(), fHelper.makePipeline(target)); + } + + bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { + NewNonAAFillRectOp* that = t->cast(); + if (!fHelper.isCompatible(that->fHelper)) { + return false; + } + fRects.push_back_n(that->fRects.count(), that->fRects.begin()); + this->joinBounds(*that); + return true; + } + + struct RectInfo { + GrColor fColor; + SkMatrix fViewMatrix; + SkRect fRect; + GrQuad fLocalQuad; + }; + + Helper fHelper; + SkSTArray<1, RectInfo, true> fRects; + typedef GrMeshDrawOp INHERITED; +}; + +namespace GrNewNonAAFillRectOp { + +std::unique_ptr Make(GrPaint&& paint, + const SkMatrix& viewMatrix, + const SkRect& rect, + const SkRect* localRect, + const SkMatrix* localMatrix, + GrAAType aaType, + const GrUserStencilSettings* stencilSettings) { + return NewNonAAFillRectOp::Make(std::move(paint), viewMatrix, rect, localRect, localMatrix, + aaType, stencilSettings); +} +}; // namespace GrNewNonAAFillRectOp + +/////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/gpu/ops/GrNewNonAAFillRectOp.h b/src/gpu/ops/GrNewNonAAFillRectOp.h new file mode 100644 index 0000000000..8f78707854 --- /dev/null +++ b/src/gpu/ops/GrNewNonAAFillRectOp.h @@ -0,0 +1,31 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrNewNonAAFillRectOp_DEFINED +#define GrNewNonAAFillRectOp_DEFINED + +#include +#include "GrColor.h" + +class GrDrawOp; +class GrPaint; +class SkMatrix; +struct SkRect; +struct GrUserStencilSettings; +enum class GrAAType : unsigned; + +namespace GrNewNonAAFillRectOp { +std::unique_ptr Make(GrPaint&&, + const SkMatrix& viewMatrix, + const SkRect& rect, + const SkRect* localRect, + const SkMatrix* localMatrix, + GrAAType, + const GrUserStencilSettings* = nullptr); +}; + +#endif diff --git a/src/gpu/ops/GrSimpleMeshDrawOpHelper.h b/src/gpu/ops/GrSimpleMeshDrawOpHelper.h new file mode 100644 index 0000000000..f64f9eca2e --- /dev/null +++ b/src/gpu/ops/GrSimpleMeshDrawOpHelper.h @@ -0,0 +1,194 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrSimpleMeshDrawOpHelper_DEFINED +#define GrSimpleMeshDrawOpHelper_DEFINED + +#include "GrAppliedClip.h" +#include "GrOpFlushState.h" +#include "GrPipeline.h" +#include "GrProcessorSet.h" +#include "GrUserStencilSettings.h" + +/** + * This class can be used to help implement simple mesh draw ops. It reduces the amount of + * boilerplate code to type and also provides a mechanism for optionally allocating space for a + * GrProcessorSet based on a GrPaint. It is intended to be used by ops that construct a single + * GrPipeline for a uniform primitive color and a GrPaint. + */ +class GrSimpleMeshDrawOpHelper { +public: + struct MakeArgs; + + /** + * This can be used by a Op class to perform allocation and initialization such that a + * GrProcessorSet (if required) is allocated at the same time as the Op instance. It requires + * that Op implements a constructor of the form: + * Op(MakeArgs, GrColor, OpArgs...) + * which is public or made accessible via 'friend'. + */ + template + static std::unique_ptr FactoryHelper(GrPaint&& paint, OpArgs... opArgs); + + GrSimpleMeshDrawOpHelper(const MakeArgs& args, GrAAType aaType, + GrUserStencilSettings* stencilSettings = nullptr) + : fProcessors(args.fProcessorSet) + , fPipelineFlags(args.fSRGBFlags) + , fAAType((int)aaType) { + SkASSERT(!stencilSettings); + if (GrAATypeIsHW(aaType)) { + fPipelineFlags |= GrPipeline::kHWAntialias_Flag; + } + } + + ~GrSimpleMeshDrawOpHelper() { + if (fProcessors) { + fProcessors->~GrProcessorSet(); + } + } + + GrSimpleMeshDrawOpHelper() = delete; + GrSimpleMeshDrawOpHelper(const GrSimpleMeshDrawOpHelper&) = delete; + GrSimpleMeshDrawOpHelper& operator=(const GrSimpleMeshDrawOpHelper&) = delete; + + GrDrawOp::FixedFunctionFlags fixedFunctionFlags() const { + return GrAATypeIsHW((this->aaType())) ? GrDrawOp::FixedFunctionFlags::kUsesHWAA + : GrDrawOp::FixedFunctionFlags::kNone; + } + + bool isCompatible(const GrSimpleMeshDrawOpHelper& that) const { + if (SkToBool(fProcessors) != SkToBool(that.fProcessors)) { + return false; + } + if (SkToBool(fProcessors) && *fProcessors != *that.fProcessors) { + return false; + } + return fPipelineFlags == that.fPipelineFlags && fAAType == that.fAAType; + } + + bool xpRequiresDstTexture(const GrCaps& caps, const GrAppliedClip* clip, + GrProcessorAnalysisCoverage geometryCoverage, GrColor* color) { + if (fProcessors) { + GrProcessorAnalysisCoverage coverage = geometryCoverage; + if (GrProcessorAnalysisCoverage::kNone == coverage) { + coverage = clip->clipCoverageFragmentProcessor() + ? GrProcessorAnalysisCoverage::kSingleChannel + : GrProcessorAnalysisCoverage::kNone; + } + bool isMixedSamples = this->aaType() == GrAAType::kMixedSamples; + GrProcessorSet::Analysis analysis = + fProcessors->finalize(*color, coverage, clip, isMixedSamples, caps, color); + return analysis.requiresDstTexture(); + } else { + return GrProcessorSet::EmptySetAnalysis().requiresDstTexture(); + } + } + + GrPipeline* makePipeline(GrMeshDrawOp::Target* target) const { + return target->allocPipeline(this->pipelineInitArgs(target)); + } + + struct MakeArgs { + private: + MakeArgs() = default; + + GrProcessorSet* fProcessorSet; + uint32_t fSRGBFlags; + + friend class GrSimpleMeshDrawOpHelper; + }; + +protected: + GrAAType aaType() const { return static_cast(fAAType); } + uint32_t pipelineFlags() const { return fPipelineFlags; } + const GrProcessorSet& processors() const { + return fProcessors ? *fProcessors : GrProcessorSet::EmptySet(); + } + + GrPipeline::InitArgs pipelineInitArgs(GrMeshDrawOp::Target* target) const { + GrPipeline::InitArgs args; + args.fFlags = this->pipelineFlags(); + args.fProcessors = &this->processors(); + args.fRenderTarget = target->renderTarget(); + args.fAppliedClip = target->clip(); + args.fDstTexture = target->dstTexture(); + args.fCaps = &target->caps(); + return args; + } + +private: + GrProcessorSet* fProcessors; + unsigned fPipelineFlags : 8; + unsigned fAAType : 2; +}; + +/** + * This class extends GrSimpleMeshDrawOpHelper to support an optional GrUserStencilSettings. This + * uses private inheritance because it non-virtually overrides methods in the base class and should + * never be used with a GrSimpleMeshDrawOpHelper pointer or reference. + */ +class GrSimpleMeshDrawOpHelperWithStencil : private GrSimpleMeshDrawOpHelper { +public: + using MakeArgs = GrSimpleMeshDrawOpHelper::MakeArgs; + + // using declarations can't be templated, so this is a pass through function instead. + template + static std::unique_ptr FactoryHelper(GrPaint&& paint, OpArgs... opArgs) { + return GrSimpleMeshDrawOpHelper::FactoryHelper( + std::move(paint), std::forward(opArgs)...); + } + + GrSimpleMeshDrawOpHelperWithStencil(const MakeArgs& args, GrAAType aaType, + const GrUserStencilSettings* stencilSettings) + : INHERITED(args, aaType) + , fStencilSettings(stencilSettings ? stencilSettings + : &GrUserStencilSettings::kUnused) {} + + GrDrawOp::FixedFunctionFlags fixedFunctionFlags() const { + GrDrawOp::FixedFunctionFlags flags = INHERITED::fixedFunctionFlags(); + if (fStencilSettings != &GrUserStencilSettings::kUnused) { + flags |= GrDrawOp::FixedFunctionFlags::kUsesStencil; + } + return flags; + } + + using GrSimpleMeshDrawOpHelper::xpRequiresDstTexture; + + bool isCompatible(const GrSimpleMeshDrawOpHelperWithStencil& that) const { + return INHERITED::isCompatible(that) && fStencilSettings == that.fStencilSettings; + } + + GrPipeline* makePipeline(GrMeshDrawOp::Target* target) const { + auto args = INHERITED::pipelineInitArgs(target); + args.fUserStencil = fStencilSettings; + return target->allocPipeline(args); + } + +private: + const GrUserStencilSettings* fStencilSettings; + typedef GrSimpleMeshDrawOpHelper INHERITED; +}; + +template +std::unique_ptr GrSimpleMeshDrawOpHelper::FactoryHelper(GrPaint&& paint, + OpArgs... opArgs) { + MakeArgs makeArgs; + makeArgs.fSRGBFlags = GrPipeline::SRGBFlagsFromPaint(paint); + GrColor color = paint.getColor(); + if (paint.isTrivial()) { + makeArgs.fProcessorSet = nullptr; + return std::unique_ptr(new Op(makeArgs, color, std::forward(opArgs)...)); + } else { + char* mem = (char*)GrOp::operator new(sizeof(Op) + sizeof(GrProcessorSet)); + char* setMem = mem + sizeof(Op); + makeArgs.fProcessorSet = new (setMem) GrProcessorSet(std::move(paint)); + return std::unique_ptr( + new (mem) Op(makeArgs, color, std::forward(opArgs)...)); + } +} + +#endif