OLD | NEW |
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 "GrConvexPolyEffect.h" | 10 #include "GrConvexPolyEffect.h" |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
155 const char *rectName; | 155 const char *rectName; |
156 const char *radiusPlusHalfName; | 156 const char *radiusPlusHalfName; |
157 // The inner rect is the rrect bounds inset by the radius. Its left, top, ri
ght, and bottom | 157 // The inner rect is the rrect bounds inset by the radius. Its left, top, ri
ght, and bottom |
158 // edges correspond to components x, y, z, and w, respectively. When a side
of the rrect has | 158 // edges correspond to components x, y, z, and w, respectively. When a side
of the rrect has |
159 // only rectangular corners, that side's value corresponds to the rect edge'
s value outset by | 159 // only rectangular corners, that side's value corresponds to the rect edge'
s value outset by |
160 // half a pixel. | 160 // half a pixel. |
161 fInnerRectUniform = uniformHandler->addUniform(GrGLSLUniformHandler::kFragme
nt_Visibility, | 161 fInnerRectUniform = uniformHandler->addUniform(GrGLSLUniformHandler::kFragme
nt_Visibility, |
162 kVec4f_GrSLType, kDefault_GrS
LPrecision, | 162 kVec4f_GrSLType, kDefault_GrS
LPrecision, |
163 "innerRect", | 163 "innerRect", |
164 &rectName); | 164 &rectName); |
| 165 // x is (r + .5) and y is 1/(r + .5) |
165 fRadiusPlusHalfUniform = uniformHandler->addUniform(GrGLSLUniformHandler::kF
ragment_Visibility, | 166 fRadiusPlusHalfUniform = uniformHandler->addUniform(GrGLSLUniformHandler::kF
ragment_Visibility, |
166 kFloat_GrSLType, kDefaul
t_GrSLPrecision, | 167 kVec2f_GrSLType, kDefaul
t_GrSLPrecision, |
167 "radiusPlusHalf", | 168 "radiusPlusHalf", |
168 &radiusPlusHalfName); | 169 &radiusPlusHalfName); |
169 | 170 |
| 171 // If we're on a device with a "real" mediump then the length calculation co
uld overflow. |
| 172 SkString clampedCircleDistance; |
| 173 if (args.fGLSLCaps->floatPrecisionVaries()) { |
| 174 clampedCircleDistance.printf("clamp(%s.x * (1.0 - length(dxy * %s.y)), 0
.0, 1.0);", |
| 175 radiusPlusHalfName, radiusPlusHalfName); |
| 176 } else { |
| 177 clampedCircleDistance.printf("clamp(%s.x - length(dxy), 0.0, 1.0);", rad
iusPlusHalfName); |
| 178 } |
| 179 |
170 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; | 180 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; |
171 const char* fragmentPos = fragBuilder->fragmentPosition(); | 181 const char* fragmentPos = fragBuilder->fragmentPosition(); |
172 // At each quarter-circle corner we compute a vector that is the offset of t
he fragment position | 182 // At each quarter-circle corner we compute a vector that is the offset of t
he fragment position |
173 // from the circle center. The vector is pinned in x and y to be in the quar
ter-plane relevant | 183 // from the circle center. The vector is pinned in x and y to be in the quar
ter-plane relevant |
174 // to that corner. This means that points near the interior near the rrect t
op edge will have | 184 // to that corner. This means that points near the interior near the rrect t
op edge will have |
175 // a vector that points straight up for both the TL left and TR corners. Com
puting an | 185 // a vector that points straight up for both the TL left and TR corners. Com
puting an |
176 // alpha from this vector at either the TR or TL corner will give the correc
t result. Similarly, | 186 // alpha from this vector at either the TR or TL corner will give the correc
t result. Similarly, |
177 // fragments near the other three edges will get the correct AA. Fragments i
n the interior of | 187 // fragments near the other three edges will get the correct AA. Fragments i
n the interior of |
178 // the rrect will have a (0,0) vector at all four corners. So long as the ra
dius > 0.5 they will | 188 // the rrect will have a (0,0) vector at all four corners. So long as the ra
dius > 0.5 they will |
179 // correctly produce an alpha value of 1 at all four corners. We take the mi
n of all the alphas. | 189 // correctly produce an alpha value of 1 at all four corners. We take the mi
n of all the alphas. |
180 // The code below is a simplified version of the above that performs maxs on
the vector | 190 // The code below is a simplified version of the above that performs maxs on
the vector |
181 // components before computing distances and alpha values so that only one d
istance computation | 191 // components before computing distances and alpha values so that only one d
istance computation |
182 // need be computed to determine the min alpha. | 192 // need be computed to determine the min alpha. |
183 // | 193 // |
184 // For the cases where one half of the rrect is rectangular we drop one of t
he x or y | 194 // For the cases where one half of the rrect is rectangular we drop one of t
he x or y |
185 // computations, compute a separate rect edge alpha for the rect side, and m
ul the two computed | 195 // computations, compute a separate rect edge alpha for the rect side, and m
ul the two computed |
186 // alphas together. | 196 // alphas together. |
187 switch (crre.getCircularCornerFlags()) { | 197 switch (crre.getCircularCornerFlags()) { |
188 case CircularRRectEffect::kAll_CornerFlags: | 198 case CircularRRectEffect::kAll_CornerFlags: |
189 fragBuilder->codeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectNam
e, fragmentPos); | 199 fragBuilder->codeAppendf("vec2 dxy0 = %s.xy - %s.xy;", rectName, fra
gmentPos); |
190 fragBuilder->codeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmen
tPos, rectName); | 200 fragBuilder->codeAppendf("vec2 dxy1 = %s.xy - %s.zw;", fragmentPos,
rectName); |
191 fragBuilder->codeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n
"); | 201 fragBuilder->codeAppend("vec2 dxy = max(max(dxy0, dxy1), 0.0);"); |
192 fragBuilder->codeAppendf("\t\tfloat alpha = clamp(%s - length(dxy),
0.0, 1.0);\n", | 202 fragBuilder->codeAppendf("float alpha = %s;", clampedCircleDistance.
c_str()); |
193 radiusPlusHalfName); | |
194 break; | 203 break; |
195 case CircularRRectEffect::kTopLeft_CornerFlag: | 204 case CircularRRectEffect::kTopLeft_CornerFlag: |
196 fragBuilder->codeAppendf("\t\tvec2 dxy = max(%s.xy - %s.xy, 0.0);\n"
, | 205 fragBuilder->codeAppendf("vec2 dxy = max(%s.xy - %s.xy, 0.0);", |
197 rectName, fragmentPos); | 206 rectName, fragmentPos); |
198 fragBuilder->codeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x,
0.0, 1.0);\n", | 207 fragBuilder->codeAppendf("float rightAlpha = clamp(%s.z - %s.x, 0.0,
1.0);", |
199 rectName, fragmentPos); | 208 rectName, fragmentPos); |
200 fragBuilder->codeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y,
0.0, 1.0);\n", | 209 fragBuilder->codeAppendf("float bottomAlpha = clamp(%s.w - %s.y, 0.0
, 1.0);", |
201 rectName, fragmentPos); | 210 rectName, fragmentPos); |
202 fragBuilder->codeAppendf( | 211 fragBuilder->codeAppendf("float alpha = bottomAlpha * rightAlpha * %
s;", |
203 "\t\tfloat alpha = bottomAlpha * rightAlpha * clamp(%s - length(
dxy), 0.0, 1.0);\n", | 212 clampedCircleDistance.c_str()); |
204 radiusPlusHalfName); | |
205 break; | 213 break; |
206 case CircularRRectEffect::kTopRight_CornerFlag: | 214 case CircularRRectEffect::kTopRight_CornerFlag: |
207 fragBuilder->codeAppendf("\t\tvec2 dxy = max(vec2(%s.x - %s.z, %s.y
- %s.y), 0.0);\n", | 215 fragBuilder->codeAppendf("vec2 dxy = max(vec2(%s.x - %s.z, %s.y - %s
.y), 0.0);", |
208 fragmentPos, rectName, rectName, fragmentPo
s); | 216 fragmentPos, rectName, rectName, fragmentPo
s); |
209 fragBuilder->codeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0
.0, 1.0);\n", | 217 fragBuilder->codeAppendf("float leftAlpha = clamp(%s.x - %s.x, 0.0,
1.0);", |
210 fragmentPos, rectName); | 218 fragmentPos, rectName); |
211 fragBuilder->codeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y,
0.0, 1.0);\n", | 219 fragBuilder->codeAppendf("float bottomAlpha = clamp(%s.w - %s.y, 0.0
, 1.0);", |
212 rectName, fragmentPos); | 220 rectName, fragmentPos); |
213 fragBuilder->codeAppendf( | 221 fragBuilder->codeAppendf("float alpha = bottomAlpha * leftAlpha * %s
;", |
214 "\t\tfloat alpha = bottomAlpha * leftAlpha * clamp(%s - length(d
xy), 0.0, 1.0);\n", | 222 clampedCircleDistance.c_str()); |
215 radiusPlusHalfName); | |
216 break; | 223 break; |
217 case CircularRRectEffect::kBottomRight_CornerFlag: | 224 case CircularRRectEffect::kBottomRight_CornerFlag: |
218 fragBuilder->codeAppendf("\t\tvec2 dxy = max(%s.xy - %s.zw, 0.0);\n"
, | 225 fragBuilder->codeAppendf("vec2 dxy = max(%s.xy - %s.zw, 0.0);", |
219 fragmentPos, rectName); | 226 fragmentPos, rectName); |
220 fragBuilder->codeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0
.0, 1.0);\n", | 227 fragBuilder->codeAppendf("float leftAlpha = clamp(%s.x - %s.x, 0.0,
1.0);", |
221 fragmentPos, rectName); | 228 fragmentPos, rectName); |
222 fragBuilder->codeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.
0, 1.0);\n", | 229 fragBuilder->codeAppendf("float topAlpha = clamp(%s.y - %s.y, 0.0, 1
.0);", |
223 fragmentPos, rectName); | 230 fragmentPos, rectName); |
224 fragBuilder->codeAppendf( | 231 fragBuilder->codeAppendf("float alpha = topAlpha * leftAlpha * %s;", |
225 "\t\tfloat alpha = topAlpha * leftAlpha * clamp(%s - length(dxy)
, 0.0, 1.0);\n", | 232 clampedCircleDistance.c_str()); |
226 radiusPlusHalfName); | |
227 break; | 233 break; |
228 case CircularRRectEffect::kBottomLeft_CornerFlag: | 234 case CircularRRectEffect::kBottomLeft_CornerFlag: |
229 fragBuilder->codeAppendf("\t\tvec2 dxy = max(vec2(%s.x - %s.x, %s.y
- %s.w), 0.0);\n", | 235 fragBuilder->codeAppendf("vec2 dxy = max(vec2(%s.x - %s.x, %s.y - %s
.w), 0.0);", |
230 rectName, fragmentPos, fragmentPos, rectNam
e); | 236 rectName, fragmentPos, fragmentPos, rectNam
e); |
231 fragBuilder->codeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x,
0.0, 1.0);\n", | 237 fragBuilder->codeAppendf("float rightAlpha = clamp(%s.z - %s.x, 0.0,
1.0);", |
232 rectName, fragmentPos); | 238 rectName, fragmentPos); |
233 fragBuilder->codeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.
0, 1.0);\n", | 239 fragBuilder->codeAppendf("float topAlpha = clamp(%s.y - %s.y, 0.0, 1
.0);", |
234 fragmentPos, rectName); | 240 fragmentPos, rectName); |
235 fragBuilder->codeAppendf( | 241 fragBuilder->codeAppendf("float alpha = topAlpha * rightAlpha * %s;"
, |
236 "\t\tfloat alpha = topAlpha * rightAlpha * clamp(%s - length(dxy
), 0.0, 1.0);\n", | 242 clampedCircleDistance.c_str()); |
237 radiusPlusHalfName); | |
238 break; | 243 break; |
239 case CircularRRectEffect::kLeft_CornerFlags: | 244 case CircularRRectEffect::kLeft_CornerFlags: |
240 fragBuilder->codeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectNam
e, fragmentPos); | 245 fragBuilder->codeAppendf("vec2 dxy0 = %s.xy - %s.xy;", rectName, fra
gmentPos); |
241 fragBuilder->codeAppendf("\t\tfloat dy1 = %s.y - %s.w;\n", fragmentP
os, rectName); | 246 fragBuilder->codeAppendf("float dy1 = %s.y - %s.w;", fragmentPos, re
ctName); |
242 fragBuilder->codeAppend("\t\tvec2 dxy = max(vec2(dxy0.x, max(dxy0.y,
dy1)), 0.0);\n"); | 247 fragBuilder->codeAppend("vec2 dxy = max(vec2(dxy0.x, max(dxy0.y, dy1
)), 0.0);"); |
243 fragBuilder->codeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x,
0.0, 1.0);\n", | 248 fragBuilder->codeAppendf("float rightAlpha = clamp(%s.z - %s.x, 0.0,
1.0);", |
244 rectName, fragmentPos); | 249 rectName, fragmentPos); |
245 fragBuilder->codeAppendf( | 250 fragBuilder->codeAppendf("float alpha = rightAlpha * %s;", |
246 "\t\tfloat alpha = rightAlpha * clamp(%s - length(dxy), 0.0, 1.0
);\n", | 251 clampedCircleDistance.c_str()); |
247 radiusPlusHalfName); | |
248 break; | 252 break; |
249 case CircularRRectEffect::kTop_CornerFlags: | 253 case CircularRRectEffect::kTop_CornerFlags: |
250 fragBuilder->codeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectNam
e, fragmentPos); | 254 fragBuilder->codeAppendf("vec2 dxy0 = %s.xy - %s.xy;", rectName, fra
gmentPos); |
251 fragBuilder->codeAppendf("\t\tfloat dx1 = %s.x - %s.z;\n", fragmentP
os, rectName); | 255 fragBuilder->codeAppendf("float dx1 = %s.x - %s.z;", fragmentPos, re
ctName); |
252 fragBuilder->codeAppend("\t\tvec2 dxy = max(vec2(max(dxy0.x, dx1), d
xy0.y), 0.0);\n"); | 256 fragBuilder->codeAppend("vec2 dxy = max(vec2(max(dxy0.x, dx1), dxy0.
y), 0.0);"); |
253 fragBuilder->codeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y,
0.0, 1.0);\n", | 257 fragBuilder->codeAppendf("float bottomAlpha = clamp(%s.w - %s.y, 0.0
, 1.0);", |
254 rectName, fragmentPos); | 258 rectName, fragmentPos); |
255 fragBuilder->codeAppendf( | 259 fragBuilder->codeAppendf("float alpha = bottomAlpha * %s;", |
256 "\t\tfloat alpha = bottomAlpha * clamp(%s - length(dxy), 0.0, 1.
0);\n", | 260 clampedCircleDistance.c_str()); |
257 radiusPlusHalfName); | |
258 break; | 261 break; |
259 case CircularRRectEffect::kRight_CornerFlags: | 262 case CircularRRectEffect::kRight_CornerFlags: |
260 fragBuilder->codeAppendf("\t\tfloat dy0 = %s.y - %s.y;\n", rectName,
fragmentPos); | 263 fragBuilder->codeAppendf("float dy0 = %s.y - %s.y;", rectName, fragm
entPos); |
261 fragBuilder->codeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmen
tPos, rectName); | 264 fragBuilder->codeAppendf("vec2 dxy1 = %s.xy - %s.zw;", fragmentPos,
rectName); |
262 fragBuilder->codeAppend("\t\tvec2 dxy = max(vec2(dxy1.x, max(dy0, dx
y1.y)), 0.0);\n"); | 265 fragBuilder->codeAppend("vec2 dxy = max(vec2(dxy1.x, max(dy0, dxy1.y
)), 0.0);"); |
263 fragBuilder->codeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0
.0, 1.0);\n", | 266 fragBuilder->codeAppendf("float leftAlpha = clamp(%s.x - %s.x, 0.0,
1.0);", |
264 fragmentPos, rectName); | 267 fragmentPos, rectName); |
265 fragBuilder->codeAppendf( | 268 fragBuilder->codeAppendf("float alpha = leftAlpha * %s;", |
266 "\t\tfloat alpha = leftAlpha * clamp(%s - length(dxy), 0.0, 1.0)
;\n", | 269 clampedCircleDistance.c_str()); |
267 radiusPlusHalfName); | |
268 break; | 270 break; |
269 case CircularRRectEffect::kBottom_CornerFlags: | 271 case CircularRRectEffect::kBottom_CornerFlags: |
270 fragBuilder->codeAppendf("\t\tfloat dx0 = %s.x - %s.x;\n", rectName,
fragmentPos); | 272 fragBuilder->codeAppendf("float dx0 = %s.x - %s.x;", rectName, fragm
entPos); |
271 fragBuilder->codeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmen
tPos, rectName); | 273 fragBuilder->codeAppendf("vec2 dxy1 = %s.xy - %s.zw;", fragmentPos,
rectName); |
272 fragBuilder->codeAppend("\t\tvec2 dxy = max(vec2(max(dx0, dxy1.x), d
xy1.y), 0.0);\n"); | 274 fragBuilder->codeAppend("vec2 dxy = max(vec2(max(dx0, dxy1.x), dxy1.
y), 0.0);"); |
273 fragBuilder->codeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.
0, 1.0);\n", | 275 fragBuilder->codeAppendf("float topAlpha = clamp(%s.y - %s.y, 0.0, 1
.0);", |
274 fragmentPos, rectName); | 276 fragmentPos, rectName); |
275 fragBuilder->codeAppendf( | 277 fragBuilder->codeAppendf("float alpha = topAlpha * %s;", |
276 "\t\tfloat alpha = topAlpha * clamp(%s - length(dxy), 0.0, 1.0);
\n", | 278 clampedCircleDistance.c_str()); |
277 radiusPlusHalfName); | |
278 break; | 279 break; |
279 } | 280 } |
280 | 281 |
281 if (kInverseFillAA_GrProcessorEdgeType == crre.getEdgeType()) { | 282 if (kInverseFillAA_GrProcessorEdgeType == crre.getEdgeType()) { |
282 fragBuilder->codeAppend("\t\talpha = 1.0 - alpha;\n"); | 283 fragBuilder->codeAppend("alpha = 1.0 - alpha;"); |
283 } | 284 } |
284 | 285 |
285 fragBuilder->codeAppendf("\t\t%s = %s;\n", args.fOutputColor, | 286 fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, |
286 (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("alpha
")).c_str()); | 287 (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("alpha
")).c_str()); |
287 } | 288 } |
288 | 289 |
289 void GLCircularRRectEffect::GenKey(const GrProcessor& processor, const GrGLSLCap
s&, | 290 void GLCircularRRectEffect::GenKey(const GrProcessor& processor, const GrGLSLCap
s&, |
290 GrProcessorKeyBuilder* b) { | 291 GrProcessorKeyBuilder* b) { |
291 const CircularRRectEffect& crre = processor.cast<CircularRRectEffect>(); | 292 const CircularRRectEffect& crre = processor.cast<CircularRRectEffect>(); |
292 GR_STATIC_ASSERT(kGrProcessorEdgeTypeCnt <= 8); | 293 GR_STATIC_ASSERT(kGrProcessorEdgeTypeCnt <= 8); |
293 b->add32((crre.getCircularCornerFlags() << 3) | crre.getEdgeType()); | 294 b->add32((crre.getCircularCornerFlags() << 3) | crre.getEdgeType()); |
294 } | 295 } |
295 | 296 |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
360 radius = rrect.radii(SkRRect::kLowerLeft_Corner).fX; | 361 radius = rrect.radii(SkRRect::kLowerLeft_Corner).fX; |
361 rect.fLeft += radius; | 362 rect.fLeft += radius; |
362 rect.fTop -= 0.5f; | 363 rect.fTop -= 0.5f; |
363 rect.fRight -= radius; | 364 rect.fRight -= radius; |
364 rect.fBottom -= radius; | 365 rect.fBottom -= radius; |
365 break; | 366 break; |
366 default: | 367 default: |
367 SkFAIL("Should have been one of the above cases."); | 368 SkFAIL("Should have been one of the above cases."); |
368 } | 369 } |
369 pdman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.
fBottom); | 370 pdman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.
fBottom); |
370 pdman.set1f(fRadiusPlusHalfUniform, radius + 0.5f); | 371 radius += 0.5f; |
| 372 pdman.set2f(fRadiusPlusHalfUniform, radius, 1.f / radius); |
371 fPrevRRect = rrect; | 373 fPrevRRect = rrect; |
372 } | 374 } |
373 } | 375 } |
374 | 376 |
375 ////////////////////////////////////////////////////////////////////////////////
//////////////////// | 377 ////////////////////////////////////////////////////////////////////////////////
//////////////////// |
376 | 378 |
377 void CircularRRectEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps, | 379 void CircularRRectEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps, |
378 GrProcessorKeyBuilder* b) const
{ | 380 GrProcessorKeyBuilder* b) const
{ |
379 GLCircularRRectEffect::GenKey(*this, caps, b); | 381 GLCircularRRectEffect::GenKey(*this, caps, b); |
380 } | 382 } |
(...skipping 345 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
726 if (rrect.isNinePatch()) { | 728 if (rrect.isNinePatch()) { |
727 return EllipticalRRectEffect::Create(edgeType, rrect); | 729 return EllipticalRRectEffect::Create(edgeType, rrect); |
728 } | 730 } |
729 return nullptr; | 731 return nullptr; |
730 } | 732 } |
731 } | 733 } |
732 } | 734 } |
733 | 735 |
734 return nullptr; | 736 return nullptr; |
735 } | 737 } |
OLD | NEW |