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 GrCCPathParser_DEFINED
9 #define GrCCPathParser_DEFINED
10 
11 #include "GrMesh.h"
12 #include "GrNonAtomicRef.h"
13 #include "GrTessellator.h"
14 #include "SkRect.h"
15 #include "SkRefCnt.h"
16 #include "ccpr/GrCCCoverageProcessor.h"
17 #include "ccpr/GrCCGeometry.h"
18 #include "ops/GrDrawOp.h"
19 
20 class GrOnFlushResourceProvider;
21 class SkMatrix;
22 class SkPath;
23 
24 /**
25  * This class parses SkPaths into CCPR primitives in GPU buffers, then issues calls to draw their
26  * coverage counts.
27  */
28 class GrCCPathParser : public GrNonAtomicRef<GrCCPathParser> {
29 public:
30     // Indicates whether a path should enforce a scissor clip when rendering its mask. (Specified
31     // as an int because these values get used directly as indices into arrays.)
32     enum class ScissorMode : int { kNonScissored = 0, kScissored = 1 };
33     static constexpr int kNumScissorModes = 2;
34 
35     GrCCPathParser(int maxTotalPaths, int maxPathPoints, int numSkPoints, int numSkVerbs);
36 
37     ~GrCCPathParser() {
38         // Enforce the contract that the client always calls saveParsedPath or discardParsedPath.
39         SkASSERT(!fParsingPath);
40     }
41 
42     using CoverageCountBatchID = int;
43 
44     // Parses an SkPath into a temporary staging area. The path will not be included in the current
45     // batch until there is a matching call to saveParsedPath. The user must complement this with a
46     // following call to either saveParsedPath or discardParsedPath.
47     //
48     // Returns two tight bounding boxes: device space and "45 degree" (| 1 -1 | * devCoords) space.
49     //                                                                 | 1  1 |
50     void parsePath(const SkMatrix&, const SkPath&, SkRect* devBounds, SkRect* devBounds45);
51 
52     // Parses a device-space SkPath into a temporary staging area. The path will not be included in
53     // the current batch until there is a matching call to saveParsedPath. The user must complement
54     // this with a following call to either saveParsedPath or discardParsedPath.
55     void parseDeviceSpacePath(const SkPath&);
56 
57     // Commits the currently-parsed path from staging to the current batch, and specifies whether
58     // the mask should be rendered with a scissor in effect. Accepts an optional post-device-space
59     // translate for placement in an atlas.
60     void saveParsedPath(ScissorMode, const SkIRect& clippedDevIBounds, int16_t atlasOffsetX,
61                         int16_t atlasOffsetY);
62     void discardParsedPath();
63 
64     // Compiles the outstanding saved paths into a batch, and returns an ID that can be used to draw
65     // their coverage counts in the future.
66     CoverageCountBatchID closeCurrentBatch();
67 
68     // Builds internal GPU buffers and prepares for calls to drawCoverageCount. Caller must close
69     // the current batch before calling this method, and cannot parse new paths afer.
70     bool finalize(GrOnFlushResourceProvider*);
71 
72     // Called after finalize. Draws the given batch of parsed paths.
73     void drawCoverageCount(GrOpFlushState*, CoverageCountBatchID, const SkIRect& drawBounds) const;
74 
75 private:
76     using PrimitiveTallies = GrCCGeometry::PrimitiveTallies;
77 
78     // Every kBeginPath verb has a corresponding PathInfo entry.
79     struct PathInfo {
80         PathInfo(ScissorMode scissorMode, int16_t offsetX, int16_t offsetY)
81                 : fScissorMode(scissorMode), fAtlasOffsetX(offsetX), fAtlasOffsetY(offsetY) {}
82 
83         ScissorMode fScissorMode;
84         int16_t fAtlasOffsetX, fAtlasOffsetY;
85         std::unique_ptr<GrTessellator::WindingVertex[]> fFanTessellation;
86         int fFanTessellationCount = 0;
87     };
88 
89     // Defines a batch of CCPR primitives. Start indices are deduced by looking at the previous
90     // CoverageCountBatch in the list.
91     struct CoverageCountBatch {
92         PrimitiveTallies fEndNonScissorIndices;
93         int fEndScissorSubBatchIdx;
94         PrimitiveTallies fTotalPrimitiveCounts;
95     };
96 
97     // Defines a sub-batch from CoverageCountBatch that will be drawn with the given scissor rect.
98     // Start indices are deduced by looking at the previous ScissorSubBatch in the list.
99     struct ScissorSubBatch {
100         PrimitiveTallies fEndPrimitiveIndices;
101         SkIRect fScissor;
102     };
103 
104     void parsePath(const SkPath&, const SkPoint* deviceSpacePts);
105     void endContourIfNeeded(bool insideContour);
106 
107     void drawRenderPass(GrOpFlushState*, const GrPipeline&, CoverageCountBatchID,
108                         GrCCCoverageProcessor::RenderPass, GrCCCoverageProcessor::WindMethod,
109                         int PrimitiveTallies::*instanceType, const SkIRect& drawBounds) const;
110 
111     // Staging area for the path being parsed.
112     SkDEBUGCODE(int fParsingPath = false);
113     const SkAutoSTArray<32, SkPoint> fLocalDevPtsBuffer;
114     int fCurrPathPointsIdx;
115     int fCurrPathVerbsIdx;
116     PrimitiveTallies fCurrPathPrimitiveCounts;
117 
118     GrCCGeometry fGeometry;
119     SkSTArray<32, PathInfo, true> fPathsInfo;
120     SkSTArray<32, CoverageCountBatch, true> fCoverageCountBatches;
121     SkSTArray<32, ScissorSubBatch, true> fScissorSubBatches;
122     PrimitiveTallies fTotalPrimitiveCounts[kNumScissorModes];
123     int fMaxMeshesPerDraw = 0;
124 
125     sk_sp<GrBuffer> fInstanceBuffer;
126     PrimitiveTallies fBaseInstances[kNumScissorModes];
127     mutable SkSTArray<32, GrMesh> fMeshesScratchBuffer;
128     mutable SkSTArray<32, GrPipeline::DynamicState> fDynamicStatesScratchBuffer;
129 };
130 
131 #endif
132