/* * 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 "SkTaskGroup2D.h" 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 drawBitmap(const SkBitmap&, SkScalar x, SkScalar y, 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 DrawState; struct DrawElement { SkIRect fDrawBounds; std::function fDrawFn; }; class DrawQueue { 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(); } SK_ALWAYS_INLINE void push(DrawElement&& element) { if (fSize == MAX_QUEUE_SIZE) { this->reset(); } SkASSERT(fSize < MAX_QUEUE_SIZE); fElements[fSize++] = std::move(element); fTasks->addColumn(); } private: SkThreadedBMPDevice* fDevice; std::unique_ptr fTasks; DrawElement fElements[MAX_QUEUE_SIZE]; int fSize; }; SkIRect transformDrawBounds(const SkRect& drawBounds) const; const int fTileCnt; const int fThreadCnt; SkTArray 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 fInternalExecutor; DrawQueue fQueue; typedef SkBitmapDevice INHERITED; }; #endif // SkThreadedBMPDevice_DEFINED