Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(542)

Side by Side Diff: src/core/SkPicture.cpp

Issue 364823009: Port suitableForGpuRasterization to SkRecord (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Reed review complete Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 1
2 /* 2 /*
3 * Copyright 2007 The Android Open Source Project 3 * Copyright 2007 The Android Open Source Project
4 * 4 *
5 * Use of this source code is governed by a BSD-style license that can be 5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file. 6 * found in the LICENSE file.
7 */ 7 */
8 8
9 9
10 #include "SkPictureFlat.h" 10 #include "SkPictureFlat.h"
11 #include "SkPictureData.h" 11 #include "SkPictureData.h"
12 #include "SkPicturePlayback.h" 12 #include "SkPicturePlayback.h"
13 #include "SkPictureRecord.h" 13 #include "SkPictureRecord.h"
14 #include "SkPictureRecorder.h" 14 #include "SkPictureRecorder.h"
15 #include "SkPictureStateTree.h" 15 #include "SkPictureStateTree.h"
16 16
17 #include "SkBitmapDevice.h" 17 #include "SkBitmapDevice.h"
18 #include "SkCanvas.h" 18 #include "SkCanvas.h"
19 #include "SkChunkAlloc.h" 19 #include "SkChunkAlloc.h"
20 #include "SkDrawPictureCallback.h" 20 #include "SkDrawPictureCallback.h"
21 #include "SkPaintPriv.h" 21 #include "SkPaintPriv.h"
22 #include "SkPathEffect.h"
22 #include "SkPicture.h" 23 #include "SkPicture.h"
23 #include "SkRecordAnalysis.h"
24 #include "SkRegion.h" 24 #include "SkRegion.h"
25 #include "SkShader.h"
25 #include "SkStream.h" 26 #include "SkStream.h"
26 #include "SkTDArray.h" 27 #include "SkTDArray.h"
28 #include "SkTLogic.h"
27 #include "SkTSearch.h" 29 #include "SkTSearch.h"
28 #include "SkTime.h" 30 #include "SkTime.h"
29 31
30 #include "SkReader32.h" 32 #include "SkReader32.h"
31 #include "SkWriter32.h" 33 #include "SkWriter32.h"
32 #include "SkRTree.h" 34 #include "SkRTree.h"
33 #include "SkBBoxHierarchyRecord.h" 35 #include "SkBBoxHierarchyRecord.h"
34 36
35 #if SK_SUPPORT_GPU 37 #if SK_SUPPORT_GPU
36 #include "GrContext.h" 38 #include "GrContext.h"
37 #endif 39 #endif
38 40
39 #include "SkRecord.h" 41 #include "SkRecord.h"
40 #include "SkRecordDraw.h" 42 #include "SkRecordDraw.h"
41 #include "SkRecorder.h" 43 #include "SkRecorder.h"
42 44
43 template <typename T> int SafeCount(const T* obj) { 45 template <typename T> int SafeCount(const T* obj) {
44 return obj ? obj->count() : 0; 46 return obj ? obj->count() : 0;
45 } 47 }
46 48
47 /////////////////////////////////////////////////////////////////////////////// 49 ///////////////////////////////////////////////////////////////////////////////
48 50
51 namespace {
52
53 /** SkRecords visitor to determine whether an instance may require an
54 "external" bitmap to rasterize. May return false positives.
55 Does not return true for bitmap text.
56
57 Expected use is to determine whether images need to be decoded before
58 rasterizing a particular SkRecord.
59 */
60 struct BitmapTester {
61 // Helpers. These create HasMember_bitmap and HasMember_paint.
62 SK_CREATE_MEMBER_DETECTOR(bitmap);
63 SK_CREATE_MEMBER_DETECTOR(paint);
64
65 // Some commands have a paint, some have an optional paint. Either way, get back a pointer.
66 static const SkPaint* AsPtr(const SkPaint& p) { return &p; }
mtklein 2014/08/18 19:22:14 Might promote these guys out of the structs, now t
tomhudson 2014/08/18 21:37:00 Done.
67 static const SkPaint* AsPtr(const SkRecords::Optional<SkPaint>& p) { return p; }
68
69
70 // Main entry for visitor:
71 // If the command has a bitmap directly, return true.
72 // If the command has a paint and the paint has a bitmap, return true.
73 // Otherwise, return false.
74 template <typename T>
75 bool operator()(const T& r) { return CheckBitmap(r); }
76
77
78 // If the command has a bitmap, of course we're going to play back bitmaps.
79 template <typename T>
80 static SK_WHEN(HasMember_bitmap<T>, bool) CheckBitmap(const T&) { return tru e; }
81
82 // If not, look for one in its paint (if it has a paint).
83 template <typename T>
84 static SK_WHEN(!HasMember_bitmap<T>, bool) CheckBitmap(const T& r) { return CheckPaint(r); }
85
86 // If we have a paint, dig down into the effects looking for a bitmap.
87 template <typename T>
88 static SK_WHEN(HasMember_paint<T>, bool) CheckPaint(const T& r) {
89 const SkPaint* paint = AsPtr(r.paint);
90 if (paint) {
91 const SkShader* shader = paint->getShader();
92 if (shader &&
93 shader->asABitmap(NULL, NULL, NULL) == SkShader::kDefault_Bitmap Type) {
94 return true;
95 }
96 }
97 return false;
98 }
99
100 // If we don't have a paint, that non-paint has no bitmap.
101 template <typename T>
102 static SK_WHEN(!HasMember_paint<T>, bool) CheckPaint(const T&) { return fals e; }
103 };
104
105 bool WillPlaybackBitmaps(const SkRecord& record) {
106 BitmapTester tester;
107 for (unsigned i = 0; i < record.count(); i++) {
108 if (record.visit<bool>(i, tester)) {
109 return true;
110 }
111 }
112 return false;
113 }
114
115 /** SkRecords visitor to determine heuristically whether or not a SkPicture
116 will be performant when rasterized on the GPU.
117 */
118 struct PathCounter {
119 SK_CREATE_MEMBER_DETECTOR(paint);
120 SK_CREATE_TYPE_DETECTOR(DrawPoints);
121 SK_CREATE_TYPE_DETECTOR(DrawPath);
122
123 // Some commands have a paint, some have an optional paint. Either way, get back a pointer.
124 static const SkPaint* AsPtr(const SkPaint& p) { return &p; }
125 static const SkPaint* AsPtr(const SkRecords::Optional<SkPaint>& p) { return p; }
126
127 PathCounter()
128 : numPaintWithPathEffectUses (0)
129 , numFastPathDashEffects (0)
130 , numAAConcavePaths (0)
131 , numAAHairlineConcavePaths (0) {
132 }
133
134 // Must have a return type to make the SkRecord vistor templates happy.
135 template <typename T>
136 bool operator()(const T& r) {
mtklein 2014/08/18 19:22:14 void's okay too. Just use record.visit<void>(...)
mtklein 2014/08/18 19:22:14 I'd structure this a little differently: void che
tomhudson 2014/08/18 21:37:00 How about this, which gets rid of the indirection
tomhudson 2014/08/18 21:37:00 Done.
137 CheckPaint(r);
138 CheckDrawPoints(r);
139 CheckDrawPath(r);
140 return true;
141 }
142
143 template <typename T>
144 SK_WHEN(HasMember_paint<T>, void) CheckPaint(const T& r) {
145 const SkPaint* paint = AsPtr(r.paint);
146 if (paint && paint->getPathEffect()) {
147 numPaintWithPathEffectUses++;
148 }
149 }
150
151 template <typename T>
152 SK_WHEN(!HasMember_paint<T>, void) CheckPaint(const T& r) { /* do nothing */ }
153
154 template <typename T>
155 SK_WHEN(HasType_DrawPoints<T>, void) CheckDrawPoints(const T& r) {
156 const SkPathEffect* effect = r.paint.getPathEffect();
157 if (effect) {
158 SkPathEffect::DashInfo info;
159 SkPathEffect::DashType dashType = effect->asADash(&info);
160 if (2 == r.count && SkPaint::kRound_Cap != r.paint.getStrokeCap() &&
161 SkPathEffect::kDash_DashType == dashType && 2 == info.fCount) {
162 numFastPathDashEffects++;
163 }
164 }
165 }
166
167 template <typename T>
168 SK_WHEN(!HasType_DrawPoints<T>, void) CheckDrawPoints(const T& r) { /* do no thing */ }
169
170 template <typename T>
171 SK_WHEN(HasType_DrawPath<T>, void) CheckDrawPath(const T& r) {
172 if (r.paint.isAntiAlias() && !r.path.isConvex()) {
173 numAAConcavePaths++;
174
175 if (SkPaint::kStroke_Style == r.paint.getStyle() &&
176 0 == r.paint.getStrokeWidth()) {
177 numAAHairlineConcavePaths++;
178 }
179 }
180 }
181
182 template <typename T>
183 SK_WHEN(!HasType_DrawPath<T>, void) CheckDrawPath(const T& r) { /* do nothin g */ }
184
185
186 int numPaintWithPathEffectUses;
187 int numFastPathDashEffects;
188 int numAAConcavePaths;
189 int numAAHairlineConcavePaths;
190 };
191
192 bool SuitableForGpuRasterization(const SkRecord& record,
193 const char** reason = NULL,
mtklein 2014/08/18 19:22:14 Funky indent?
tomhudson 2014/08/18 21:37:00 Done.
194 int sampleCount = 0) {
195 PathCounter counter;
196 for (unsigned i = 0; i < record.count(); i++) {
197 record.visit<bool>(i, counter);
198 }
199
200 // TODO: the heuristic used here needs to be refined
201 static const int kNumPaintWithPathEffectsUsesTol = 1;
202 static const int kNumAAConcavePathsTol = 5;
203
204 int numNonDashedPathEffects = counter.numPaintWithPathEffectUses -
205 counter.numFastPathDashEffects;
206 bool suitableForDash = (0 == counter.numPaintWithPathEffectUses) ||
207 (numNonDashedPathEffects < kNumPaintWithPathEffectsUs esTol
208 && 0 == sampleCount);
209
210 bool ret = suitableForDash &&
211 (counter.numAAConcavePaths - counter.numAAHairlineConcavePaths)
212 < kNumAAConcavePathsTol;
213
214 if (!ret && NULL != reason) {
215 if (!suitableForDash) {
216 if (0 != sampleCount) {
217 *reason = "Can't use multisample on dash effect.";
218 } else {
219 *reason = "Too many non dashed path effects.";
220 }
221 } else if ((counter.numAAConcavePaths - counter.numAAHairlineConcavePath s)
222 >= kNumAAConcavePathsTol)
223 *reason = "Too many anti-aliased concave paths.";
224 else
225 *reason = "Unknown reason for GPU unsuitability.";
226 }
227 return ret;
228 }
229
230 } // namespace
231
232 SkPicture::Analysis::Analysis(const SkRecord& record)
233 : fWillPlaybackBitmaps (WillPlaybackBitmaps(record))
234 , fSuitableForGpuRasterization (SuitableForGpuRasterization(record)) { }
235
236 ///////////////////////////////////////////////////////////////////////////////
237
49 #ifdef SK_SUPPORT_LEGACY_DEFAULT_PICTURE_CTOR 238 #ifdef SK_SUPPORT_LEGACY_DEFAULT_PICTURE_CTOR
50 // fRecord OK 239 // fRecord OK
51 SkPicture::SkPicture() 240 SkPicture::SkPicture()
52 : fWidth(0) 241 : fWidth(0)
53 , fHeight(0) 242 , fHeight(0) {
54 , fRecordWillPlayBackBitmaps(false) {
55 this->needsNewGenID(); 243 this->needsNewGenID();
56 } 244 }
57 #endif 245 #endif
58 246
59 // fRecord OK 247 // fRecord OK
60 SkPicture::SkPicture(int width, int height, 248 SkPicture::SkPicture(int width, int height,
61 const SkPictureRecord& record, 249 const SkPictureRecord& record,
62 bool deepCopyOps) 250 bool deepCopyOps)
63 : fWidth(width) 251 : fWidth(width)
64 , fHeight(height) 252 , fHeight(height) {
65 , fRecordWillPlayBackBitmaps(false) {
66 this->needsNewGenID(); 253 this->needsNewGenID();
67 254
68 SkPictInfo info; 255 SkPictInfo info;
69 this->createHeader(&info); 256 this->createHeader(&info);
70 fData.reset(SkNEW_ARGS(SkPictureData, (record, info, deepCopyOps))); 257 fData.reset(SkNEW_ARGS(SkPictureData, (record, info, deepCopyOps)));
71 } 258 }
72 259
73 // Create an SkPictureData-backed SkPicture from an SkRecord. 260 // Create an SkPictureData-backed SkPicture from an SkRecord.
74 // This for compatibility with serialization code only. This is not cheap. 261 // This for compatibility with serialization code only. This is not cheap.
75 static SkPicture* backport(const SkRecord& src, int width, int height) { 262 static SkPicture* backport(const SkRecord& src, int width, int height) {
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
130 } 317 }
131 SkASSERT(SafeCount(fData->fBitmapHeap.get()) == heapSize); 318 SkASSERT(SafeCount(fData->fBitmapHeap.get()) == heapSize);
132 319
133 // needed to create typeface playback 320 // needed to create typeface playback
134 copyInfo.controller.setupPlaybacks(); 321 copyInfo.controller.setupPlaybacks();
135 322
136 newData.reset(SkNEW_ARGS(SkPictureData, (*fData, &copyInfo))); 323 newData.reset(SkNEW_ARGS(SkPictureData, (*fData, &copyInfo)));
137 } 324 }
138 325
139 SkPicture* clone = SkNEW_ARGS(SkPicture, (newData.detach(), fWidth, fHeight) ); 326 SkPicture* clone = SkNEW_ARGS(SkPicture, (newData.detach(), fWidth, fHeight) );
140 clone->fRecordWillPlayBackBitmaps = fRecordWillPlayBackBitmaps;
141 clone->fUniqueID = this->uniqueID(); // need to call method to ensure != 0 327 clone->fUniqueID = this->uniqueID(); // need to call method to ensure != 0
142 328
143 return clone; 329 return clone;
144 #endif 330 #endif
145 } 331 }
146 #endif//SK_SUPPORT_LEGACY_PICTURE_CLONE 332 #endif//SK_SUPPORT_LEGACY_PICTURE_CLONE
147 333
148 // fRecord OK 334 // fRecord OK
149 void SkPicture::EXPERIMENTAL_addAccelData(const SkPicture::AccelData* data) cons t { 335 void SkPicture::EXPERIMENTAL_addAccelData(const SkPicture::AccelData* data) cons t {
150 fAccelData.reset(SkRef(data)); 336 fAccelData.reset(SkRef(data));
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
257 if (pInfo != NULL) { 443 if (pInfo != NULL) {
258 *pInfo = info; 444 *pInfo = info;
259 } 445 }
260 return true; 446 return true;
261 } 447 }
262 448
263 // fRecord OK 449 // fRecord OK
264 SkPicture::SkPicture(SkPictureData* data, int width, int height) 450 SkPicture::SkPicture(SkPictureData* data, int width, int height)
265 : fData(data) 451 : fData(data)
266 , fWidth(width) 452 , fWidth(width)
267 , fHeight(height) 453 , fHeight(height) {
268 , fRecordWillPlayBackBitmaps(false) {
269 this->needsNewGenID(); 454 this->needsNewGenID();
270 } 455 }
271 456
272 // fRecord OK 457 // fRecord OK
273 SkPicture* SkPicture::CreateFromStream(SkStream* stream, InstallPixelRefProc pro c) { 458 SkPicture* SkPicture::CreateFromStream(SkStream* stream, InstallPixelRefProc pro c) {
274 SkPictInfo info; 459 SkPictInfo info;
275 460
276 if (!InternalOnly_StreamIsSKP(stream, &info)) { 461 if (!InternalOnly_StreamIsSKP(stream, &info)) {
277 return NULL; 462 return NULL;
278 } 463 }
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
373 558
374 if (NULL != data) { 559 if (NULL != data) {
375 buffer.writeBool(true); 560 buffer.writeBool(true);
376 data->flatten(buffer); 561 data->flatten(buffer);
377 } else { 562 } else {
378 buffer.writeBool(false); 563 buffer.writeBool(false);
379 } 564 }
380 } 565 }
381 566
382 #if SK_SUPPORT_GPU 567 #if SK_SUPPORT_GPU
383 // fRecord TODO 568 // fRecord OK
384 bool SkPicture::suitableForGpuRasterization(GrContext* context, const char **rea son) const { 569 bool SkPicture::suitableForGpuRasterization(GrContext* context, const char **rea son) const {
570 if (fRecord.get()) {
571 return fAnalysis.fSuitableForGpuRasterization;
572 }
385 if (NULL == fData.get()) { 573 if (NULL == fData.get()) {
386 if (NULL != reason) { 574 if (NULL != reason) {
387 *reason = "Missing internal data."; 575 *reason = "Missing internal data.";
388 } 576 }
389 return false; 577 return false;
390 } 578 }
391 579
392 return fData->suitableForGpuRasterization(context, reason); 580 return fData->suitableForGpuRasterization(context, reason);
393 } 581 }
394 #endif 582 #endif
395 583
396 // fRecord OK 584 // fRecord OK
397 bool SkPicture::willPlayBackBitmaps() const { 585 bool SkPicture::willPlayBackBitmaps() const {
398 if (fRecord.get()) { 586 if (fRecord.get()) {
399 return fRecordWillPlayBackBitmaps; 587 return fAnalysis.fWillPlaybackBitmaps;
400 } 588 }
401 if (!fData.get()) { 589 if (!fData.get()) {
402 return false; 590 return false;
403 } 591 }
404 return fData->containsBitmaps(); 592 return fData->containsBitmaps();
405 } 593 }
406 594
407 // fRecord OK 595 // fRecord OK
408 static int32_t next_picture_generation_id() { 596 static int32_t next_picture_generation_id() {
409 static int32_t gPictureGenerationID = 0; 597 static int32_t gPictureGenerationID = 0;
(...skipping 13 matching lines...) Expand all
423 } 611 }
424 return fUniqueID; 612 return fUniqueID;
425 } 613 }
426 614
427 // fRecord OK 615 // fRecord OK
428 SkPicture::SkPicture(int width, int height, SkRecord* record, SkBBoxHierarchy* b bh) 616 SkPicture::SkPicture(int width, int height, SkRecord* record, SkBBoxHierarchy* b bh)
429 : fWidth(width) 617 : fWidth(width)
430 , fHeight(height) 618 , fHeight(height)
431 , fRecord(record) 619 , fRecord(record)
432 , fBBH(SkSafeRef(bbh)) 620 , fBBH(SkSafeRef(bbh))
433 , fRecordWillPlayBackBitmaps(SkRecordWillPlaybackBitmaps(*record)) { 621 , fAnalysis(*record) {
434 // TODO: delay as much of this work until just before first playback? 622 // TODO: delay as much of this work until just before first playback?
435 if (fBBH.get()) { 623 if (fBBH.get()) {
436 SkRecordFillBounds(*record, fBBH.get()); 624 SkRecordFillBounds(*record, fBBH.get());
437 } 625 }
438 this->needsNewGenID(); 626 this->needsNewGenID();
439 } 627 }
440 628
441 // Note that we are assuming that this entry point will only be called from 629 // Note that we are assuming that this entry point will only be called from
442 // one thread. Currently the only client of this method is 630 // one thread. Currently the only client of this method is
443 // SkGpuDevice::EXPERIMENTAL_optimize which should be only called from a single 631 // SkGpuDevice::EXPERIMENTAL_optimize which should be only called from a single
444 // thread. 632 // thread.
445 void SkPicture::addDeletionListener(DeletionListener* listener) const { 633 void SkPicture::addDeletionListener(DeletionListener* listener) const {
446 SkASSERT(NULL != listener); 634 SkASSERT(NULL != listener);
447 635
448 *fDeletionListeners.append() = SkRef(listener); 636 *fDeletionListeners.append() = SkRef(listener);
449 } 637 }
450 638
451 void SkPicture::callDeletionListeners() { 639 void SkPicture::callDeletionListeners() {
452 for (int i = 0; i < fDeletionListeners.count(); ++i) { 640 for (int i = 0; i < fDeletionListeners.count(); ++i) {
453 fDeletionListeners[i]->onDeletion(this->uniqueID()); 641 fDeletionListeners[i]->onDeletion(this->uniqueID());
454 } 642 }
455 643
456 fDeletionListeners.unrefAll(); 644 fDeletionListeners.unrefAll();
457 } 645 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698