#include "gm.h"
#include "SkCanvas.h"
+#include "SkGradientShader.h"
#include "SkPath.h"
-static void make_bm(SkBitmap* bm, int width, int height, SkColor color) {
+static void make_bm(SkBitmap* bm, int width, int height, SkColor colors[2]) {
bm->setConfig(SkBitmap::kARGB_8888_Config, width, height);
bm->allocPixels();
- bm->eraseColor(color);
+ SkCanvas canvas(*bm);
+ SkPoint center = {SkIntToScalar(width)/2, SkIntToScalar(height)/2};
+ SkScalar radius = 40;
+ SkShader* shader = SkGradientShader::CreateRadial(center, radius, colors, NULL, 2,
+ SkShader::kMirror_TileMode);
+ SkPaint paint;
+ paint.setShader(shader)->unref();
+ paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+ canvas.drawPaint(paint);
bm->setImmutable();
}
-static void show_bm(SkCanvas* canvas, int width, int height, SkColor color) {
+static void show_bm(SkCanvas* canvas, int width, int height, SkColor colors[2]) {
SkBitmap bm;
- make_bm(&bm, width, height, color);
+ make_bm(&bm, width, height, colors);
SkPaint paint;
SkRect r;
}
virtual SkISize onISize() SK_OVERRIDE {
- return SkISize::Make(640, 480);
+ return SkISize::Make(500, 600);
}
virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
int veryBig = 70*1024; // 64K < size
- int big = 60*1024; // 32K < size < 64K
+ int big = 60*1024; // 32K < size < 64K
+ // smaller than many max texture sizes, but large enough to gpu-tile for memory reasons.
+ int medium = 7*1024;
int small = 150;
+ SkColor colors[2];
+
canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
- show_bm(canvas, small, small, SK_ColorRED);
+ colors[0] = SK_ColorRED;
+ colors[1] = SK_ColorGREEN;
+ show_bm(canvas, small, small, colors);
+ canvas->translate(0, SkIntToScalar(150));
+
+ colors[0] = SK_ColorBLUE;
+ colors[1] = SK_ColorMAGENTA;
+ show_bm(canvas, big, small, colors);
canvas->translate(0, SkIntToScalar(150));
- show_bm(canvas, big, small, SK_ColorBLUE);
+ colors[0] = SK_ColorMAGENTA;
+ colors[1] = SK_ColorYELLOW;
+ // as of this writing, the raster code will fail to draw the scaled version
+ // since it has a 64K limit on x,y coordinates... (but gpu should succeed)
+ show_bm(canvas, medium, medium, colors);
canvas->translate(0, SkIntToScalar(150));
+ colors[0] = SK_ColorGREEN;
+ colors[1] = SK_ColorYELLOW;
// as of this writing, the raster code will fail to draw the scaled version
// since it has a 64K limit on x,y coordinates... (but gpu should succeed)
- show_bm(canvas, veryBig, small, SK_ColorGREEN);
+ show_bm(canvas, veryBig, small, colors);
}
private:
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;
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,
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);
}
}
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;