diff options
author | 2017-08-28 16:29:46 -0400 | |
---|---|---|
committer | 2017-08-30 19:39:27 +0000 | |
commit | 604a71a5e08ed33b9c983113852e63120f8616ef (patch) | |
tree | cd51e485129f05d7b87103481f84248db5d7e2c8 | |
parent | 195c05b6d5afbd65f803816938e24eebd51292c8 (diff) |
Allow providing SkExecutor to SkThreadedBMPDevice
So that callers could manage the thread pool themselves instead of
relying on SkThreadBMPDevice.
Bug: skia:
Change-Id: Idbeafc9ac5d111370fd1b74f6eab9ac8df179940
Reviewed-on: https://skia-review.googlesource.com/39760
Reviewed-by: Mike Klein <mtklein@google.com>
Commit-Queue: Yuqian Li <liyuqian@google.com>
-rw-r--r-- | src/core/SkThreadedBMPDevice.cpp | 35 | ||||
-rw-r--r-- | src/core/SkThreadedBMPDevice.h | 23 |
2 files changed, 41 insertions, 17 deletions
diff --git a/src/core/SkThreadedBMPDevice.cpp b/src/core/SkThreadedBMPDevice.cpp index ac004b1a76..9b6be1cfba 100644 --- a/src/core/SkThreadedBMPDevice.cpp +++ b/src/core/SkThreadedBMPDevice.cpp @@ -176,7 +176,6 @@ private: }; void SkThreadedBMPDevice::startThreads() { - SkASSERT(fThreadFutures.count() == 0); SkASSERT(fQueueSize == 0); TiledDrawScheduler::WorkFunc work = [this](int tileIndex, int drawIndex){ @@ -190,29 +189,40 @@ void SkThreadedBMPDevice::startThreads() { // using Scheduler = TiledDrawSchedulerBySpinning; using Scheduler = TiledDrawSchedulerFlexible; fScheduler.reset(new Scheduler(fTileCnt, work)); - for(int i = 0; i < fThreadCnt; ++i) { - fThreadFutures.push_back(std::async(std::launch::async, [this, i]() { - int tileIndex = i; - while (fScheduler->next(tileIndex)) {} - })); - } + + // We intentionally call the int parameter tileIndex although it ranges from 0 to fThreadCnt-1. + // For some schedulers (e.g., TiledDrawSchedulerBySemaphores and TiledDrawSchedulerBySpinning), + // fThreadCnt should be equal to fTileCnt so it doesn't make a difference. + // + // For TiledDrawSchedulerFlexible, the input tileIndex provides only a hint about which tile + // the current thread should draw; the scheduler may later modify that tileIndex to draw on + // another tile. + fTaskGroup->batch(fThreadCnt, [this](int tileIndex){ + while (fScheduler->next(tileIndex)) {} + }); } void SkThreadedBMPDevice::finishThreads() { fScheduler->finish(); - for(auto& future : fThreadFutures) { - future.wait(); - } - fThreadFutures.reset(); + fTaskGroup->wait(); fQueueSize = 0; fScheduler.reset(nullptr); } -SkThreadedBMPDevice::SkThreadedBMPDevice(const SkBitmap& bitmap, int tiles, int threads) +SkThreadedBMPDevice::SkThreadedBMPDevice(const SkBitmap& bitmap, + int tiles, + int threads, + SkExecutor* executor) : INHERITED(bitmap) , fTileCnt(tiles) , fThreadCnt(threads <= 0 ? tiles : threads) { + if (executor == nullptr) { + fInternalExecutor = SkExecutor::MakeThreadPool(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(); @@ -221,6 +231,7 @@ SkThreadedBMPDevice::SkThreadedBMPDevice(const SkBitmap& bitmap, int tiles, int fTileBounds.push_back(SkIRect::MakeLTRB(0, top, w, top + h)); } fQueueSize = 0; + fTaskGroup.reset(new SkTaskGroup(*fExecutor)); startThreads(); } diff --git a/src/core/SkThreadedBMPDevice.h b/src/core/SkThreadedBMPDevice.h index d7f3d6b3b7..aa2276bd27 100644 --- a/src/core/SkThreadedBMPDevice.h +++ b/src/core/SkThreadedBMPDevice.h @@ -8,11 +8,10 @@ #ifndef SkThreadedBMPDevice_DEFINED #define SkThreadedBMPDevice_DEFINED +#include "SkTaskGroup.h" #include "SkDraw.h" #include "SkBitmapDevice.h" -#include <future> - class TiledDrawScheduler { public: using WorkFunc = std::function<void(int, int)>; @@ -39,8 +38,11 @@ public: /////////////////////////////////////////////////////////////////////////////// class SkThreadedBMPDevice : public SkBitmapDevice { public: - // When threads = 0, we make fThreadCnt = fTileCnt - SkThreadedBMPDevice(const SkBitmap& bitmap, int tiles, int threads = 0); + // 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 { finishThreads(); } protected: @@ -83,7 +85,18 @@ private: const int fThreadCnt; std::unique_ptr<TiledDrawScheduler> fScheduler; SkTArray<SkIRect> fTileBounds; - SkTArray<std::future<void>> fThreadFutures; + + /** + * 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; + + std::unique_ptr<SkTaskGroup> fTaskGroup; // generated from fExecutor + DrawElement fQueue[MAX_QUEUE_SIZE]; int fQueueSize; |