• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
reset()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 
SkThreadedBMPDevice(const SkBitmap & bitmap,int tiles,int threads,SkExecutor * executor)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 
flush()61 void SkThreadedBMPDevice::flush() {
62     fQueue.reset();
63 }
64 
DrawState(SkThreadedBMPDevice * dev)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 
transformDrawBounds(const SkRect & drawBounds) const75 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 
getDraw() const84 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 
TileDraw(const DrawState & ds,const SkIRect & tileBounds)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 
get_fast_bounds(const SkRect & r,const SkPaint & p)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 
drawPaint(const SkPaint & paint)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 
drawPoints(SkCanvas::PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)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 
drawRect(const SkRect & r,const SkPaint & paint)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 
drawRRect(const SkRRect & rrect,const SkPaint & paint)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 
drawPath(const SkPath & path,const SkPaint & paint,const SkMatrix * prePathMatrix,bool pathIsMutable)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 
drawBitmap(const SkBitmap & bitmap,SkScalar x,SkScalar y,const SkPaint & paint)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 
drawSprite(const SkBitmap & bitmap,int x,int y,const SkPaint & paint)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 
drawText(const void * text,size_t len,SkScalar x,SkScalar y,const SkPaint & paint)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 
drawPosText(const void * text,size_t len,const SkScalar xpos[],int scalarsPerPos,const SkPoint & offset,const SkPaint & paint)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 
drawVertices(const SkVertices * vertices,SkBlendMode bmode,const SkPaint & paint)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 
drawDevice(SkBaseDevice * device,int x,int y,const SkPaint & paint)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