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 "include/private/gpu/ganesh/GrTypesPriv.h" 12 #include "src/base/SkArenaAlloc.h" 13 #include "src/gpu/ganesh/GrCaps.h" 14 #include "src/gpu/ganesh/GrGeometryProcessor.h" 15 #include "src/gpu/ganesh/GrProcessor.h" 16 #include "src/gpu/ganesh/GrProcessorUnitTest.h" 17 18 /** 19 * Shader is based off of Loop-Blinn Quadratic GPU Rendering 20 * The output of this effect is a hairline edge for conics. 21 * Conics specified by implicit equation K^2 - LM. 22 * K, L, and M, are the first three values of the vertex attribute, 23 * the fourth value is not used. Distance is calculated using a 24 * first order approximation from the taylor series. 25 * Coverage for AA is max(0, 1-distance). 26 * 27 * Test were also run using a second order distance approximation. 28 * There were two versions of the second order approx. The first version 29 * is of roughly the form: 30 * f(q) = |f(p)| - ||f'(p)||*||q-p|| - ||f''(p)||*||q-p||^2. 31 * The second is similar: 32 * f(q) = |f(p)| + ||f'(p)||*||q-p|| + ||f''(p)||*||q-p||^2. 33 * The exact version of the equations can be found in the paper 34 * "Distance Approximations for Rasterizing Implicit Curves" by Gabriel Taubin 35 * 36 * In both versions we solve the quadratic for ||q-p||. 37 * Version 1: 38 * gFM is magnitude of first partials and gFM2 is magnitude of 2nd partials (as derived from paper) 39 * builder->fsCodeAppend("\t\tedgeAlpha = (sqrt(gFM*gFM+4.0*func*gF2M) - gFM)/(2.0*gF2M);\n"); 40 * Version 2: 41 * builder->fsCodeAppend("\t\tedgeAlpha = (gFM - sqrt(gFM*gFM-4.0*func*gF2M))/(2.0*gF2M);\n"); 42 * 43 * Also note that 2nd partials of k,l,m are zero 44 * 45 * When comparing the two second order approximations to the first order approximations, 46 * the following results were found. Version 1 tends to underestimate the distances, thus it 47 * basically increases all the error that we were already seeing in the first order 48 * approx. So this version is not the one to use. Version 2 has the opposite effect 49 * and tends to overestimate the distances. This is much closer to what we are 50 * looking for. It is able to render ellipses (even thin ones) without the need to chop. 51 * However, it can not handle thin hyperbolas well and thus would still rely on 52 * chopping to tighten the clipping. Another side effect of the overestimating is 53 * that the curves become much thinner and "ropey". If all that was ever rendered 54 * were "not too thin" curves and ellipses then 2nd order may have an advantage since 55 * only one geometry would need to be rendered. However no benches were run comparing 56 * chopped first order and non chopped 2nd order. 57 */ 58 class GrGLConicEffect; 59 60 class GrConicEffect : public GrGeometryProcessor { 61 public: 62 static GrGeometryProcessor* Make(SkArenaAlloc* arena, 63 const SkPMColor4f& color, 64 const SkMatrix& viewMatrix, 65 const GrCaps& caps, 66 const SkMatrix& localMatrix, 67 bool usesLocalCoords, 68 uint8_t coverage = 0xff) { 69 if (!caps.shaderCaps()->fShaderDerivativeSupport) { 70 return nullptr; 71 } 72 73 return arena->make([&](void* ptr) { 74 return new (ptr) GrConicEffect(color, viewMatrix, coverage, localMatrix, 75 usesLocalCoords); 76 }); 77 } 78 79 ~GrConicEffect() override; 80 name()81 const char* name() const override { return "Conic"; } 82 83 void addToKey(const GrShaderCaps& caps, skgpu::KeyBuilder* b) const override; 84 85 std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const override; 86 87 private: 88 class Impl; 89 90 GrConicEffect(const SkPMColor4f&, const SkMatrix& viewMatrix, uint8_t coverage, 91 const SkMatrix& localMatrix, bool usesLocalCoords); 92 inPosition()93 inline const Attribute& inPosition() const { return kAttributes[0]; } inConicCoeffs()94 inline const Attribute& inConicCoeffs() const { return kAttributes[1]; } 95 96 SkPMColor4f fColor; 97 SkMatrix fViewMatrix; 98 SkMatrix fLocalMatrix; 99 bool fUsesLocalCoords; 100 uint8_t fCoverageScale; 101 inline static constexpr Attribute kAttributes[] = { 102 {"inPosition", kFloat2_GrVertexAttribType, SkSLType::kFloat2}, 103 {"inConicCoeffs", kFloat4_GrVertexAttribType, SkSLType::kHalf4} 104 }; 105 106 GR_DECLARE_GEOMETRY_PROCESSOR_TEST 107 108 using INHERITED = GrGeometryProcessor; 109 }; 110 111 /////////////////////////////////////////////////////////////////////////////// 112 /** 113 * The output of this effect is a hairline edge for quadratics. 114 * Quadratic specified by 0=u^2-v canonical coords. u and v are the first 115 * two components of the vertex attribute. At the three control points that define 116 * the Quadratic, u, v have the values {0,0}, {1/2, 0}, and {1, 1} respectively. 117 * Coverage for AA is min(0, 1-distance). 3rd & 4th cimponent unused. 118 * Requires shader derivative instruction support. 119 */ 120 class GrGLQuadEffect; 121 122 class GrQuadEffect : public GrGeometryProcessor { 123 public: 124 static GrGeometryProcessor* Make(SkArenaAlloc* arena, 125 const SkPMColor4f& color, 126 const SkMatrix& viewMatrix, 127 const GrCaps& caps, 128 const SkMatrix& localMatrix, 129 bool usesLocalCoords, 130 uint8_t coverage = 0xff) { 131 if (!caps.shaderCaps()->fShaderDerivativeSupport) { 132 return nullptr; 133 } 134 135 return arena->make([&](void* ptr) { 136 return new (ptr) GrQuadEffect(color, viewMatrix, coverage, localMatrix, 137 usesLocalCoords); 138 }); 139 } 140 141 ~GrQuadEffect() override; 142 name()143 const char* name() const override { return "Quad"; } 144 145 void addToKey(const GrShaderCaps& caps, skgpu::KeyBuilder* b) const override; 146 147 std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const override; 148 149 private: 150 class Impl; 151 152 GrQuadEffect(const SkPMColor4f&, const SkMatrix& viewMatrix, uint8_t coverage, 153 const SkMatrix& localMatrix, bool usesLocalCoords); 154 inPosition()155 inline const Attribute& inPosition() const { return kAttributes[0]; } inHairQuadEdge()156 inline const Attribute& inHairQuadEdge() const { return kAttributes[1]; } 157 158 SkPMColor4f fColor; 159 SkMatrix fViewMatrix; 160 SkMatrix fLocalMatrix; 161 bool fUsesLocalCoords; 162 uint8_t fCoverageScale; 163 164 inline static constexpr Attribute kAttributes[] = { 165 {"inPosition", kFloat2_GrVertexAttribType, SkSLType::kFloat2}, 166 {"inHairQuadEdge", kFloat4_GrVertexAttribType, SkSLType::kHalf4} 167 }; 168 169 GR_DECLARE_GEOMETRY_PROCESSOR_TEST 170 171 using INHERITED = GrGeometryProcessor; 172 }; 173 174 #endif 175