1 /* 2 * Copyright 2019 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 GrPathTessellationShader_DEFINED 9 #define GrPathTessellationShader_DEFINED 10 11 #include "src/gpu/ganesh/tessellate/GrTessellationShader.h" 12 #include "src/gpu/tessellate/Tessellation.h" 13 14 // This is the base class for shaders in the GPU tessellator that fill paths. 15 class GrPathTessellationShader : public GrTessellationShader { 16 protected: 17 using PatchAttribs = skgpu::tess::PatchAttribs; 18 19 public: 20 // Draws a simple array of triangles. 21 static GrPathTessellationShader* MakeSimpleTriangleShader(SkArenaAlloc*, 22 const SkMatrix& viewMatrix, 23 const SkPMColor4f&); 24 25 // Uses instanced draws to triangulate curves with a "middle-out" topology. Middle-out draws a 26 // triangle with vertices at T=[0, 1/2, 1] and then recurses breadth first: 27 // 28 // depth=0: T=[0, 1/2, 1] 29 // depth=1: T=[0, 1/4, 2/4], T=[2/4, 3/4, 1] 30 // depth=2: T=[0, 1/8, 2/8], T=[2/8, 3/8, 4/8], T=[4/8, 5/8, 6/8], T=[6/8, 7/8, 1] 31 // ... 32 // 33 // The shader determines how many segments are required to render each individual curve 34 // smoothly, and emits empty triangles at any vertices whose sk_VertexIDs are higher than 35 // necessary. It is the caller's responsibility to draw enough vertices per instance for the 36 // most complex curve in the batch to render smoothly (i.e., NumTrianglesAtResolveLevel() * 3). 37 // 38 // If PatchAttribs::kFanPoint is set, an additional triangle is added, connecting the base of 39 // the curve to the fan point. 40 static GrPathTessellationShader* Make(const GrShaderCaps&, 41 SkArenaAlloc*, 42 const SkMatrix& viewMatrix, 43 const SkPMColor4f&, 44 PatchAttribs); 45 46 // Returns the stencil settings to use for a standard Redbook "stencil" pass. StencilPathSettings(GrFillRule fillRule)47 static const GrUserStencilSettings* StencilPathSettings(GrFillRule fillRule) { 48 // Increments clockwise triangles and decrements counterclockwise. Used for "winding" fill. 49 constexpr static GrUserStencilSettings kIncrDecrStencil( 50 GrUserStencilSettings::StaticInitSeparate< 51 0x0000, 0x0000, 52 GrUserStencilTest::kAlwaysIfInClip, GrUserStencilTest::kAlwaysIfInClip, 53 0xffff, 0xffff, 54 GrUserStencilOp::kIncWrap, GrUserStencilOp::kDecWrap, 55 GrUserStencilOp::kKeep, GrUserStencilOp::kKeep, 56 0xffff, 0xffff>()); 57 58 // Inverts the bottom stencil bit. Used for "even/odd" fill. 59 constexpr static GrUserStencilSettings kInvertStencil( 60 GrUserStencilSettings::StaticInit< 61 0x0000, 62 GrUserStencilTest::kAlwaysIfInClip, 63 0xffff, 64 GrUserStencilOp::kInvert, 65 GrUserStencilOp::kKeep, 66 0x0001>()); 67 68 return (fillRule == GrFillRule::kNonzero) ? &kIncrDecrStencil : &kInvertStencil; 69 } 70 71 // Returns the stencil settings to use for a standard Redbook "fill" pass. Allows non-zero 72 // stencil values to pass and write a color, and resets the stencil value back to zero; discards 73 // immediately on stencil values of zero. 74 static const GrUserStencilSettings* TestAndResetStencilSettings(bool isInverseFill = false) { 75 constexpr static GrUserStencilSettings kTestAndResetStencil( 76 GrUserStencilSettings::StaticInit< 77 0x0000, 78 // No need to check the clip because the previous stencil pass will have only 79 // written to samples already inside the clip. 80 GrUserStencilTest::kNotEqual, 81 0xffff, 82 GrUserStencilOp::kZero, 83 GrUserStencilOp::kKeep, 84 0xffff>()); 85 86 constexpr static GrUserStencilSettings kTestAndResetStencilInverted( 87 GrUserStencilSettings::StaticInit< 88 0x0000, 89 // No need to check the clip because the previous stencil pass will have only 90 // written to samples already inside the clip. 91 GrUserStencilTest::kEqual, 92 0xffff, 93 GrUserStencilOp::kKeep, 94 GrUserStencilOp::kZero, 95 0xffff>()); 96 97 return isInverseFill ? &kTestAndResetStencilInverted : &kTestAndResetStencil; 98 } 99 100 // Creates a pipeline that does not write to the color buffer. 101 static const GrPipeline* MakeStencilOnlyPipeline( 102 const ProgramArgs&, 103 GrAAType, 104 const GrAppliedHardClip&, 105 GrPipeline::InputFlags = GrPipeline::InputFlags::kNone); 106 107 protected: 108 constexpr static size_t kMiddleOutVertexStride = 2 * sizeof(float); 109 GrPathTessellationShader(ClassID classID,GrPrimitiveType primitiveType,const SkMatrix & viewMatrix,const SkPMColor4f & color,PatchAttribs attribs)110 GrPathTessellationShader(ClassID classID, 111 GrPrimitiveType primitiveType, 112 const SkMatrix& viewMatrix, 113 const SkPMColor4f& color, 114 PatchAttribs attribs) 115 : GrTessellationShader(classID, primitiveType, viewMatrix, color) 116 , fAttribs(attribs) { 117 } 118 119 // Default path tessellation shader implementation that manages a uniform matrix and color. 120 class Impl : public ProgramImpl { 121 public: 122 void onEmitCode(EmitArgs&, GrGPArgs*) final; 123 void setData(const GrGLSLProgramDataManager&, const GrShaderCaps&, 124 const GrGeometryProcessor&) override; 125 126 protected: 127 // float4x3 unpack_rational_cubic(float2 p0, float2 p1, float2 p2, float2 p3) { ... 128 // 129 // Evaluate our point of interest using numerically stable linear interpolations. We add our 130 // own "safe_mix" method to guarantee we get exactly "b" when T=1. The builtin mix() 131 // function seems spec'd to behave this way, but empirical results results have shown it 132 // does not always. 133 static const char* kEvalRationalCubicFn; 134 135 virtual void emitVertexCode(const GrShaderCaps&, 136 const GrPathTessellationShader&, 137 GrGLSLVertexBuilder*, 138 GrGLSLVaryingHandler*, 139 GrGPArgs*) = 0; 140 141 GrGLSLUniformHandler::UniformHandle fAffineMatrixUniform; 142 GrGLSLUniformHandler::UniformHandle fTranslateUniform; 143 GrGLSLUniformHandler::UniformHandle fColorUniform; 144 SkString fVaryingColorName; 145 }; 146 147 const PatchAttribs fAttribs; 148 }; 149 150 #endif 151