| 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" |
| 11 #include "GrFragmentProcessor.h" | 11 #include "GrFragmentProcessor.h" |
| 12 #include "GrInvariantOutput.h" | 12 #include "GrInvariantOutput.h" |
| 13 #include "GrOvalEffect.h" | 13 #include "GrOvalEffect.h" |
| 14 #include "SkRRect.h" | 14 #include "SkRRect.h" |
| 15 #include "gl/GrGLFragmentProcessor.h" | 15 #include "gl/GrGLFragmentProcessor.h" |
| 16 #include "gl/builders/GrGLProgramBuilder.h" | 16 #include "glsl/GrGLSLFragmentShaderBuilder.h" |
| 17 #include "glsl/GrGLSLProgramBuilder.h" |
| 17 #include "glsl/GrGLSLProgramDataManager.h" | 18 #include "glsl/GrGLSLProgramDataManager.h" |
| 18 | 19 |
| 19 // The effects defined here only handle rrect radii >= kRadiusMin. | 20 // The effects defined here only handle rrect radii >= kRadiusMin. |
| 20 static const SkScalar kRadiusMin = SK_ScalarHalf; | 21 static const SkScalar kRadiusMin = SK_ScalarHalf; |
| 21 | 22 |
| 22 ////////////////////////////////////////////////////////////////////////////// | 23 ////////////////////////////////////////////////////////////////////////////// |
| 23 | 24 |
| 24 class CircularRRectEffect : public GrFragmentProcessor { | 25 class CircularRRectEffect : public GrFragmentProcessor { |
| 25 public: | 26 public: |
| 26 | 27 |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 148 } | 149 } |
| 149 | 150 |
| 150 void GLCircularRRectEffect::emitCode(EmitArgs& args) { | 151 void GLCircularRRectEffect::emitCode(EmitArgs& args) { |
| 151 const CircularRRectEffect& crre = args.fFp.cast<CircularRRectEffect>(); | 152 const CircularRRectEffect& crre = args.fFp.cast<CircularRRectEffect>(); |
| 152 const char *rectName; | 153 const char *rectName; |
| 153 const char *radiusPlusHalfName; | 154 const char *radiusPlusHalfName; |
| 154 // The inner rect is the rrect bounds inset by the radius. Its left, top, ri
ght, and bottom | 155 // The inner rect is the rrect bounds inset by the radius. Its left, top, ri
ght, and bottom |
| 155 // edges correspond to components x, y, z, and w, respectively. When a side
of the rrect has | 156 // edges correspond to components x, y, z, and w, respectively. When a side
of the rrect has |
| 156 // only rectangular corners, that side's value corresponds to the rect edge'
s value outset by | 157 // only rectangular corners, that side's value corresponds to the rect edge'
s value outset by |
| 157 // half a pixel. | 158 // half a pixel. |
| 158 fInnerRectUniform = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_
Visibility, | 159 fInnerRectUniform = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragmen
t_Visibility, |
| 159 kVec4f_GrSLType, kDefault_GrSLPrecis
ion, | 160 kVec4f_GrSLType, kDefault_GrSL
Precision, |
| 160 "innerRect", | 161 "innerRect", |
| 161 &rectName); | 162 &rectName); |
| 162 fRadiusPlusHalfUniform = args.fBuilder->addUniform(GrGLProgramBuilder::kFrag
ment_Visibility, | 163 fRadiusPlusHalfUniform = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFr
agment_Visibility, |
| 163 kFloat_GrSLType, kDefault_GrSLP
recision, | 164 kFloat_GrSLType, kDefault
_GrSLPrecision, |
| 164 "radiusPlusHalf", | 165 "radiusPlusHalf", |
| 165 &radiusPlusHalfName); | 166 &radiusPlusHalfName); |
| 166 | 167 |
| 167 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder(); | 168 GrGLSLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder()
; |
| 168 const char* fragmentPos = fsBuilder->fragmentPosition(); | 169 const char* fragmentPos = fsBuilder->fragmentPosition(); |
| 169 // At each quarter-circle corner we compute a vector that is the offset of t
he fragment position | 170 // At each quarter-circle corner we compute a vector that is the offset of t
he fragment position |
| 170 // from the circle center. The vector is pinned in x and y to be in the quar
ter-plane relevant | 171 // from the circle center. The vector is pinned in x and y to be in the quar
ter-plane relevant |
| 171 // to that corner. This means that points near the interior near the rrect t
op edge will have | 172 // to that corner. This means that points near the interior near the rrect t
op edge will have |
| 172 // a vector that points straight up for both the TL left and TR corners. Com
puting an | 173 // a vector that points straight up for both the TL left and TR corners. Com
puting an |
| 173 // alpha from this vector at either the TR or TL corner will give the correc
t result. Similarly, | 174 // alpha from this vector at either the TR or TL corner will give the correc
t result. Similarly, |
| 174 // fragments near the other three edges will get the correct AA. Fragments i
n the interior of | 175 // fragments near the other three edges will get the correct AA. Fragments i
n the interior of |
| 175 // the rrect will have a (0,0) vector at all four corners. So long as the ra
dius > 0.5 they will | 176 // the rrect will have a (0,0) vector at all four corners. So long as the ra
dius > 0.5 they will |
| 176 // correctly produce an alpha value of 1 at all four corners. We take the mi
n of all the alphas. | 177 // correctly produce an alpha value of 1 at all four corners. We take the mi
n of all the alphas. |
| 177 // The code below is a simplified version of the above that performs maxs on
the vector | 178 // The code below is a simplified version of the above that performs maxs on
the vector |
| (...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 357 } | 358 } |
| 358 pdman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.
fBottom); | 359 pdman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.
fBottom); |
| 359 pdman.set1f(fRadiusPlusHalfUniform, radius + 0.5f); | 360 pdman.set1f(fRadiusPlusHalfUniform, radius + 0.5f); |
| 360 fPrevRRect = rrect; | 361 fPrevRRect = rrect; |
| 361 } | 362 } |
| 362 } | 363 } |
| 363 | 364 |
| 364 ////////////////////////////////////////////////////////////////////////////////
//////////////////// | 365 ////////////////////////////////////////////////////////////////////////////////
//////////////////// |
| 365 | 366 |
| 366 void CircularRRectEffect::onGetGLProcessorKey(const GrGLSLCaps& caps, | 367 void CircularRRectEffect::onGetGLProcessorKey(const GrGLSLCaps& caps, |
| 367 GrProcessorKeyBuilder* b) const { | 368 GrProcessorKeyBuilder* b) const { |
| 368 GLCircularRRectEffect::GenKey(*this, caps, b); | 369 GLCircularRRectEffect::GenKey(*this, caps, b); |
| 369 } | 370 } |
| 370 | 371 |
| 371 GrGLFragmentProcessor* CircularRRectEffect::onCreateGLInstance() const { | 372 GrGLFragmentProcessor* CircularRRectEffect::onCreateGLInstance() const { |
| 372 return new GLCircularRRectEffect(*this); | 373 return new GLCircularRRectEffect(*this); |
| 373 } | 374 } |
| 374 | 375 |
| 375 ////////////////////////////////////////////////////////////////////////////// | 376 ////////////////////////////////////////////////////////////////////////////// |
| 376 | 377 |
| 377 class EllipticalRRectEffect : public GrFragmentProcessor { | 378 class EllipticalRRectEffect : public GrFragmentProcessor { |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 490 }; | 491 }; |
| 491 | 492 |
| 492 GLEllipticalRRectEffect::GLEllipticalRRectEffect(const GrProcessor& effect) { | 493 GLEllipticalRRectEffect::GLEllipticalRRectEffect(const GrProcessor& effect) { |
| 493 fPrevRRect.setEmpty(); | 494 fPrevRRect.setEmpty(); |
| 494 } | 495 } |
| 495 | 496 |
| 496 void GLEllipticalRRectEffect::emitCode(EmitArgs& args) { | 497 void GLEllipticalRRectEffect::emitCode(EmitArgs& args) { |
| 497 const EllipticalRRectEffect& erre = args.fFp.cast<EllipticalRRectEffect>(); | 498 const EllipticalRRectEffect& erre = args.fFp.cast<EllipticalRRectEffect>(); |
| 498 const char *rectName; | 499 const char *rectName; |
| 499 // The inner rect is the rrect bounds inset by the x/y radii | 500 // The inner rect is the rrect bounds inset by the x/y radii |
| 500 fInnerRectUniform = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_
Visibility, | 501 fInnerRectUniform = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragmen
t_Visibility, |
| 501 kVec4f_GrSLType, kDefault_GrSLPrecis
ion, | 502 kVec4f_GrSLType, kDefault_GrSLPrecis
ion, |
| 502 "innerRect", | 503 "innerRect", |
| 503 &rectName); | 504 &rectName); |
| 504 | 505 |
| 505 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder(); | 506 GrGLSLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder()
; |
| 506 const char* fragmentPos = fsBuilder->fragmentPosition(); | 507 const char* fragmentPos = fsBuilder->fragmentPosition(); |
| 507 // At each quarter-ellipse corner we compute a vector that is the offset of
the fragment pos | 508 // At each quarter-ellipse corner we compute a vector that is the offset of
the fragment pos |
| 508 // to the ellipse center. The vector is pinned in x and y to be in the quart
er-plane relevant | 509 // to the ellipse center. The vector is pinned in x and y to be in the quart
er-plane relevant |
| 509 // to that corner. This means that points near the interior near the rrect t
op edge will have | 510 // to that corner. This means that points near the interior near the rrect t
op edge will have |
| 510 // a vector that points straight up for both the TL left and TR corners. Com
puting an | 511 // a vector that points straight up for both the TL left and TR corners. Com
puting an |
| 511 // alpha from this vector at either the TR or TL corner will give the correc
t result. Similarly, | 512 // alpha from this vector at either the TR or TL corner will give the correc
t result. Similarly, |
| 512 // fragments near the other three edges will get the correct AA. Fragments i
n the interior of | 513 // fragments near the other three edges will get the correct AA. Fragments i
n the interior of |
| 513 // the rrect will have a (0,0) vector at all four corners. So long as the ra
dii > 0.5 they will | 514 // the rrect will have a (0,0) vector at all four corners. So long as the ra
dii > 0.5 they will |
| 514 // correctly produce an alpha value of 1 at all four corners. We take the mi
n of all the alphas. | 515 // correctly produce an alpha value of 1 at all four corners. We take the mi
n of all the alphas. |
| 515 // | 516 // |
| 516 // The code below is a simplified version of the above that performs maxs on
the vector | 517 // The code below is a simplified version of the above that performs maxs on
the vector |
| 517 // components before computing distances and alpha values so that only one d
istance computation | 518 // components before computing distances and alpha values so that only one d
istance computation |
| 518 // need be computed to determine the min alpha. | 519 // need be computed to determine the min alpha. |
| 519 fsBuilder->codeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmen
tPos); | 520 fsBuilder->codeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmen
tPos); |
| 520 fsBuilder->codeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rect
Name); | 521 fsBuilder->codeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rect
Name); |
| 521 // The uniforms with the inv squared radii are highp to prevent underflow. | 522 // The uniforms with the inv squared radii are highp to prevent underflow. |
| 522 switch (erre.getRRect().getType()) { | 523 switch (erre.getRRect().getType()) { |
| 523 case SkRRect::kSimple_Type: { | 524 case SkRRect::kSimple_Type: { |
| 524 const char *invRadiiXYSqdName; | 525 const char *invRadiiXYSqdName; |
| 525 fInvRadiiSqdUniform = args.fBuilder->addUniform(GrGLProgramBuilder::
kFragment_Visibility, | 526 fInvRadiiSqdUniform = args.fBuilder->addUniform( |
| 526 kVec2f_GrSLType, kHigh_GrS
LPrecision, | 527 GrGLSLProgramBuilder::k
Fragment_Visibility, |
| 527 "invRadiiXY", | 528 kVec2f_GrSLType, kHigh_
GrSLPrecision, |
| 528 &invRadiiXYSqdName); | 529 "invRadiiXY", |
| 530 &invRadiiXYSqdName); |
| 529 fsBuilder->codeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n")
; | 531 fsBuilder->codeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n")
; |
| 530 // Z is the x/y offsets divided by squared radii. | 532 // Z is the x/y offsets divided by squared radii. |
| 531 fsBuilder->codeAppendf("\t\tvec2 Z = dxy * %s;\n", invRadiiXYSqdName
); | 533 fsBuilder->codeAppendf("\t\tvec2 Z = dxy * %s;\n", invRadiiXYSqdName
); |
| 532 break; | 534 break; |
| 533 } | 535 } |
| 534 case SkRRect::kNinePatch_Type: { | 536 case SkRRect::kNinePatch_Type: { |
| 535 const char *invRadiiLTRBSqdName; | 537 const char *invRadiiLTRBSqdName; |
| 536 fInvRadiiSqdUniform = args.fBuilder->addUniform(GrGLProgramBuilder::
kFragment_Visibility, | 538 fInvRadiiSqdUniform = args.fBuilder->addUniform( |
| 537 kVec4f_GrSLType, kHigh_GrS
LPrecision, | 539 GrGLSLProgramBuilder::k
Fragment_Visibility, |
| 538 "invRadiiLTRB", | 540 kVec4f_GrSLType, kHigh_
GrSLPrecision, |
| 539 &invRadiiLTRBSqdName); | 541 "invRadiiLTRB", |
| 542 &invRadiiLTRBSqdName); |
| 540 fsBuilder->codeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n")
; | 543 fsBuilder->codeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n")
; |
| 541 // Z is the x/y offsets divided by squared radii. We only care about
the (at most) one | 544 // Z is the x/y offsets divided by squared radii. We only care about
the (at most) one |
| 542 // corner where both the x and y offsets are positive, hence the max
es. (The inverse | 545 // corner where both the x and y offsets are positive, hence the max
es. (The inverse |
| 543 // squared radii will always be positive.) | 546 // squared radii will always be positive.) |
| 544 fsBuilder->codeAppendf("\t\tvec2 Z = max(max(dxy0 * %s.xy, dxy1 * %s
.zw), 0.0);\n", | 547 fsBuilder->codeAppendf("\t\tvec2 Z = max(max(dxy0 * %s.xy, dxy1 * %s
.zw), 0.0);\n", |
| 545 invRadiiLTRBSqdName, invRadiiLTRBSqdName); | 548 invRadiiLTRBSqdName, invRadiiLTRBSqdName); |
| 546 break; | 549 break; |
| 547 } | 550 } |
| 548 default: | 551 default: |
| 549 SkFAIL("RRect should always be simple or nine-patch."); | 552 SkFAIL("RRect should always be simple or nine-patch."); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 606 SkFAIL("RRect should always be simple or nine-patch."); | 609 SkFAIL("RRect should always be simple or nine-patch."); |
| 607 } | 610 } |
| 608 pdman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.
fBottom); | 611 pdman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.
fBottom); |
| 609 fPrevRRect = rrect; | 612 fPrevRRect = rrect; |
| 610 } | 613 } |
| 611 } | 614 } |
| 612 | 615 |
| 613 ////////////////////////////////////////////////////////////////////////////////
//////////////////// | 616 ////////////////////////////////////////////////////////////////////////////////
//////////////////// |
| 614 | 617 |
| 615 void EllipticalRRectEffect::onGetGLProcessorKey(const GrGLSLCaps& caps, | 618 void EllipticalRRectEffect::onGetGLProcessorKey(const GrGLSLCaps& caps, |
| 616 GrProcessorKeyBuilder* b) const { | 619 GrProcessorKeyBuilder* b) const
{ |
| 617 GLEllipticalRRectEffect::GenKey(*this, caps, b); | 620 GLEllipticalRRectEffect::GenKey(*this, caps, b); |
| 618 } | 621 } |
| 619 | 622 |
| 620 GrGLFragmentProcessor* EllipticalRRectEffect::onCreateGLInstance() const { | 623 GrGLFragmentProcessor* EllipticalRRectEffect::onCreateGLInstance() const { |
| 621 return new GLEllipticalRRectEffect(*this); | 624 return new GLEllipticalRRectEffect(*this); |
| 622 } | 625 } |
| 623 | 626 |
| 624 ////////////////////////////////////////////////////////////////////////////// | 627 ////////////////////////////////////////////////////////////////////////////// |
| 625 | 628 |
| 626 GrFragmentProcessor* GrRRectEffect::Create(GrPrimitiveEdgeType edgeType, const S
kRRect& rrect) { | 629 GrFragmentProcessor* GrRRectEffect::Create(GrPrimitiveEdgeType edgeType, const S
kRRect& rrect) { |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 712 if (rrect.isNinePatch()) { | 715 if (rrect.isNinePatch()) { |
| 713 return EllipticalRRectEffect::Create(edgeType, rrect); | 716 return EllipticalRRectEffect::Create(edgeType, rrect); |
| 714 } | 717 } |
| 715 return nullptr; | 718 return nullptr; |
| 716 } | 719 } |
| 717 } | 720 } |
| 718 } | 721 } |
| 719 | 722 |
| 720 return nullptr; | 723 return nullptr; |
| 721 } | 724 } |
| OLD | NEW |