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