1 2 /* 3 * Copyright 2007 The Android Open Source Project 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 10 #include "SkPictureFlat.h" 11 #include "SkPictureData.h" 12 #include "SkPicturePlayback.h" 13 #include "SkPictureRecord.h" 14 #include "SkPictureRecorder.h" 15 #include "SkPictureStateTree.h" 16 17 #include "SkBitmapDevice.h" 18 #include "SkCanvas.h" 19 #include "SkChunkAlloc.h" 20 #include "SkDrawPictureCallback.h" 21 #include "SkPaintPriv.h" 22 #include "SkPathEffect.h" 23 #include "SkPicture.h" 24 #include "SkRegion.h" 25 #include "SkShader.h" 26 #include "SkStream.h" 27 #include "SkTDArray.h" 28 #include "SkTLogic.h" 29 #include "SkTSearch.h" 30 #include "SkTime.h" 31 32 #include "SkReader32.h" 33 #include "SkWriter32.h" 34 #include "SkRTree.h" 35 #include "SkBBoxHierarchyRecord.h" 36 37 #if SK_SUPPORT_GPU 38 #include "GrContext.h" 39 #endif 40 41 #include "SkRecord.h" 42 #include "SkRecordDraw.h" 43 #include "SkRecordOpts.h" 44 #include "SkRecorder.h" 45 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. 55 static const SkPaint* AsPtr(const SkPaint& p) { return &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. 76 bool operator()(const SkRecords::DrawPicture& op) { return op.picture->willPlayBackBitmaps(); } 77 78 template <typename T> 79 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> 84 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> 88 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> 92 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> 106 static SK_WHEN(!HasMember_paint<T>, bool) CheckPaint(const T&) { return false; } 107 }; 108 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); 123 bool operator()(const SkRecords::DrawPicture& op) { return op.picture->hasText(); } 124 template <typename T> SK_WHEN(HasMember_text<T>, bool) operator()(const T&) { return true; } 125 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 136 PathCounter() 137 : numPaintWithPathEffectUses (0) 138 , numFastPathDashEffects (0) 139 , numAAConcavePaths (0) 140 , numAAHairlineConcavePaths (0) { 141 } 142 143 // Recurse into nested pictures. 144 void operator()(const SkRecords::DrawPicture& op) { 145 const SkPicture::Analysis& analysis = op.picture->fAnalysis; 146 numPaintWithPathEffectUses += analysis.fNumPaintWithPathEffectUses; 147 numFastPathDashEffects += analysis.fNumFastPathDashEffects; 148 numAAConcavePaths += analysis.fNumAAConcavePaths; 149 numAAHairlineConcavePaths += analysis.fNumAAHairlineConcavePaths; 150 } 151 152 void checkPaint(const SkPaint* paint) { 153 if (paint && paint->getPathEffect()) { 154 numPaintWithPathEffectUses++; 155 } 156 } 157 158 void operator()(const SkRecords::DrawPoints& op) { 159 this->checkPaint(&op.paint); 160 const SkPathEffect* effect = op.paint.getPathEffect(); 161 if (effect) { 162 SkPathEffect::DashInfo info; 163 SkPathEffect::DashType dashType = effect->asADash(&info); 164 if (2 == op.count && SkPaint::kRound_Cap != op.paint.getStrokeCap() && 165 SkPathEffect::kDash_DashType == dashType && 2 == info.fCount) { 166 numFastPathDashEffects++; 167 } 168 } 169 } 170 171 void operator()(const SkRecords::DrawPath& op) { 172 this->checkPaint(&op.paint); 173 if (op.paint.isAntiAlias() && !op.path.isConvex()) { 174 numAAConcavePaths++; 175 176 if (SkPaint::kStroke_Style == op.paint.getStyle() && 177 0 == op.paint.getStrokeWidth()) { 178 numAAHairlineConcavePaths++; 179 } 180 } 181 } 182 183 template <typename T> 184 SK_WHEN(HasMember_paint<T>, void) operator()(const T& op) { 185 this->checkPaint(AsPtr(op.paint)); 186 } 187 188 template <typename T> 189 SK_WHEN(!HasMember_paint<T>, void) operator()(const T& op) { /* do nothing */ } 190 191 int numPaintWithPathEffectUses; 192 int numFastPathDashEffects; 193 int numAAConcavePaths; 194 int numAAHairlineConcavePaths; 195 }; 196 197 SkPicture::Analysis::Analysis(const SkRecord& record) { 198 fWillPlaybackBitmaps = WillPlaybackBitmaps(record); 199 200 PathCounter counter; 201 for (unsigned i = 0; i < record.count(); i++) { 202 record.visit<void>(i, counter); 203 } 204 fNumPaintWithPathEffectUses = counter.numPaintWithPathEffectUses; 205 fNumFastPathDashEffects = counter.numFastPathDashEffects; 206 fNumAAConcavePaths = counter.numAAConcavePaths; 207 fNumAAHairlineConcavePaths = counter.numAAHairlineConcavePaths; 208 209 fHasText = false; 210 TextHunter text; 211 for (unsigned i = 0; i < record.count(); i++) { 212 if (record.visit<bool>(i, text)) { 213 fHasText = true; 214 break; 215 } 216 } 217 } 218 219 bool SkPicture::Analysis::suitableForGpuRasterization(const char** reason, 220 int sampleCount) const { 221 // TODO: the heuristic used here needs to be refined 222 static const int kNumPaintWithPathEffectsUsesTol = 1; 223 static const int kNumAAConcavePathsTol = 5; 224 225 int numNonDashedPathEffects = fNumPaintWithPathEffectUses - 226 fNumFastPathDashEffects; 227 bool suitableForDash = (0 == fNumPaintWithPathEffectUses) || 228 (numNonDashedPathEffects < kNumPaintWithPathEffectsUsesTol 229 && 0 == sampleCount); 230 231 bool ret = suitableForDash && 232 (fNumAAConcavePaths - fNumAAHairlineConcavePaths) 233 < kNumAAConcavePathsTol; 234 235 if (!ret && reason) { 236 if (!suitableForDash) { 237 if (0 != sampleCount) { 238 *reason = "Can't use multisample on dash effect."; 239 } else { 240 *reason = "Too many non dashed path effects."; 241 } 242 } else if ((fNumAAConcavePaths - fNumAAHairlineConcavePaths) 243 >= kNumAAConcavePathsTol) 244 *reason = "Too many anti-aliased concave paths."; 245 else 246 *reason = "Unknown reason for GPU unsuitability."; 247 } 248 return ret; 249 } 250 251 /////////////////////////////////////////////////////////////////////////////// 252 253 // fRecord OK 254 SkPicture::SkPicture(SkScalar width, SkScalar height, 255 const SkPictureRecord& record, 256 bool deepCopyOps) 257 : fCullWidth(width) 258 , fCullHeight(height) 259 , fAnalysis() { 260 this->needsNewGenID(); 261 262 SkPictInfo info; 263 this->createHeader(&info); 264 fData.reset(SkNEW_ARGS(SkPictureData, (record, info, deepCopyOps))); 265 } 266 267 // Create an SkPictureData-backed SkPicture from an SkRecord. 268 // This for compatibility with serialization code only. This is not cheap. 269 static SkPicture* backport(const SkRecord& src, const SkRect& cullRect) { 270 SkPictureRecorder recorder; 271 SkRecordDraw(src, 272 recorder.DEPRECATED_beginRecording(cullRect.width(), cullRect.height()), 273 NULL/*bbh*/, NULL/*callback*/); 274 return recorder.endRecording(); 275 } 276 277 // fRecord OK 278 SkPicture::~SkPicture() { 279 this->callDeletionListeners(); 280 } 281 282 // fRecord OK 283 #ifdef SK_SUPPORT_LEGACY_PICTURE_CLONE 284 SkPicture* SkPicture::clone() const { 285 return SkRef(const_cast<SkPicture*>(this)); 286 } 287 #endif//SK_SUPPORT_LEGACY_PICTURE_CLONE 288 289 // fRecord OK 290 void SkPicture::EXPERIMENTAL_addAccelData(const SkPicture::AccelData* data) const { 291 fAccelData.reset(SkRef(data)); 292 } 293 294 // fRecord OK 295 const SkPicture::AccelData* SkPicture::EXPERIMENTAL_getAccelData( 296 SkPicture::AccelData::Key key) const { 297 if (fAccelData.get() && fAccelData->getKey() == key) { 298 return fAccelData.get(); 299 } 300 return NULL; 301 } 302 303 // fRecord OK 304 SkPicture::AccelData::Domain SkPicture::AccelData::GenerateDomain() { 305 static int32_t gNextID = 0; 306 307 int32_t id = sk_atomic_inc(&gNextID); 308 if (id >= 1 << (8 * sizeof(Domain))) { 309 SK_CRASH(); 310 } 311 312 return static_cast<Domain>(id); 313 } 314 315 /////////////////////////////////////////////////////////////////////////////// 316 317 uint32_t SkPicture::OperationList::offset(int index) const { 318 SkASSERT(index < fOps.count()); 319 return ((SkPictureStateTree::Draw*)fOps[index])->fOffset; 320 } 321 322 const SkMatrix& SkPicture::OperationList::matrix(int index) const { 323 SkASSERT(index < fOps.count()); 324 return *((SkPictureStateTree::Draw*)fOps[index])->fMatrix; 325 } 326 327 // fRecord OK 328 void SkPicture::playback(SkCanvas* canvas, SkDrawPictureCallback* callback) const { 329 SkASSERT(canvas); 330 SkASSERT(fData.get() || fRecord.get()); 331 332 // If the query contains the whole picture, don't bother with the BBH. 333 SkRect clipBounds = { 0, 0, 0, 0 }; 334 (void)canvas->getClipBounds(&clipBounds); 335 const bool useBBH = !clipBounds.contains(this->cullRect()); 336 337 if (fData.get()) { 338 SkPicturePlayback playback(this); 339 playback.setUseBBH(useBBH); 340 playback.draw(canvas, callback); 341 } 342 if (fRecord.get()) { 343 SkRecordDraw(*fRecord, canvas, useBBH ? fBBH.get() : NULL, callback); 344 } 345 } 346 347 /////////////////////////////////////////////////////////////////////////////// 348 349 #include "SkStream.h" 350 351 static const char kMagic[] = { 's', 'k', 'i', 'a', 'p', 'i', 'c', 't' }; 352 353 // fRecord OK 354 bool SkPicture::IsValidPictInfo(const SkPictInfo& info) { 355 if (0 != memcmp(info.fMagic, kMagic, sizeof(kMagic))) { 356 return false; 357 } 358 359 if (info.fVersion < MIN_PICTURE_VERSION || 360 info.fVersion > CURRENT_PICTURE_VERSION) { 361 return false; 362 } 363 364 return true; 365 } 366 367 // fRecord OK 368 bool SkPicture::InternalOnly_StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) { 369 if (NULL == stream) { 370 return false; 371 } 372 373 // Check magic bytes. 374 SkPictInfo info; 375 SkASSERT(sizeof(kMagic) == sizeof(info.fMagic)); 376 377 if (!stream->read(&info.fMagic, sizeof(kMagic))) { 378 return false; 379 } 380 381 info.fVersion = stream->readU32(); 382 383 #ifndef V35_COMPATIBILITY_CODE 384 if (info.fVersion < 35) { 385 info.fCullRect.fLeft = 0; 386 info.fCullRect.fTop = 0; 387 info.fCullRect.fRight = SkIntToScalar(stream->readU32()); 388 info.fCullRect.fBottom = SkIntToScalar(stream->readU32()); 389 } else { 390 #endif 391 info.fCullRect.fLeft = stream->readScalar(); 392 info.fCullRect.fTop = stream->readScalar(); 393 info.fCullRect.fRight = stream->readScalar(); 394 info.fCullRect.fBottom = stream->readScalar(); 395 #ifndef V35_COMPATIBILITY_CODE 396 } 397 #endif 398 399 info.fFlags = stream->readU32(); 400 401 if (!IsValidPictInfo(info)) { 402 return false; 403 } 404 405 if (pInfo != NULL) { 406 *pInfo = info; 407 } 408 return true; 409 } 410 411 // fRecord OK 412 bool SkPicture::InternalOnly_BufferIsSKP(SkReadBuffer* buffer, SkPictInfo* pInfo) { 413 // Check magic bytes. 414 SkPictInfo info; 415 SkASSERT(sizeof(kMagic) == sizeof(info.fMagic)); 416 417 if (!buffer->readByteArray(&info.fMagic, sizeof(kMagic))) { 418 return false; 419 } 420 421 info.fVersion = buffer->readUInt(); 422 423 #ifndef V35_COMPATIBILITY_CODE 424 if (info.fVersion < 35) { 425 info.fCullRect.fLeft = 0; 426 info.fCullRect.fTop = 0; 427 info.fCullRect.fRight = SkIntToScalar(buffer->readUInt()); 428 info.fCullRect.fBottom = SkIntToScalar(buffer->readUInt()); 429 } else { 430 #endif 431 buffer->readRect(&info.fCullRect); 432 #ifndef V35_COMPATIBILITY_CODE 433 } 434 #endif 435 436 info.fFlags = buffer->readUInt(); 437 438 if (!IsValidPictInfo(info)) { 439 return false; 440 } 441 442 if (pInfo != NULL) { 443 *pInfo = info; 444 } 445 return true; 446 } 447 448 // fRecord OK 449 SkPicture::SkPicture(SkPictureData* data, SkScalar width, SkScalar height) 450 : fData(data) 451 , fCullWidth(width) 452 , fCullHeight(height) 453 , fAnalysis() { 454 this->needsNewGenID(); 455 } 456 457 SkPicture* SkPicture::Forwardport(const SkPicture& src) { 458 SkAutoTDelete<SkRecord> record(SkNEW(SkRecord)); 459 SkRecorder canvas(record.get(), src.cullRect().width(), src.cullRect().height()); 460 src.playback(&canvas); 461 return SkNEW_ARGS(SkPicture, (src.cullRect().width(), src.cullRect().height(), 462 record.detach(), NULL/*bbh*/)); 463 } 464 465 // fRecord OK 466 SkPicture* SkPicture::CreateFromStream(SkStream* stream, InstallPixelRefProc proc) { 467 SkPictInfo info; 468 469 if (!InternalOnly_StreamIsSKP(stream, &info)) { 470 return NULL; 471 } 472 473 // Check to see if there is a playback to recreate. 474 if (stream->readBool()) { 475 SkPictureData* data = SkPictureData::CreateFromStream(stream, info, proc); 476 if (NULL == data) { 477 return NULL; 478 } 479 const SkPicture src(data, info.fCullRect.width(), info.fCullRect.height()); 480 return Forwardport(src); 481 } 482 483 return NULL; 484 } 485 486 // fRecord OK 487 SkPicture* SkPicture::CreateFromBuffer(SkReadBuffer& buffer) { 488 SkPictInfo info; 489 490 if (!InternalOnly_BufferIsSKP(&buffer, &info)) { 491 return NULL; 492 } 493 494 // Check to see if there is a playback to recreate. 495 if (buffer.readBool()) { 496 SkPictureData* data = SkPictureData::CreateFromBuffer(buffer, info); 497 if (NULL == data) { 498 return NULL; 499 } 500 const SkPicture src(data, info.fCullRect.width(), info.fCullRect.height()); 501 return Forwardport(src); 502 } 503 504 return NULL; 505 } 506 507 // fRecord OK 508 void SkPicture::createHeader(SkPictInfo* info) const { 509 // Copy magic bytes at the beginning of the header 510 SkASSERT(sizeof(kMagic) == 8); 511 SkASSERT(sizeof(kMagic) == sizeof(info->fMagic)); 512 memcpy(info->fMagic, kMagic, sizeof(kMagic)); 513 514 // Set picture info after magic bytes in the header 515 info->fVersion = CURRENT_PICTURE_VERSION; 516 info->fCullRect = this->cullRect(); 517 info->fFlags = SkPictInfo::kCrossProcess_Flag; 518 // TODO: remove this flag, since we're always float (now) 519 info->fFlags |= SkPictInfo::kScalarIsFloat_Flag; 520 521 if (8 == sizeof(void*)) { 522 info->fFlags |= SkPictInfo::kPtrIs64Bit_Flag; 523 } 524 } 525 526 // fRecord OK 527 void SkPicture::serialize(SkWStream* stream, EncodeBitmap encoder) const { 528 const SkPictureData* data = fData.get(); 529 530 // If we're a new-format picture, backport to old format for serialization. 531 SkAutoTDelete<SkPicture> oldFormat; 532 if (NULL == data && fRecord.get()) { 533 oldFormat.reset(backport(*fRecord, this->cullRect())); 534 data = oldFormat->fData.get(); 535 SkASSERT(data); 536 } 537 538 SkPictInfo info; 539 this->createHeader(&info); 540 SkASSERT(sizeof(SkPictInfo) == 32); 541 stream->write(&info, sizeof(info)); 542 543 if (data) { 544 stream->writeBool(true); 545 data->serialize(stream, encoder); 546 } else { 547 stream->writeBool(false); 548 } 549 } 550 551 // fRecord OK 552 void SkPicture::flatten(SkWriteBuffer& buffer) const { 553 const SkPictureData* data = fData.get(); 554 555 // If we're a new-format picture, backport to old format for serialization. 556 SkAutoTDelete<SkPicture> oldFormat; 557 if (NULL == data && fRecord.get()) { 558 oldFormat.reset(backport(*fRecord, this->cullRect())); 559 data = oldFormat->fData.get(); 560 SkASSERT(data); 561 } 562 563 SkPictInfo info; 564 this->createHeader(&info); 565 buffer.writeByteArray(&info.fMagic, sizeof(info.fMagic)); 566 buffer.writeUInt(info.fVersion); 567 buffer.writeRect(info.fCullRect); 568 buffer.writeUInt(info.fFlags); 569 570 if (data) { 571 buffer.writeBool(true); 572 data->flatten(buffer); 573 } else { 574 buffer.writeBool(false); 575 } 576 } 577 578 #if SK_SUPPORT_GPU 579 // fRecord OK 580 bool SkPicture::suitableForGpuRasterization(GrContext* context, const char **reason) const { 581 if (fRecord.get()) { 582 return fAnalysis.suitableForGpuRasterization(reason, 0); 583 } 584 if (NULL == fData.get()) { 585 if (reason) { 586 *reason = "Missing internal data."; 587 } 588 return false; 589 } 590 591 return fData->suitableForGpuRasterization(context, reason); 592 } 593 #endif 594 595 // fRecord OK 596 bool SkPicture::hasText() const { 597 if (fRecord.get()) { 598 return fAnalysis.fHasText; 599 } 600 if (fData.get()) { 601 return fData->hasText(); 602 } 603 SkFAIL("Unreachable"); 604 return false; 605 } 606 607 // fRecord OK 608 bool SkPicture::willPlayBackBitmaps() const { 609 if (fRecord.get()) { 610 return fAnalysis.fWillPlaybackBitmaps; 611 } 612 if (fData.get()) { 613 return fData->containsBitmaps(); 614 } 615 SkFAIL("Unreachable"); 616 return false; 617 } 618 619 // fRecord OK 620 static int32_t next_picture_generation_id() { 621 static int32_t gPictureGenerationID = 0; 622 // do a loop in case our global wraps around, as we never want to 623 // return a 0 624 int32_t genID; 625 do { 626 genID = sk_atomic_inc(&gPictureGenerationID) + 1; 627 } while (SK_InvalidGenID == genID); 628 return genID; 629 } 630 631 // fRecord OK 632 uint32_t SkPicture::uniqueID() const { 633 if (SK_InvalidGenID == fUniqueID) { 634 fUniqueID = next_picture_generation_id(); 635 } 636 return fUniqueID; 637 } 638 639 640 static SkRecord* optimized(SkRecord* r) { 641 #ifdef SK_PICTURE_OPTIMIZE_SK_RECORD 642 SkRecordOptimize(r); 643 #endif 644 return r; 645 } 646 647 // fRecord OK 648 SkPicture::SkPicture(SkScalar width, SkScalar height, SkRecord* record, SkBBoxHierarchy* bbh) 649 : fCullWidth(width) 650 , fCullHeight(height) 651 , fRecord(optimized(record)) 652 , fBBH(SkSafeRef(bbh)) 653 , fAnalysis(*fRecord) { 654 // TODO: delay as much of this work until just before first playback? 655 if (fBBH.get()) { 656 SkRecordFillBounds(*fRecord, fBBH.get()); 657 } 658 this->needsNewGenID(); 659 } 660 661 // Note that we are assuming that this entry point will only be called from 662 // one thread. Currently the only client of this method is 663 // SkGpuDevice::EXPERIMENTAL_optimize which should be only called from a single 664 // thread. 665 void SkPicture::addDeletionListener(DeletionListener* listener) const { 666 SkASSERT(listener); 667 668 *fDeletionListeners.append() = SkRef(listener); 669 } 670 671 void SkPicture::callDeletionListeners() { 672 for (int i = 0; i < fDeletionListeners.count(); ++i) { 673 fDeletionListeners[i]->onDeletion(this->uniqueID()); 674 } 675 676 fDeletionListeners.unrefAll(); 677 } 678 679 // fRecord OK 680 int SkPicture::approximateOpCount() const { 681 SkASSERT(fRecord.get() || fData.get()); 682 if (fRecord.get()) { 683 return fRecord->count(); 684 } 685 if (fData.get()) { 686 return fData->opCount(); 687 } 688 return 0; 689 } 690