/* * 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 "SkTaskGroup.h" #include "SkDraw.h" #include "SkBitmapDevice.h" class TiledDrawScheduler { public: using WorkFunc = std::function; virtual ~TiledDrawScheduler() {} virtual void signal() = 0; // signal that one more draw is available for all tiles // Tell scheduler that no more draw calls will be added (no signal will be called). virtual void finish() = 0; // Handle the next draw available. This method will block until // (1) the next draw is finished, or // (2) the finish is called // The method will return true for case (1) and false for case (2). // When there's no draw available and we haven't called finish, we will just wait. // In many cases, the parameter tileIndex specifies the tile that the next draw should happen. // However, for some schedulers, that tileIndex may only be a hint and the scheduler is free // to find another tile to draw. In that case, tileIndex will be changed to the actual tileIndex // where the draw happens. virtual bool next(int& tileIndex) = 0; }; /////////////////////////////////////////////////////////////////////////////// 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 { finishThreads(); } 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 DrawElement { SkIRect fDrawBounds; std::function fDrawFn; }; struct DrawState; SkIRect transformDrawBounds(const SkRect& drawBounds) const; void startThreads(); void finishThreads(); static constexpr int MAX_QUEUE_SIZE = 100000; const int fTileCnt; const int fThreadCnt; std::unique_ptr fScheduler; 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; std::unique_ptr fTaskGroup; // generated from fExecutor DrawElement fQueue[MAX_QUEUE_SIZE]; int fQueueSize; typedef SkBitmapDevice INHERITED; }; #endif // SkThreadedBMPDevice_DEFINED