Update Ganesh to support fractional rects in drawBitmapRect
https://codereview.appspot.com/6561070/
git-svn-id: http://skia.googlecode.com/svn/trunk@5724 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/gpu/SkGpuDevice.h b/include/gpu/SkGpuDevice.h
index 45ae05a..c9d54e5 100644
--- a/include/gpu/SkGpuDevice.h
+++ b/include/gpu/SkGpuDevice.h
@@ -157,14 +157,24 @@
void prepareRenderTarget(const SkDraw&);
bool shouldTileBitmap(const SkBitmap& bitmap,
const GrTextureParams& sampler,
- const SkIRect* srcRectPtr,
- int* tileSize) const;
+ const SkRect* srcRectPtr) const;
void internalDrawBitmap(const SkDraw&,
const SkBitmap&,
- const SkIRect&,
+ const SkRect&,
const SkMatrix&,
const GrTextureParams& params,
GrPaint* grPaint);
+ void drawTiledBitmap(const SkDraw& draw,
+ const SkBitmap& bitmap,
+ const SkRect& srcRect,
+ const SkMatrix& m,
+ const GrTextureParams& params,
+ GrPaint* grPaint);
+ void drawBitmapCommon(const SkDraw&,
+ const SkBitmap& bitmap,
+ const SkRect* srcRectPtr,
+ const SkMatrix&,
+ const SkPaint&);
/**
* Returns non-initialized instance.
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 59a3b61..ee09371 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -1154,7 +1154,7 @@
}
inline int determine_tile_size(const SkBitmap& bitmap,
- const SkIRect* srcRectPtr,
+ const SkRect& src,
int maxTextureSize) {
static const int kSmallTileSize = 1 << 10;
if (maxTextureSize <= kSmallTileSize) {
@@ -1164,23 +1164,20 @@
size_t maxTexTotalTileSize;
size_t smallTotalTileSize;
- if (NULL == srcRectPtr) {
- int w = bitmap.width();
- int h = bitmap.height();
- maxTexTotalTileSize = get_tile_count(0, 0, w, h, maxTextureSize);
- smallTotalTileSize = get_tile_count(0, 0, w, h, kSmallTileSize);
- } else {
- maxTexTotalTileSize = get_tile_count(srcRectPtr->fLeft,
- srcRectPtr->fTop,
- srcRectPtr->fRight,
- srcRectPtr->fBottom,
- maxTextureSize);
- smallTotalTileSize = get_tile_count(srcRectPtr->fLeft,
- srcRectPtr->fTop,
- srcRectPtr->fRight,
- srcRectPtr->fBottom,
- kSmallTileSize);
- }
+ 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);
+
maxTexTotalTileSize *= maxTextureSize * maxTextureSize;
smallTotalTileSize *= kSmallTileSize * kSmallTileSize;
@@ -1194,10 +1191,7 @@
bool SkGpuDevice::shouldTileBitmap(const SkBitmap& bitmap,
const GrTextureParams& params,
- const SkIRect* srcRectPtr,
- int* tileSize) const {
- SkASSERT(NULL != tileSize);
-
+ const SkRect* srcRectPtr) const {
// if bitmap is explictly texture backed then just use the texture
if (NULL != bitmap.getTexture()) {
return false;
@@ -1207,7 +1201,6 @@
const int maxTextureSize = fContext->getMaxTextureSize();
if (bitmap.width() > maxTextureSize ||
bitmap.height() > maxTextureSize) {
- *tileSize = determine_tile_size(bitmap, srcRectPtr, maxTextureSize);
return true;
}
// if we are going to have to draw the whole thing, then don't tile
@@ -1233,11 +1226,9 @@
return false;
}
- SkFixed fracUsed =
- SkFixedMul((srcRectPtr->width() << 16) / bitmap.width(),
- (srcRectPtr->height() << 16) / bitmap.height());
- if (fracUsed <= SK_FixedHalf) {
- *tileSize = determine_tile_size(bitmap, srcRectPtr, maxTextureSize);
+ SkScalar fracUsed = SkScalarMul(srcRectPtr->width() / bitmap.width(),
+ srcRectPtr->height() / bitmap.height());
+ if (fracUsed <= SK_ScalarHalf) {
return true;
} else {
return false;
@@ -1249,11 +1240,30 @@
const SkIRect* srcRectPtr,
const SkMatrix& m,
const SkPaint& paint) {
+
+ SkRect tmp;
+ SkRect* tmpPtr = NULL;
+
+ // convert from SkIRect to SkRect
+ if (NULL != srcRectPtr) {
+ tmp.set(*srcRectPtr);
+ tmpPtr = &tmp;
+ }
+
+ // We cannot call drawBitmapRect here since 'm' could be anything
+ this->drawBitmapCommon(draw, bitmap, tmpPtr, m, paint);
+}
+
+void SkGpuDevice::drawBitmapCommon(const SkDraw& draw,
+ const SkBitmap& bitmap,
+ const SkRect* srcRectPtr,
+ const SkMatrix& m,
+ const SkPaint& paint) {
CHECK_SHOULD_DRAW(draw);
- SkIRect srcRect;
+ SkRect srcRect;
if (NULL == srcRectPtr) {
- srcRect.set(0, 0, bitmap.width(), bitmap.height());
+ srcRect.set(0, 0, SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height()));
} else {
srcRect = *srcRectPtr;
}
@@ -1261,30 +1271,34 @@
if (paint.getMaskFilter()){
// Convert the bitmap to a shader so that the rect can be drawn
// through drawRect, which supports mask filters.
+ SkMatrix newM(m);
SkBitmap tmp; // subset of bitmap, if necessary
const SkBitmap* bitmapPtr = &bitmap;
- if (srcRectPtr) {
- if (!bitmap.extractSubset(&tmp, srcRect)) {
+ if (NULL != srcRectPtr) {
+ SkIRect iSrc;
+ srcRect.roundOut(&iSrc);
+ if (!bitmap.extractSubset(&tmp, iSrc)) {
return; // extraction failed
}
bitmapPtr = &tmp;
- srcRect.set(0,0, srcRect.width(), srcRect.height());
+ srcRect.offset(SkIntToScalar(-iSrc.fLeft), SkIntToScalar(-iSrc.fTop));
+ // The source rect has changed so update the matrix
+ newM.preTranslate(SkIntToScalar(iSrc.fLeft), SkIntToScalar(iSrc.fTop));
}
+
SkPaint paintWithTexture(paint);
paintWithTexture.setShader(SkShader::CreateBitmapShader(*bitmapPtr,
SkShader::kClamp_TileMode, SkShader::kClamp_TileMode))->unref();
- SkRect ScalarRect;
- ScalarRect.set(srcRect);
- // Transform 'm' needs to be concatenated to the draw matrix,
- // rather than transforming the primitive directly, so that 'm' will
+ // Transform 'newM' needs to be concatenated to the draw matrix,
+ // rather than transforming the primitive directly, so that 'newM' will
// also affect the behavior of the mask filter.
SkMatrix drawMatrix;
- drawMatrix.setConcat(*draw.fMatrix, m);
+ drawMatrix.setConcat(*draw.fMatrix, newM);
SkDraw transformedDraw(draw);
transformedDraw.fMatrix = &drawMatrix;
- this->drawRect(transformedDraw, ScalarRect, paintWithTexture);
+ this->drawRect(transformedDraw, srcRect, paintWithTexture);
return;
}
@@ -1297,28 +1311,39 @@
GrTextureParams params;
params.setBilerp(paint.isFilterBitmap());
- int tileSize;
- if (!this->shouldTileBitmap(bitmap, params, srcRectPtr, &tileSize)) {
+ if (!this->shouldTileBitmap(bitmap, params, srcRectPtr)) {
// take the simple case
this->internalDrawBitmap(draw, bitmap, srcRect, m, params, &grPaint);
- return;
+ } else {
+ this->drawTiledBitmap(draw, bitmap, srcRect, m, params, &grPaint);
}
+}
+
+// Break 'bitmap' into several tiles to draw it since it has already
+// been determined to be too large to fit in VRAM
+void SkGpuDevice::drawTiledBitmap(const SkDraw& draw,
+ const SkBitmap& bitmap,
+ const SkRect& srcRect,
+ const SkMatrix& m,
+ const GrTextureParams& params,
+ GrPaint* grPaint) {
+ const int maxTextureSize = fContext->getMaxTextureSize();
+
+ int tileSize = determine_tile_size(bitmap, srcRect, maxTextureSize);
// undo the translate done by SkCanvas
- int DX = SkMax32(0, srcRect.fLeft);
- int DY = SkMax32(0, srcRect.fTop);
+ SkScalar DX = SkMaxScalar(0, srcRect.fLeft);
+ SkScalar DY = SkMaxScalar(0, srcRect.fTop);
// compute clip bounds in local coordinates
- SkIRect clipRect;
+ SkRect clipRect;
{
- SkRect r;
- r.set(draw.fClip->getBounds());
+ clipRect.set(draw.fClip->getBounds());
SkMatrix matrix, inverse;
matrix.setConcat(*draw.fMatrix, m);
if (!matrix.invert(&inverse)) {
return;
}
- inverse.mapRect(&r);
- r.roundOut(&clipRect);
+ inverse.mapRect(&clipRect);
// apply the canvas' translate to our local clip
clipRect.offset(DX, DY);
}
@@ -1327,30 +1352,34 @@
int ny = bitmap.height() / tileSize;
for (int x = 0; x <= nx; x++) {
for (int y = 0; y <= ny; y++) {
- SkIRect tileR;
- tileR.set(x * tileSize, y * tileSize,
- (x + 1) * tileSize, (y + 1) * tileSize);
- if (!SkIRect::Intersects(tileR, clipRect)) {
+ SkRect tileR;
+ tileR.set(SkIntToScalar(x * tileSize),
+ SkIntToScalar(y * tileSize),
+ SkIntToScalar((x + 1) * tileSize),
+ SkIntToScalar((y + 1) * tileSize));
+
+ if (!SkRect::Intersects(tileR, clipRect)) {
continue;
}
- SkIRect srcR = tileR;
- if (!srcR.intersect(srcRect)) {
+ if (!tileR.intersect(srcRect)) {
continue;
}
SkBitmap tmpB;
- if (bitmap.extractSubset(&tmpB, tileR)) {
+ SkIRect iTileR;
+ tileR.roundOut(&iTileR);
+ if (bitmap.extractSubset(&tmpB, iTileR)) {
// now offset it to make it "local" to our tmp bitmap
- srcR.offset(-tileR.fLeft, -tileR.fTop);
+ tileR.offset(SkIntToScalar(-iTileR.fLeft), SkIntToScalar(-iTileR.fTop));
SkMatrix tmpM(m);
{
- int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
- int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
- tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
+ SkScalar dx = iTileR.fLeft - DX + SkMaxScalar(0, tileR.fLeft);
+ SkScalar dy = iTileR.fTop - DY + SkMaxScalar(0, tileR.fTop);
+ tmpM.preTranslate(dx, dy);
}
- this->internalDrawBitmap(draw, tmpB, srcR, tmpM, params, &grPaint);
+ this->internalDrawBitmap(draw, tmpB, tileR, tmpM, params, grPaint);
}
}
}
@@ -1408,7 +1437,7 @@
*/
void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
const SkBitmap& bitmap,
- const SkIRect& srcRect,
+ const SkRect& srcRect,
const SkMatrix& m,
const GrTextureParams& params,
GrPaint* grPaint) {
@@ -1431,35 +1460,34 @@
return;
}
- GrRect dstRect = SkRect::MakeWH(GrIntToScalar(srcRect.width()),
- GrIntToScalar(srcRect.height()));
+ GrRect dstRect(srcRect);
GrRect paintRect;
- float wInv = 1.f / bitmap.width();
- float hInv = 1.f / bitmap.height();
- paintRect.setLTRB(SkFloatToScalar(srcRect.fLeft * wInv),
- SkFloatToScalar(srcRect.fTop * hInv),
- SkFloatToScalar(srcRect.fRight * wInv),
- SkFloatToScalar(srcRect.fBottom * hInv));
+ SkScalar wInv = SkScalarInvert(SkIntToScalar(bitmap.width()));
+ SkScalar hInv = SkScalarInvert(SkIntToScalar(bitmap.height()));
+ paintRect.setLTRB(SkScalarMul(srcRect.fLeft, wInv),
+ SkScalarMul(srcRect.fTop, hInv),
+ SkScalarMul(srcRect.fRight, wInv),
+ SkScalarMul(srcRect.fBottom, hInv));
bool needsTextureDomain = false;
if (params.isBilerp()) {
// Need texture domain if drawing a sub rect.
- needsTextureDomain = srcRect.width() < bitmap.width() || srcRect.height() < bitmap.height();
+ needsTextureDomain = srcRect.width() < bitmap.width() ||
+ srcRect.height() < bitmap.height();
if (m.rectStaysRect() && draw.fMatrix->rectStaysRect()) {
// sampling is axis-aligned
- GrRect floatSrcRect, transformedRect;
- floatSrcRect.set(srcRect);
+ GrRect transformedRect;
SkMatrix srcToDeviceMatrix(m);
srcToDeviceMatrix.postConcat(*draw.fMatrix);
- srcToDeviceMatrix.mapRect(&transformedRect, floatSrcRect);
+ srcToDeviceMatrix.mapRect(&transformedRect, srcRect);
- if (hasAlignedSamples(floatSrcRect, transformedRect)) {
+ if (hasAlignedSamples(srcRect, transformedRect)) {
// We could also turn off filtering here (but we already did a cache lookup with
// params).
needsTextureDomain = false;
} else {
needsTextureDomain = needsTextureDomain &&
- mayColorBleed(floatSrcRect, transformedRect, m);
+ mayColorBleed(srcRect, transformedRect, m);
}
}
}
@@ -1469,14 +1497,14 @@
if (needsTextureDomain) {
// Use a constrained texture domain to avoid color bleeding
GrScalar left, top, right, bottom;
- if (srcRect.width() > 1) {
+ if (srcRect.width() > GR_Scalar1) {
GrScalar border = GR_ScalarHalf / bitmap.width();
left = paintRect.left() + border;
right = paintRect.right() - border;
} else {
left = right = GrScalarHalf(paintRect.left() + paintRect.right());
}
- if (srcRect.height() > 1) {
+ if (srcRect.height() > GR_Scalar1) {
GrScalar border = GR_ScalarHalf / bitmap.height();
top = paintRect.top() + border;
bottom = paintRect.bottom() - border;
@@ -1592,42 +1620,31 @@
void SkGpuDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
const SkRect* src, const SkRect& dst,
const SkPaint& paint) {
- SkMatrix matrix;
+ SkMatrix matrix;
+ SkRect bitmapBounds, tmpSrc;
+
+ bitmapBounds.set(0, 0,
+ SkIntToScalar(bitmap.width()),
+ SkIntToScalar(bitmap.height()));
+
// Compute matrix from the two rectangles
- {
- SkRect tmpSrc;
- if (src) {
- tmpSrc = *src;
- // if the extract process clipped off the top or left of the
- // original, we adjust for that here to get the position right.
- if (tmpSrc.fLeft > 0) {
- tmpSrc.fRight -= tmpSrc.fLeft;
- tmpSrc.fLeft = 0;
+ if (NULL != src) {
+ tmpSrc = *src;
+ } else {
+ tmpSrc = bitmapBounds;
+ }
+ matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
+
+ // clip the tmpSrc to the bounds of the bitmap. No check needed if src==null.
+ if (NULL != src) {
+ if (!bitmapBounds.contains(tmpSrc)) {
+ if (!tmpSrc.intersect(bitmapBounds)) {
+ return; // nothing to draw
}
- if (tmpSrc.fTop > 0) {
- tmpSrc.fBottom -= tmpSrc.fTop;
- tmpSrc.fTop = 0;
- }
- } else {
- tmpSrc.set(0, 0, SkIntToScalar(bitmap.width()),
- SkIntToScalar(bitmap.height()));
}
- matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
}
- // ensure that src is "valid" before we pass it to our internal routines
- // and to SkDevice. i.e. sure it is contained inside the original bitmap.
- SkIRect isrcStorage;
- SkIRect* isrcPtr = NULL;
- if (src) {
- src->roundOut(&isrcStorage);
- if (!isrcStorage.intersect(0, 0, bitmap.width(), bitmap.height())) {
- return;
- }
- isrcPtr = &isrcStorage;
- }
-
- this->drawBitmap(draw, bitmap, isrcPtr, matrix, paint);
+ this->drawBitmapCommon(draw, bitmap, &tmpSrc, matrix, paint);
}
void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* device,