1 /* 2 * Copyright 2013 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 GrBezierEffect_DEFINED 9 #define GrBezierEffect_DEFINED 10 11 #include "GrDrawTargetCaps.h" 12 #include "GrProcessor.h" 13 #include "GrGeometryProcessor.h" 14 #include "GrInvariantOutput.h" 15 #include "GrTypesPriv.h" 16 17 /** 18 * Shader is based off of Loop-Blinn Quadratic GPU Rendering 19 * The output of this effect is a hairline edge for conics. 20 * Conics specified by implicit equation K^2 - LM. 21 * K, L, and M, are the first three values of the vertex attribute, 22 * the fourth value is not used. Distance is calculated using a 23 * first order approximation from the taylor series. 24 * Coverage for AA is max(0, 1-distance). 25 * 26 * Test were also run using a second order distance approximation. 27 * There were two versions of the second order approx. The first version 28 * is of roughly the form: 29 * f(q) = |f(p)| - ||f'(p)||*||q-p|| - ||f''(p)||*||q-p||^2. 30 * The second is similar: 31 * f(q) = |f(p)| + ||f'(p)||*||q-p|| + ||f''(p)||*||q-p||^2. 32 * The exact version of the equations can be found in the paper 33 * "Distance Approximations for Rasterizing Implicit Curves" by Gabriel Taubin 34 * 35 * In both versions we solve the quadratic for ||q-p||. 36 * Version 1: 37 * gFM is magnitude of first partials and gFM2 is magnitude of 2nd partials (as derived from paper) 38 * builder->fsCodeAppend("\t\tedgeAlpha = (sqrt(gFM*gFM+4.0*func*gF2M) - gFM)/(2.0*gF2M);\n"); 39 * Version 2: 40 * builder->fsCodeAppend("\t\tedgeAlpha = (gFM - sqrt(gFM*gFM-4.0*func*gF2M))/(2.0*gF2M);\n"); 41 * 42 * Also note that 2nd partials of k,l,m are zero 43 * 44 * When comparing the two second order approximations to the first order approximations, 45 * the following results were found. Version 1 tends to underestimate the distances, thus it 46 * basically increases all the error that we were already seeing in the first order 47 * approx. So this version is not the one to use. Version 2 has the opposite effect 48 * and tends to overestimate the distances. This is much closer to what we are 49 * looking for. It is able to render ellipses (even thin ones) without the need to chop. 50 * However, it can not handle thin hyperbolas well and thus would still rely on 51 * chopping to tighten the clipping. Another side effect of the overestimating is 52 * that the curves become much thinner and "ropey". If all that was ever rendered 53 * were "not too thin" curves and ellipses then 2nd order may have an advantage since 54 * only one geometry would need to be rendered. However no benches were run comparing 55 * chopped first order and non chopped 2nd order. 56 */ 57 class GrGLConicEffect; 58 59 class GrConicEffect : public GrGeometryProcessor { 60 public: 61 static GrGeometryProcessor* Create(GrColor color, 62 const SkMatrix& viewMatrix, 63 const GrPrimitiveEdgeType edgeType, 64 const GrDrawTargetCaps& caps, 65 const SkMatrix& localMatrix, 66 uint8_t coverage = 0xff) { 67 switch (edgeType) { 68 case kFillAA_GrProcessorEdgeType: 69 if (!caps.shaderCaps()->shaderDerivativeSupport()) { 70 return NULL; 71 } 72 return SkNEW_ARGS(GrConicEffect, (color, viewMatrix, coverage, 73 kFillAA_GrProcessorEdgeType, 74 localMatrix)); 75 case kHairlineAA_GrProcessorEdgeType: 76 if (!caps.shaderCaps()->shaderDerivativeSupport()) { 77 return NULL; 78 } 79 return SkNEW_ARGS(GrConicEffect, (color, viewMatrix, coverage, 80 kHairlineAA_GrProcessorEdgeType, 81 localMatrix)); 82 case kFillBW_GrProcessorEdgeType: 83 return SkNEW_ARGS(GrConicEffect, (color, viewMatrix, coverage, 84 kFillBW_GrProcessorEdgeType, 85 localMatrix)); 86 default: 87 return NULL; 88 } 89 } 90 91 virtual ~GrConicEffect(); 92 name()93 const char* name() const override { return "Conic"; } 94 inPosition()95 inline const Attribute* inPosition() const { return fInPosition; } inConicCoeffs()96 inline const Attribute* inConicCoeffs() const { return fInConicCoeffs; } isAntiAliased()97 inline bool isAntiAliased() const { return GrProcessorEdgeTypeIsAA(fEdgeType); } isFilled()98 inline bool isFilled() const { return GrProcessorEdgeTypeIsFill(fEdgeType); } getEdgeType()99 inline GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; } color()100 GrColor color() const { return fColor; } viewMatrix()101 const SkMatrix& viewMatrix() const { return fViewMatrix; } localMatrix()102 const SkMatrix& localMatrix() const { return fLocalMatrix; } 103 104 virtual void getGLProcessorKey(const GrBatchTracker& bt, 105 const GrGLSLCaps& caps, 106 GrProcessorKeyBuilder* b) const override; 107 108 virtual GrGLPrimitiveProcessor* createGLInstance(const GrBatchTracker& bt, 109 const GrGLSLCaps&) const override; 110 111 void initBatchTracker(GrBatchTracker*, const GrPipelineInfo&) const override; 112 113 private: 114 GrConicEffect(GrColor, const SkMatrix& viewMatrix, uint8_t coverage, GrPrimitiveEdgeType, 115 const SkMatrix& localMatrix); 116 117 GrColor fColor; 118 SkMatrix fViewMatrix; 119 SkMatrix fLocalMatrix; 120 uint8_t fCoverageScale; 121 GrPrimitiveEdgeType fEdgeType; 122 const Attribute* fInPosition; 123 const Attribute* fInConicCoeffs; 124 125 GR_DECLARE_GEOMETRY_PROCESSOR_TEST; 126 127 typedef GrGeometryProcessor INHERITED; 128 }; 129 130 /////////////////////////////////////////////////////////////////////////////// 131 /** 132 * The output of this effect is a hairline edge for quadratics. 133 * Quadratic specified by 0=u^2-v canonical coords. u and v are the first 134 * two components of the vertex attribute. At the three control points that define 135 * the Quadratic, u, v have the values {0,0}, {1/2, 0}, and {1, 1} respectively. 136 * Coverage for AA is min(0, 1-distance). 3rd & 4th cimponent unused. 137 * Requires shader derivative instruction support. 138 */ 139 class GrGLQuadEffect; 140 141 class GrQuadEffect : public GrGeometryProcessor { 142 public: 143 static GrGeometryProcessor* Create(GrColor color, 144 const SkMatrix& viewMatrix, 145 const GrPrimitiveEdgeType edgeType, 146 const GrDrawTargetCaps& caps, 147 const SkMatrix& localMatrix, 148 uint8_t coverage = 0xff) { 149 switch (edgeType) { 150 case kFillAA_GrProcessorEdgeType: 151 if (!caps.shaderCaps()->shaderDerivativeSupport()) { 152 return NULL; 153 } 154 return SkNEW_ARGS(GrQuadEffect, (color, viewMatrix, coverage, 155 kFillAA_GrProcessorEdgeType, 156 localMatrix)); 157 case kHairlineAA_GrProcessorEdgeType: 158 if (!caps.shaderCaps()->shaderDerivativeSupport()) { 159 return NULL; 160 } 161 return SkNEW_ARGS(GrQuadEffect, (color, viewMatrix, coverage, 162 kHairlineAA_GrProcessorEdgeType, 163 localMatrix)); 164 case kFillBW_GrProcessorEdgeType: 165 return SkNEW_ARGS(GrQuadEffect, (color, viewMatrix, coverage, 166 kFillBW_GrProcessorEdgeType, 167 localMatrix)); 168 default: 169 return NULL; 170 } 171 } 172 173 virtual ~GrQuadEffect(); 174 name()175 const char* name() const override { return "Quad"; } 176 inPosition()177 inline const Attribute* inPosition() const { return fInPosition; } inHairQuadEdge()178 inline const Attribute* inHairQuadEdge() const { return fInHairQuadEdge; } isAntiAliased()179 inline bool isAntiAliased() const { return GrProcessorEdgeTypeIsAA(fEdgeType); } isFilled()180 inline bool isFilled() const { return GrProcessorEdgeTypeIsFill(fEdgeType); } getEdgeType()181 inline GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; } color()182 GrColor color() const { return fColor; } viewMatrix()183 const SkMatrix& viewMatrix() const { return fViewMatrix; } localMatrix()184 const SkMatrix& localMatrix() const { return fLocalMatrix; } 185 186 virtual void getGLProcessorKey(const GrBatchTracker& bt, 187 const GrGLSLCaps& caps, 188 GrProcessorKeyBuilder* b) const override; 189 190 virtual GrGLPrimitiveProcessor* createGLInstance(const GrBatchTracker& bt, 191 const GrGLSLCaps&) const override; 192 193 void initBatchTracker(GrBatchTracker*, const GrPipelineInfo&) const override; 194 195 private: 196 GrQuadEffect(GrColor, const SkMatrix& viewMatrix, uint8_t coverage, GrPrimitiveEdgeType, 197 const SkMatrix& localMatrix); 198 199 GrColor fColor; 200 SkMatrix fViewMatrix; 201 SkMatrix fLocalMatrix; 202 uint8_t fCoverageScale; 203 GrPrimitiveEdgeType fEdgeType; 204 const Attribute* fInPosition; 205 const Attribute* fInHairQuadEdge; 206 207 GR_DECLARE_GEOMETRY_PROCESSOR_TEST; 208 209 typedef GrGeometryProcessor INHERITED; 210 }; 211 212 ////////////////////////////////////////////////////////////////////////////// 213 /** 214 * Shader is based off of "Resolution Independent Curve Rendering using 215 * Programmable Graphics Hardware" by Loop and Blinn. 216 * The output of this effect is a hairline edge for non rational cubics. 217 * Cubics are specified by implicit equation K^3 - LM. 218 * K, L, and M, are the first three values of the vertex attribute, 219 * the fourth value is not used. Distance is calculated using a 220 * first order approximation from the taylor series. 221 * Coverage for AA is max(0, 1-distance). 222 */ 223 class GrGLCubicEffect; 224 225 class GrCubicEffect : public GrGeometryProcessor { 226 public: Create(GrColor color,const SkMatrix & viewMatrix,const GrPrimitiveEdgeType edgeType,const GrDrawTargetCaps & caps)227 static GrGeometryProcessor* Create(GrColor color, 228 const SkMatrix& viewMatrix, 229 const GrPrimitiveEdgeType edgeType, 230 const GrDrawTargetCaps& caps) { 231 switch (edgeType) { 232 case kFillAA_GrProcessorEdgeType: 233 if (!caps.shaderCaps()->shaderDerivativeSupport()) { 234 return NULL; 235 } 236 return SkNEW_ARGS(GrCubicEffect, (color, viewMatrix, kFillAA_GrProcessorEdgeType)); 237 case kHairlineAA_GrProcessorEdgeType: 238 if (!caps.shaderCaps()->shaderDerivativeSupport()) { 239 return NULL; 240 } 241 return SkNEW_ARGS(GrCubicEffect, (color, viewMatrix, 242 kHairlineAA_GrProcessorEdgeType)); 243 case kFillBW_GrProcessorEdgeType: 244 return SkNEW_ARGS(GrCubicEffect, (color, viewMatrix, 245 kFillBW_GrProcessorEdgeType)); 246 default: 247 return NULL; 248 } 249 } 250 251 virtual ~GrCubicEffect(); 252 name()253 const char* name() const override { return "Cubic"; } 254 inPosition()255 inline const Attribute* inPosition() const { return fInPosition; } inCubicCoeffs()256 inline const Attribute* inCubicCoeffs() const { return fInCubicCoeffs; } isAntiAliased()257 inline bool isAntiAliased() const { return GrProcessorEdgeTypeIsAA(fEdgeType); } isFilled()258 inline bool isFilled() const { return GrProcessorEdgeTypeIsFill(fEdgeType); } getEdgeType()259 inline GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; } color()260 GrColor color() const { return fColor; } viewMatrix()261 const SkMatrix& viewMatrix() const { return fViewMatrix; } 262 263 virtual void getGLProcessorKey(const GrBatchTracker& bt, 264 const GrGLSLCaps& caps, 265 GrProcessorKeyBuilder* b) const override; 266 267 virtual GrGLPrimitiveProcessor* createGLInstance(const GrBatchTracker& bt, 268 const GrGLSLCaps&) const override; 269 270 void initBatchTracker(GrBatchTracker*, const GrPipelineInfo&) const override; 271 272 private: 273 GrCubicEffect(GrColor, const SkMatrix& viewMatrix, GrPrimitiveEdgeType); 274 275 GrColor fColor; 276 SkMatrix fViewMatrix; 277 GrPrimitiveEdgeType fEdgeType; 278 const Attribute* fInPosition; 279 const Attribute* fInCubicCoeffs; 280 281 GR_DECLARE_GEOMETRY_PROCESSOR_TEST; 282 283 typedef GrGeometryProcessor INHERITED; 284 }; 285 286 #endif 287