aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Mike Klein <mtklein@google.com>2018-07-25 13:28:44 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-07-25 18:17:26 +0000
commit48b649060c8d3ae104274703553d7c03a58f3ddd (patch)
tree6f29689578387a2c1234a6aeb89803d3f6924c59 /src
parent1c94a8fabed7196e985a0ed81ce8325c8f606940 (diff)
remove SkThreadedBMPDevice and friends
It is unused, is becoming a maintainence burden and source of bugs, and takes up a lot of time on the *SAN bots. Change-Id: If383eb6e4838ca23140f9e16d518b1bfc655fa12 Reviewed-on: https://skia-review.googlesource.com/143307 Auto-Submit: Mike Klein <mtklein@google.com> Commit-Queue: Herb Derby <herb@google.com> Reviewed-by: Herb Derby <herb@google.com>
Diffstat (limited to 'src')
-rw-r--r--src/core/SkBitmapDevice.h1
-rw-r--r--src/core/SkDraw.cpp50
-rw-r--r--src/core/SkDraw.h7
-rw-r--r--src/core/SkTaskGroup2D.cpp86
-rw-r--r--src/core/SkTaskGroup2D.h123
-rw-r--r--src/core/SkThreadedBMPDevice.cpp250
-rw-r--r--src/core/SkThreadedBMPDevice.h225
7 files changed, 6 insertions, 736 deletions
diff --git a/src/core/SkBitmapDevice.h b/src/core/SkBitmapDevice.h
index 379d42ddd1..8abc677f99 100644
--- a/src/core/SkBitmapDevice.h
+++ b/src/core/SkBitmapDevice.h
@@ -155,7 +155,6 @@ private:
friend class SkDrawTiler;
friend class SkDeviceFilteredPaint;
friend class SkSurface_Raster;
- friend class SkThreadedBMPDevice; // to copy fRCStack
class BDDraw;
diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp
index 8a49abfe3a..bd607553cd 100644
--- a/src/core/SkDraw.cpp
+++ b/src/core/SkDraw.cpp
@@ -35,7 +35,6 @@
#include "SkTLazy.h"
#include "SkTemplates.h"
#include "SkTextMapStateProc.h"
-#include "SkThreadedBMPDevice.h"
#include "SkTo.h"
#include "SkUtils.h"
@@ -957,11 +956,8 @@ SkScalar SkDraw::ComputeResScaleForStroking(const SkMatrix& matrix) {
}
void SkDraw::drawDevPath(const SkPath& devPath, const SkPaint& paint, bool drawCoverage,
- SkBlitter* customBlitter, bool doFill, SkInitOnceData* iData) const {
+ SkBlitter* customBlitter, bool doFill) const {
if (SkPathPriv::TooBigForMath(devPath)) {
- if (iData) {
- iData->setEmptyDrawFn();
- }
return;
}
SkBlitter* blitter = nullptr;
@@ -976,9 +972,6 @@ void SkDraw::drawDevPath(const SkPath& devPath, const SkPaint& paint, bool drawC
SkStrokeRec::InitStyle style = doFill ? SkStrokeRec::kFill_InitStyle
: SkStrokeRec::kHairline_InitStyle;
if (as_MFB(paint.getMaskFilter())->filterPath(devPath, *fMatrix, *fRC, blitter, style)) {
- if (iData) {
- iData->setEmptyDrawFn();
- }
return; // filterPath() called the blitter, so we're done
}
}
@@ -1024,48 +1017,16 @@ void SkDraw::drawDevPath(const SkPath& devPath, const SkPaint& paint, bool drawC
}
}
- if (iData == nullptr) {
- proc(devPath, *fRC, blitter); // proceed directly if we're not in threaded init-once
- } else if (!doFill || !paint.isAntiAlias()) {
- // We're in threaded init-once but we can't use DAA. Hence we'll stop here and hand all the
- // remaining work to draw phase. This is a simple example of how to add init-once to
- // existing drawXXX commands: simply send in SkInitOnceData, do as much init work as
- // possible, and finally wrap the remaining work into iData->fElement->fDrawFn.
- SkASSERT(customBlitter == nullptr);
- devPath.updateBoundsCache(); // make it thread safe
- iData->fElement->setDrawFn([proc, devPath, paint, drawCoverage](SkArenaAlloc* alloc,
- const SkThreadedBMPDevice::DrawState& ds, const SkIRect& tileBounds) {
- SkThreadedBMPDevice::TileDraw tileDraw(ds, tileBounds);
- SkAutoBlitterChoose blitterStorage(tileDraw, nullptr, paint, drawCoverage);
- proc(devPath, *tileDraw.fRC, blitterStorage.get());
- });
- } else {
- // We can use DAA to do scan conversion in the init-once phase.
- SkDAARecord* record = iData->fAlloc->make<SkDAARecord>(iData->fAlloc);
- SkNullBlitter nullBlitter; // We don't want to blit anything during the init phase
- SkScan::AntiFillPath(devPath, *fRC, &nullBlitter, record);
- SkASSERT(customBlitter == nullptr);
- iData->fElement->setDrawFn([record, devPath, paint, drawCoverage](SkArenaAlloc* alloc,
- const SkThreadedBMPDevice::DrawState& ds, const SkIRect& tileBounds) {
- SkASSERT(record->fType != SkDAARecord::Type::kToBeComputed);
- SkThreadedBMPDevice::TileDraw tileDraw(ds, tileBounds);
- SkAutoBlitterChoose blitterStorage(tileDraw, nullptr, paint, drawCoverage);
- SkScan::AntiFillPath(devPath, *tileDraw.fRC, blitterStorage.get(), record);
- });
- }
+ proc(devPath, *fRC, blitter);
}
void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint,
const SkMatrix* prePathMatrix, bool pathIsMutable,
- bool drawCoverage, SkBlitter* customBlitter,
- SkInitOnceData* iData) const {
+ bool drawCoverage, SkBlitter* customBlitter) const {
SkDEBUGCODE(this->validate();)
// nothing to draw
if (fRC->isEmpty()) {
- if (iData) {
- iData->setEmptyDrawFn();
- }
return;
}
@@ -1075,9 +1036,6 @@ void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint,
SkPath* tmpPath = &tmpPathStorage;
SkMatrix tmpMatrix;
const SkMatrix* matrix = fMatrix;
- if (iData) {
- tmpPath = iData->fAlloc->make<SkPath>();
- }
tmpPath->setIsVolatile(true);
SkPathPriv::SetIsBadForDAA(*tmpPath, SkPathPriv::IsBadForDAA(origSrcPath));
@@ -1142,7 +1100,7 @@ void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint,
// transform the path into device space
pathPtr->transform(*matrix, devPathPtr);
- this->drawDevPath(*devPathPtr, *paint, drawCoverage, customBlitter, doFill, iData);
+ this->drawDevPath(*devPathPtr, *paint, drawCoverage, customBlitter, doFill);
}
void SkDraw::drawBitmapAsMask(const SkBitmap& bitmap, const SkPaint& paint) const {
diff --git a/src/core/SkDraw.h b/src/core/SkDraw.h
index deb7451b99..a64abe74ff 100644
--- a/src/core/SkDraw.h
+++ b/src/core/SkDraw.h
@@ -31,7 +31,6 @@ class SkRasterClip;
struct SkDrawProcs;
struct SkRect;
class SkRRect;
-struct SkInitOnceData;
class SkDraw {
public:
@@ -137,11 +136,11 @@ private:
void drawPath(const SkPath&, const SkPaint&, const SkMatrix* preMatrix,
bool pathIsMutable, bool drawCoverage,
- SkBlitter* customBlitter = nullptr, SkInitOnceData* iData = nullptr) const;
+ SkBlitter* customBlitter = nullptr) const;
void drawLine(const SkPoint[2], const SkPaint&) const;
void drawDevPath(const SkPath& devPath, const SkPaint& paint, bool drawCoverage,
- SkBlitter* customBlitter, bool doFill, SkInitOnceData* iData = nullptr) const;
+ SkBlitter* customBlitter, bool doFill) const;
/**
* Return the current clip bounds, in local coordinates, with slop to account
* for antialiasing or hairlines (i.e. device-bounds outset by 1, and then
@@ -169,8 +168,6 @@ public:
#else
void validate() const {}
#endif
-
- friend class SkThreadedBMPDevice; // to access private method drawPath
};
#endif
diff --git a/src/core/SkTaskGroup2D.cpp b/src/core/SkTaskGroup2D.cpp
deleted file mode 100644
index 59eecf9f9a..0000000000
--- a/src/core/SkTaskGroup2D.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * 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 "SkTaskGroup2D.h"
-
-void SkTaskGroup2D::start() {
- fThreadsGroup->batch(fThreadCnt, [this](int threadId){
- this->work(threadId);
- });
-}
-
-void SkTaskGroup2D::addColumn() {
- SkASSERT(!fIsFinishing); // we're not supposed to add more work after the calling of finish
- fWidth++;
-}
-
-void SkTaskGroup2D::finish() {
- fIsFinishing = true;
- fThreadsGroup->wait();
-}
-
-void SkSpinningTaskGroup2D::work(int threadId) {
- int workCol = 0;
- int initCol = 0;
-
- while (true) {
- SkASSERT(workCol <= fWidth);
- if (this->isFinishing() && workCol >= fWidth) {
- return;
- }
-
- // Note that row = threadId
- if (workCol < fWidth && fKernel->work2D(threadId, workCol, threadId)) {
- workCol++;
- } else {
- // Initialize something if we can't work
- this->initAnUninitializedColumn(initCol, threadId);
- }
- }
-}
-
-void SkFlexibleTaskGroup2D::work(int threadId) {
- int row = threadId;
- int initCol = 0;
- int numRowsCompleted = 0;
- std::vector<bool> completedRows(fHeight, false);
-
- // Only keep fHeight - numRowsCompleted number of threads looping. When rows are about to
- // complete, this strategy keeps the contention low.
- while (threadId < fHeight - numRowsCompleted) {
- RowData& rowData = fRowData[row];
-
- // The Android roller somehow gets a false-positive compile warning/error about the try-lock
- // and unlock process. Hence we disable -Wthread-safety-analysis to bypass it.
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wthread-safety-analysis"
-#endif
- if (rowData.fMutex.try_lock()) {
- while (rowData.fNextColumn < fWidth &&
- fKernel->work2D(row, rowData.fNextColumn, threadId)) {
- rowData.fNextColumn++;
- }
- // isFinishing can never go from true to false. Once it's true, we count how many rows
- // are completed (out of work). If that count reaches fHeight, then we're out of work
- // for the whole group and we can stop.
- if (rowData.fNextColumn == fWidth && this->isFinishing()) {
- numRowsCompleted += (completedRows[row] == false);
- completedRows[row] = true; // so we won't count this row twice
- }
- rowData.fMutex.unlock();
- }
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-
- // By reaching here, we're either unable to acquire the row, or out of work, or blocked by
- // initialization
- row = (row + 1) % fHeight; // Move to the next row
- this->initAnUninitializedColumn(initCol, threadId); // Initialize something
- }
-}
diff --git a/src/core/SkTaskGroup2D.h b/src/core/SkTaskGroup2D.h
deleted file mode 100644
index 20915cf9d7..0000000000
--- a/src/core/SkTaskGroup2D.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * 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 SkTaskGroup2D_DEFINED
-#define SkTaskGroup2D_DEFINED
-
-#include "SkTaskGroup.h"
-
-#include <mutex>
-#include <vector>
-
-// The interface for doing work on a 2D grid with possible initialization on columns.
-class SkWorkKernel2D {
-public:
- // Return false iff the column needs initialization and such initialization is not finished yet.
- virtual bool work2D(int row, int column, int thread) = 0;
-
- // Return false if no initialization is done for this colum (e.g., it's already initialized; or
- // maybe some other thread is initializing the column).
- virtual bool initColumn(int column, int thread) = 0;
-
- virtual ~SkWorkKernel2D() {}
-};
-
-// A 2D grid (height rows x width columns) of tasks to be executed on a given executor with
-// threadCnt number of threads.
-//
-// The height (number of rows) is fixed. The width (number of columns) may be dynamically expanded.
-//
-// The task on row i and column j is abstracted as work2D(i, j, t). Parameter t is the thread id and
-// it shouldn't affect the work to be done. It's only used to allow some variables that are not
-// thread safe and should be used exclusively by one thread (e.g., thread allocators). We guarantee
-// that the task on the same row will be executed in order (i.e., work2D(1, 1, t) is guaranteed to
-// finish before calling work2D(1, 2, t)). Tasks in different rows can happen in any order.
-//
-// There are also width number of init calls, one per column. work2D(i, j, t) may return false if
-// column j requires initialization but it's not initialized yet. In that case, a thread t needs to
-// call initColumn(j, t) once to unblock all rows that depend on the initialization of column j.
-// (Again, t shouldn't affect the init work to be done; it's just for some non-thread-safe
-// variables). The init calls have no order requirement so we can call them in any order.
-//
-// Multiple therads may try to init the same column j at the same time. InitFn is expected to handle
-// this gracefully (e.g., let only one thread do the init and return immediately for other threads).
-class SkTaskGroup2D {
-public:
- SkTaskGroup2D(SkWorkKernel2D* kernel, int height, SkExecutor* executor, int threadCnt)
- : fKernel(kernel), fHeight(height), fThreadCnt(threadCnt), fIsFinishing(false)
- , fWidth(0), fThreadsGroup(new SkTaskGroup(*executor)) {}
-
- virtual ~SkTaskGroup2D() {}
-
- virtual void addColumn(); // Add a new column of tasks.
-
- void start(); // start threads to execute tasks
- void finish(); // wait and finish all tasks (no more tasks can be added after calling this)
-
- SK_ALWAYS_INLINE bool isFinishing() const {
- return fIsFinishing;
- }
-
-protected:
- static constexpr int MAX_CACHE_LINE = 64;
-
- // Finish all tasks on the threadId and then return.
- virtual void work(int threadId) = 0;
-
- // Initialize a column that needs to be initialized. The parameter initCol is not thread safe
- // and should only be exclusively accessed by the working thread which will modify it to the
- // column that may need to be initialized next.
- void initAnUninitializedColumn(int& initCol, int threadId) {
- bool didSomeInit = false;
- while (initCol < fWidth && !didSomeInit) {
- didSomeInit = fKernel->initColumn(initCol++, threadId);
- }
- }
-
- SkWorkKernel2D* fKernel;
- const int fHeight;
- const int fThreadCnt;
-
- std::atomic<bool> fIsFinishing;
- std::atomic<int> fWidth;
-
- std::unique_ptr<SkTaskGroup> fThreadsGroup;
-};
-
-// A simple spinning task group that assumes height equals threadCnt.
-class SkSpinningTaskGroup2D final : public SkTaskGroup2D {
-public:
- SkSpinningTaskGroup2D(SkWorkKernel2D* kernel, int h, SkExecutor* x, int t)
- : SkTaskGroup2D(kernel, h, x, t) {
- SkASSERT(h == t); // height must be equal to threadCnt
- }
-
-protected:
- void work(int threadId) override;
-};
-
-class SkFlexibleTaskGroup2D final : public SkTaskGroup2D {
-public:
- SkFlexibleTaskGroup2D(SkWorkKernel2D* kernel, int h, SkExecutor* x, int t)
- : SkTaskGroup2D(kernel, h, x, t), fRowData(h) {}
-
-protected:
- void work(int threadId) override;
-
-private:
- // alignas(MAX_CACHE_LINE) to avoid false sharing by cache lines
- struct alignas(MAX_CACHE_LINE) RowData {
- RowData() : fNextColumn(0) {}
-
- int fNextColumn; // next column index to work
- std::mutex fMutex; // the mutex for the thread to acquire
- };
-
- std::vector<RowData> fRowData;
-};
-
-#endif//SkTaskGroup2D_DEFINED
diff --git a/src/core/SkThreadedBMPDevice.cpp b/src/core/SkThreadedBMPDevice.cpp
deleted file mode 100644
index 1dea5e6d2d..0000000000
--- a/src/core/SkThreadedBMPDevice.cpp
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * 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 "SkSpecialImage.h"
-#include "SkTaskGroup.h"
-#include "SkVertices.h"
-
-// Calling init(j, k) would initialize the j-th element on k-th thread. It returns false if it's
-// already initiailized.
-bool SkThreadedBMPDevice::DrawQueue::initColumn(int column, int thread) {
- return fElements[column].tryInitOnce(&fThreadAllocs[thread]);
-}
-
-// Calling work(i, j, k) would draw j-th element the i-th tile on k-th thead. If the element still
-// needs to be initialized, drawFn will return false without drawing.
-bool SkThreadedBMPDevice::DrawQueue::work2D(int row, int column, int thread) {
- return fElements[column].tryDraw(fDevice->fTileBounds[row], &fThreadAllocs[thread]);
-}
-
-void SkThreadedBMPDevice::DrawQueue::reset() {
- if (fTasks) {
- fTasks->finish();
- }
-
- fThreadAllocs.reset(fDevice->fThreadCnt);
- fSize = 0;
-
- // using TaskGroup2D = SkSpinningTaskGroup2D;
- using TaskGroup2D = SkFlexibleTaskGroup2D;
-
- fTasks.reset(new TaskGroup2D(this, fDevice->fTileCnt, fDevice->fExecutor,
- fDevice->fThreadCnt));
- fTasks->start();
-}
-
-SkThreadedBMPDevice::SkThreadedBMPDevice(const SkBitmap& bitmap,
- int tiles,
- int threads,
- SkExecutor* executor)
- : INHERITED(bitmap)
- , fTileCnt(tiles)
- , fThreadCnt(threads <= 0 ? tiles : threads)
- , fQueue(this)
-{
- if (executor == nullptr) {
- fInternalExecutor = SkExecutor::MakeFIFOThreadPool(fThreadCnt);
- executor = fInternalExecutor.get();
- }
- fExecutor = executor;
-
- // Tiling using stripes for now; we'll explore better tiling in the future.
- int h = (bitmap.height() + fTileCnt - 1) / SkTMax(fTileCnt, 1);
- int w = bitmap.width();
- int top = 0;
- for(int tid = 0; tid < fTileCnt; ++tid, top += h) {
- fTileBounds.push_back(SkIRect::MakeLTRB(0, top, w, top + h));
- }
- fQueue.reset();
-}
-
-void SkThreadedBMPDevice::flush() {
- fQueue.reset();
- fAlloc.reset();
-}
-
-SkThreadedBMPDevice::DrawState::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();
- fMatrix.getType(); // make it thread safe
- fRC = dev->fRCStack.rc();
-}
-
-SkDraw SkThreadedBMPDevice::DrawState::getDraw() const {
- SkDraw draw;
- draw.fDst = fDst;
- draw.fMatrix = &fMatrix;
- draw.fRC = &fRC;
- return draw;
-}
-
-SkThreadedBMPDevice::TileDraw::TileDraw(const DrawState& ds, const SkIRect& tileBounds)
- : fTileRC(ds.fRC) {
- fDst = ds.fDst;
- fMatrix = &ds.fMatrix;
- fTileRC.op(tileBounds, SkRegion::kIntersect_Op);
- fRC = &fTileRC;
-}
-
-static inline SkRect get_fast_bounds(const SkRect& r, const SkPaint& p) {
- SkRect result;
- if (p.canComputeFastBounds()) {
- result = p.computeFastBounds(r, &result);
- } else {
- result = SkRectPriv::MakeLargest();
- }
- return result;
-}
-
-void SkThreadedBMPDevice::drawPaint(const SkPaint& paint) {
- SkRect drawBounds = SkRectPriv::MakeLargest();
- fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
- TileDraw(ds, tileBounds).drawPaint(paint);
- });
-}
-
-void SkThreadedBMPDevice::drawPoints(SkCanvas::PointMode mode, size_t count,
- const SkPoint pts[], const SkPaint& paint) {
- SkPoint* clonedPts = this->cloneArray(pts, count);
- SkRect drawBounds = SkRectPriv::MakeLargest(); // TODO tighter drawBounds
- fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
- TileDraw(ds, tileBounds).drawPoints(mode, count, clonedPts, paint, nullptr);
- });
-}
-
-void SkThreadedBMPDevice::drawRect(const SkRect& r, const SkPaint& paint) {
- SkRect drawBounds = get_fast_bounds(r, paint);
- fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
- TileDraw(ds, tileBounds).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);
- fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
- TileDraw(ds, tileBounds).drawRRect(rrect, paint);
- });
-#endif
-}
-
-void SkThreadedBMPDevice::drawPath(const SkPath& path, const SkPaint& paint,
- const SkMatrix* prePathMatrix, bool pathIsMutable) {
- SkRect drawBounds = path.isInverseFillType() ? SkRectPriv::MakeLargest()
- : get_fast_bounds(path.getBounds(), paint);
- // when path is small, init-once has too much overhead; init-once also can't handle mask filter
- if (path.countVerbs() < 4 || paint.getMaskFilter()) {
- fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds) {
- TileDraw(ds, tileBounds).drawPath(path, paint, prePathMatrix, false);
- });
- } else {
- fQueue.push(drawBounds, [=](SkArenaAlloc* alloc, DrawElement* elem) {
- SkInitOnceData data = {alloc, elem};
- elem->getDraw().drawPath(path, paint, prePathMatrix, false, false, nullptr, &data);
- });
- }
-}
-
-SkBitmap SkThreadedBMPDevice::snapBitmap(const SkBitmap& bitmap) {
- // We can't use bitmap.isImmutable() because it could be temporarily immutable
- // TODO(liyuqian): use genID to reduce the copy frequency
- SkBitmap snap;
- snap.allocPixels(bitmap.info());
- bitmap.readPixels(snap.pixmap());
- return snap;
-}
-
-void SkThreadedBMPDevice::drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix,
- const SkRect* dstOrNull, const SkPaint& paint) {
- SkRect drawBounds;
- SkRect* clonedDstOrNull = nullptr;
- if (dstOrNull == nullptr) {
- drawBounds = SkRect::MakeWH(bitmap.width(), bitmap.height());
- matrix.mapRect(&drawBounds);
- } else {
- drawBounds = *dstOrNull;
- clonedDstOrNull = fAlloc.make<SkRect>(*dstOrNull);
- }
-
- SkBitmap snap = this->snapBitmap(bitmap);
- fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
- SkBitmap local = snap; // bitmap is not thread safe; copy a local one.
- TileDraw(ds, tileBounds).drawBitmap(local, matrix, clonedDstOrNull, paint);
- });
-}
-
-void SkThreadedBMPDevice::drawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
- const SkRect& dst, const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) {
- // SkBitmapDevice::drawBitmapRect may use shader and drawRect. In that case, we need to snap
- // the bitmap here because we won't go into SkThreadedBMPDevice::drawBitmap.
- SkBitmap snap = this->snapBitmap(bitmap);
- this->SkBitmapDevice::drawBitmapRect(snap, src, dst, paint, constraint);
-}
-
-
-void SkThreadedBMPDevice::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& paint) {
- SkRect drawBounds = SkRect::MakeXYWH(x, y, bitmap.width(), bitmap.height());
- SkBitmap snap = this->snapBitmap(bitmap);
- fQueue.push<false>(drawBounds, [=](SkArenaAlloc*, const DrawState& ds,
- const SkIRect& tileBounds){
- SkBitmap local = snap; // bitmap is not thread safe; copy a local one.
- TileDraw(ds, tileBounds).drawSprite(local, x, y, paint);
- });
-}
-
-void SkThreadedBMPDevice::drawPosText(const void* text, size_t len, const SkScalar xpos[],
- int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) {
- char* clonedText = this->cloneArray((const char*)text, len);
- SkScalar* clonedXpos = this->cloneArray(xpos, paint.countText(text, len) * scalarsPerPos);
- SkRect drawBounds = SkRectPriv::MakeLargest(); // TODO tighter drawBounds
- SkSurfaceProps prop(SkBitmapDeviceFilteredSurfaceProps(fBitmap, paint, this->surfaceProps())());
- fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
- TileDraw(ds, tileBounds).drawPosText(clonedText, len, clonedXpos, scalarsPerPos, offset,
- paint, &prop);
- });
-}
-
-void SkThreadedBMPDevice::drawVertices(const SkVertices* vertices, const SkMatrix* bones,
- int boneCount, SkBlendMode bmode, const SkPaint& paint) {
- const sk_sp<SkVertices> verts = sk_ref_sp(vertices); // retain vertices until flush
- SkRect drawBounds = SkRectPriv::MakeLargest(); // TODO tighter drawBounds
-
- // Make a copy of the bone matrices.
- SkMatrix* clonedBones = bones ? this->cloneArray(bones, boneCount) : nullptr;
-
- // Make the bone matrices thread-safe.
- for (int i = 0; i < boneCount; i ++) {
- clonedBones[i].getType();
- }
-
- fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
- TileDraw(ds, tileBounds).drawVertices(verts->mode(), verts->vertexCount(),
- verts->positions(), verts->texCoords(),
- verts->colors(), verts->boneIndices(),
- verts->boneWeights(), bmode, verts->indices(),
- verts->indexCount(), paint, clonedBones, boneCount);
- });
-}
-
-sk_sp<SkSpecialImage> SkThreadedBMPDevice::snapSpecial() {
- this->flush();
- return this->makeSpecial(fBitmap);
-}
diff --git a/src/core/SkThreadedBMPDevice.h b/src/core/SkThreadedBMPDevice.h
deleted file mode 100644
index 0cfb91db07..0000000000
--- a/src/core/SkThreadedBMPDevice.h
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * 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 "SkBitmapDevice.h"
-#include "SkDraw.h"
-#include "SkRectPriv.h"
-#include "SkTaskGroup2D.h"
-#include <new>
-
-class SkThreadedBMPDevice : public SkBitmapDevice {
-public:
- // When threads = 0, we make fThreadCnt = tiles. Otherwise fThreadCnt = threads.
- // When executor = nullptr, we manages the thread pool. Otherwise, the caller manages it.
- SkThreadedBMPDevice(const SkBitmap& bitmap, int tiles, int threads = 0,
- SkExecutor* executor = nullptr);
-
- ~SkThreadedBMPDevice() override { fQueue.finish(); }
-
-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 drawSprite(const SkBitmap&, int x, int 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*, const SkMatrix* bones, int boneCount, SkBlendMode,
- const SkPaint&) override;
-
- void drawBitmap(const SkBitmap&, const SkMatrix&, const SkRect* dstOrNull,
- const SkPaint&) override;
- void drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
- const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) override;
-
- sk_sp<SkSpecialImage> snapSpecial() override;
-
- void flush() override;
-
-private:
- // We store DrawState inside DrawElement because inifFn and drawFn both want to use it
- struct DrawState {
- SkPixmap fDst;
- SkMatrix fMatrix;
- SkRasterClip fRC;
-
- DrawState() {}
- explicit DrawState(SkThreadedBMPDevice* dev);
-
- SkDraw getDraw() const;
- };
-
- class TileDraw : public SkDraw {
- public: TileDraw(const DrawState& ds, const SkIRect& tileBounds);
- private: SkRasterClip fTileRC;
- };
-
- class DrawElement {
- public:
- using InitFn = std::function<void(SkArenaAlloc* threadAlloc, DrawElement* element)>;
- using DrawFn = std::function<void(SkArenaAlloc* threadAlloc, const DrawState& ds,
- const SkIRect& tileBounds)>;
-
- DrawElement() {}
- DrawElement(SkThreadedBMPDevice* device, DrawFn&& drawFn, const SkIRect& drawBounds)
- : fInitialized(true)
- , fDrawFn(std::move(drawFn))
- , fDS(device)
- , fDrawBounds(drawBounds) {}
- DrawElement(SkThreadedBMPDevice* device, InitFn&& initFn, const SkIRect& drawBounds)
- : fInitialized(false)
- , fNeedInit(true)
- , fInitFn(std::move(initFn))
- , fDS(device)
- , fDrawBounds(drawBounds) {}
-
- SK_ALWAYS_INLINE bool tryInitOnce(SkArenaAlloc* alloc) {
- bool t = true;
- // If there are multiple threads reaching this point simutaneously,
- // compare_exchange_strong ensures that only one thread can enter the if condition and
- // do the initialization.
- if (!fInitialized && fNeedInit && fNeedInit.compare_exchange_strong(t, false)) {
-#ifdef SK_DEBUG
- fDrawFn = 0; // Invalidate fDrawFn
-#endif
- fInitFn(alloc, this);
- fInitialized = true;
- SkASSERT(fDrawFn != 0); // Ensure that fInitFn does populate fDrawFn
- return true;
- }
- return false;
- }
-
- SK_ALWAYS_INLINE bool tryDraw(const SkIRect& tileBounds, SkArenaAlloc* alloc) {
- if (!SkIRect::Intersects(tileBounds, fDrawBounds)) {
- return true;
- }
- if (fInitialized) {
- fDrawFn(alloc, fDS, tileBounds);
- return true;
- }
- return false;
- }
-
- SkDraw getDraw() const { return fDS.getDraw(); }
- void setDrawFn(DrawFn&& fn) { fDrawFn = std::move(fn); }
-
- private:
- std::atomic<bool> fInitialized;
- std::atomic<bool> fNeedInit;
- InitFn fInitFn;
- DrawFn fDrawFn;
- DrawState fDS;
- SkIRect fDrawBounds;
- };
-
- class DrawQueue : public SkWorkKernel2D {
- public:
- static constexpr int MAX_QUEUE_SIZE = 100000;
-
- DrawQueue(SkThreadedBMPDevice* device) : fDevice(device) {}
- void reset();
-
- // For ~SkThreadedBMPDevice() to shutdown tasks, we use this instead of reset because reset
- // will start new tasks.
- void finish() { fTasks->finish(); }
-
- // Push a draw command into the queue. If Fn is DrawFn, we're pushing an element without
- // the need of initialization. If Fn is InitFn, we're pushing an element with init-once
- // and the InitFn will generate the DrawFn during initialization.
- template<bool useCTM = true, typename Fn>
- SK_ALWAYS_INLINE void push(const SkRect& rawDrawBounds, Fn&& fn) {
- if (fSize == MAX_QUEUE_SIZE) {
- this->reset();
- }
- SkASSERT(fSize < MAX_QUEUE_SIZE);
- SkIRect drawBounds = fDevice->transformDrawBounds<useCTM>(rawDrawBounds);
- fElements[fSize].~DrawElement(); // release previous resources to prevent memory leak
- new (&fElements[fSize++]) DrawElement(fDevice, std::move(fn), drawBounds);
- fTasks->addColumn();
- }
-
- // SkWorkKernel2D
- bool initColumn(int column, int thread) override;
- bool work2D(int row, int column, int thread) override;
-
- private:
- SkThreadedBMPDevice* fDevice;
- std::unique_ptr<SkTaskGroup2D> fTasks;
- SkTArray<SkSTArenaAlloc<8 << 10>> fThreadAllocs; // 8k stack size
- DrawElement fElements[MAX_QUEUE_SIZE];
- int fSize;
- };
-
- template<bool useCTM = true>
- SkIRect transformDrawBounds(const SkRect& drawBounds) const {
- if (drawBounds == SkRectPriv::MakeLargest()) {
- return SkRectPriv::MakeILarge();
- }
- SkRect transformedBounds;
- if (useCTM) {
- this->ctm().mapRect(&transformedBounds, drawBounds);
- } else {
- transformedBounds = drawBounds;
- }
- return transformedBounds.roundOut();
- }
-
-
-
- template<typename T>
- T* cloneArray(const T* array, int count) {
- T* clone = fAlloc.makeArrayDefault<T>(count);
- memcpy(clone, array, sizeof(T) * count);
- return clone;
- }
-
- SkBitmap snapBitmap(const SkBitmap& bitmap);
-
- const int fTileCnt;
- const int fThreadCnt;
- SkTArray<SkIRect> fTileBounds;
-
- /**
- * This can either be
- * 1. fInternalExecutor.get() which means that we're managing the thread pool's life cycle.
- * 2. provided by our caller which means that our caller is managing the threads' life cycle.
- * In the 2nd case, fInternalExecutor == nullptr.
- */
- SkExecutor* fExecutor = nullptr;
- std::unique_ptr<SkExecutor> fInternalExecutor;
-
- SkSTArenaAlloc<8 << 10> fAlloc; // so we can allocate memory that lives until flush
-
- DrawQueue fQueue;
-
- friend struct SkInitOnceData; // to access DrawElement and DrawState
- friend class SkDraw; // to access DrawState
-
- typedef SkBitmapDevice INHERITED;
-};
-
-// Passed to SkDraw::drawXXX to enable threaded draw with init-once. The goal is to reuse as much
-// code as possible from SkDraw. (See SkDraw::drawPath and SkDraw::drawDevPath for an example.)
-struct SkInitOnceData {
- SkArenaAlloc* fAlloc;
- SkThreadedBMPDevice::DrawElement* fElement;
-
- void setEmptyDrawFn() {
- fElement->setDrawFn([](SkArenaAlloc* threadAlloc, const SkThreadedBMPDevice::DrawState& ds,
- const SkIRect& tileBounds){});
- }
-};
-
-#endif // SkThreadedBMPDevice_DEFINED