gfx/skia/trunk/src/gpu/effects/GrRRectEffect.cpp

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:1303b604defb
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 "GrRRectEffect.h"
9
10 #include "gl/GrGLEffect.h"
11 #include "gl/GrGLSL.h"
12 #include "GrTBackendEffectFactory.h"
13
14 #include "SkRRect.h"
15
16 class GLCircularRRectEffect;
17
18 class CircularRRectEffect : public GrEffect {
19 public:
20 // This effect only supports circular corner rrects where the radius is >= kRadiusMin.
21 static const SkScalar kRadiusMin;
22
23 enum CornerFlags {
24 kTopLeft_CornerFlag = (1 << SkRRect::kUpperLeft_Corner),
25 kTopRight_CornerFlag = (1 << SkRRect::kUpperRight_Corner),
26 kBottomRight_CornerFlag = (1 << SkRRect::kLowerRight_Corner),
27 kBottomLeft_CornerFlag = (1 << SkRRect::kLowerLeft_Corner),
28
29 kLeft_CornerFlags = kTopLeft_CornerFlag | kBottomLeft_CornerFlag,
30 kTop_CornerFlags = kTopLeft_CornerFlag | kTopRight_CornerFlag,
31 kRight_CornerFlags = kTopRight_CornerFlag | kBottomRight_CornerFlag,
32 kBottom_CornerFlags = kBottomLeft_CornerFlag | kBottomRight_CornerFlag,
33
34 kAll_CornerFlags = kTopLeft_CornerFlag | kTopRight_CornerFlag |
35 kBottomLeft_CornerFlag | kBottomRight_CornerFlag,
36
37 };
38
39 // The flags are used to indicate which corners are circluar (unflagged corners are assumed to
40 // be square).
41 static GrEffectRef* Create(GrEffectEdgeType, uint32_t circularCornerFlags, const SkRRect&);
42
43 virtual ~CircularRRectEffect() {};
44 static const char* Name() { return "CircularRRect"; }
45
46 const SkRRect& getRRect() const { return fRRect; }
47
48 uint32_t getCircularCornerFlags() const { return fCircularCornerFlags; }
49
50 GrEffectEdgeType getEdgeType() const { return fEdgeType; }
51
52 typedef GLCircularRRectEffect GLEffect;
53
54 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
55
56 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
57
58 private:
59 CircularRRectEffect(GrEffectEdgeType, uint32_t circularCornerFlags, const SkRRect&);
60
61 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE;
62
63 SkRRect fRRect;
64 GrEffectEdgeType fEdgeType;
65 uint32_t fCircularCornerFlags;
66
67 GR_DECLARE_EFFECT_TEST;
68
69 typedef GrEffect INHERITED;
70 };
71
72 const SkScalar CircularRRectEffect::kRadiusMin = 0.5f;
73
74 GrEffectRef* CircularRRectEffect::Create(GrEffectEdgeType edgeType,
75 uint32_t circularCornerFlags,
76 const SkRRect& rrect) {
77 SkASSERT(kFillAA_GrEffectEdgeType == edgeType || kInverseFillAA_GrEffectEdgeType == edgeType);
78 return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(CircularRRectEffect,
79 (edgeType, circularCornerFlags, rrect))));
80 }
81
82 void CircularRRectEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
83 *validFlags = 0;
84 }
85
86 const GrBackendEffectFactory& CircularRRectEffect::getFactory() const {
87 return GrTBackendEffectFactory<CircularRRectEffect>::getInstance();
88 }
89
90 CircularRRectEffect::CircularRRectEffect(GrEffectEdgeType edgeType, uint32_t circularCornerFlags,
91 const SkRRect& rrect)
92 : fRRect(rrect)
93 , fEdgeType(edgeType)
94 , fCircularCornerFlags(circularCornerFlags) {
95 this->setWillReadFragmentPosition();
96 }
97
98 bool CircularRRectEffect::onIsEqual(const GrEffect& other) const {
99 const CircularRRectEffect& crre = CastEffect<CircularRRectEffect>(other);
100 // The corner flags are derived from fRRect, so no need to check them.
101 return fEdgeType == crre.fEdgeType && fRRect == crre.fRRect;
102 }
103
104 //////////////////////////////////////////////////////////////////////////////
105
106 GR_DEFINE_EFFECT_TEST(CircularRRectEffect);
107
108 GrEffectRef* CircularRRectEffect::TestCreate(SkRandom* random,
109 GrContext*,
110 const GrDrawTargetCaps& caps,
111 GrTexture*[]) {
112 SkScalar w = random->nextRangeScalar(20.f, 1000.f);
113 SkScalar h = random->nextRangeScalar(20.f, 1000.f);
114 SkScalar r = random->nextRangeF(kRadiusMin, 9.f);
115 SkRRect rrect;
116 rrect.setRectXY(SkRect::MakeWH(w, h), r, r);
117 GrEffectRef* effect;
118 do {
119 GrEffectEdgeType et = (GrEffectEdgeType)random->nextULessThan(kGrEffectEdgeTypeCnt);
120 effect = GrRRectEffect::Create(et, rrect);
121 } while (NULL == effect);
122 return effect;
123 }
124
125 //////////////////////////////////////////////////////////////////////////////
126
127 class GLCircularRRectEffect : public GrGLEffect {
128 public:
129 GLCircularRRectEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
130
131 virtual void emitCode(GrGLShaderBuilder* builder,
132 const GrDrawEffect& drawEffect,
133 EffectKey key,
134 const char* outputColor,
135 const char* inputColor,
136 const TransformedCoordsArray&,
137 const TextureSamplerArray&) SK_OVERRIDE;
138
139 static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
140
141 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
142
143 private:
144 GrGLUniformManager::UniformHandle fInnerRectUniform;
145 GrGLUniformManager::UniformHandle fRadiusPlusHalfUniform;
146 SkRRect fPrevRRect;
147 typedef GrGLEffect INHERITED;
148 };
149
150 GLCircularRRectEffect::GLCircularRRectEffect(const GrBackendEffectFactory& factory,
151 const GrDrawEffect& drawEffect)
152 : INHERITED (factory) {
153 fPrevRRect.setEmpty();
154 }
155
156 void GLCircularRRectEffect::emitCode(GrGLShaderBuilder* builder,
157 const GrDrawEffect& drawEffect,
158 EffectKey key,
159 const char* outputColor,
160 const char* inputColor,
161 const TransformedCoordsArray&,
162 const TextureSamplerArray& samplers) {
163 const CircularRRectEffect& crre = drawEffect.castEffect<CircularRRectEffect>();
164 const char *rectName;
165 const char *radiusPlusHalfName;
166 // The inner rect is the rrect bounds inset by the radius. Its left, top, right, and bottom
167 // edges correspond to components x, y, z, and w, respectively. When a side of the rrect has
168 // only rectangular corners, that side's value corresponds to the rect edge's value outset by
169 // half a pixel.
170 fInnerRectUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
171 kVec4f_GrSLType,
172 "innerRect",
173 &rectName);
174 fRadiusPlusHalfUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
175 kFloat_GrSLType,
176 "radiusPlusHalf",
177 &radiusPlusHalfName);
178 const char* fragmentPos = builder->fragmentPosition();
179 // At each quarter-circle corner we compute a vector that is the offset of the fragment position
180 // from the circle center. The vector is pinned in x and y to be in the quarter-plane relevant
181 // to that corner. This means that points near the interior near the rrect top edge will have
182 // a vector that points straight up for both the TL left and TR corners. Computing an
183 // alpha from this vector at either the TR or TL corner will give the correct result. Similarly,
184 // fragments near the other three edges will get the correct AA. Fragments in the interior of
185 // the rrect will have a (0,0) vector at all four corners. So long as the radius > 0.5 they will
186 // correctly produce an alpha value of 1 at all four corners. We take the min of all the alphas.
187 // The code below is a simplified version of the above that performs maxs on the vector
188 // components before computing distances and alpha values so that only one distance computation
189 // need be computed to determine the min alpha.
190 //
191 // For the cases where one half of the rrect is rectangular we drop one of the x or y
192 // computations, compute a separate rect edge alpha for the rect side, and mul the two computed
193 // alphas together.
194 switch (crre.getCircularCornerFlags()) {
195 case CircularRRectEffect::kAll_CornerFlags:
196 builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
197 builder->fsCodeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
198 builder->fsCodeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n");
199 builder->fsCodeAppendf("\t\tfloat alpha = clamp(%s - length(dxy), 0.0, 1.0);\n",
200 radiusPlusHalfName);
201 break;
202 case CircularRRectEffect::kTopLeft_CornerFlag:
203 builder->fsCodeAppendf("\t\tvec2 dxy = max(%s.xy - %s.xy, 0.0);\n",
204 rectName, fragmentPos);
205 builder->fsCodeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n",
206 rectName, fragmentPos);
207 builder->fsCodeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n",
208 rectName, fragmentPos);
209 builder->fsCodeAppendf("\t\tfloat alpha = bottomAlpha * rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
210 radiusPlusHalfName);
211 break;
212 case CircularRRectEffect::kTopRight_CornerFlag:
213 builder->fsCodeAppendf("\t\tvec2 dxy = max(vec2(%s.x - %s.z, %s.y - %s.y), 0.0);\n",
214 fragmentPos, rectName, rectName, fragmentPos);
215 builder->fsCodeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n",
216 fragmentPos, rectName);
217 builder->fsCodeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n",
218 rectName, fragmentPos);
219 builder->fsCodeAppendf("\t\tfloat alpha = bottomAlpha * leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
220 radiusPlusHalfName);
221 break;
222 case CircularRRectEffect::kBottomRight_CornerFlag:
223 builder->fsCodeAppendf("\t\tvec2 dxy = max(%s.xy - %s.zw, 0.0);\n",
224 fragmentPos, rectName);
225 builder->fsCodeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n",
226 fragmentPos, rectName);
227 builder->fsCodeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n",
228 fragmentPos, rectName);
229 builder->fsCodeAppendf("\t\tfloat alpha = topAlpha * leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
230 radiusPlusHalfName);
231 break;
232 case CircularRRectEffect::kBottomLeft_CornerFlag:
233 builder->fsCodeAppendf("\t\tvec2 dxy = max(vec2(%s.x - %s.x, %s.y - %s.w), 0.0);\n",
234 rectName, fragmentPos, fragmentPos, rectName);
235 builder->fsCodeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n",
236 rectName, fragmentPos);
237 builder->fsCodeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n",
238 fragmentPos, rectName);
239 builder->fsCodeAppendf("\t\tfloat alpha = topAlpha * rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
240 radiusPlusHalfName);
241 break;
242 case CircularRRectEffect::kLeft_CornerFlags:
243 builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
244 builder->fsCodeAppendf("\t\tfloat dy1 = %s.y - %s.w;\n", fragmentPos, rectName);
245 builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(dxy0.x, max(dxy0.y, dy1)), 0.0);\n");
246 builder->fsCodeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n",
247 rectName, fragmentPos);
248 builder->fsCodeAppendf("\t\tfloat alpha = rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
249 radiusPlusHalfName);
250 break;
251 case CircularRRectEffect::kTop_CornerFlags:
252 builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
253 builder->fsCodeAppendf("\t\tfloat dx1 = %s.x - %s.z;\n", fragmentPos, rectName);
254 builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(max(dxy0.x, dx1), dxy0.y), 0.0);\n");
255 builder->fsCodeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n",
256 rectName, fragmentPos);
257 builder->fsCodeAppendf("\t\tfloat alpha = bottomAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
258 radiusPlusHalfName);
259 break;
260 case CircularRRectEffect::kRight_CornerFlags:
261 builder->fsCodeAppendf("\t\tfloat dy0 = %s.y - %s.y;\n", rectName, fragmentPos);
262 builder->fsCodeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
263 builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(dxy1.x, max(dy0, dxy1.y)), 0.0);\n");
264 builder->fsCodeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n",
265 fragmentPos, rectName);
266 builder->fsCodeAppendf("\t\tfloat alpha = leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
267 radiusPlusHalfName);
268 break;
269 case CircularRRectEffect::kBottom_CornerFlags:
270 builder->fsCodeAppendf("\t\tfloat dx0 = %s.x - %s.x;\n", rectName, fragmentPos);
271 builder->fsCodeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
272 builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(max(dx0, dxy1.x), dxy1.y), 0.0);\n");
273 builder->fsCodeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n",
274 fragmentPos, rectName);
275 builder->fsCodeAppendf("\t\tfloat alpha = topAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
276 radiusPlusHalfName);
277 break;
278 }
279
280 if (kInverseFillAA_GrEffectEdgeType == crre.getEdgeType()) {
281 builder->fsCodeAppend("\t\talpha = 1.0 - alpha;\n");
282 }
283
284 builder->fsCodeAppendf("\t\t%s = %s;\n", outputColor,
285 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str());
286 }
287
288 GrGLEffect::EffectKey GLCircularRRectEffect::GenKey(const GrDrawEffect& drawEffect,
289 const GrGLCaps&) {
290 const CircularRRectEffect& crre = drawEffect.castEffect<CircularRRectEffect>();
291 GR_STATIC_ASSERT(kGrEffectEdgeTypeCnt <= 8);
292 return (crre.getCircularCornerFlags() << 3) | crre.getEdgeType();
293 }
294
295 void GLCircularRRectEffect::setData(const GrGLUniformManager& uman,
296 const GrDrawEffect& drawEffect) {
297 const CircularRRectEffect& crre = drawEffect.castEffect<CircularRRectEffect>();
298 const SkRRect& rrect = crre.getRRect();
299 if (rrect != fPrevRRect) {
300 SkRect rect = rrect.getBounds();
301 SkScalar radius = 0;
302 switch (crre.getCircularCornerFlags()) {
303 case CircularRRectEffect::kAll_CornerFlags:
304 SkASSERT(rrect.isSimpleCircular());
305 radius = rrect.getSimpleRadii().fX;
306 SkASSERT(radius >= CircularRRectEffect::kRadiusMin);
307 rect.inset(radius, radius);
308 break;
309 case CircularRRectEffect::kTopLeft_CornerFlag:
310 radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX;
311 rect.fLeft += radius;
312 rect.fTop += radius;
313 rect.fRight += 0.5f;
314 rect.fBottom += 0.5f;
315 break;
316 case CircularRRectEffect::kTopRight_CornerFlag:
317 radius = rrect.radii(SkRRect::kUpperRight_Corner).fX;
318 rect.fLeft -= 0.5f;
319 rect.fTop += radius;
320 rect.fRight -= radius;
321 rect.fBottom += 0.5f;
322 break;
323 case CircularRRectEffect::kBottomRight_CornerFlag:
324 radius = rrect.radii(SkRRect::kLowerRight_Corner).fX;
325 rect.fLeft -= 0.5f;
326 rect.fTop -= 0.5f;
327 rect.fRight -= radius;
328 rect.fBottom -= radius;
329 break;
330 case CircularRRectEffect::kBottomLeft_CornerFlag:
331 radius = rrect.radii(SkRRect::kLowerLeft_Corner).fX;
332 rect.fLeft += radius;
333 rect.fTop -= 0.5f;
334 rect.fRight += 0.5f;
335 rect.fBottom -= radius;
336 break;
337 case CircularRRectEffect::kLeft_CornerFlags:
338 radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX;
339 rect.fLeft += radius;
340 rect.fTop += radius;
341 rect.fRight += 0.5f;
342 rect.fBottom -= radius;
343 break;
344 case CircularRRectEffect::kTop_CornerFlags:
345 radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX;
346 rect.fLeft += radius;
347 rect.fTop += radius;
348 rect.fRight -= radius;
349 rect.fBottom += 0.5f;
350 break;
351 case CircularRRectEffect::kRight_CornerFlags:
352 radius = rrect.radii(SkRRect::kUpperRight_Corner).fX;
353 rect.fLeft -= 0.5f;
354 rect.fTop += radius;
355 rect.fRight -= radius;
356 rect.fBottom -= radius;
357 break;
358 case CircularRRectEffect::kBottom_CornerFlags:
359 radius = rrect.radii(SkRRect::kLowerLeft_Corner).fX;
360 rect.fLeft += radius;
361 rect.fTop -= 0.5f;
362 rect.fRight -= radius;
363 rect.fBottom -= radius;
364 break;
365 default:
366 GrCrash("Should have been one of the above cases.");
367 }
368 uman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
369 uman.set1f(fRadiusPlusHalfUniform, radius + 0.5f);
370 fPrevRRect = rrect;
371 }
372 }
373
374 //////////////////////////////////////////////////////////////////////////////
375
376 class GLEllipticalRRectEffect;
377
378 class EllipticalRRectEffect : public GrEffect {
379 public:
380 // This effect currently works for these two classifications of SkRRects
381 enum RRectType {
382 kSimple_RRectType, // SkRRect::kSimple_Type
383 kNinePatch_RRectType, // The two left x radii are the same, the two
384 // top y radii are the same, etc.
385 };
386
387 // This effect only supports rrects where the radii are >= kRadiusMin.
388 static const SkScalar kRadiusMin;
389
390 static GrEffectRef* Create(GrEffectEdgeType, RRectType, const SkRRect&);
391
392 virtual ~EllipticalRRectEffect() {};
393 static const char* Name() { return "EllipticalRRect"; }
394
395 const SkRRect& getRRect() const { return fRRect; }
396
397 RRectType getRRectType() const { return fRRectType; }
398
399 GrEffectEdgeType getEdgeType() const { return fEdgeType; }
400
401 typedef GLEllipticalRRectEffect GLEffect;
402
403 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
404
405 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
406
407 private:
408 EllipticalRRectEffect(GrEffectEdgeType, RRectType, const SkRRect&);
409
410 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE;
411
412 SkRRect fRRect;
413 RRectType fRRectType;
414 GrEffectEdgeType fEdgeType;
415
416 GR_DECLARE_EFFECT_TEST;
417
418 typedef GrEffect INHERITED;
419 };
420
421 const SkScalar EllipticalRRectEffect::kRadiusMin = 0.5f;
422
423 GrEffectRef* EllipticalRRectEffect::Create(GrEffectEdgeType edgeType,
424 RRectType rrType,
425 const SkRRect& rrect) {
426 SkASSERT(kFillAA_GrEffectEdgeType == edgeType || kInverseFillAA_GrEffectEdgeType == edgeType);
427 return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(EllipticalRRectEffect, (edgeType, rrType,
428 rrect))));
429 }
430
431 void EllipticalRRectEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
432 *validFlags = 0;
433 }
434
435 const GrBackendEffectFactory& EllipticalRRectEffect::getFactory() const {
436 return GrTBackendEffectFactory<EllipticalRRectEffect>::getInstance();
437 }
438
439 EllipticalRRectEffect::EllipticalRRectEffect(GrEffectEdgeType edgeType, RRectType rrType,
440 const SkRRect& rrect)
441 : fRRect(rrect)
442 , fRRectType(rrType)
443 , fEdgeType(edgeType){
444 this->setWillReadFragmentPosition();
445 }
446
447 bool EllipticalRRectEffect::onIsEqual(const GrEffect& other) const {
448 const EllipticalRRectEffect& erre = CastEffect<EllipticalRRectEffect>(other);
449 // No need to check fRRectType as it is derived from fRRect.
450 return fEdgeType == erre.fEdgeType && fRRect == erre.fRRect;
451 }
452
453 //////////////////////////////////////////////////////////////////////////////
454
455 GR_DEFINE_EFFECT_TEST(EllipticalRRectEffect);
456
457 GrEffectRef* EllipticalRRectEffect::TestCreate(SkRandom* random,
458 GrContext*,
459 const GrDrawTargetCaps& caps,
460 GrTexture*[]) {
461 SkScalar w = random->nextRangeScalar(20.f, 1000.f);
462 SkScalar h = random->nextRangeScalar(20.f, 1000.f);
463 SkVector r[4];
464 r[SkRRect::kUpperLeft_Corner].fX = random->nextRangeF(kRadiusMin, 9.f);
465 // ensure at least one corner really is elliptical
466 do {
467 r[SkRRect::kUpperLeft_Corner].fY = random->nextRangeF(kRadiusMin, 9.f);
468 } while (r[SkRRect::kUpperLeft_Corner].fY == r[SkRRect::kUpperLeft_Corner].fX);
469
470 SkRRect rrect;
471 if (random->nextBool()) {
472 // half the time create a four-radii rrect.
473 r[SkRRect::kLowerRight_Corner].fX = random->nextRangeF(kRadiusMin, 9.f);
474 r[SkRRect::kLowerRight_Corner].fY = random->nextRangeF(kRadiusMin, 9.f);
475
476 r[SkRRect::kUpperRight_Corner].fX = r[SkRRect::kLowerRight_Corner].fX;
477 r[SkRRect::kUpperRight_Corner].fY = r[SkRRect::kUpperLeft_Corner].fY;
478
479 r[SkRRect::kLowerLeft_Corner].fX = r[SkRRect::kUpperLeft_Corner].fX;
480 r[SkRRect::kLowerLeft_Corner].fY = r[SkRRect::kLowerRight_Corner].fY;
481
482 rrect.setRectRadii(SkRect::MakeWH(w, h), r);
483 } else {
484 rrect.setRectXY(SkRect::MakeWH(w, h), r[SkRRect::kUpperLeft_Corner].fX,
485 r[SkRRect::kUpperLeft_Corner].fY);
486 }
487 GrEffectRef* effect;
488 do {
489 GrEffectEdgeType et = (GrEffectEdgeType)random->nextULessThan(kGrEffectEdgeTypeCnt);
490 effect = GrRRectEffect::Create(et, rrect);
491 } while (NULL == effect);
492 return effect;
493 }
494
495 //////////////////////////////////////////////////////////////////////////////
496
497 class GLEllipticalRRectEffect : public GrGLEffect {
498 public:
499 GLEllipticalRRectEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
500
501 virtual void emitCode(GrGLShaderBuilder* builder,
502 const GrDrawEffect& drawEffect,
503 EffectKey key,
504 const char* outputColor,
505 const char* inputColor,
506 const TransformedCoordsArray&,
507 const TextureSamplerArray&) SK_OVERRIDE;
508
509 static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
510
511 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
512
513 private:
514 GrGLUniformManager::UniformHandle fInnerRectUniform;
515 GrGLUniformManager::UniformHandle fInvRadiiSqdUniform;
516 SkRRect fPrevRRect;
517 typedef GrGLEffect INHERITED;
518 };
519
520 GLEllipticalRRectEffect::GLEllipticalRRectEffect(const GrBackendEffectFactory& factory,
521 const GrDrawEffect& drawEffect)
522 : INHERITED (factory) {
523 fPrevRRect.setEmpty();
524 }
525
526 void GLEllipticalRRectEffect::emitCode(GrGLShaderBuilder* builder,
527 const GrDrawEffect& drawEffect,
528 EffectKey key,
529 const char* outputColor,
530 const char* inputColor,
531 const TransformedCoordsArray&,
532 const TextureSamplerArray& samplers) {
533 const EllipticalRRectEffect& erre = drawEffect.castEffect<EllipticalRRectEffect>();
534 const char *rectName;
535 // The inner rect is the rrect bounds inset by the x/y radii
536 fInnerRectUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
537 kVec4f_GrSLType,
538 "innerRect",
539 &rectName);
540 const char* fragmentPos = builder->fragmentPosition();
541 // At each quarter-ellipse corner we compute a vector that is the offset of the fragment pos
542 // to the ellipse center. The vector is pinned in x and y to be in the quarter-plane relevant
543 // to that corner. This means that points near the interior near the rrect top edge will have
544 // a vector that points straight up for both the TL left and TR corners. Computing an
545 // alpha from this vector at either the TR or TL corner will give the correct result. Similarly,
546 // fragments near the other three edges will get the correct AA. Fragments in the interior of
547 // the rrect will have a (0,0) vector at all four corners. So long as the radii > 0.5 they will
548 // correctly produce an alpha value of 1 at all four corners. We take the min of all the alphas.
549 // The code below is a simplified version of the above that performs maxs on the vector
550 // components before computing distances and alpha values so that only one distance computation
551 // need be computed to determine the min alpha.
552 builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
553 builder->fsCodeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
554 switch (erre.getRRectType()) {
555 case EllipticalRRectEffect::kSimple_RRectType: {
556 const char *invRadiiXYSqdName;
557 fInvRadiiSqdUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
558 kVec2f_GrSLType,
559 "invRadiiXY",
560 &invRadiiXYSqdName);
561 builder->fsCodeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n");
562 // Z is the x/y offsets divided by squared radii.
563 builder->fsCodeAppendf("\t\tvec2 Z = dxy * %s;\n", invRadiiXYSqdName);
564 break;
565 }
566 case EllipticalRRectEffect::kNinePatch_RRectType: {
567 const char *invRadiiLTRBSqdName;
568 fInvRadiiSqdUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
569 kVec4f_GrSLType,
570 "invRadiiLTRB",
571 &invRadiiLTRBSqdName);
572 builder->fsCodeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n");
573 // Z is the x/y offsets divided by squared radii. We only care about the (at most) one
574 // corner where both the x and y offsets are positive, hence the maxes. (The inverse
575 // squared radii will always be positive.)
576 builder->fsCodeAppendf("\t\tvec2 Z = max(max(dxy0 * %s.xy, dxy1 * %s.zw), 0.0);\n",
577 invRadiiLTRBSqdName, invRadiiLTRBSqdName);
578 break;
579 }
580 }
581 // implicit is the evaluation of (x/a)^2 + (y/b)^2 - 1.
582 builder->fsCodeAppend("\t\tfloat implicit = dot(Z, dxy) - 1.0;\n");
583 // grad_dot is the squared length of the gradient of the implicit.
584 builder->fsCodeAppendf("\t\tfloat grad_dot = 4.0 * dot(Z, Z);\n");
585 builder->fsCodeAppend("\t\tgrad_dot = max(grad_dot, 1.0e-4);\n");
586 builder->fsCodeAppendf("\t\tfloat approx_dist = implicit * inversesqrt(grad_dot);\n");
587
588 if (kFillAA_GrEffectEdgeType == erre.getEdgeType()) {
589 builder->fsCodeAppend("\t\tfloat alpha = clamp(0.5 - approx_dist, 0.0, 1.0);\n");
590 } else {
591 builder->fsCodeAppend("\t\tfloat alpha = clamp(0.5 + approx_dist, 0.0, 1.0);\n");
592 }
593
594 builder->fsCodeAppendf("\t\t%s = %s;\n", outputColor,
595 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str());
596 }
597
598 GrGLEffect::EffectKey GLEllipticalRRectEffect::GenKey(const GrDrawEffect& drawEffect,
599 const GrGLCaps&) {
600 const EllipticalRRectEffect& erre = drawEffect.castEffect<EllipticalRRectEffect>();
601 GR_STATIC_ASSERT(kLast_GrEffectEdgeType < (1 << 3));
602 return erre.getRRectType() | erre.getEdgeType() << 3;
603 }
604
605 void GLEllipticalRRectEffect::setData(const GrGLUniformManager& uman,
606 const GrDrawEffect& drawEffect) {
607 const EllipticalRRectEffect& erre = drawEffect.castEffect<EllipticalRRectEffect>();
608 const SkRRect& rrect = erre.getRRect();
609 if (rrect != fPrevRRect) {
610 SkRect rect = rrect.getBounds();
611 const SkVector& r0 = rrect.radii(SkRRect::kUpperLeft_Corner);
612 SkASSERT(r0.fX >= EllipticalRRectEffect::kRadiusMin);
613 SkASSERT(r0.fY >= EllipticalRRectEffect::kRadiusMin);
614 switch (erre.getRRectType()) {
615 case EllipticalRRectEffect::kSimple_RRectType:
616 rect.inset(r0.fX, r0.fY);
617 uman.set2f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX),
618 1.f / (r0.fY * r0.fY));
619 break;
620 case EllipticalRRectEffect::kNinePatch_RRectType: {
621 const SkVector& r1 = rrect.radii(SkRRect::kLowerRight_Corner);
622 SkASSERT(r1.fX >= EllipticalRRectEffect::kRadiusMin);
623 SkASSERT(r1.fY >= EllipticalRRectEffect::kRadiusMin);
624 rect.fLeft += r0.fX;
625 rect.fTop += r0.fY;
626 rect.fRight -= r1.fX;
627 rect.fBottom -= r1.fY;
628 uman.set4f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX),
629 1.f / (r0.fY * r0.fY),
630 1.f / (r1.fX * r1.fX),
631 1.f / (r1.fY * r1.fY));
632 break;
633 }
634 }
635 uman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
636 fPrevRRect = rrect;
637 }
638 }
639
640 //////////////////////////////////////////////////////////////////////////////
641
642 GrEffectRef* GrRRectEffect::Create(GrEffectEdgeType edgeType, const SkRRect& rrect) {
643 if (kFillAA_GrEffectEdgeType != edgeType && kInverseFillAA_GrEffectEdgeType != edgeType) {
644 return NULL;
645 }
646 uint32_t cornerFlags;
647 if (rrect.isSimple()) {
648 if (rrect.getSimpleRadii().fX == rrect.getSimpleRadii().fY) {
649 if (rrect.getSimpleRadii().fX < CircularRRectEffect::kRadiusMin) {
650 return NULL;
651 }
652 cornerFlags = CircularRRectEffect::kAll_CornerFlags;
653 } else {
654 if (rrect.getSimpleRadii().fX < EllipticalRRectEffect::kRadiusMin ||
655 rrect.getSimpleRadii().fY < EllipticalRRectEffect::kRadiusMin) {
656 return NULL;
657 }
658 return EllipticalRRectEffect::Create(edgeType,
659 EllipticalRRectEffect::kSimple_RRectType, rrect);
660 }
661 } else if (rrect.isComplex()) {
662 // Check for the "tab" cases - two adjacent circular corners and two square corners.
663 SkScalar radius = 0;
664 cornerFlags = 0;
665 for (int c = 0; c < 4; ++c) {
666 const SkVector& r = rrect.radii((SkRRect::Corner)c);
667 SkASSERT((0 == r.fX) == (0 == r.fY));
668 if (0 == r.fX) {
669 continue;
670 }
671 if (r.fX != r.fY) {
672 cornerFlags = ~0U;
673 break;
674 }
675 if (!cornerFlags) {
676 radius = r.fX;
677 if (radius < CircularRRectEffect::kRadiusMin) {
678 cornerFlags = ~0U;
679 break;
680 }
681 cornerFlags = 1 << c;
682 } else {
683 if (r.fX != radius) {
684 cornerFlags = ~0U;
685 break;
686 }
687 cornerFlags |= 1 << c;
688 }
689 }
690
691 switch (cornerFlags) {
692 case CircularRRectEffect::kTopLeft_CornerFlag:
693 case CircularRRectEffect::kTopRight_CornerFlag:
694 case CircularRRectEffect::kBottomRight_CornerFlag:
695 case CircularRRectEffect::kBottomLeft_CornerFlag:
696 case CircularRRectEffect::kLeft_CornerFlags:
697 case CircularRRectEffect::kTop_CornerFlags:
698 case CircularRRectEffect::kRight_CornerFlags:
699 case CircularRRectEffect::kBottom_CornerFlags:
700 case CircularRRectEffect::kAll_CornerFlags:
701 break;
702 default:
703 if (rrect.isNinePatch()) {
704 const SkVector& r0 = rrect.radii(SkRRect::kUpperLeft_Corner);
705 const SkVector& r1 = rrect.radii(SkRRect::kLowerRight_Corner);
706 if (r0.fX >= EllipticalRRectEffect::kRadiusMin &&
707 r0.fY >= EllipticalRRectEffect::kRadiusMin &&
708 r1.fX >= EllipticalRRectEffect::kRadiusMin &&
709 r1.fY >= EllipticalRRectEffect::kRadiusMin) {
710 return EllipticalRRectEffect::Create(edgeType,
711 EllipticalRRectEffect::kNinePatch_RRectType,
712 rrect);
713 }
714 }
715 return NULL;
716 }
717 } else {
718 return NULL;
719 }
720 return CircularRRectEffect::Create(edgeType, cornerFlags, rrect);
721 }

mercurial