diff options
author | 2013-10-24 17:52:07 +0000 | |
---|---|---|
committer | 2013-10-24 17:52:07 +0000 | |
commit | af562b437e43a99f5371585ba50643b1d88f09e0 (patch) | |
tree | 897a659d5f33727b19467bd92661bc41cd32b091 /src/gpu | |
parent | a34b1f8e0bff03c3706ea3d9bdfeba94b6f8eb8b (diff) |
Tile large bitmaps that are clipped.
R=robertphillips@google.com
Review URL: https://codereview.chromium.org/31033002
git-svn-id: http://skia.googlecode.com/svn/trunk@11951 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/gpu')
-rw-r--r-- | src/gpu/SkGpuDevice.cpp | 133 |
1 files changed, 75 insertions, 58 deletions
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index d80d0f511e..db440c149a 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -978,68 +978,84 @@ void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath, fContext->drawPath(grPaint, *pathPtr, stroke); } -namespace { +static const int kBmpSmallTileSize = 1 << 10; -inline int get_tile_count(int l, int t, int r, int b, int tileSize) { - int tilesX = (r / tileSize) - (l / tileSize) + 1; - int tilesY = (b / tileSize) - (t / tileSize) + 1; +static inline int get_tile_count(const SkIRect& srcRect, int tileSize) { + int tilesX = (srcRect.fRight / tileSize) - (srcRect.fLeft / tileSize) + 1; + int tilesY = (srcRect.fBottom / tileSize) - (srcRect.fTop / tileSize) + 1; return tilesX * tilesY; } -inline int determine_tile_size(const SkBitmap& bitmap, - const SkRect& src, - int maxTextureSize) { - static const int kSmallTileSize = 1 << 10; - if (maxTextureSize <= kSmallTileSize) { - return maxTextureSize; +static int determine_tile_size(const SkBitmap& bitmap, const SkIRect& src, int maxTileSize) { + if (maxTileSize <= kBmpSmallTileSize) { + return maxTileSize; } - size_t maxTexTotalTileSize; - size_t smallTotalTileSize; - - SkIRect iSrc; - src.roundOut(&iSrc); - - maxTexTotalTileSize = get_tile_count(iSrc.fLeft, - iSrc.fTop, - iSrc.fRight, - iSrc.fBottom, - maxTextureSize); - smallTotalTileSize = get_tile_count(iSrc.fLeft, - iSrc.fTop, - iSrc.fRight, - iSrc.fBottom, - kSmallTileSize); + size_t maxTileTotalTileSize = get_tile_count(src, maxTileSize); + size_t smallTotalTileSize = get_tile_count(src, kBmpSmallTileSize); - maxTexTotalTileSize *= maxTextureSize * maxTextureSize; - smallTotalTileSize *= kSmallTileSize * kSmallTileSize; + maxTileTotalTileSize *= maxTileSize * maxTileSize; + smallTotalTileSize *= kBmpSmallTileSize * kBmpSmallTileSize; - if (maxTexTotalTileSize > 2 * smallTotalTileSize) { - return kSmallTileSize; + if (maxTileTotalTileSize > 2 * smallTotalTileSize) { + return kBmpSmallTileSize; } else { - return maxTextureSize; + return maxTileSize; } } + +// Given a bitmap, an optional src rect, and a context with a clip and matrix determine what +// pixels from the bitmap are necessary. +static void determine_clipped_src_rect(const GrContext* context, + const SkBitmap& bitmap, + const SkRect* srcRectPtr, + SkIRect* clippedSrcIRect) { + const GrClipData* clip = context->getClip(); + clip->getConservativeBounds(context->getRenderTarget(), clippedSrcIRect, NULL); + SkMatrix inv; + if (!context->getMatrix().invert(&inv)) { + clippedSrcIRect->setEmpty(); + return; + } + SkRect clippedSrcRect = SkRect::MakeFromIRect(*clippedSrcIRect); + inv.mapRect(&clippedSrcRect); + if (NULL != srcRectPtr) { + if (!clippedSrcRect.intersect(*srcRectPtr)) { + clippedSrcIRect->setEmpty(); + return; + } + } + clippedSrcRect.roundOut(clippedSrcIRect); + SkIRect bmpBounds = SkIRect::MakeWH(bitmap.width(), bitmap.height()); + if (!clippedSrcIRect->intersect(bmpBounds)) { + clippedSrcIRect->setEmpty(); + } } + bool SkGpuDevice::shouldTileBitmap(const SkBitmap& bitmap, const GrTextureParams& params, - const SkRect* srcRectPtr) const { + const SkRect* srcRectPtr, + int maxTileSize, + int* tileSize) const { // if bitmap is explictly texture backed then just use the texture if (NULL != bitmap.getTexture()) { return false; } - // if it's larger than the max texture size, then we have no choice but - // tiling - const int maxTextureSize = fContext->getMaxTextureSize(); - if (bitmap.width() > maxTextureSize || - bitmap.height() > maxTextureSize) { + + SkIRect clippedSrcRect; + + // if it's larger than the max tile size, then we have no choice but tiling. + if (bitmap.width() > maxTileSize || bitmap.height() > maxTileSize) { + determine_clipped_src_rect(fContext, bitmap, srcRectPtr, &clippedSrcRect); + *tileSize = determine_tile_size(bitmap, clippedSrcRect, maxTileSize); return true; } - // if we are going to have to draw the whole thing, then don't tile - if (NULL == srcRectPtr) { + + if (bitmap.width() * bitmap.height() < 4 * kBmpSmallTileSize * kBmpSmallTileSize) { return false; } + // if the entire texture is already in our cache then no reason to tile it if (GrIsBitmapInCache(fContext, bitmap, ¶ms)) { return false; @@ -1059,13 +1075,13 @@ bool SkGpuDevice::shouldTileBitmap(const SkBitmap& bitmap, return false; } - SkScalar fracUsed = SkScalarMul(srcRectPtr->width() / bitmap.width(), - srcRectPtr->height() / bitmap.height()); - if (fracUsed <= SK_ScalarHalf) { - return true; - } else { - return false; - } + // Figure out how much of the src we will need based on the src rect and clipping. + determine_clipped_src_rect(fContext, bitmap, srcRectPtr, &clippedSrcRect); + *tileSize = kBmpSmallTileSize; // already know whole bitmap fits in one max sized tile. + size_t usedTileBytes = get_tile_count(clippedSrcRect, kBmpSmallTileSize) * + kBmpSmallTileSize * kBmpSmallTileSize; + + return usedTileBytes < 2 * bmpSize; } void SkGpuDevice::drawBitmap(const SkDraw& draw, @@ -1195,11 +1211,19 @@ void SkGpuDevice::drawBitmapCommon(const SkDraw& draw, params.setFilterMode(textureFilterMode); - if (!this->shouldTileBitmap(bitmap, params, srcRectPtr)) { + int maxTileSize = fContext->getMaxTextureSize(); + if (SkPaint::kNone_FilterLevel != paint.getFilterLevel()) { + // We may need a skosh more room if we have to bump out the tile + // by 1 pixel all around + maxTileSize -= 2; + } + int tileSize; + + if (this->shouldTileBitmap(bitmap, params, srcRectPtr, maxTileSize, &tileSize)) { + this->drawTiledBitmap(bitmap, srcRect, params, paint, flags, tileSize); + } else { // take the simple case this->internalDrawBitmap(bitmap, srcRect, params, paint, flags); - } else { - this->drawTiledBitmap(bitmap, srcRect, params, paint, flags); } } @@ -1209,15 +1233,8 @@ void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap, const SkRect& srcRect, const GrTextureParams& params, const SkPaint& paint, - SkCanvas::DrawBitmapRectFlags flags) { - int maxTextureSize = fContext->getMaxTextureSize(); - if (SkPaint::kNone_FilterLevel != paint.getFilterLevel()) { - // We may need a skosh more room if we have to bump out the tile - // by 1 pixel all around - maxTextureSize -= 2; - } - - int tileSize = determine_tile_size(bitmap, srcRect, maxTextureSize); + SkCanvas::DrawBitmapRectFlags flags, + int tileSize) { // compute clip bounds in local coordinates SkRect clipRect; |