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 "GrBlurUtils.h" |
10 #include "GrContext.h" | 11 #include "GrContext.h" |
11 #include "GrDrawContext.h" | 12 #include "GrDrawContext.h" |
12 #include "GrGpu.h" | 13 #include "GrGpu.h" |
13 #include "GrGpuResourcePriv.h" | 14 #include "GrGpuResourcePriv.h" |
14 #include "GrLayerHoister.h" | 15 #include "GrLayerHoister.h" |
15 #include "GrRecordReplaceDraw.h" | 16 #include "GrRecordReplaceDraw.h" |
16 #include "GrStrokeInfo.h" | 17 #include "GrStrokeInfo.h" |
17 #include "GrTextContext.h" | 18 #include "GrTextContext.h" |
18 #include "GrTracing.h" | 19 #include "GrTracing.h" |
19 #include "SkCanvasPriv.h" | 20 #include "SkCanvasPriv.h" |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
160 fNeedClear = flags & kNeedClear_Flag; | 161 fNeedClear = flags & kNeedClear_Flag; |
161 | 162 |
162 fRenderTarget = SkRef(rt); | 163 fRenderTarget = SkRef(rt); |
163 | 164 |
164 SkImageInfo info = rt->surfacePriv().info().makeWH(width, height); | 165 SkImageInfo info = rt->surfacePriv().info().makeWH(width, height); |
165 SkPixelRef* pr = SkNEW_ARGS(SkGrPixelRef, (info, rt)); | 166 SkPixelRef* pr = SkNEW_ARGS(SkGrPixelRef, (info, rt)); |
166 fLegacyBitmap.setInfo(info); | 167 fLegacyBitmap.setInfo(info); |
167 fLegacyBitmap.setPixelRef(pr)->unref(); | 168 fLegacyBitmap.setPixelRef(pr)->unref(); |
168 | 169 |
169 bool useDFT = fSurfaceProps.isUseDistanceFieldFonts(); | 170 bool useDFT = fSurfaceProps.isUseDistanceFieldFonts(); |
170 fTextContext = fContext->createTextContext(fRenderTarget, this, this->getLea
kyProperties(), | 171 fTextContext = fContext->createTextContext(fRenderTarget, this->getLeakyProp
erties(), useDFT); |
171 useDFT); | |
172 fDrawContext.reset(SkRef(fContext->drawContext())); | 172 fDrawContext.reset(SkRef(fContext->drawContext())); |
173 } | 173 } |
174 | 174 |
175 GrRenderTarget* SkGpuDevice::CreateRenderTarget(GrContext* context, SkSurface::B
udgeted budgeted, | 175 GrRenderTarget* SkGpuDevice::CreateRenderTarget(GrContext* context, SkSurface::B
udgeted budgeted, |
176 const SkImageInfo& origInfo, int
sampleCount) { | 176 const SkImageInfo& origInfo, int
sampleCount) { |
177 if (kUnknown_SkColorType == origInfo.colorType() || | 177 if (kUnknown_SkColorType == origInfo.colorType() || |
178 origInfo.width() < 0 || origInfo.height() < 0) { | 178 origInfo.width() < 0 || origInfo.height() < 0) { |
179 return NULL; | 179 return NULL; |
180 } | 180 } |
181 | 181 |
(...skipping 437 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
619 return; | 619 return; |
620 } | 620 } |
621 | 621 |
622 fDrawContext->drawOval(fRenderTarget, fClip, grPaint, *draw.fMatrix, oval, s
trokeInfo); | 622 fDrawContext->drawOval(fRenderTarget, fClip, grPaint, *draw.fMatrix, oval, s
trokeInfo); |
623 } | 623 } |
624 | 624 |
625 #include "SkMaskFilter.h" | 625 #include "SkMaskFilter.h" |
626 | 626 |
627 /////////////////////////////////////////////////////////////////////////////// | 627 /////////////////////////////////////////////////////////////////////////////// |
628 | 628 |
629 // helpers for applying mask filters | 629 static SkBitmap wrap_texture(GrTexture* texture, int width, int height) { |
630 namespace { | |
631 | |
632 // Draw a mask using the supplied paint. Since the coverage/geometry | |
633 // is already burnt into the mask this boils down to a rect draw. | |
634 // Return true if the mask was successfully drawn. | |
635 bool draw_mask(GrDrawContext* drawContext, | |
636 GrRenderTarget* rt, | |
637 const GrClip& clip, | |
638 const SkMatrix& viewMatrix, | |
639 const SkRect& maskRect, | |
640 GrPaint* grp, | |
641 GrTexture* mask) { | |
642 SkMatrix matrix; | |
643 matrix.setTranslate(-maskRect.fLeft, -maskRect.fTop); | |
644 matrix.postIDiv(mask->width(), mask->height()); | |
645 | |
646 grp->addCoverageProcessor(GrSimpleTextureEffect::Create(mask, matrix, | |
647 kDevice_GrCoordSet))
->unref(); | |
648 | |
649 SkMatrix inverse; | |
650 if (!viewMatrix.invert(&inverse)) { | |
651 return false; | |
652 } | |
653 drawContext->drawNonAARectWithLocalMatrix(rt, clip, *grp, SkMatrix::I(), mas
kRect, inverse); | |
654 return true; | |
655 } | |
656 | |
657 static bool clip_bounds_quick_reject(const SkIRect& clipBounds, const SkIRect& r
ect) { | |
658 return clipBounds.isEmpty() || rect.isEmpty() || !SkIRect::Intersects(clipBo
unds, rect); | |
659 } | |
660 | |
661 bool draw_with_mask_filter(GrDrawContext* drawContext, | |
662 GrTextureProvider* textureProvider, | |
663 GrRenderTarget* rt, | |
664 const GrClip& clipData, | |
665 const SkMatrix& viewMatrix, | |
666 const SkPath& devPath, | |
667 SkMaskFilter* filter, | |
668 const SkIRect& clipBounds, | |
669 GrPaint* grp, | |
670 SkPaint::Style style) { | |
671 SkMask srcM, dstM; | |
672 | |
673 if (!SkDraw::DrawToMask(devPath, &clipBounds, filter, &viewMatrix, &srcM, | |
674 SkMask::kComputeBoundsAndRenderImage_CreateMode, sty
le)) { | |
675 return false; | |
676 } | |
677 SkAutoMaskFreeImage autoSrc(srcM.fImage); | |
678 | |
679 if (!filter->filterMask(&dstM, srcM, viewMatrix, NULL)) { | |
680 return false; | |
681 } | |
682 // this will free-up dstM when we're done (allocated in filterMask()) | |
683 SkAutoMaskFreeImage autoDst(dstM.fImage); | |
684 | |
685 if (clip_bounds_quick_reject(clipBounds, dstM.fBounds)) { | |
686 return false; | |
687 } | |
688 | |
689 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using | |
690 // the current clip (and identity matrix) and GrPaint settings | |
691 GrSurfaceDesc desc; | |
692 desc.fWidth = dstM.fBounds.width(); | |
693 desc.fHeight = dstM.fBounds.height(); | |
694 desc.fConfig = kAlpha_8_GrPixelConfig; | |
695 | |
696 SkAutoTUnref<GrTexture> texture(textureProvider->refScratchTexture( | |
697 desc, GrTextureProvider::kApprox_ScratchTexMatch)); | |
698 if (!texture) { | |
699 return false; | |
700 } | |
701 texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig, | |
702 dstM.fImage, dstM.fRowBytes); | |
703 | |
704 SkRect maskRect = SkRect::Make(dstM.fBounds); | |
705 | |
706 return draw_mask(drawContext, rt, clipData, viewMatrix, maskRect, grp, textu
re); | |
707 } | |
708 | |
709 // Create a mask of 'devPath' and place the result in 'mask'. | |
710 GrTexture* create_mask_GPU(GrContext* context, | |
711 const SkRect& maskRect, | |
712 const SkPath& devPath, | |
713 const GrStrokeInfo& strokeInfo, | |
714 bool doAA, | |
715 int sampleCnt) { | |
716 GrSurfaceDesc desc; | |
717 desc.fFlags = kRenderTarget_GrSurfaceFlag; | |
718 desc.fWidth = SkScalarCeilToInt(maskRect.width()); | |
719 desc.fHeight = SkScalarCeilToInt(maskRect.height()); | |
720 desc.fSampleCnt = doAA ? sampleCnt : 0; | |
721 // We actually only need A8, but it often isn't supported as a | |
722 // render target so default to RGBA_8888 | |
723 desc.fConfig = kRGBA_8888_GrPixelConfig; | |
724 | |
725 if (context->isConfigRenderable(kAlpha_8_GrPixelConfig, | |
726 desc.fSampleCnt > 0)) { | |
727 desc.fConfig = kAlpha_8_GrPixelConfig; | |
728 } | |
729 | |
730 GrTexture* mask = context->textureProvider()->refScratchTexture( | |
731 desc, GrTextureProvider::kApprox_ScratchTexMatch); | |
732 if (NULL == mask) { | |
733 return NULL; | |
734 } | |
735 | |
736 SkRect clipRect = SkRect::MakeWH(maskRect.width(), maskRect.height()); | |
737 | |
738 GrDrawContext* drawContext = context->drawContext(); | |
739 if (!drawContext) { | |
740 return NULL; | |
741 } | |
742 | |
743 drawContext->clear(mask->asRenderTarget(), NULL, 0x0, true); | |
744 | |
745 GrPaint tempPaint; | |
746 tempPaint.setAntiAlias(doAA); | |
747 tempPaint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op); | |
748 | |
749 // setup new clip | |
750 GrClip clip(clipRect); | |
751 | |
752 // Draw the mask into maskTexture with the path's top-left at the origin usi
ng tempPaint. | |
753 SkMatrix translate; | |
754 translate.setTranslate(-maskRect.fLeft, -maskRect.fTop); | |
755 drawContext->drawPath(mask->asRenderTarget(), clip, tempPaint, translate, de
vPath, strokeInfo); | |
756 return mask; | |
757 } | |
758 | |
759 SkBitmap wrap_texture(GrTexture* texture, int width, int height) { | |
760 SkBitmap result; | 630 SkBitmap result; |
761 result.setInfo(SkImageInfo::MakeN32Premul(width, height)); | 631 result.setInfo(SkImageInfo::MakeN32Premul(width, height)); |
762 result.setPixelRef(SkNEW_ARGS(SkGrPixelRef, (result.info(), texture)))->unre
f(); | 632 result.setPixelRef(SkNEW_ARGS(SkGrPixelRef, (result.info(), texture)))->unre
f(); |
763 return result; | 633 return result; |
764 } | 634 } |
765 | 635 |
766 }; | |
767 | |
768 void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath, | 636 void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath, |
769 const SkPaint& paint, const SkMatrix* prePathMatrix, | 637 const SkPaint& paint, const SkMatrix* prePathMatrix, |
770 bool pathIsMutable) { | 638 bool pathIsMutable) { |
771 CHECK_FOR_ANNOTATION(paint); | 639 CHECK_FOR_ANNOTATION(paint); |
772 CHECK_SHOULD_DRAW(draw); | 640 CHECK_SHOULD_DRAW(draw); |
773 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawPath", fContext); | 641 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawPath", fContext); |
774 | 642 |
775 return this->internalDrawPath(origSrcPath, paint, *draw.fMatrix, prePathMatr
ix, | 643 GrBlurUtils::drawPathWithMaskFilter(fContext, fDrawContext, fRenderTarget, |
776 draw.fClip->getBounds(), pathIsMutable); | 644 fClip, origSrcPath, paint, |
777 } | 645 *draw.fMatrix, prePathMatrix, |
778 | 646 draw.fClip->getBounds(), pathIsMutable); |
779 void SkGpuDevice::internalDrawPath(const SkPath& origSrcPath, const SkPaint& pai
nt, | |
780 const SkMatrix& origViewMatrix, const SkMatri
x* prePathMatrix, | |
781 const SkIRect& clipBounds, bool pathIsMutable
) { | |
782 SkASSERT(!pathIsMutable || origSrcPath.isVolatile()); | |
783 | |
784 GrStrokeInfo strokeInfo(paint); | |
785 | |
786 // If we have a prematrix, apply it to the path, optimizing for the case | |
787 // where the original path can in fact be modified in place (even though | |
788 // its parameter type is const). | |
789 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath); | |
790 SkTLazy<SkPath> tmpPath; | |
791 SkTLazy<SkPath> effectPath; | |
792 SkPathEffect* pathEffect = paint.getPathEffect(); | |
793 | |
794 SkMatrix viewMatrix = origViewMatrix; | |
795 | |
796 if (prePathMatrix) { | |
797 // stroking, path effects, and blurs are supposed to be applied *after*
the prePathMatrix. | |
798 // The pre-path-matrix also should not affect shading. | |
799 if (NULL == paint.getMaskFilter() && NULL == pathEffect && NULL == paint
.getShader() && | |
800 (strokeInfo.isFillStyle() || strokeInfo.isHairlineStyle())) { | |
801 viewMatrix.preConcat(*prePathMatrix); | |
802 } else { | |
803 SkPath* result = pathPtr; | |
804 | |
805 if (!pathIsMutable) { | |
806 result = tmpPath.init(); | |
807 result->setIsVolatile(true); | |
808 pathIsMutable = true; | |
809 } | |
810 // should I push prePathMatrix on our MV stack temporarily, instead | |
811 // of applying it here? See SkDraw.cpp | |
812 pathPtr->transform(*prePathMatrix, result); | |
813 pathPtr = result; | |
814 } | |
815 } | |
816 // at this point we're done with prePathMatrix | |
817 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;) | |
818 | |
819 GrPaint grPaint; | |
820 if (!SkPaint2GrPaint(this->context(), fRenderTarget, paint, viewMatrix, true
, &grPaint)) { | |
821 return; | |
822 } | |
823 | |
824 const SkRect* cullRect = NULL; // TODO: what is our bounds? | |
825 if (!strokeInfo.isDashed() && pathEffect && pathEffect->filterPath(effectPat
h.init(), *pathPtr, | |
826 &strokeIn
fo, cullRect)) { | |
827 pathPtr = effectPath.get(); | |
828 pathIsMutable = true; | |
829 } | |
830 | |
831 if (paint.getMaskFilter()) { | |
832 if (!strokeInfo.isHairlineStyle()) { | |
833 SkPath* strokedPath = pathIsMutable ? pathPtr : tmpPath.init(); | |
834 if (strokeInfo.isDashed()) { | |
835 if (pathEffect->filterPath(strokedPath, *pathPtr, &strokeInfo, c
ullRect)) { | |
836 pathPtr = strokedPath; | |
837 pathIsMutable = true; | |
838 } | |
839 strokeInfo.removeDash(); | |
840 } | |
841 if (strokeInfo.applyToPath(strokedPath, *pathPtr)) { | |
842 pathPtr = strokedPath; | |
843 pathIsMutable = true; | |
844 strokeInfo.setFillStyle(); | |
845 } | |
846 } | |
847 | |
848 // avoid possibly allocating a new path in transform if we can | |
849 SkPath* devPathPtr = pathIsMutable ? pathPtr : tmpPath.init(); | |
850 if (!pathIsMutable) { | |
851 devPathPtr->setIsVolatile(true); | |
852 } | |
853 | |
854 // transform the path into device space | |
855 pathPtr->transform(viewMatrix, devPathPtr); | |
856 | |
857 SkRect maskRect; | |
858 if (paint.getMaskFilter()->canFilterMaskGPU(devPathPtr->getBounds(), | |
859 clipBounds, | |
860 viewMatrix, | |
861 &maskRect)) { | |
862 SkIRect finalIRect; | |
863 maskRect.roundOut(&finalIRect); | |
864 if (clip_bounds_quick_reject(clipBounds, finalIRect)) { | |
865 // clipped out | |
866 return; | |
867 } | |
868 | |
869 if (paint.getMaskFilter()->directFilterMaskGPU(fContext, | |
870 fRenderTarget, | |
871 &grPaint, | |
872 fClip, | |
873 viewMatrix, | |
874 strokeInfo, | |
875 *devPathPtr)) { | |
876 // the mask filter was able to draw itself directly, so there's
nothing | |
877 // left to do. | |
878 return; | |
879 } | |
880 | |
881 | |
882 SkAutoTUnref<GrTexture> mask(create_mask_GPU(fContext, | |
883 maskRect, | |
884 *devPathPtr, | |
885 strokeInfo, | |
886 grPaint.isAntiAlias(), | |
887 fRenderTarget->numSampl
es())); | |
888 if (mask) { | |
889 GrTexture* filtered; | |
890 | |
891 if (paint.getMaskFilter()->filterMaskGPU(mask, viewMatrix, maskR
ect, &filtered, true)) { | |
892 // filterMaskGPU gives us ownership of a ref to the result | |
893 SkAutoTUnref<GrTexture> atu(filtered); | |
894 if (draw_mask(fDrawContext, | |
895 fRenderTarget, | |
896 fClip, | |
897 viewMatrix, | |
898 maskRect, | |
899 &grPaint, | |
900 filtered)) { | |
901 // This path is completely drawn | |
902 return; | |
903 } | |
904 } | |
905 } | |
906 } | |
907 | |
908 // draw the mask on the CPU - this is a fallthrough path in case the | |
909 // GPU path fails | |
910 SkPaint::Style style = strokeInfo.isHairlineStyle() ? SkPaint::kStroke_S
tyle : | |
911 SkPaint::kFill_Sty
le; | |
912 draw_with_mask_filter(fDrawContext, fContext->textureProvider(), fRender
Target, | |
913 fClip, viewMatrix, *devPathPtr, | |
914 paint.getMaskFilter(), clipBounds, &grPaint, style
); | |
915 return; | |
916 } | |
917 | |
918 fDrawContext->drawPath(fRenderTarget, fClip, grPaint, viewMatrix, *pathPtr,
strokeInfo); | |
919 } | 647 } |
920 | 648 |
921 static const int kBmpSmallTileSize = 1 << 10; | 649 static const int kBmpSmallTileSize = 1 << 10; |
922 | 650 |
923 static inline int get_tile_count(const SkIRect& srcRect, int tileSize) { | 651 static inline int get_tile_count(const SkIRect& srcRect, int tileSize) { |
924 int tilesX = (srcRect.fRight / tileSize) - (srcRect.fLeft / tileSize) + 1; | 652 int tilesX = (srcRect.fRight / tileSize) - (srcRect.fLeft / tileSize) + 1; |
925 int tilesY = (srcRect.fBottom / tileSize) - (srcRect.fTop / tileSize) + 1; | 653 int tilesY = (srcRect.fBottom / tileSize) - (srcRect.fTop / tileSize) + 1; |
926 return tilesX * tilesY; | 654 return tilesX * tilesY; |
927 } | 655 } |
928 | 656 |
(...skipping 995 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1924 draw.fClip->getBounds()); | 1652 draw.fClip->getBounds()); |
1925 } | 1653 } |
1926 | 1654 |
1927 void SkGpuDevice::drawTextBlob(const SkDraw& draw, const SkTextBlob* blob, SkSca
lar x, SkScalar y, | 1655 void SkGpuDevice::drawTextBlob(const SkDraw& draw, const SkTextBlob* blob, SkSca
lar x, SkScalar y, |
1928 const SkPaint& paint, SkDrawFilter* drawFilter) { | 1656 const SkPaint& paint, SkDrawFilter* drawFilter) { |
1929 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawTextBlob", fContext); | 1657 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawTextBlob", fContext); |
1930 CHECK_SHOULD_DRAW(draw); | 1658 CHECK_SHOULD_DRAW(draw); |
1931 | 1659 |
1932 SkDEBUGCODE(this->validate();) | 1660 SkDEBUGCODE(this->validate();) |
1933 | 1661 |
1934 fTextContext->drawTextBlob(fRenderTarget, fClip, paint, *draw.fMatrix, blob,
x, y, drawFilter, | 1662 fTextContext->drawTextBlob(this, fRenderTarget, fClip, paint, *draw.fMatrix, |
1935 draw.fClip->getBounds()); | 1663 blob, x, y, drawFilter, draw.fClip->getBounds()); |
1936 } | 1664 } |
1937 | 1665 |
1938 /////////////////////////////////////////////////////////////////////////////// | 1666 /////////////////////////////////////////////////////////////////////////////// |
1939 | 1667 |
1940 bool SkGpuDevice::onShouldDisableLCD(const SkPaint& paint) const { | 1668 bool SkGpuDevice::onShouldDisableLCD(const SkPaint& paint) const { |
1941 if (paint.getShader() || | 1669 if (paint.getShader() || |
1942 !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode) || | 1670 !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode) || |
1943 paint.getMaskFilter() || | 1671 paint.getMaskFilter() || |
1944 paint.getRasterizer() || | 1672 paint.getRasterizer() || |
1945 paint.getColorFilter() || | 1673 paint.getColorFilter() || |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2064 #endif | 1792 #endif |
2065 } | 1793 } |
2066 | 1794 |
2067 SkImageFilter::Cache* SkGpuDevice::getImageFilterCache() { | 1795 SkImageFilter::Cache* SkGpuDevice::getImageFilterCache() { |
2068 // We always return a transient cache, so it is freed after each | 1796 // We always return a transient cache, so it is freed after each |
2069 // filter traversal. | 1797 // filter traversal. |
2070 return SkImageFilter::Cache::Create(kDefaultImageFilterCacheSize); | 1798 return SkImageFilter::Cache::Create(kDefaultImageFilterCacheSize); |
2071 } | 1799 } |
2072 | 1800 |
2073 #endif | 1801 #endif |
OLD | NEW |