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 GrGrStrokePatchBuilder_DEFINED |
9 | #define GrGrStrokePatchBuilder_DEFINED |
10 | |
11 | #include "include/core/SkPaint.h" |
12 | #include "include/core/SkPoint.h" |
13 | #include "include/private/SkTArray.h" |
14 | #include "src/gpu/ops/GrMeshDrawOp.h" |
15 | #include "src/gpu/tessellate/GrStrokeTessellateShader.h" |
16 | |
17 | class SkStrokeRec; |
18 | |
19 | // This is an RAII class that expands strokes into tessellation patches for consumption by |
20 | // GrStrokeTessellateShader. The provided GrMeshDrawOp::Target must not be used externally for the |
21 | // entire lifetime of this class. e.g.: |
22 | // |
23 | // void onPrepare(GrOpFlushState* target) { |
24 | // GrStrokePatchBuilder builder(target, &fMyVertexChunks, scale, count); // Locks target. |
25 | // for (...) { |
26 | // builder.addPath(path, stroke); |
27 | // } |
28 | // } |
29 | // ... target can now be used normally again. |
30 | // ... fMyVertexChunks now contains chunks that can be drawn during onExecute. |
31 | class GrStrokePatchBuilder { |
32 | public: |
33 | // We generate vertex buffers in chunks. Normally there will only be one chunk, but in rare |
34 | // cases the first can run out of space if too many cubics needed to be subdivided. |
35 | struct VertexChunk { |
36 | sk_sp<const GrBuffer> fVertexBuffer; |
37 | int fVertexCount = 0; |
38 | int fBaseVertex; |
39 | }; |
40 | |
41 | // Stores raw pointers to the provided target and vertexChunkArray, which this class will use |
42 | // and push to as addPath is called. The caller is responsible to bind and draw each chunk that |
43 | // gets pushed to the array. (See GrStrokeTessellateShader.) |
44 | // |
45 | // All points are multiplied by 'matrixScale' before being written to the GPU buffer. |
46 | GrStrokePatchBuilder(GrMeshDrawOp::Target* target, SkTArray<VertexChunk>* vertexChunkArray, |
47 | float matrixScale, int totalCombinedVerbCnt) |
48 | : fTarget(target) |
49 | , fVertexChunkArray(vertexChunkArray) |
50 | , fMaxTessellationSegments(target->caps().shaderCaps()->maxTessellationSegments()) |
51 | , fMatrixScale(matrixScale) { |
52 | this->allocVertexChunk( |
53 | (totalCombinedVerbCnt * 3) * GrStrokeTessellateShader::kNumVerticesPerPatch); |
54 | } |
55 | |
56 | // "Releases" the target to be used externally again by putting back any unused pre-allocated |
57 | // vertices. |
58 | ~GrStrokePatchBuilder() { |
59 | fTarget->putBackVertices(fCurrChunkVertexCapacity - fVertexChunkArray->back().fVertexCount, |
60 | sizeof(SkPoint)); |
61 | } |
62 | |
63 | void addPath(const SkPath&, const SkStrokeRec&); |
64 | |
65 | private: |
66 | void allocVertexChunk(int minVertexAllocCount); |
67 | SkPoint* reservePatch(); |
68 | |
69 | // Join types are written as floats in P4.x. See GrStrokeTessellateShader for definitions. |
70 | void writeCubicSegment(float leftJoinType, const SkPoint pts[4], float overrideNumSegments = 0); |
71 | void writeCubicSegment(float leftJoinType, const Sk2f& p0, const Sk2f& p1, const Sk2f& p2, |
72 | const Sk2f& p3, float overrideNumSegments = 0) { |
73 | SkPoint pts[4]; |
74 | p0.store(&pts[0]); |
75 | p1.store(&pts[1]); |
76 | p2.store(&pts[2]); |
77 | p3.store(&pts[3]); |
78 | this->writeCubicSegment(leftJoinType, pts, overrideNumSegments); |
79 | } |
80 | void writeJoin(float joinType, const SkPoint& anchorPoint, const SkPoint& prevControlPoint, |
81 | const SkPoint& nextControlPoint); |
82 | void writeSquareCap(const SkPoint& endPoint, const SkPoint& controlPoint); |
83 | void writeCaps(); |
84 | |
85 | void beginPath(const SkStrokeRec&); |
86 | void moveTo(const SkPoint&); |
87 | void lineTo(const SkPoint& p0, const SkPoint& p1); |
88 | void quadraticTo(const SkPoint[3]); |
89 | void cubicTo(const SkPoint[4]); |
90 | void close(); |
91 | |
92 | void lineTo(float leftJoinType, const SkPoint& p0, const SkPoint& p1); |
93 | void quadraticTo(float leftJoinType, const SkPoint[3], float maxCurvatureT); |
94 | |
95 | static constexpr float kLeftMaxCurvatureNone = 1; |
96 | static constexpr float kRightMaxCurvatureNone = 0; |
97 | void cubicTo(float leftJoinType, const SkPoint[4], float maxCurvatureT, float leftMaxCurvatureT, |
98 | float rightMaxCurvatureT); |
99 | |
100 | // TEMPORARY: Rotates the current control point without changing the current position. |
101 | // This is used when we convert a curve to a lineTo, and that behavior will soon go away. |
102 | void rotateTo(float leftJoinType, const SkPoint& anchorPoint, const SkPoint& controlPoint); |
103 | |
104 | // These are raw pointers whose lifetimes are controlled outside this class. |
105 | GrMeshDrawOp::Target* const fTarget; |
106 | SkTArray<VertexChunk>* const fVertexChunkArray; |
107 | |
108 | const int fMaxTessellationSegments; |
109 | const float fMatrixScale; |
110 | |
111 | // Variables related to the vertex chunk that we are currently filling. |
112 | int fCurrChunkVertexCapacity; |
113 | int fCurrChunkMinVertexAllocCount; |
114 | SkPoint* fCurrChunkVertexData; |
115 | |
116 | // Variables related to the path that we are currently iterating. |
117 | float fCurrStrokeRadius; |
118 | float fCurrStrokeJoinType; // See GrStrokeTessellateShader for join type definitions . |
119 | SkPaint::Cap fCurrStrokeCapType; |
120 | // Any curvature on the original curve gets magnified on the outer edge of the stroke, |
121 | // proportional to how thick the stroke radius is. This field tells us the maximum curvature we |
122 | // can tolerate using the current stroke radius, before linearization artifacts begin to appear |
123 | // on the outer edge. |
124 | // |
125 | // (Curvature this strong is quite rare in practice, but when it does happen, we decompose the |
126 | // section with strong curvature into lineTo's with round joins in between.) |
127 | float fMaxCurvatureCosTheta; |
128 | |
129 | // Variables related to the specific contour that we are currently iterating. |
130 | bool fHasPreviousSegment = false; |
131 | SkPoint fCurrContourStartPoint; |
132 | SkPoint fCurrContourFirstControlPoint; |
133 | SkPoint fLastControlPoint; |
134 | SkPoint fCurrentPoint; |
135 | }; |
136 | |
137 | #endif |
138 | |