1 | /* |
2 | * Copyright 2018 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 GrCCStroker_DEFINED |
9 | #define GrCCStroker_DEFINED |
10 | |
11 | #include "include/private/GrTypesPriv.h" |
12 | #include "include/private/SkNx.h" |
13 | #include "src/gpu/GrTAllocator.h" |
14 | #include "src/gpu/ccpr/GrCCStrokeGeometry.h" |
15 | |
16 | class GrGpuBuffer; |
17 | class GrCCCoverageProcessor; |
18 | class GrOnFlushResourceProvider; |
19 | class GrOpFlushState; |
20 | class GrPipeline; |
21 | class GrPrimitiveProcessor; |
22 | class SkMatrix; |
23 | class SkPath; |
24 | class SkStrokeRec; |
25 | |
26 | /** |
27 | * This class parses stroked SkPaths into a GPU instance buffer, then issues calls to draw their |
28 | * coverage counts. |
29 | */ |
30 | class GrCCStroker { |
31 | public: |
32 | GrCCStroker(int numPaths, int numSkPoints, int numSkVerbs) |
33 | : fGeometry(numSkPoints, numSkVerbs), fPathInfos(numPaths) {} |
34 | |
35 | // Parses a device-space SkPath into the current batch, using the SkPath's original verbs with |
36 | // 'deviceSpacePts', and the SkStrokeRec's original settings with 'strokeDevWidth'. Accepts an |
37 | // optional post-device-space translate for placement in an atlas. |
38 | // |
39 | // Strokes intended as hairlines must have a strokeDevWidth of 1. Non-hairline strokes can only |
40 | // be drawn with rigid body transforms; affine transformation of the stroke lines themselves is |
41 | // not yet supported. |
42 | void parseDeviceSpaceStroke(const SkPath&, const SkPoint* deviceSpacePts, const SkStrokeRec&, |
43 | float strokeDevWidth, GrScissorTest, |
44 | const SkIRect& clippedDevIBounds, |
45 | const SkIVector& devToAtlasOffset); |
46 | |
47 | using BatchID = int; |
48 | |
49 | // Compiles the outstanding parsed paths into a batch, and returns an ID that can be used to |
50 | // draw their strokes in the future. |
51 | BatchID closeCurrentBatch(); |
52 | |
53 | // Builds an internal GPU buffer and prepares for calls to drawStrokes(). Caller must close the |
54 | // current batch before calling this method, and cannot parse new paths afer. |
55 | bool prepareToDraw(GrOnFlushResourceProvider*); |
56 | |
57 | // Called after prepareToDraw(). Draws the given batch of path strokes. |
58 | void drawStrokes( |
59 | GrOpFlushState*, GrCCCoverageProcessor*, BatchID, const SkIRect& drawBounds) const; |
60 | |
61 | private: |
62 | static constexpr int kNumScissorModes = 2; |
63 | static constexpr BatchID kEmptyBatchID = -1; |
64 | using Verb = GrCCStrokeGeometry::Verb; |
65 | using InstanceTallies = GrCCStrokeGeometry::InstanceTallies; |
66 | using InstanceTalliesAllocator = GrTAllocator<InstanceTallies, 128>; |
67 | |
68 | // Every kBeginPath verb has a corresponding PathInfo entry. |
69 | struct PathInfo { |
70 | SkIVector fDevToAtlasOffset; |
71 | float fStrokeRadius; |
72 | GrScissorTest fScissorTest; |
73 | }; |
74 | |
75 | // Defines a sub-batch of stroke instances that have a scissor test and the same scissor rect. |
76 | // Start indices are deduced by looking at the previous ScissorSubBatch. |
77 | struct ScissorSubBatch { |
78 | ScissorSubBatch(InstanceTalliesAllocator* alloc, const InstanceTallies& startIndices, |
79 | const SkIRect& scissor) |
80 | : fEndInstances(&alloc->emplace_back(startIndices)), fScissor(scissor) {} |
81 | InstanceTallies* fEndInstances; |
82 | SkIRect fScissor; |
83 | }; |
84 | |
85 | // Defines a batch of stroke instances that can be drawn with drawStrokes(). Start indices are |
86 | // deduced by looking at the previous Batch in the list. |
87 | struct Batch { |
88 | Batch(InstanceTalliesAllocator* alloc, const InstanceTallies& startNonScissorIndices, |
89 | int startScissorSubBatch) |
90 | : fNonScissorEndInstances(&alloc->emplace_back(startNonScissorIndices)) |
91 | , fEndScissorSubBatch(startScissorSubBatch) {} |
92 | InstanceTallies* fNonScissorEndInstances; |
93 | int fEndScissorSubBatch; |
94 | }; |
95 | |
96 | class InstanceBufferBuilder; |
97 | |
98 | // Draws a batch of strokes by chopping them into "2^numSegmentsLog2" linear segments each. |
99 | void drawLog2Strokes(int numSegmentsLog2, GrOpFlushState*, const GrPrimitiveProcessor&, |
100 | const GrPipeline&, const Batch&, const InstanceTallies* startIndices[2], |
101 | int startScissorSubBatch, const SkIRect& drawBounds) const; |
102 | |
103 | template<int GrCCStrokeGeometry::InstanceTallies::* InstanceType> |
104 | void drawConnectingGeometry(GrOpFlushState*, const GrPipeline&, |
105 | const GrCCCoverageProcessor&, const Batch&, |
106 | const InstanceTallies* startIndices[2], int startScissorSubBatch, |
107 | const SkIRect& drawBounds) const; |
108 | |
109 | GrCCStrokeGeometry fGeometry; |
110 | SkSTArray<32, PathInfo> fPathInfos; |
111 | SkSTArray<32, Batch> fBatches; |
112 | SkSTArray<32, ScissorSubBatch> fScissorSubBatches; |
113 | int fMaxNumScissorSubBatches = 0; |
114 | bool fHasOpenBatch = false; |
115 | |
116 | const InstanceTallies fZeroTallies = InstanceTallies(); |
117 | InstanceTalliesAllocator fTalliesAllocator; |
118 | const InstanceTallies* fInstanceCounts[kNumScissorModes] = {&fZeroTallies, &fZeroTallies}; |
119 | |
120 | sk_sp<GrGpuBuffer> fInstanceBuffer; |
121 | // The indices stored in batches are relative to these base instances. |
122 | InstanceTallies fBaseInstances[kNumScissorModes]; |
123 | }; |
124 | |
125 | #endif |
126 | |