/* * Copyright 2021 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef AtlasRenderTask_DEFINED #define AtlasRenderTask_DEFINED #include "include/core/SkPath.h" #include "include/core/SkRefCnt.h" #include "include/private/SkColorData.h" #include "include/private/base/SkAssert.h" #include "include/private/base/SkNoncopyable.h" #include "src/base/SkBlockAllocator.h" #include "src/base/SkTBlockList.h" #include "src/gpu/ganesh/GrCaps.h" #include "src/gpu/ganesh/GrDynamicAtlas.h" #include "src/gpu/ganesh/GrSurfaceProxyView.h" #include "src/gpu/ganesh/GrTexture.h" #include "src/gpu/ganesh/ops/GrOp.h" #include "src/gpu/ganesh/ops/OpsTask.h" #include "src/gpu/ganesh/tessellate/PathTessellator.h" #include #include class GrArenas; class GrOnFlushResourceProvider; class GrOpFlushState; class GrRecordingContext; class GrTextureProxy; class SkMatrix; struct GrUserStencilSettings; struct SkIPoint16; struct SkIPoint; struct SkIRect; struct SkRect; namespace skgpu::ganesh { // Represents a GrRenderTask that draws paths into an atlas. This task gets added the DAG and left // open, lays out its atlas while future tasks call addPath(), and finally adds its internal draw // ops during onMakeClosed(). // // The atlas texture does not get instantiated automatically. It is the creator's responsibility to // call instantiate() at flush time. class AtlasRenderTask final : public OpsTask { public: AtlasRenderTask(GrRecordingContext*, sk_sp, std::unique_ptr); const GrTextureProxy* atlasProxy() const { return fDynamicAtlas->textureProxy(); } GrSurfaceProxyView readView(const GrCaps& caps) const { return fDynamicAtlas->readView(caps); } // Allocates a rectangle for, and stages the given path to be rendered into the atlas. Returns // false if there was not room in the atlas. On success, writes out the location of the path's // upper-left corner to 'locationInAtlas'. bool addPath(const SkMatrix&, const SkPath&, SkIPoint pathDevTopLeft, int widthInAtlas, int heightInAtlas, bool transposedInAtlas, SkIPoint16* locationInAtlas); // Must be called at flush time. The texture proxy is instantiated with 'backingTexture', if // provided. See GrDynamicAtlas. [[nodiscard]] bool instantiate(GrOnFlushResourceProvider* onFlushRP, sk_sp backingTexture = nullptr) { SkASSERT(this->isClosed()); return fDynamicAtlas->instantiate(onFlushRP, std::move(backingTexture)); } private: // Adds internal ops to render the atlas before deferring to OpsTask::onMakeClosed. ExpectedOutcome onMakeClosed(GrRecordingContext*, SkIRect* targetUpdateBounds) override; void stencilAtlasRect(GrRecordingContext*, const SkRect&, const SkPMColor4f&, const GrUserStencilSettings*); void addAtlasDrawOp(GrOp::Owner, const GrCaps&); // Executes the OpsTask and resolves msaa if needed. bool onExecute(GrOpFlushState* flushState) override; const std::unique_ptr fDynamicAtlas; // Allocate enough inline entries for 16 atlas path draws, then spill to the heap. using PathDrawList = PathTessellator::PathDrawList; using PathDrawAllocator = SkTBlockList; PathDrawAllocator fPathDrawAllocator{64, SkBlockAllocator::GrowthPolicy::kFibonacci}; class AtlasPathList : SkNoncopyable { public: void add(PathDrawAllocator* alloc, const SkMatrix& pathMatrix, const SkPath& path) { fPathDrawList = &alloc->emplace_back(pathMatrix, path, SK_PMColor4fTRANSPARENT, fPathDrawList); if (path.isInverseFillType()) { // The atlas never has inverse paths. The inversion happens later. fPathDrawList->fPath.toggleInverseFillType(); } fTotalCombinedPathVerbCnt += path.countVerbs(); ++fPathCount; } const PathDrawList* pathDrawList() const { return fPathDrawList; } int totalCombinedPathVerbCnt() const { return fTotalCombinedPathVerbCnt; } int pathCount() const { return fPathCount; } private: PathDrawList* fPathDrawList = nullptr; int fTotalCombinedPathVerbCnt = 0; int fPathCount = 0; }; AtlasPathList fWindingPathList; AtlasPathList fEvenOddPathList; }; } // namespace skgpu::ganesh #endif // AtlasRenderTask_DEFINED