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

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: fix gcc warnings 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
42 SkRRect fRRect; 52 SkRRect fRRect;
53 Type fType;
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");
184 builder->fsCodeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0. 0, 1.0);\n",
185 rectName, fragmentPos);
186 builder->fsCodeAppendf("\t\tfloat alpha = rightAlpha * clamp(%s - le ngth(dxy), 0.0, 1.0);\n",
187 radiusPlusHalfName);
188 break;
189 case RRectEffect::kTopCircleTab_Type:
190 builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
191 builder->fsCodeAppendf("\t\tfloat dx1 = %s.x - %s.z;\n", fragmentPos , rectName);
192 builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(max(dxy0.x, dx1), dxy 0.y), 0.0);\n");
193 builder->fsCodeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0 .0, 1.0);\n",
194 rectName, fragmentPos);
195 builder->fsCodeAppendf("\t\tfloat alpha = bottomAlpha * clamp(%s - l ength(dxy), 0.0, 1.0);\n",
196 radiusPlusHalfName);
197 break;
198 case RRectEffect::kRightCircleTab_Type:
199 builder->fsCodeAppendf("\t\tfloat dy0 = %s.y - %s.y;\n", rectName, f ragmentPos);
200 builder->fsCodeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentP os, rectName);
201 builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(dxy1.x, max(dy0, dxy1 .y)), 0.0);\n");
202 builder->fsCodeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0 , 1.0);\n",
203 fragmentPos, rectName);
204 builder->fsCodeAppendf("\t\tfloat alpha = leftAlpha * clamp(%s - len gth(dxy), 0.0, 1.0);\n",
205 radiusPlusHalfName);
206 break;
207 case RRectEffect::kBottomCircleTab_Type:
208 builder->fsCodeAppendf("\t\tfloat dx0 = %s.x - %s.x;\n", rectName, f ragmentPos);
209 builder->fsCodeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentP os, rectName);
210 builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(max(dx0, dxy1.x), dxy 1.y), 0.0);\n");
211 builder->fsCodeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n",
212 fragmentPos, rectName);
213 builder->fsCodeAppendf("\t\tfloat alpha = topAlpha * clamp(%s - leng th(dxy), 0.0, 1.0);\n",
214 radiusPlusHalfName);
215 break;
216 }
157 217
158 builder->fsCodeAppendf("\t\t%s = %s;\n", outputColor, 218 builder->fsCodeAppendf("\t\t%s = %s;\n", outputColor,
159 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_st r()); 219 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_st r());
160 } 220 }
161 221
222 GrGLEffect::EffectKey GLRRectEffect::GenKey(const GrDrawEffect& drawEffect, cons t GrGLCaps&) {
223 const RRectEffect& rre = drawEffect.castEffect<RRectEffect>();
224 return rre.getType();
225 }
226
162 void GLRRectEffect::setData(const GrGLUniformManager& uman, const GrDrawEffect& drawEffect) { 227 void GLRRectEffect::setData(const GrGLUniformManager& uman, const GrDrawEffect& drawEffect) {
163 const RRectEffect& rre = drawEffect.castEffect<RRectEffect>(); 228 const RRectEffect& rre = drawEffect.castEffect<RRectEffect>();
164 const SkRRect& rrect = rre.getRRect(); 229 const SkRRect& rrect = rre.getRRect();
165 if (rrect != fPrevRRect) { 230 if (rrect != fPrevRRect) {
166 SkASSERT(rrect.isSimpleCircular());
167 SkRect rect = rrect.getBounds(); 231 SkRect rect = rrect.getBounds();
168 SkScalar radius = rrect.getSimpleRadii().fX; 232 SkScalar radius = 0;
169 SkASSERT(radius >= RRectEffect::kRadiusMin); 233 switch (rre.getType()) {
170 rect.inset(radius, radius); 234 case RRectEffect::kCircleCorner_Type:
235 SkASSERT(rrect.isSimpleCircular());
236 radius = rrect.getSimpleRadii().fX;
237 SkASSERT(radius >= RRectEffect::kRadiusMin);
238 rect.inset(radius, radius);
239 break;
240 case RRectEffect::kLeftCircleTab_Type:
241 radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX;
242 rect.fLeft += radius;
243 rect.fTop += radius;
244 rect.fRight += 0.5f;
245 rect.fBottom -= radius;
246 break;
247 case RRectEffect::kTopCircleTab_Type:
248 radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX;
249 rect.fLeft += radius;
250 rect.fTop += radius;
251 rect.fRight -= radius;
252 rect.fBottom += 0.5f;
253 break;
254 case RRectEffect::kRightCircleTab_Type:
255 radius = rrect.radii(SkRRect::kUpperRight_Corner).fX;
256 rect.fLeft -= 0.5f;
257 rect.fTop += radius;
258 rect.fRight -= radius;
259 rect.fBottom -= radius;
260 break;
261 case RRectEffect::kBottomCircleTab_Type:
262 radius = rrect.radii(SkRRect::kLowerLeft_Corner).fX;
263 rect.fLeft += radius;
264 rect.fTop -= 0.5f;
265 rect.fRight -= radius;
266 rect.fBottom -= radius;
267 break;
268 }
171 uman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.f Bottom); 269 uman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.f Bottom);
172 uman.set1f(fRadiusPlusHalfUniform, radius + 0.5f); 270 uman.set1f(fRadiusPlusHalfUniform, radius + 0.5f);
173 fPrevRRect = rrect; 271 fPrevRRect = rrect;
174 } 272 }
175 } 273 }
176 274
177 ////////////////////////////////////////////////////////////////////////////// 275 //////////////////////////////////////////////////////////////////////////////
178 276
179 GrEffectRef* GrRRectEffect::Create(const SkRRect& rrect) { 277 GrEffectRef* GrRRectEffect::Create(const SkRRect& rrect) {
180 if (!rrect.isSimpleCircular()) { 278 RRectEffect::Type type;
279 if (rrect.isSimpleCircular()) {
280 if (rrect.getSimpleRadii().fX < RRectEffect::kRadiusMin) {
281 return NULL;
282 }
283 type = RRectEffect::kCircleCorner_Type;
284 } else if (rrect.isComplex()) {
285 // Check for the "tab" cases - two adjacent circular corners and two squ are corners.
286 SkScalar radius = 0;
287 int circleCornerBitfield = 0;
288 for (int c = 0; c < 4; ++c) {
289 const SkVector& r = rrect.radii((SkRRect::Corner)c);
290 SkASSERT((0 == r.fX) == (0 == r.fY));
291 if (0 == r.fX) {
292 continue;
293 }
294 if (r.fX != r.fY) {
295 return NULL;
296 }
297 if (!circleCornerBitfield) {
298 radius = r.fX;
299 if (radius < RRectEffect::kRadiusMin) {
300 return NULL;
301 }
302 circleCornerBitfield = 1 << c;
303 } else {
304 if (r.fX != radius) {
305 return NULL;
306 }
307 circleCornerBitfield |= 1 << c;
308 }
309 }
310
311 GR_STATIC_ASSERT(SkRRect::kUpperLeft_Corner == 0);
312 GR_STATIC_ASSERT(SkRRect::kUpperRight_Corner == 1);
313 GR_STATIC_ASSERT(SkRRect::kLowerRight_Corner == 2);
314 GR_STATIC_ASSERT(SkRRect::kLowerLeft_Corner == 3);
315 switch (circleCornerBitfield) {
316 case 3:
317 type = RRectEffect::kTopCircleTab_Type;
318 break;
319 case 6:
320 type = RRectEffect::kRightCircleTab_Type;
321 break;
322 case 9:
323 type = RRectEffect::kLeftCircleTab_Type;
324 break;
325 case 12:
326 type = RRectEffect::kBottomCircleTab_Type;
327 break;
328 default:
329 return NULL;
330 }
331 } else {
181 return NULL; 332 return NULL;
182 } 333 }
183 334 return RRectEffect::Create(rrect, type);
184 if (rrect.getSimpleRadii().fX < RRectEffect::kRadiusMin) {
185 return NULL;
186 }
187
188 return RRectEffect::Create(rrect);
189 } 335 }
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