1/*
2 * Copyright 2020 Google LLC.
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 GrStrokeTessellateShader_DEFINED
9#define GrStrokeTessellateShader_DEFINED
10
11#include "src/gpu/tessellate/GrPathShader.h"
12
13#include "src/gpu/tessellate/GrTessellationPathRenderer.h"
14
15class GrGLSLUniformHandler;
16
17// Tessellates a batch of stroke patches directly to the canvas. A patch is either a "cubic"
18// (single stroked bezier curve with butt caps) or a "join". A patch is defined by 5 points as
19// follows:
20//
21// P0..P3 : Represent the cubic control points.
22// (P4.x == 0) : The patch is a cubic and the shader decides how many linear segments to produce.
23// (P4.x < 0) : The patch is still a cubic, but will be linearized into exactly |P4.x| segments.
24// (P4.x == 1) : The patch is an outer bevel join.
25// (P4.x == 2) : The patch is an outer miter join.
26// (NOTE: If miterLimitOrZero == 0, then miter join patches are illegal.)
27// (P4.x == 3) : The patch is an outer round join.
28// (P4.x == 4) : The patch is an inner and outer round join.
29// P4.y : Represents the stroke radius.
30//
31// If a patch is a join, P0 must equal P3, P1 must equal the control point coming into the junction,
32// and P2 must equal the control point going out. It's imperative that a junction's control points
33// match the control points of their neighbor cubics exactly, or the rasterization might not be
34// water tight. (Also note that if P1==P0 or P2==P3, the junction needs to be given its neighbor's
35// opposite cubic control point.)
36//
37// To use this shader, construct a GrProgramInfo with a primitiveType of "kPatches" and a
38// tessellationPatchVertexCount of 5.
39class GrStrokeTessellateShader : public GrPathShader {
40public:
41 constexpr static float kBevelJoinType = -1;
42 constexpr static float kMiterJoinType = -2;
43 constexpr static float kRoundJoinType = -3;
44 constexpr static float kInternalRoundJoinType = -4;
45
46 constexpr static int kNumVerticesPerPatch = 5;
47
48 // 'skewMatrix' is applied to the post-tessellation triangles. It cannot expand the geometry in
49 // any direction. For now, patches should be pre-scaled on CPU by the view matrix's maxScale,
50 // which leaves 'skewMatrix' as the original view matrix divided by maxScale.
51 //
52 // If 'miterLimitOrZero' is zero, then the patches being drawn cannot include any miter joins.
53 // If a stroke uses miter joins with a miter limit of zero, then they need to be pre-converted
54 // to bevel joins.
55 GrStrokeTessellateShader(const SkMatrix& skewMatrix, SkPMColor4f color, float miterLimitOrZero)
56 : GrPathShader(kTessellate_GrStrokeTessellateShader_ClassID, skewMatrix,
57 GrPrimitiveType::kPatches, kNumVerticesPerPatch)
58 , fColor(color)
59 , fMiterLimitOrZero(miterLimitOrZero) {
60 // Since the skewMatrix is applied after tessellation, it cannot expand the geometry in any
61 // direction. (The caller can create a skewMatrix by dividing their viewMatrix by its
62 // maxScale and then pre-multiplying their control points by the same maxScale.)
63 SkASSERT(skewMatrix.getMaxScale() < 1 + SK_ScalarNearlyZero);
64 constexpr static Attribute kInputPointAttrib{"inputPoint", kFloat2_GrVertexAttribType,
65 kFloat2_GrSLType};
66 this->setVertexAttributes(&kInputPointAttrib, 1);
67 }
68
69private:
70 const char* name() const override { return "GrStrokeTessellateShader"; }
71 void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
72 b->add32(this->viewMatrix().isIdentity());
73 }
74 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const final;
75
76 SkString getTessControlShaderGLSL(const GrGLSLPrimitiveProcessor*,
77 const char* versionAndExtensionDecls,
78 const GrGLSLUniformHandler&,
79 const GrShaderCaps&) const override;
80 SkString getTessEvaluationShaderGLSL(const GrGLSLPrimitiveProcessor*,
81 const char* versionAndExtensionDecls,
82 const GrGLSLUniformHandler&,
83 const GrShaderCaps&) const override;
84
85 const SkPMColor4f fColor;
86 const float fMiterLimitOrZero; // Zero if there will not be any miter join patches.
87
88 class Impl;
89};
90
91#endif
92