| 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 |  | 
|---|