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