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/gpu/effects/GrRRectEffect.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "src/core/SkRRectPriv.h" 11cb93a386Sopenharmony_ci#include "src/core/SkTLazy.h" 12cb93a386Sopenharmony_ci#include "src/gpu/GrFragmentProcessor.h" 13cb93a386Sopenharmony_ci#include "src/gpu/GrShaderCaps.h" 14cb93a386Sopenharmony_ci#include "src/gpu/effects/GrConvexPolyEffect.h" 15cb93a386Sopenharmony_ci#include "src/gpu/effects/GrOvalEffect.h" 16cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" 17cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLProgramDataManager.h" 18cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLUniformHandler.h" 19cb93a386Sopenharmony_ci 20cb93a386Sopenharmony_ci// The effects defined here only handle rrect radii >= kRadiusMin. 21cb93a386Sopenharmony_cistatic const SkScalar kRadiusMin = SK_ScalarHalf; 22cb93a386Sopenharmony_ci 23cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////// 24cb93a386Sopenharmony_ci 25cb93a386Sopenharmony_cinamespace { 26cb93a386Sopenharmony_ciclass CircularRRectEffect : public GrFragmentProcessor { 27cb93a386Sopenharmony_cipublic: 28cb93a386Sopenharmony_ci enum CornerFlags { 29cb93a386Sopenharmony_ci kTopLeft_CornerFlag = (1 << SkRRect::kUpperLeft_Corner), 30cb93a386Sopenharmony_ci kTopRight_CornerFlag = (1 << SkRRect::kUpperRight_Corner), 31cb93a386Sopenharmony_ci kBottomRight_CornerFlag = (1 << SkRRect::kLowerRight_Corner), 32cb93a386Sopenharmony_ci kBottomLeft_CornerFlag = (1 << SkRRect::kLowerLeft_Corner), 33cb93a386Sopenharmony_ci 34cb93a386Sopenharmony_ci kLeft_CornerFlags = kTopLeft_CornerFlag | kBottomLeft_CornerFlag, 35cb93a386Sopenharmony_ci kTop_CornerFlags = kTopLeft_CornerFlag | kTopRight_CornerFlag, 36cb93a386Sopenharmony_ci kRight_CornerFlags = kTopRight_CornerFlag | kBottomRight_CornerFlag, 37cb93a386Sopenharmony_ci kBottom_CornerFlags = kBottomLeft_CornerFlag | kBottomRight_CornerFlag, 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_ci kAll_CornerFlags = kTopLeft_CornerFlag | kTopRight_CornerFlag | 40cb93a386Sopenharmony_ci kBottomLeft_CornerFlag | kBottomRight_CornerFlag, 41cb93a386Sopenharmony_ci 42cb93a386Sopenharmony_ci kNone_CornerFlags = 0 43cb93a386Sopenharmony_ci }; 44cb93a386Sopenharmony_ci 45cb93a386Sopenharmony_ci // The flags are used to indicate which corners are circluar (unflagged corners are assumed to 46cb93a386Sopenharmony_ci // be square). 47cb93a386Sopenharmony_ci static GrFPResult Make(std::unique_ptr<GrFragmentProcessor>, GrClipEdgeType, 48cb93a386Sopenharmony_ci uint32_t circularCornerFlags, const SkRRect&); 49cb93a386Sopenharmony_ci 50cb93a386Sopenharmony_ci ~CircularRRectEffect() override {} 51cb93a386Sopenharmony_ci 52cb93a386Sopenharmony_ci const char* name() const override { return "CircularRRect"; } 53cb93a386Sopenharmony_ci 54cb93a386Sopenharmony_ci SkString getShaderDfxInfo() const override; 55cb93a386Sopenharmony_ci 56cb93a386Sopenharmony_ci std::unique_ptr<GrFragmentProcessor> clone() const override; 57cb93a386Sopenharmony_ci 58cb93a386Sopenharmony_ciprivate: 59cb93a386Sopenharmony_ci class Impl; 60cb93a386Sopenharmony_ci 61cb93a386Sopenharmony_ci CircularRRectEffect(std::unique_ptr<GrFragmentProcessor> inputFP, 62cb93a386Sopenharmony_ci GrClipEdgeType, uint32_t circularCornerFlags, const SkRRect&); 63cb93a386Sopenharmony_ci CircularRRectEffect(const CircularRRectEffect& that); 64cb93a386Sopenharmony_ci 65cb93a386Sopenharmony_ci std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override; 66cb93a386Sopenharmony_ci 67cb93a386Sopenharmony_ci void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; 68cb93a386Sopenharmony_ci 69cb93a386Sopenharmony_ci bool onIsEqual(const GrFragmentProcessor& other) const override; 70cb93a386Sopenharmony_ci 71cb93a386Sopenharmony_ci SkRRect fRRect; 72cb93a386Sopenharmony_ci GrClipEdgeType fEdgeType; 73cb93a386Sopenharmony_ci uint32_t fCircularCornerFlags; 74cb93a386Sopenharmony_ci 75cb93a386Sopenharmony_ci GR_DECLARE_FRAGMENT_PROCESSOR_TEST 76cb93a386Sopenharmony_ci 77cb93a386Sopenharmony_ci using INHERITED = GrFragmentProcessor; 78cb93a386Sopenharmony_ci}; 79cb93a386Sopenharmony_ci} // anonymous namespace 80cb93a386Sopenharmony_ci 81cb93a386Sopenharmony_ciGrFPResult CircularRRectEffect::Make(std::unique_ptr<GrFragmentProcessor> inputFP, 82cb93a386Sopenharmony_ci GrClipEdgeType edgeType, 83cb93a386Sopenharmony_ci uint32_t circularCornerFlags, const SkRRect& rrect) { 84cb93a386Sopenharmony_ci if (GrClipEdgeType::kFillAA != edgeType && GrClipEdgeType::kInverseFillAA != edgeType) { 85cb93a386Sopenharmony_ci return GrFPFailure(std::move(inputFP)); 86cb93a386Sopenharmony_ci } 87cb93a386Sopenharmony_ci return GrFPSuccess(std::unique_ptr<GrFragmentProcessor>( 88cb93a386Sopenharmony_ci new CircularRRectEffect(std::move(inputFP), edgeType, circularCornerFlags, rrect))); 89cb93a386Sopenharmony_ci} 90cb93a386Sopenharmony_ci 91cb93a386Sopenharmony_ciCircularRRectEffect::CircularRRectEffect(std::unique_ptr<GrFragmentProcessor> inputFP, 92cb93a386Sopenharmony_ci GrClipEdgeType edgeType, 93cb93a386Sopenharmony_ci uint32_t circularCornerFlags, 94cb93a386Sopenharmony_ci const SkRRect& rrect) 95cb93a386Sopenharmony_ci : INHERITED(kCircularRRectEffect_ClassID, 96cb93a386Sopenharmony_ci ProcessorOptimizationFlags(inputFP.get()) & 97cb93a386Sopenharmony_ci kCompatibleWithCoverageAsAlpha_OptimizationFlag) 98cb93a386Sopenharmony_ci , fRRect(rrect) 99cb93a386Sopenharmony_ci , fEdgeType(edgeType) 100cb93a386Sopenharmony_ci , fCircularCornerFlags(circularCornerFlags) { 101cb93a386Sopenharmony_ci this->registerChild(std::move(inputFP)); 102cb93a386Sopenharmony_ci} 103cb93a386Sopenharmony_ci 104cb93a386Sopenharmony_ciCircularRRectEffect::CircularRRectEffect(const CircularRRectEffect& that) 105cb93a386Sopenharmony_ci : INHERITED(that) 106cb93a386Sopenharmony_ci , fRRect(that.fRRect) 107cb93a386Sopenharmony_ci , fEdgeType(that.fEdgeType) 108cb93a386Sopenharmony_ci , fCircularCornerFlags(that.fCircularCornerFlags) {} 109cb93a386Sopenharmony_ci 110cb93a386Sopenharmony_cistd::unique_ptr<GrFragmentProcessor> CircularRRectEffect::clone() const { 111cb93a386Sopenharmony_ci return std::unique_ptr<GrFragmentProcessor>(new CircularRRectEffect(*this)); 112cb93a386Sopenharmony_ci} 113cb93a386Sopenharmony_ci 114cb93a386Sopenharmony_cibool CircularRRectEffect::onIsEqual(const GrFragmentProcessor& other) const { 115cb93a386Sopenharmony_ci const CircularRRectEffect& crre = other.cast<CircularRRectEffect>(); 116cb93a386Sopenharmony_ci // The corner flags are derived from fRRect, so no need to check them. 117cb93a386Sopenharmony_ci return fEdgeType == crre.fEdgeType && fRRect == crre.fRRect; 118cb93a386Sopenharmony_ci} 119cb93a386Sopenharmony_ci 120cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////// 121cb93a386Sopenharmony_ci 122cb93a386Sopenharmony_ciGR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircularRRectEffect); 123cb93a386Sopenharmony_ci 124cb93a386Sopenharmony_ci#if GR_TEST_UTILS 125cb93a386Sopenharmony_cistd::unique_ptr<GrFragmentProcessor> CircularRRectEffect::TestCreate(GrProcessorTestData* d) { 126cb93a386Sopenharmony_ci SkScalar w = d->fRandom->nextRangeScalar(20.f, 1000.f); 127cb93a386Sopenharmony_ci SkScalar h = d->fRandom->nextRangeScalar(20.f, 1000.f); 128cb93a386Sopenharmony_ci SkScalar r = d->fRandom->nextRangeF(kRadiusMin, 9.f); 129cb93a386Sopenharmony_ci SkRRect rrect; 130cb93a386Sopenharmony_ci rrect.setRectXY(SkRect::MakeWH(w, h), r, r); 131cb93a386Sopenharmony_ci std::unique_ptr<GrFragmentProcessor> fp = d->inputFP(); 132cb93a386Sopenharmony_ci bool success; 133cb93a386Sopenharmony_ci do { 134cb93a386Sopenharmony_ci GrClipEdgeType et = 135cb93a386Sopenharmony_ci (GrClipEdgeType)d->fRandom->nextULessThan(kGrClipEdgeTypeCnt); 136cb93a386Sopenharmony_ci std::tie(success, fp) = GrRRectEffect::Make(std::move(fp), et, rrect, 137cb93a386Sopenharmony_ci *d->caps()->shaderCaps()); 138cb93a386Sopenharmony_ci } while (!success); 139cb93a386Sopenharmony_ci return fp; 140cb93a386Sopenharmony_ci} 141cb93a386Sopenharmony_ci#endif 142cb93a386Sopenharmony_ci 143cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////// 144cb93a386Sopenharmony_ci 145cb93a386Sopenharmony_ciclass CircularRRectEffect::Impl : public ProgramImpl { 146cb93a386Sopenharmony_cipublic: 147cb93a386Sopenharmony_ci void emitCode(EmitArgs&) override; 148cb93a386Sopenharmony_ci 149cb93a386Sopenharmony_ciprivate: 150cb93a386Sopenharmony_ci void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; 151cb93a386Sopenharmony_ci 152cb93a386Sopenharmony_ci GrGLSLProgramDataManager::UniformHandle fInnerRectUniform; 153cb93a386Sopenharmony_ci GrGLSLProgramDataManager::UniformHandle fRadiusPlusHalfUniform; 154cb93a386Sopenharmony_ci SkRRect fPrevRRect; 155cb93a386Sopenharmony_ci}; 156cb93a386Sopenharmony_ci 157cb93a386Sopenharmony_civoid CircularRRectEffect::Impl::emitCode(EmitArgs& args) { 158cb93a386Sopenharmony_ci const CircularRRectEffect& crre = args.fFp.cast<CircularRRectEffect>(); 159cb93a386Sopenharmony_ci GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; 160cb93a386Sopenharmony_ci const char *rectName; 161cb93a386Sopenharmony_ci const char *radiusPlusHalfName; 162cb93a386Sopenharmony_ci // The inner rect is the rrect bounds inset by the radius. Its left, top, right, and bottom 163cb93a386Sopenharmony_ci // edges correspond to components x, y, z, and w, respectively. When a side of the rrect has 164cb93a386Sopenharmony_ci // only rectangular corners, that side's value corresponds to the rect edge's value outset by 165cb93a386Sopenharmony_ci // half a pixel. 166cb93a386Sopenharmony_ci fInnerRectUniform = uniformHandler->addUniform(&crre, kFragment_GrShaderFlag, kFloat4_GrSLType, 167cb93a386Sopenharmony_ci "innerRect", &rectName); 168cb93a386Sopenharmony_ci // x is (r + .5) and y is 1/(r + .5) 169cb93a386Sopenharmony_ci fRadiusPlusHalfUniform = uniformHandler->addUniform(&crre, kFragment_GrShaderFlag, 170cb93a386Sopenharmony_ci kHalf2_GrSLType, "radiusPlusHalf", 171cb93a386Sopenharmony_ci &radiusPlusHalfName); 172cb93a386Sopenharmony_ci 173cb93a386Sopenharmony_ci // If we're on a device where float != fp32 then the length calculation could overflow. 174cb93a386Sopenharmony_ci SkString clampedCircleDistance; 175cb93a386Sopenharmony_ci if (!args.fShaderCaps->floatIs32Bits()) { 176cb93a386Sopenharmony_ci clampedCircleDistance.printf("saturate(%s.x * (1.0 - length(dxy * %s.y)))", 177cb93a386Sopenharmony_ci radiusPlusHalfName, radiusPlusHalfName); 178cb93a386Sopenharmony_ci } else { 179cb93a386Sopenharmony_ci clampedCircleDistance.printf("saturate(%s.x - length(dxy))", radiusPlusHalfName); 180cb93a386Sopenharmony_ci } 181cb93a386Sopenharmony_ci 182cb93a386Sopenharmony_ci GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; 183cb93a386Sopenharmony_ci // At each quarter-circle corner we compute a vector that is the offset of the fragment position 184cb93a386Sopenharmony_ci // from the circle center. The vector is pinned in x and y to be in the quarter-plane relevant 185cb93a386Sopenharmony_ci // to that corner. This means that points near the interior near the rrect top edge will have 186cb93a386Sopenharmony_ci // a vector that points straight up for both the TL left and TR corners. Computing an 187cb93a386Sopenharmony_ci // alpha from this vector at either the TR or TL corner will give the correct result. Similarly, 188cb93a386Sopenharmony_ci // fragments near the other three edges will get the correct AA. Fragments in the interior of 189cb93a386Sopenharmony_ci // the rrect will have a (0,0) vector at all four corners. So long as the radius > 0.5 they will 190cb93a386Sopenharmony_ci // correctly produce an alpha value of 1 at all four corners. We take the min of all the alphas. 191cb93a386Sopenharmony_ci // The code below is a simplified version of the above that performs maxs on the vector 192cb93a386Sopenharmony_ci // components before computing distances and alpha values so that only one distance computation 193cb93a386Sopenharmony_ci // need be computed to determine the min alpha. 194cb93a386Sopenharmony_ci // 195cb93a386Sopenharmony_ci // For the cases where one half of the rrect is rectangular we drop one of the x or y 196cb93a386Sopenharmony_ci // computations, compute a separate rect edge alpha for the rect side, and mul the two computed 197cb93a386Sopenharmony_ci // alphas together. 198cb93a386Sopenharmony_ci switch (crre.fCircularCornerFlags) { 199cb93a386Sopenharmony_ci case CircularRRectEffect::kAll_CornerFlags: 200cb93a386Sopenharmony_ci fragBuilder->codeAppendf("float2 dxy0 = %s.LT - sk_FragCoord.xy;", rectName); 201cb93a386Sopenharmony_ci fragBuilder->codeAppendf("float2 dxy1 = sk_FragCoord.xy - %s.RB;", rectName); 202cb93a386Sopenharmony_ci fragBuilder->codeAppend("float2 dxy = max(max(dxy0, dxy1), 0.0);"); 203cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half alpha = half(%s);", clampedCircleDistance.c_str()); 204cb93a386Sopenharmony_ci break; 205cb93a386Sopenharmony_ci case CircularRRectEffect::kTopLeft_CornerFlag: 206cb93a386Sopenharmony_ci fragBuilder->codeAppendf("float2 dxy = max(%s.LT - sk_FragCoord.xy, 0.0);", 207cb93a386Sopenharmony_ci rectName); 208cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half rightAlpha = half(saturate(%s.R - sk_FragCoord.x));", 209cb93a386Sopenharmony_ci rectName); 210cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half bottomAlpha = half(saturate(%s.B - sk_FragCoord.y));", 211cb93a386Sopenharmony_ci rectName); 212cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half alpha = bottomAlpha * rightAlpha * half(%s);", 213cb93a386Sopenharmony_ci clampedCircleDistance.c_str()); 214cb93a386Sopenharmony_ci break; 215cb93a386Sopenharmony_ci case CircularRRectEffect::kTopRight_CornerFlag: 216cb93a386Sopenharmony_ci fragBuilder->codeAppendf("float2 dxy = max(float2(sk_FragCoord.x - %s.R, " 217cb93a386Sopenharmony_ci "%s.T - sk_FragCoord.y), 0.0);", 218cb93a386Sopenharmony_ci rectName, rectName); 219cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half leftAlpha = half(saturate(sk_FragCoord.x - %s.L));", 220cb93a386Sopenharmony_ci rectName); 221cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half bottomAlpha = half(saturate(%s.B - sk_FragCoord.y));", 222cb93a386Sopenharmony_ci rectName); 223cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half alpha = bottomAlpha * leftAlpha * half(%s);", 224cb93a386Sopenharmony_ci clampedCircleDistance.c_str()); 225cb93a386Sopenharmony_ci break; 226cb93a386Sopenharmony_ci case CircularRRectEffect::kBottomRight_CornerFlag: 227cb93a386Sopenharmony_ci fragBuilder->codeAppendf("float2 dxy = max(sk_FragCoord.xy - %s.RB, 0.0);", 228cb93a386Sopenharmony_ci rectName); 229cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half leftAlpha = half(saturate(sk_FragCoord.x - %s.L));", 230cb93a386Sopenharmony_ci rectName); 231cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half topAlpha = half(saturate(sk_FragCoord.y - %s.T));", 232cb93a386Sopenharmony_ci rectName); 233cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half alpha = topAlpha * leftAlpha * half(%s);", 234cb93a386Sopenharmony_ci clampedCircleDistance.c_str()); 235cb93a386Sopenharmony_ci break; 236cb93a386Sopenharmony_ci case CircularRRectEffect::kBottomLeft_CornerFlag: 237cb93a386Sopenharmony_ci fragBuilder->codeAppendf("float2 dxy = max(float2(%s.L - sk_FragCoord.x, " 238cb93a386Sopenharmony_ci "sk_FragCoord.y - %s.B), 0.0);", 239cb93a386Sopenharmony_ci rectName, rectName); 240cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half rightAlpha = half(saturate(%s.R - sk_FragCoord.x));", 241cb93a386Sopenharmony_ci rectName); 242cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half topAlpha = half(saturate(sk_FragCoord.y - %s.T));", 243cb93a386Sopenharmony_ci rectName); 244cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half alpha = topAlpha * rightAlpha * half(%s);", 245cb93a386Sopenharmony_ci clampedCircleDistance.c_str()); 246cb93a386Sopenharmony_ci break; 247cb93a386Sopenharmony_ci case CircularRRectEffect::kLeft_CornerFlags: 248cb93a386Sopenharmony_ci fragBuilder->codeAppendf("float2 dxy0 = %s.LT - sk_FragCoord.xy;", rectName); 249cb93a386Sopenharmony_ci fragBuilder->codeAppendf("float dy1 = sk_FragCoord.y - %s.B;", rectName); 250cb93a386Sopenharmony_ci fragBuilder->codeAppend("float2 dxy = max(float2(dxy0.x, max(dxy0.y, dy1)), 0.0);"); 251cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half rightAlpha = half(saturate(%s.R - sk_FragCoord.x));", 252cb93a386Sopenharmony_ci rectName); 253cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half alpha = rightAlpha * half(%s);", 254cb93a386Sopenharmony_ci clampedCircleDistance.c_str()); 255cb93a386Sopenharmony_ci break; 256cb93a386Sopenharmony_ci case CircularRRectEffect::kTop_CornerFlags: 257cb93a386Sopenharmony_ci fragBuilder->codeAppendf("float2 dxy0 = %s.LT - sk_FragCoord.xy;", rectName); 258cb93a386Sopenharmony_ci fragBuilder->codeAppendf("float dx1 = sk_FragCoord.x - %s.R;", rectName); 259cb93a386Sopenharmony_ci fragBuilder->codeAppend("float2 dxy = max(float2(max(dxy0.x, dx1), dxy0.y), 0.0);"); 260cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half bottomAlpha = half(saturate(%s.B - sk_FragCoord.y));", 261cb93a386Sopenharmony_ci rectName); 262cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half alpha = bottomAlpha * half(%s);", 263cb93a386Sopenharmony_ci clampedCircleDistance.c_str()); 264cb93a386Sopenharmony_ci break; 265cb93a386Sopenharmony_ci case CircularRRectEffect::kRight_CornerFlags: 266cb93a386Sopenharmony_ci fragBuilder->codeAppendf("float dy0 = %s.T - sk_FragCoord.y;", rectName); 267cb93a386Sopenharmony_ci fragBuilder->codeAppendf("float2 dxy1 = sk_FragCoord.xy - %s.RB;", rectName); 268cb93a386Sopenharmony_ci fragBuilder->codeAppend("float2 dxy = max(float2(dxy1.x, max(dy0, dxy1.y)), 0.0);"); 269cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half leftAlpha = half(saturate(sk_FragCoord.x - %s.L));", 270cb93a386Sopenharmony_ci rectName); 271cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half alpha = leftAlpha * half(%s);", 272cb93a386Sopenharmony_ci clampedCircleDistance.c_str()); 273cb93a386Sopenharmony_ci break; 274cb93a386Sopenharmony_ci case CircularRRectEffect::kBottom_CornerFlags: 275cb93a386Sopenharmony_ci fragBuilder->codeAppendf("float dx0 = %s.L - sk_FragCoord.x;", rectName); 276cb93a386Sopenharmony_ci fragBuilder->codeAppendf("float2 dxy1 = sk_FragCoord.xy - %s.RB;", rectName); 277cb93a386Sopenharmony_ci fragBuilder->codeAppend("float2 dxy = max(float2(max(dx0, dxy1.x), dxy1.y), 0.0);"); 278cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half topAlpha = half(saturate(sk_FragCoord.y - %s.T));", 279cb93a386Sopenharmony_ci rectName); 280cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half alpha = topAlpha * half(%s);", 281cb93a386Sopenharmony_ci clampedCircleDistance.c_str()); 282cb93a386Sopenharmony_ci break; 283cb93a386Sopenharmony_ci } 284cb93a386Sopenharmony_ci 285cb93a386Sopenharmony_ci if (GrClipEdgeType::kInverseFillAA == crre.fEdgeType) { 286cb93a386Sopenharmony_ci fragBuilder->codeAppend("alpha = 1.0 - alpha;"); 287cb93a386Sopenharmony_ci } 288cb93a386Sopenharmony_ci 289cb93a386Sopenharmony_ci SkString inputSample = this->invokeChild(/*childIndex=*/0, args); 290cb93a386Sopenharmony_ci 291cb93a386Sopenharmony_ci fragBuilder->codeAppendf("return %s * alpha;", inputSample.c_str()); 292cb93a386Sopenharmony_ci} 293cb93a386Sopenharmony_ci 294cb93a386Sopenharmony_civoid CircularRRectEffect::Impl::onSetData(const GrGLSLProgramDataManager& pdman, 295cb93a386Sopenharmony_ci const GrFragmentProcessor& processor) { 296cb93a386Sopenharmony_ci const CircularRRectEffect& crre = processor.cast<CircularRRectEffect>(); 297cb93a386Sopenharmony_ci const SkRRect& rrect = crre.fRRect; 298cb93a386Sopenharmony_ci if (rrect != fPrevRRect) { 299cb93a386Sopenharmony_ci SkRect rect = rrect.getBounds(); 300cb93a386Sopenharmony_ci SkScalar radius = 0; 301cb93a386Sopenharmony_ci switch (crre.fCircularCornerFlags) { 302cb93a386Sopenharmony_ci case CircularRRectEffect::kAll_CornerFlags: 303cb93a386Sopenharmony_ci SkASSERT(SkRRectPriv::IsSimpleCircular(rrect)); 304cb93a386Sopenharmony_ci radius = SkRRectPriv::GetSimpleRadii(rrect).fX; 305cb93a386Sopenharmony_ci SkASSERT(radius >= kRadiusMin); 306cb93a386Sopenharmony_ci rect.inset(radius, radius); 307cb93a386Sopenharmony_ci break; 308cb93a386Sopenharmony_ci case CircularRRectEffect::kTopLeft_CornerFlag: 309cb93a386Sopenharmony_ci radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX; 310cb93a386Sopenharmony_ci rect.fLeft += radius; 311cb93a386Sopenharmony_ci rect.fTop += radius; 312cb93a386Sopenharmony_ci rect.fRight += 0.5f; 313cb93a386Sopenharmony_ci rect.fBottom += 0.5f; 314cb93a386Sopenharmony_ci break; 315cb93a386Sopenharmony_ci case CircularRRectEffect::kTopRight_CornerFlag: 316cb93a386Sopenharmony_ci radius = rrect.radii(SkRRect::kUpperRight_Corner).fX; 317cb93a386Sopenharmony_ci rect.fLeft -= 0.5f; 318cb93a386Sopenharmony_ci rect.fTop += radius; 319cb93a386Sopenharmony_ci rect.fRight -= radius; 320cb93a386Sopenharmony_ci rect.fBottom += 0.5f; 321cb93a386Sopenharmony_ci break; 322cb93a386Sopenharmony_ci case CircularRRectEffect::kBottomRight_CornerFlag: 323cb93a386Sopenharmony_ci radius = rrect.radii(SkRRect::kLowerRight_Corner).fX; 324cb93a386Sopenharmony_ci rect.fLeft -= 0.5f; 325cb93a386Sopenharmony_ci rect.fTop -= 0.5f; 326cb93a386Sopenharmony_ci rect.fRight -= radius; 327cb93a386Sopenharmony_ci rect.fBottom -= radius; 328cb93a386Sopenharmony_ci break; 329cb93a386Sopenharmony_ci case CircularRRectEffect::kBottomLeft_CornerFlag: 330cb93a386Sopenharmony_ci radius = rrect.radii(SkRRect::kLowerLeft_Corner).fX; 331cb93a386Sopenharmony_ci rect.fLeft += radius; 332cb93a386Sopenharmony_ci rect.fTop -= 0.5f; 333cb93a386Sopenharmony_ci rect.fRight += 0.5f; 334cb93a386Sopenharmony_ci rect.fBottom -= radius; 335cb93a386Sopenharmony_ci break; 336cb93a386Sopenharmony_ci case CircularRRectEffect::kLeft_CornerFlags: 337cb93a386Sopenharmony_ci radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX; 338cb93a386Sopenharmony_ci rect.fLeft += radius; 339cb93a386Sopenharmony_ci rect.fTop += radius; 340cb93a386Sopenharmony_ci rect.fRight += 0.5f; 341cb93a386Sopenharmony_ci rect.fBottom -= radius; 342cb93a386Sopenharmony_ci break; 343cb93a386Sopenharmony_ci case CircularRRectEffect::kTop_CornerFlags: 344cb93a386Sopenharmony_ci radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX; 345cb93a386Sopenharmony_ci rect.fLeft += radius; 346cb93a386Sopenharmony_ci rect.fTop += radius; 347cb93a386Sopenharmony_ci rect.fRight -= radius; 348cb93a386Sopenharmony_ci rect.fBottom += 0.5f; 349cb93a386Sopenharmony_ci break; 350cb93a386Sopenharmony_ci case CircularRRectEffect::kRight_CornerFlags: 351cb93a386Sopenharmony_ci radius = rrect.radii(SkRRect::kUpperRight_Corner).fX; 352cb93a386Sopenharmony_ci rect.fLeft -= 0.5f; 353cb93a386Sopenharmony_ci rect.fTop += radius; 354cb93a386Sopenharmony_ci rect.fRight -= radius; 355cb93a386Sopenharmony_ci rect.fBottom -= radius; 356cb93a386Sopenharmony_ci break; 357cb93a386Sopenharmony_ci case CircularRRectEffect::kBottom_CornerFlags: 358cb93a386Sopenharmony_ci radius = rrect.radii(SkRRect::kLowerLeft_Corner).fX; 359cb93a386Sopenharmony_ci rect.fLeft += radius; 360cb93a386Sopenharmony_ci rect.fTop -= 0.5f; 361cb93a386Sopenharmony_ci rect.fRight -= radius; 362cb93a386Sopenharmony_ci rect.fBottom -= radius; 363cb93a386Sopenharmony_ci break; 364cb93a386Sopenharmony_ci default: 365cb93a386Sopenharmony_ci SK_ABORT("Should have been one of the above cases."); 366cb93a386Sopenharmony_ci } 367cb93a386Sopenharmony_ci pdman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom); 368cb93a386Sopenharmony_ci radius += 0.5f; 369cb93a386Sopenharmony_ci pdman.set2f(fRadiusPlusHalfUniform, radius, 1.f / radius); 370cb93a386Sopenharmony_ci fPrevRRect = rrect; 371cb93a386Sopenharmony_ci } 372cb93a386Sopenharmony_ci} 373cb93a386Sopenharmony_ci 374cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////////////////////////// 375cb93a386Sopenharmony_ci 376cb93a386Sopenharmony_ciSkString CircularRRectEffect::getShaderDfxInfo() const { 377cb93a386Sopenharmony_ci SkString format; 378cb93a386Sopenharmony_ci format.printf("ShaderDfx_CircularRRectEffect_%d_%d", fCircularCornerFlags, fEdgeType); 379cb93a386Sopenharmony_ci return format; 380cb93a386Sopenharmony_ci} 381cb93a386Sopenharmony_ci 382cb93a386Sopenharmony_civoid CircularRRectEffect::onAddToKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { 383cb93a386Sopenharmony_ci static_assert(kGrClipEdgeTypeCnt <= 8); 384cb93a386Sopenharmony_ci b->add32((fCircularCornerFlags << 3) | static_cast<int>(fEdgeType)); 385cb93a386Sopenharmony_ci} 386cb93a386Sopenharmony_ci 387cb93a386Sopenharmony_cistd::unique_ptr<GrFragmentProcessor::ProgramImpl> CircularRRectEffect::onMakeProgramImpl() const { 388cb93a386Sopenharmony_ci return std::make_unique<Impl>(); 389cb93a386Sopenharmony_ci} 390cb93a386Sopenharmony_ci 391cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////// 392cb93a386Sopenharmony_ci 393cb93a386Sopenharmony_cinamespace { 394cb93a386Sopenharmony_ciclass EllipticalRRectEffect : public GrFragmentProcessor { 395cb93a386Sopenharmony_cipublic: 396cb93a386Sopenharmony_ci static GrFPResult Make(std::unique_ptr<GrFragmentProcessor>, GrClipEdgeType, const SkRRect&); 397cb93a386Sopenharmony_ci 398cb93a386Sopenharmony_ci ~EllipticalRRectEffect() override {} 399cb93a386Sopenharmony_ci 400cb93a386Sopenharmony_ci const char* name() const override { return "EllipticalRRect"; } 401cb93a386Sopenharmony_ci 402cb93a386Sopenharmony_ci SkString getShaderDfxInfo() const override; 403cb93a386Sopenharmony_ci 404cb93a386Sopenharmony_ci std::unique_ptr<GrFragmentProcessor> clone() const override; 405cb93a386Sopenharmony_ci 406cb93a386Sopenharmony_ciprivate: 407cb93a386Sopenharmony_ci class Impl; 408cb93a386Sopenharmony_ci 409cb93a386Sopenharmony_ci EllipticalRRectEffect(std::unique_ptr<GrFragmentProcessor>, GrClipEdgeType, const SkRRect&); 410cb93a386Sopenharmony_ci EllipticalRRectEffect(const EllipticalRRectEffect& that); 411cb93a386Sopenharmony_ci 412cb93a386Sopenharmony_ci std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override; 413cb93a386Sopenharmony_ci 414cb93a386Sopenharmony_ci void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; 415cb93a386Sopenharmony_ci 416cb93a386Sopenharmony_ci bool onIsEqual(const GrFragmentProcessor& other) const override; 417cb93a386Sopenharmony_ci 418cb93a386Sopenharmony_ci SkRRect fRRect; 419cb93a386Sopenharmony_ci GrClipEdgeType fEdgeType; 420cb93a386Sopenharmony_ci 421cb93a386Sopenharmony_ci GR_DECLARE_FRAGMENT_PROCESSOR_TEST 422cb93a386Sopenharmony_ci 423cb93a386Sopenharmony_ci using INHERITED = GrFragmentProcessor; 424cb93a386Sopenharmony_ci}; 425cb93a386Sopenharmony_ci 426cb93a386Sopenharmony_ciGrFPResult EllipticalRRectEffect::Make(std::unique_ptr<GrFragmentProcessor> inputFP, 427cb93a386Sopenharmony_ci GrClipEdgeType edgeType, 428cb93a386Sopenharmony_ci const SkRRect& rrect) { 429cb93a386Sopenharmony_ci if (GrClipEdgeType::kFillAA != edgeType && GrClipEdgeType::kInverseFillAA != edgeType) { 430cb93a386Sopenharmony_ci return GrFPFailure(std::move(inputFP)); 431cb93a386Sopenharmony_ci } 432cb93a386Sopenharmony_ci return GrFPSuccess(std::unique_ptr<GrFragmentProcessor>( 433cb93a386Sopenharmony_ci new EllipticalRRectEffect(std::move(inputFP), edgeType, rrect))); 434cb93a386Sopenharmony_ci} 435cb93a386Sopenharmony_ci 436cb93a386Sopenharmony_ciEllipticalRRectEffect::EllipticalRRectEffect(std::unique_ptr<GrFragmentProcessor> inputFP, 437cb93a386Sopenharmony_ci GrClipEdgeType edgeType, 438cb93a386Sopenharmony_ci const SkRRect& rrect) 439cb93a386Sopenharmony_ci : INHERITED(kEllipticalRRectEffect_ClassID, 440cb93a386Sopenharmony_ci ProcessorOptimizationFlags(inputFP.get()) & 441cb93a386Sopenharmony_ci kCompatibleWithCoverageAsAlpha_OptimizationFlag) 442cb93a386Sopenharmony_ci , fRRect(rrect) 443cb93a386Sopenharmony_ci , fEdgeType(edgeType) { 444cb93a386Sopenharmony_ci this->registerChild(std::move(inputFP)); 445cb93a386Sopenharmony_ci} 446cb93a386Sopenharmony_ci 447cb93a386Sopenharmony_ciEllipticalRRectEffect::EllipticalRRectEffect(const EllipticalRRectEffect& that) 448cb93a386Sopenharmony_ci : INHERITED(that) 449cb93a386Sopenharmony_ci , fRRect(that.fRRect) 450cb93a386Sopenharmony_ci , fEdgeType(that.fEdgeType) {} 451cb93a386Sopenharmony_ci 452cb93a386Sopenharmony_cistd::unique_ptr<GrFragmentProcessor> EllipticalRRectEffect::clone() const { 453cb93a386Sopenharmony_ci return std::unique_ptr<GrFragmentProcessor>(new EllipticalRRectEffect(*this)); 454cb93a386Sopenharmony_ci} 455cb93a386Sopenharmony_ci 456cb93a386Sopenharmony_cibool EllipticalRRectEffect::onIsEqual(const GrFragmentProcessor& other) const { 457cb93a386Sopenharmony_ci const EllipticalRRectEffect& erre = other.cast<EllipticalRRectEffect>(); 458cb93a386Sopenharmony_ci return fEdgeType == erre.fEdgeType && fRRect == erre.fRRect; 459cb93a386Sopenharmony_ci} 460cb93a386Sopenharmony_ci} // anonymous namespace 461cb93a386Sopenharmony_ci 462cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////// 463cb93a386Sopenharmony_ci 464cb93a386Sopenharmony_ciGR_DEFINE_FRAGMENT_PROCESSOR_TEST(EllipticalRRectEffect); 465cb93a386Sopenharmony_ci 466cb93a386Sopenharmony_ci#if GR_TEST_UTILS 467cb93a386Sopenharmony_cistd::unique_ptr<GrFragmentProcessor> EllipticalRRectEffect::TestCreate(GrProcessorTestData* d) { 468cb93a386Sopenharmony_ci SkScalar w = d->fRandom->nextRangeScalar(20.f, 1000.f); 469cb93a386Sopenharmony_ci SkScalar h = d->fRandom->nextRangeScalar(20.f, 1000.f); 470cb93a386Sopenharmony_ci SkVector r[4]; 471cb93a386Sopenharmony_ci r[SkRRect::kUpperLeft_Corner].fX = d->fRandom->nextRangeF(kRadiusMin, 9.f); 472cb93a386Sopenharmony_ci // ensure at least one corner really is elliptical 473cb93a386Sopenharmony_ci do { 474cb93a386Sopenharmony_ci r[SkRRect::kUpperLeft_Corner].fY = d->fRandom->nextRangeF(kRadiusMin, 9.f); 475cb93a386Sopenharmony_ci } while (r[SkRRect::kUpperLeft_Corner].fY == r[SkRRect::kUpperLeft_Corner].fX); 476cb93a386Sopenharmony_ci 477cb93a386Sopenharmony_ci SkRRect rrect; 478cb93a386Sopenharmony_ci if (d->fRandom->nextBool()) { 479cb93a386Sopenharmony_ci // half the time create a four-radii rrect. 480cb93a386Sopenharmony_ci r[SkRRect::kLowerRight_Corner].fX = d->fRandom->nextRangeF(kRadiusMin, 9.f); 481cb93a386Sopenharmony_ci r[SkRRect::kLowerRight_Corner].fY = d->fRandom->nextRangeF(kRadiusMin, 9.f); 482cb93a386Sopenharmony_ci 483cb93a386Sopenharmony_ci r[SkRRect::kUpperRight_Corner].fX = r[SkRRect::kLowerRight_Corner].fX; 484cb93a386Sopenharmony_ci r[SkRRect::kUpperRight_Corner].fY = r[SkRRect::kUpperLeft_Corner].fY; 485cb93a386Sopenharmony_ci 486cb93a386Sopenharmony_ci r[SkRRect::kLowerLeft_Corner].fX = r[SkRRect::kUpperLeft_Corner].fX; 487cb93a386Sopenharmony_ci r[SkRRect::kLowerLeft_Corner].fY = r[SkRRect::kLowerRight_Corner].fY; 488cb93a386Sopenharmony_ci 489cb93a386Sopenharmony_ci rrect.setRectRadii(SkRect::MakeWH(w, h), r); 490cb93a386Sopenharmony_ci } else { 491cb93a386Sopenharmony_ci rrect.setRectXY(SkRect::MakeWH(w, h), r[SkRRect::kUpperLeft_Corner].fX, 492cb93a386Sopenharmony_ci r[SkRRect::kUpperLeft_Corner].fY); 493cb93a386Sopenharmony_ci } 494cb93a386Sopenharmony_ci std::unique_ptr<GrFragmentProcessor> fp = d->inputFP(); 495cb93a386Sopenharmony_ci bool success; 496cb93a386Sopenharmony_ci do { 497cb93a386Sopenharmony_ci GrClipEdgeType et = (GrClipEdgeType)d->fRandom->nextULessThan(kGrClipEdgeTypeCnt); 498cb93a386Sopenharmony_ci std::tie(success, fp) = GrRRectEffect::Make(std::move(fp), et, rrect, 499cb93a386Sopenharmony_ci *d->caps()->shaderCaps()); 500cb93a386Sopenharmony_ci } while (!success); 501cb93a386Sopenharmony_ci return fp; 502cb93a386Sopenharmony_ci} 503cb93a386Sopenharmony_ci#endif 504cb93a386Sopenharmony_ci 505cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////// 506cb93a386Sopenharmony_ci 507cb93a386Sopenharmony_ciclass EllipticalRRectEffect::Impl : public ProgramImpl { 508cb93a386Sopenharmony_cipublic: 509cb93a386Sopenharmony_ci void emitCode(EmitArgs&) override; 510cb93a386Sopenharmony_ci 511cb93a386Sopenharmony_ciprivate: 512cb93a386Sopenharmony_ci void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; 513cb93a386Sopenharmony_ci 514cb93a386Sopenharmony_ci GrGLSLProgramDataManager::UniformHandle fInnerRectUniform; 515cb93a386Sopenharmony_ci GrGLSLProgramDataManager::UniformHandle fInvRadiiSqdUniform; 516cb93a386Sopenharmony_ci GrGLSLProgramDataManager::UniformHandle fScaleUniform; 517cb93a386Sopenharmony_ci SkRRect fPrevRRect; 518cb93a386Sopenharmony_ci}; 519cb93a386Sopenharmony_ci 520cb93a386Sopenharmony_civoid EllipticalRRectEffect::Impl::emitCode(EmitArgs& args) { 521cb93a386Sopenharmony_ci const EllipticalRRectEffect& erre = args.fFp.cast<EllipticalRRectEffect>(); 522cb93a386Sopenharmony_ci GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; 523cb93a386Sopenharmony_ci const char *rectName; 524cb93a386Sopenharmony_ci // The inner rect is the rrect bounds inset by the x/y radii 525cb93a386Sopenharmony_ci fInnerRectUniform = uniformHandler->addUniform(&erre, kFragment_GrShaderFlag, kFloat4_GrSLType, 526cb93a386Sopenharmony_ci "innerRect", &rectName); 527cb93a386Sopenharmony_ci 528cb93a386Sopenharmony_ci GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; 529cb93a386Sopenharmony_ci // At each quarter-ellipse corner we compute a vector that is the offset of the fragment pos 530cb93a386Sopenharmony_ci // to the ellipse center. The vector is pinned in x and y to be in the quarter-plane relevant 531cb93a386Sopenharmony_ci // to that corner. This means that points near the interior near the rrect top edge will have 532cb93a386Sopenharmony_ci // a vector that points straight up for both the TL left and TR corners. Computing an 533cb93a386Sopenharmony_ci // alpha from this vector at either the TR or TL corner will give the correct result. Similarly, 534cb93a386Sopenharmony_ci // fragments near the other three edges will get the correct AA. Fragments in the interior of 535cb93a386Sopenharmony_ci // the rrect will have a (0,0) vector at all four corners. So long as the radii > 0.5 they will 536cb93a386Sopenharmony_ci // correctly produce an alpha value of 1 at all four corners. We take the min of all the alphas. 537cb93a386Sopenharmony_ci // 538cb93a386Sopenharmony_ci // The code below is a simplified version of the above that performs maxs on the vector 539cb93a386Sopenharmony_ci // components before computing distances and alpha values so that only one distance computation 540cb93a386Sopenharmony_ci // need be computed to determine the min alpha. 541cb93a386Sopenharmony_ci fragBuilder->codeAppendf("float2 dxy0 = %s.LT - sk_FragCoord.xy;", rectName); 542cb93a386Sopenharmony_ci fragBuilder->codeAppendf("float2 dxy1 = sk_FragCoord.xy - %s.RB;", rectName); 543cb93a386Sopenharmony_ci 544cb93a386Sopenharmony_ci // If we're on a device where float != fp32 then we'll do the distance computation in a space 545cb93a386Sopenharmony_ci // that is normalized by the largest radius. The scale uniform will be scale, 1/scale. The 546cb93a386Sopenharmony_ci // radii uniform values are already in this normalized space. 547cb93a386Sopenharmony_ci const char* scaleName = nullptr; 548cb93a386Sopenharmony_ci if (!args.fShaderCaps->floatIs32Bits()) { 549cb93a386Sopenharmony_ci fScaleUniform = uniformHandler->addUniform(&erre, kFragment_GrShaderFlag, kHalf2_GrSLType, 550cb93a386Sopenharmony_ci "scale", &scaleName); 551cb93a386Sopenharmony_ci } 552cb93a386Sopenharmony_ci 553cb93a386Sopenharmony_ci // The uniforms with the inv squared radii are highp to prevent underflow. 554cb93a386Sopenharmony_ci switch (erre.fRRect.getType()) { 555cb93a386Sopenharmony_ci case SkRRect::kSimple_Type: { 556cb93a386Sopenharmony_ci const char *invRadiiXYSqdName; 557cb93a386Sopenharmony_ci fInvRadiiSqdUniform = uniformHandler->addUniform(&erre, 558cb93a386Sopenharmony_ci kFragment_GrShaderFlag, 559cb93a386Sopenharmony_ci kFloat2_GrSLType, 560cb93a386Sopenharmony_ci "invRadiiXY", 561cb93a386Sopenharmony_ci &invRadiiXYSqdName); 562cb93a386Sopenharmony_ci fragBuilder->codeAppend("float2 dxy = max(max(dxy0, dxy1), 0.0);"); 563cb93a386Sopenharmony_ci if (scaleName) { 564cb93a386Sopenharmony_ci fragBuilder->codeAppendf("dxy *= %s.y;", scaleName); 565cb93a386Sopenharmony_ci } 566cb93a386Sopenharmony_ci // Z is the x/y offsets divided by squared radii. 567cb93a386Sopenharmony_ci fragBuilder->codeAppendf("float2 Z = dxy * %s.xy;", invRadiiXYSqdName); 568cb93a386Sopenharmony_ci break; 569cb93a386Sopenharmony_ci } 570cb93a386Sopenharmony_ci case SkRRect::kNinePatch_Type: { 571cb93a386Sopenharmony_ci const char *invRadiiLTRBSqdName; 572cb93a386Sopenharmony_ci fInvRadiiSqdUniform = uniformHandler->addUniform(&erre, 573cb93a386Sopenharmony_ci kFragment_GrShaderFlag, 574cb93a386Sopenharmony_ci kFloat4_GrSLType, 575cb93a386Sopenharmony_ci "invRadiiLTRB", 576cb93a386Sopenharmony_ci &invRadiiLTRBSqdName); 577cb93a386Sopenharmony_ci if (scaleName) { 578cb93a386Sopenharmony_ci fragBuilder->codeAppendf("dxy0 *= %s.y;", scaleName); 579cb93a386Sopenharmony_ci fragBuilder->codeAppendf("dxy1 *= %s.y;", scaleName); 580cb93a386Sopenharmony_ci } 581cb93a386Sopenharmony_ci fragBuilder->codeAppend("float2 dxy = max(max(dxy0, dxy1), 0.0);"); 582cb93a386Sopenharmony_ci // Z is the x/y offsets divided by squared radii. We only care about the (at most) one 583cb93a386Sopenharmony_ci // corner where both the x and y offsets are positive, hence the maxes. (The inverse 584cb93a386Sopenharmony_ci // squared radii will always be positive.) 585cb93a386Sopenharmony_ci fragBuilder->codeAppendf("float2 Z = max(max(dxy0 * %s.xy, dxy1 * %s.zw), 0.0);", 586cb93a386Sopenharmony_ci invRadiiLTRBSqdName, invRadiiLTRBSqdName); 587cb93a386Sopenharmony_ci 588cb93a386Sopenharmony_ci break; 589cb93a386Sopenharmony_ci } 590cb93a386Sopenharmony_ci default: 591cb93a386Sopenharmony_ci SK_ABORT("RRect should always be simple or nine-patch."); 592cb93a386Sopenharmony_ci } 593cb93a386Sopenharmony_ci // implicit is the evaluation of (x/a)^2 + (y/b)^2 - 1. 594cb93a386Sopenharmony_ci fragBuilder->codeAppend("half implicit = half(dot(Z, dxy) - 1.0);"); 595cb93a386Sopenharmony_ci // grad_dot is the squared length of the gradient of the implicit. 596cb93a386Sopenharmony_ci fragBuilder->codeAppend("half grad_dot = half(4.0 * dot(Z, Z));"); 597cb93a386Sopenharmony_ci // avoid calling inversesqrt on zero. 598cb93a386Sopenharmony_ci fragBuilder->codeAppend("grad_dot = max(grad_dot, 1.0e-4);"); 599cb93a386Sopenharmony_ci fragBuilder->codeAppend("half approx_dist = implicit * half(inversesqrt(grad_dot));"); 600cb93a386Sopenharmony_ci if (scaleName) { 601cb93a386Sopenharmony_ci fragBuilder->codeAppendf("approx_dist *= %s.x;", scaleName); 602cb93a386Sopenharmony_ci } 603cb93a386Sopenharmony_ci 604cb93a386Sopenharmony_ci if (erre.fEdgeType == GrClipEdgeType::kFillAA) { 605cb93a386Sopenharmony_ci fragBuilder->codeAppend("half alpha = clamp(0.5 - approx_dist, 0.0, 1.0);"); 606cb93a386Sopenharmony_ci } else { 607cb93a386Sopenharmony_ci fragBuilder->codeAppend("half alpha = clamp(0.5 + approx_dist, 0.0, 1.0);"); 608cb93a386Sopenharmony_ci } 609cb93a386Sopenharmony_ci 610cb93a386Sopenharmony_ci SkString inputSample = this->invokeChild(/*childIndex=*/0, args); 611cb93a386Sopenharmony_ci 612cb93a386Sopenharmony_ci fragBuilder->codeAppendf("return %s * alpha;", inputSample.c_str()); 613cb93a386Sopenharmony_ci} 614cb93a386Sopenharmony_ci 615cb93a386Sopenharmony_civoid EllipticalRRectEffect::Impl::onSetData(const GrGLSLProgramDataManager& pdman, 616cb93a386Sopenharmony_ci const GrFragmentProcessor& effect) { 617cb93a386Sopenharmony_ci const EllipticalRRectEffect& erre = effect.cast<EllipticalRRectEffect>(); 618cb93a386Sopenharmony_ci const SkRRect& rrect = erre.fRRect; 619cb93a386Sopenharmony_ci // If we're using a scale factor to work around precision issues, choose the largest radius 620cb93a386Sopenharmony_ci // as the scale factor. The inv radii need to be pre-adjusted by the scale factor. 621cb93a386Sopenharmony_ci if (rrect != fPrevRRect) { 622cb93a386Sopenharmony_ci SkRect rect = rrect.getBounds(); 623cb93a386Sopenharmony_ci const SkVector& r0 = rrect.radii(SkRRect::kUpperLeft_Corner); 624cb93a386Sopenharmony_ci SkASSERT(r0.fX >= kRadiusMin); 625cb93a386Sopenharmony_ci SkASSERT(r0.fY >= kRadiusMin); 626cb93a386Sopenharmony_ci switch (rrect.getType()) { 627cb93a386Sopenharmony_ci case SkRRect::kSimple_Type: 628cb93a386Sopenharmony_ci rect.inset(r0.fX, r0.fY); 629cb93a386Sopenharmony_ci if (fScaleUniform.isValid()) { 630cb93a386Sopenharmony_ci if (r0.fX > r0.fY) { 631cb93a386Sopenharmony_ci pdman.set2f(fInvRadiiSqdUniform, 1.f, (r0.fX * r0.fX) / (r0.fY * r0.fY)); 632cb93a386Sopenharmony_ci pdman.set2f(fScaleUniform, r0.fX, 1.f / r0.fX); 633cb93a386Sopenharmony_ci } else { 634cb93a386Sopenharmony_ci pdman.set2f(fInvRadiiSqdUniform, (r0.fY * r0.fY) / (r0.fX * r0.fX), 1.f); 635cb93a386Sopenharmony_ci pdman.set2f(fScaleUniform, r0.fY, 1.f / r0.fY); 636cb93a386Sopenharmony_ci } 637cb93a386Sopenharmony_ci } else { 638cb93a386Sopenharmony_ci pdman.set2f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX), 639cb93a386Sopenharmony_ci 1.f / (r0.fY * r0.fY)); 640cb93a386Sopenharmony_ci } 641cb93a386Sopenharmony_ci break; 642cb93a386Sopenharmony_ci case SkRRect::kNinePatch_Type: { 643cb93a386Sopenharmony_ci const SkVector& r1 = rrect.radii(SkRRect::kLowerRight_Corner); 644cb93a386Sopenharmony_ci SkASSERT(r1.fX >= kRadiusMin); 645cb93a386Sopenharmony_ci SkASSERT(r1.fY >= kRadiusMin); 646cb93a386Sopenharmony_ci rect.fLeft += r0.fX; 647cb93a386Sopenharmony_ci rect.fTop += r0.fY; 648cb93a386Sopenharmony_ci rect.fRight -= r1.fX; 649cb93a386Sopenharmony_ci rect.fBottom -= r1.fY; 650cb93a386Sopenharmony_ci if (fScaleUniform.isValid()) { 651cb93a386Sopenharmony_ci float scale = std::max(std::max(r0.fX, r0.fY), std::max(r1.fX, r1.fY)); 652cb93a386Sopenharmony_ci float scaleSqd = scale * scale; 653cb93a386Sopenharmony_ci pdman.set4f(fInvRadiiSqdUniform, scaleSqd / (r0.fX * r0.fX), 654cb93a386Sopenharmony_ci scaleSqd / (r0.fY * r0.fY), 655cb93a386Sopenharmony_ci scaleSqd / (r1.fX * r1.fX), 656cb93a386Sopenharmony_ci scaleSqd / (r1.fY * r1.fY)); 657cb93a386Sopenharmony_ci pdman.set2f(fScaleUniform, scale, 1.f / scale); 658cb93a386Sopenharmony_ci } else { 659cb93a386Sopenharmony_ci pdman.set4f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX), 660cb93a386Sopenharmony_ci 1.f / (r0.fY * r0.fY), 661cb93a386Sopenharmony_ci 1.f / (r1.fX * r1.fX), 662cb93a386Sopenharmony_ci 1.f / (r1.fY * r1.fY)); 663cb93a386Sopenharmony_ci } 664cb93a386Sopenharmony_ci break; 665cb93a386Sopenharmony_ci } 666cb93a386Sopenharmony_ci default: 667cb93a386Sopenharmony_ci SK_ABORT("RRect should always be simple or nine-patch."); 668cb93a386Sopenharmony_ci } 669cb93a386Sopenharmony_ci pdman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom); 670cb93a386Sopenharmony_ci fPrevRRect = rrect; 671cb93a386Sopenharmony_ci } 672cb93a386Sopenharmony_ci} 673cb93a386Sopenharmony_ci 674cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////////////////////////// 675cb93a386Sopenharmony_ci 676cb93a386Sopenharmony_ciSkString EllipticalRRectEffect::getShaderDfxInfo() const { 677cb93a386Sopenharmony_ci SkString format; 678cb93a386Sopenharmony_ci format.printf("ShaderDfx_EllipticalRRectEffect_%d_%d", fRRect.getType(), fEdgeType); 679cb93a386Sopenharmony_ci return format; 680cb93a386Sopenharmony_ci} 681cb93a386Sopenharmony_ci 682cb93a386Sopenharmony_civoid EllipticalRRectEffect::onAddToKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { 683cb93a386Sopenharmony_ci static_assert((int)GrClipEdgeType::kLast < (1 << 3)); 684cb93a386Sopenharmony_ci b->add32(fRRect.getType() | static_cast<int>(fEdgeType) << 3); 685cb93a386Sopenharmony_ci} 686cb93a386Sopenharmony_ci 687cb93a386Sopenharmony_cistd::unique_ptr<GrFragmentProcessor::ProgramImpl> EllipticalRRectEffect::onMakeProgramImpl() const { 688cb93a386Sopenharmony_ci return std::make_unique<Impl>(); 689cb93a386Sopenharmony_ci} 690cb93a386Sopenharmony_ci 691cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////// 692cb93a386Sopenharmony_ci 693cb93a386Sopenharmony_ciGrFPResult GrRRectEffect::Make(std::unique_ptr<GrFragmentProcessor> inputFP, 694cb93a386Sopenharmony_ci GrClipEdgeType edgeType, const SkRRect& rrect, 695cb93a386Sopenharmony_ci const GrShaderCaps& caps) { 696cb93a386Sopenharmony_ci if (rrect.isRect()) { 697cb93a386Sopenharmony_ci auto fp = GrFragmentProcessor::Rect(std::move(inputFP), edgeType, rrect.getBounds()); 698cb93a386Sopenharmony_ci return GrFPSuccess(std::move(fp)); 699cb93a386Sopenharmony_ci } 700cb93a386Sopenharmony_ci 701cb93a386Sopenharmony_ci if (rrect.isOval()) { 702cb93a386Sopenharmony_ci return GrOvalEffect::Make(std::move(inputFP), edgeType, rrect.getBounds(), caps); 703cb93a386Sopenharmony_ci } 704cb93a386Sopenharmony_ci 705cb93a386Sopenharmony_ci if (rrect.isSimple()) { 706cb93a386Sopenharmony_ci if (SkRRectPriv::GetSimpleRadii(rrect).fX < kRadiusMin || 707cb93a386Sopenharmony_ci SkRRectPriv::GetSimpleRadii(rrect).fY < kRadiusMin) { 708cb93a386Sopenharmony_ci // In this case the corners are extremely close to rectangular and we collapse the 709cb93a386Sopenharmony_ci // clip to a rectangular clip. 710cb93a386Sopenharmony_ci auto fp = GrFragmentProcessor::Rect(std::move(inputFP), edgeType, rrect.getBounds()); 711cb93a386Sopenharmony_ci return GrFPSuccess(std::move(fp)); 712cb93a386Sopenharmony_ci } 713cb93a386Sopenharmony_ci if (SkRRectPriv::GetSimpleRadii(rrect).fX == SkRRectPriv::GetSimpleRadii(rrect).fY) { 714cb93a386Sopenharmony_ci return CircularRRectEffect::Make(std::move(inputFP), edgeType, 715cb93a386Sopenharmony_ci CircularRRectEffect::kAll_CornerFlags, rrect); 716cb93a386Sopenharmony_ci } else { 717cb93a386Sopenharmony_ci return EllipticalRRectEffect::Make(std::move(inputFP), edgeType, rrect); 718cb93a386Sopenharmony_ci } 719cb93a386Sopenharmony_ci } 720cb93a386Sopenharmony_ci 721cb93a386Sopenharmony_ci if (rrect.isComplex() || rrect.isNinePatch()) { 722cb93a386Sopenharmony_ci // Check for the "tab" cases - two adjacent circular corners and two square corners. 723cb93a386Sopenharmony_ci SkScalar circularRadius = 0; 724cb93a386Sopenharmony_ci uint32_t cornerFlags = 0; 725cb93a386Sopenharmony_ci 726cb93a386Sopenharmony_ci SkVector radii[4]; 727cb93a386Sopenharmony_ci bool squashedRadii = false; 728cb93a386Sopenharmony_ci for (int c = 0; c < 4; ++c) { 729cb93a386Sopenharmony_ci radii[c] = rrect.radii((SkRRect::Corner)c); 730cb93a386Sopenharmony_ci SkASSERT((0 == radii[c].fX) == (0 == radii[c].fY)); 731cb93a386Sopenharmony_ci if (0 == radii[c].fX) { 732cb93a386Sopenharmony_ci // The corner is square, so no need to squash or flag as circular. 733cb93a386Sopenharmony_ci continue; 734cb93a386Sopenharmony_ci } 735cb93a386Sopenharmony_ci if (radii[c].fX < kRadiusMin || radii[c].fY < kRadiusMin) { 736cb93a386Sopenharmony_ci radii[c].set(0, 0); 737cb93a386Sopenharmony_ci squashedRadii = true; 738cb93a386Sopenharmony_ci continue; 739cb93a386Sopenharmony_ci } 740cb93a386Sopenharmony_ci if (radii[c].fX != radii[c].fY) { 741cb93a386Sopenharmony_ci cornerFlags = ~0U; 742cb93a386Sopenharmony_ci break; 743cb93a386Sopenharmony_ci } 744cb93a386Sopenharmony_ci if (!cornerFlags) { 745cb93a386Sopenharmony_ci circularRadius = radii[c].fX; 746cb93a386Sopenharmony_ci cornerFlags = 1 << c; 747cb93a386Sopenharmony_ci } else { 748cb93a386Sopenharmony_ci if (radii[c].fX != circularRadius) { 749cb93a386Sopenharmony_ci cornerFlags = ~0U; 750cb93a386Sopenharmony_ci break; 751cb93a386Sopenharmony_ci } 752cb93a386Sopenharmony_ci cornerFlags |= 1 << c; 753cb93a386Sopenharmony_ci } 754cb93a386Sopenharmony_ci } 755cb93a386Sopenharmony_ci 756cb93a386Sopenharmony_ci switch (cornerFlags) { 757cb93a386Sopenharmony_ci case CircularRRectEffect::kAll_CornerFlags: 758cb93a386Sopenharmony_ci // This rrect should have been caught in the simple case above. Though, it would 759cb93a386Sopenharmony_ci // be correctly handled in the fallthrough code. 760cb93a386Sopenharmony_ci SkASSERT(false); 761cb93a386Sopenharmony_ci [[fallthrough]]; 762cb93a386Sopenharmony_ci case CircularRRectEffect::kTopLeft_CornerFlag: 763cb93a386Sopenharmony_ci case CircularRRectEffect::kTopRight_CornerFlag: 764cb93a386Sopenharmony_ci case CircularRRectEffect::kBottomRight_CornerFlag: 765cb93a386Sopenharmony_ci case CircularRRectEffect::kBottomLeft_CornerFlag: 766cb93a386Sopenharmony_ci case CircularRRectEffect::kLeft_CornerFlags: 767cb93a386Sopenharmony_ci case CircularRRectEffect::kTop_CornerFlags: 768cb93a386Sopenharmony_ci case CircularRRectEffect::kRight_CornerFlags: 769cb93a386Sopenharmony_ci case CircularRRectEffect::kBottom_CornerFlags: { 770cb93a386Sopenharmony_ci SkTCopyOnFirstWrite<SkRRect> rr(rrect); 771cb93a386Sopenharmony_ci if (squashedRadii) { 772cb93a386Sopenharmony_ci rr.writable()->setRectRadii(rrect.getBounds(), radii); 773cb93a386Sopenharmony_ci } 774cb93a386Sopenharmony_ci return CircularRRectEffect::Make(std::move(inputFP), edgeType, cornerFlags, *rr); 775cb93a386Sopenharmony_ci } 776cb93a386Sopenharmony_ci case CircularRRectEffect::kNone_CornerFlags: { 777cb93a386Sopenharmony_ci auto fp = 778cb93a386Sopenharmony_ci GrFragmentProcessor::Rect(std::move(inputFP), edgeType, rrect.getBounds()); 779cb93a386Sopenharmony_ci return GrFPSuccess(std::move(fp)); 780cb93a386Sopenharmony_ci } 781cb93a386Sopenharmony_ci default: { 782cb93a386Sopenharmony_ci const SkVector ul = rrect.radii(SkRRect::kUpperLeft_Corner); 783cb93a386Sopenharmony_ci const SkVector lr = rrect.radii(SkRRect::kLowerRight_Corner); 784cb93a386Sopenharmony_ci if (rrect.isNinePatch() && 785cb93a386Sopenharmony_ci ul.fX >= kRadiusMin && 786cb93a386Sopenharmony_ci ul.fY >= kRadiusMin && 787cb93a386Sopenharmony_ci lr.fX >= kRadiusMin && 788cb93a386Sopenharmony_ci lr.fY >= kRadiusMin) { 789cb93a386Sopenharmony_ci return EllipticalRRectEffect::Make(std::move(inputFP), edgeType, rrect); 790cb93a386Sopenharmony_ci } 791cb93a386Sopenharmony_ci return GrFPFailure(std::move(inputFP)); 792cb93a386Sopenharmony_ci } 793cb93a386Sopenharmony_ci } 794cb93a386Sopenharmony_ci } 795cb93a386Sopenharmony_ci return GrFPFailure(std::move(inputFP)); 796cb93a386Sopenharmony_ci} 797