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