| /* |
| * 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 GrCCPRCoverageOpsBuilder_DEFINED |
| #define GrCCPRCoverageOpsBuilder_DEFINED |
| |
| #include "GrBuffer.h" |
| #include "SkRefCnt.h" |
| #include "SkRect.h" |
| #include "ccpr/GrCCPRCoverageProcessor.h" |
| |
| class GrCCPRCoverageOp; |
| class GrDrawOp; |
| class GrOnFlushResourceProvider; |
| class GrResourceProvider; |
| class SkMatrix; |
| class SkPath; |
| struct SkDCubic; |
| enum class SkCubicType; |
| |
| /** |
| * This class produces GrDrawOps 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 then produce a GrDrawOp for all currently saved paths by calling either |
| * createIntermediateOp() or 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; |
| |
| struct MaxPrimitives { |
| int fMaxTriangles = 0; |
| int fMaxQuadratics = 0; |
| int fMaxCubics = 0; |
| |
| void operator+=(const MaxPrimitives&); |
| int sum() const; |
| }; |
| |
| struct MaxBufferItems { |
| int fMaxFanPoints = 0; |
| int fMaxControlPoints = 0; |
| MaxPrimitives fMaxPrimitives[kNumScissorModes]; |
| int fMaxPaths = 0; |
| |
| void operator+=(const MaxBufferItems&); |
| void countPathItems(ScissorMode, const SkPath&); |
| }; |
| |
| GrCCPRCoverageOpsBuilder() : fScissorBatches(512) { |
| SkDEBUGCODE(fPointsData = nullptr;) |
| SkDEBUGCODE(fInstanceData = nullptr;) |
| } |
| |
| bool init(GrOnFlushResourceProvider*, const MaxBufferItems&); |
| |
| // Parses an SkPath into a temporary staging area. The path will not yet be included in the next |
| // Op until there is a matching call to saveParsedPath. |
| // |
| // Returns two tight bounding boxes: device space and "45 degree" (| 1 -1 | * devCoords) space. |
| // | 1 1 | |
| void parsePath(ScissorMode, const SkMatrix&, const SkPath&, SkRect* devBounds, |
| SkRect* devBounds45); |
| |
| // Commits the currently-parsed path from the staging area to the GPU buffers and next Op. |
| // Accepts an optional post-device-space translate for placement in an atlas. |
| void saveParsedPath(const SkIRect& clippedDevIBounds, |
| int16_t atlasOffsetX, int16_t atlasOffsetY); |
| |
| // Flushes all currently-saved paths to a GrDrawOp and leaves the GPU buffers open to accept |
| // new paths (e.g. for when an atlas runs out of space). |
| // 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. |
| std::unique_ptr<GrDrawOp> SK_WARN_UNUSED_RESULT createIntermediateOp(SkISize drawBounds); |
| |
| // Flushes the remaining saved paths to a final GrDrawOp and closes off the GPU buffers. This |
| // must be called before attempting to draw any Ops produced by this class. |
| std::unique_ptr<GrDrawOp> SK_WARN_UNUSED_RESULT finalize(SkISize drawBounds); |
| |
| class CoverageOp; |
| |
| private: |
| using PrimitiveInstance = GrCCPRCoverageProcessor::PrimitiveInstance; |
| |
| struct PrimitiveTallies { |
| int fTriangles; |
| int fQuadratics; |
| int fSerpentines; |
| int fLoops; |
| |
| PrimitiveTallies operator+(const PrimitiveTallies&) const; |
| PrimitiveTallies operator-(const PrimitiveTallies&) const; |
| int sum() const; |
| }; |
| |
| struct ScissorBatch { |
| PrimitiveTallies fInstanceCounts; |
| SkIRect fScissor; |
| }; |
| |
| void startContour(const SkPoint& anchorPoint); |
| void fanTo(const SkPoint& pt); |
| void quadraticTo(SkPoint controlPt, SkPoint endPt); |
| void cubicTo(SkPoint controlPt1, SkPoint controlPt2, SkPoint endPt); |
| void emitCubicSegment(SkCubicType, const SkDCubic&, const SkPoint& ts0, const SkPoint& ts1); |
| void closeContour(); |
| void emitHierarchicalFan(int32_t indices[], int count); |
| SkDEBUGCODE(void validate();) |
| |
| ScissorMode fCurrScissorMode; |
| PrimitiveTallies fCurrPathIndices; |
| int32_t fCurrContourStartIdx; |
| SkPoint fCurrAnchorPoint; |
| SkPoint fCurrFanPoint; |
| |
| sk_sp<GrBuffer> fPointsBuffer; |
| SkPoint* fPointsData; |
| int32_t fFanPtsIdx; |
| int32_t fControlPtsIdx; |
| SkDEBUGCODE(int fMaxFanPoints;) |
| SkDEBUGCODE(int fMaxControlPoints;) |
| |
| sk_sp<GrBuffer> fInstanceBuffer; |
| PrimitiveInstance* fInstanceData; |
| PrimitiveTallies fBaseInstances[kNumScissorModes]; |
| PrimitiveTallies fInstanceIndices[kNumScissorModes]; |
| |
| SkTArray<ScissorBatch> fScissorBatches; |
| }; |
| |
| inline void GrCCPRCoverageOpsBuilder::MaxBufferItems::operator+=(const MaxBufferItems& b) { |
| fMaxFanPoints += b.fMaxFanPoints; |
| fMaxControlPoints += b.fMaxControlPoints; |
| fMaxPrimitives[0] += b.fMaxPrimitives[0]; |
| fMaxPrimitives[1] += b.fMaxPrimitives[1]; |
| fMaxPaths += b.fMaxPaths; |
| } |
| |
| inline void GrCCPRCoverageOpsBuilder::MaxPrimitives::operator+=(const MaxPrimitives& b) { |
| fMaxTriangles += b.fMaxTriangles; |
| fMaxQuadratics += b.fMaxQuadratics; |
| fMaxCubics += b.fMaxCubics; |
| } |
| |
| inline int GrCCPRCoverageOpsBuilder::MaxPrimitives::sum() const { |
| return fMaxTriangles + fMaxQuadratics + fMaxCubics; |
| } |
| |
| #endif |