OLD | NEW |
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2006 The Android Open Source Project | 3 * Copyright 2006 The Android Open Source Project |
4 * | 4 * |
5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
7 */ | 7 */ |
8 | 8 |
9 #include "SkBlurMaskFilter.h" | 9 #include "SkBlurMaskFilter.h" |
10 #include "SkBlurMask.h" | 10 #include "SkBlurMask.h" |
(...skipping 539 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
550 typedef GrGLRectBlurEffect GLEffect; | 550 typedef GrGLRectBlurEffect GLEffect; |
551 | 551 |
552 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE; | 552 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE; |
553 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags
) const SK_OVERRIDE; | 553 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags
) const SK_OVERRIDE; |
554 | 554 |
555 /** | 555 /** |
556 * Create a simple filter effect with custom bicubic coefficients. | 556 * Create a simple filter effect with custom bicubic coefficients. |
557 */ | 557 */ |
558 static GrEffectRef* Create(GrContext *context, const SkRect& rect, | 558 static GrEffectRef* Create(GrContext *context, const SkRect& rect, |
559 float sigma) { | 559 float sigma) { |
560 GrTexture *horizontalScanline = NULL, *verticalScanline = NULL; | 560 GrTexture *blurProfileTexture = NULL; |
561 bool createdScanlines = CreateScanlineTextures(context, sigma, | 561 int doubleProfileSize = SkScalarCeilToInt(12*sigma); |
562 SkScalarCeilToInt(rect.wi
dth()), | 562 |
563 SkScalarCeilToInt(rect.he
ight()), | 563 if (doubleProfileSize <= rect.width() || doubleProfileSize <= rect.heigh
t()) { |
564 &horizontalScanline, &ver
ticalScanline); | 564 // if the blur sigma is too large so the gaussian overlaps the whole |
565 SkAutoTUnref<GrTexture> hunref(horizontalScanline), vunref(verticalScan
line); | 565 // rect in either direction, fall back to CPU path for now. |
566 if (!createdScanlines) { | 566 |
567 return NULL; | 567 return NULL; |
568 } | 568 } |
569 AutoEffectUnref effect(SkNEW_ARGS(GrRectBlurEffect, (rect, sigma, | 569 |
570 horizontalScanline,
verticalScanline))); | 570 bool createdBlurProfileTexture = CreateBlurProfileTexture(context, sigma
, &blurProfileTexture); |
| 571 SkAutoTUnref<GrTexture> hunref(blurProfileTexture); |
| 572 if (!createdBlurProfileTexture) { |
| 573 return NULL; |
| 574 } |
| 575 AutoEffectUnref effect(SkNEW_ARGS(GrRectBlurEffect, (rect, sigma, blurPr
ofileTexture))); |
571 return CreateEffectRef(effect); | 576 return CreateEffectRef(effect); |
572 } | 577 } |
573 | 578 |
574 unsigned int getWidth() const { return fWidth; } | 579 const SkRect& getRect() const { return fRect; } |
575 unsigned int getHeight() const { return fHeight; } | |
576 float getSigma() const { return fSigma; } | 580 float getSigma() const { return fSigma; } |
577 const GrCoordTransform& getTransform() const { return fTransform; } | |
578 | 581 |
579 private: | 582 private: |
580 GrRectBlurEffect(const SkRect& rect, float sigma, | 583 GrRectBlurEffect(const SkRect& rect, float sigma, GrTexture *blur_profile); |
581 GrTexture *horizontal_scanline, GrTexture *vertical_scanlin
e); | |
582 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE; | 584 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE; |
583 | 585 |
584 static bool CreateScanlineTextures(GrContext *context, float sigma, | 586 static bool CreateBlurProfileTexture(GrContext *context, float sigma, |
585 unsigned int width, unsigned int height, | 587 GrTexture **blurProfileTexture); |
586 GrTexture **horizontalScanline, | |
587 GrTexture **verticalScanline); | |
588 | 588 |
589 unsigned int fWidth, fHeight; | 589 SkRect fRect; |
590 float fSigma; | 590 float fSigma; |
591 GrTextureAccess fHorizontalScanlineAccess; | 591 GrTextureAccess fBlurProfileAccess; |
592 GrTextureAccess fVerticalScanlineAccess; | |
593 GrCoordTransform fTransform; | |
594 | 592 |
595 GR_DECLARE_EFFECT_TEST; | 593 GR_DECLARE_EFFECT_TEST; |
596 | 594 |
597 typedef GrEffect INHERITED; | 595 typedef GrEffect INHERITED; |
598 }; | 596 }; |
599 | 597 |
600 class GrGLRectBlurEffect : public GrGLEffect { | 598 class GrGLRectBlurEffect : public GrGLEffect { |
601 public: | 599 public: |
602 GrGLRectBlurEffect(const GrBackendEffectFactory& factory, | 600 GrGLRectBlurEffect(const GrBackendEffectFactory& factory, |
603 const GrDrawEffect&); | 601 const GrDrawEffect&); |
604 virtual void emitCode(GrGLShaderBuilder*, | 602 virtual void emitCode(GrGLShaderBuilder*, |
605 const GrDrawEffect&, | 603 const GrDrawEffect&, |
606 EffectKey, | 604 EffectKey, |
607 const char* outputColor, | 605 const char* outputColor, |
608 const char* inputColor, | 606 const char* inputColor, |
609 const TransformedCoordsArray&, | 607 const TransformedCoordsArray&, |
610 const TextureSamplerArray&) SK_OVERRIDE; | 608 const TextureSamplerArray&) SK_OVERRIDE; |
611 | 609 |
612 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVER
RIDE; | 610 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVER
RIDE; |
613 | 611 |
614 private: | 612 private: |
615 typedef GrGLUniformManager::UniformHandle UniformHandle; | 613 typedef GrGLUniformManager::UniformHandle UniformHandle; |
616 | 614 |
617 UniformHandle fWidthUni; | 615 UniformHandle fProxyRectUniform; |
618 UniformHandle fHeightUni; | 616 UniformHandle fProfileSizeUniform; |
619 | 617 |
620 typedef GrGLEffect INHERITED; | 618 typedef GrGLEffect INHERITED; |
621 }; | 619 }; |
622 | 620 |
| 621 |
| 622 |
623 GrGLRectBlurEffect::GrGLRectBlurEffect(const GrBackendEffectFactory& factory, co
nst GrDrawEffect&) | 623 GrGLRectBlurEffect::GrGLRectBlurEffect(const GrBackendEffectFactory& factory, co
nst GrDrawEffect&) |
624 : INHERITED(factory) { | 624 : INHERITED(factory) { |
625 } | 625 } |
626 | 626 |
| 627 void OutputRectBlurProfileLookup(GrGLShaderBuilder* builder, |
| 628 const GrGLShaderBuilder::TextureSampler& sample
r, |
| 629 const char *output, |
| 630 const char *profileSize, const char *loc, |
| 631 const char *blurred_width, |
| 632 const char *sharp_width) { |
| 633 builder->fsCodeAppendf("\t\tfloat coord = (0.5 * (abs(2*%s - %s) - %s))/%s;\
n", |
| 634 loc, blurred_width, sharp_width, profileSize); |
| 635 builder->fsCodeAppendf("\t\t%s = ", output); |
| 636 builder->fsAppendTextureLookup(sampler, "vec2(coord,0.5)"); |
| 637 builder->fsCodeAppend(";\n"); |
| 638 } |
| 639 |
627 void GrGLRectBlurEffect::emitCode(GrGLShaderBuilder* builder, | 640 void GrGLRectBlurEffect::emitCode(GrGLShaderBuilder* builder, |
628 const GrDrawEffect&, | 641 const GrDrawEffect&, |
629 EffectKey key, | 642 EffectKey key, |
630 const char* outputColor, | 643 const char* outputColor, |
631 const char* inputColor, | 644 const char* inputColor, |
632 const TransformedCoordsArray& coords, | 645 const TransformedCoordsArray& coords, |
633 const TextureSamplerArray& samplers) { | 646 const TextureSamplerArray& samplers) { |
634 | 647 |
635 SkString texture_coords = builder->ensureFSCoords2D(coords, 0); | 648 const char *rectName; |
| 649 const char *profileSizeName; |
| 650 |
| 651 fProxyRectUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibil
ity, |
| 652 kVec4f_GrSLType, |
| 653 "proxyRect", |
| 654 &rectName); |
| 655 fProfileSizeUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visib
ility, |
| 656 kFloat_GrSLType, |
| 657 "profileSize", |
| 658 &profileSizeName); |
| 659 |
| 660 const char *fragmentPos = builder->fragmentPosition(); |
636 | 661 |
637 if (inputColor) { | 662 if (inputColor) { |
638 builder->fsCodeAppendf("\tvec4 src=%s;\n", inputColor); | 663 builder->fsCodeAppendf("\tvec4 src=%s;\n", inputColor); |
639 } else { | 664 } else { |
640 builder->fsCodeAppendf("\tvec4 src=vec4(1)\n;"); | 665 builder->fsCodeAppendf("\tvec4 src=vec4(1)\n;"); |
641 } | 666 } |
642 | 667 |
643 builder->fsCodeAppendf("\tvec4 horiz = "); | 668 builder->fsCodeAppendf("\tvec2 translatedPos = %s.xy - %s.xy;\n", fragmentPo
s, rectName ); |
644 builder->fsAppendTextureLookup( samplers[0], texture_coords.c_str() ); | 669 builder->fsCodeAppendf("\tfloat width = %s.z - %s.x;\n", rectName, rectName)
; |
645 builder->fsCodeAppendf(";\n"); | 670 builder->fsCodeAppendf("\tfloat height = %s.w - %s.y;\n", rectName, rectName
); |
646 builder->fsCodeAppendf("\tvec4 vert = "); | |
647 builder->fsAppendTextureLookup( samplers[1], texture_coords.c_str() ); | |
648 builder->fsCodeAppendf(";\n"); | |
649 | 671 |
650 builder->fsCodeAppendf("\tfloat final = (horiz*vert).r;\n"); | 672 builder->fsCodeAppendf("\tvec2 smallDims = vec2(width - %s, height-%s);\n",
profileSizeName, profileSizeName); |
651 builder->fsCodeAppendf("\t%s = final*src;\n", outputColor); | 673 builder->fsCodeAppendf("\tfloat center = 2.0 * floor(%s/2 + .25) - 1;\n", pr
ofileSizeName); |
| 674 builder->fsCodeAppendf("\tvec2 wh = smallDims - vec2(center,center);\n"); |
| 675 |
| 676 builder->fsCodeAppendf("\tfloat horiz_lookup;\n"); |
| 677 builder->fsCodeAppendf("\tif (%s <= smallDims.x) {\n", profileSizeName); |
| 678 OutputRectBlurProfileLookup(builder, samplers[0], "horiz_lookup", profileSiz
eName, "translatedPos.x", "width", "wh.x"); |
| 679 builder->fsCodeAppendf("\t}\n"); |
| 680 |
| 681 builder->fsCodeAppendf("\tfloat vert_lookup;\n"); |
| 682 builder->fsCodeAppendf("\tif (%s <= smallDims.y) {\n", profileSizeName); |
| 683 OutputRectBlurProfileLookup(builder, samplers[0], "vert_lookup", profileSize
Name, "translatedPos.y", "height", "wh.y"); |
| 684 builder->fsCodeAppendf("\t}\n"); |
| 685 |
| 686 builder->fsCodeAppendf("\tfloat final = 1.0 - horiz_lookup * vert_lookup;\n"
); |
| 687 |
| 688 builder->fsCodeAppendf("\t%s = vec4(final, final, final, 1);\n", outputColor
); |
652 } | 689 } |
653 | 690 |
654 void GrGLRectBlurEffect::setData(const GrGLUniformManager& uman, | 691 void GrGLRectBlurEffect::setData(const GrGLUniformManager& uman, |
655 const GrDrawEffect& drawEffect) { | 692 const GrDrawEffect& drawEffect) { |
| 693 const GrRectBlurEffect& rbe = drawEffect.castEffect<GrRectBlurEffect>(); |
| 694 SkRect rect = rbe.getRect(); |
| 695 |
| 696 uman.set4f(fProxyRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBott
om); |
| 697 uman.set1f(fProfileSizeUniform, SkScalarCeilToScalar(6*rbe.getSigma())); |
656 } | 698 } |
657 | 699 |
658 bool GrRectBlurEffect::CreateScanlineTextures(GrContext *context, float sigma, | 700 bool GrRectBlurEffect::CreateBlurProfileTexture(GrContext *context, float sigma, |
659 unsigned int width, unsigned int h
eight, | 701 GrTexture **blurProfileTexture) { |
660 GrTexture **horizontalScanline, | |
661 GrTexture **verticalScanline) { | |
662 GrTextureParams params; | 702 GrTextureParams params; |
663 GrTextureDesc texDesc; | 703 GrTextureDesc texDesc; |
664 | 704 |
665 unsigned int profile_size = SkScalarFloorToInt(6*sigma); | 705 unsigned int profile_size = SkScalarCeilToInt(6*sigma); |
666 | 706 |
667 texDesc.fWidth = width; | 707 texDesc.fWidth = profile_size; |
668 texDesc.fHeight = 1; | 708 texDesc.fHeight = 1; |
669 texDesc.fConfig = kAlpha_8_GrPixelConfig; | 709 texDesc.fConfig = kAlpha_8_GrPixelConfig; |
670 | 710 |
671 static const GrCacheID::Domain gBlurProfileDomain = GrCacheID::GenerateDomai
n(); | 711 static const GrCacheID::Domain gBlurProfileDomain = GrCacheID::GenerateDomai
n(); |
672 GrCacheID::Key key; | 712 GrCacheID::Key key; |
673 memset(&key, 0, sizeof(key)); | 713 memset(&key, 0, sizeof(key)); |
674 key.fData32[0] = profile_size; | 714 key.fData32[0] = profile_size; |
675 key.fData32[1] = width; | 715 key.fData32[1] = 1; |
676 key.fData32[2] = 1; | 716 GrCacheID blurProfileKey(gBlurProfileDomain, key); |
677 GrCacheID horizontalCacheID(gBlurProfileDomain, key); | |
678 | 717 |
679 uint8_t *profile = NULL; | 718 uint8_t *profile = NULL; |
680 SkAutoTDeleteArray<uint8_t> ada(NULL); | 719 SkAutoTDeleteArray<uint8_t> ada(NULL); |
681 | 720 |
682 *horizontalScanline = context->findAndRefTexture(texDesc, horizontalCacheID,
¶ms); | 721 *blurProfileTexture = context->findAndRefTexture(texDesc, blurProfileKey, &p
arams); |
683 | 722 |
684 if (NULL == *horizontalScanline) { | 723 if (NULL == *blurProfileTexture) { |
685 | 724 |
686 SkBlurMask::ComputeBlurProfile(sigma, &profile); | 725 SkBlurMask::ComputeBlurProfile(sigma, &profile); |
687 ada.reset(profile); | 726 ada.reset(profile); |
688 | 727 |
689 SkAutoTMalloc<uint8_t> horizontalPixels(width); | 728 *blurProfileTexture = context->createTexture(¶ms, texDesc, blurProfi
leKey, |
690 SkBlurMask::ComputeBlurredScanline(horizontalPixels, profile, width, sig
ma); | 729 profile, 0); |
691 | 730 |
692 *horizontalScanline = context->createTexture(¶ms, texDesc, horizonta
lCacheID, | 731 if (NULL == *blurProfileTexture) { |
693 horizontalPixels, 0); | |
694 | |
695 if (NULL == *horizontalScanline) { | |
696 return false; | 732 return false; |
697 } | 733 } |
698 } | 734 } |
699 | 735 |
700 texDesc.fWidth = 1; | |
701 texDesc.fHeight = height; | |
702 key.fData32[1] = 1; | |
703 key.fData32[2] = height; | |
704 GrCacheID verticalCacheID(gBlurProfileDomain, key); | |
705 | |
706 *verticalScanline = context->findAndRefTexture(texDesc, verticalCacheID, &pa
rams); | |
707 if (NULL == *verticalScanline) { | |
708 if (NULL == profile) { | |
709 SkBlurMask::ComputeBlurProfile(sigma, &profile); | |
710 ada.reset(profile); | |
711 } | |
712 | |
713 SkAutoTMalloc<uint8_t> verticalPixels(height); | |
714 SkBlurMask::ComputeBlurredScanline(verticalPixels, profile, height, sigm
a); | |
715 | |
716 *verticalScanline = context->createTexture(¶ms, texDesc, verticalCac
heID, | |
717 verticalPixels, 0); | |
718 | |
719 if (NULL == *verticalScanline) { | |
720 SkSafeSetNull(*horizontalScanline); | |
721 return false; | |
722 } | |
723 | |
724 } | |
725 return true; | 736 return true; |
726 } | 737 } |
727 | 738 |
728 GrRectBlurEffect::GrRectBlurEffect(const SkRect& rect, float sigma, | 739 GrRectBlurEffect::GrRectBlurEffect(const SkRect& rect, float sigma, |
729 GrTexture *horizontal_scanline, GrTexture *ve
rtical_scanline) | 740 GrTexture *blur_profile) |
730 : INHERITED(), | 741 : INHERITED(), |
731 fWidth(horizontal_scanline->width()), | 742 fRect(rect), |
732 fHeight(vertical_scanline->width()), | |
733 fSigma(sigma), | 743 fSigma(sigma), |
734 fHorizontalScanlineAccess(horizontal_scanline), | 744 fBlurProfileAccess(blur_profile) { |
735 fVerticalScanlineAccess(vertical_scanline) { | 745 this->addTextureAccess(&fBlurProfileAccess); |
736 SkMatrix mat; | 746 this->setWillReadFragmentPosition(); |
737 mat.setRectToRect(rect, SkRect::MakeWH(1,1), SkMatrix::kFill_ScaleToFit); | |
738 fTransform.reset(kLocal_GrCoordSet, mat); | |
739 this->addTextureAccess(&fHorizontalScanlineAccess); | |
740 this->addTextureAccess(&fVerticalScanlineAccess); | |
741 this->addCoordTransform(&fTransform); | |
742 } | 747 } |
743 | 748 |
744 GrRectBlurEffect::~GrRectBlurEffect() { | 749 GrRectBlurEffect::~GrRectBlurEffect() { |
745 } | 750 } |
746 | 751 |
747 const GrBackendEffectFactory& GrRectBlurEffect::getFactory() const { | 752 const GrBackendEffectFactory& GrRectBlurEffect::getFactory() const { |
748 return GrTBackendEffectFactory<GrRectBlurEffect>::getInstance(); | 753 return GrTBackendEffectFactory<GrRectBlurEffect>::getInstance(); |
749 } | 754 } |
750 | 755 |
751 bool GrRectBlurEffect::onIsEqual(const GrEffect& sBase) const { | 756 bool GrRectBlurEffect::onIsEqual(const GrEffect& sBase) const { |
752 const GrRectBlurEffect& s = CastEffect<GrRectBlurEffect>(sBase); | 757 const GrRectBlurEffect& s = CastEffect<GrRectBlurEffect>(sBase); |
753 return this->getWidth() == s.getWidth() && | 758 return this->getSigma() == s.getSigma(); |
754 this->getHeight() == s.getHeight() && | |
755 this->getSigma() == s.getSigma() && | |
756 this->getTransform() == s.getTransform(); | |
757 } | 759 } |
758 | 760 |
759 void GrRectBlurEffect::getConstantColorComponents(GrColor* color, uint32_t* vali
dFlags) const { | 761 void GrRectBlurEffect::getConstantColorComponents(GrColor* color, uint32_t* vali
dFlags) const { |
760 *validFlags = 0; | 762 *validFlags = 0; |
761 return; | 763 return; |
762 } | 764 } |
763 | 765 |
764 GR_DEFINE_EFFECT_TEST(GrRectBlurEffect); | 766 GR_DEFINE_EFFECT_TEST(GrRectBlurEffect); |
765 | 767 |
766 GrEffectRef* GrRectBlurEffect::TestCreate(SkRandom* random, | 768 GrEffectRef* GrRectBlurEffect::TestCreate(SkRandom* random, |
(...skipping 19 matching lines...) Expand all Loading... |
786 if (!path.isRect(&rect)) { | 788 if (!path.isRect(&rect)) { |
787 return false; | 789 return false; |
788 } | 790 } |
789 | 791 |
790 if (!strokeRec.isFillStyle()) { | 792 if (!strokeRec.isFillStyle()) { |
791 return false; | 793 return false; |
792 } | 794 } |
793 | 795 |
794 SkMatrix ctm = context->getMatrix(); | 796 SkMatrix ctm = context->getMatrix(); |
795 SkScalar xformedSigma = this->computeXformedSigma(ctm); | 797 SkScalar xformedSigma = this->computeXformedSigma(ctm); |
796 rect.outset(3*xformedSigma, 3*xformedSigma); | 798 |
| 799 float pad=SkScalarCeilToScalar(6*xformedSigma)/2.0f; |
| 800 rect.outset(pad, pad); |
797 | 801 |
798 SkAutoTUnref<GrEffectRef> effect(GrRectBlurEffect::Create( | 802 SkAutoTUnref<GrEffectRef> effect(GrRectBlurEffect::Create( |
799 context, rect, xformedSigma)); | 803 context, rect, xformedSigma)); |
800 if (!effect) { | 804 if (!effect) { |
801 return false; | 805 return false; |
802 } | 806 } |
803 | 807 |
804 GrContext::AutoMatrix am; | 808 GrContext::AutoMatrix am; |
805 if (!am.setIdentity(context, grp)) { | 809 if (!am.setIdentity(context, grp)) { |
806 return false; | 810 return false; |
807 } | 811 } |
808 | 812 |
809 | |
810 grp->addCoverageEffect(effect); | 813 grp->addCoverageEffect(effect); |
811 | 814 |
812 context->drawRect(*grp, rect); | 815 context->drawRect(*grp, rect); |
813 return true; | 816 return true; |
814 } | 817 } |
815 | 818 |
816 class GrGLRRectBlurEffect; | 819 class GrGLRRectBlurEffect; |
817 | 820 |
818 class GrRRectBlurEffect : public GrEffect { | 821 class GrRRectBlurEffect : public GrEffect { |
819 public: | 822 public: |
(...skipping 389 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1209 } else { | 1212 } else { |
1210 str->append("None"); | 1213 str->append("None"); |
1211 } | 1214 } |
1212 str->append("))"); | 1215 str->append("))"); |
1213 } | 1216 } |
1214 #endif | 1217 #endif |
1215 | 1218 |
1216 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkBlurMaskFilter) | 1219 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkBlurMaskFilter) |
1217 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurMaskFilterImpl) | 1220 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurMaskFilterImpl) |
1218 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END | 1221 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END |
OLD | NEW |