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 "GrBlurUtils.h" |
(...skipping 675 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
686 } | 686 } |
687 | 687 |
688 static const int kBmpSmallTileSize = 1 << 10; | 688 static const int kBmpSmallTileSize = 1 << 10; |
689 | 689 |
690 static inline int get_tile_count(const SkIRect& srcRect, int tileSize) { | 690 static inline int get_tile_count(const SkIRect& srcRect, int tileSize) { |
691 int tilesX = (srcRect.fRight / tileSize) - (srcRect.fLeft / tileSize) + 1; | 691 int tilesX = (srcRect.fRight / tileSize) - (srcRect.fLeft / tileSize) + 1; |
692 int tilesY = (srcRect.fBottom / tileSize) - (srcRect.fTop / tileSize) + 1; | 692 int tilesY = (srcRect.fBottom / tileSize) - (srcRect.fTop / tileSize) + 1; |
693 return tilesX * tilesY; | 693 return tilesX * tilesY; |
694 } | 694 } |
695 | 695 |
696 static int determine_tile_size(const SkBitmap& bitmap, const SkIRect& src, int m
axTileSize) { | 696 static int determine_tile_size(const SkIRect& src, int maxTileSize) { |
697 if (maxTileSize <= kBmpSmallTileSize) { | 697 if (maxTileSize <= kBmpSmallTileSize) { |
698 return maxTileSize; | 698 return maxTileSize; |
699 } | 699 } |
700 | 700 |
701 size_t maxTileTotalTileSize = get_tile_count(src, maxTileSize); | 701 size_t maxTileTotalTileSize = get_tile_count(src, maxTileSize); |
702 size_t smallTotalTileSize = get_tile_count(src, kBmpSmallTileSize); | 702 size_t smallTotalTileSize = get_tile_count(src, kBmpSmallTileSize); |
703 | 703 |
704 maxTileTotalTileSize *= maxTileSize * maxTileSize; | 704 maxTileTotalTileSize *= maxTileSize * maxTileSize; |
705 smallTotalTileSize *= kBmpSmallTileSize * kBmpSmallTileSize; | 705 smallTotalTileSize *= kBmpSmallTileSize * kBmpSmallTileSize; |
706 | 706 |
707 if (maxTileTotalTileSize > 2 * smallTotalTileSize) { | 707 if (maxTileTotalTileSize > 2 * smallTotalTileSize) { |
708 return kBmpSmallTileSize; | 708 return kBmpSmallTileSize; |
709 } else { | 709 } else { |
710 return maxTileSize; | 710 return maxTileSize; |
711 } | 711 } |
712 } | 712 } |
713 | 713 |
714 // Given a bitmap, an optional src rect, and a context with a clip and matrix de
termine what | 714 // Given a bitmap, an optional src rect, and a context with a clip and matrix de
termine what |
715 // pixels from the bitmap are necessary. | 715 // pixels from the bitmap are necessary. |
716 static void determine_clipped_src_rect(const GrRenderTarget* rt, | 716 static void determine_clipped_src_rect(const GrRenderTarget* rt, |
717 const GrClip& clip, | 717 const GrClip& clip, |
718 const SkMatrix& viewMatrix, | 718 const SkMatrix& viewMatrix, |
719 const SkBitmap& bitmap, | 719 const SkISize& imageSize, |
720 const SkRect* srcRectPtr, | 720 const SkRect* srcRectPtr, |
721 SkIRect* clippedSrcIRect) { | 721 SkIRect* clippedSrcIRect) { |
722 clip.getConservativeBounds(rt, clippedSrcIRect, nullptr); | 722 clip.getConservativeBounds(rt, clippedSrcIRect, nullptr); |
723 SkMatrix inv; | 723 SkMatrix inv; |
724 if (!viewMatrix.invert(&inv)) { | 724 if (!viewMatrix.invert(&inv)) { |
725 clippedSrcIRect->setEmpty(); | 725 clippedSrcIRect->setEmpty(); |
726 return; | 726 return; |
727 } | 727 } |
728 SkRect clippedSrcRect = SkRect::Make(*clippedSrcIRect); | 728 SkRect clippedSrcRect = SkRect::Make(*clippedSrcIRect); |
729 inv.mapRect(&clippedSrcRect); | 729 inv.mapRect(&clippedSrcRect); |
730 if (srcRectPtr) { | 730 if (srcRectPtr) { |
731 // we've setup src space 0,0 to map to the top left of the src rect. | 731 // we've setup src space 0,0 to map to the top left of the src rect. |
732 clippedSrcRect.offset(srcRectPtr->fLeft, srcRectPtr->fTop); | 732 clippedSrcRect.offset(srcRectPtr->fLeft, srcRectPtr->fTop); |
733 if (!clippedSrcRect.intersect(*srcRectPtr)) { | 733 if (!clippedSrcRect.intersect(*srcRectPtr)) { |
734 clippedSrcIRect->setEmpty(); | 734 clippedSrcIRect->setEmpty(); |
735 return; | 735 return; |
736 } | 736 } |
737 } | 737 } |
738 clippedSrcRect.roundOut(clippedSrcIRect); | 738 clippedSrcRect.roundOut(clippedSrcIRect); |
739 SkIRect bmpBounds = SkIRect::MakeWH(bitmap.width(), bitmap.height()); | 739 SkIRect bmpBounds = SkIRect::MakeSize(imageSize); |
740 if (!clippedSrcIRect->intersect(bmpBounds)) { | 740 if (!clippedSrcIRect->intersect(bmpBounds)) { |
741 clippedSrcIRect->setEmpty(); | 741 clippedSrcIRect->setEmpty(); |
742 } | 742 } |
743 } | 743 } |
744 | 744 |
745 bool SkGpuDevice::shouldTileBitmap(const SkBitmap& bitmap, | 745 bool SkGpuDevice::shouldTileImageID(uint32_t imageID, const SkIRect& imageRect, |
746 const SkMatrix& viewMatrix, | 746 const SkMatrix& viewMatrix, |
747 const GrTextureParams& params, | 747 const GrTextureParams& params, |
748 const SkRect* srcRectPtr, | 748 const SkRect* srcRectPtr, |
749 int maxTileSize, | 749 int maxTileSize, |
750 int* tileSize, | 750 int* tileSize, |
751 SkIRect* clippedSrcRect) const { | 751 SkIRect* clippedSubset) const { |
752 // if bitmap is explictly texture backed then just use the texture | 752 // if it's larger than the max tile size, then we have no choice but tiling. |
753 if (bitmap.getTexture()) { | 753 if (imageRect.width() > maxTileSize || imageRect.height() > maxTileSize) { |
| 754 determine_clipped_src_rect(fRenderTarget, fClip, viewMatrix, imageRect.s
ize(), |
| 755 srcRectPtr, clippedSubset); |
| 756 *tileSize = determine_tile_size(*clippedSubset, maxTileSize); |
| 757 return true; |
| 758 } |
| 759 |
| 760 const size_t area = imageRect.width() * imageRect.height(); |
| 761 if (area < 4 * kBmpSmallTileSize * kBmpSmallTileSize) { |
754 return false; | 762 return false; |
755 } | 763 } |
756 | 764 |
757 // if it's larger than the max tile size, then we have no choice but tiling. | 765 // if the entire image/bitmap is already in our cache then no reason to tile
it |
758 if (bitmap.width() > maxTileSize || bitmap.height() > maxTileSize) { | 766 if (GrIsImageInCache(fContext, imageID, imageRect, nullptr, ¶ms)) { |
759 determine_clipped_src_rect(fRenderTarget, fClip, viewMatrix, bitmap, | |
760 srcRectPtr, clippedSrcRect); | |
761 *tileSize = determine_tile_size(bitmap, *clippedSrcRect, maxTileSize); | |
762 return true; | |
763 } | |
764 | |
765 if (bitmap.width() * bitmap.height() < 4 * kBmpSmallTileSize * kBmpSmallTile
Size) { | |
766 return false; | 767 return false; |
767 } | 768 } |
768 | 769 |
769 // if the entire texture is already in our cache then no reason to tile it | |
770 if (GrIsBitmapInCache(fContext, bitmap, ¶ms)) { | |
771 return false; | |
772 } | |
773 | |
774 // At this point we know we could do the draw by uploading the entire bitmap | 770 // At this point we know we could do the draw by uploading the entire bitmap |
775 // as a texture. However, if the texture would be large compared to the | 771 // as a texture. However, if the texture would be large compared to the |
776 // cache size and we don't require most of it for this draw then tile to | 772 // cache size and we don't require most of it for this draw then tile to |
777 // reduce the amount of upload and cache spill. | 773 // reduce the amount of upload and cache spill. |
778 | 774 |
779 // assumption here is that sw bitmap size is a good proxy for its size as | 775 // assumption here is that sw bitmap size is a good proxy for its size as |
780 // a texture | 776 // a texture |
781 size_t bmpSize = bitmap.getSize(); | 777 size_t bmpSize = area * sizeof(SkPMColor); // assume 32bit pixels |
782 size_t cacheSize; | 778 size_t cacheSize; |
783 fContext->getResourceCacheLimits(nullptr, &cacheSize); | 779 fContext->getResourceCacheLimits(nullptr, &cacheSize); |
784 if (bmpSize < cacheSize / 2) { | 780 if (bmpSize < cacheSize / 2) { |
785 return false; | 781 return false; |
786 } | 782 } |
787 | 783 |
788 // Figure out how much of the src we will need based on the src rect and cli
pping. | 784 // Figure out how much of the src we will need based on the src rect and cli
pping. |
789 determine_clipped_src_rect(fRenderTarget, fClip, viewMatrix, bitmap, srcRect
Ptr, | 785 determine_clipped_src_rect(fRenderTarget, fClip, viewMatrix, imageRect.size(
), srcRectPtr, |
790 clippedSrcRect); | 786 clippedSubset); |
791 *tileSize = kBmpSmallTileSize; // already know whole bitmap fits in one max
sized tile. | 787 *tileSize = kBmpSmallTileSize; // already know whole bitmap fits in one max
sized tile. |
792 size_t usedTileBytes = get_tile_count(*clippedSrcRect, kBmpSmallTileSize) * | 788 size_t usedTileBytes = get_tile_count(*clippedSubset, kBmpSmallTileSize) * |
793 kBmpSmallTileSize * kBmpSmallTileSize; | 789 kBmpSmallTileSize * kBmpSmallTileSize; |
794 | 790 |
795 return usedTileBytes < 2 * bmpSize; | 791 return usedTileBytes < 2 * bmpSize; |
796 } | 792 } |
797 | 793 |
| 794 bool SkGpuDevice::shouldTileBitmap(const SkBitmap& bitmap, |
| 795 const SkMatrix& viewMatrix, |
| 796 const GrTextureParams& params, |
| 797 const SkRect* srcRectPtr, |
| 798 int maxTileSize, |
| 799 int* tileSize, |
| 800 SkIRect* clippedSrcRect) const { |
| 801 // if bitmap is explictly texture backed then just use the texture |
| 802 if (bitmap.getTexture()) { |
| 803 return false; |
| 804 } |
| 805 |
| 806 return this->shouldTileImageID(bitmap.getGenerationID(), bitmap.getSubset(),
viewMatrix, params, |
| 807 srcRectPtr, maxTileSize, tileSize, clippedSrc
Rect); |
| 808 } |
| 809 |
| 810 bool SkGpuDevice::shouldTileImage(const SkImage* image, const SkRect* srcRectPtr
, |
| 811 SkCanvas::SrcRectConstraint constraint, SkFilt
erQuality quality, |
| 812 const SkMatrix& viewMatrix) const { |
| 813 // if image is explictly texture backed then just use the texture |
| 814 if (as_IB(image)->peekTexture()) { |
| 815 return false; |
| 816 } |
| 817 |
| 818 GrTextureParams params; |
| 819 bool doBicubic; |
| 820 GrTextureParams::FilterMode textureFilterMode = |
| 821 GrSkFilterQualityToGrFilterMode(quality, viewMatrix, SkMatri
x::I(), &doBicubic); |
| 822 |
| 823 int tileFilterPad; |
| 824 if (doBicubic) { |
| 825 tileFilterPad = GrBicubicEffect::kFilterTexelPad; |
| 826 } else if (GrTextureParams::kNone_FilterMode == textureFilterMode) { |
| 827 tileFilterPad = 0; |
| 828 } else { |
| 829 tileFilterPad = 1; |
| 830 } |
| 831 params.setFilterMode(textureFilterMode); |
| 832 |
| 833 int maxTileSize = fContext->caps()->maxTextureSize() - 2 * tileFilterPad; |
| 834 |
| 835 // these are output, which we safely ignore, as we just want to know the pre
dicate |
| 836 int outTileSize; |
| 837 SkIRect outClippedSrcRect; |
| 838 |
| 839 return this->shouldTileImageID(image->unique(), image->bounds(), viewMatrix,
params, srcRectPtr, |
| 840 maxTileSize, &outTileSize, &outClippedSrcRect
); |
| 841 } |
| 842 |
798 void SkGpuDevice::drawBitmap(const SkDraw& origDraw, | 843 void SkGpuDevice::drawBitmap(const SkDraw& origDraw, |
799 const SkBitmap& bitmap, | 844 const SkBitmap& bitmap, |
800 const SkMatrix& m, | 845 const SkMatrix& m, |
801 const SkPaint& paint) { | 846 const SkPaint& paint) { |
802 SkMatrix concat; | 847 SkMatrix concat; |
803 SkTCopyOnFirstWrite<SkDraw> draw(origDraw); | 848 SkTCopyOnFirstWrite<SkDraw> draw(origDraw); |
804 if (!m.isIdentity()) { | 849 if (!m.isIdentity()) { |
805 concat.setConcat(*draw->fMatrix, m); | 850 concat.setConcat(*draw->fMatrix, m); |
806 draw.writable()->fMatrix = &concat; | 851 draw.writable()->fMatrix = &concat; |
807 } | 852 } |
(...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1083 } else { | 1128 } else { |
1084 draw_aa_bitmap(fDrawContext, fContext, fRenderTarget, fClip, *draw.f
Matrix, | 1129 draw_aa_bitmap(fDrawContext, fContext, fRenderTarget, fClip, *draw.f
Matrix, |
1085 srcRectToDstRect, paint, bitmapPtr, dstSize); | 1130 srcRectToDstRect, paint, bitmapPtr, dstSize); |
1086 } | 1131 } |
1087 | 1132 |
1088 return; | 1133 return; |
1089 } | 1134 } |
1090 | 1135 |
1091 // If there is no mask filter than it is OK to handle the src rect -> dst re
ct scaling using | 1136 // If there is no mask filter than it is OK to handle the src rect -> dst re
ct scaling using |
1092 // the view matrix rather than a local matrix. | 1137 // the view matrix rather than a local matrix. |
1093 SkMatrix m; | |
1094 m.setScale(dstSize.fWidth / srcRect.width(), | |
1095 dstSize.fHeight / srcRect.height()); | |
1096 SkMatrix viewM = *draw.fMatrix; | 1138 SkMatrix viewM = *draw.fMatrix; |
1097 viewM.preConcat(m); | 1139 viewM.preScale(dstSize.fWidth / srcRect.width(), |
| 1140 dstSize.fHeight / srcRect.height()); |
1098 | 1141 |
1099 GrTextureParams params; | 1142 GrTextureParams params; |
1100 bool doBicubic; | 1143 bool doBicubic; |
1101 GrTextureParams::FilterMode textureFilterMode = | 1144 GrTextureParams::FilterMode textureFilterMode = |
1102 GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), viewM, SkM
atrix::I(), | 1145 GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), viewM, SkM
atrix::I(), |
1103 &doBicubic); | 1146 &doBicubic); |
1104 | 1147 |
1105 int tileFilterPad; | 1148 int tileFilterPad; |
1106 if (doBicubic) { | 1149 if (doBicubic) { |
1107 tileFilterPad = GrBicubicEffect::kFilterTexelPad; | 1150 tileFilterPad = GrBicubicEffect::kFilterTexelPad; |
(...skipping 431 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1539 // must be pushed upstack. | 1582 // must be pushed upstack. |
1540 AutoBitmapTexture abt(fContext, src, nullptr, &texture); | 1583 AutoBitmapTexture abt(fContext, src, nullptr, &texture); |
1541 if (!texture) { | 1584 if (!texture) { |
1542 return false; | 1585 return false; |
1543 } | 1586 } |
1544 | 1587 |
1545 return this->filterTexture(fContext, texture, src.width(), src.height(), | 1588 return this->filterTexture(fContext, texture, src.width(), src.height(), |
1546 filter, ctx, result, offset); | 1589 filter, ctx, result, offset); |
1547 } | 1590 } |
1548 | 1591 |
1549 static bool wrap_as_bm(const SkImage* image, SkBitmap* bm) { | 1592 static bool wrap_as_bm(GrContext* ctx, const SkImage* image, SkBitmap* bm) { |
1550 GrTexture* tex = as_IB(image)->getTexture(); | 1593 SkAutoTUnref<GrTexture> tex(as_IB(image)->asTextureRef(ctx, kUntiled_SkImage
UsageType)); |
1551 if (tex) { | 1594 if (tex) { |
1552 GrWrapTextureInBitmap(tex, image->width(), image->height(), image->isOpa
que(), bm); | 1595 GrWrapTextureInBitmap(tex, image->width(), image->height(), image->isOpa
que(), bm); |
1553 return true; | 1596 return true; |
1554 } else { | 1597 } else { |
1555 return as_IB(image)->getROPixels(bm); | 1598 return as_IB(image)->getROPixels(bm); |
1556 } | 1599 } |
1557 } | 1600 } |
1558 | 1601 |
1559 void SkGpuDevice::drawImage(const SkDraw& draw, const SkImage* image, SkScalar x
, SkScalar y, | 1602 void SkGpuDevice::drawImage(const SkDraw& draw, const SkImage* image, SkScalar x
, SkScalar y, |
1560 const SkPaint& paint) { | 1603 const SkPaint& paint) { |
1561 SkBitmap bm; | 1604 SkBitmap bm; |
1562 if (wrap_as_bm(image, &bm)) { | 1605 if (GrTexture* tex = as_IB(image)->peekTexture()) { |
1563 this->drawBitmap(draw, bm, SkMatrix::MakeTrans(x, y), paint); | 1606 GrWrapTextureInBitmap(tex, image->width(), image->height(), image->isOpa
que(), &bm); |
| 1607 } else { |
| 1608 if (this->shouldTileImage(image, nullptr, SkCanvas::kFast_SrcRectConstra
int, |
| 1609 paint.getFilterQuality(), *draw.fMatrix)) { |
| 1610 // only support tiling as bitmap at the moment, so force raster-vers
ion |
| 1611 if (!as_IB(image)->getROPixels(&bm)) { |
| 1612 return; |
| 1613 } |
| 1614 } else { |
| 1615 if (!wrap_as_bm(this->context(), image, &bm)) { |
| 1616 return; |
| 1617 } |
| 1618 } |
1564 } | 1619 } |
| 1620 this->drawBitmap(draw, bm, SkMatrix::MakeTrans(x, y), paint); |
1565 } | 1621 } |
1566 | 1622 |
1567 void SkGpuDevice::drawImageRect(const SkDraw& draw, const SkImage* image, const
SkRect* src, | 1623 void SkGpuDevice::drawImageRect(const SkDraw& draw, const SkImage* image, const
SkRect* src, |
1568 const SkRect& dst, const SkPaint& paint, | 1624 const SkRect& dst, const SkPaint& paint, |
1569 SkCanvas::SrcRectConstraint constraint) { | 1625 SkCanvas::SrcRectConstraint constraint) { |
1570 SkBitmap bm; | 1626 SkBitmap bm; |
1571 if (wrap_as_bm(image, &bm)) { | 1627 if (GrTexture* tex = as_IB(image)->peekTexture()) { |
1572 this->drawBitmapRect(draw, bm, src, dst, paint, constraint); | 1628 GrWrapTextureInBitmap(tex, image->width(), image->height(), image->isOpa
que(), &bm); |
| 1629 } else { |
| 1630 SkMatrix viewMatrix = *draw.fMatrix; |
| 1631 viewMatrix.preScale(dst.width() / (src ? src->width() : image->width()), |
| 1632 dst.height() / (src ? src->height() : image->height(
))); |
| 1633 |
| 1634 if (this->shouldTileImage(image, src, constraint, paint.getFilterQuality
(), viewMatrix)) { |
| 1635 // only support tiling as bitmap at the moment, so force raster-vers
ion |
| 1636 if (!as_IB(image)->getROPixels(&bm)) { |
| 1637 return; |
| 1638 } |
| 1639 } else { |
| 1640 if (!wrap_as_bm(this->context(), image, &bm)) { |
| 1641 return; |
| 1642 } |
| 1643 } |
1573 } | 1644 } |
| 1645 this->drawBitmapRect(draw, bm, src, dst, paint, constraint); |
1574 } | 1646 } |
1575 | 1647 |
1576 /////////////////////////////////////////////////////////////////////////////// | 1648 /////////////////////////////////////////////////////////////////////////////// |
1577 | 1649 |
1578 // must be in SkCanvas::VertexMode order | 1650 // must be in SkCanvas::VertexMode order |
1579 static const GrPrimitiveType gVertexMode2PrimitiveType[] = { | 1651 static const GrPrimitiveType gVertexMode2PrimitiveType[] = { |
1580 kTriangles_GrPrimitiveType, | 1652 kTriangles_GrPrimitiveType, |
1581 kTriangleStrip_GrPrimitiveType, | 1653 kTriangleStrip_GrPrimitiveType, |
1582 kTriangleFan_GrPrimitiveType, | 1654 kTriangleFan_GrPrimitiveType, |
1583 }; | 1655 }; |
(...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1900 #endif | 1972 #endif |
1901 } | 1973 } |
1902 | 1974 |
1903 SkImageFilter::Cache* SkGpuDevice::getImageFilterCache() { | 1975 SkImageFilter::Cache* SkGpuDevice::getImageFilterCache() { |
1904 // We always return a transient cache, so it is freed after each | 1976 // We always return a transient cache, so it is freed after each |
1905 // filter traversal. | 1977 // filter traversal. |
1906 return SkImageFilter::Cache::Create(kDefaultImageFilterCacheSize); | 1978 return SkImageFilter::Cache::Create(kDefaultImageFilterCacheSize); |
1907 } | 1979 } |
1908 | 1980 |
1909 #endif | 1981 #endif |
OLD | NEW |