aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu
diff options
context:
space:
mode:
authorGravatar bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-10-24 17:52:07 +0000
committerGravatar bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-10-24 17:52:07 +0000
commitaf562b437e43a99f5371585ba50643b1d88f09e0 (patch)
tree897a659d5f33727b19467bd92661bc41cd32b091 /src/gpu
parenta34b1f8e0bff03c3706ea3d9bdfeba94b6f8eb8b (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.cpp133
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, &params)) {
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;