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