1 /* 2 * Copyright 2017 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 GrCCPRCubicProcessor_DEFINED 9 #define GrCCPRCubicProcessor_DEFINED 10 11 #include "ccpr/GrCCPRCoverageProcessor.h" 12 13 class GrGLSLGeometryBuilder; 14 15 /** 16 * This class renders the coverage of convex closed cubic segments using the techniques outlined in 17 * "Resolution Independent Curve Rendering using Programmable Graphics Hardware" by Charles Loop and 18 * Jim Blinn: 19 * 20 * https://www.microsoft.com/en-us/research/wp-content/uploads/2005/01/p1000-loop.pdf 21 * 22 * The caller is expected to chop cubics at the KLM roots (a.k.a. inflection points and loop 23 * intersection points, resulting in necessarily convex segments) before feeding them into this 24 * processor. 25 * 26 * The curves are rendered in two passes: 27 * 28 * Pass 1: Draw the (convex) bezier quadrilateral, inset by 1/2 pixel all around, and use the 29 * gradient-based AA technique outlined in the Loop/Blinn paper to compute coverage. 30 * 31 * Pass 2: Draw a border around the previous inset, up to the bezier quadrilatral's conservative 32 * raster hull, and compute coverage using pseudo MSAA. This pass is necessary because the 33 * gradient approach does not work near the L and M lines. 34 * 35 * FIXME: The pseudo MSAA border is slow and ugly. We should investigate an alternate solution of 36 * just approximating the curve with straight lines for short distances across the problem points 37 * instead. 38 */ 39 class GrCCPRCubicProcessor : public GrCCPRCoverageProcessor::PrimitiveProcessor { 40 public: 41 enum class Type { 42 kSerpentine, 43 kLoop 44 }; 45 GrCCPRCubicProcessor(Type type)46 GrCCPRCubicProcessor(Type type) 47 : INHERITED(CoverageType::kShader) 48 , fType(type) 49 , fInset(kVec3f_GrSLType) 50 , fTS(kFloat_GrSLType) 51 , fKLMMatrix("klm_matrix", kMat33f_GrSLType, GrShaderVar::kNonArray, 52 kHigh_GrSLPrecision) 53 , fKLMDerivatives("klm_derivatives", kVec2f_GrSLType, 3, kHigh_GrSLPrecision) {} 54 resetVaryings(GrGLSLVaryingHandler * varyingHandler)55 void resetVaryings(GrGLSLVaryingHandler* varyingHandler) override { 56 varyingHandler->addVarying("insets", &fInset, kHigh_GrSLPrecision); 57 varyingHandler->addVarying("ts", &fTS, kHigh_GrSLPrecision); 58 } 59 60 void onEmitVertexShader(const GrCCPRCoverageProcessor&, GrGLSLVertexBuilder*, 61 const TexelBufferHandle& pointsBuffer, const char* atlasOffset, 62 const char* rtAdjust, GrGPArgs*) const override; 63 void emitWind(GrGLSLGeometryBuilder*, const char* rtAdjust, const char* outputWind) const final; 64 void onEmitGeometryShader(GrGLSLGeometryBuilder*, const char* emitVertexFn, const char* wind, 65 const char* rtAdjust) const final; 66 67 protected: 68 virtual void emitCubicGeometry(GrGLSLGeometryBuilder*, const char* emitVertexFn, 69 const char* wind, const char* rtAdjust) const = 0; 70 71 const Type fType; 72 GrGLSLVertToGeo fInset; 73 GrGLSLVertToGeo fTS; 74 GrShaderVar fKLMMatrix; 75 GrShaderVar fKLMDerivatives; 76 77 typedef GrCCPRCoverageProcessor::PrimitiveProcessor INHERITED; 78 }; 79 80 class GrCCPRCubicInsetProcessor : public GrCCPRCubicProcessor { 81 public: GrCCPRCubicInsetProcessor(Type type)82 GrCCPRCubicInsetProcessor(Type type) 83 : INHERITED(type) 84 , fKLM(kVec3f_GrSLType) 85 , fGradMatrix(kMat22f_GrSLType) {} 86 resetVaryings(GrGLSLVaryingHandler * varyingHandler)87 void resetVaryings(GrGLSLVaryingHandler* varyingHandler) override { 88 this->INHERITED::resetVaryings(varyingHandler); 89 varyingHandler->addVarying("klm", &fKLM, kHigh_GrSLPrecision); 90 varyingHandler->addVarying("grad_matrix", &fGradMatrix, kHigh_GrSLPrecision); 91 } 92 93 void emitCubicGeometry(GrGLSLGeometryBuilder*, const char* emitVertexFn, 94 const char* wind, const char* rtAdjust) const override; 95 void emitPerVertexGeometryCode(SkString* fnBody, const char* position, const char* coverage, 96 const char* wind) const override; 97 void emitShaderCoverage(GrGLSLFragmentBuilder*, const char* outputCoverage) const override; 98 99 protected: 100 GrGLSLGeoToFrag fKLM; 101 GrGLSLGeoToFrag fGradMatrix; 102 103 typedef GrCCPRCubicProcessor INHERITED; 104 }; 105 106 class GrCCPRCubicBorderProcessor : public GrCCPRCubicProcessor { 107 public: GrCCPRCubicBorderProcessor(Type type)108 GrCCPRCubicBorderProcessor(Type type) 109 : INHERITED(type) 110 , fEdgeDistanceEquation("edge_distance_equation", kVec3f_GrSLType, 111 GrShaderVar::kNonArray, kHigh_GrSLPrecision) 112 , fEdgeDistanceDerivatives("edge_distance_derivatives", kVec2f_GrSLType, 113 GrShaderVar::kNonArray, kHigh_GrSLPrecision) 114 , fEdgeSpaceTransform("edge_space_transform", kVec4f_GrSLType, GrShaderVar::kNonArray, 115 kHigh_GrSLPrecision) 116 , fKLMD(kVec4f_GrSLType) 117 , fdKLMDdx(kVec4f_GrSLType) 118 , fdKLMDdy(kVec4f_GrSLType) 119 , fEdgeSpaceCoord(kVec2f_GrSLType) {} 120 resetVaryings(GrGLSLVaryingHandler * varyingHandler)121 void resetVaryings(GrGLSLVaryingHandler* varyingHandler) override { 122 this->INHERITED::resetVaryings(varyingHandler); 123 varyingHandler->addVarying("klmd", &fKLMD, kHigh_GrSLPrecision); 124 varyingHandler->addFlatVarying("dklmddx", &fdKLMDdx, kHigh_GrSLPrecision); 125 varyingHandler->addFlatVarying("dklmddy", &fdKLMDdy, kHigh_GrSLPrecision); 126 varyingHandler->addVarying("edge_space_coord", &fEdgeSpaceCoord, kHigh_GrSLPrecision); 127 } 128 129 void emitCubicGeometry(GrGLSLGeometryBuilder*, const char* emitVertexFn, 130 const char* wind, const char* rtAdjust) const override; 131 void emitPerVertexGeometryCode(SkString* fnBody, const char* position, const char* coverage, 132 const char* wind) const override; 133 void emitShaderCoverage(GrGLSLFragmentBuilder*, const char* outputCoverage) const override; 134 135 protected: 136 GrShaderVar fEdgeDistanceEquation; 137 GrShaderVar fEdgeDistanceDerivatives; 138 GrShaderVar fEdgeSpaceTransform; 139 GrGLSLGeoToFrag fKLMD; 140 GrGLSLGeoToFrag fdKLMDdx; 141 GrGLSLGeoToFrag fdKLMDdy; 142 GrGLSLGeoToFrag fEdgeSpaceCoord; 143 144 typedef GrCCPRCubicProcessor INHERITED; 145 }; 146 147 #endif 148