Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2017 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkThreadedBMPDevice.h"
      9 
     10 #include "SkPath.h"
     11 #include "SkRectPriv.h"
     12 #include "SkTaskGroup.h"
     13 #include "SkVertices.h"
     14 
     15 void SkThreadedBMPDevice::DrawQueue::reset() {
     16     if (fTasks) {
     17         fTasks->finish();
     18     }
     19 
     20     fSize = 0;
     21 
     22     // using TaskGroup2D = SkSpinningTaskGroup2D;
     23     using TaskGroup2D = SkFlexibleTaskGroup2D;
     24     auto draw2D = [this](int row, int column){
     25         SkThreadedBMPDevice::DrawElement& element = fElements[column];
     26         if (!SkIRect::Intersects(fDevice->fTileBounds[row], element.fDrawBounds)) {
     27             return;
     28         }
     29         element.fDrawFn(nullptr, element.fDS, fDevice->fTileBounds[row]);
     30     };
     31     fTasks.reset(new TaskGroup2D(draw2D, fDevice->fTileCnt, fDevice->fExecutor,
     32                                  fDevice->fThreadCnt));
     33     fTasks->start();
     34 }
     35 
     36 SkThreadedBMPDevice::SkThreadedBMPDevice(const SkBitmap& bitmap,
     37                                          int tiles,
     38                                          int threads,
     39                                          SkExecutor* executor)
     40         : INHERITED(bitmap)
     41         , fTileCnt(tiles)
     42         , fThreadCnt(threads <= 0 ? tiles : threads)
     43         , fQueue(this)
     44 {
     45     if (executor == nullptr) {
     46         fInternalExecutor = SkExecutor::MakeFIFOThreadPool(fThreadCnt);
     47         executor = fInternalExecutor.get();
     48     }
     49     fExecutor = executor;
     50 
     51     // Tiling using stripes for now; we'll explore better tiling in the future.
     52     int h = (bitmap.height() + fTileCnt - 1) / SkTMax(fTileCnt, 1);
     53     int w = bitmap.width();
     54     int top = 0;
     55     for(int tid = 0; tid < fTileCnt; ++tid, top += h) {
     56         fTileBounds.push_back(SkIRect::MakeLTRB(0, top, w, top + h));
     57     }
     58     fQueue.reset();
     59 }
     60 
     61 void SkThreadedBMPDevice::flush() {
     62     fQueue.reset();
     63 }
     64 
     65 SkThreadedBMPDevice::DrawState::DrawState(SkThreadedBMPDevice* dev) {
     66     // we need fDst to be set, and if we're actually drawing, to dirty the genID
     67     if (!dev->accessPixels(&fDst)) {
     68         // NoDrawDevice uses us (why?) so we have to catch this case w/ no pixels
     69         fDst.reset(dev->imageInfo(), nullptr, 0);
     70     }
     71     fMatrix = dev->ctm();
     72     fRC = dev->fRCStack.rc();
     73 }
     74 
     75 SkIRect SkThreadedBMPDevice::transformDrawBounds(const SkRect& drawBounds) const {
     76     if (drawBounds == SkRectPriv::MakeLargest()) {
     77         return SkRectPriv::MakeILarge();
     78     }
     79     SkRect transformedBounds;
     80     this->ctm().mapRect(&transformedBounds, drawBounds);
     81     return transformedBounds.roundOut();
     82 }
     83 
     84 SkDraw SkThreadedBMPDevice::DrawState::getDraw() const {
     85     SkDraw draw;
     86     draw.fDst = fDst;
     87     draw.fMatrix = &fMatrix;
     88     draw.fRC = &fRC;
     89     return draw;
     90 }
     91 
     92 SkThreadedBMPDevice::TileDraw::TileDraw(const DrawState& ds, const SkIRect& tileBounds)
     93         : fTileRC(ds.fRC) {
     94     fDst = ds.fDst;
     95     fMatrix = &ds.fMatrix;
     96     fTileRC.op(tileBounds, SkRegion::kIntersect_Op);
     97     fRC = &fTileRC;
     98 }
     99 
    100 static inline SkRect get_fast_bounds(const SkRect& r, const SkPaint& p) {
    101     SkRect result;
    102     if (p.canComputeFastBounds()) {
    103         result = p.computeFastBounds(r, &result);
    104     } else {
    105         result = SkRectPriv::MakeLargest();
    106     }
    107     return result;
    108 }
    109 
    110 void SkThreadedBMPDevice::drawPaint(const SkPaint& paint) {
    111     SkRect drawBounds = SkRectPriv::MakeLargest();
    112     fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
    113         TileDraw(ds, tileBounds).drawPaint(paint);
    114     });
    115 }
    116 
    117 void SkThreadedBMPDevice::drawPoints(SkCanvas::PointMode mode, size_t count,
    118         const SkPoint pts[], const SkPaint& paint) {
    119     SkRect drawBounds = SkRectPriv::MakeLargest(); // TODO tighter drawBounds
    120     fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
    121         TileDraw(ds, tileBounds).drawPoints(mode, count, pts, paint, nullptr);
    122     });
    123 }
    124 
    125 void SkThreadedBMPDevice::drawRect(const SkRect& r, const SkPaint& paint) {
    126     SkRect drawBounds = get_fast_bounds(r, paint);
    127     fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
    128         TileDraw(ds, tileBounds).drawRect(r, paint);
    129     });
    130 }
    131 
    132 void SkThreadedBMPDevice::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
    133 #ifdef SK_IGNORE_BLURRED_RRECT_OPT
    134     SkPath  path;
    135 
    136     path.addRRect(rrect);
    137     // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
    138     // required to override drawRRect.
    139     this->drawPath(path, paint, nullptr, false);
    140 #else
    141     SkRect drawBounds = get_fast_bounds(rrect.getBounds(), paint);
    142     fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
    143         TileDraw(ds, tileBounds).drawRRect(rrect, paint);
    144     });
    145 #endif
    146 }
    147 
    148 void SkThreadedBMPDevice::drawPath(const SkPath& path, const SkPaint& paint,
    149         const SkMatrix* prePathMatrix, bool pathIsMutable) {
    150     SkRect drawBounds = path.isInverseFillType() ? SkRectPriv::MakeLargest()
    151                                                  : get_fast_bounds(path.getBounds(), paint);
    152     fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds) {
    153         TileDraw(ds, tileBounds).drawPath(path, paint, prePathMatrix, false);
    154     });
    155 }
    156 
    157 void SkThreadedBMPDevice::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
    158         const SkPaint& paint) {
    159     SkMatrix matrix = SkMatrix::MakeTrans(x, y);
    160     LogDrawScaleFactor(SkMatrix::Concat(this->ctm(), matrix), paint.getFilterQuality());
    161     SkRect drawBounds = SkRect::MakeWH(bitmap.width(), bitmap.height());
    162     matrix.mapRect(&drawBounds);
    163     fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
    164         TileDraw(ds, tileBounds).drawBitmap(bitmap, matrix, nullptr, paint);
    165     });
    166 }
    167 
    168 void SkThreadedBMPDevice::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& paint) {
    169     SkRect drawBounds = SkRect::MakeXYWH(x, y, bitmap.width(), bitmap.height());
    170     fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
    171         TileDraw(ds, tileBounds).drawSprite(bitmap, x, y, paint);
    172     });
    173 }
    174 
    175 void SkThreadedBMPDevice::drawText(const void* text, size_t len, SkScalar x, SkScalar y,
    176         const SkPaint& paint) {
    177     SkRect drawBounds = SkRectPriv::MakeLargest(); // TODO tighter drawBounds
    178     fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
    179         TileDraw(ds, tileBounds).drawText((const char*)text, len, x, y, paint,
    180                                           &this->surfaceProps());
    181     });
    182 }
    183 
    184 void SkThreadedBMPDevice::drawPosText(const void* text, size_t len, const SkScalar xpos[],
    185         int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) {
    186     SkRect drawBounds = SkRectPriv::MakeLargest(); // TODO tighter drawBounds
    187     fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
    188         TileDraw(ds, tileBounds).drawPosText((const char*)text, len, xpos, scalarsPerPos, offset,
    189                                              paint, &surfaceProps());
    190     });
    191 }
    192 
    193 void SkThreadedBMPDevice::drawVertices(const SkVertices* vertices, SkBlendMode bmode,
    194         const SkPaint& paint) {
    195     SkRect drawBounds = SkRectPriv::MakeLargest(); // TODO tighter drawBounds
    196     fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
    197         TileDraw(ds, tileBounds).drawVertices(vertices->mode(), vertices->vertexCount(),
    198                                               vertices->positions(), vertices->texCoords(),
    199                                               vertices->colors(), bmode, vertices->indices(),
    200                                               vertices->indexCount(), paint);
    201     });
    202 }
    203 
    204 void SkThreadedBMPDevice::drawDevice(SkBaseDevice* device, int x, int y, const SkPaint& paint) {
    205     SkASSERT(!paint.getImageFilter());
    206     SkRect drawBounds = SkRect::MakeXYWH(x, y, device->width(), device->height());
    207     fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
    208         TileDraw(ds, tileBounds).drawSprite(static_cast<SkBitmapDevice*>(device)->fBitmap,
    209                                             x, y, paint);
    210     });
    211 }
    212