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