blob: f08a7e2b1fb47c3b0b5b2fbe3dbe8d27c967ef91 [file] [log] [blame]
/*
* 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 "src/core/SkTBlockList.h"
#include "src/gpu/GrDynamicAtlas.h"
#include "src/gpu/ops/OpsTask.h"
#include "src/gpu/tessellate/PathTessellator.h"
struct SkIPoint16;
namespace skgpu::v1 {
// 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 : public OpsTask {
public:
AtlasRenderTask(GrRecordingContext*,
sk_sp<GrArenas>,
std::unique_ptr<GrDynamicAtlas>);
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.
void instantiate(GrOnFlushResourceProvider* onFlushRP,
sk_sp<GrTexture> backingTexture = nullptr) {
SkASSERT(this->isClosed());
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<GrDynamicAtlas> fDynamicAtlas;
// Allocate enough inline entries for 16 atlas path draws, then spill to the heap.
using PathDrawList = skgpu::tess::PathTessellator::PathDrawList;
using PathDrawAllocator = SkTBlockList<PathDrawList, 16>;
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, 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::v1
#endif // AtlasRenderTask_DEFINED