SkPicture.cpp revision d55b59574854055fae275a5300a352d61978c8a6
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 "SkBitmapDevice.h"
16#include "SkCanvas.h"
17#include "SkChunkAlloc.h"
18#include "SkDrawPictureCallback.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
44DECLARE_SKMESSAGEBUS_MESSAGE(SkPicture::DeletionMessage);
45
46template <typename T> int SafeCount(const T* obj) {
47    return obj ? obj->count() : 0;
48}
49
50static int32_t gPictureGenerationID;
51
52// never returns a 0
53static int32_t next_picture_generation_id() {
54    // Loop in case our global wraps around.
55    int32_t genID;
56    do {
57        genID = sk_atomic_inc(&gPictureGenerationID) + 1;
58    } while (0 == genID);
59    return genID;
60}
61
62///////////////////////////////////////////////////////////////////////////////
63
64namespace {
65
66// Some commands have a paint, some have an optional paint.  Either way, get back a pointer.
67static const SkPaint* AsPtr(const SkPaint& p) { return &p; }
68static const SkPaint* AsPtr(const SkRecords::Optional<SkPaint>& p) { return p; }
69
70/** SkRecords visitor to determine whether an instance may require an
71    "external" bitmap to rasterize. May return false positives.
72    Does not return true for bitmap text.
73
74    Expected use is to determine whether images need to be decoded before
75    rasterizing a particular SkRecord.
76 */
77struct BitmapTester {
78    // Helpers.  These create HasMember_bitmap and HasMember_paint.
79    SK_CREATE_MEMBER_DETECTOR(bitmap);
80    SK_CREATE_MEMBER_DETECTOR(paint);
81
82
83    // Main entry for visitor:
84    // If the command is a DrawPicture, recurse.
85    // If the command has a bitmap directly, return true.
86    // If the command has a paint and the paint has a bitmap, return true.
87    // Otherwise, return false.
88    bool operator()(const SkRecords::DrawPicture& op) { return op.picture->willPlayBackBitmaps(); }
89
90    template <typename T>
91    bool operator()(const T& r) { return CheckBitmap(r); }
92
93
94    // If the command has a bitmap, of course we're going to play back bitmaps.
95    template <typename T>
96    static SK_WHEN(HasMember_bitmap<T>, bool) CheckBitmap(const T&) { return true; }
97
98    // If not, look for one in its paint (if it has a paint).
99    template <typename T>
100    static SK_WHEN(!HasMember_bitmap<T>, bool) CheckBitmap(const T& r) { return CheckPaint(r); }
101
102    // If we have a paint, dig down into the effects looking for a bitmap.
103    template <typename T>
104    static SK_WHEN(HasMember_paint<T>, bool) CheckPaint(const T& r) {
105        const SkPaint* paint = AsPtr(r.paint);
106        if (paint) {
107            const SkShader* shader = paint->getShader();
108            if (shader &&
109                shader->asABitmap(NULL, NULL, NULL) == SkShader::kDefault_BitmapType) {
110                return true;
111            }
112        }
113        return false;
114    }
115
116    // If we don't have a paint, that non-paint has no bitmap.
117    template <typename T>
118    static SK_WHEN(!HasMember_paint<T>, bool) CheckPaint(const T&) { return false; }
119};
120
121bool WillPlaybackBitmaps(const SkRecord& record) {
122    BitmapTester tester;
123    for (unsigned i = 0; i < record.count(); i++) {
124        if (record.visit<bool>(i, tester)) {
125            return true;
126        }
127    }
128    return false;
129}
130
131// SkRecord visitor to find recorded text.
132struct TextHunter {
133    // All ops with text have that text as a char array member named "text".
134    SK_CREATE_MEMBER_DETECTOR(text);
135    bool operator()(const SkRecords::DrawPicture& op) { return op.picture->hasText(); }
136    template <typename T> SK_WHEN(HasMember_text<T>,  bool) operator()(const T&) { return true;  }
137    template <typename T> SK_WHEN(!HasMember_text<T>, bool) operator()(const T&) { return false; }
138};
139
140} // namespace
141
142/** SkRecords visitor to determine heuristically whether or not a SkPicture
143    will be performant when rasterized on the GPU.
144 */
145struct SkPicture::PathCounter {
146    SK_CREATE_MEMBER_DETECTOR(paint);
147
148    PathCounter()
149        : numPaintWithPathEffectUses (0)
150        , numFastPathDashEffects (0)
151        , numAAConcavePaths (0)
152        , numAAHairlineConcavePaths (0)
153        , numAADFEligibleConcavePaths(0) {
154    }
155
156    // Recurse into nested pictures.
157    void operator()(const SkRecords::DrawPicture& op) {
158        const SkPicture::Analysis& analysis = op.picture->fAnalysis;
159        numPaintWithPathEffectUses += analysis.fNumPaintWithPathEffectUses;
160        numFastPathDashEffects     += analysis.fNumFastPathDashEffects;
161        numAAConcavePaths          += analysis.fNumAAConcavePaths;
162        numAAHairlineConcavePaths  += analysis.fNumAAHairlineConcavePaths;
163        numAADFEligibleConcavePaths  += analysis.fNumAADFEligibleConcavePaths;
164    }
165
166    void checkPaint(const SkPaint* paint) {
167        if (paint && paint->getPathEffect()) {
168            numPaintWithPathEffectUses++;
169        }
170    }
171
172    void operator()(const SkRecords::DrawPoints& op) {
173        this->checkPaint(&op.paint);
174        const SkPathEffect* effect = op.paint.getPathEffect();
175        if (effect) {
176            SkPathEffect::DashInfo info;
177            SkPathEffect::DashType dashType = effect->asADash(&info);
178            if (2 == op.count && SkPaint::kRound_Cap != op.paint.getStrokeCap() &&
179                SkPathEffect::kDash_DashType == dashType && 2 == info.fCount) {
180                numFastPathDashEffects++;
181            }
182        }
183    }
184
185    void operator()(const SkRecords::DrawPath& op) {
186        this->checkPaint(&op.paint);
187        if (op.paint.isAntiAlias() && !op.path.isConvex()) {
188            numAAConcavePaths++;
189
190            SkPaint::Style paintStyle = op.paint.getStyle();
191            const SkRect& pathBounds = op.path.getBounds();
192            if (SkPaint::kStroke_Style == paintStyle &&
193                0 == op.paint.getStrokeWidth()) {
194                numAAHairlineConcavePaths++;
195            } else if (SkPaint::kFill_Style == paintStyle && pathBounds.width() < 64.f &&
196                       pathBounds.height() < 64.f && !op.path.isVolatile()) {
197                numAADFEligibleConcavePaths++;
198            }
199        }
200    }
201
202    template <typename T>
203    SK_WHEN(HasMember_paint<T>, void) operator()(const T& op) {
204        this->checkPaint(AsPtr(op.paint));
205    }
206
207    template <typename T>
208    SK_WHEN(!HasMember_paint<T>, void) operator()(const T& op) { /* do nothing */ }
209
210    int numPaintWithPathEffectUses;
211    int numFastPathDashEffects;
212    int numAAConcavePaths;
213    int numAAHairlineConcavePaths;
214    int numAADFEligibleConcavePaths;
215};
216
217SkPicture::Analysis::Analysis(const SkRecord& record) {
218    fWillPlaybackBitmaps = WillPlaybackBitmaps(record);
219
220    PathCounter counter;
221    for (unsigned i = 0; i < record.count(); i++) {
222        record.visit<void>(i, counter);
223    }
224    fNumPaintWithPathEffectUses = counter.numPaintWithPathEffectUses;
225    fNumFastPathDashEffects     = counter.numFastPathDashEffects;
226    fNumAAConcavePaths          = counter.numAAConcavePaths;
227    fNumAAHairlineConcavePaths  = counter.numAAHairlineConcavePaths;
228    fNumAADFEligibleConcavePaths  = counter.numAADFEligibleConcavePaths;
229
230    fHasText = false;
231    TextHunter text;
232    for (unsigned i = 0; i < record.count(); i++) {
233        if (record.visit<bool>(i, text)) {
234            fHasText = true;
235            break;
236        }
237    }
238}
239
240bool SkPicture::Analysis::suitableForGpuRasterization(const char** reason,
241                                                      int sampleCount) const {
242    // TODO: the heuristic used here needs to be refined
243    static const int kNumPaintWithPathEffectsUsesTol = 1;
244    static const int kNumAAConcavePathsTol = 5;
245
246    int numNonDashedPathEffects = fNumPaintWithPathEffectUses -
247                                  fNumFastPathDashEffects;
248    bool suitableForDash = (0 == fNumPaintWithPathEffectUses) ||
249                           (numNonDashedPathEffects < kNumPaintWithPathEffectsUsesTol
250                               && 0 == sampleCount);
251
252    bool ret = suitableForDash &&
253               (fNumAAConcavePaths - fNumAAHairlineConcavePaths - fNumAADFEligibleConcavePaths)
254                   < kNumAAConcavePathsTol;
255
256    if (!ret && reason) {
257        if (!suitableForDash) {
258            if (0 != sampleCount) {
259                *reason = "Can't use multisample on dash effect.";
260            } else {
261                *reason = "Too many non dashed path effects.";
262            }
263        } else if ((fNumAAConcavePaths - fNumAAHairlineConcavePaths - fNumAADFEligibleConcavePaths)
264                    >= kNumAAConcavePathsTol)
265            *reason = "Too many anti-aliased concave paths.";
266        else
267            *reason = "Unknown reason for GPU unsuitability.";
268    }
269    return ret;
270}
271
272///////////////////////////////////////////////////////////////////////////////
273
274int SkPicture::drawableCount() const {
275    return fDrawablePicts.get() ? fDrawablePicts->count() : 0;
276}
277
278SkPicture const* const* SkPicture::drawablePicts() const {
279    return fDrawablePicts.get() ? fDrawablePicts->begin() : NULL;
280}
281
282SkPicture::~SkPicture() {
283    SkPicture::DeletionMessage msg;
284    msg.fUniqueID = this->uniqueID();
285    SkMessageBus<SkPicture::DeletionMessage>::Post(msg);
286}
287
288void SkPicture::EXPERIMENTAL_addAccelData(const SkPicture::AccelData* data) const {
289    fAccelData.reset(SkRef(data));
290}
291
292const SkPicture::AccelData* SkPicture::EXPERIMENTAL_getAccelData(
293        SkPicture::AccelData::Key key) const {
294    if (fAccelData.get() && fAccelData->getKey() == key) {
295        return fAccelData.get();
296    }
297    return NULL;
298}
299
300SkPicture::AccelData::Domain SkPicture::AccelData::GenerateDomain() {
301    static int32_t gNextID = 0;
302
303    int32_t id = sk_atomic_inc(&gNextID);
304    if (id >= 1 << (8 * sizeof(Domain))) {
305        SK_CRASH();
306    }
307
308    return static_cast<Domain>(id);
309}
310
311///////////////////////////////////////////////////////////////////////////////
312
313void SkPicture::playback(SkCanvas* canvas, SkDrawPictureCallback* callback) const {
314    SkASSERT(canvas);
315
316    // If the query contains the whole picture, don't bother with the BBH.
317    SkRect clipBounds = { 0, 0, 0, 0 };
318    (void)canvas->getClipBounds(&clipBounds);
319    const bool useBBH = !clipBounds.contains(this->cullRect());
320
321    SkRecordDraw(*fRecord, canvas, this->drawablePicts(), NULL, this->drawableCount(),
322                 useBBH ? fBBH.get() : NULL, callback);
323}
324
325///////////////////////////////////////////////////////////////////////////////
326
327#include "SkStream.h"
328
329static const char kMagic[] = { 's', 'k', 'i', 'a', 'p', 'i', 'c', 't' };
330
331bool SkPicture::IsValidPictInfo(const SkPictInfo& info) {
332    if (0 != memcmp(info.fMagic, kMagic, sizeof(kMagic))) {
333        return false;
334    }
335
336    if (info.fVersion < MIN_PICTURE_VERSION ||
337        info.fVersion > CURRENT_PICTURE_VERSION) {
338        return false;
339    }
340
341    return true;
342}
343
344bool SkPicture::InternalOnly_StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) {
345    if (NULL == stream) {
346        return false;
347    }
348
349    // Check magic bytes.
350    SkPictInfo info;
351    SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
352
353    if (!stream->read(&info.fMagic, sizeof(kMagic))) {
354        return false;
355    }
356
357    info.fVersion = stream->readU32();
358    info.fCullRect.fLeft = stream->readScalar();
359    info.fCullRect.fTop = stream->readScalar();
360    info.fCullRect.fRight = stream->readScalar();
361    info.fCullRect.fBottom = stream->readScalar();
362
363    info.fFlags = stream->readU32();
364
365    if (!IsValidPictInfo(info)) {
366        return false;
367    }
368
369    if (pInfo != NULL) {
370        *pInfo = info;
371    }
372    return true;
373}
374
375bool SkPicture::InternalOnly_BufferIsSKP(SkReadBuffer* buffer, SkPictInfo* pInfo) {
376    // Check magic bytes.
377    SkPictInfo info;
378    SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
379
380    if (!buffer->readByteArray(&info.fMagic, sizeof(kMagic))) {
381        return false;
382    }
383
384    info.fVersion = buffer->readUInt();
385    buffer->readRect(&info.fCullRect);
386    info.fFlags = buffer->readUInt();
387
388    if (!IsValidPictInfo(info)) {
389        return false;
390    }
391
392    if (pInfo != NULL) {
393        *pInfo = info;
394    }
395    return true;
396}
397
398SkPicture* SkPicture::Forwardport(const SkPictInfo& info, const SkPictureData* data) {
399    if (!data) {
400        return NULL;
401    }
402    SkPicturePlayback playback(data);
403    SkPictureRecorder r;
404    playback.draw(r.beginRecording(SkScalarCeilToInt(info.fCullRect.width()),
405                                   SkScalarCeilToInt(info.fCullRect.height())),
406                  NULL/*no callback*/);
407    return r.endRecording();
408}
409
410SkPicture* SkPicture::CreateFromStream(SkStream* stream, InstallPixelRefProc proc) {
411    SkPictInfo info;
412    if (!InternalOnly_StreamIsSKP(stream, &info) || !stream->readBool()) {
413        return NULL;
414    }
415    SkAutoTDelete<SkPictureData> data(SkPictureData::CreateFromStream(stream, info, proc));
416    return Forwardport(info, data);
417}
418
419SkPicture* SkPicture::CreateFromBuffer(SkReadBuffer& buffer) {
420    SkPictInfo info;
421    if (!InternalOnly_BufferIsSKP(&buffer, &info) || !buffer.readBool()) {
422        return NULL;
423    }
424    SkAutoTDelete<SkPictureData> data(SkPictureData::CreateFromBuffer(buffer, info));
425    return Forwardport(info, data);
426}
427
428void SkPicture::createHeader(SkPictInfo* info) const {
429    // Copy magic bytes at the beginning of the header
430    SkASSERT(sizeof(kMagic) == 8);
431    SkASSERT(sizeof(kMagic) == sizeof(info->fMagic));
432    memcpy(info->fMagic, kMagic, sizeof(kMagic));
433
434    // Set picture info after magic bytes in the header
435    info->fVersion = CURRENT_PICTURE_VERSION;
436    info->fCullRect = this->cullRect();
437    info->fFlags = SkPictInfo::kCrossProcess_Flag;
438    // TODO: remove this flag, since we're always float (now)
439    info->fFlags |= SkPictInfo::kScalarIsFloat_Flag;
440
441    if (8 == sizeof(void*)) {
442        info->fFlags |= SkPictInfo::kPtrIs64Bit_Flag;
443    }
444}
445
446// This for compatibility with serialization code only.  This is not cheap.
447SkPictureData* SkPicture::Backport(const SkRecord& src, const SkPictInfo& info,
448                                   SkPicture const* const drawablePicts[], int drawableCount) {
449    SkPictureRecord rec(SkISize::Make(info.fCullRect.width(), info.fCullRect.height()), 0/*flags*/);
450    rec.beginRecording();
451        SkRecordDraw(src, &rec, drawablePicts, NULL, drawableCount, NULL/*bbh*/, NULL/*callback*/);
452    rec.endRecording();
453    return SkNEW_ARGS(SkPictureData, (rec, info, false/*deep copy ops?*/));
454}
455
456#ifdef SK_LEGACY_ENCODE_BITMAP
457// Helper to support the EncodeBitmap version of serialize.
458// Mimics the old behavior of always accepting the encoded data, and encoding
459// using EncodeBitmap if there was no encoded data.
460class EncodeBitmapSerializer : public SkPixelSerializer {
461public:
462    explicit EncodeBitmapSerializer(SkPicture::EncodeBitmap encoder)
463    : fEncoder(encoder)
464    {
465        SkASSERT(fEncoder);
466    }
467
468    bool onUseEncodedData(const void*, size_t) SK_OVERRIDE { return true; }
469
470    SkData* onEncodePixels(const SkImageInfo& info, const void* pixels,
471                                   size_t rowBytes) SK_OVERRIDE {
472        // Required by signature of EncodeBitmap.
473        size_t unused;
474        SkBitmap bm;
475        bm.installPixels(info, const_cast<void*>(pixels), rowBytes);
476        return fEncoder(&unused, bm);
477    }
478
479private:
480    SkPicture::EncodeBitmap fEncoder;
481};
482
483void SkPicture::serialize(SkWStream* wStream, SkPicture::EncodeBitmap encoder) const {
484    EncodeBitmapSerializer serializer(encoder);
485    this->serialize(wStream, &serializer);
486}
487
488#endif
489
490void SkPicture::serialize(SkWStream* stream, SkPixelSerializer* pixelSerializer) const {
491    SkPictInfo info;
492    this->createHeader(&info);
493    SkAutoTDelete<SkPictureData> data(Backport(*fRecord, info, this->drawablePicts(),
494                                               this->drawableCount()));
495
496    stream->write(&info, sizeof(info));
497    if (data) {
498        stream->writeBool(true);
499        data->serialize(stream, pixelSerializer);
500    } else {
501        stream->writeBool(false);
502    }
503}
504
505void SkPicture::flatten(SkWriteBuffer& buffer) const {
506    SkPictInfo info;
507    this->createHeader(&info);
508    SkAutoTDelete<SkPictureData> data(Backport(*fRecord, info, this->drawablePicts(),
509                                               this->drawableCount()));
510
511    buffer.writeByteArray(&info.fMagic, sizeof(info.fMagic));
512    buffer.writeUInt(info.fVersion);
513    buffer.writeRect(info.fCullRect);
514    buffer.writeUInt(info.fFlags);
515    if (data) {
516        buffer.writeBool(true);
517        data->flatten(buffer);
518    } else {
519        buffer.writeBool(false);
520    }
521}
522
523#if SK_SUPPORT_GPU
524bool SkPicture::suitableForGpuRasterization(GrContext*, const char **reason) const {
525    return fAnalysis.suitableForGpuRasterization(reason, 0);
526}
527#endif
528
529bool SkPicture::hasText()             const { return fAnalysis.fHasText; }
530bool SkPicture::willPlayBackBitmaps() const { return fAnalysis.fWillPlaybackBitmaps; }
531int  SkPicture::approximateOpCount()  const { return fRecord->count(); }
532
533SkPicture::SkPicture(const SkRect& cullRect, SkRecord* record, SnapshotArray* drawablePicts,
534                     SkBBoxHierarchy* bbh)
535    : fUniqueID(next_picture_generation_id())
536    , fCullRect(cullRect)
537    , fRecord(SkRef(record))
538    , fBBH(SkSafeRef(bbh))
539    , fDrawablePicts(drawablePicts)     // take ownership
540    , fAnalysis(*fRecord)
541{}
542