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