blob: 7d457fef33adb76dabc06cd45b9b247a4d4bc88f [file] [log] [blame]
/*
* 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 GrCCPRCoverageOp_DEFINED
#define GrCCPRCoverageOp_DEFINED
#include "GrMesh.h"
#include "SkRect.h"
#include "SkRefCnt.h"
#include "ccpr/GrCCPRCoverageProcessor.h"
#include "ccpr/GrCCPRGeometry.h"
#include "ops/GrDrawOp.h"
class GrCCPRCoverageOp;
class GrOnFlushResourceProvider;
class SkMatrix;
class SkPath;
/**
* This class produces GrCCPRCoverageOps that render coverage count masks and atlases. A path is
* added to the current op in two steps:
*
* 1) parsePath(ScissorMode, viewMatrix, path, &devBounds, &devBounds45);
*
* <client decides where to put the mask within an atlas, if wanted>
*
* 2) saveParsedPath(offsetX, offsetY, clipBounds);
*
* The client can flush the currently saved paths to a GrCCPRCoverageOp by calling emitOp, and
* retrieve all emitted ops after calling finalize().
*/
class GrCCPRCoverageOpsBuilder {
public:
// Indicates whether a path should enforce a scissor clip when rendering its mask. (Specified
// as an int because these values get used directly as indices into arrays.)
enum class ScissorMode : int {
kNonScissored = 0,
kScissored = 1
};
static constexpr int kNumScissorModes = 2;
GrCCPRCoverageOpsBuilder(int maxTotalPaths, int numSkPoints, int numSkVerbs)
: fPathsInfo(maxTotalPaths)
, fGeometry(numSkPoints, numSkVerbs)
, fTallies{PrimitiveTallies(), PrimitiveTallies()}
, fScissorBatches(maxTotalPaths) {}
~GrCCPRCoverageOpsBuilder() {
// Enforce the contract that the client always calls saveParsedPath or discardParsedPath.
SkASSERT(!fParsingPath);
}
// Parses an SkPath into a temporary staging area. The path will not yet be included in the next
// Op unless there is a matching call to saveParsedPath. The user must complement this with a
// following call to either saveParsedPath or discardParsedPath.
//
// Returns two tight bounding boxes: device space and "45 degree" (| 1 -1 | * devCoords) space.
// | 1 1 |
void parsePath(const SkMatrix&, const SkPath&, SkRect* devBounds, SkRect* devBounds45);
// Commits the currently-parsed path from staging to the next Op, and specifies whether the mask
// should be rendered with a scissor clip in effect. Accepts an optional post-device-space
// translate for placement in an atlas.
void saveParsedPath(ScissorMode, const SkIRect& clippedDevIBounds,
int16_t atlasOffsetX, int16_t atlasOffsetY);
void discardParsedPath();
// Flushes all currently-saved paths internally to a GrCCPRCoverageOp.
//
// NOTE: if there is a parsed path in the staging area, it will not be included. But the client
// may still call saveParsedPath to include it in a future Op.
void emitOp(SkISize drawBounds);
// Builds GPU buffers and returns the list of GrCCPRCoverageOps as specified by calls to emitOp.
bool finalize(GrOnFlushResourceProvider*, SkTArray<std::unique_ptr<GrCCPRCoverageOp>>*);
private:
using PrimitiveTallies = GrCCPRGeometry::PrimitiveTallies;
// Every kBeginPath verb has a corresponding PathInfo entry.
struct PathInfo {
ScissorMode fScissorMode;
int32_t fPackedAtlasOffset; // (offsetY << 16) | (offsetX & 0xffff)
std::unique_ptr<GrCCPRCoverageOp> fTerminatingOp;
};
// Every PathInfo with a mode of kScissored has a corresponding ScissorBatch.
struct ScissorBatch {
PrimitiveTallies fInstanceCounts;
SkIRect fScissor;
};
void endContourIfNeeded(bool insideContour);
// Staging area for the path being parsed.
SkDEBUGCODE(int fParsingPath = false);
int fCurrPathPointsIdx;
int fCurrPathVerbsIdx;
PrimitiveTallies fCurrPathTallies;
SkSTArray<32, PathInfo, true> fPathsInfo;
GrCCPRGeometry fGeometry;
PrimitiveTallies fTallies[kNumScissorModes];
SkTArray<ScissorBatch, true> fScissorBatches;
std::unique_ptr<GrCCPRCoverageOp> fTerminatingOp;
friend class GrCCPRCoverageOp; // For ScissorBatch.
};
/**
* This Op renders coverage count masks and atlases. Create it using GrCCPRCoverageOpsBuilder.
*/
class GrCCPRCoverageOp : public GrDrawOp {
public:
DEFINE_OP_CLASS_ID
// GrDrawOp interface.
const char* name() const override { return "GrCCPRCoverageOp"; }
FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*,
GrPixelConfigIsClamped) override {
return RequiresDstTexture::kNo;
}
bool onCombineIfPossible(GrOp* other, const GrCaps& caps) override { return false; }
void onPrepare(GrOpFlushState*) override {}
void onExecute(GrOpFlushState*) override;
private:
static constexpr int kNumScissorModes = GrCCPRCoverageOpsBuilder::kNumScissorModes;
using PrimitiveTallies = GrCCPRGeometry::PrimitiveTallies;
using ScissorBatch = GrCCPRCoverageOpsBuilder::ScissorBatch;
GrCCPRCoverageOp(SkTArray<ScissorBatch, true>&& scissorBatches, const SkISize& drawBounds)
: INHERITED(ClassID())
, fScissorBatches(std::move(scissorBatches))
, fDrawBounds(drawBounds) {
this->setBounds(SkRect::MakeIWH(fDrawBounds.width(), fDrawBounds.height()),
GrOp::HasAABloat::kNo, GrOp::IsZeroArea::kNo);
}
void setBuffers(sk_sp<GrBuffer> pointsBuffer, sk_sp<GrBuffer> instanceBuffer,
const PrimitiveTallies baseInstances[kNumScissorModes],
const PrimitiveTallies endInstances[kNumScissorModes]);
void drawMaskPrimitives(GrOpFlushState*, const GrPipeline&, const GrCCPRCoverageProcessor::Mode,
GrPrimitiveType, int vertexCount,
int PrimitiveTallies::* instanceType) const;
sk_sp<GrBuffer> fPointsBuffer;
sk_sp<GrBuffer> fInstanceBuffer;
PrimitiveTallies fBaseInstances[kNumScissorModes];
PrimitiveTallies fInstanceCounts[kNumScissorModes];
const SkTArray<ScissorBatch, true> fScissorBatches;
const SkISize fDrawBounds;
mutable SkTArray<GrMesh> fMeshesScratchBuffer;
mutable SkTArray<GrPipeline::DynamicState> fDynamicStatesScratchBuffer;
friend class GrCCPRCoverageOpsBuilder;
typedef GrDrawOp INHERITED;
};
#endif