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("\tfloat %s;\n", output); |
| 634 builder->fsCodeAppendf("\t\t{\n"); |
| 635 builder->fsCodeAppendf("\t\t\tfloat coord = (0.5 * (abs(2.0*%s - %s) - %s))/
%s;\n", |
| 636 loc, blurred_width, sharp_width, profileSize); |
| 637 builder->fsCodeAppendf("\t\t\t%s = ", output); |
| 638 builder->fsAppendTextureLookup(sampler, "vec2(coord,0.5)"); |
| 639 builder->fsCodeAppend(".a;\n"); |
| 640 builder->fsCodeAppendf("\t\t}\n"); |
| 641 } |
| 642 |
627 void GrGLRectBlurEffect::emitCode(GrGLShaderBuilder* builder, | 643 void GrGLRectBlurEffect::emitCode(GrGLShaderBuilder* builder, |
628 const GrDrawEffect&, | 644 const GrDrawEffect&, |
629 EffectKey key, | 645 EffectKey key, |
630 const char* outputColor, | 646 const char* outputColor, |
631 const char* inputColor, | 647 const char* inputColor, |
632 const TransformedCoordsArray& coords, | 648 const TransformedCoordsArray& coords, |
633 const TextureSamplerArray& samplers) { | 649 const TextureSamplerArray& samplers) { |
634 | 650 |
635 SkString texture_coords = builder->ensureFSCoords2D(coords, 0); | 651 const char *rectName; |
| 652 const char *profileSizeName; |
| 653 |
| 654 fProxyRectUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibil
ity, |
| 655 kVec4f_GrSLType, |
| 656 "proxyRect", |
| 657 &rectName); |
| 658 fProfileSizeUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visib
ility, |
| 659 kFloat_GrSLType, |
| 660 "profileSize", |
| 661 &profileSizeName); |
| 662 |
| 663 const char *fragmentPos = builder->fragmentPosition(); |
636 | 664 |
637 if (inputColor) { | 665 if (inputColor) { |
638 builder->fsCodeAppendf("\tvec4 src=%s;\n", inputColor); | 666 builder->fsCodeAppendf("\tvec4 src=%s;\n", inputColor); |
639 } else { | 667 } else { |
640 builder->fsCodeAppendf("\tvec4 src=vec4(1)\n;"); | 668 builder->fsCodeAppendf("\tvec4 src=vec4(1)\n;"); |
641 } | 669 } |
642 | 670 |
643 builder->fsCodeAppendf("\tvec4 horiz = "); | 671 builder->fsCodeAppendf("\tvec2 translatedPos = %s.xy - %s.xy;\n", fragmentPo
s, rectName ); |
644 builder->fsAppendTextureLookup( samplers[0], texture_coords.c_str() ); | 672 builder->fsCodeAppendf("\tfloat width = %s.z - %s.x;\n", rectName, rectName)
; |
645 builder->fsCodeAppendf(";\n"); | 673 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 | 674 |
650 builder->fsCodeAppendf("\tfloat final = (horiz*vert).r;\n"); | 675 builder->fsCodeAppendf("\tvec2 smallDims = vec2(width - %s, height-%s);\n",
profileSizeName, profileSizeName); |
651 builder->fsCodeAppendf("\t%s = final*src;\n", outputColor); | 676 builder->fsCodeAppendf("\tfloat center = 2.0 * floor(%s/2.0 + .25) - 1.0;\n"
, profileSizeName); |
| 677 builder->fsCodeAppendf("\tvec2 wh = smallDims - vec2(center,center);\n"); |
| 678 |
| 679 OutputRectBlurProfileLookup(builder, samplers[0], "horiz_lookup", profileSiz
eName, "translatedPos.x", "width", "wh.x"); |
| 680 OutputRectBlurProfileLookup(builder, samplers[0], "vert_lookup", profileSize
Name, "translatedPos.y", "height", "wh.y"); |
| 681 |
| 682 builder->fsCodeAppendf("\tfloat final = horiz_lookup * vert_lookup;\n"); |
| 683 builder->fsCodeAppendf("\t%s = src * vec4(final);\n", outputColor ); |
652 } | 684 } |
653 | 685 |
654 void GrGLRectBlurEffect::setData(const GrGLUniformManager& uman, | 686 void GrGLRectBlurEffect::setData(const GrGLUniformManager& uman, |
655 const GrDrawEffect& drawEffect) { | 687 const GrDrawEffect& drawEffect) { |
| 688 const GrRectBlurEffect& rbe = drawEffect.castEffect<GrRectBlurEffect>(); |
| 689 SkRect rect = rbe.getRect(); |
| 690 |
| 691 uman.set4f(fProxyRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBott
om); |
| 692 uman.set1f(fProfileSizeUniform, SkScalarCeilToScalar(6*rbe.getSigma())); |
656 } | 693 } |
657 | 694 |
658 bool GrRectBlurEffect::CreateScanlineTextures(GrContext *context, float sigma, | 695 bool GrRectBlurEffect::CreateBlurProfileTexture(GrContext *context, float sigma, |
659 unsigned int width, unsigned int h
eight, | 696 GrTexture **blurProfileTexture) { |
660 GrTexture **horizontalScanline, | |
661 GrTexture **verticalScanline) { | |
662 GrTextureParams params; | 697 GrTextureParams params; |
663 GrTextureDesc texDesc; | 698 GrTextureDesc texDesc; |
664 | 699 |
665 unsigned int profile_size = SkScalarFloorToInt(6*sigma); | 700 unsigned int profile_size = SkScalarCeilToInt(6*sigma); |
666 | 701 |
667 texDesc.fWidth = width; | 702 texDesc.fWidth = profile_size; |
668 texDesc.fHeight = 1; | 703 texDesc.fHeight = 1; |
669 texDesc.fConfig = kAlpha_8_GrPixelConfig; | 704 texDesc.fConfig = kAlpha_8_GrPixelConfig; |
670 | 705 |
671 static const GrCacheID::Domain gBlurProfileDomain = GrCacheID::GenerateDomai
n(); | 706 static const GrCacheID::Domain gBlurProfileDomain = GrCacheID::GenerateDomai
n(); |
672 GrCacheID::Key key; | 707 GrCacheID::Key key; |
673 memset(&key, 0, sizeof(key)); | 708 memset(&key, 0, sizeof(key)); |
674 key.fData32[0] = profile_size; | 709 key.fData32[0] = profile_size; |
675 key.fData32[1] = width; | 710 key.fData32[1] = 1; |
676 key.fData32[2] = 1; | 711 GrCacheID blurProfileKey(gBlurProfileDomain, key); |
677 GrCacheID horizontalCacheID(gBlurProfileDomain, key); | |
678 | 712 |
679 uint8_t *profile = NULL; | 713 uint8_t *profile = NULL; |
680 SkAutoTDeleteArray<uint8_t> ada(NULL); | 714 SkAutoTDeleteArray<uint8_t> ada(NULL); |
681 | 715 |
682 *horizontalScanline = context->findAndRefTexture(texDesc, horizontalCacheID,
¶ms); | 716 *blurProfileTexture = context->findAndRefTexture(texDesc, blurProfileKey, &p
arams); |
683 | 717 |
684 if (NULL == *horizontalScanline) { | 718 if (NULL == *blurProfileTexture) { |
685 | 719 |
686 SkBlurMask::ComputeBlurProfile(sigma, &profile); | 720 SkBlurMask::ComputeBlurProfile(sigma, &profile); |
687 ada.reset(profile); | 721 ada.reset(profile); |
688 | 722 |
689 SkAutoTMalloc<uint8_t> horizontalPixels(width); | 723 *blurProfileTexture = context->createTexture(¶ms, texDesc, blurProfi
leKey, |
690 SkBlurMask::ComputeBlurredScanline(horizontalPixels, profile, width, sig
ma); | 724 profile, 0); |
691 | 725 |
692 *horizontalScanline = context->createTexture(¶ms, texDesc, horizonta
lCacheID, | 726 if (NULL == *blurProfileTexture) { |
693 horizontalPixels, 0); | |
694 | |
695 if (NULL == *horizontalScanline) { | |
696 return false; | 727 return false; |
697 } | 728 } |
698 } | 729 } |
699 | 730 |
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; | 731 return true; |
726 } | 732 } |
727 | 733 |
728 GrRectBlurEffect::GrRectBlurEffect(const SkRect& rect, float sigma, | 734 GrRectBlurEffect::GrRectBlurEffect(const SkRect& rect, float sigma, |
729 GrTexture *horizontal_scanline, GrTexture *ve
rtical_scanline) | 735 GrTexture *blur_profile) |
730 : INHERITED(), | 736 : INHERITED(), |
731 fWidth(horizontal_scanline->width()), | 737 fRect(rect), |
732 fHeight(vertical_scanline->width()), | |
733 fSigma(sigma), | 738 fSigma(sigma), |
734 fHorizontalScanlineAccess(horizontal_scanline), | 739 fBlurProfileAccess(blur_profile) { |
735 fVerticalScanlineAccess(vertical_scanline) { | 740 this->addTextureAccess(&fBlurProfileAccess); |
736 SkMatrix mat; | 741 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 } | 742 } |
743 | 743 |
744 GrRectBlurEffect::~GrRectBlurEffect() { | 744 GrRectBlurEffect::~GrRectBlurEffect() { |
745 } | 745 } |
746 | 746 |
747 const GrBackendEffectFactory& GrRectBlurEffect::getFactory() const { | 747 const GrBackendEffectFactory& GrRectBlurEffect::getFactory() const { |
748 return GrTBackendEffectFactory<GrRectBlurEffect>::getInstance(); | 748 return GrTBackendEffectFactory<GrRectBlurEffect>::getInstance(); |
749 } | 749 } |
750 | 750 |
751 bool GrRectBlurEffect::onIsEqual(const GrEffect& sBase) const { | 751 bool GrRectBlurEffect::onIsEqual(const GrEffect& sBase) const { |
752 const GrRectBlurEffect& s = CastEffect<GrRectBlurEffect>(sBase); | 752 const GrRectBlurEffect& s = CastEffect<GrRectBlurEffect>(sBase); |
753 return this->getWidth() == s.getWidth() && | 753 return this->getSigma() == s.getSigma() && this->getRect() == s.getRect(); |
754 this->getHeight() == s.getHeight() && | |
755 this->getSigma() == s.getSigma() && | |
756 this->getTransform() == s.getTransform(); | |
757 } | 754 } |
758 | 755 |
759 void GrRectBlurEffect::getConstantColorComponents(GrColor* color, uint32_t* vali
dFlags) const { | 756 void GrRectBlurEffect::getConstantColorComponents(GrColor* color, uint32_t* vali
dFlags) const { |
760 *validFlags = 0; | 757 *validFlags = 0; |
761 return; | 758 return; |
762 } | 759 } |
763 | 760 |
764 GR_DEFINE_EFFECT_TEST(GrRectBlurEffect); | 761 GR_DEFINE_EFFECT_TEST(GrRectBlurEffect); |
765 | 762 |
766 GrEffectRef* GrRectBlurEffect::TestCreate(SkRandom* random, | 763 GrEffectRef* GrRectBlurEffect::TestCreate(SkRandom* random, |
(...skipping 19 matching lines...) Expand all Loading... |
786 if (!path.isRect(&rect)) { | 783 if (!path.isRect(&rect)) { |
787 return false; | 784 return false; |
788 } | 785 } |
789 | 786 |
790 if (!strokeRec.isFillStyle()) { | 787 if (!strokeRec.isFillStyle()) { |
791 return false; | 788 return false; |
792 } | 789 } |
793 | 790 |
794 SkMatrix ctm = context->getMatrix(); | 791 SkMatrix ctm = context->getMatrix(); |
795 SkScalar xformedSigma = this->computeXformedSigma(ctm); | 792 SkScalar xformedSigma = this->computeXformedSigma(ctm); |
796 rect.outset(3*xformedSigma, 3*xformedSigma); | 793 |
| 794 int pad=SkScalarCeilToInt(6*xformedSigma)/2; |
| 795 rect.outset(SkIntToScalar(pad), SkIntToScalar(pad)); |
797 | 796 |
798 SkAutoTUnref<GrEffectRef> effect(GrRectBlurEffect::Create( | 797 SkAutoTUnref<GrEffectRef> effect(GrRectBlurEffect::Create( |
799 context, rect, xformedSigma)); | 798 context, rect, xformedSigma)); |
800 if (!effect) { | 799 if (!effect) { |
801 return false; | 800 return false; |
802 } | 801 } |
803 | 802 |
804 GrContext::AutoMatrix am; | 803 GrContext::AutoMatrix am; |
805 if (!am.setIdentity(context, grp)) { | 804 if (!am.setIdentity(context, grp)) { |
806 return false; | 805 return false; |
807 } | 806 } |
808 | 807 |
809 | |
810 grp->addCoverageEffect(effect); | 808 grp->addCoverageEffect(effect); |
811 | 809 |
812 context->drawRect(*grp, rect); | 810 context->drawRect(*grp, rect); |
813 return true; | 811 return true; |
814 } | 812 } |
815 | 813 |
816 class GrGLRRectBlurEffect; | 814 class GrGLRRectBlurEffect; |
817 | 815 |
818 class GrRRectBlurEffect : public GrEffect { | 816 class GrRRectBlurEffect : public GrEffect { |
819 public: | 817 public: |
(...skipping 389 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1209 } else { | 1207 } else { |
1210 str->append("None"); | 1208 str->append("None"); |
1211 } | 1209 } |
1212 str->append("))"); | 1210 str->append("))"); |
1213 } | 1211 } |
1214 #endif | 1212 #endif |
1215 | 1213 |
1216 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkBlurMaskFilter) | 1214 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkBlurMaskFilter) |
1217 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurMaskFilterImpl) | 1215 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurMaskFilterImpl) |
1218 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END | 1216 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END |
OLD | NEW |