1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2014 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "src/core/SkPathPriv.h" 9cb93a386Sopenharmony_ci#include "src/gpu/effects/GrConvexPolyEffect.h" 10cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" 11cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLProgramDataManager.h" 12cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLUniformHandler.h" 13cb93a386Sopenharmony_ci#include "src/sksl/dsl/priv/DSLFPs.h" 14cb93a386Sopenharmony_ci 15cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////// 16cb93a386Sopenharmony_ci 17cb93a386Sopenharmony_ciGrFPResult GrConvexPolyEffect::Make(std::unique_ptr<GrFragmentProcessor> inputFP, 18cb93a386Sopenharmony_ci GrClipEdgeType type, const SkPath& path) { 19cb93a386Sopenharmony_ci if (path.getSegmentMasks() != SkPath::kLine_SegmentMask || !path.isConvex()) { 20cb93a386Sopenharmony_ci return GrFPFailure(std::move(inputFP)); 21cb93a386Sopenharmony_ci } 22cb93a386Sopenharmony_ci 23cb93a386Sopenharmony_ci SkPathFirstDirection dir = SkPathPriv::ComputeFirstDirection(path); 24cb93a386Sopenharmony_ci // The only way this should fail is if the clip is effectively a infinitely thin line. In that 25cb93a386Sopenharmony_ci // case nothing is inside the clip. It'd be nice to detect this at a higher level and either 26cb93a386Sopenharmony_ci // skip the draw or omit the clip element. 27cb93a386Sopenharmony_ci if (dir == SkPathFirstDirection::kUnknown) { 28cb93a386Sopenharmony_ci if (GrClipEdgeTypeIsInverseFill(type)) { 29cb93a386Sopenharmony_ci return GrFPSuccess( 30cb93a386Sopenharmony_ci GrFragmentProcessor::ModulateRGBA(std::move(inputFP), SK_PMColor4fWHITE)); 31cb93a386Sopenharmony_ci } 32cb93a386Sopenharmony_ci // This could use ConstColor instead of ModulateRGBA but it would trigger a debug print 33cb93a386Sopenharmony_ci // about a coverage processor not being compatible with the alpha-as-coverage optimization. 34cb93a386Sopenharmony_ci // We don't really care about this unlikely case so we just use ModulateRGBA to suppress 35cb93a386Sopenharmony_ci // the print. 36cb93a386Sopenharmony_ci return GrFPSuccess( 37cb93a386Sopenharmony_ci GrFragmentProcessor::ModulateRGBA(std::move(inputFP), SK_PMColor4fTRANSPARENT)); 38cb93a386Sopenharmony_ci } 39cb93a386Sopenharmony_ci 40cb93a386Sopenharmony_ci SkScalar edges[3 * kMaxEdges]; 41cb93a386Sopenharmony_ci SkPoint pts[4]; 42cb93a386Sopenharmony_ci SkPath::Verb verb; 43cb93a386Sopenharmony_ci SkPath::Iter iter(path, true); 44cb93a386Sopenharmony_ci 45cb93a386Sopenharmony_ci // SkPath considers itself convex so long as there is a convex contour within it, 46cb93a386Sopenharmony_ci // regardless of any degenerate contours such as a string of moveTos before it. 47cb93a386Sopenharmony_ci // Iterate here to consume any degenerate contours and only process the points 48cb93a386Sopenharmony_ci // on the actual convex contour. 49cb93a386Sopenharmony_ci int n = 0; 50cb93a386Sopenharmony_ci while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 51cb93a386Sopenharmony_ci switch (verb) { 52cb93a386Sopenharmony_ci case SkPath::kMove_Verb: 53cb93a386Sopenharmony_ci case SkPath::kClose_Verb: 54cb93a386Sopenharmony_ci break; 55cb93a386Sopenharmony_ci case SkPath::kLine_Verb: { 56cb93a386Sopenharmony_ci if (n >= kMaxEdges) { 57cb93a386Sopenharmony_ci return GrFPFailure(std::move(inputFP)); 58cb93a386Sopenharmony_ci } 59cb93a386Sopenharmony_ci if (pts[0] != pts[1]) { 60cb93a386Sopenharmony_ci SkVector v = pts[1] - pts[0]; 61cb93a386Sopenharmony_ci v.normalize(); 62cb93a386Sopenharmony_ci if (SkPathFirstDirection::kCCW == dir) { 63cb93a386Sopenharmony_ci edges[3 * n] = v.fY; 64cb93a386Sopenharmony_ci edges[3 * n + 1] = -v.fX; 65cb93a386Sopenharmony_ci } else { 66cb93a386Sopenharmony_ci edges[3 * n] = -v.fY; 67cb93a386Sopenharmony_ci edges[3 * n + 1] = v.fX; 68cb93a386Sopenharmony_ci } 69cb93a386Sopenharmony_ci edges[3 * n + 2] = -(edges[3 * n] * pts[1].fX + edges[3 * n + 1] * pts[1].fY); 70cb93a386Sopenharmony_ci ++n; 71cb93a386Sopenharmony_ci } 72cb93a386Sopenharmony_ci break; 73cb93a386Sopenharmony_ci } 74cb93a386Sopenharmony_ci default: 75cb93a386Sopenharmony_ci // Non-linear segment so not a polygon. 76cb93a386Sopenharmony_ci return GrFPFailure(std::move(inputFP)); 77cb93a386Sopenharmony_ci } 78cb93a386Sopenharmony_ci } 79cb93a386Sopenharmony_ci 80cb93a386Sopenharmony_ci if (path.isInverseFillType()) { 81cb93a386Sopenharmony_ci type = GrInvertClipEdgeType(type); 82cb93a386Sopenharmony_ci } 83cb93a386Sopenharmony_ci return GrConvexPolyEffect::Make(std::move(inputFP), type, n, edges); 84cb93a386Sopenharmony_ci} 85cb93a386Sopenharmony_ci 86cb93a386Sopenharmony_ciGrConvexPolyEffect::~GrConvexPolyEffect() {} 87cb93a386Sopenharmony_ci 88cb93a386Sopenharmony_ciSkString GrConvexPolyEffect::getShaderDfxInfo() const 89cb93a386Sopenharmony_ci{ 90cb93a386Sopenharmony_ci SkString format; 91cb93a386Sopenharmony_ci format.printf("ShaderDfx_GrConvexPolyEffect_%d_%d", fEdgeCount, fEdgeType); 92cb93a386Sopenharmony_ci return format; 93cb93a386Sopenharmony_ci} 94cb93a386Sopenharmony_ci 95cb93a386Sopenharmony_civoid GrConvexPolyEffect::onAddToKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { 96cb93a386Sopenharmony_ci static_assert(kGrClipEdgeTypeCnt <= 8); 97cb93a386Sopenharmony_ci uint32_t key = (fEdgeCount << 3) | static_cast<int>(fEdgeType); 98cb93a386Sopenharmony_ci b->add32(key); 99cb93a386Sopenharmony_ci} 100cb93a386Sopenharmony_ci 101cb93a386Sopenharmony_cistd::unique_ptr<GrFragmentProcessor::ProgramImpl> GrConvexPolyEffect::onMakeProgramImpl() const { 102cb93a386Sopenharmony_ci class Impl : public ProgramImpl { 103cb93a386Sopenharmony_ci public: 104cb93a386Sopenharmony_ci void emitCode(EmitArgs& args) override { 105cb93a386Sopenharmony_ci const GrConvexPolyEffect& cpe = args.fFp.cast<GrConvexPolyEffect>(); 106cb93a386Sopenharmony_ci 107cb93a386Sopenharmony_ci using namespace SkSL::dsl; 108cb93a386Sopenharmony_ci StartFragmentProcessor(this, &args); 109cb93a386Sopenharmony_ci GlobalVar edgeArray(kUniform_Modifier, Array(kHalf3_Type, cpe.fEdgeCount), "edgeArray"); 110cb93a386Sopenharmony_ci Declare(edgeArray); 111cb93a386Sopenharmony_ci fEdgeUniform = VarUniformHandle(edgeArray); 112cb93a386Sopenharmony_ci Var alpha(kHalf_Type, "alpha", 1); 113cb93a386Sopenharmony_ci Declare(alpha); 114cb93a386Sopenharmony_ci Var edge(kHalf_Type, "edge"); 115cb93a386Sopenharmony_ci Declare(edge); 116cb93a386Sopenharmony_ci for (int i = 0; i < cpe.fEdgeCount; ++i) { 117cb93a386Sopenharmony_ci edge = Dot(edgeArray[i], Half3(Swizzle(sk_FragCoord(), X, Y, ONE))); 118cb93a386Sopenharmony_ci if (GrClipEdgeTypeIsAA(cpe.fEdgeType)) { 119cb93a386Sopenharmony_ci edge = Saturate(edge); 120cb93a386Sopenharmony_ci } else { 121cb93a386Sopenharmony_ci edge = Select(edge >= 0.5, 1.0, 0.0); 122cb93a386Sopenharmony_ci } 123cb93a386Sopenharmony_ci alpha *= edge; 124cb93a386Sopenharmony_ci } 125cb93a386Sopenharmony_ci 126cb93a386Sopenharmony_ci if (GrClipEdgeTypeIsInverseFill(cpe.fEdgeType)) { 127cb93a386Sopenharmony_ci alpha = 1.0 - alpha; 128cb93a386Sopenharmony_ci } 129cb93a386Sopenharmony_ci 130cb93a386Sopenharmony_ci Return(SampleChild(0) * alpha); 131cb93a386Sopenharmony_ci EndFragmentProcessor(); 132cb93a386Sopenharmony_ci } 133cb93a386Sopenharmony_ci 134cb93a386Sopenharmony_ci private: 135cb93a386Sopenharmony_ci void onSetData(const GrGLSLProgramDataManager& pdman, 136cb93a386Sopenharmony_ci const GrFragmentProcessor& fp) override { 137cb93a386Sopenharmony_ci const GrConvexPolyEffect& cpe = fp.cast<GrConvexPolyEffect>(); 138cb93a386Sopenharmony_ci size_t n = 3*cpe.fEdgeCount; 139cb93a386Sopenharmony_ci if (!std::equal(fPrevEdges.begin(), fPrevEdges.begin() + n, cpe.fEdges.begin())) { 140cb93a386Sopenharmony_ci pdman.set3fv(fEdgeUniform, cpe.fEdgeCount, cpe.fEdges.data()); 141cb93a386Sopenharmony_ci std::copy_n(cpe.fEdges.begin(), n, fPrevEdges.begin()); 142cb93a386Sopenharmony_ci } 143cb93a386Sopenharmony_ci } 144cb93a386Sopenharmony_ci 145cb93a386Sopenharmony_ci GrGLSLProgramDataManager::UniformHandle fEdgeUniform; 146cb93a386Sopenharmony_ci std::array<float, 3 * GrConvexPolyEffect::kMaxEdges> fPrevEdges = {SK_FloatNaN}; 147cb93a386Sopenharmony_ci }; 148cb93a386Sopenharmony_ci 149cb93a386Sopenharmony_ci return std::make_unique<Impl>(); 150cb93a386Sopenharmony_ci} 151cb93a386Sopenharmony_ci 152cb93a386Sopenharmony_ciGrConvexPolyEffect::GrConvexPolyEffect(std::unique_ptr<GrFragmentProcessor> inputFP, 153cb93a386Sopenharmony_ci GrClipEdgeType edgeType, 154cb93a386Sopenharmony_ci int n, 155cb93a386Sopenharmony_ci const float edges[]) 156cb93a386Sopenharmony_ci : INHERITED(kGrConvexPolyEffect_ClassID, 157cb93a386Sopenharmony_ci ProcessorOptimizationFlags(inputFP.get()) & 158cb93a386Sopenharmony_ci kCompatibleWithCoverageAsAlpha_OptimizationFlag) 159cb93a386Sopenharmony_ci , fEdgeType(edgeType) 160cb93a386Sopenharmony_ci , fEdgeCount(n) { 161cb93a386Sopenharmony_ci // Factory function should have already ensured this. 162cb93a386Sopenharmony_ci SkASSERT(n <= kMaxEdges); 163cb93a386Sopenharmony_ci std::copy_n(edges, 3*n, fEdges.begin()); 164cb93a386Sopenharmony_ci // Outset the edges by 0.5 so that a pixel with center on an edge is 50% covered in the AA case 165cb93a386Sopenharmony_ci // and 100% covered in the non-AA case. 166cb93a386Sopenharmony_ci for (int i = 0; i < n; ++i) { 167cb93a386Sopenharmony_ci fEdges[3 * i + 2] += SK_ScalarHalf; 168cb93a386Sopenharmony_ci } 169cb93a386Sopenharmony_ci 170cb93a386Sopenharmony_ci this->registerChild(std::move(inputFP)); 171cb93a386Sopenharmony_ci} 172cb93a386Sopenharmony_ci 173cb93a386Sopenharmony_ciGrConvexPolyEffect::GrConvexPolyEffect(const GrConvexPolyEffect& that) 174cb93a386Sopenharmony_ci : INHERITED(that) 175cb93a386Sopenharmony_ci , fEdgeType(that.fEdgeType) 176cb93a386Sopenharmony_ci , fEdgeCount(that.fEdgeCount) { 177cb93a386Sopenharmony_ci std::copy_n(that.fEdges.begin(), 3*that.fEdgeCount, fEdges.begin()); 178cb93a386Sopenharmony_ci} 179cb93a386Sopenharmony_ci 180cb93a386Sopenharmony_cistd::unique_ptr<GrFragmentProcessor> GrConvexPolyEffect::clone() const { 181cb93a386Sopenharmony_ci return std::unique_ptr<GrFragmentProcessor>(new GrConvexPolyEffect(*this)); 182cb93a386Sopenharmony_ci} 183cb93a386Sopenharmony_ci 184cb93a386Sopenharmony_cibool GrConvexPolyEffect::onIsEqual(const GrFragmentProcessor& other) const { 185cb93a386Sopenharmony_ci const GrConvexPolyEffect& cpe = other.cast<GrConvexPolyEffect>(); 186cb93a386Sopenharmony_ci int n = 3*cpe.fEdgeCount; 187cb93a386Sopenharmony_ci return cpe.fEdgeType == fEdgeType && 188cb93a386Sopenharmony_ci cpe.fEdgeCount == fEdgeCount && 189cb93a386Sopenharmony_ci std::equal(cpe.fEdges.begin(), cpe.fEdges.begin() + n, fEdges.begin()); 190cb93a386Sopenharmony_ci} 191cb93a386Sopenharmony_ci 192cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////// 193cb93a386Sopenharmony_ci 194cb93a386Sopenharmony_ciGR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrConvexPolyEffect); 195cb93a386Sopenharmony_ci 196cb93a386Sopenharmony_ci#if GR_TEST_UTILS 197cb93a386Sopenharmony_cistd::unique_ptr<GrFragmentProcessor> GrConvexPolyEffect::TestCreate(GrProcessorTestData* d) { 198cb93a386Sopenharmony_ci int count = d->fRandom->nextULessThan(kMaxEdges) + 1; 199cb93a386Sopenharmony_ci SkScalar edges[kMaxEdges * 3]; 200cb93a386Sopenharmony_ci for (int i = 0; i < 3 * count; ++i) { 201cb93a386Sopenharmony_ci edges[i] = d->fRandom->nextSScalar1(); 202cb93a386Sopenharmony_ci } 203cb93a386Sopenharmony_ci 204cb93a386Sopenharmony_ci bool success; 205cb93a386Sopenharmony_ci std::unique_ptr<GrFragmentProcessor> fp = d->inputFP(); 206cb93a386Sopenharmony_ci do { 207cb93a386Sopenharmony_ci GrClipEdgeType edgeType = 208cb93a386Sopenharmony_ci static_cast<GrClipEdgeType>(d->fRandom->nextULessThan(kGrClipEdgeTypeCnt)); 209cb93a386Sopenharmony_ci std::tie(success, fp) = GrConvexPolyEffect::Make(std::move(fp), edgeType, count, edges); 210cb93a386Sopenharmony_ci } while (!success); 211cb93a386Sopenharmony_ci return fp; 212cb93a386Sopenharmony_ci} 213cb93a386Sopenharmony_ci#endif 214