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