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