OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 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 "SkGpuDevice.h" | 8 #include "SkGpuDevice.h" |
9 | 9 |
10 #include "effects/GrTextureDomainEffect.h" | 10 #include "effects/GrTextureDomainEffect.h" |
(...skipping 29 matching lines...) Expand all Loading... |
40 | 40 |
41 // we use the same effect slot on GrPaint for bitmaps and shaders (since drawBit
map, drawSprite, | 41 // we use the same effect slot on GrPaint for bitmaps and shaders (since drawBit
map, drawSprite, |
42 // and drawDevice ignore SkShader) | 42 // and drawDevice ignore SkShader) |
43 enum { | 43 enum { |
44 kShaderEffectIdx = 0, | 44 kShaderEffectIdx = 0, |
45 kBitmapEffectIdx = 0, | 45 kBitmapEffectIdx = 0, |
46 kColorFilterEffectIdx = 1, | 46 kColorFilterEffectIdx = 1, |
47 kXfermodeEffectIdx = 2, | 47 kXfermodeEffectIdx = 2, |
48 }; | 48 }; |
49 | 49 |
50 #define MAX_BLUR_SIGMA 4.0f | |
51 // FIXME: This value comes from from SkBlurMaskFilter.cpp. | |
52 // Should probably be put in a common header someplace. | |
53 #define MAX_BLUR_RADIUS SkIntToScalar(128) | |
54 // This constant approximates the scaling done in the software path's | |
55 // "high quality" mode, in SkBlurMask::Blur() (1 / sqrt(3)). | |
56 // IMHO, it actually should be 1: we blur "less" than we should do | |
57 // according to the CSS and canvas specs, simply because Safari does the same. | |
58 // Firefox used to do the same too, until 4.0 where they fixed it. So at some | |
59 // point we should probably get rid of these scaling constants and rebaseline | |
60 // all the blur tests. | |
61 #define BLUR_SIGMA_SCALE 0.6f | |
62 // This constant represents the screen alignment criterion in texels for | 50 // This constant represents the screen alignment criterion in texels for |
63 // requiring texture domain clamping to prevent color bleeding when drawing | 51 // requiring texture domain clamping to prevent color bleeding when drawing |
64 // a sub region of a larger source image. | 52 // a sub region of a larger source image. |
65 #define COLOR_BLEED_TOLERANCE SkFloatToScalar(0.001f) | 53 #define COLOR_BLEED_TOLERANCE SkFloatToScalar(0.001f) |
66 | 54 |
67 #define DO_DEFERRED_CLEAR() \ | 55 #define DO_DEFERRED_CLEAR() \ |
68 do { \ | 56 do { \ |
69 if (fNeedClear) { \ | 57 if (fNeedClear) { \ |
70 this->clear(SK_ColorTRANSPARENT); \ | 58 this->clear(SK_ColorTRANSPARENT); \ |
71 } \ | 59 } \ |
(...skipping 697 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
769 } | 757 } |
770 | 758 |
771 #include "SkMaskFilter.h" | 759 #include "SkMaskFilter.h" |
772 #include "SkBounder.h" | 760 #include "SkBounder.h" |
773 | 761 |
774 /////////////////////////////////////////////////////////////////////////////// | 762 /////////////////////////////////////////////////////////////////////////////// |
775 | 763 |
776 // helpers for applying mask filters | 764 // helpers for applying mask filters |
777 namespace { | 765 namespace { |
778 | 766 |
779 // We prefer to blur small rect with small radius via CPU. | 767 // Draw a mask using the supplied paint. Since the coverage/geometry |
780 #define MIN_GPU_BLUR_SIZE SkIntToScalar(64) | 768 // is already burnt into the mask this boils down to a rect draw. |
781 #define MIN_GPU_BLUR_RADIUS SkIntToScalar(32) | 769 // Return true if the mask was successfully drawn. |
782 inline bool shouldDrawBlurWithCPU(const SkRect& rect, SkScalar radius) { | 770 bool draw_mask(GrContext* context, const SkRect& maskRect, |
783 if (rect.width() <= MIN_GPU_BLUR_SIZE && | 771 GrPaint* grp, GrTexture* mask) { |
784 rect.height() <= MIN_GPU_BLUR_SIZE && | |
785 radius <= MIN_GPU_BLUR_RADIUS) { | |
786 return true; | |
787 } | |
788 return false; | |
789 } | |
790 | |
791 bool drawWithGPUMaskFilter(GrContext* context, const SkPath& devPath, const SkSt
rokeRec& stroke, | |
792 SkMaskFilter* filter, const SkRegion& clip, | |
793 SkBounder* bounder, GrPaint* grp) { | |
794 SkMaskFilter::BlurInfo info; | |
795 SkMaskFilter::BlurType blurType = filter->asABlur(&info); | |
796 if (SkMaskFilter::kNone_BlurType == blurType) { | |
797 return false; | |
798 } | |
799 SkScalar radius = info.fIgnoreTransform ? info.fRadius | |
800 : context->getMatrix().mapRadius(inf
o.fRadius); | |
801 radius = SkMinScalar(radius, MAX_BLUR_RADIUS); | |
802 if (radius <= 0) { | |
803 return false; | |
804 } | |
805 | |
806 SkRect srcRect = devPath.getBounds(); | |
807 if (shouldDrawBlurWithCPU(srcRect, radius)) { | |
808 return false; | |
809 } | |
810 | |
811 float sigma = SkScalarToFloat(radius) * BLUR_SIGMA_SCALE; | |
812 float sigma3 = sigma * 3.0f; | |
813 | |
814 SkRect clipRect; | |
815 clipRect.set(clip.getBounds()); | |
816 | |
817 // Outset srcRect and clipRect by 3 * sigma, to compute affected blur area. | |
818 srcRect.inset(SkFloatToScalar(-sigma3), SkFloatToScalar(-sigma3)); | |
819 clipRect.inset(SkFloatToScalar(-sigma3), SkFloatToScalar(-sigma3)); | |
820 srcRect.intersect(clipRect); | |
821 SkRect finalRect = srcRect; | |
822 SkIRect finalIRect; | |
823 finalRect.roundOut(&finalIRect); | |
824 if (clip.quickReject(finalIRect)) { | |
825 return true; | |
826 } | |
827 if (bounder && !bounder->doIRect(finalIRect)) { | |
828 return true; | |
829 } | |
830 GrPoint offset = GrPoint::Make(-srcRect.fLeft, -srcRect.fTop); | |
831 srcRect.offset(offset); | |
832 GrTextureDesc desc; | |
833 desc.fFlags = kRenderTarget_GrTextureFlagBit; | |
834 desc.fWidth = SkScalarCeilToInt(srcRect.width()); | |
835 desc.fHeight = SkScalarCeilToInt(srcRect.height()); | |
836 // We actually only need A8, but it often isn't supported as a | |
837 // render target so default to RGBA_8888 | |
838 desc.fConfig = kRGBA_8888_GrPixelConfig; | |
839 | |
840 if (context->isConfigRenderable(kAlpha_8_GrPixelConfig)) { | |
841 desc.fConfig = kAlpha_8_GrPixelConfig; | |
842 } | |
843 | |
844 GrAutoScratchTexture pathEntry(context, desc); | |
845 GrTexture* pathTexture = pathEntry.texture(); | |
846 if (NULL == pathTexture) { | |
847 return false; | |
848 } | |
849 | |
850 SkAutoTUnref<GrTexture> blurTexture; | |
851 | |
852 { | |
853 GrContext::AutoRenderTarget art(context, pathTexture->asRenderTarget()); | |
854 GrContext::AutoClip ac(context, srcRect); | |
855 | |
856 context->clear(NULL, 0); | |
857 | |
858 GrPaint tempPaint; | |
859 if (grp->isAntiAlias()) { | |
860 tempPaint.setAntiAlias(true); | |
861 // AA uses the "coverage" stages on GrDrawTarget. Coverage with a ds
t | |
862 // blend coeff of zero requires dual source blending support in orde
r | |
863 // to properly blend partially covered pixels. This means the AA | |
864 // code path may not be taken. So we use a dst blend coeff of ISA. W
e | |
865 // could special case AA draws to a dst surface with known alpha=0 t
o | |
866 // use a zero dst coeff when dual source blending isn't available.f | |
867 tempPaint.setBlendFunc(kOne_GrBlendCoeff, kISC_GrBlendCoeff); | |
868 } | |
869 | |
870 GrContext::AutoMatrix am; | |
871 | |
872 // Draw hard shadow to pathTexture with path top-left at origin using te
mpPaint. | |
873 SkMatrix translate; | |
874 translate.setTranslate(offset.fX, offset.fY); | |
875 am.set(context, translate); | |
876 context->drawPath(tempPaint, devPath, stroke); | |
877 | |
878 // If we're doing a normal blur, we can clobber the pathTexture in the | |
879 // gaussianBlur. Otherwise, we need to save it for later compositing. | |
880 bool isNormalBlur = blurType == SkMaskFilter::kNormal_BlurType; | |
881 blurTexture.reset(context->gaussianBlur(pathTexture, isNormalBlur, | |
882 srcRect, sigma, sigma)); | |
883 if (NULL == blurTexture) { | |
884 return false; | |
885 } | |
886 | |
887 if (!isNormalBlur) { | |
888 context->setIdentityMatrix(); | |
889 GrPaint paint; | |
890 SkMatrix matrix; | |
891 matrix.setIDiv(pathTexture->width(), pathTexture->height()); | |
892 // Blend pathTexture over blurTexture. | |
893 context->setRenderTarget(blurTexture->asRenderTarget()); | |
894 paint.colorStage(0)->setEffect( | |
895 GrSimpleTextureEffect::Create(pathTexture, matrix))->unref(); | |
896 if (SkMaskFilter::kInner_BlurType == blurType) { | |
897 // inner: dst = dst * src | |
898 paint.setBlendFunc(kDC_GrBlendCoeff, kZero_GrBlendCoeff); | |
899 } else if (SkMaskFilter::kSolid_BlurType == blurType) { | |
900 // solid: dst = src + dst - src * dst | |
901 // = (1 - dst) * src + 1 * dst | |
902 paint.setBlendFunc(kIDC_GrBlendCoeff, kOne_GrBlendCoeff); | |
903 } else if (SkMaskFilter::kOuter_BlurType == blurType) { | |
904 // outer: dst = dst * (1 - src) | |
905 // = 0 * src + (1 - src) * dst | |
906 paint.setBlendFunc(kZero_GrBlendCoeff, kISC_GrBlendCoeff); | |
907 } | |
908 context->drawRect(paint, srcRect); | |
909 } | |
910 } | |
911 | 772 |
912 GrContext::AutoMatrix am; | 773 GrContext::AutoMatrix am; |
913 if (!am.setIdentity(context, grp)) { | 774 if (!am.setIdentity(context, grp)) { |
914 return false; | 775 return false; |
915 } | 776 } |
916 | 777 |
917 static const int MASK_IDX = GrPaint::kMaxCoverageStages - 1; | 778 static const int MASK_IDX = GrPaint::kMaxCoverageStages - 1; |
918 // we assume the last mask index is available for use | 779 // we assume the last mask index is available for use |
919 GrAssert(!grp->isCoverageStageEnabled(MASK_IDX)); | 780 GrAssert(!grp->isCoverageStageEnabled(MASK_IDX)); |
920 | 781 |
921 SkMatrix matrix; | 782 SkMatrix matrix; |
922 matrix.setTranslate(-finalRect.fLeft, -finalRect.fTop); | 783 matrix.setTranslate(-maskRect.fLeft, -maskRect.fTop); |
923 matrix.postIDiv(blurTexture->width(), blurTexture->height()); | 784 matrix.postIDiv(mask->width(), mask->height()); |
924 | 785 |
925 grp->coverageStage(MASK_IDX)->reset(); | 786 grp->coverageStage(MASK_IDX)->reset(); |
926 grp->coverageStage(MASK_IDX)->setEffect( | 787 grp->coverageStage(MASK_IDX)->setEffect(GrSimpleTextureEffect::Create(mask,
matrix))->unref(); |
927 GrSimpleTextureEffect::Create(blurTexture, matrix))->unref(); | 788 context->drawRect(*grp, maskRect); |
928 context->drawRect(*grp, finalRect); | |
929 return true; | 789 return true; |
930 } | 790 } |
931 | 791 |
932 bool drawWithMaskFilter(GrContext* context, const SkPath& devPath, | 792 bool draw_with_mask_filter(GrContext* context, const SkPath& devPath, |
933 SkMaskFilter* filter, const SkRegion& clip, SkBounder* b
ounder, | 793 SkMaskFilter* filter, const SkRegion& clip, SkBounder
* bounder, |
934 GrPaint* grp, SkPaint::Style style) { | 794 GrPaint* grp, SkPaint::Style style) { |
935 SkMask srcM, dstM; | 795 SkMask srcM, dstM; |
936 | 796 |
937 if (!SkDraw::DrawToMask(devPath, &clip.getBounds(), filter, &context->getMat
rix(), &srcM, | 797 if (!SkDraw::DrawToMask(devPath, &clip.getBounds(), filter, &context->getMat
rix(), &srcM, |
938 SkMask::kComputeBoundsAndRenderImage_CreateMode, sty
le)) { | 798 SkMask::kComputeBoundsAndRenderImage_CreateMode, sty
le)) { |
939 return false; | 799 return false; |
940 } | 800 } |
941 SkAutoMaskFreeImage autoSrc(srcM.fImage); | 801 SkAutoMaskFreeImage autoSrc(srcM.fImage); |
942 | 802 |
943 if (!filter->filterMask(&dstM, srcM, context->getMatrix(), NULL)) { | 803 if (!filter->filterMask(&dstM, srcM, context->getMatrix(), NULL)) { |
944 return false; | 804 return false; |
945 } | 805 } |
946 // this will free-up dstM when we're done (allocated in filterMask()) | 806 // this will free-up dstM when we're done (allocated in filterMask()) |
947 SkAutoMaskFreeImage autoDst(dstM.fImage); | 807 SkAutoMaskFreeImage autoDst(dstM.fImage); |
948 | 808 |
949 if (clip.quickReject(dstM.fBounds)) { | 809 if (clip.quickReject(dstM.fBounds)) { |
950 return false; | 810 return false; |
951 } | 811 } |
952 if (bounder && !bounder->doIRect(dstM.fBounds)) { | 812 if (bounder && !bounder->doIRect(dstM.fBounds)) { |
953 return false; | 813 return false; |
954 } | 814 } |
955 | 815 |
956 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using | 816 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using |
957 // the current clip (and identity matrix) and GrPaint settings | 817 // the current clip (and identity matrix) and GrPaint settings |
958 GrContext::AutoMatrix am; | |
959 am.setIdentity(context, grp); | |
960 | |
961 GrTextureDesc desc; | 818 GrTextureDesc desc; |
962 desc.fWidth = dstM.fBounds.width(); | 819 desc.fWidth = dstM.fBounds.width(); |
963 desc.fHeight = dstM.fBounds.height(); | 820 desc.fHeight = dstM.fBounds.height(); |
964 desc.fConfig = kAlpha_8_GrPixelConfig; | 821 desc.fConfig = kAlpha_8_GrPixelConfig; |
965 | 822 |
966 GrAutoScratchTexture ast(context, desc); | 823 GrAutoScratchTexture ast(context, desc); |
967 GrTexture* texture = ast.texture(); | 824 GrTexture* texture = ast.texture(); |
968 | 825 |
969 if (NULL == texture) { | 826 if (NULL == texture) { |
970 return false; | 827 return false; |
971 } | 828 } |
972 texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig, | 829 texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig, |
973 dstM.fImage, dstM.fRowBytes); | 830 dstM.fImage, dstM.fRowBytes); |
974 | 831 |
975 static const int MASK_IDX = GrPaint::kMaxCoverageStages - 1; | 832 SkRect maskRect = SkRect::MakeFromIRect(dstM.fBounds); |
976 // we assume the last mask index is available for use | |
977 GrAssert(!grp->isCoverageStageEnabled(MASK_IDX)); | |
978 | 833 |
979 SkMatrix m; | 834 return draw_mask(context, maskRect, grp, texture); |
980 m.setTranslate(-dstM.fBounds.fLeft*SK_Scalar1, -dstM.fBounds.fTop*SK_Scalar1
); | 835 } |
981 m.postIDiv(texture->width(), texture->height()); | |
982 | 836 |
983 grp->coverageStage(MASK_IDX)->setEffect(GrSimpleTextureEffect::Create(textur
e, m))->unref(); | 837 // Create a mask of 'devPath' and place the result in 'mask'. Return true on |
984 GrRect d; | 838 // success; false otherwise. |
985 d.setLTRB(SkIntToScalar(dstM.fBounds.fLeft), | 839 bool create_mask_GPU(GrContext* context, |
986 SkIntToScalar(dstM.fBounds.fTop), | 840 const SkRect& maskRect, |
987 SkIntToScalar(dstM.fBounds.fRight), | 841 const SkPath& devPath, |
988 SkIntToScalar(dstM.fBounds.fBottom)); | 842 const SkStrokeRec& stroke, |
| 843 bool doAA, |
| 844 GrAutoScratchTexture* mask) { |
| 845 GrTextureDesc desc; |
| 846 desc.fFlags = kRenderTarget_GrTextureFlagBit; |
| 847 desc.fWidth = SkScalarCeilToInt(maskRect.width()); |
| 848 desc.fHeight = SkScalarCeilToInt(maskRect.height()); |
| 849 // We actually only need A8, but it often isn't supported as a |
| 850 // render target so default to RGBA_8888 |
| 851 desc.fConfig = kRGBA_8888_GrPixelConfig; |
| 852 if (context->isConfigRenderable(kAlpha_8_GrPixelConfig)) { |
| 853 desc.fConfig = kAlpha_8_GrPixelConfig; |
| 854 } |
989 | 855 |
990 context->drawRect(*grp, d); | 856 mask->set(context, desc); |
| 857 if (NULL == mask->texture()) { |
| 858 return false; |
| 859 } |
| 860 |
| 861 GrTexture* maskTexture = mask->texture(); |
| 862 SkRect clipRect = SkRect::MakeWH(maskRect.width(), maskRect.height()); |
| 863 |
| 864 GrContext::AutoRenderTarget art(context, maskTexture->asRenderTarget()); |
| 865 GrContext::AutoClip ac(context, clipRect); |
| 866 |
| 867 context->clear(NULL, 0x0); |
| 868 |
| 869 GrPaint tempPaint; |
| 870 if (doAA) { |
| 871 tempPaint.setAntiAlias(true); |
| 872 // AA uses the "coverage" stages on GrDrawTarget. Coverage with a dst |
| 873 // blend coeff of zero requires dual source blending support in order |
| 874 // to properly blend partially covered pixels. This means the AA |
| 875 // code path may not be taken. So we use a dst blend coeff of ISA. We |
| 876 // could special case AA draws to a dst surface with known alpha=0 to |
| 877 // use a zero dst coeff when dual source blending isn't available. |
| 878 tempPaint.setBlendFunc(kOne_GrBlendCoeff, kISC_GrBlendCoeff); |
| 879 } |
| 880 |
| 881 GrContext::AutoMatrix am; |
| 882 |
| 883 // Draw the mask into maskTexture with the path's top-left at the origin usi
ng tempPaint. |
| 884 SkMatrix translate; |
| 885 translate.setTranslate(-maskRect.fLeft, -maskRect.fTop); |
| 886 am.set(context, translate); |
| 887 context->drawPath(tempPaint, devPath, stroke); |
991 return true; | 888 return true; |
992 } | 889 } |
993 | 890 |
| 891 SkBitmap wrap_texture(GrTexture* texture) { |
| 892 SkBitmap result; |
| 893 bool dummy; |
| 894 SkBitmap::Config config = grConfig2skConfig(texture->config(), &dummy); |
| 895 result.setConfig(config, texture->width(), texture->height()); |
| 896 result.setPixelRef(SkNEW_ARGS(SkGrPixelRef, (texture)))->unref(); |
| 897 return result; |
994 } | 898 } |
995 | 899 |
996 /////////////////////////////////////////////////////////////////////////////// | 900 }; |
997 | 901 |
998 void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath, | 902 void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath, |
999 const SkPaint& paint, const SkMatrix* prePathMatrix, | 903 const SkPaint& paint, const SkMatrix* prePathMatrix, |
1000 bool pathIsMutable) { | 904 bool pathIsMutable) { |
1001 CHECK_FOR_NODRAW_ANNOTATION(paint); | 905 CHECK_FOR_NODRAW_ANNOTATION(paint); |
1002 CHECK_SHOULD_DRAW(draw, false); | 906 CHECK_SHOULD_DRAW(draw, false); |
1003 | 907 |
1004 GrPaint grPaint; | 908 GrPaint grPaint; |
1005 if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) { | 909 if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) { |
1006 return; | 910 return; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1044 } | 948 } |
1045 | 949 |
1046 if (!pathEffect && doHairLine) { | 950 if (!pathEffect && doHairLine) { |
1047 stroke.setHairlineStyle(); | 951 stroke.setHairlineStyle(); |
1048 } | 952 } |
1049 | 953 |
1050 if (paint.getMaskFilter()) { | 954 if (paint.getMaskFilter()) { |
1051 if (!stroke.isHairlineStyle()) { | 955 if (!stroke.isHairlineStyle()) { |
1052 if (stroke.applyToPath(&tmpPath, *pathPtr)) { | 956 if (stroke.applyToPath(&tmpPath, *pathPtr)) { |
1053 pathPtr = &tmpPath; | 957 pathPtr = &tmpPath; |
| 958 pathIsMutable = true; |
1054 stroke.setFillStyle(); | 959 stroke.setFillStyle(); |
1055 } | 960 } |
1056 } | 961 } |
1057 | 962 |
1058 // avoid possibly allocating a new path in transform if we can | 963 // avoid possibly allocating a new path in transform if we can |
1059 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath; | 964 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath; |
1060 | 965 |
1061 // transform the path into device space | 966 // transform the path into device space |
1062 pathPtr->transform(fContext->getMatrix(), devPathPtr); | 967 pathPtr->transform(fContext->getMatrix(), devPathPtr); |
1063 if (!drawWithGPUMaskFilter(fContext, *devPathPtr, stroke, paint.getMaskF
ilter(), | 968 |
1064 *draw.fClip, draw.fBounder, &grPaint)) { | 969 SkRect maskRect; |
1065 SkPaint::Style style = stroke.isHairlineStyle() ? SkPaint::kStroke_S
tyle : | 970 if (paint.getMaskFilter()->canFilterMaskGPU(devPathPtr->getBounds(), |
1066 SkPaint::kFill_Sty
le; | 971 draw.fClip->getBounds(), |
1067 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(), | 972 fContext->getMatrix(), |
1068 *draw.fClip, draw.fBounder, &grPaint, style); | 973 &maskRect)) { |
| 974 SkIRect finalIRect; |
| 975 maskRect.roundOut(&finalIRect); |
| 976 if (draw.fClip->quickReject(finalIRect)) { |
| 977 // clipped out |
| 978 return; |
| 979 } |
| 980 if (NULL != draw.fBounder && !draw.fBounder->doIRect(finalIRect)) { |
| 981 // nothing to draw |
| 982 return; |
| 983 } |
| 984 |
| 985 GrAutoScratchTexture mask; |
| 986 |
| 987 if (create_mask_GPU(fContext, maskRect, *devPathPtr, stroke, |
| 988 grPaint.isAntiAlias(), &mask)) { |
| 989 GrTexture* filtered; |
| 990 |
| 991 if (paint.getMaskFilter()->filterMaskGPU(mask.texture(), maskRec
t, &filtered, true)) { |
| 992 SkAutoTUnref<GrTexture> atu(filtered); |
| 993 |
| 994 if (draw_mask(fContext, maskRect, &grPaint, filtered)) { |
| 995 // This path is completely drawn |
| 996 return; |
| 997 } |
| 998 } |
| 999 } |
1069 } | 1000 } |
| 1001 |
| 1002 // draw the mask on the CPU - this is a fallthrough path in case the |
| 1003 // GPU path fails |
| 1004 SkPaint::Style style = stroke.isHairlineStyle() ? SkPaint::kStroke_Style
: |
| 1005 SkPaint::kFill_Style; |
| 1006 draw_with_mask_filter(fContext, *devPathPtr, paint.getMaskFilter(), |
| 1007 *draw.fClip, draw.fBounder, &grPaint, style); |
1070 return; | 1008 return; |
1071 } | 1009 } |
1072 | 1010 |
1073 fContext->drawPath(grPaint, *pathPtr, stroke); | 1011 fContext->drawPath(grPaint, *pathPtr, stroke); |
1074 } | 1012 } |
1075 | 1013 |
1076 namespace { | 1014 namespace { |
1077 | 1015 |
1078 inline int get_tile_count(int l, int t, int r, int b, int tileSize) { | 1016 inline int get_tile_count(int l, int t, int r, int b, int tileSize) { |
1079 int tilesX = (r / tileSize) - (l / tileSize) + 1; | 1017 int tilesX = (r / tileSize) - (l / tileSize) + 1; |
(...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1430 textureDomain, | 1368 textureDomain, |
1431 GrTextureDomainEffect::kClamp
_WrapMode, | 1369 GrTextureDomainEffect::kClamp
_WrapMode, |
1432 params.isBilerp())); | 1370 params.isBilerp())); |
1433 } else { | 1371 } else { |
1434 effect.reset(GrSimpleTextureEffect::Create(texture, SkMatrix::I(), param
s)); | 1372 effect.reset(GrSimpleTextureEffect::Create(texture, SkMatrix::I(), param
s)); |
1435 } | 1373 } |
1436 grPaint->colorStage(kBitmapEffectIdx)->setEffect(effect); | 1374 grPaint->colorStage(kBitmapEffectIdx)->setEffect(effect); |
1437 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &m); | 1375 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &m); |
1438 } | 1376 } |
1439 | 1377 |
1440 static SkBitmap wrap_texture(GrTexture* texture) { | |
1441 SkBitmap result; | |
1442 bool dummy; | |
1443 SkBitmap::Config config = grConfig2skConfig(texture->config(), &dummy); | |
1444 result.setConfig(config, texture->width(), texture->height()); | |
1445 result.setPixelRef(SkNEW_ARGS(SkGrPixelRef, (texture)))->unref(); | |
1446 return result; | |
1447 } | |
1448 | |
1449 static bool filter_texture(SkDevice* device, GrContext* context, | 1378 static bool filter_texture(SkDevice* device, GrContext* context, |
1450 GrTexture* texture, SkImageFilter* filter, | 1379 GrTexture* texture, SkImageFilter* filter, |
1451 int w, int h, SkBitmap* result) { | 1380 int w, int h, SkBitmap* result) { |
1452 GrAssert(filter); | 1381 GrAssert(filter); |
1453 SkDeviceImageFilterProxy proxy(device); | 1382 SkDeviceImageFilterProxy proxy(device); |
1454 | 1383 |
1455 if (filter->canFilterImageGPU()) { | 1384 if (filter->canFilterImageGPU()) { |
1456 // Save the render target and set it to NULL, so we don't accidentally d
raw to it in the | 1385 // Save the render target and set it to NULL, so we don't accidentally d
raw to it in the |
1457 // filter. Also set the clip wide open and the matrix to identity. | 1386 // filter. Also set the clip wide open and the matrix to identity. |
1458 GrContext::AutoWideOpenIdentityDraw awo(context, NULL); | 1387 GrContext::AutoWideOpenIdentityDraw awo(context, NULL); |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1601 // want explicitly our impl, so guard against a subclass of us overriding it | 1530 // want explicitly our impl, so guard against a subclass of us overriding it |
1602 if (!this->SkGpuDevice::canHandleImageFilter(filter)) { | 1531 if (!this->SkGpuDevice::canHandleImageFilter(filter)) { |
1603 return false; | 1532 return false; |
1604 } | 1533 } |
1605 | 1534 |
1606 SkAutoLockPixels alp(src, !src.getTexture()); | 1535 SkAutoLockPixels alp(src, !src.getTexture()); |
1607 if (!src.getTexture() && !src.readyToDraw()) { | 1536 if (!src.getTexture() && !src.readyToDraw()) { |
1608 return false; | 1537 return false; |
1609 } | 1538 } |
1610 | 1539 |
1611 GrPaint paint; | |
1612 | |
1613 GrTexture* texture; | 1540 GrTexture* texture; |
1614 // We assume here that the filter will not attempt to tile the src. Otherwis
e, this cache lookup | 1541 // We assume here that the filter will not attempt to tile the src. Otherwis
e, this cache lookup |
1615 // must be pushed upstack. | 1542 // must be pushed upstack. |
1616 SkAutoCachedTexture act(this, src, NULL, &texture); | 1543 SkAutoCachedTexture act(this, src, NULL, &texture); |
1617 | 1544 |
1618 return filter_texture(this, fContext, texture, filter, src.width(), src.heig
ht(), result); | 1545 return filter_texture(this, fContext, texture, filter, src.width(), src.heig
ht(), result); |
1619 } | 1546 } |
1620 | 1547 |
1621 /////////////////////////////////////////////////////////////////////////////// | 1548 /////////////////////////////////////////////////////////////////////////////// |
1622 | 1549 |
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1852 GrTexture* texture, | 1779 GrTexture* texture, |
1853 bool needClear) | 1780 bool needClear) |
1854 : SkDevice(make_bitmap(context, texture->asRenderTarget())) { | 1781 : SkDevice(make_bitmap(context, texture->asRenderTarget())) { |
1855 | 1782 |
1856 GrAssert(texture && texture->asRenderTarget()); | 1783 GrAssert(texture && texture->asRenderTarget()); |
1857 // This constructor is called from onCreateCompatibleDevice. It has locked t
he RT in the texture | 1784 // This constructor is called from onCreateCompatibleDevice. It has locked t
he RT in the texture |
1858 // cache. We pass true for the third argument so that it will get unlocked. | 1785 // cache. We pass true for the third argument so that it will get unlocked. |
1859 this->initFromRenderTarget(context, texture->asRenderTarget(), true); | 1786 this->initFromRenderTarget(context, texture->asRenderTarget(), true); |
1860 fNeedClear = needClear; | 1787 fNeedClear = needClear; |
1861 } | 1788 } |
OLD | NEW |