1 /* 2 * Copyright 2012 Google Inc. 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 #include "PictureRenderer.h" 9 #include "picture_utils.h" 10 #include "SamplePipeControllers.h" 11 #include "SkCanvas.h" 12 #include "SkDevice.h" 13 #include "SkGPipe.h" 14 #if SK_SUPPORT_GPU 15 #include "SkGpuDevice.h" 16 #endif 17 #include "SkGraphics.h" 18 #include "SkImageEncoder.h" 19 #include "SkMaskFilter.h" 20 #include "SkMatrix.h" 21 #include "SkPicture.h" 22 #include "SkRTree.h" 23 #include "SkScalar.h" 24 #include "SkStream.h" 25 #include "SkString.h" 26 #include "SkTemplates.h" 27 #include "SkTileGridPicture.h" 28 #include "SkTDArray.h" 29 #include "SkThreadUtils.h" 30 #include "SkTypes.h" 31 #include "SkData.h" 32 #include "SkPictureUtils.h" 33 34 namespace sk_tools { 35 36 enum { 37 kDefaultTileWidth = 256, 38 kDefaultTileHeight = 256 39 }; 40 41 void PictureRenderer::init(SkPicture* pict) { 42 SkASSERT(NULL == fPicture); 43 SkASSERT(NULL == fCanvas.get()); 44 if (fPicture != NULL || NULL != fCanvas.get()) { 45 return; 46 } 47 48 SkASSERT(pict != NULL); 49 if (NULL == pict) { 50 return; 51 } 52 53 fPicture = pict; 54 fPicture->ref(); 55 fCanvas.reset(this->setupCanvas()); 56 } 57 58 class FlagsDrawFilter : public SkDrawFilter { 59 public: 60 FlagsDrawFilter(PictureRenderer::DrawFilterFlags* flags) : 61 fFlags(flags) {} 62 63 virtual bool filter(SkPaint* paint, Type t) { 64 paint->setFlags(paint->getFlags() & ~fFlags[t] & SkPaint::kAllFlags); 65 if (PictureRenderer::kBlur_DrawFilterFlag & fFlags[t]) { 66 SkMaskFilter* maskFilter = paint->getMaskFilter(); 67 SkMaskFilter::BlurInfo blurInfo; 68 if (maskFilter && maskFilter->asABlur(&blurInfo)) { 69 paint->setMaskFilter(NULL); 70 } 71 } 72 if (PictureRenderer::kHinting_DrawFilterFlag & fFlags[t]) { 73 paint->setHinting(SkPaint::kNo_Hinting); 74 } else if (PictureRenderer::kSlightHinting_DrawFilterFlag & fFlags[t]) { 75 paint->setHinting(SkPaint::kSlight_Hinting); 76 } 77 return true; 78 } 79 80 private: 81 PictureRenderer::DrawFilterFlags* fFlags; 82 }; 83 84 static void setUpFilter(SkCanvas* canvas, PictureRenderer::DrawFilterFlags* drawFilters) { 85 if (drawFilters && !canvas->getDrawFilter()) { 86 canvas->setDrawFilter(SkNEW_ARGS(FlagsDrawFilter, (drawFilters)))->unref(); 87 if (drawFilters[0] & PictureRenderer::kAAClip_DrawFilterFlag) { 88 canvas->setAllowSoftClip(false); 89 } 90 } 91 } 92 93 SkCanvas* PictureRenderer::setupCanvas() { 94 const int width = this->getViewWidth(); 95 const int height = this->getViewHeight(); 96 return this->setupCanvas(width, height); 97 } 98 99 SkCanvas* PictureRenderer::setupCanvas(int width, int height) { 100 SkCanvas* canvas; 101 switch(fDeviceType) { 102 case kBitmap_DeviceType: { 103 SkBitmap bitmap; 104 sk_tools::setup_bitmap(&bitmap, width, height); 105 canvas = SkNEW_ARGS(SkCanvas, (bitmap)); 106 } 107 break; 108 #if SK_SUPPORT_GPU 109 case kGPU_DeviceType: { 110 SkAutoTUnref<SkGpuDevice> device(SkNEW_ARGS(SkGpuDevice, 111 (fGrContext, SkBitmap::kARGB_8888_Config, 112 width, height))); 113 canvas = SkNEW_ARGS(SkCanvas, (device.get())); 114 } 115 break; 116 #endif 117 default: 118 SkASSERT(0); 119 return NULL; 120 } 121 setUpFilter(canvas, fDrawFilters); 122 this->scaleToScaleFactor(canvas); 123 return canvas; 124 } 125 126 void PictureRenderer::scaleToScaleFactor(SkCanvas* canvas) { 127 SkASSERT(canvas != NULL); 128 if (fScaleFactor != SK_Scalar1) { 129 canvas->scale(fScaleFactor, fScaleFactor); 130 } 131 } 132 133 void PictureRenderer::end() { 134 this->resetState(true); 135 SkSafeUnref(fPicture); 136 fPicture = NULL; 137 fCanvas.reset(NULL); 138 } 139 140 int PictureRenderer::getViewWidth() { 141 SkASSERT(fPicture != NULL); 142 int width = fPicture->width(); 143 if (fViewport.width() > 0) { 144 width = SkMin32(width, fViewport.width()); 145 } 146 return width; 147 } 148 149 int PictureRenderer::getViewHeight() { 150 SkASSERT(fPicture != NULL); 151 int height = fPicture->height(); 152 if (fViewport.height() > 0) { 153 height = SkMin32(height, fViewport.height()); 154 } 155 return height; 156 } 157 158 /** Converts fPicture to a picture that uses a BBoxHierarchy. 159 * PictureRenderer subclasses that are used to test picture playback 160 * should call this method during init. 161 */ 162 void PictureRenderer::buildBBoxHierarchy() { 163 SkASSERT(NULL != fPicture); 164 if (kNone_BBoxHierarchyType != fBBoxHierarchyType && NULL != fPicture) { 165 SkPicture* newPicture = this->createPicture(); 166 SkCanvas* recorder = newPicture->beginRecording(fPicture->width(), fPicture->height(), 167 this->recordFlags()); 168 fPicture->draw(recorder); 169 newPicture->endRecording(); 170 fPicture->unref(); 171 fPicture = newPicture; 172 } 173 } 174 175 void PictureRenderer::resetState(bool callFinish) { 176 #if SK_SUPPORT_GPU 177 if (this->isUsingGpuDevice()) { 178 SkGLContext* glContext = fGrContextFactory.getGLContext( 179 GrContextFactory::kNative_GLContextType); 180 181 SkASSERT(glContext != NULL); 182 if (NULL == glContext) { 183 return; 184 } 185 186 fGrContext->flush(); 187 if (callFinish) { 188 SK_GL(*glContext, Finish()); 189 } 190 } 191 #endif 192 } 193 194 uint32_t PictureRenderer::recordFlags() { 195 return ((kNone_BBoxHierarchyType == fBBoxHierarchyType) ? 0 : 196 SkPicture::kOptimizeForClippedPlayback_RecordingFlag) | 197 SkPicture::kUsePathBoundsForClip_RecordingFlag; 198 } 199 200 /** 201 * Write the canvas to the specified path. 202 * @param canvas Must be non-null. Canvas to be written to a file. 203 * @param path Path for the file to be written. Should have no extension; write() will append 204 * an appropriate one. Passed in by value so it can be modified. 205 * @return bool True if the Canvas is written to a file. 206 */ 207 static bool write(SkCanvas* canvas, SkString path) { 208 SkASSERT(canvas != NULL); 209 if (NULL == canvas) { 210 return false; 211 } 212 213 SkBitmap bitmap; 214 SkISize size = canvas->getDeviceSize(); 215 sk_tools::setup_bitmap(&bitmap, size.width(), size.height()); 216 217 canvas->readPixels(&bitmap, 0, 0); 218 sk_tools::force_all_opaque(bitmap); 219 220 // Since path is passed in by value, it is okay to modify it. 221 path.append(".png"); 222 return SkImageEncoder::EncodeFile(path.c_str(), bitmap, SkImageEncoder::kPNG_Type, 100); 223 } 224 225 /** 226 * If path is non NULL, append number to it, and call write(SkCanvas*, SkString) to write the 227 * provided canvas to a file. Returns true if path is NULL or if write() succeeds. 228 */ 229 static bool writeAppendNumber(SkCanvas* canvas, const SkString* path, int number) { 230 if (NULL == path) { 231 return true; 232 } 233 SkString pathWithNumber(*path); 234 pathWithNumber.appendf("%i", number); 235 return write(canvas, pathWithNumber); 236 } 237 238 /////////////////////////////////////////////////////////////////////////////////////////////// 239 240 SkCanvas* RecordPictureRenderer::setupCanvas(int width, int height) { 241 // defer the canvas setup until the render step 242 return NULL; 243 } 244 245 static bool PNGEncodeBitmapToStream(SkWStream* wStream, const SkBitmap& bm) { 246 return SkImageEncoder::EncodeStream(wStream, bm, SkImageEncoder::kPNG_Type, 100); 247 } 248 249 bool RecordPictureRenderer::render(const SkString* path, SkBitmap** out) { 250 SkAutoTUnref<SkPicture> replayer(this->createPicture()); 251 SkCanvas* recorder = replayer->beginRecording(this->getViewWidth(), this->getViewHeight(), 252 this->recordFlags()); 253 this->scaleToScaleFactor(recorder); 254 fPicture->draw(recorder); 255 replayer->endRecording(); 256 if (path != NULL) { 257 // Record the new picture as a new SKP with PNG encoded bitmaps. 258 SkString skpPath(*path); 259 // ".skp" was removed from 'path' before being passed in here. 260 skpPath.append(".skp"); 261 SkFILEWStream stream(skpPath.c_str()); 262 replayer->serialize(&stream, &PNGEncodeBitmapToStream); 263 return true; 264 } 265 return false; 266 } 267 268 SkString RecordPictureRenderer::getConfigNameInternal() { 269 return SkString("record"); 270 } 271 272 /////////////////////////////////////////////////////////////////////////////////////////////// 273 274 bool PipePictureRenderer::render(const SkString* path, SkBitmap** out) { 275 SkASSERT(fCanvas.get() != NULL); 276 SkASSERT(fPicture != NULL); 277 if (NULL == fCanvas.get() || NULL == fPicture) { 278 return false; 279 } 280 281 PipeController pipeController(fCanvas.get()); 282 SkGPipeWriter writer; 283 SkCanvas* pipeCanvas = writer.startRecording(&pipeController); 284 pipeCanvas->drawPicture(*fPicture); 285 writer.endRecording(); 286 fCanvas->flush(); 287 if (NULL != path) { 288 return write(fCanvas, *path); 289 } 290 if (NULL != out) { 291 *out = SkNEW(SkBitmap); 292 setup_bitmap(*out, fPicture->width(), fPicture->height()); 293 fCanvas->readPixels(*out, 0, 0); 294 } 295 return true; 296 } 297 298 SkString PipePictureRenderer::getConfigNameInternal() { 299 return SkString("pipe"); 300 } 301 302 /////////////////////////////////////////////////////////////////////////////////////////////// 303 304 void SimplePictureRenderer::init(SkPicture* picture) { 305 INHERITED::init(picture); 306 this->buildBBoxHierarchy(); 307 } 308 309 bool SimplePictureRenderer::render(const SkString* path, SkBitmap** out) { 310 SkASSERT(fCanvas.get() != NULL); 311 SkASSERT(fPicture != NULL); 312 if (NULL == fCanvas.get() || NULL == fPicture) { 313 return false; 314 } 315 316 fCanvas->drawPicture(*fPicture); 317 fCanvas->flush(); 318 if (NULL != path) { 319 return write(fCanvas, *path); 320 } 321 322 if (NULL != out) { 323 *out = SkNEW(SkBitmap); 324 setup_bitmap(*out, fPicture->width(), fPicture->height()); 325 fCanvas->readPixels(*out, 0, 0); 326 } 327 328 return true; 329 } 330 331 SkString SimplePictureRenderer::getConfigNameInternal() { 332 return SkString("simple"); 333 } 334 335 /////////////////////////////////////////////////////////////////////////////////////////////// 336 337 TiledPictureRenderer::TiledPictureRenderer() 338 : fTileWidth(kDefaultTileWidth) 339 , fTileHeight(kDefaultTileHeight) 340 , fTileWidthPercentage(0.0) 341 , fTileHeightPercentage(0.0) 342 , fTileMinPowerOf2Width(0) 343 , fCurrentTileOffset(-1) 344 , fTilesX(0) 345 , fTilesY(0) { } 346 347 void TiledPictureRenderer::init(SkPicture* pict) { 348 SkASSERT(pict != NULL); 349 SkASSERT(0 == fTileRects.count()); 350 if (NULL == pict || fTileRects.count() != 0) { 351 return; 352 } 353 354 // Do not call INHERITED::init(), which would create a (potentially large) canvas which is not 355 // used by bench_pictures. 356 fPicture = pict; 357 fPicture->ref(); 358 this->buildBBoxHierarchy(); 359 360 if (fTileWidthPercentage > 0) { 361 fTileWidth = sk_float_ceil2int(float(fTileWidthPercentage * fPicture->width() / 100)); 362 } 363 if (fTileHeightPercentage > 0) { 364 fTileHeight = sk_float_ceil2int(float(fTileHeightPercentage * fPicture->height() / 100)); 365 } 366 367 if (fTileMinPowerOf2Width > 0) { 368 this->setupPowerOf2Tiles(); 369 } else { 370 this->setupTiles(); 371 } 372 fCanvas.reset(this->setupCanvas(fTileWidth, fTileHeight)); 373 // Initialize to -1 so that the first call to nextTile will set this up to draw tile 0 on the 374 // first call to drawCurrentTile. 375 fCurrentTileOffset = -1; 376 } 377 378 void TiledPictureRenderer::end() { 379 fTileRects.reset(); 380 this->INHERITED::end(); 381 } 382 383 void TiledPictureRenderer::setupTiles() { 384 // Only use enough tiles to cover the viewport 385 const int width = this->getViewWidth(); 386 const int height = this->getViewHeight(); 387 388 fTilesX = fTilesY = 0; 389 for (int tile_y_start = 0; tile_y_start < height; tile_y_start += fTileHeight) { 390 fTilesY++; 391 for (int tile_x_start = 0; tile_x_start < width; tile_x_start += fTileWidth) { 392 if (0 == tile_y_start) { 393 // Only count tiles in the X direction on the first pass. 394 fTilesX++; 395 } 396 *fTileRects.append() = SkRect::MakeXYWH(SkIntToScalar(tile_x_start), 397 SkIntToScalar(tile_y_start), 398 SkIntToScalar(fTileWidth), 399 SkIntToScalar(fTileHeight)); 400 } 401 } 402 } 403 404 bool TiledPictureRenderer::tileDimensions(int &x, int &y) { 405 if (fTileRects.count() == 0 || NULL == fPicture) { 406 return false; 407 } 408 x = fTilesX; 409 y = fTilesY; 410 return true; 411 } 412 413 // The goal of the powers of two tiles is to minimize the amount of wasted tile 414 // space in the width-wise direction and then minimize the number of tiles. The 415 // constraints are that every tile must have a pixel width that is a power of 416 // two and also be of some minimal width (that is also a power of two). 417 // 418 // This is solved by first taking our picture size and rounding it up to the 419 // multiple of the minimal width. The binary representation of this rounded 420 // value gives us the tiles we need: a bit of value one means we need a tile of 421 // that size. 422 void TiledPictureRenderer::setupPowerOf2Tiles() { 423 // Only use enough tiles to cover the viewport 424 const int width = this->getViewWidth(); 425 const int height = this->getViewHeight(); 426 427 int rounded_value = width; 428 if (width % fTileMinPowerOf2Width != 0) { 429 rounded_value = width - (width % fTileMinPowerOf2Width) + fTileMinPowerOf2Width; 430 } 431 432 int num_bits = SkScalarCeilToInt(SkScalarLog2(SkIntToScalar(width))); 433 int largest_possible_tile_size = 1 << num_bits; 434 435 fTilesX = fTilesY = 0; 436 // The tile height is constant for a particular picture. 437 for (int tile_y_start = 0; tile_y_start < height; tile_y_start += fTileHeight) { 438 fTilesY++; 439 int tile_x_start = 0; 440 int current_width = largest_possible_tile_size; 441 // Set fTileWidth to be the width of the widest tile, so that each canvas is large enough 442 // to draw each tile. 443 fTileWidth = current_width; 444 445 while (current_width >= fTileMinPowerOf2Width) { 446 // It is very important this is a bitwise AND. 447 if (current_width & rounded_value) { 448 if (0 == tile_y_start) { 449 // Only count tiles in the X direction on the first pass. 450 fTilesX++; 451 } 452 *fTileRects.append() = SkRect::MakeXYWH(SkIntToScalar(tile_x_start), 453 SkIntToScalar(tile_y_start), 454 SkIntToScalar(current_width), 455 SkIntToScalar(fTileHeight)); 456 tile_x_start += current_width; 457 } 458 459 current_width >>= 1; 460 } 461 } 462 } 463 464 /** 465 * Draw the specified playback to the canvas translated to rectangle provided, so that this mini 466 * canvas represents the rectangle's portion of the overall picture. 467 * Saves and restores so that the initial clip and matrix return to their state before this function 468 * is called. 469 */ 470 template<class T> 471 static void DrawTileToCanvas(SkCanvas* canvas, const SkRect& tileRect, T* playback) { 472 int saveCount = canvas->save(); 473 // Translate so that we draw the correct portion of the picture. 474 // Perform a postTranslate so that the scaleFactor does not interfere with the positioning. 475 SkMatrix mat(canvas->getTotalMatrix()); 476 mat.postTranslate(-tileRect.fLeft, -tileRect.fTop); 477 canvas->setMatrix(mat); 478 playback->draw(canvas); 479 canvas->restoreToCount(saveCount); 480 canvas->flush(); 481 } 482 483 /////////////////////////////////////////////////////////////////////////////////////////////// 484 485 static void bitmapCopySubset(const SkBitmap& src, SkBitmap* dst, int xDst, 486 int yDst) { 487 for (int y = 0; y <src.height() && y + yDst < dst->height() ; y++) { 488 for (int x = 0; x < src.width() && x + xDst < dst->width() ; x++) { 489 *dst->getAddr32(xDst + x, yDst + y) = *src.getAddr32(x, y); 490 } 491 } 492 } 493 494 bool TiledPictureRenderer::nextTile(int &i, int &j) { 495 if (++fCurrentTileOffset < fTileRects.count()) { 496 i = fCurrentTileOffset % fTilesX; 497 j = fCurrentTileOffset / fTilesX; 498 return true; 499 } 500 return false; 501 } 502 503 void TiledPictureRenderer::drawCurrentTile() { 504 SkASSERT(fCurrentTileOffset >= 0 && fCurrentTileOffset < fTileRects.count()); 505 DrawTileToCanvas(fCanvas, fTileRects[fCurrentTileOffset], fPicture); 506 } 507 508 bool TiledPictureRenderer::render(const SkString* path, SkBitmap** out) { 509 SkASSERT(fPicture != NULL); 510 if (NULL == fPicture) { 511 return false; 512 } 513 514 SkBitmap bitmap; 515 if (out){ 516 *out = SkNEW(SkBitmap); 517 setup_bitmap(*out, fPicture->width(), fPicture->height()); 518 setup_bitmap(&bitmap, fTileWidth, fTileHeight); 519 } 520 bool success = true; 521 for (int i = 0; i < fTileRects.count(); ++i) { 522 DrawTileToCanvas(fCanvas, fTileRects[i], fPicture); 523 if (NULL != path) { 524 success &= writeAppendNumber(fCanvas, path, i); 525 } 526 if (NULL != out) { 527 if (fCanvas->readPixels(&bitmap, 0, 0)) { 528 bitmapCopySubset(bitmap, *out, SkScalarFloorToInt(fTileRects[i].left()), 529 SkScalarFloorToInt(fTileRects[i].top())); 530 } else { 531 success = false; 532 } 533 } 534 } 535 return success; 536 } 537 538 SkCanvas* TiledPictureRenderer::setupCanvas(int width, int height) { 539 SkCanvas* canvas = this->INHERITED::setupCanvas(width, height); 540 SkASSERT(fPicture != NULL); 541 // Clip the tile to an area that is completely inside both the SkPicture and the viewport. This 542 // is mostly important for tiles on the right and bottom edges as they may go over this area and 543 // the picture may have some commands that draw outside of this area and so should not actually 544 // be written. 545 // Uses a clipRegion so that it will be unaffected by the scale factor, which may have been set 546 // by INHERITED::setupCanvas. 547 SkRegion clipRegion; 548 clipRegion.setRect(0, 0, this->getViewWidth(), this->getViewHeight()); 549 canvas->clipRegion(clipRegion); 550 return canvas; 551 } 552 553 SkString TiledPictureRenderer::getConfigNameInternal() { 554 SkString name; 555 if (fTileMinPowerOf2Width > 0) { 556 name.append("pow2tile_"); 557 name.appendf("%i", fTileMinPowerOf2Width); 558 } else { 559 name.append("tile_"); 560 if (fTileWidthPercentage > 0) { 561 name.appendf("%.f%%", fTileWidthPercentage); 562 } else { 563 name.appendf("%i", fTileWidth); 564 } 565 } 566 name.append("x"); 567 if (fTileHeightPercentage > 0) { 568 name.appendf("%.f%%", fTileHeightPercentage); 569 } else { 570 name.appendf("%i", fTileHeight); 571 } 572 return name; 573 } 574 575 /////////////////////////////////////////////////////////////////////////////////////////////// 576 577 // Holds all of the information needed to draw a set of tiles. 578 class CloneData : public SkRunnable { 579 580 public: 581 CloneData(SkPicture* clone, SkCanvas* canvas, SkTDArray<SkRect>& rects, int start, int end, 582 SkRunnable* done) 583 : fClone(clone) 584 , fCanvas(canvas) 585 , fPath(NULL) 586 , fRects(rects) 587 , fStart(start) 588 , fEnd(end) 589 , fSuccess(NULL) 590 , fDone(done) { 591 SkASSERT(fDone != NULL); 592 } 593 594 virtual void run() SK_OVERRIDE { 595 SkGraphics::SetTLSFontCacheLimit(1024 * 1024); 596 597 SkBitmap bitmap; 598 if (fBitmap != NULL) { 599 // All tiles are the same size. 600 setup_bitmap(&bitmap, SkScalarFloorToInt(fRects[0].width()), SkScalarFloorToInt(fRects[0].height())); 601 } 602 603 for (int i = fStart; i < fEnd; i++) { 604 DrawTileToCanvas(fCanvas, fRects[i], fClone); 605 if (fPath != NULL && !writeAppendNumber(fCanvas, fPath, i) 606 && fSuccess != NULL) { 607 *fSuccess = false; 608 // If one tile fails to write to a file, do not continue drawing the rest. 609 break; 610 } 611 if (fBitmap != NULL) { 612 if (fCanvas->readPixels(&bitmap, 0, 0)) { 613 SkAutoLockPixels alp(*fBitmap); 614 bitmapCopySubset(bitmap, fBitmap, SkScalarFloorToInt(fRects[i].left()), 615 SkScalarFloorToInt(fRects[i].top())); 616 } else { 617 *fSuccess = false; 618 // If one tile fails to read pixels, do not continue drawing the rest. 619 break; 620 } 621 } 622 } 623 fDone->run(); 624 } 625 626 void setPathAndSuccess(const SkString* path, bool* success) { 627 fPath = path; 628 fSuccess = success; 629 } 630 631 void setBitmap(SkBitmap* bitmap) { 632 fBitmap = bitmap; 633 } 634 635 private: 636 // All pointers unowned. 637 SkPicture* fClone; // Picture to draw from. Each CloneData has a unique one which 638 // is threadsafe. 639 SkCanvas* fCanvas; // Canvas to draw to. Reused for each tile. 640 const SkString* fPath; // If non-null, path to write the result to as a PNG. 641 SkTDArray<SkRect>& fRects; // All tiles of the picture. 642 const int fStart; // Range of tiles drawn by this thread. 643 const int fEnd; 644 bool* fSuccess; // Only meaningful if path is non-null. Shared by all threads, 645 // and only set to false upon failure to write to a PNG. 646 SkRunnable* fDone; 647 SkBitmap* fBitmap; 648 }; 649 650 MultiCorePictureRenderer::MultiCorePictureRenderer(int threadCount) 651 : fNumThreads(threadCount) 652 , fThreadPool(threadCount) 653 , fCountdown(threadCount) { 654 // Only need to create fNumThreads - 1 clones, since one thread will use the base 655 // picture. 656 fPictureClones = SkNEW_ARRAY(SkPicture, fNumThreads - 1); 657 fCloneData = SkNEW_ARRAY(CloneData*, fNumThreads); 658 } 659 660 void MultiCorePictureRenderer::init(SkPicture *pict) { 661 // Set fPicture and the tiles. 662 this->INHERITED::init(pict); 663 for (int i = 0; i < fNumThreads; ++i) { 664 *fCanvasPool.append() = this->setupCanvas(this->getTileWidth(), this->getTileHeight()); 665 } 666 // Only need to create fNumThreads - 1 clones, since one thread will use the base picture. 667 fPicture->clone(fPictureClones, fNumThreads - 1); 668 // Populate each thread with the appropriate data. 669 // Group the tiles into nearly equal size chunks, rounding up so we're sure to cover them all. 670 const int chunkSize = (fTileRects.count() + fNumThreads - 1) / fNumThreads; 671 672 for (int i = 0; i < fNumThreads; i++) { 673 SkPicture* pic; 674 if (i == fNumThreads-1) { 675 // The last set will use the original SkPicture. 676 pic = fPicture; 677 } else { 678 pic = &fPictureClones[i]; 679 } 680 const int start = i * chunkSize; 681 const int end = SkMin32(start + chunkSize, fTileRects.count()); 682 fCloneData[i] = SkNEW_ARGS(CloneData, 683 (pic, fCanvasPool[i], fTileRects, start, end, &fCountdown)); 684 } 685 } 686 687 bool MultiCorePictureRenderer::render(const SkString *path, SkBitmap** out) { 688 bool success = true; 689 if (path != NULL) { 690 for (int i = 0; i < fNumThreads-1; i++) { 691 fCloneData[i]->setPathAndSuccess(path, &success); 692 } 693 } 694 695 if (NULL != out) { 696 *out = SkNEW(SkBitmap); 697 setup_bitmap(*out, fPicture->width(), fPicture->height()); 698 for (int i = 0; i < fNumThreads; i++) { 699 fCloneData[i]->setBitmap(*out); 700 } 701 } else { 702 for (int i = 0; i < fNumThreads; i++) { 703 fCloneData[i]->setBitmap(NULL); 704 } 705 } 706 707 fCountdown.reset(fNumThreads); 708 for (int i = 0; i < fNumThreads; i++) { 709 fThreadPool.add(fCloneData[i]); 710 } 711 fCountdown.wait(); 712 713 return success; 714 } 715 716 void MultiCorePictureRenderer::end() { 717 for (int i = 0; i < fNumThreads - 1; i++) { 718 SkDELETE(fCloneData[i]); 719 fCloneData[i] = NULL; 720 } 721 722 fCanvasPool.unrefAll(); 723 724 this->INHERITED::end(); 725 } 726 727 MultiCorePictureRenderer::~MultiCorePictureRenderer() { 728 // Each individual CloneData was deleted in end. 729 SkDELETE_ARRAY(fCloneData); 730 SkDELETE_ARRAY(fPictureClones); 731 } 732 733 SkString MultiCorePictureRenderer::getConfigNameInternal() { 734 SkString name = this->INHERITED::getConfigNameInternal(); 735 name.appendf("_multi_%i_threads", fNumThreads); 736 return name; 737 } 738 739 /////////////////////////////////////////////////////////////////////////////////////////////// 740 741 void PlaybackCreationRenderer::setup() { 742 fReplayer.reset(this->createPicture()); 743 SkCanvas* recorder = fReplayer->beginRecording(this->getViewWidth(), this->getViewHeight(), 744 this->recordFlags()); 745 this->scaleToScaleFactor(recorder); 746 fPicture->draw(recorder); 747 } 748 749 bool PlaybackCreationRenderer::render(const SkString*, SkBitmap** out) { 750 fReplayer->endRecording(); 751 // Since this class does not actually render, return false. 752 return false; 753 } 754 755 SkString PlaybackCreationRenderer::getConfigNameInternal() { 756 return SkString("playback_creation"); 757 } 758 759 /////////////////////////////////////////////////////////////////////////////////////////////// 760 // SkPicture variants for each BBoxHierarchy type 761 762 class RTreePicture : public SkPicture { 763 public: 764 virtual SkBBoxHierarchy* createBBoxHierarchy() const SK_OVERRIDE{ 765 static const int kRTreeMinChildren = 6; 766 static const int kRTreeMaxChildren = 11; 767 SkScalar aspectRatio = SkScalarDiv(SkIntToScalar(fWidth), 768 SkIntToScalar(fHeight)); 769 return SkRTree::Create(kRTreeMinChildren, kRTreeMaxChildren, 770 aspectRatio); 771 } 772 }; 773 774 SkPicture* PictureRenderer::createPicture() { 775 switch (fBBoxHierarchyType) { 776 case kNone_BBoxHierarchyType: 777 return SkNEW(SkPicture); 778 case kRTree_BBoxHierarchyType: 779 return SkNEW(RTreePicture); 780 case kTileGrid_BBoxHierarchyType: 781 return SkNEW_ARGS(SkTileGridPicture, (fGridWidth, fGridHeight, fPicture->width(), 782 fPicture->height())); 783 } 784 SkASSERT(0); // invalid bbhType 785 return NULL; 786 } 787 788 /////////////////////////////////////////////////////////////////////////////// 789 790 class GatherRenderer : public PictureRenderer { 791 public: 792 virtual bool render(const SkString* path, SkBitmap** out = NULL) 793 SK_OVERRIDE { 794 SkRect bounds = SkRect::MakeWH(SkIntToScalar(fPicture->width()), 795 SkIntToScalar(fPicture->height())); 796 SkData* data = SkPictureUtils::GatherPixelRefs(fPicture, bounds); 797 SkSafeUnref(data); 798 799 return NULL == path; // we don't have anything to write 800 } 801 802 private: 803 virtual SkString getConfigNameInternal() SK_OVERRIDE { 804 return SkString("gather_pixelrefs"); 805 } 806 }; 807 808 PictureRenderer* CreateGatherPixelRefsRenderer() { 809 return SkNEW(GatherRenderer); 810 } 811 812 /////////////////////////////////////////////////////////////////////////////// 813 814 class PictureCloneRenderer : public PictureRenderer { 815 public: 816 virtual bool render(const SkString* path, SkBitmap** out = NULL) 817 SK_OVERRIDE { 818 for (int i = 0; i < 100; ++i) { 819 SkPicture* clone = fPicture->clone(); 820 SkSafeUnref(clone); 821 } 822 823 return NULL == path; // we don't have anything to write 824 } 825 826 private: 827 virtual SkString getConfigNameInternal() SK_OVERRIDE { 828 return SkString("picture_clone"); 829 } 830 }; 831 832 PictureRenderer* CreatePictureCloneRenderer() { 833 return SkNEW(PictureCloneRenderer); 834 } 835 836 } // namespace sk_tools 837