diff options
author | Yuqian Li <liyuqian@google.com> | 2017-04-03 10:52:48 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-04-03 15:42:15 +0000 |
commit | b55dd553124cd00260bc9e3a63ec8a8fe09412a8 (patch) | |
tree | c2456bbc9458f1ce9b9c33c56db9449b5b05c7f2 /src | |
parent | 94421943818126921cf9fd3337f372e9f377bd16 (diff) |
Add SkThreadedBMPDevice for Threaded Raster Backend
BUG=skia:
Change-Id: I882b6563c735796f3a4dcd19f6c79e7efd8306ae
Reviewed-on: https://skia-review.googlesource.com/10505
Commit-Queue: Yuqian Li <liyuqian@google.com>
Reviewed-by: Mike Klein <mtklein@chromium.org>
Diffstat (limited to 'src')
-rw-r--r-- | src/core/SkBitmapDevice.h | 3 | ||||
-rw-r--r-- | src/core/SkThreadedBMPDevice.cpp | 176 | ||||
-rw-r--r-- | src/core/SkThreadedBMPDevice.h | 57 |
3 files changed, 235 insertions, 1 deletions
diff --git a/src/core/SkBitmapDevice.h b/src/core/SkBitmapDevice.h index d0f8be4acd..8055b9d12d 100644 --- a/src/core/SkBitmapDevice.h +++ b/src/core/SkBitmapDevice.h @@ -111,7 +111,7 @@ protected: void drawDevice(SkBaseDevice*, int x, int y, const SkPaint&) override; /////////////////////////////////////////////////////////////////////////// - + void drawSpecial(SkSpecialImage*, int x, int y, const SkPaint&) override; sk_sp<SkSpecialImage> makeSpecial(const SkBitmap&) override; sk_sp<SkSpecialImage> makeSpecial(const SkImage*) override; @@ -143,6 +143,7 @@ private: friend class SkDrawIter; friend class SkDeviceFilteredPaint; friend class SkSurface_Raster; + friend class SkThreadedBMPDevice; // to copy fRCStack class BDDraw; diff --git a/src/core/SkThreadedBMPDevice.cpp b/src/core/SkThreadedBMPDevice.cpp new file mode 100644 index 0000000000..1cf7fe449a --- /dev/null +++ b/src/core/SkThreadedBMPDevice.cpp @@ -0,0 +1,176 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkThreadedBMPDevice.h" + +#include "SkPath.h" +#include "SkTaskGroup.h" +#include "SkVertices.h" + +SkThreadedBMPDevice::SkThreadedBMPDevice(const SkBitmap& bitmap, int threads) + : INHERITED(bitmap) + , fThreadCnt(threads) +{ + // Tiling using stripes for now; we'll explore better tiling in the future. + int h = (bitmap.height() + fThreadCnt - 1) / SkTMax(fThreadCnt, 1); + int w = bitmap.width(); + int top = 0; + for(int tid = 0; tid < fThreadCnt; ++tid, top += h) { + fThreadBounds.push_back(SkIRect::MakeLTRB(0, top, w, top + h)); + } +} + +void SkThreadedBMPDevice::flush() { + SkTaskGroup().batch(fThreadCnt, [this](int i) { + for(auto& element : fQueue) { + if (SkIRect::Intersects(fThreadBounds[i], element.fDrawBounds)) { + element.fDrawFn(fThreadBounds[i]); + } + } + }); + fQueue.reset(); +} + +// Having this captured in lambda seems to be faster than saving this in DrawElement +struct SkThreadedBMPDevice::DrawState { + SkPixmap fDst; + SkMatrix fMatrix; + SkRasterClip fRC; + + explicit DrawState(SkThreadedBMPDevice* 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(); + } + + SkDraw getThreadDraw(SkRasterClip& threadRC, const SkIRect& threadBounds) const { + SkDraw draw; + draw.fDst = fDst; + draw.fMatrix = &fMatrix; + threadRC = fRC; + threadRC.op(threadBounds, SkRegion::kIntersect_Op); + draw.fRC = &threadRC; + return draw; + } +}; + +SkIRect SkThreadedBMPDevice::transformDrawBounds(const SkRect& drawBounds) const { + if (drawBounds.isLargest()) { + return SkIRect::MakeLargest(); + } + SkRect transformedBounds; + this->ctm().mapRect(&transformedBounds, drawBounds); + return transformedBounds.roundOut(); +} + +// The do {...} while (false) is to enforce trailing semicolon as suggested by mtklein@ +#define THREADED_DRAW(drawBounds, actualDrawCall) \ + do { \ + DrawState ds(this); \ + fQueue.push_back({ \ + this->transformDrawBounds(drawBounds), \ + [=](const SkIRect& threadBounds) { \ + SkRasterClip threadRC; \ + SkDraw draw = ds.getThreadDraw(threadRC, threadBounds); \ + draw.actualDrawCall; \ + }, \ + }); \ + } while (false) + +static inline SkRect get_fast_bounds(const SkRect& r, const SkPaint& p) { + SkRect result; + if (p.canComputeFastBounds()) { + result = p.computeFastBounds(r, &result); + } else { + result = SkRect::MakeLargest(); + } + return result; +} + +void SkThreadedBMPDevice::drawPaint(const SkPaint& paint) { + THREADED_DRAW(SkRect::MakeLargest(), drawPaint(paint)); +} + +void SkThreadedBMPDevice::drawPoints(SkCanvas::PointMode mode, size_t count, + const SkPoint pts[], const SkPaint& paint) { + // TODO tighter drawBounds + SkRect drawBounds = SkRect::MakeLargest(); + THREADED_DRAW(drawBounds, drawPoints(mode, count, pts, paint, nullptr)); +} + +void SkThreadedBMPDevice::drawRect(const SkRect& r, const SkPaint& paint) { + SkRect drawBounds = get_fast_bounds(r, paint); + THREADED_DRAW(drawBounds, drawRect(r, paint)); +} + +void SkThreadedBMPDevice::drawRRect(const SkRRect& rrect, const SkPaint& paint) { +#ifdef SK_IGNORE_BLURRED_RRECT_OPT + SkPath path; + + path.addRRect(rrect); + // call the VIRTUAL version, so any subclasses who do handle drawPath aren't + // required to override drawRRect. + this->drawPath(path, paint, nullptr, false); +#else + SkRect drawBounds = get_fast_bounds(rrect.getBounds(), paint); + THREADED_DRAW(drawBounds, drawRRect(rrect, paint)); +#endif +} + +void SkThreadedBMPDevice::drawPath(const SkPath& path, const SkPaint& paint, + const SkMatrix* prePathMatrix, bool pathIsMutable) { + SkRect drawBounds = path.isInverseFillType() ? SkRect::MakeLargest() + : get_fast_bounds(path.getBounds(), paint); + // For thread safety, make path imutable + THREADED_DRAW(drawBounds, drawPath(path, paint, prePathMatrix, false)); +} + +void SkThreadedBMPDevice::drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, + const SkPaint& paint) { + LogDrawScaleFactor(SkMatrix::Concat(this->ctm(), matrix), paint.getFilterQuality()); + SkRect drawBounds = SkRect::MakeWH(bitmap.width(), bitmap.height()); + matrix.mapRect(&drawBounds); + THREADED_DRAW(drawBounds, drawBitmap(bitmap, matrix, nullptr, paint)); +} + +void SkThreadedBMPDevice::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& paint) { + SkRect drawBounds = SkRect::MakeXYWH(x, y, bitmap.width(), bitmap.height()); + THREADED_DRAW(drawBounds, drawSprite(bitmap, x, y, paint)); +} + +void SkThreadedBMPDevice::drawText(const void* text, size_t len, SkScalar x, SkScalar y, + const SkPaint& paint) { + SkRect drawBounds = SkRect::MakeLargest(); // TODO tighter drawBounds + THREADED_DRAW(drawBounds, drawText((const char*)text, len, x, y, paint, &this->surfaceProps())); +} + +void SkThreadedBMPDevice::drawPosText(const void* text, size_t len, const SkScalar xpos[], + int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) { + SkRect drawBounds = SkRect::MakeLargest(); // TODO tighter drawBounds + THREADED_DRAW(drawBounds, drawPosText((const char*)text, len, xpos, scalarsPerPos, offset, + paint, &surfaceProps())); +} + +void SkThreadedBMPDevice::drawVertices(const SkVertices* vertices, SkBlendMode bmode, + const SkPaint& paint) { + SkRect drawBounds = SkRect::MakeLargest(); // TODO tighter drawBounds + THREADED_DRAW(drawBounds, drawVertices(vertices->mode(), vertices->vertexCount(), + vertices->positions(), vertices->texCoords(), + vertices->colors(), bmode, vertices->indices(), + vertices->indexCount(), paint)); +} + +void SkThreadedBMPDevice::drawDevice(SkBaseDevice* device, int x, int y, const SkPaint& paint) { + SkASSERT(!paint.getImageFilter()); + SkRect drawBounds = SkRect::MakeXYWH(x, y, device->width(), device->height()); + THREADED_DRAW(drawBounds, + drawSprite(static_cast<SkBitmapDevice*>(device)->fBitmap, x, y, paint)); +} diff --git a/src/core/SkThreadedBMPDevice.h b/src/core/SkThreadedBMPDevice.h new file mode 100644 index 0000000000..ea69f7a858 --- /dev/null +++ b/src/core/SkThreadedBMPDevice.h @@ -0,0 +1,57 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkThreadedBMPDevice_DEFINED +#define SkThreadedBMPDevice_DEFINED + +#include "SkDraw.h" +#include "SkBitmapDevice.h" + +/////////////////////////////////////////////////////////////////////////////// +class SkThreadedBMPDevice : public SkBitmapDevice { +public: + SkThreadedBMPDevice(const SkBitmap& bitmap, int threads); + +protected: + void drawPaint(const SkPaint& paint) override; + void drawPoints(SkCanvas::PointMode mode, size_t count, + const SkPoint[], const SkPaint& paint) override; + void drawRect(const SkRect& r, const SkPaint& paint) override; + void drawRRect(const SkRRect& rr, const SkPaint& paint) override; + + void drawPath(const SkPath&, const SkPaint&, const SkMatrix* prePathMatrix, + bool pathIsMutable) override; + void drawBitmap(const SkBitmap&, const SkMatrix&, const SkPaint&) override; + void drawSprite(const SkBitmap&, int x, int y, const SkPaint&) override; + + void drawText(const void* text, size_t len, SkScalar x, SkScalar y, + const SkPaint&) override; + void drawPosText(const void* text, size_t len, const SkScalar pos[], + int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) override; + void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override; + void drawDevice(SkBaseDevice*, int x, int y, const SkPaint&) override; + + void flush() override; + +private: + struct DrawElement { + SkIRect fDrawBounds; + std::function<void(const SkIRect& threadBounds)> fDrawFn; + }; + + struct DrawState; + + SkIRect transformDrawBounds(const SkRect& drawBounds) const; + + const int fThreadCnt; + SkTArray<SkIRect> fThreadBounds; + SkTArray<DrawElement> fQueue; + + typedef SkBitmapDevice INHERITED; +}; + +#endif // SkThreadedBMPDevice_DEFINED |