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