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 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
121 } while (NULL == fp); | 121 } while (NULL == fp); |
122 return fp; | 122 return fp; |
123 } | 123 } |
124 | 124 |
125 ////////////////////////////////////////////////////////////////////////////// | 125 ////////////////////////////////////////////////////////////////////////////// |
126 | 126 |
127 class GLCircularRRectEffect : public GrGLFragmentProcessor { | 127 class GLCircularRRectEffect : public GrGLFragmentProcessor { |
128 public: | 128 public: |
129 GLCircularRRectEffect(const GrProcessor&); | 129 GLCircularRRectEffect(const GrProcessor&); |
130 | 130 |
131 virtual void emitCode(GrGLFPBuilder* builder, | 131 virtual void emitCode(EmitArgs&) override; |
132 const GrFragmentProcessor& fp, | |
133 const char* outputColor, | |
134 const char* inputColor, | |
135 const TransformedCoordsArray&, | |
136 const TextureSamplerArray&) override; | |
137 | 132 |
138 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessor
KeyBuilder*); | 133 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessor
KeyBuilder*); |
139 | 134 |
140 void setData(const GrGLProgramDataManager&, const GrProcessor&) override; | 135 void setData(const GrGLProgramDataManager&, const GrProcessor&) override; |
141 | 136 |
142 private: | 137 private: |
143 GrGLProgramDataManager::UniformHandle fInnerRectUniform; | 138 GrGLProgramDataManager::UniformHandle fInnerRectUniform; |
144 GrGLProgramDataManager::UniformHandle fRadiusPlusHalfUniform; | 139 GrGLProgramDataManager::UniformHandle fRadiusPlusHalfUniform; |
145 SkRRect fPrevRRect; | 140 SkRRect fPrevRRect; |
146 typedef GrGLFragmentProcessor INHERITED; | 141 typedef GrGLFragmentProcessor INHERITED; |
147 }; | 142 }; |
148 | 143 |
149 GLCircularRRectEffect::GLCircularRRectEffect(const GrProcessor& ) { | 144 GLCircularRRectEffect::GLCircularRRectEffect(const GrProcessor& ) { |
150 fPrevRRect.setEmpty(); | 145 fPrevRRect.setEmpty(); |
151 } | 146 } |
152 | 147 |
153 void GLCircularRRectEffect::emitCode(GrGLFPBuilder* builder, | 148 void GLCircularRRectEffect::emitCode(EmitArgs& args) { |
154 const GrFragmentProcessor& fp, | 149 const CircularRRectEffect& crre = args.fFp.cast<CircularRRectEffect>(); |
155 const char* outputColor, | |
156 const char* inputColor, | |
157 const TransformedCoordsArray&, | |
158 const TextureSamplerArray& samplers) { | |
159 const CircularRRectEffect& crre = fp.cast<CircularRRectEffect>(); | |
160 const char *rectName; | 150 const char *rectName; |
161 const char *radiusPlusHalfName; | 151 const char *radiusPlusHalfName; |
162 // The inner rect is the rrect bounds inset by the radius. Its left, top, ri
ght, and bottom | 152 // The inner rect is the rrect bounds inset by the radius. Its left, top, ri
ght, and bottom |
163 // edges correspond to components x, y, z, and w, respectively. When a side
of the rrect has | 153 // edges correspond to components x, y, z, and w, respectively. When a side
of the rrect has |
164 // only rectangular corners, that side's value corresponds to the rect edge'
s value outset by | 154 // only rectangular corners, that side's value corresponds to the rect edge'
s value outset by |
165 // half a pixel. | 155 // half a pixel. |
166 fInnerRectUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibi
lity, | 156 fInnerRectUniform = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_
Visibility, |
167 kVec4f_GrSLType, kDefault_GrSLPrecis
ion, | 157 kVec4f_GrSLType, kDefault_GrSLPrecis
ion, |
168 "innerRect", | 158 "innerRect", |
169 &rectName); | 159 &rectName); |
170 fRadiusPlusHalfUniform = builder->addUniform(GrGLProgramBuilder::kFragment_V
isibility, | 160 fRadiusPlusHalfUniform = args.fBuilder->addUniform(GrGLProgramBuilder::kFrag
ment_Visibility, |
171 kFloat_GrSLType, kDefault_GrSLP
recision, | 161 kFloat_GrSLType, kDefault_GrSLP
recision, |
172 "radiusPlusHalf", | 162 "radiusPlusHalf", |
173 &radiusPlusHalfName); | 163 &radiusPlusHalfName); |
174 | 164 |
175 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); | 165 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder(); |
176 const char* fragmentPos = fsBuilder->fragmentPosition(); | 166 const char* fragmentPos = fsBuilder->fragmentPosition(); |
177 // At each quarter-circle corner we compute a vector that is the offset of t
he fragment position | 167 // At each quarter-circle corner we compute a vector that is the offset of t
he fragment position |
178 // from the circle center. The vector is pinned in x and y to be in the quar
ter-plane relevant | 168 // from the circle center. The vector is pinned in x and y to be in the quar
ter-plane relevant |
179 // to that corner. This means that points near the interior near the rrect t
op edge will have | 169 // to that corner. This means that points near the interior near the rrect t
op edge will have |
180 // a vector that points straight up for both the TL left and TR corners. Com
puting an | 170 // a vector that points straight up for both the TL left and TR corners. Com
puting an |
181 // alpha from this vector at either the TR or TL corner will give the correc
t result. Similarly, | 171 // alpha from this vector at either the TR or TL corner will give the correc
t result. Similarly, |
182 // fragments near the other three edges will get the correct AA. Fragments i
n the interior of | 172 // fragments near the other three edges will get the correct AA. Fragments i
n the interior of |
183 // the rrect will have a (0,0) vector at all four corners. So long as the ra
dius > 0.5 they will | 173 // the rrect will have a (0,0) vector at all four corners. So long as the ra
dius > 0.5 they will |
184 // correctly produce an alpha value of 1 at all four corners. We take the mi
n of all the alphas. | 174 // correctly produce an alpha value of 1 at all four corners. We take the mi
n of all the alphas. |
185 // The code below is a simplified version of the above that performs maxs on
the vector | 175 // The code below is a simplified version of the above that performs maxs on
the vector |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
272 fragmentPos, rectName); | 262 fragmentPos, rectName); |
273 fsBuilder->codeAppendf("\t\tfloat alpha = topAlpha * clamp(%s - leng
th(dxy), 0.0, 1.0);\n", | 263 fsBuilder->codeAppendf("\t\tfloat alpha = topAlpha * clamp(%s - leng
th(dxy), 0.0, 1.0);\n", |
274 radiusPlusHalfName); | 264 radiusPlusHalfName); |
275 break; | 265 break; |
276 } | 266 } |
277 | 267 |
278 if (kInverseFillAA_GrProcessorEdgeType == crre.getEdgeType()) { | 268 if (kInverseFillAA_GrProcessorEdgeType == crre.getEdgeType()) { |
279 fsBuilder->codeAppend("\t\talpha = 1.0 - alpha;\n"); | 269 fsBuilder->codeAppend("\t\talpha = 1.0 - alpha;\n"); |
280 } | 270 } |
281 | 271 |
282 fsBuilder->codeAppendf("\t\t%s = %s;\n", outputColor, | 272 fsBuilder->codeAppendf("\t\t%s = %s;\n", args.fOutputColor, |
283 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_st
r()); | 273 (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("alpha")
).c_str()); |
284 } | 274 } |
285 | 275 |
286 void GLCircularRRectEffect::GenKey(const GrProcessor& processor, const GrGLSLCap
s&, | 276 void GLCircularRRectEffect::GenKey(const GrProcessor& processor, const GrGLSLCap
s&, |
287 GrProcessorKeyBuilder* b) { | 277 GrProcessorKeyBuilder* b) { |
288 const CircularRRectEffect& crre = processor.cast<CircularRRectEffect>(); | 278 const CircularRRectEffect& crre = processor.cast<CircularRRectEffect>(); |
289 GR_STATIC_ASSERT(kGrProcessorEdgeTypeCnt <= 8); | 279 GR_STATIC_ASSERT(kGrProcessorEdgeTypeCnt <= 8); |
290 b->add32((crre.getCircularCornerFlags() << 3) | crre.getEdgeType()); | 280 b->add32((crre.getCircularCornerFlags() << 3) | crre.getEdgeType()); |
291 } | 281 } |
292 | 282 |
293 void GLCircularRRectEffect::setData(const GrGLProgramDataManager& pdman, | 283 void GLCircularRRectEffect::setData(const GrGLProgramDataManager& pdman, |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
476 } while (NULL == fp); | 466 } while (NULL == fp); |
477 return fp; | 467 return fp; |
478 } | 468 } |
479 | 469 |
480 ////////////////////////////////////////////////////////////////////////////// | 470 ////////////////////////////////////////////////////////////////////////////// |
481 | 471 |
482 class GLEllipticalRRectEffect : public GrGLFragmentProcessor { | 472 class GLEllipticalRRectEffect : public GrGLFragmentProcessor { |
483 public: | 473 public: |
484 GLEllipticalRRectEffect(const GrProcessor&); | 474 GLEllipticalRRectEffect(const GrProcessor&); |
485 | 475 |
486 virtual void emitCode(GrGLFPBuilder* builder, | 476 virtual void emitCode(EmitArgs&) override; |
487 const GrFragmentProcessor& effect, | |
488 const char* outputColor, | |
489 const char* inputColor, | |
490 const TransformedCoordsArray&, | |
491 const TextureSamplerArray&) override; | |
492 | 477 |
493 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessor
KeyBuilder*); | 478 static inline void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessor
KeyBuilder*); |
494 | 479 |
495 void setData(const GrGLProgramDataManager&, const GrProcessor&) override; | 480 void setData(const GrGLProgramDataManager&, const GrProcessor&) override; |
496 | 481 |
497 private: | 482 private: |
498 GrGLProgramDataManager::UniformHandle fInnerRectUniform; | 483 GrGLProgramDataManager::UniformHandle fInnerRectUniform; |
499 GrGLProgramDataManager::UniformHandle fInvRadiiSqdUniform; | 484 GrGLProgramDataManager::UniformHandle fInvRadiiSqdUniform; |
500 SkRRect fPrevRRect; | 485 SkRRect fPrevRRect; |
501 typedef GrGLFragmentProcessor INHERITED; | 486 typedef GrGLFragmentProcessor INHERITED; |
502 }; | 487 }; |
503 | 488 |
504 GLEllipticalRRectEffect::GLEllipticalRRectEffect(const GrProcessor& effect) { | 489 GLEllipticalRRectEffect::GLEllipticalRRectEffect(const GrProcessor& effect) { |
505 fPrevRRect.setEmpty(); | 490 fPrevRRect.setEmpty(); |
506 } | 491 } |
507 | 492 |
508 void GLEllipticalRRectEffect::emitCode(GrGLFPBuilder* builder, | 493 void GLEllipticalRRectEffect::emitCode(EmitArgs& args) { |
509 const GrFragmentProcessor& effect, | 494 const EllipticalRRectEffect& erre = args.fFp.cast<EllipticalRRectEffect>(); |
510 const char* outputColor, | |
511 const char* inputColor, | |
512 const TransformedCoordsArray&, | |
513 const TextureSamplerArray& samplers) { | |
514 const EllipticalRRectEffect& erre = effect.cast<EllipticalRRectEffect>(); | |
515 const char *rectName; | 495 const char *rectName; |
516 // The inner rect is the rrect bounds inset by the x/y radii | 496 // The inner rect is the rrect bounds inset by the x/y radii |
517 fInnerRectUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibi
lity, | 497 fInnerRectUniform = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_
Visibility, |
518 kVec4f_GrSLType, kDefault_GrSLPrecis
ion, | 498 kVec4f_GrSLType, kDefault_GrSLPrecis
ion, |
519 "innerRect", | 499 "innerRect", |
520 &rectName); | 500 &rectName); |
521 | 501 |
522 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); | 502 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder(); |
523 const char* fragmentPos = fsBuilder->fragmentPosition(); | 503 const char* fragmentPos = fsBuilder->fragmentPosition(); |
524 // At each quarter-ellipse corner we compute a vector that is the offset of
the fragment pos | 504 // At each quarter-ellipse corner we compute a vector that is the offset of
the fragment pos |
525 // to the ellipse center. The vector is pinned in x and y to be in the quart
er-plane relevant | 505 // to the ellipse center. The vector is pinned in x and y to be in the quart
er-plane relevant |
526 // to that corner. This means that points near the interior near the rrect t
op edge will have | 506 // to that corner. This means that points near the interior near the rrect t
op edge will have |
527 // a vector that points straight up for both the TL left and TR corners. Com
puting an | 507 // a vector that points straight up for both the TL left and TR corners. Com
puting an |
528 // alpha from this vector at either the TR or TL corner will give the correc
t result. Similarly, | 508 // alpha from this vector at either the TR or TL corner will give the correc
t result. Similarly, |
529 // fragments near the other three edges will get the correct AA. Fragments i
n the interior of | 509 // fragments near the other three edges will get the correct AA. Fragments i
n the interior of |
530 // the rrect will have a (0,0) vector at all four corners. So long as the ra
dii > 0.5 they will | 510 // the rrect will have a (0,0) vector at all four corners. So long as the ra
dii > 0.5 they will |
531 // correctly produce an alpha value of 1 at all four corners. We take the mi
n of all the alphas. | 511 // correctly produce an alpha value of 1 at all four corners. We take the mi
n of all the alphas. |
532 // The code below is a simplified version of the above that performs maxs on
the vector | 512 // The code below is a simplified version of the above that performs maxs on
the vector |
533 // components before computing distances and alpha values so that only one d
istance computation | 513 // components before computing distances and alpha values so that only one d
istance computation |
534 // need be computed to determine the min alpha. | 514 // need be computed to determine the min alpha. |
535 fsBuilder->codeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmen
tPos); | 515 fsBuilder->codeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmen
tPos); |
536 fsBuilder->codeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rect
Name); | 516 fsBuilder->codeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rect
Name); |
537 switch (erre.getRRect().getType()) { | 517 switch (erre.getRRect().getType()) { |
538 case SkRRect::kSimple_Type: { | 518 case SkRRect::kSimple_Type: { |
539 const char *invRadiiXYSqdName; | 519 const char *invRadiiXYSqdName; |
540 fInvRadiiSqdUniform = builder->addUniform(GrGLProgramBuilder::kFragm
ent_Visibility, | 520 fInvRadiiSqdUniform = args.fBuilder->addUniform(GrGLProgramBuilder::
kFragment_Visibility, |
541 kVec2f_GrSLType, kDefault_
GrSLPrecision, | 521 kVec2f_GrSLType, kDefault_
GrSLPrecision, |
542 "invRadiiXY", | 522 "invRadiiXY", |
543 &invRadiiXYSqdName); | 523 &invRadiiXYSqdName); |
544 fsBuilder->codeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n")
; | 524 fsBuilder->codeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n")
; |
545 // Z is the x/y offsets divided by squared radii. | 525 // Z is the x/y offsets divided by squared radii. |
546 fsBuilder->codeAppendf("\t\tvec2 Z = dxy * %s;\n", invRadiiXYSqdName
); | 526 fsBuilder->codeAppendf("\t\tvec2 Z = dxy * %s;\n", invRadiiXYSqdName
); |
547 break; | 527 break; |
548 } | 528 } |
549 case SkRRect::kNinePatch_Type: { | 529 case SkRRect::kNinePatch_Type: { |
550 const char *invRadiiLTRBSqdName; | 530 const char *invRadiiLTRBSqdName; |
551 fInvRadiiSqdUniform = builder->addUniform(GrGLProgramBuilder::kFragm
ent_Visibility, | 531 fInvRadiiSqdUniform = args.fBuilder->addUniform(GrGLProgramBuilder::
kFragment_Visibility, |
552 kVec4f_GrSLType, kDefault_
GrSLPrecision, | 532 kVec4f_GrSLType, kDefault_
GrSLPrecision, |
553 "invRadiiLTRB", | 533 "invRadiiLTRB", |
554 &invRadiiLTRBSqdName); | 534 &invRadiiLTRBSqdName); |
555 fsBuilder->codeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n")
; | 535 fsBuilder->codeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n")
; |
556 // Z is the x/y offsets divided by squared radii. We only care about
the (at most) one | 536 // Z is the x/y offsets divided by squared radii. We only care about
the (at most) one |
557 // corner where both the x and y offsets are positive, hence the max
es. (The inverse | 537 // corner where both the x and y offsets are positive, hence the max
es. (The inverse |
558 // squared radii will always be positive.) | 538 // squared radii will always be positive.) |
559 fsBuilder->codeAppendf("\t\tvec2 Z = max(max(dxy0 * %s.xy, dxy1 * %s
.zw), 0.0);\n", | 539 fsBuilder->codeAppendf("\t\tvec2 Z = max(max(dxy0 * %s.xy, dxy1 * %s
.zw), 0.0);\n", |
560 invRadiiLTRBSqdName, invRadiiLTRBSqdName); | 540 invRadiiLTRBSqdName, invRadiiLTRBSqdName); |
561 break; | 541 break; |
562 } | 542 } |
563 default: | 543 default: |
564 SkFAIL("RRect should always be simple or nine-patch."); | 544 SkFAIL("RRect should always be simple or nine-patch."); |
565 } | 545 } |
566 // implicit is the evaluation of (x/a)^2 + (y/b)^2 - 1. | 546 // implicit is the evaluation of (x/a)^2 + (y/b)^2 - 1. |
567 fsBuilder->codeAppend("\t\tfloat implicit = dot(Z, dxy) - 1.0;\n"); | 547 fsBuilder->codeAppend("\t\tfloat implicit = dot(Z, dxy) - 1.0;\n"); |
568 // grad_dot is the squared length of the gradient of the implicit. | 548 // grad_dot is the squared length of the gradient of the implicit. |
569 fsBuilder->codeAppendf("\t\tfloat grad_dot = 4.0 * dot(Z, Z);\n"); | 549 fsBuilder->codeAppendf("\t\tfloat grad_dot = 4.0 * dot(Z, Z);\n"); |
570 // avoid calling inversesqrt on zero. | 550 // avoid calling inversesqrt on zero. |
571 fsBuilder->codeAppend("\t\tgrad_dot = max(grad_dot, 1.0e-4);\n"); | 551 fsBuilder->codeAppend("\t\tgrad_dot = max(grad_dot, 1.0e-4);\n"); |
572 fsBuilder->codeAppendf("\t\tfloat approx_dist = implicit * inversesqrt(grad_
dot);\n"); | 552 fsBuilder->codeAppendf("\t\tfloat approx_dist = implicit * inversesqrt(grad_
dot);\n"); |
573 | 553 |
574 if (kFillAA_GrProcessorEdgeType == erre.getEdgeType()) { | 554 if (kFillAA_GrProcessorEdgeType == erre.getEdgeType()) { |
575 fsBuilder->codeAppend("\t\tfloat alpha = clamp(0.5 - approx_dist, 0.0, 1
.0);\n"); | 555 fsBuilder->codeAppend("\t\tfloat alpha = clamp(0.5 - approx_dist, 0.0, 1
.0);\n"); |
576 } else { | 556 } else { |
577 fsBuilder->codeAppend("\t\tfloat alpha = clamp(0.5 + approx_dist, 0.0, 1
.0);\n"); | 557 fsBuilder->codeAppend("\t\tfloat alpha = clamp(0.5 + approx_dist, 0.0, 1
.0);\n"); |
578 } | 558 } |
579 | 559 |
580 fsBuilder->codeAppendf("\t\t%s = %s;\n", outputColor, | 560 fsBuilder->codeAppendf("\t\t%s = %s;\n", args.fOutputColor, |
581 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_st
r()); | 561 (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr1("alpha")
).c_str()); |
582 } | 562 } |
583 | 563 |
584 void GLEllipticalRRectEffect::GenKey(const GrProcessor& effect, const GrGLSLCaps
&, | 564 void GLEllipticalRRectEffect::GenKey(const GrProcessor& effect, const GrGLSLCaps
&, |
585 GrProcessorKeyBuilder* b) { | 565 GrProcessorKeyBuilder* b) { |
586 const EllipticalRRectEffect& erre = effect.cast<EllipticalRRectEffect>(); | 566 const EllipticalRRectEffect& erre = effect.cast<EllipticalRRectEffect>(); |
587 GR_STATIC_ASSERT(kLast_GrProcessorEdgeType < (1 << 3)); | 567 GR_STATIC_ASSERT(kLast_GrProcessorEdgeType < (1 << 3)); |
588 b->add32(erre.getRRect().getType() | erre.getEdgeType() << 3); | 568 b->add32(erre.getRRect().getType() | erre.getEdgeType() << 3); |
589 } | 569 } |
590 | 570 |
591 void GLEllipticalRRectEffect::setData(const GrGLProgramDataManager& pdman, | 571 void GLEllipticalRRectEffect::setData(const GrGLProgramDataManager& pdman, |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
727 if (rrect.isNinePatch()) { | 707 if (rrect.isNinePatch()) { |
728 return EllipticalRRectEffect::Create(edgeType, rrect); | 708 return EllipticalRRectEffect::Create(edgeType, rrect); |
729 } | 709 } |
730 return NULL; | 710 return NULL; |
731 } | 711 } |
732 } | 712 } |
733 } | 713 } |
734 | 714 |
735 return NULL; | 715 return NULL; |
736 } | 716 } |
OLD | NEW |