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