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