diff options
author | Mike Reed <reed@google.com> | 2018-03-06 13:40:24 -0500 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-03-06 19:56:46 +0000 |
commit | be1b3971806e3d80aa9673a36e2b35d0145198ac (patch) | |
tree | fec8c2a345951fdd14b4c5da392586f231cb9c92 /src/core/SkBitmapDevice.cpp | |
parent | 18e9ba1eddb09bff6083f9a83dc569d3b3b54fe6 (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.cpp | 160 |
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)) } /////////////////////////////////////////////////////////////////////////////// |