Line data Source code
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 "SkTaskGroup.h"
12 : #include "SkVertices.h"
13 :
14 0 : SkThreadedBMPDevice::SkThreadedBMPDevice(const SkBitmap& bitmap, int threads)
15 : : INHERITED(bitmap)
16 0 : , fThreadCnt(threads)
17 : {
18 : // Tiling using stripes for now; we'll explore better tiling in the future.
19 0 : int h = (bitmap.height() + fThreadCnt - 1) / SkTMax(fThreadCnt, 1);
20 0 : int w = bitmap.width();
21 0 : int top = 0;
22 0 : for(int tid = 0; tid < fThreadCnt; ++tid, top += h) {
23 0 : fThreadBounds.push_back(SkIRect::MakeLTRB(0, top, w, top + h));
24 : }
25 0 : }
26 :
27 0 : void SkThreadedBMPDevice::flush() {
28 0 : SkTaskGroup().batch(fThreadCnt, [this](int i) {
29 0 : for(auto& element : fQueue) {
30 0 : if (SkIRect::Intersects(fThreadBounds[i], element.fDrawBounds)) {
31 0 : element.fDrawFn(fThreadBounds[i]);
32 : }
33 : }
34 0 : });
35 0 : fQueue.reset();
36 0 : }
37 :
38 : // Having this captured in lambda seems to be faster than saving this in DrawElement
39 0 : struct SkThreadedBMPDevice::DrawState {
40 : SkPixmap fDst;
41 : SkMatrix fMatrix;
42 : SkRasterClip fRC;
43 :
44 0 : explicit DrawState(SkThreadedBMPDevice* dev) {
45 : // we need fDst to be set, and if we're actually drawing, to dirty the genID
46 0 : if (!dev->accessPixels(&fDst)) {
47 : // NoDrawDevice uses us (why?) so we have to catch this case w/ no pixels
48 0 : fDst.reset(dev->imageInfo(), nullptr, 0);
49 : }
50 0 : fMatrix = dev->ctm();
51 0 : fRC = dev->fRCStack.rc();
52 0 : }
53 :
54 0 : SkDraw getThreadDraw(SkRasterClip& threadRC, const SkIRect& threadBounds) const {
55 0 : SkDraw draw;
56 0 : draw.fDst = fDst;
57 0 : draw.fMatrix = &fMatrix;
58 0 : threadRC = fRC;
59 0 : threadRC.op(threadBounds, SkRegion::kIntersect_Op);
60 0 : draw.fRC = &threadRC;
61 0 : return draw;
62 : }
63 : };
64 :
65 0 : SkIRect SkThreadedBMPDevice::transformDrawBounds(const SkRect& drawBounds) const {
66 0 : if (drawBounds.isLargest()) {
67 0 : return SkIRect::MakeLargest();
68 : }
69 : SkRect transformedBounds;
70 0 : this->ctm().mapRect(&transformedBounds, drawBounds);
71 0 : return transformedBounds.roundOut();
72 : }
73 :
74 : // The do {...} while (false) is to enforce trailing semicolon as suggested by mtklein@
75 : #define THREADED_DRAW(drawBounds, actualDrawCall) \
76 : do { \
77 : DrawState ds(this); \
78 : fQueue.push_back({ \
79 : this->transformDrawBounds(drawBounds), \
80 : [=](const SkIRect& threadBounds) { \
81 : SkRasterClip threadRC; \
82 : SkDraw draw = ds.getThreadDraw(threadRC, threadBounds); \
83 : draw.actualDrawCall; \
84 : }, \
85 : }); \
86 : } while (false)
87 :
88 0 : static inline SkRect get_fast_bounds(const SkRect& r, const SkPaint& p) {
89 : SkRect result;
90 0 : if (p.canComputeFastBounds()) {
91 0 : result = p.computeFastBounds(r, &result);
92 : } else {
93 0 : result = SkRect::MakeLargest();
94 : }
95 0 : return result;
96 : }
97 :
98 0 : void SkThreadedBMPDevice::drawPaint(const SkPaint& paint) {
99 0 : THREADED_DRAW(SkRect::MakeLargest(), drawPaint(paint));
100 0 : }
101 :
102 0 : void SkThreadedBMPDevice::drawPoints(SkCanvas::PointMode mode, size_t count,
103 : const SkPoint pts[], const SkPaint& paint) {
104 : // TODO tighter drawBounds
105 0 : SkRect drawBounds = SkRect::MakeLargest();
106 0 : THREADED_DRAW(drawBounds, drawPoints(mode, count, pts, paint, nullptr));
107 0 : }
108 :
109 0 : void SkThreadedBMPDevice::drawRect(const SkRect& r, const SkPaint& paint) {
110 0 : SkRect drawBounds = get_fast_bounds(r, paint);
111 0 : THREADED_DRAW(drawBounds, drawRect(r, paint));
112 0 : }
113 :
114 0 : void SkThreadedBMPDevice::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
115 : #ifdef SK_IGNORE_BLURRED_RRECT_OPT
116 : SkPath path;
117 :
118 : path.addRRect(rrect);
119 : // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
120 : // required to override drawRRect.
121 : this->drawPath(path, paint, nullptr, false);
122 : #else
123 0 : SkRect drawBounds = get_fast_bounds(rrect.getBounds(), paint);
124 0 : THREADED_DRAW(drawBounds, drawRRect(rrect, paint));
125 : #endif
126 0 : }
127 :
128 0 : void SkThreadedBMPDevice::drawPath(const SkPath& path, const SkPaint& paint,
129 : const SkMatrix* prePathMatrix, bool pathIsMutable) {
130 0 : SkRect drawBounds = path.isInverseFillType() ? SkRect::MakeLargest()
131 0 : : get_fast_bounds(path.getBounds(), paint);
132 : // For thread safety, make path imutable
133 0 : THREADED_DRAW(drawBounds, drawPath(path, paint, prePathMatrix, false));
134 0 : }
135 :
136 0 : void SkThreadedBMPDevice::drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix,
137 : const SkPaint& paint) {
138 0 : LogDrawScaleFactor(SkMatrix::Concat(this->ctm(), matrix), paint.getFilterQuality());
139 0 : SkRect drawBounds = SkRect::MakeWH(bitmap.width(), bitmap.height());
140 0 : matrix.mapRect(&drawBounds);
141 0 : THREADED_DRAW(drawBounds, drawBitmap(bitmap, matrix, nullptr, paint));
142 0 : }
143 :
144 0 : void SkThreadedBMPDevice::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& paint) {
145 0 : SkRect drawBounds = SkRect::MakeXYWH(x, y, bitmap.width(), bitmap.height());
146 0 : THREADED_DRAW(drawBounds, drawSprite(bitmap, x, y, paint));
147 0 : }
148 :
149 0 : void SkThreadedBMPDevice::drawText(const void* text, size_t len, SkScalar x, SkScalar y,
150 : const SkPaint& paint) {
151 0 : SkRect drawBounds = SkRect::MakeLargest(); // TODO tighter drawBounds
152 0 : THREADED_DRAW(drawBounds, drawText((const char*)text, len, x, y, paint, &this->surfaceProps()));
153 0 : }
154 :
155 0 : void SkThreadedBMPDevice::drawPosText(const void* text, size_t len, const SkScalar xpos[],
156 : int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) {
157 0 : SkRect drawBounds = SkRect::MakeLargest(); // TODO tighter drawBounds
158 0 : THREADED_DRAW(drawBounds, drawPosText((const char*)text, len, xpos, scalarsPerPos, offset,
159 : paint, &surfaceProps()));
160 0 : }
161 :
162 0 : void SkThreadedBMPDevice::drawVertices(const SkVertices* vertices, SkBlendMode bmode,
163 : const SkPaint& paint) {
164 0 : SkRect drawBounds = SkRect::MakeLargest(); // TODO tighter drawBounds
165 0 : THREADED_DRAW(drawBounds, drawVertices(vertices->mode(), vertices->vertexCount(),
166 : vertices->positions(), vertices->texCoords(),
167 : vertices->colors(), bmode, vertices->indices(),
168 : vertices->indexCount(), paint));
169 0 : }
170 :
171 0 : void SkThreadedBMPDevice::drawDevice(SkBaseDevice* device, int x, int y, const SkPaint& paint) {
172 0 : SkASSERT(!paint.getImageFilter());
173 0 : SkRect drawBounds = SkRect::MakeXYWH(x, y, device->width(), device->height());
174 0 : THREADED_DRAW(drawBounds,
175 : drawSprite(static_cast<SkBitmapDevice*>(device)->fBitmap, x, y, paint));
176 0 : }
|