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