Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2017 Google Inc. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license that can be |
| 5 | * found in the LICENSE file. |
| 6 | */ |
| 7 | |
| 8 | #ifndef GrCCPRCoverageOpsBuilder_DEFINED |
| 9 | #define GrCCPRCoverageOpsBuilder_DEFINED |
| 10 | |
| 11 | #include "GrBuffer.h" |
| 12 | #include "SkRefCnt.h" |
| 13 | #include "SkRect.h" |
| 14 | #include "ccpr/GrCCPRCoverageProcessor.h" |
| 15 | |
| 16 | class GrCCPRCoverageOp; |
| 17 | class GrDrawOp; |
| 18 | class GrOnFlushResourceProvider; |
| 19 | class GrResourceProvider; |
| 20 | class SkMatrix; |
| 21 | class SkPath; |
| 22 | struct SkDCubic; |
| 23 | enum class SkCubicType; |
| 24 | |
| 25 | /** |
| 26 | * This class produces GrDrawOps that render coverage count masks and atlases. A path is added to |
| 27 | * the current op in two steps: |
| 28 | * |
| 29 | * 1) parsePath(ScissorMode, viewMatrix, path, &devBounds, &devBounds45); |
| 30 | * |
| 31 | * <client decides where to put the mask within an atlas, if wanted> |
| 32 | * |
| 33 | * 2) saveParsedPath(offsetX, offsetY, clipBounds); |
| 34 | * |
| 35 | * The client can then produce a GrDrawOp for all currently saved paths by calling either |
| 36 | * createIntermediateOp() or finalize(). |
| 37 | */ |
| 38 | class GrCCPRCoverageOpsBuilder { |
| 39 | public: |
| 40 | // Indicates whether a path should enforce a scissor clip when rendering its mask. (Specified |
| 41 | // as an int because these values get used directly as indices into arrays.) |
| 42 | enum class ScissorMode : int { |
| 43 | kNonScissored = 0, |
| 44 | kScissored = 1 |
| 45 | }; |
| 46 | static constexpr int kNumScissorModes = 2; |
| 47 | |
| 48 | struct MaxPrimitives { |
| 49 | int fMaxTriangles = 0; |
| 50 | int fMaxQuadratics = 0; |
| 51 | int fMaxCubics = 0; |
| 52 | |
| 53 | void operator+=(const MaxPrimitives&); |
| 54 | int sum() const; |
| 55 | }; |
| 56 | |
| 57 | struct MaxBufferItems { |
| 58 | int fMaxFanPoints = 0; |
| 59 | int fMaxControlPoints = 0; |
| 60 | MaxPrimitives fMaxPrimitives[kNumScissorModes]; |
| 61 | int fMaxPaths = 0; |
| 62 | |
| 63 | void operator+=(const MaxBufferItems&); |
| 64 | void countPathItems(ScissorMode, const SkPath&); |
| 65 | }; |
| 66 | |
| 67 | GrCCPRCoverageOpsBuilder() : fScissorBatches(512) { |
| 68 | SkDEBUGCODE(fPointsData = nullptr;) |
| 69 | SkDEBUGCODE(fInstanceData = nullptr;) |
| 70 | } |
| 71 | |
| 72 | bool init(GrOnFlushResourceProvider*, const MaxBufferItems&); |
| 73 | |
| 74 | // Parses an SkPath into a temporary staging area. The path will not yet be included in the next |
| 75 | // Op until there is a matching call to saveParsedPath. |
| 76 | // |
| 77 | // Returns two tight bounding boxes: device space and "45 degree" (| 1 -1 | * devCoords) space. |
| 78 | // | 1 1 | |
| 79 | void parsePath(ScissorMode, const SkMatrix&, const SkPath&, SkRect* devBounds, |
| 80 | SkRect* devBounds45); |
| 81 | |
| 82 | // Commits the currently-parsed path from the staging area to the GPU buffers and next Op. |
| 83 | // Accepts an optional post-device-space translate for placement in an atlas. |
| 84 | void saveParsedPath(const SkIRect& clippedDevIBounds, |
| 85 | int16_t atlasOffsetX, int16_t atlasOffsetY); |
| 86 | |
| 87 | // Flushes all currently-saved paths to a GrDrawOp and leaves the GPU buffers open to accept |
| 88 | // new paths (e.g. for when an atlas runs out of space). |
| 89 | // NOTE: if there is a parsed path in the staging area, it will not be included. But the client |
| 90 | // may still call saveParsedPath to include it in a future Op. |
| 91 | std::unique_ptr<GrDrawOp> SK_WARN_UNUSED_RESULT createIntermediateOp(SkISize drawBounds); |
| 92 | |
| 93 | // Flushes the remaining saved paths to a final GrDrawOp and closes off the GPU buffers. This |
| 94 | // must be called before attempting to draw any Ops produced by this class. |
| 95 | std::unique_ptr<GrDrawOp> SK_WARN_UNUSED_RESULT finalize(SkISize drawBounds); |
| 96 | |
| 97 | class CoverageOp; |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 98 | |
| 99 | private: |
| 100 | using PrimitiveInstance = GrCCPRCoverageProcessor::PrimitiveInstance; |
| 101 | |
| 102 | struct PrimitiveTallies { |
| 103 | int fTriangles; |
| 104 | int fQuadratics; |
| 105 | int fSerpentines; |
| 106 | int fLoops; |
| 107 | |
| 108 | PrimitiveTallies operator+(const PrimitiveTallies&) const; |
| 109 | PrimitiveTallies operator-(const PrimitiveTallies&) const; |
| 110 | int sum() const; |
| 111 | }; |
| 112 | |
| 113 | struct ScissorBatch { |
| 114 | PrimitiveTallies fInstanceCounts; |
| 115 | SkIRect fScissor; |
| 116 | }; |
| 117 | |
Chris Dalton | 21171e5 | 2017-08-01 15:36:01 -0600 | [diff] [blame] | 118 | void startContour(const SkPoint& anchorPoint); |
| 119 | void fanTo(const SkPoint& pt); |
| 120 | void quadraticTo(SkPoint controlPt, SkPoint endPt); |
| 121 | void cubicTo(SkPoint controlPt1, SkPoint controlPt2, SkPoint endPt); |
| 122 | void emitCubicSegment(SkCubicType, const SkDCubic&, const SkPoint& ts0, const SkPoint& ts1); |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 123 | void closeContour(); |
| 124 | void emitHierarchicalFan(int32_t indices[], int count); |
| 125 | SkDEBUGCODE(void validate();) |
| 126 | |
| 127 | ScissorMode fCurrScissorMode; |
| 128 | PrimitiveTallies fCurrPathIndices; |
| 129 | int32_t fCurrContourStartIdx; |
Chris Dalton | 21171e5 | 2017-08-01 15:36:01 -0600 | [diff] [blame] | 130 | SkPoint fCurrAnchorPoint; |
| 131 | SkPoint fCurrFanPoint; |
Chris Dalton | 1a325d2 | 2017-07-14 15:17:41 -0600 | [diff] [blame] | 132 | |
| 133 | sk_sp<GrBuffer> fPointsBuffer; |
| 134 | SkPoint* fPointsData; |
| 135 | int32_t fFanPtsIdx; |
| 136 | int32_t fControlPtsIdx; |
| 137 | SkDEBUGCODE(int fMaxFanPoints;) |
| 138 | SkDEBUGCODE(int fMaxControlPoints;) |
| 139 | |
| 140 | sk_sp<GrBuffer> fInstanceBuffer; |
| 141 | PrimitiveInstance* fInstanceData; |
| 142 | PrimitiveTallies fBaseInstances[kNumScissorModes]; |
| 143 | PrimitiveTallies fInstanceIndices[kNumScissorModes]; |
| 144 | |
| 145 | SkTArray<ScissorBatch> fScissorBatches; |
| 146 | }; |
| 147 | |
| 148 | inline void GrCCPRCoverageOpsBuilder::MaxBufferItems::operator+=(const MaxBufferItems& b) { |
| 149 | fMaxFanPoints += b.fMaxFanPoints; |
| 150 | fMaxControlPoints += b.fMaxControlPoints; |
| 151 | fMaxPrimitives[0] += b.fMaxPrimitives[0]; |
| 152 | fMaxPrimitives[1] += b.fMaxPrimitives[1]; |
| 153 | fMaxPaths += b.fMaxPaths; |
| 154 | } |
| 155 | |
| 156 | inline void GrCCPRCoverageOpsBuilder::MaxPrimitives::operator+=(const MaxPrimitives& b) { |
| 157 | fMaxTriangles += b.fMaxTriangles; |
| 158 | fMaxQuadratics += b.fMaxQuadratics; |
| 159 | fMaxCubics += b.fMaxCubics; |
| 160 | } |
| 161 | |
| 162 | inline int GrCCPRCoverageOpsBuilder::MaxPrimitives::sum() const { |
| 163 | return fMaxTriangles + fMaxQuadratics + fMaxCubics; |
| 164 | } |
| 165 | |
| 166 | #endif |