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