Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: src/gpu/effects/GrRRectEffect.cpp

Issue 175423002: Add effect-based clipping for circular "tab" style rrects. (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: update Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « gm/rrects.cpp ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2014 Google Inc. 2 * Copyright 2014 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "GrRRectEffect.h" 8 #include "GrRRectEffect.h"
9 9
10 #include "gl/GrGLEffect.h" 10 #include "gl/GrGLEffect.h"
11 #include "gl/GrGLSL.h" 11 #include "gl/GrGLSL.h"
12 #include "GrTBackendEffectFactory.h" 12 #include "GrTBackendEffectFactory.h"
13 13
14 #include "SkRRect.h" 14 #include "SkRRect.h"
15 15
16 class GLRRectEffect; 16 class GLRRectEffect;
17 17
18 class RRectEffect : public GrEffect { 18 class RRectEffect : public GrEffect {
19 public: 19 public:
20 // This effect only supports circular corner rrects where all corners have t he same radius 20 // This effect only supports circular corner rrects where the radius is >= k RadiusMin.
21 // which must be <= kRadiusMin.
22 static const SkScalar kRadiusMin; 21 static const SkScalar kRadiusMin;
23 22
24 static GrEffectRef* Create(const SkRRect&); 23 /// The types of circular corner rrects supported
24 enum Type {
25 kCircleCorner_Type, //<! All four corners have the same circular rad ius.
26 kLeftCircleTab_Type, //<! The left side has circular corners and the right is a rect.
27 kTopCircleTab_Type, //<! etc
28 kRightCircleTab_Type,
29 kBottomCircleTab_Type,
30 };
31
32 static GrEffectRef* Create(const SkRRect&, Type);
25 33
26 virtual ~RRectEffect() {}; 34 virtual ~RRectEffect() {};
27 static const char* Name() { return "RRect"; } 35 static const char* Name() { return "RRect"; }
28 36
29 const SkRRect& getRRect() const { return fRRect; } 37 const SkRRect& getRRect() const { return fRRect; }
30 38
39 Type getType() const { return fType; }
40
31 typedef GLRRectEffect GLEffect; 41 typedef GLRRectEffect GLEffect;
32 42
33 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags ) const SK_OVERRIDE; 43 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags ) const SK_OVERRIDE;
34 44
35 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE; 45 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
36 46
37 private: 47 private:
38 RRectEffect(const SkRRect&); 48 RRectEffect(const SkRRect&, Type);
39 49
40 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE; 50 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE;
41 51
52 Type fType;
42 SkRRect fRRect; 53 SkRRect fRRect;
43 54
44 GR_DECLARE_EFFECT_TEST; 55 GR_DECLARE_EFFECT_TEST;
45 56
46 typedef GrEffect INHERITED; 57 typedef GrEffect INHERITED;
47 }; 58 };
48 59
49 const SkScalar RRectEffect::kRadiusMin = 0.5f; 60 const SkScalar RRectEffect::kRadiusMin = 0.5f;
50 61
51 GrEffectRef* RRectEffect::Create(const SkRRect& rrect) { 62 GrEffectRef* RRectEffect::Create(const SkRRect& rrect, Type type) {
52 return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(RRectEffect, (rrect)))); 63 return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(RRectEffect, (rrect, type) )));
53 } 64 }
54 65
55 void RRectEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlag s) const { 66 void RRectEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlag s) const {
56 *validFlags = 0; 67 *validFlags = 0;
57 } 68 }
58 69
59 const GrBackendEffectFactory& RRectEffect::getFactory() const { 70 const GrBackendEffectFactory& RRectEffect::getFactory() const {
60 return GrTBackendEffectFactory<RRectEffect>::getInstance(); 71 return GrTBackendEffectFactory<RRectEffect>::getInstance();
61 } 72 }
62 73
63 RRectEffect::RRectEffect(const SkRRect& rrect) 74 RRectEffect::RRectEffect(const SkRRect& rrect, Type type)
64 : fRRect(rrect) { 75 : fRRect(rrect)
76 , fType(type) {
65 this->setWillReadFragmentPosition(); 77 this->setWillReadFragmentPosition();
66 } 78 }
67 79
68 bool RRectEffect::onIsEqual(const GrEffect& other) const { 80 bool RRectEffect::onIsEqual(const GrEffect& other) const {
69 const RRectEffect& rre = CastEffect<RRectEffect>(other); 81 const RRectEffect& rre = CastEffect<RRectEffect>(other);
82 // type is derived from fRRect, so no need to check it.
70 return fRRect == rre.fRRect; 83 return fRRect == rre.fRRect;
71 } 84 }
72 85
73 ////////////////////////////////////////////////////////////////////////////// 86 //////////////////////////////////////////////////////////////////////////////
74 87
75 GR_DEFINE_EFFECT_TEST(RRectEffect); 88 GR_DEFINE_EFFECT_TEST(RRectEffect);
76 89
77 GrEffectRef* RRectEffect::TestCreate(SkRandom* random, 90 GrEffectRef* RRectEffect::TestCreate(SkRandom* random,
78 GrContext*, 91 GrContext*,
79 const GrDrawTargetCaps& caps, 92 const GrDrawTargetCaps& caps,
(...skipping 14 matching lines...) Expand all
94 GLRRectEffect(const GrBackendEffectFactory&, const GrDrawEffect&); 107 GLRRectEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
95 108
96 virtual void emitCode(GrGLShaderBuilder* builder, 109 virtual void emitCode(GrGLShaderBuilder* builder,
97 const GrDrawEffect& drawEffect, 110 const GrDrawEffect& drawEffect,
98 EffectKey key, 111 EffectKey key,
99 const char* outputColor, 112 const char* outputColor,
100 const char* inputColor, 113 const char* inputColor,
101 const TransformedCoordsArray&, 114 const TransformedCoordsArray&,
102 const TextureSamplerArray&) SK_OVERRIDE; 115 const TextureSamplerArray&) SK_OVERRIDE;
103 116
104 static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&) { retur n 0; } 117 static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
105 118
106 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVER RIDE; 119 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVER RIDE;
107 120
108 private: 121 private:
109 GrGLUniformManager::UniformHandle fInnerRectUniform; 122 GrGLUniformManager::UniformHandle fInnerRectUniform;
110 GrGLUniformManager::UniformHandle fRadiusPlusHalfUniform; 123 GrGLUniformManager::UniformHandle fRadiusPlusHalfUniform;
111 SkRRect fPrevRRect; 124 SkRRect fPrevRRect;
112 typedef GrGLEffect INHERITED; 125 typedef GrGLEffect INHERITED;
113 }; 126 };
114 127
115 GLRRectEffect::GLRRectEffect(const GrBackendEffectFactory& factory, 128 GLRRectEffect::GLRRectEffect(const GrBackendEffectFactory& factory,
116 const GrDrawEffect& drawEffect) 129 const GrDrawEffect& drawEffect)
117 : INHERITED (factory) { 130 : INHERITED (factory) {
118 fPrevRRect.setEmpty(); 131 fPrevRRect.setEmpty();
119 } 132 }
120 133
121 void GLRRectEffect::emitCode(GrGLShaderBuilder* builder, 134 void GLRRectEffect::emitCode(GrGLShaderBuilder* builder,
122 const GrDrawEffect& drawEffect, 135 const GrDrawEffect& drawEffect,
123 EffectKey key, 136 EffectKey key,
124 const char* outputColor, 137 const char* outputColor,
125 const char* inputColor, 138 const char* inputColor,
126 const TransformedCoordsArray&, 139 const TransformedCoordsArray&,
127 const TextureSamplerArray& samplers) { 140 const TextureSamplerArray& samplers) {
141 const RRectEffect& rre = drawEffect.castEffect<RRectEffect>();
128 const char *rectName; 142 const char *rectName;
129 const char *radiusPlusHalfName; 143 const char *radiusPlusHalfName;
130 // The inner rect is the rrect bounds inset by the radius. Its top, left, ri ght, and bottom 144 // The inner rect is the rrect bounds inset by the radius. Its top, left, ri ght, and bottom
131 // edges correspond to components x, y, z, and w, respectively. 145 // edges correspond to components x, y, z, and w, respectively. When one sid e of the rrect has
146 // rectangular corners, that side's value corresponds to the rect edge's val ue outset by half a
147 // pixel.
132 fInnerRectUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibil ity, 148 fInnerRectUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibil ity,
133 kVec4f_GrSLType, 149 kVec4f_GrSLType,
134 "innerRect", 150 "innerRect",
135 &rectName); 151 &rectName);
136 fRadiusPlusHalfUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Vi sibility, 152 fRadiusPlusHalfUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Vi sibility,
137 kFloat_GrSLType, 153 kFloat_GrSLType,
138 "radiusPlusHalf", 154 "radiusPlusHalf",
139 &radiusPlusHalfName); 155 &radiusPlusHalfName);
140 const char* fragmentPos = builder->fragmentPosition(); 156 const char* fragmentPos = builder->fragmentPosition();
141 // At each quarter-circle corner we compute a vector that is the offset of t he fragment position 157 // At each quarter-circle corner we compute a vector that is the offset of t he fragment position
142 // from the circle center. The vector is pinned in x and y to be in the quar ter-plane relevant 158 // from the circle center. The vector is pinned in x and y to be in the quar ter-plane relevant
143 // to that corner. This means that points near the interior near the rrect t op edge will have 159 // to that corner. This means that points near the interior near the rrect t op edge will have
144 // a vector that points straight up for both the TL left and TR corners. Com puting an 160 // a vector that points straight up for both the TL left and TR corners. Com puting an
145 // alpha from this vector at either the TR or TL corner will give the correc t result. Similarly, 161 // alpha from this vector at either the TR or TL corner will give the correc t result. Similarly,
146 // fragments near the other three edges will get the correct AA. Fragments i n the interior of 162 // fragments near the other three edges will get the correct AA. Fragments i n the interior of
147 // the rrect will have a (0,0) vector at all four corners. So long as the ra dius > 0.5 they will 163 // the rrect will have a (0,0) vector at all four corners. So long as the ra dius > 0.5 they will
148 // correctly produce an alpha value of 1 at all four corners. We take the mi n of all the alphas. 164 // correctly produce an alpha value of 1 at all four corners. We take the mi n of all the alphas.
149 // The code below is a simplified version of the above that performs maxs on the vector 165 // The code below is a simplified version of the above that performs maxs on the vector
150 // components before computing distances and alpha values so that only one d istance computation 166 // components before computing distances and alpha values so that only one d istance computation
151 // need be computed to determine the min alpha. 167 // need be computed to determine the min alpha.
152 builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmen tPos); 168 //
153 builder->fsCodeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rect Name); 169 // For the cases where one half of the rrect is rectangular we drop one of t he x or y
154 builder->fsCodeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n"); 170 // computations, compute a separate rect edge alpha for the rect side, and m ul the two computed
155 builder->fsCodeAppendf("\t\tfloat alpha = clamp(%s - length(dxy), 0.0, 1.0); \n", 171 // alphas together.
156 radiusPlusHalfName); 172 switch (rre.getType()) {
173 case RRectEffect::kCircleCorner_Type:
174 builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
175 builder->fsCodeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentP os, rectName);
176 builder->fsCodeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n") ;
177 builder->fsCodeAppendf("\t\tfloat alpha = clamp(%s - length(dxy), 0. 0, 1.0);\n",
178 radiusPlusHalfName);
179 break;
180 case RRectEffect::kLeftCircleTab_Type:
181 builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
182 builder->fsCodeAppendf("\t\tfloat dy1 = %s.y - %s.w;\n", fragmentPos , rectName);
183 builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(dxy0.x, max(dxy0.y, d y1)), 0.0);\n");
robertphillips 2014/02/21 19:26:36 \n?
bsalomon 2014/02/21 21:20:45 Done. x4
184 builder->fsCodeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0. 0, 1.0);\n", rectName, fragmentPos);
185 builder->fsCodeAppendf("\t\tfloat alpha = rightAlpha * clamp(%s - le ngth(dxy), 0.0, 1.0);\n",
186 radiusPlusHalfName);
187 break;
188 case RRectEffect::kTopCircleTab_Type:
189 builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
190 builder->fsCodeAppendf("\t\tfloat dx1 = %s.x - %s.z;\n", fragmentPos , rectName);
191 builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(max(dxy0.x, dx1), dxy 0.y), 0.0);\n");
robertphillips 2014/02/21 19:26:36 \n?
192 builder->fsCodeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0 .0, 1.0);\n", rectName, fragmentPos);
193 builder->fsCodeAppendf("\t\tfloat alpha = bottomAlpha * clamp(%s - l ength(dxy), 0.0, 1.0);\n",
194 radiusPlusHalfName);
195 break;
196 case RRectEffect::kRightCircleTab_Type:
197 builder->fsCodeAppendf("\t\tfloat dy0 = %s.y - %s.y;\n", rectName, f ragmentPos);
198 builder->fsCodeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentP os, rectName);
199 builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(dxy1.x, max(dy0, dxy1 .y)), 0.0);\n");
robertphillips 2014/02/21 19:26:36 \n?
200 builder->fsCodeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0 , 1.0);\n", fragmentPos, rectName);
201 builder->fsCodeAppendf("\t\tfloat alpha = leftAlpha * clamp(%s - len gth(dxy), 0.0, 1.0);\n",
202 radiusPlusHalfName);
203 break;
204 case RRectEffect::kBottomCircleTab_Type:
205 builder->fsCodeAppendf("\t\tfloat dx0 = %s.x - %s.x;\n", rectName, f ragmentPos);
206 builder->fsCodeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentP os, rectName);
207 builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(max(dx0, dxy1.x), dxy 1.y), 0.0);\n");
robertphillips 2014/02/21 19:26:36 \n?
208 builder->fsCodeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n", fragmentPos, rectName);
209 builder->fsCodeAppendf("\t\tfloat alpha = topAlpha * clamp(%s - leng th(dxy), 0.0, 1.0);\n",
210 radiusPlusHalfName);
211 break;
212 }
157 213
158 builder->fsCodeAppendf("\t\t%s = %s;\n", outputColor, 214 builder->fsCodeAppendf("\t\t%s = %s;\n", outputColor,
159 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_st r()); 215 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_st r());
160 } 216 }
161 217
218 GrGLEffect::EffectKey GLRRectEffect::GenKey(const GrDrawEffect& drawEffect, cons t GrGLCaps&) {
219 const RRectEffect& rre = drawEffect.castEffect<RRectEffect>();
220 return rre.getType();
221 }
222
162 void GLRRectEffect::setData(const GrGLUniformManager& uman, const GrDrawEffect& drawEffect) { 223 void GLRRectEffect::setData(const GrGLUniformManager& uman, const GrDrawEffect& drawEffect) {
163 const RRectEffect& rre = drawEffect.castEffect<RRectEffect>(); 224 const RRectEffect& rre = drawEffect.castEffect<RRectEffect>();
164 const SkRRect& rrect = rre.getRRect(); 225 const SkRRect& rrect = rre.getRRect();
165 if (rrect != fPrevRRect) { 226 if (rrect != fPrevRRect) {
166 SkASSERT(rrect.isSimpleCircular());
167 SkRect rect = rrect.getBounds(); 227 SkRect rect = rrect.getBounds();
168 SkScalar radius = rrect.getSimpleRadii().fX; 228 SkScalar radius;
169 SkASSERT(radius >= RRectEffect::kRadiusMin); 229 switch (rre.getType()) {
170 rect.inset(radius, radius); 230 case RRectEffect::kCircleCorner_Type:
231 SkASSERT(rrect.isSimpleCircular());
232 radius = rrect.getSimpleRadii().fX;
233 SkASSERT(radius >= RRectEffect::kRadiusMin);
234 rect.inset(radius, radius);
235 break;
236 case RRectEffect::kLeftCircleTab_Type:
237 radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX;
238 rect.fLeft += radius;
239 rect.fTop += radius;
240 rect.fRight += 0.5f;
241 rect.fBottom -= radius;
242 break;
243 case RRectEffect::kTopCircleTab_Type:
244 radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX;
245 rect.fLeft += radius;
246 rect.fTop += radius;
247 rect.fRight -= radius;
248 rect.fBottom += 0.5f;
249 break;
250 case RRectEffect::kRightCircleTab_Type:
251 radius = rrect.radii(SkRRect::kUpperRight_Corner).fX;
252 rect.fLeft -= 0.5f;
253 rect.fTop += radius;
254 rect.fRight -= radius;
255 rect.fBottom -= radius;
256 break;
257 case RRectEffect::kBottomCircleTab_Type:
258 radius = rrect.radii(SkRRect::kLowerLeft_Corner).fX;
259 rect.fLeft += radius;
260 rect.fTop -= 0.5f;
261 rect.fRight -= radius;
262 rect.fBottom -= radius;
263 break;
264 }
171 uman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.f Bottom); 265 uman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.f Bottom);
172 uman.set1f(fRadiusPlusHalfUniform, radius + 0.5f); 266 uman.set1f(fRadiusPlusHalfUniform, radius + 0.5f);
173 fPrevRRect = rrect; 267 fPrevRRect = rrect;
174 } 268 }
175 } 269 }
176 270
177 ////////////////////////////////////////////////////////////////////////////// 271 //////////////////////////////////////////////////////////////////////////////
178 272
179 GrEffectRef* GrRRectEffect::Create(const SkRRect& rrect) { 273 GrEffectRef* GrRRectEffect::Create(const SkRRect& rrect) {
180 if (!rrect.isSimpleCircular()) { 274 RRectEffect::Type type;
275 if (rrect.isSimpleCircular()) {
276 if (rrect.getSimpleRadii().fX < RRectEffect::kRadiusMin) {
277 return NULL;
278 }
279 type = RRectEffect::kCircleCorner_Type;
280 } else if (rrect.isComplex()) {
281 // Check for the "tab" cases - two adjacent circular corners and two squ are corners.
282 SkScalar radius;
283 int circleCornerBitfield = 0;
284 for (int c = 0; c < 4; ++c) {
285 const SkVector& r = rrect.radii((SkRRect::Corner)c);
286 SkASSERT((0 == r.fX) == (0 == r.fY));
287 if (0 == r.fX) {
288 continue;
289 }
290 if (r.fX != r.fY) {
291 circleCornerBitfield = 0;
robertphillips 2014/02/21 19:26:36 just return NULL here?
bsalomon 2014/02/21 21:20:45 Done. x3
292 break;
293 }
294 if (!circleCornerBitfield) {
295 radius = r.fX;
296 if (radius < RRectEffect::kRadiusMin) {
robertphillips 2014/02/21 19:26:36 can't we just return NULL here?
297 break;
298 }
299 circleCornerBitfield = 1 << c;
300 } else {
301 if (r.fX != radius) {
302 circleCornerBitfield = 0;
303 break;
304 }
305 circleCornerBitfield |= 1 << c;
306 }
307 }
308
309 GR_STATIC_ASSERT(SkRRect::kUpperLeft_Corner == 0);
310 GR_STATIC_ASSERT(SkRRect::kUpperRight_Corner == 1);
311 GR_STATIC_ASSERT(SkRRect::kLowerRight_Corner == 2);
312 GR_STATIC_ASSERT(SkRRect::kLowerLeft_Corner == 3);
313 switch (circleCornerBitfield) {
314 case 3:
315 type = RRectEffect::kTopCircleTab_Type;
316 break;
317 case 6:
318 type = RRectEffect::kRightCircleTab_Type;
319 break;
320 case 9:
321 type = RRectEffect::kLeftCircleTab_Type;
322 break;
323 case 12:
324 type = RRectEffect::kBottomCircleTab_Type;
325 break;
326 default:
327 return NULL;
328 }
329 } else {
181 return NULL; 330 return NULL;
182 } 331 }
183 332 return RRectEffect::Create(rrect, type);
184 if (rrect.getSimpleRadii().fX < RRectEffect::kRadiusMin) {
185 return NULL;
186 }
187
188 return RRectEffect::Create(rrect);
189 } 333 }
OLDNEW
« no previous file with comments | « gm/rrects.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698