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 GrStencilPathShader_DEFINED 9 #define GrStencilPathShader_DEFINED 10 11 #include "src/gpu/GrDrawIndirectCommand.h" 12 #include "src/gpu/tessellate/GrPathShader.h" 13 #include "src/gpu/tessellate/GrTessellationPathRenderer.h" 14 15 // This is the base class for shaders that stencil path elements, namely, triangles, standalone 16 // cubics, and wedges. 17 class GrStencilPathShader : public GrPathShader { 18 public: 19 GrStencilPathShader(ClassID classID, const SkMatrix& viewMatrix, GrPrimitiveType primitiveType, 20 int tessellationPatchVertexCount = 0) GrPathShader(classID,viewMatrix,primitiveType,tessellationPatchVertexCount)21 : GrPathShader(classID, viewMatrix, primitiveType, tessellationPatchVertexCount) { 22 } 23 24 // Creates a pipeline that can be used for normal Redbook stencil draws. MakeStencilPassPipeline(const GrPathShader::ProgramArgs & args,GrAAType aaType,GrTessellationPathRenderer::OpFlags opFlags,const GrAppliedHardClip & hardClip)25 static const GrPipeline* MakeStencilPassPipeline(const GrPathShader::ProgramArgs& args, 26 GrAAType aaType, 27 GrTessellationPathRenderer::OpFlags opFlags, 28 const GrAppliedHardClip& hardClip) { 29 using OpFlags = GrTessellationPathRenderer::OpFlags; 30 GrPipeline::InitArgs pipelineArgs; 31 if (aaType != GrAAType::kNone) { 32 pipelineArgs.fInputFlags |= GrPipeline::InputFlags::kHWAntialias; 33 } 34 if (args.fCaps->wireframeSupport() && (opFlags & OpFlags::kWireframe)) { 35 pipelineArgs.fInputFlags |= GrPipeline::InputFlags::kWireframe; 36 } 37 pipelineArgs.fCaps = args.fCaps; 38 return args.fArena->make<GrPipeline>(pipelineArgs, 39 GrDisableColorXPFactory::MakeXferProcessor(), 40 hardClip); 41 } 42 43 // Returns the stencil settings to use for a standard Redbook stencil draw. StencilPassSettings(SkPathFillType fillType)44 static const GrUserStencilSettings* StencilPassSettings(SkPathFillType fillType) { 45 // Increments clockwise triangles and decrements counterclockwise. Used for "winding" fill. 46 constexpr static GrUserStencilSettings kIncrDecrStencil( 47 GrUserStencilSettings::StaticInitSeparate< 48 0x0000, 0x0000, 49 GrUserStencilTest::kAlwaysIfInClip, GrUserStencilTest::kAlwaysIfInClip, 50 0xffff, 0xffff, 51 GrUserStencilOp::kIncWrap, GrUserStencilOp::kDecWrap, 52 GrUserStencilOp::kKeep, GrUserStencilOp::kKeep, 53 0xffff, 0xffff>()); 54 55 // Inverts the bottom stencil bit. Used for "even/odd" fill. 56 constexpr static GrUserStencilSettings kInvertStencil( 57 GrUserStencilSettings::StaticInit< 58 0x0000, 59 GrUserStencilTest::kAlwaysIfInClip, 60 0xffff, 61 GrUserStencilOp::kInvert, 62 GrUserStencilOp::kKeep, 63 0x0001>()); 64 65 SkASSERT(fillType == SkPathFillType::kWinding || fillType == SkPathFillType::kEvenOdd); 66 return (fillType == SkPathFillType::kWinding) ? &kIncrDecrStencil : &kInvertStencil; 67 } 68 69 template<typename ShaderType> MakeStencilProgram(const ProgramArgs & args,const SkMatrix & viewMatrix,const GrPipeline * pipeline,const GrUserStencilSettings * stencil)70 static GrProgramInfo* MakeStencilProgram(const ProgramArgs& args, const SkMatrix& viewMatrix, 71 const GrPipeline* pipeline, 72 const GrUserStencilSettings* stencil) { 73 const auto* shader = args.fArena->make<ShaderType>(viewMatrix); 74 return GrPathShader::MakeProgram(args, shader, pipeline, stencil); 75 } 76 77 template<typename ShaderType> MakeStencilProgram(const ProgramArgs & args,const SkMatrix & viewMatrix,const GrPipeline * pipeline,const SkPathFillType fillType)78 static GrProgramInfo* MakeStencilProgram(const ProgramArgs& args, const SkMatrix& viewMatrix, 79 const GrPipeline* pipeline, 80 const SkPathFillType fillType) { 81 return MakeStencilProgram<ShaderType>(args, viewMatrix, pipeline, 82 StencilPassSettings(fillType)); 83 } 84 85 protected: 86 constexpr static Attribute kSinglePointAttrib{"inputPoint", kFloat2_GrVertexAttribType, 87 kFloat2_GrSLType}; getGLSLProcessorKey(const GrShaderCaps &,GrProcessorKeyBuilder * b)88 void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override { 89 b->add32(this->viewMatrix().isIdentity()); 90 } 91 GrGLSLGeometryProcessor* createGLSLInstance(const GrShaderCaps&) const override; 92 93 class Impl; 94 }; 95 96 // Draws simple triangles to the stencil buffer. 97 class GrStencilTriangleShader : public GrStencilPathShader { 98 public: GrStencilTriangleShader(const SkMatrix & viewMatrix)99 GrStencilTriangleShader(const SkMatrix& viewMatrix) : GrStencilPathShader( 100 kTessellate_GrStencilTriangleShader_ClassID, viewMatrix, GrPrimitiveType::kTriangles) { 101 this->setVertexAttributes(&kSinglePointAttrib, 1); 102 } name()103 const char* name() const override { return "tessellate_GrStencilTriangleShader"; } 104 }; 105 106 // Uses GPU tessellation shaders to linearize, triangulate, and render standalone closed cubics. 107 // TODO: Eventually we want to use rational cubic wedges in order to support perspective and conics. 108 class GrCubicTessellateShader : public GrStencilPathShader { 109 public: GrCubicTessellateShader(const SkMatrix & viewMatrix)110 GrCubicTessellateShader(const SkMatrix& viewMatrix) : GrStencilPathShader( 111 kTessellate_GrCubicTessellateShader_ClassID, viewMatrix, GrPrimitiveType::kPatches, 4) { 112 this->setVertexAttributes(&kSinglePointAttrib, 1); 113 } name()114 const char* name() const override { return "tessellate_GrCubicTessellateShader"; } 115 116 private: 117 GrGLSLGeometryProcessor* createGLSLInstance(const GrShaderCaps&) const override; 118 }; 119 120 // Uses GPU tessellation shaders to linearize, triangulate, and render cubic "wedge" patches. A 121 // wedge is a 5-point patch consisting of 4 cubic control points, plus an anchor point fanning from 122 // the center of the curve's resident contour. 123 // TODO: Eventually we want to use rational cubic wedges in order to support perspective and conics. 124 class GrWedgeTessellateShader : public GrStencilPathShader { 125 public: GrWedgeTessellateShader(const SkMatrix & viewMatrix)126 GrWedgeTessellateShader(const SkMatrix& viewMatrix) : GrStencilPathShader( 127 kTessellate_GrWedgeTessellateShader_ClassID, viewMatrix, GrPrimitiveType::kPatches, 5) { 128 this->setVertexAttributes(&kSinglePointAttrib, 1); 129 } name()130 const char* name() const override { return "tessellate_GrWedgeTessellateShader"; } 131 132 private: 133 GrGLSLGeometryProcessor* createGLSLInstance(const GrShaderCaps&) const override; 134 }; 135 136 // Uses indirect (instanced) draws to triangulate standalone closed cubics with a "middle-out" 137 // topology. The caller must compute each cubic's resolveLevel on the CPU (i.e., the log2 number of 138 // line segments it will be divided into; see GrWangsFormula::cubic_log2/quadratic_log2), and then 139 // sort the instance buffer by resolveLevel for efficient batching of indirect draws. 140 class GrMiddleOutCubicShader : public GrStencilPathShader { 141 public: 142 // How many vertices do we need to draw in order to triangulate a cubic with 2^resolveLevel 143 // line segments? NumVerticesAtResolveLevel(int resolveLevel)144 constexpr static int NumVerticesAtResolveLevel(int resolveLevel) { 145 // resolveLevel=0 -> 0 line segments -> 0 triangles -> 0 vertices 146 // resolveLevel=1 -> 2 line segments -> 1 triangle -> 3 vertices 147 // resolveLevel=2 -> 4 line segments -> 3 triangles -> 9 vertices 148 // resolveLevel=3 -> 8 line segments -> 7 triangles -> 21 vertices 149 // ... 150 return ((1 << resolveLevel) - 1) * 3; 151 } 152 153 // Configures an indirect draw to render cubic instances with 2^resolveLevel evenly-spaced (in 154 // the parametric sense) line segments. WriteDrawCubicsIndirectCmd(GrDrawIndexedIndirectWriter * indirectWriter,int resolveLevel,uint32_t instanceCount,uint32_t baseInstance)155 static void WriteDrawCubicsIndirectCmd(GrDrawIndexedIndirectWriter* indirectWriter, 156 int resolveLevel, uint32_t instanceCount, 157 uint32_t baseInstance) { 158 SkASSERT(resolveLevel > 0 && resolveLevel <= GrTessellationPathRenderer::kMaxResolveLevel); 159 // Starting at baseIndex=3, the index buffer triangulates a cubic with 2^kMaxResolveLevel 160 // line segments. Each index value corresponds to a parametric T value on the curve. Since 161 // the triangles are arranged in "middle-out" order, we can conveniently control the 162 // resolveLevel by changing only the indexCount. 163 uint32_t indexCount = NumVerticesAtResolveLevel(resolveLevel); 164 indirectWriter->writeIndexed(indexCount, 3, instanceCount, baseInstance, 0); 165 } 166 167 // For performance reasons we can often express triangles as an indirect cubic draw and sneak 168 // them in alongside the other indirect draws. This method configures an indirect draw to emit 169 // the triangle [P0, P1, P2] from a 4-point instance. WriteDrawTrianglesIndirectCmd(GrDrawIndexedIndirectWriter * indirectWriter,uint32_t instanceCount,uint32_t baseInstance)170 static void WriteDrawTrianglesIndirectCmd(GrDrawIndexedIndirectWriter* indirectWriter, 171 uint32_t instanceCount, uint32_t baseInstance) { 172 // Indices 0,1,2 have special index values that emit points P0, P1, and P2 respectively. 173 indirectWriter->writeIndexed(3, 0, instanceCount, baseInstance, 0); 174 } 175 176 // Returns the index buffer that should be bound when drawing with this shader. 177 // (Our vertex shader uses raw index values directly, so there is no vertex buffer.) 178 static sk_sp<const GrGpuBuffer> FindOrMakeMiddleOutIndexBuffer(GrResourceProvider*); 179 GrMiddleOutCubicShader(const SkMatrix & viewMatrix)180 GrMiddleOutCubicShader(const SkMatrix& viewMatrix) 181 : GrStencilPathShader(kTessellate_GrMiddleOutCubicShader_ClassID, viewMatrix, 182 GrPrimitiveType::kTriangles) { 183 constexpr static Attribute kInputPtsAttribs[] = { 184 {"inputPoints_0_1", kFloat4_GrVertexAttribType, kFloat4_GrSLType}, 185 {"inputPoints_2_3", kFloat4_GrVertexAttribType, kFloat4_GrSLType}}; 186 this->setInstanceAttributes(kInputPtsAttribs, 2); 187 } 188 name()189 const char* name() const override { return "tessellate_GrMiddleOutCubicShader"; } 190 191 private: 192 GrGLSLGeometryProcessor* createGLSLInstance(const GrShaderCaps&) const override; 193 194 class Impl; 195 }; 196 197 #endif 198