Home | History | Annotate | Download | only in tools
      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