aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkBitmapDevice.cpp
diff options
context:
space:
mode:
authorGravatar Mike Reed <reed@google.com>2018-03-06 13:40:24 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-03-06 19:56:46 +0000
commitbe1b3971806e3d80aa9673a36e2b35d0145198ac (patch)
treefec8c2a345951fdd14b4c5da392586f231cb9c92 /src/core/SkBitmapDevice.cpp
parent18e9ba1eddb09bff6083f9a83dc569d3b3b54fe6 (diff)
add tiler for SkDraw
Bug: skia:2122 Change-Id: I276de2064939151eef5fa14c53188e8b5728b7c9 Reviewed-on: https://skia-review.googlesource.com/110840 Commit-Queue: Mike Reed <reed@google.com> Reviewed-by: Yuqian Li <liyuqian@google.com>
Diffstat (limited to 'src/core/SkBitmapDevice.cpp')
-rw-r--r--src/core/SkBitmapDevice.cpp160
1 files changed, 132 insertions, 28 deletions
diff --git a/src/core/SkBitmapDevice.cpp b/src/core/SkBitmapDevice.cpp
index 3d66ba6dfc..219724451a 100644
--- a/src/core/SkBitmapDevice.cpp
+++ b/src/core/SkBitmapDevice.cpp
@@ -23,6 +23,116 @@
#include "SkTLazy.h"
#include "SkVertices.h"
+class SkDrawTiler {
+ enum {
+ // 8K is 1 too big, since 8K << supersample == 32768 which is too big for SkFixed
+ kMaxDim = 8192 - 1
+ };
+
+ SkBitmapDevice* fDevice;
+ SkPixmap fRootPixmap;
+
+ // Used for tiling and non-tiling
+ SkDraw fDraw;
+
+ // fCurr... are only used if fNeedTiling
+ SkMatrix fTileMatrix;
+ SkRasterClip fTileRC;
+ SkIPoint fCurrOrigin, fOrigin;
+
+ bool fDone, fNeedsTiling;
+
+public:
+ SkDrawTiler(SkBitmapDevice* dev) : fDevice(dev) {
+ // we need fDst to be set, and if we're actually drawing, to dirty the genID
+ if (!dev->accessPixels(&fRootPixmap)) {
+ // NoDrawDevice uses us (why?) so we have to catch this case w/ no pixels
+ fRootPixmap.reset(dev->imageInfo(), nullptr, 0);
+ }
+
+ fDone = false;
+ fNeedsTiling = fRootPixmap.width() > kMaxDim || fRootPixmap.height() > kMaxDim;
+ fOrigin.set(0, 0);
+ fCurrOrigin = fOrigin;
+
+ if (fNeedsTiling) {
+ // fDraw.fDst is reset each time in setupTileDraw()
+ fDraw.fMatrix = &fTileMatrix;
+ fDraw.fRC = &fTileRC;
+ } else {
+ fDraw.fDst = fRootPixmap;
+ fDraw.fMatrix = &dev->ctm();
+ fDraw.fRC = &dev->fRCStack.rc();
+ }
+ }
+
+ bool needsTiling() const { return fNeedsTiling; }
+
+ const SkDraw* next() {
+ if (fDone) {
+ return nullptr;
+ }
+ if (fNeedsTiling) {
+ do {
+ this->setupTileDraw(); // might set the clip to empty
+ this->stepOrigin(); // might set fDone to true
+ } while (!fDone && fTileRC.isEmpty());
+ // if we exit the loop and we're still empty, we're (past) done
+ if (fTileRC.isEmpty()) {
+ SkASSERT(fDone);
+ return nullptr;
+ }
+ SkASSERT(!fTileRC.isEmpty());
+ } else {
+ fDone = true; // only draw untiled once
+ }
+ return &fDraw;
+ }
+
+ int curr_x() const { return fCurrOrigin.x(); }
+ int curr_y() const { return fCurrOrigin.y(); }
+
+private:
+ void setupTileDraw() {
+ SkASSERT(!fDone);
+ SkIRect bounds = SkIRect::MakeXYWH(fOrigin.x(), fOrigin.y(), kMaxDim, kMaxDim);
+ SkASSERT(!bounds.isEmpty());
+ bool success = fRootPixmap.extractSubset(&fDraw.fDst, bounds);
+ SkASSERT_RELEASE(success);
+ // now don't use bounds, since fDst has the clipped dimensions.
+
+ fTileMatrix = fDevice->ctm();
+ fTileMatrix.postTranslate(SkIntToScalar(-fOrigin.x()), SkIntToScalar(-fOrigin.y()));
+ fDevice->fRCStack.rc().translate(-fOrigin.x(), -fOrigin.y(), &fTileRC);
+ fTileRC.op(SkIRect::MakeWH(fDraw.fDst.width(), fDraw.fDst.height()),
+ SkRegion::kIntersect_Op);
+
+ fCurrOrigin = fOrigin;
+ }
+
+ void stepOrigin() {
+ SkASSERT(!fDone);
+ SkASSERT(fNeedsTiling);
+ fOrigin.fX += kMaxDim;
+ if (fOrigin.fX >= fRootPixmap.width()) { // too far
+ fOrigin.fX = 0;
+ fOrigin.fY += kMaxDim;
+ if (fOrigin.fY >= fRootPixmap.height()) {
+ fDone = true; // way too far
+ }
+ }
+ }
+};
+
+#define LOOP_TILER(code) \
+ SkDrawTiler priv_tiler(this); \
+ while (const SkDraw* priv_draw = priv_tiler.next()) { \
+ priv_draw->code; \
+ }
+#define TILER_X(x) (x) - priv_tiler.curr_x()
+#define TILER_Y(y) (y) - priv_tiler.curr_y()
+
+
class SkColorTable;
static bool valid_for_bitmap_device(const SkImageInfo& info,
@@ -173,30 +283,17 @@ bool SkBitmapDevice::onReadPixels(const SkPixmap& pm, int x, int y) {
///////////////////////////////////////////////////////////////////////////////
-class SkBitmapDevice::BDDraw : public SkDraw {
-public:
- BDDraw(SkBitmapDevice* dev) {
- // we need fDst to be set, and if we're actually drawing, to dirty the genID
- if (!dev->accessPixels(&fDst)) {
- // NoDrawDevice uses us (why?) so we have to catch this case w/ no pixels
- fDst.reset(dev->imageInfo(), nullptr, 0);
- }
- fMatrix = &dev->ctm();
- fRC = &dev->fRCStack.rc();
- }
-};
-
void SkBitmapDevice::drawPaint(const SkPaint& paint) {
- BDDraw(this).drawPaint(paint);
+ LOOP_TILER( drawPaint(paint))
}
void SkBitmapDevice::drawPoints(SkCanvas::PointMode mode, size_t count,
const SkPoint pts[], const SkPaint& paint) {
- BDDraw(this).drawPoints(mode, count, pts, paint, nullptr);
+ LOOP_TILER( drawPoints(mode, count, pts, paint, nullptr))
}
void SkBitmapDevice::drawRect(const SkRect& r, const SkPaint& paint) {
- BDDraw(this).drawRect(r, paint);
+ LOOP_TILER( drawRect(r, paint))
}
void SkBitmapDevice::drawOval(const SkRect& oval, const SkPaint& paint) {
@@ -216,21 +313,27 @@ void SkBitmapDevice::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
// required to override drawRRect.
this->drawPath(path, paint, nullptr, true);
#else
- BDDraw(this).drawRRect(rrect, paint);
+ LOOP_TILER( drawRRect(rrect, paint))
#endif
}
void SkBitmapDevice::drawPath(const SkPath& path,
const SkPaint& paint, const SkMatrix* prePathMatrix,
bool pathIsMutable) {
- BDDraw(this).drawPath(path, paint, prePathMatrix, pathIsMutable);
+ SkDrawTiler tiler(this);
+ if (tiler.needsTiling()) {
+ pathIsMutable = false;
+ }
+ while (const SkDraw* draw = tiler.next()) {
+ draw->drawPath(path, paint, prePathMatrix, pathIsMutable);
+ }
}
void SkBitmapDevice::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
const SkPaint& paint) {
SkMatrix matrix = SkMatrix::MakeTrans(x, y);
LogDrawScaleFactor(SkMatrix::Concat(this->ctm(), matrix), paint.getFilterQuality());
- BDDraw(this).drawBitmap(bitmap, matrix, nullptr, paint);
+ LOOP_TILER( drawBitmap(bitmap, matrix, nullptr, paint))
}
static inline bool CanApplyDstMatrixAsCTM(const SkMatrix& m, const SkPaint& paint) {
@@ -325,7 +428,7 @@ void SkBitmapDevice::drawBitmapRect(const SkBitmap& bitmap,
// matrix with the CTM, and try to call drawSprite if it can. If not,
// it will make a shader and call drawRect, as we do below.
if (CanApplyDstMatrixAsCTM(matrix, paint)) {
- BDDraw(this).drawBitmap(*bitmapPtr, matrix, dstPtr, paint);
+ LOOP_TILER( drawBitmap(*bitmapPtr, matrix, dstPtr, paint))
return;
}
}
@@ -354,25 +457,25 @@ void SkBitmapDevice::drawBitmapRect(const SkBitmap& bitmap,
}
void SkBitmapDevice::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& paint) {
- BDDraw(this).drawSprite(bitmap, x, y, paint);
+ LOOP_TILER( drawSprite(bitmap, TILER_X(x), TILER_Y(y), paint))
}
void SkBitmapDevice::drawText(const void* text, size_t len,
SkScalar x, SkScalar y, const SkPaint& paint) {
- BDDraw(this).drawText((const char*)text, len, x, y, paint, &fSurfaceProps);
+ LOOP_TILER( drawText((const char*)text, len, x, y, paint, &fSurfaceProps))
}
void SkBitmapDevice::drawPosText(const void* text, size_t len, const SkScalar xpos[],
int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) {
- BDDraw(this).drawPosText((const char*)text, len, xpos, scalarsPerPos, offset, paint,
- &fSurfaceProps);
+ LOOP_TILER( drawPosText((const char*)text, len, xpos, scalarsPerPos, offset, paint,
+ &fSurfaceProps))
}
void SkBitmapDevice::drawVertices(const SkVertices* vertices, SkBlendMode bmode,
const SkPaint& paint) {
- BDDraw(this).drawVertices(vertices->mode(), vertices->vertexCount(), vertices->positions(),
- vertices->texCoords(), vertices->colors(), bmode,
- vertices->indices(), vertices->indexCount(), paint);
+ LOOP_TILER( drawVertices(vertices->mode(), vertices->vertexCount(), vertices->positions(),
+ vertices->texCoords(), vertices->colors(), bmode,
+ vertices->indices(), vertices->indexCount(), paint))
}
void SkBitmapDevice::drawDevice(SkBaseDevice* device, int x, int y, const SkPaint& origPaint) {
@@ -384,7 +487,8 @@ void SkBitmapDevice::drawDevice(SkBaseDevice* device, int x, int y, const SkPain
paint.writable()->setMaskFilter(paint->getMaskFilter()->makeWithLocalMatrix(this->ctm()));
}
- BDDraw(this).drawSprite(static_cast<SkBitmapDevice*>(device)->fBitmap, x, y, *paint);
+ LOOP_TILER( drawSprite(static_cast<SkBitmapDevice*>(device)->fBitmap,
+ TILER_X(x), TILER_Y(y), *paint))
}
///////////////////////////////////////////////////////////////////////////////