| 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 |