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 "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