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