• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2007 The Android Open Source Project
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 
9 #include "SkPictureFlat.h"
10 #include "SkPictureData.h"
11 #include "SkPicturePlayback.h"
12 #include "SkPictureRecord.h"
13 #include "SkPictureRecorder.h"
14 
15 #include "SkAtomics.h"
16 #include "SkBitmapDevice.h"
17 #include "SkCanvas.h"
18 #include "SkChunkAlloc.h"
19 #include "SkMessageBus.h"
20 #include "SkPaintPriv.h"
21 #include "SkPathEffect.h"
22 #include "SkPicture.h"
23 #include "SkRegion.h"
24 #include "SkShader.h"
25 #include "SkStream.h"
26 #include "SkTDArray.h"
27 #include "SkTLogic.h"
28 #include "SkTSearch.h"
29 #include "SkTime.h"
30 
31 #include "SkReader32.h"
32 #include "SkWriter32.h"
33 #include "SkRTree.h"
34 
35 #if SK_SUPPORT_GPU
36 #include "GrContext.h"
37 #endif
38 
39 #include "SkRecord.h"
40 #include "SkRecordDraw.h"
41 #include "SkRecordOpts.h"
42 #include "SkRecorder.h"
43 
44 DECLARE_SKMESSAGEBUS_MESSAGE(SkPicture::DeletionMessage);
45 
SafeCount(const T * obj)46 template <typename T> int SafeCount(const T* obj) {
47     return obj ? obj->count() : 0;
48 }
49 
50 ///////////////////////////////////////////////////////////////////////////////
51 
52 namespace {
53 
54 // Some commands have a paint, some have an optional paint.  Either way, get back a pointer.
AsPtr(const SkPaint & p)55 static const SkPaint* AsPtr(const SkPaint& p) { return &p; }
AsPtr(const SkRecords::Optional<SkPaint> & p)56 static const SkPaint* AsPtr(const SkRecords::Optional<SkPaint>& p) { return p; }
57 
58 /** SkRecords visitor to determine whether an instance may require an
59     "external" bitmap to rasterize. May return false positives.
60     Does not return true for bitmap text.
61 
62     Expected use is to determine whether images need to be decoded before
63     rasterizing a particular SkRecord.
64  */
65 struct BitmapTester {
66     // Helpers.  These create HasMember_bitmap and HasMember_paint.
67     SK_CREATE_MEMBER_DETECTOR(bitmap);
68     SK_CREATE_MEMBER_DETECTOR(paint);
69 
70 
71     // Main entry for visitor:
72     // If the command is a DrawPicture, recurse.
73     // If the command has a bitmap directly, return true.
74     // If the command has a paint and the paint has a bitmap, return true.
75     // Otherwise, return false.
operator ()__anon01569c020111::BitmapTester76     bool operator()(const SkRecords::DrawPicture& op) { return op.picture->willPlayBackBitmaps(); }
77 
78     template <typename T>
operator ()__anon01569c020111::BitmapTester79     bool operator()(const T& r) { return CheckBitmap(r); }
80 
81 
82     // If the command has a bitmap, of course we're going to play back bitmaps.
83     template <typename T>
SK_WHEN__anon01569c020111::BitmapTester84     static SK_WHEN(HasMember_bitmap<T>, bool) CheckBitmap(const T&) { return true; }
85 
86     // If not, look for one in its paint (if it has a paint).
87     template <typename T>
CheckBitmap__anon01569c020111::BitmapTester88     static SK_WHEN(!HasMember_bitmap<T>, bool) CheckBitmap(const T& r) { return CheckPaint(r); }
89 
90     // If we have a paint, dig down into the effects looking for a bitmap.
91     template <typename T>
SK_WHEN__anon01569c020111::BitmapTester92     static SK_WHEN(HasMember_paint<T>, bool) CheckPaint(const T& r) {
93         const SkPaint* paint = AsPtr(r.paint);
94         if (paint) {
95             const SkShader* shader = paint->getShader();
96             if (shader &&
97                 shader->asABitmap(NULL, NULL, NULL) == SkShader::kDefault_BitmapType) {
98                 return true;
99             }
100         }
101         return false;
102     }
103 
104     // If we don't have a paint, that non-paint has no bitmap.
105     template <typename T>
CheckPaint__anon01569c020111::BitmapTester106     static SK_WHEN(!HasMember_paint<T>, bool) CheckPaint(const T&) { return false; }
107 };
108 
WillPlaybackBitmaps(const SkRecord & record)109 bool WillPlaybackBitmaps(const SkRecord& record) {
110     BitmapTester tester;
111     for (unsigned i = 0; i < record.count(); i++) {
112         if (record.visit<bool>(i, tester)) {
113             return true;
114         }
115     }
116     return false;
117 }
118 
119 // SkRecord visitor to find recorded text.
120 struct TextHunter {
121     // All ops with text have that text as a char array member named "text".
122     SK_CREATE_MEMBER_DETECTOR(text);
operator ()__anon01569c020111::TextHunter123     bool operator()(const SkRecords::DrawPicture& op) { return op.picture->hasText(); }
SK_WHEN__anon01569c020111::TextHunter124     template <typename T> SK_WHEN(HasMember_text<T>,  bool) operator()(const T&) { return true;  }
operator ()__anon01569c020111::TextHunter125     template <typename T> SK_WHEN(!HasMember_text<T>, bool) operator()(const T&) { return false; }
126 };
127 
128 } // namespace
129 
130 /** SkRecords visitor to determine heuristically whether or not a SkPicture
131     will be performant when rasterized on the GPU.
132  */
133 struct SkPicture::PathCounter {
134     SK_CREATE_MEMBER_DETECTOR(paint);
135 
PathCounterSkPicture::PathCounter136     PathCounter() : fNumSlowPathsAndDashEffects(0) {}
137 
138     // Recurse into nested pictures.
operator ()SkPicture::PathCounter139     void operator()(const SkRecords::DrawPicture& op) {
140         const SkPicture::Analysis& analysis = op.picture->analysis();
141         fNumSlowPathsAndDashEffects += analysis.fNumSlowPathsAndDashEffects;
142     }
143 
checkPaintSkPicture::PathCounter144     void checkPaint(const SkPaint* paint) {
145         if (paint && paint->getPathEffect()) {
146             // Initially assume it's slow.
147             fNumSlowPathsAndDashEffects++;
148         }
149     }
150 
operator ()SkPicture::PathCounter151     void operator()(const SkRecords::DrawPoints& op) {
152         this->checkPaint(&op.paint);
153         const SkPathEffect* effect = op.paint.getPathEffect();
154         if (effect) {
155             SkPathEffect::DashInfo info;
156             SkPathEffect::DashType dashType = effect->asADash(&info);
157             if (2 == op.count && SkPaint::kRound_Cap != op.paint.getStrokeCap() &&
158                 SkPathEffect::kDash_DashType == dashType && 2 == info.fCount) {
159                 fNumSlowPathsAndDashEffects--;
160             }
161         }
162     }
163 
operator ()SkPicture::PathCounter164     void operator()(const SkRecords::DrawPath& op) {
165         this->checkPaint(&op.paint);
166         if (op.paint.isAntiAlias() && !op.path.isConvex()) {
167             SkPaint::Style paintStyle = op.paint.getStyle();
168             const SkRect& pathBounds = op.path.getBounds();
169             if (SkPaint::kStroke_Style == paintStyle &&
170                 0 == op.paint.getStrokeWidth()) {
171                 // AA hairline concave path is not slow.
172             } else if (SkPaint::kFill_Style == paintStyle && pathBounds.width() < 64.f &&
173                        pathBounds.height() < 64.f && !op.path.isVolatile()) {
174                 // AADF eligible concave path is not slow.
175             } else {
176                 fNumSlowPathsAndDashEffects++;
177             }
178         }
179     }
180 
181     template <typename T>
SK_WHENSkPicture::PathCounter182     SK_WHEN(HasMember_paint<T>, void) operator()(const T& op) {
183         this->checkPaint(AsPtr(op.paint));
184     }
185 
186     template <typename T>
operator ()SkPicture::PathCounter187     SK_WHEN(!HasMember_paint<T>, void) operator()(const T& op) { /* do nothing */ }
188 
189     int fNumSlowPathsAndDashEffects;
190 };
191 
Analysis(const SkRecord & record)192 SkPicture::Analysis::Analysis(const SkRecord& record) {
193     fWillPlaybackBitmaps = WillPlaybackBitmaps(record);
194 
195     PathCounter counter;
196     for (unsigned i = 0; i < record.count(); i++) {
197         record.visit<void>(i, counter);
198     }
199     fNumSlowPathsAndDashEffects = SkTMin<int>(counter.fNumSlowPathsAndDashEffects, 255);
200 
201     fHasText = false;
202     TextHunter text;
203     for (unsigned i = 0; i < record.count(); i++) {
204         if (record.visit<bool>(i, text)) {
205             fHasText = true;
206             break;
207         }
208     }
209 }
210 
suitableForGpuRasterization(const char ** reason,int sampleCount) const211 bool SkPicture::Analysis::suitableForGpuRasterization(const char** reason,
212                                                       int sampleCount) const {
213     // TODO: the heuristic used here needs to be refined
214     static const int kNumSlowPathsTol = 6;
215 
216     bool ret = fNumSlowPathsAndDashEffects < kNumSlowPathsTol;
217 
218     if (!ret && reason) {
219         *reason = "Too many slow paths (either concave or dashed).";
220     }
221     return ret;
222 }
223 
224 ///////////////////////////////////////////////////////////////////////////////
225 
drawableCount() const226 int SkPicture::drawableCount() const {
227     return fDrawablePicts.get() ? fDrawablePicts->count() : 0;
228 }
229 
drawablePicts() const230 SkPicture const* const* SkPicture::drawablePicts() const {
231     return fDrawablePicts.get() ? fDrawablePicts->begin() : NULL;
232 }
233 
~SkPicture()234 SkPicture::~SkPicture() {
235     // If the ID is still zero, no one has read it, so no need to send this message.
236     uint32_t id = sk_atomic_load(&fUniqueID, sk_memory_order_relaxed);
237     if (id != 0) {
238         SkPicture::DeletionMessage msg;
239         msg.fUniqueID = id;
240         SkMessageBus<SkPicture::DeletionMessage>::Post(msg);
241     }
242 }
243 
EXPERIMENTAL_getAccelData(SkPicture::AccelData::Key key) const244 const SkPicture::AccelData* SkPicture::EXPERIMENTAL_getAccelData(
245         SkPicture::AccelData::Key key) const {
246     if (fAccelData.get() && fAccelData->getKey() == key) {
247         return fAccelData.get();
248     }
249     return NULL;
250 }
251 
GenerateDomain()252 SkPicture::AccelData::Domain SkPicture::AccelData::GenerateDomain() {
253     static int32_t gNextID = 0;
254 
255     int32_t id = sk_atomic_inc(&gNextID);
256     if (id >= 1 << (8 * sizeof(Domain))) {
257         SK_CRASH();
258     }
259 
260     return static_cast<Domain>(id);
261 }
262 
263 ///////////////////////////////////////////////////////////////////////////////
264 
playback(SkCanvas * canvas,AbortCallback * callback) const265 void SkPicture::playback(SkCanvas* canvas, AbortCallback* callback) const {
266     SkASSERT(canvas);
267 
268     // If the query contains the whole picture, don't bother with the BBH.
269     SkRect clipBounds = { 0, 0, 0, 0 };
270     (void)canvas->getClipBounds(&clipBounds);
271     const bool useBBH = !clipBounds.contains(this->cullRect());
272 
273     SkRecordDraw(*fRecord, canvas, this->drawablePicts(), NULL, this->drawableCount(),
274                  useBBH ? fBBH.get() : NULL, callback);
275 }
276 
277 ///////////////////////////////////////////////////////////////////////////////
278 
279 #include "SkStream.h"
280 
281 static const char kMagic[] = { 's', 'k', 'i', 'a', 'p', 'i', 'c', 't' };
282 
IsValidPictInfo(const SkPictInfo & info)283 bool SkPicture::IsValidPictInfo(const SkPictInfo& info) {
284     if (0 != memcmp(info.fMagic, kMagic, sizeof(kMagic))) {
285         return false;
286     }
287 
288     if (info.fVersion < MIN_PICTURE_VERSION ||
289         info.fVersion > CURRENT_PICTURE_VERSION) {
290         return false;
291     }
292 
293     return true;
294 }
295 
InternalOnly_StreamIsSKP(SkStream * stream,SkPictInfo * pInfo)296 bool SkPicture::InternalOnly_StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) {
297     if (NULL == stream) {
298         return false;
299     }
300 
301     // Check magic bytes.
302     SkPictInfo info;
303     SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
304 
305     if (!stream->read(&info.fMagic, sizeof(kMagic))) {
306         return false;
307     }
308 
309     info.fVersion = stream->readU32();
310     info.fCullRect.fLeft = stream->readScalar();
311     info.fCullRect.fTop = stream->readScalar();
312     info.fCullRect.fRight = stream->readScalar();
313     info.fCullRect.fBottom = stream->readScalar();
314 
315     info.fFlags = stream->readU32();
316 
317     if (!IsValidPictInfo(info)) {
318         return false;
319     }
320 
321     if (pInfo != NULL) {
322         *pInfo = info;
323     }
324     return true;
325 }
326 
InternalOnly_BufferIsSKP(SkReadBuffer * buffer,SkPictInfo * pInfo)327 bool SkPicture::InternalOnly_BufferIsSKP(SkReadBuffer* buffer, SkPictInfo* pInfo) {
328     // Check magic bytes.
329     SkPictInfo info;
330     SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
331 
332     if (!buffer->readByteArray(&info.fMagic, sizeof(kMagic))) {
333         return false;
334     }
335 
336     info.fVersion = buffer->readUInt();
337     buffer->readRect(&info.fCullRect);
338     info.fFlags = buffer->readUInt();
339 
340     if (!IsValidPictInfo(info)) {
341         return false;
342     }
343 
344     if (pInfo != NULL) {
345         *pInfo = info;
346     }
347     return true;
348 }
349 
Forwardport(const SkPictInfo & info,const SkPictureData * data)350 SkPicture* SkPicture::Forwardport(const SkPictInfo& info, const SkPictureData* data) {
351     if (!data) {
352         return NULL;
353     }
354     SkPicturePlayback playback(data);
355     SkPictureRecorder r;
356     playback.draw(r.beginRecording(SkScalarCeilToInt(info.fCullRect.width()),
357                                    SkScalarCeilToInt(info.fCullRect.height())),
358                   NULL/*no callback*/);
359     return r.endRecording();
360 }
361 
CreateFromStream(SkStream * stream,InstallPixelRefProc proc)362 SkPicture* SkPicture::CreateFromStream(SkStream* stream, InstallPixelRefProc proc) {
363     SkPictInfo info;
364     if (!InternalOnly_StreamIsSKP(stream, &info) || !stream->readBool()) {
365         return NULL;
366     }
367     SkAutoTDelete<SkPictureData> data(SkPictureData::CreateFromStream(stream, info, proc));
368     return Forwardport(info, data);
369 }
370 
CreateFromBuffer(SkReadBuffer & buffer)371 SkPicture* SkPicture::CreateFromBuffer(SkReadBuffer& buffer) {
372     SkPictInfo info;
373     if (!InternalOnly_BufferIsSKP(&buffer, &info) || !buffer.readBool()) {
374         return NULL;
375     }
376     SkAutoTDelete<SkPictureData> data(SkPictureData::CreateFromBuffer(buffer, info));
377     return Forwardport(info, data);
378 }
379 
createHeader(SkPictInfo * info) const380 void SkPicture::createHeader(SkPictInfo* info) const {
381     // Copy magic bytes at the beginning of the header
382     SkASSERT(sizeof(kMagic) == 8);
383     SkASSERT(sizeof(kMagic) == sizeof(info->fMagic));
384     memcpy(info->fMagic, kMagic, sizeof(kMagic));
385 
386     // Set picture info after magic bytes in the header
387     info->fVersion = CURRENT_PICTURE_VERSION;
388     info->fCullRect = this->cullRect();
389     info->fFlags = SkPictInfo::kCrossProcess_Flag;
390     // TODO: remove this flag, since we're always float (now)
391     info->fFlags |= SkPictInfo::kScalarIsFloat_Flag;
392 
393     if (8 == sizeof(void*)) {
394         info->fFlags |= SkPictInfo::kPtrIs64Bit_Flag;
395     }
396 }
397 
398 // This for compatibility with serialization code only.  This is not cheap.
Backport(const SkRecord & src,const SkPictInfo & info,SkPicture const * const drawablePicts[],int drawableCount)399 SkPictureData* SkPicture::Backport(const SkRecord& src, const SkPictInfo& info,
400                                    SkPicture const* const drawablePicts[], int drawableCount) {
401     SkPictureRecord rec(SkISize::Make(info.fCullRect.width(), info.fCullRect.height()), 0/*flags*/);
402     rec.beginRecording();
403         SkRecordDraw(src, &rec, drawablePicts, NULL, drawableCount, NULL/*bbh*/, NULL/*callback*/);
404     rec.endRecording();
405     return SkNEW_ARGS(SkPictureData, (rec, info, false/*deep copy ops?*/));
406 }
407 
serialize(SkWStream * stream,SkPixelSerializer * pixelSerializer) const408 void SkPicture::serialize(SkWStream* stream, SkPixelSerializer* pixelSerializer) const {
409     SkPictInfo info;
410     this->createHeader(&info);
411     SkAutoTDelete<SkPictureData> data(Backport(*fRecord, info, this->drawablePicts(),
412                                                this->drawableCount()));
413 
414     stream->write(&info, sizeof(info));
415     if (data) {
416         stream->writeBool(true);
417         data->serialize(stream, pixelSerializer);
418     } else {
419         stream->writeBool(false);
420     }
421 }
422 
flatten(SkWriteBuffer & buffer) const423 void SkPicture::flatten(SkWriteBuffer& buffer) const {
424     SkPictInfo info;
425     this->createHeader(&info);
426     SkAutoTDelete<SkPictureData> data(Backport(*fRecord, info, this->drawablePicts(),
427                                                this->drawableCount()));
428 
429     buffer.writeByteArray(&info.fMagic, sizeof(info.fMagic));
430     buffer.writeUInt(info.fVersion);
431     buffer.writeRect(info.fCullRect);
432     buffer.writeUInt(info.fFlags);
433     if (data) {
434         buffer.writeBool(true);
435         data->flatten(buffer);
436     } else {
437         buffer.writeBool(false);
438     }
439 }
440 
analysis() const441 const SkPicture::Analysis& SkPicture::analysis() const {
442     auto create = [&](){ return SkNEW_ARGS(Analysis, (*fRecord)); };
443     return *fAnalysis.get(create);
444 }
445 
446 #if SK_SUPPORT_GPU
suitableForGpuRasterization(GrContext *,const char ** reason) const447 bool SkPicture::suitableForGpuRasterization(GrContext*, const char **reason) const {
448     return this->analysis().suitableForGpuRasterization(reason, 0);
449 }
450 #endif
451 
hasText() const452 bool SkPicture::hasText()             const { return this->analysis().fHasText; }
willPlayBackBitmaps() const453 bool SkPicture::willPlayBackBitmaps() const { return this->analysis().fWillPlaybackBitmaps; }
approximateOpCount() const454 int  SkPicture::approximateOpCount()  const { return fRecord->count(); }
455 
SkPicture(const SkRect & cullRect,SkRecord * record,SnapshotArray * drawablePicts,SkBBoxHierarchy * bbh,AccelData * accelData,size_t approxBytesUsedBySubPictures)456 SkPicture::SkPicture(const SkRect& cullRect,
457                      SkRecord* record,
458                      SnapshotArray* drawablePicts,
459                      SkBBoxHierarchy* bbh,
460                      AccelData* accelData,
461                      size_t approxBytesUsedBySubPictures)
462     : fUniqueID(0)
463     , fCullRect(cullRect)
464     , fRecord(record)               // Take ownership of caller's ref.
465     , fDrawablePicts(drawablePicts) // Take ownership.
466     , fBBH(bbh)                     // Take ownership of caller's ref.
467     , fAccelData(accelData)         // Take ownership of caller's ref.
468     , fApproxBytesUsedBySubPictures(approxBytesUsedBySubPictures)
469 {}
470 
471 
472 static uint32_t gNextID = 1;
uniqueID() const473 uint32_t SkPicture::uniqueID() const {
474     uint32_t id = sk_atomic_load(&fUniqueID, sk_memory_order_relaxed);
475     while (id == 0) {
476         uint32_t next = sk_atomic_fetch_add(&gNextID, 1u);
477         if (sk_atomic_compare_exchange(&fUniqueID, &id, next,
478                                        sk_memory_order_relaxed,
479                                        sk_memory_order_relaxed)) {
480             id = next;
481         } else {
482             // sk_atomic_compare_exchange replaced id with the current value of fUniqueID.
483         }
484     }
485     return id;
486 }
487