/* * 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 GrCoverageCountingPathRenderer_DEFINED #define GrCoverageCountingPathRenderer_DEFINED #include #include "GrAllocator.h" #include "GrOnFlushResourceProvider.h" #include "GrPathRenderer.h" #include "SkTInternalLList.h" #include "ccpr/GrCCAtlas.h" #include "ccpr/GrCCPathParser.h" #include "ccpr/GrCCPathProcessor.h" #include "ops/GrDrawOp.h" /** * This is a path renderer that draws antialiased paths by counting coverage in an offscreen * buffer. (See GrCCCoverageProcessor, GrCCPathProcessor) * * It also serves as the per-render-target tracker for pending path draws, and at the start of * flush, it compiles GPU buffers and renders a "coverage count atlas" for the upcoming paths. */ class GrCoverageCountingPathRenderer : public GrPathRenderer, public GrOnFlushCallbackObject { struct RTPendingPaths; public: static bool IsSupported(const GrCaps&); static sk_sp CreateIfSupported(const GrCaps&, bool drawCachablePaths); ~GrCoverageCountingPathRenderer() override { // Ensure no Ops exist that could have a dangling pointer back into this class. SkASSERT(fRTPendingPathsMap.empty()); SkASSERT(0 == fPendingDrawOpsCount); } // This is the Op that ultimately draws a path into its final destination, using the atlas we // generate at flush time. class DrawPathsOp : public GrDrawOp { public: DEFINE_OP_CLASS_ID SK_DECLARE_INTERNAL_LLIST_INTERFACE(DrawPathsOp); DrawPathsOp(GrCoverageCountingPathRenderer*, const DrawPathArgs&, GrColor); ~DrawPathsOp() override; struct SingleDraw { SkIRect fClipIBounds; SkMatrix fMatrix; SkPath fPath; GrColor fColor; SingleDraw* fNext = nullptr; }; const SingleDraw* head() const { SkASSERT(fInstanceCount >= 1); return &fHeadDraw; } SkDEBUGCODE(int numSkippedInstances_debugOnly() const { return fNumSkippedInstances; }) // GrDrawOp overrides. const char* name() const override { return "GrCoverageCountingPathRenderer::DrawPathsOp"; } FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; } RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*, GrPixelConfigIsClamped) override; void wasRecorded(GrRenderTargetOpList*) override; bool onCombineIfPossible(GrOp* other, const GrCaps& caps) override; void visitProxies(const VisitProxyFunc& func) const override { fProcessors.visitProxies(func); } void onPrepare(GrOpFlushState*) override {} void onExecute(GrOpFlushState*) override; int setupResources(GrOnFlushResourceProvider*, GrCCPathProcessor::Instance* pathInstanceData, int pathInstanceIdx); private: SkPath::FillType getFillType() const { SkASSERT(fInstanceCount >= 1); return fHeadDraw.fPath.getFillType(); } struct AtlasBatch { const GrCCAtlas* fAtlas; int fEndInstanceIdx; }; void addAtlasBatch(const GrCCAtlas* atlas, int endInstanceIdx) { SkASSERT(endInstanceIdx > fBaseInstance); SkASSERT(fAtlasBatches.empty() || endInstanceIdx > fAtlasBatches.back().fEndInstanceIdx); fAtlasBatches.push_back() = {atlas, endInstanceIdx}; } GrCoverageCountingPathRenderer* const fCCPR; const uint32_t fSRGBFlags; GrProcessorSet fProcessors; SingleDraw fHeadDraw; SingleDraw* fTailDraw; RTPendingPaths* fOwningRTPendingPaths; int fBaseInstance; SkDEBUGCODE(int fInstanceCount); SkDEBUGCODE(int fNumSkippedInstances); SkSTArray<1, AtlasBatch, true> fAtlasBatches; typedef GrDrawOp INHERITED; }; // GrPathRenderer overrides. StencilSupport onGetStencilSupport(const GrShape&) const override { return GrPathRenderer::kNoSupport_StencilSupport; } CanDrawPath onCanDrawPath(const CanDrawPathArgs& args) const override; bool onDrawPath(const DrawPathArgs&) final; // These are keyed by SkPath generation ID, and store which device-space paths are accessed and // where by clip FPs in a given opList. A single ClipPath can be referenced by multiple FPs. At // flush time their coverage count masks are packed into atlas(es) alongside normal DrawPathOps. class ClipPath { public: ClipPath() = default; ClipPath(const ClipPath&) = delete; ~ClipPath() { // Ensure no clip FPs exist with a dangling pointer back into this class. SkASSERT(!fAtlasLazyProxy || fAtlasLazyProxy->isUnique_debugOnly()); // Ensure no lazy proxy callbacks exist with a dangling pointer back into this class. SkASSERT(fHasAtlasTransform); } bool isUninitialized() const { return !fAtlasLazyProxy; } void init(GrProxyProvider* proxyProvider, const SkPath& deviceSpacePath, const SkIRect& accessRect, int rtWidth, int rtHeight); void addAccess(const SkIRect& accessRect) { SkASSERT(!this->isUninitialized()); fAccessRect.join(accessRect); } GrTextureProxy* atlasLazyProxy() const { SkASSERT(!this->isUninitialized()); return fAtlasLazyProxy.get(); } const SkPath& deviceSpacePath() const { SkASSERT(!this->isUninitialized()); return fDeviceSpacePath; } const SkIRect& pathDevIBounds() const { SkASSERT(!this->isUninitialized()); return fPathDevIBounds; } void placePathInAtlas(GrCoverageCountingPathRenderer*, GrOnFlushResourceProvider*, GrCCPathParser*); const SkVector& atlasScale() const { SkASSERT(fHasAtlasTransform); return fAtlasScale; } const SkVector& atlasTranslate() const { SkASSERT(fHasAtlasTransform); return fAtlasTranslate; } private: sk_sp fAtlasLazyProxy; SkPath fDeviceSpacePath; SkIRect fPathDevIBounds; SkIRect fAccessRect; const GrCCAtlas* fAtlas = nullptr; int16_t fAtlasOffsetX; int16_t fAtlasOffsetY; SkDEBUGCODE(bool fHasAtlas = false); SkVector fAtlasScale; SkVector fAtlasTranslate; SkDEBUGCODE(bool fHasAtlasTransform = false); }; bool canMakeClipProcessor(const SkPath& deviceSpacePath) const; std::unique_ptr makeClipProcessor(GrProxyProvider*, uint32_t oplistID, const SkPath& deviceSpacePath, const SkIRect& accessRect, int rtWidth, int rtHeight); // GrOnFlushCallbackObject overrides. void preFlush(GrOnFlushResourceProvider*, const uint32_t* opListIDs, int numOpListIDs, SkTArray>* results) override; void postFlush(GrDeferredUploadToken, const uint32_t* opListIDs, int numOpListIDs) override; private: GrCoverageCountingPathRenderer(bool drawCachablePaths) : fDrawCachablePaths(drawCachablePaths) {} GrCCAtlas* placeParsedPathInAtlas(GrOnFlushResourceProvider*, const SkIRect& accessRect, const SkIRect& pathIBounds, int16_t* atlasOffsetX, int16_t* atlasOffsetY); struct RTPendingPaths { ~RTPendingPaths() { // Ensure all DrawPathsOps in this opList have been deleted. SkASSERT(fDrawOps.isEmpty()); } SkTInternalLList fDrawOps; std::map fClipPaths; GrSTAllocator<256, DrawPathsOp::SingleDraw> fDrawsAllocator; }; // A map from render target ID to the individual render target's pending paths. std::map fRTPendingPathsMap; SkDEBUGCODE(int fPendingDrawOpsCount = 0); sk_sp fPerFlushIndexBuffer; sk_sp fPerFlushVertexBuffer; sk_sp fPerFlushInstanceBuffer; sk_sp fPerFlushPathParser; GrSTAllocator<4, GrCCAtlas> fPerFlushAtlases; bool fPerFlushResourcesAreValid; SkDEBUGCODE(bool fFlushing = false); const bool fDrawCachablePaths; }; #endif