PictureRenderer.cpp revision 070d354d51dac52a70f07d4b102392b89f2da5d7
1b3fb7c1f467c4d43dff0d98683d3043f0176e07ckeyar@chromium.org/*
2b3fb7c1f467c4d43dff0d98683d3043f0176e07ckeyar@chromium.org * Copyright 2012 Google Inc.
3b3fb7c1f467c4d43dff0d98683d3043f0176e07ckeyar@chromium.org *
4b3fb7c1f467c4d43dff0d98683d3043f0176e07ckeyar@chromium.org * Use of this source code is governed by a BSD-style license that can be
5b3fb7c1f467c4d43dff0d98683d3043f0176e07ckeyar@chromium.org * found in the LICENSE file.
6b3fb7c1f467c4d43dff0d98683d3043f0176e07ckeyar@chromium.org */
7b3fb7c1f467c4d43dff0d98683d3043f0176e07ckeyar@chromium.org
8451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org#include "PictureRenderer.h"
958b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com#include "picture_utils.h"
10451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org#include "SamplePipeControllers.h"
11451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org#include "SkCanvas.h"
12451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org#include "SkDevice.h"
13451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org#include "SkGPipe.h"
1458b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com#if SK_SUPPORT_GPU
1558b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com#include "SkGpuDevice.h"
1658b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com#endif
1758b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com#include "SkGraphics.h"
1858b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com#include "SkImageEncoder.h"
19ea82695325e2afc68f646fcc23fcae8b1bff6dc1keyar@chromium.org#include "SkMatrix.h"
20451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org#include "SkPicture.h"
21ea82695325e2afc68f646fcc23fcae8b1bff6dc1keyar@chromium.org#include "SkScalar.h"
229299eded3838a7997235ff033aa3b9a8d4c6d4d4keyar@chromium.org#include "SkString.h"
2358b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com#include "SkTemplates.h"
24451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org#include "SkTDArray.h"
2558b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com#include "SkThreadUtils.h"
26451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org#include "SkTypes.h"
274ea96c5e5449248780acfeb3cef4ec812f955d74keyar@chromium.org
28451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.orgnamespace sk_tools {
29451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org
30451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.orgenum {
31451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org    kDefaultTileWidth = 256,
32451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org    kDefaultTileHeight = 256
33451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org};
34451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org
359d696c0d04548520af08252e577d2ca88012a239keyar@chromium.orgvoid PictureRenderer::init(SkPicture* pict) {
3678a35c5f1dcc00b2b442069a94f9e7c996f8d7f9keyar@chromium.org    SkASSERT(NULL == fPicture);
3778a35c5f1dcc00b2b442069a94f9e7c996f8d7f9keyar@chromium.org    SkASSERT(NULL == fCanvas.get());
3878a35c5f1dcc00b2b442069a94f9e7c996f8d7f9keyar@chromium.org    if (fPicture != NULL || NULL != fCanvas.get()) {
399d696c0d04548520af08252e577d2ca88012a239keyar@chromium.org        return;
409d696c0d04548520af08252e577d2ca88012a239keyar@chromium.org    }
419d696c0d04548520af08252e577d2ca88012a239keyar@chromium.org
429d696c0d04548520af08252e577d2ca88012a239keyar@chromium.org    SkASSERT(pict != NULL);
4378a35c5f1dcc00b2b442069a94f9e7c996f8d7f9keyar@chromium.org    if (NULL == pict) {
449d696c0d04548520af08252e577d2ca88012a239keyar@chromium.org        return;
459d696c0d04548520af08252e577d2ca88012a239keyar@chromium.org    }
469d696c0d04548520af08252e577d2ca88012a239keyar@chromium.org
479d696c0d04548520af08252e577d2ca88012a239keyar@chromium.org    fPicture = pict;
48a474ce3c0b7f72539e20a57b583b99046dfb7706keyar@chromium.org    fCanvas.reset(this->setupCanvas());
49a474ce3c0b7f72539e20a57b583b99046dfb7706keyar@chromium.org}
50a474ce3c0b7f72539e20a57b583b99046dfb7706keyar@chromium.org
51a474ce3c0b7f72539e20a57b583b99046dfb7706keyar@chromium.orgSkCanvas* PictureRenderer::setupCanvas() {
52a474ce3c0b7f72539e20a57b583b99046dfb7706keyar@chromium.org    return this->setupCanvas(fPicture->width(), fPicture->height());
53a474ce3c0b7f72539e20a57b583b99046dfb7706keyar@chromium.org}
54a474ce3c0b7f72539e20a57b583b99046dfb7706keyar@chromium.org
55a474ce3c0b7f72539e20a57b583b99046dfb7706keyar@chromium.orgSkCanvas* PictureRenderer::setupCanvas(int width, int height) {
564ea96c5e5449248780acfeb3cef4ec812f955d74keyar@chromium.org    switch(fDeviceType) {
574ea96c5e5449248780acfeb3cef4ec812f955d74keyar@chromium.org        case kBitmap_DeviceType: {
584ea96c5e5449248780acfeb3cef4ec812f955d74keyar@chromium.org            SkBitmap bitmap;
59a474ce3c0b7f72539e20a57b583b99046dfb7706keyar@chromium.org            sk_tools::setup_bitmap(&bitmap, width, height);
60a474ce3c0b7f72539e20a57b583b99046dfb7706keyar@chromium.org            return SkNEW_ARGS(SkCanvas, (bitmap));
614ea96c5e5449248780acfeb3cef4ec812f955d74keyar@chromium.org            break;
624ea96c5e5449248780acfeb3cef4ec812f955d74keyar@chromium.org        }
634ea96c5e5449248780acfeb3cef4ec812f955d74keyar@chromium.org#if SK_SUPPORT_GPU
644ea96c5e5449248780acfeb3cef4ec812f955d74keyar@chromium.org        case kGPU_DeviceType: {
654ea96c5e5449248780acfeb3cef4ec812f955d74keyar@chromium.org            SkAutoTUnref<SkGpuDevice> device(SkNEW_ARGS(SkGpuDevice,
660612564bb76ec533d26d87e03368fd81ef97831ekeyar@chromium.org                                                    (fGrContext, SkBitmap::kARGB_8888_Config,
67a474ce3c0b7f72539e20a57b583b99046dfb7706keyar@chromium.org                                                    width, height)));
68a474ce3c0b7f72539e20a57b583b99046dfb7706keyar@chromium.org            return SkNEW_ARGS(SkCanvas, (device.get()));
694ea96c5e5449248780acfeb3cef4ec812f955d74keyar@chromium.org            break;
704ea96c5e5449248780acfeb3cef4ec812f955d74keyar@chromium.org        }
714ea96c5e5449248780acfeb3cef4ec812f955d74keyar@chromium.org#endif
724ea96c5e5449248780acfeb3cef4ec812f955d74keyar@chromium.org        default:
734ea96c5e5449248780acfeb3cef4ec812f955d74keyar@chromium.org            SkASSERT(0);
744ea96c5e5449248780acfeb3cef4ec812f955d74keyar@chromium.org    }
75a474ce3c0b7f72539e20a57b583b99046dfb7706keyar@chromium.org
76a474ce3c0b7f72539e20a57b583b99046dfb7706keyar@chromium.org    return NULL;
779d696c0d04548520af08252e577d2ca88012a239keyar@chromium.org}
789d696c0d04548520af08252e577d2ca88012a239keyar@chromium.org
799d696c0d04548520af08252e577d2ca88012a239keyar@chromium.orgvoid PictureRenderer::end() {
8077a5522d0e4437ef2b856acd7b135b6afda64ceekeyar@chromium.org    this->resetState();
819d696c0d04548520af08252e577d2ca88012a239keyar@chromium.org    fPicture = NULL;
829d696c0d04548520af08252e577d2ca88012a239keyar@chromium.org    fCanvas.reset(NULL);
839d696c0d04548520af08252e577d2ca88012a239keyar@chromium.org}
849d696c0d04548520af08252e577d2ca88012a239keyar@chromium.org
8577a5522d0e4437ef2b856acd7b135b6afda64ceekeyar@chromium.orgvoid PictureRenderer::resetState() {
8628136b308fe467da113983cfee332faea133cd8akeyar@chromium.org#if SK_SUPPORT_GPU
8728136b308fe467da113983cfee332faea133cd8akeyar@chromium.org    if (this->isUsingGpuDevice()) {
8828136b308fe467da113983cfee332faea133cd8akeyar@chromium.org        SkGLContext* glContext = fGrContextFactory.getGLContext(
8928136b308fe467da113983cfee332faea133cd8akeyar@chromium.org            GrContextFactory::kNative_GLContextType);
9028136b308fe467da113983cfee332faea133cd8akeyar@chromium.org
9128136b308fe467da113983cfee332faea133cd8akeyar@chromium.org        SkASSERT(glContext != NULL);
9228136b308fe467da113983cfee332faea133cd8akeyar@chromium.org        if (NULL == glContext) {
9328136b308fe467da113983cfee332faea133cd8akeyar@chromium.org            return;
9428136b308fe467da113983cfee332faea133cd8akeyar@chromium.org        }
9528136b308fe467da113983cfee332faea133cd8akeyar@chromium.org
969a4125283ad56cea3b986337cb669dde14bf0ed8scroggo@google.com        fGrContext->flush();
9777a5522d0e4437ef2b856acd7b135b6afda64ceekeyar@chromium.org        SK_GL(*glContext, Finish());
9877a5522d0e4437ef2b856acd7b135b6afda64ceekeyar@chromium.org    }
99a40c20df0e4c5d04acb0841d70127778c0a779eckeyar@chromium.org#endif
10077a5522d0e4437ef2b856acd7b135b6afda64ceekeyar@chromium.org}
10177a5522d0e4437ef2b856acd7b135b6afda64ceekeyar@chromium.org
102b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com/**
103b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com * Write the canvas to the specified path.
104b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com * @param canvas Must be non-null. Canvas to be written to a file.
105b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com * @param path Path for the file to be written. Should have no extension; write() will append
106b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com *             an appropriate one. Passed in by value so it can be modified.
107b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com * @return bool True if the Canvas is written to a file.
108b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com */
109b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.comstatic bool write(SkCanvas* canvas, SkString path) {
11081f9d2e05be4902993345dac93337158345c660bscroggo@google.com    SkASSERT(canvas != NULL);
111b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com    if (NULL == canvas) {
1129299eded3838a7997235ff033aa3b9a8d4c6d4d4keyar@chromium.org        return false;
1139299eded3838a7997235ff033aa3b9a8d4c6d4d4keyar@chromium.org    }
1149299eded3838a7997235ff033aa3b9a8d4c6d4d4keyar@chromium.org
1159299eded3838a7997235ff033aa3b9a8d4c6d4d4keyar@chromium.org    SkBitmap bitmap;
11681f9d2e05be4902993345dac93337158345c660bscroggo@google.com    SkISize size = canvas->getDeviceSize();
11781f9d2e05be4902993345dac93337158345c660bscroggo@google.com    sk_tools::setup_bitmap(&bitmap, size.width(), size.height());
1189299eded3838a7997235ff033aa3b9a8d4c6d4d4keyar@chromium.org
11981f9d2e05be4902993345dac93337158345c660bscroggo@google.com    canvas->readPixels(&bitmap, 0, 0);
1209299eded3838a7997235ff033aa3b9a8d4c6d4d4keyar@chromium.org    sk_tools::force_all_opaque(bitmap);
1219299eded3838a7997235ff033aa3b9a8d4c6d4d4keyar@chromium.org
12281f9d2e05be4902993345dac93337158345c660bscroggo@google.com    // Since path is passed in by value, it is okay to modify it.
12381f9d2e05be4902993345dac93337158345c660bscroggo@google.com    path.append(".png");
1249299eded3838a7997235ff033aa3b9a8d4c6d4d4keyar@chromium.org    return SkImageEncoder::EncodeFile(path.c_str(), bitmap, SkImageEncoder::kPNG_Type, 100);
1259299eded3838a7997235ff033aa3b9a8d4c6d4d4keyar@chromium.org}
1269299eded3838a7997235ff033aa3b9a8d4c6d4d4keyar@chromium.org
127b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com/**
128b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com * If path is non NULL, append number to it, and call write(SkCanvas*, SkString) to write the
129b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com * provided canvas to a file. Returns true if path is NULL or if write() succeeds.
130b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com */
131b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.comstatic bool writeAppendNumber(SkCanvas* canvas, const SkString* path, int number) {
132b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com    if (NULL == path) {
133b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com        return true;
134b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com    }
135b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com    SkString pathWithNumber(*path);
136b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com    pathWithNumber.appendf("%i", number);
137b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com    return write(canvas, pathWithNumber);
138b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com}
139b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com
140acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com///////////////////////////////////////////////////////////////////////////////////////////////
141acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com
14281f9d2e05be4902993345dac93337158345c660bscroggo@google.combool RecordPictureRenderer::render(const SkString*) {
1439a4125283ad56cea3b986337cb669dde14bf0ed8scroggo@google.com    SkPicture replayer;
1449a4125283ad56cea3b986337cb669dde14bf0ed8scroggo@google.com    SkCanvas* recorder = replayer.beginRecording(fPicture->width(), fPicture->height());
1459a4125283ad56cea3b986337cb669dde14bf0ed8scroggo@google.com    fPicture->draw(recorder);
1469a4125283ad56cea3b986337cb669dde14bf0ed8scroggo@google.com    replayer.endRecording();
14781f9d2e05be4902993345dac93337158345c660bscroggo@google.com    // Since this class does not actually render, return false.
14881f9d2e05be4902993345dac93337158345c660bscroggo@google.com    return false;
1499a4125283ad56cea3b986337cb669dde14bf0ed8scroggo@google.com}
1509a4125283ad56cea3b986337cb669dde14bf0ed8scroggo@google.com
151acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com///////////////////////////////////////////////////////////////////////////////////////////////
152acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com
15381f9d2e05be4902993345dac93337158345c660bscroggo@google.combool PipePictureRenderer::render(const SkString* path) {
1549d696c0d04548520af08252e577d2ca88012a239keyar@chromium.org    SkASSERT(fCanvas.get() != NULL);
1559d696c0d04548520af08252e577d2ca88012a239keyar@chromium.org    SkASSERT(fPicture != NULL);
15678a35c5f1dcc00b2b442069a94f9e7c996f8d7f9keyar@chromium.org    if (NULL == fCanvas.get() || NULL == fPicture) {
15781f9d2e05be4902993345dac93337158345c660bscroggo@google.com        return false;
1589d696c0d04548520af08252e577d2ca88012a239keyar@chromium.org    }
1599d696c0d04548520af08252e577d2ca88012a239keyar@chromium.org
1609d696c0d04548520af08252e577d2ca88012a239keyar@chromium.org    PipeController pipeController(fCanvas.get());
161451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org    SkGPipeWriter writer;
162451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org    SkCanvas* pipeCanvas = writer.startRecording(&pipeController);
1639d696c0d04548520af08252e577d2ca88012a239keyar@chromium.org    pipeCanvas->drawPicture(*fPicture);
164451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org    writer.endRecording();
1659a4125283ad56cea3b986337cb669dde14bf0ed8scroggo@google.com    fCanvas->flush();
166070d354d51dac52a70f07d4b102392b89f2da5d7borenet@google.com    if (NULL != path) {
167070d354d51dac52a70f07d4b102392b89f2da5d7borenet@google.com        return write(fCanvas, *path);
168070d354d51dac52a70f07d4b102392b89f2da5d7borenet@google.com    }
169070d354d51dac52a70f07d4b102392b89f2da5d7borenet@google.com    return true;
170451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org}
171451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org
172acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com///////////////////////////////////////////////////////////////////////////////////////////////
173acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com
17481f9d2e05be4902993345dac93337158345c660bscroggo@google.combool SimplePictureRenderer::render(const SkString* path) {
1759d696c0d04548520af08252e577d2ca88012a239keyar@chromium.org    SkASSERT(fCanvas.get() != NULL);
1769d696c0d04548520af08252e577d2ca88012a239keyar@chromium.org    SkASSERT(fPicture != NULL);
17778a35c5f1dcc00b2b442069a94f9e7c996f8d7f9keyar@chromium.org    if (NULL == fCanvas.get() || NULL == fPicture) {
17881f9d2e05be4902993345dac93337158345c660bscroggo@google.com        return false;
1799d696c0d04548520af08252e577d2ca88012a239keyar@chromium.org    }
1809d696c0d04548520af08252e577d2ca88012a239keyar@chromium.org
1819d696c0d04548520af08252e577d2ca88012a239keyar@chromium.org    fCanvas->drawPicture(*fPicture);
1829a4125283ad56cea3b986337cb669dde14bf0ed8scroggo@google.com    fCanvas->flush();
183070d354d51dac52a70f07d4b102392b89f2da5d7borenet@google.com    if (NULL != path) {
184070d354d51dac52a70f07d4b102392b89f2da5d7borenet@google.com        return write(fCanvas, *path);
185070d354d51dac52a70f07d4b102392b89f2da5d7borenet@google.com    }
186070d354d51dac52a70f07d4b102392b89f2da5d7borenet@google.com    return true;
187451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org}
188451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org
189acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com///////////////////////////////////////////////////////////////////////////////////////////////
190acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com
191451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.orgTiledPictureRenderer::TiledPictureRenderer()
192bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    : fUsePipe(false)
19358b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com    , fTileWidth(kDefaultTileWidth)
194b947b91794f47cc92b17c83e570536f5e315a118rileya@google.com    , fTileHeight(kDefaultTileHeight)
195a04dc02b118363fedf3a7b11cfcdab886d368f8arileya@google.com    , fTileWidthPercentage(0.0)
196b947b91794f47cc92b17c83e570536f5e315a118rileya@google.com    , fTileHeightPercentage(0.0)
197bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    , fTileMinPowerOf2Width(0)
198bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    , fTileCounter(0)
199bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    , fNumThreads(1)
200bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    , fPictureClones(NULL)
201bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    , fPipeController(NULL) { }
202451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org
2039d696c0d04548520af08252e577d2ca88012a239keyar@chromium.orgvoid TiledPictureRenderer::init(SkPicture* pict) {
2049d696c0d04548520af08252e577d2ca88012a239keyar@chromium.org    SkASSERT(pict != NULL);
205acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com    SkASSERT(0 == fTileRects.count());
206acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com    if (NULL == pict || fTileRects.count() != 0) {
2079d696c0d04548520af08252e577d2ca88012a239keyar@chromium.org        return;
2089d696c0d04548520af08252e577d2ca88012a239keyar@chromium.org    }
2099d696c0d04548520af08252e577d2ca88012a239keyar@chromium.org
210acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com    // Do not call INHERITED::init(), which would create a (potentially large) canvas which is not
211acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com    // used by bench_pictures.
212acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com    fPicture = pict;
213cc6e5efe03bfeda903d67d2bacd9ed0be58572bakeyar@chromium.org
214cc6e5efe03bfeda903d67d2bacd9ed0be58572bakeyar@chromium.org    if (fTileWidthPercentage > 0) {
2155d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com        fTileWidth = sk_float_ceil2int(float(fTileWidthPercentage * fPicture->width() / 100));
216cc6e5efe03bfeda903d67d2bacd9ed0be58572bakeyar@chromium.org    }
217cc6e5efe03bfeda903d67d2bacd9ed0be58572bakeyar@chromium.org    if (fTileHeightPercentage > 0) {
2185d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com        fTileHeight = sk_float_ceil2int(float(fTileHeightPercentage * fPicture->height() / 100));
219cc6e5efe03bfeda903d67d2bacd9ed0be58572bakeyar@chromium.org    }
220cc6e5efe03bfeda903d67d2bacd9ed0be58572bakeyar@chromium.org
221f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org    if (fTileMinPowerOf2Width > 0) {
222f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org        this->setupPowerOf2Tiles();
223f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org    } else {
224f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org        this->setupTiles();
225f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org    }
226bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com
227bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    if (this->multiThreaded()) {
228bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com        for (int i = 0; i < fNumThreads; ++i) {
229bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com            *fCanvasPool.append() = this->setupCanvas(fTileWidth, fTileHeight);
230bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com        }
231bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com        if (!fUsePipe) {
232bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com            SkASSERT(NULL == fPictureClones);
233bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com            // Only need to create fNumThreads - 1 clones, since one thread will use the base
234bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com            // picture.
235bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com            int numberOfClones = fNumThreads - 1;
236bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com            // This will be deleted in end().
237bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com            fPictureClones = SkNEW_ARRAY(SkPicture, numberOfClones);
238b4773b4802236fab24cfc63ed8b9ed7eb35f65ccscroggo@google.com            fPicture->clone(fPictureClones, numberOfClones);
239bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com        }
240bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    }
241451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org}
242451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org
2439d696c0d04548520af08252e577d2ca88012a239keyar@chromium.orgvoid TiledPictureRenderer::end() {
244bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    fTileRects.reset();
245bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    SkDELETE_ARRAY(fPictureClones);
246bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    fPictureClones = NULL;
247bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    fCanvasPool.unrefAll();
248bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    if (fPipeController != NULL) {
249bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com        SkASSERT(fUsePipe);
250bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com        SkDELETE(fPipeController);
251bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com        fPipeController = NULL;
252bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    }
2539d696c0d04548520af08252e577d2ca88012a239keyar@chromium.org    this->INHERITED::end();
254451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org}
255451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org
256451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.orgTiledPictureRenderer::~TiledPictureRenderer() {
257bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    // end() must be called to delete fPictureClones and fPipeController
258bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    SkASSERT(NULL == fPictureClones);
259bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    SkASSERT(NULL == fPipeController);
260451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org}
261451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org
2629d696c0d04548520af08252e577d2ca88012a239keyar@chromium.orgvoid TiledPictureRenderer::setupTiles() {
263acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com    for (int tile_y_start = 0; tile_y_start < fPicture->height(); tile_y_start += fTileHeight) {
264acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com        for (int tile_x_start = 0; tile_x_start < fPicture->width(); tile_x_start += fTileWidth) {
265acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com            *fTileRects.append() = SkRect::MakeXYWH(SkIntToScalar(tile_x_start),
266acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com                                                    SkIntToScalar(tile_y_start),
267acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com                                                    SkIntToScalar(fTileWidth),
268acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com                                                    SkIntToScalar(fTileHeight));
269f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org        }
270f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org    }
271f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org}
272f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org
273f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org// The goal of the powers of two tiles is to minimize the amount of wasted tile
274f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org// space in the width-wise direction and then minimize the number of tiles. The
275f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org// constraints are that every tile must have a pixel width that is a power of
276f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org// two and also be of some minimal width (that is also a power of two).
277f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org//
27858b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com// This is solved by first taking our picture size and rounding it up to the
279f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org// multiple of the minimal width. The binary representation of this rounded
280f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org// value gives us the tiles we need: a bit of value one means we need a tile of
281f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org// that size.
282f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.orgvoid TiledPictureRenderer::setupPowerOf2Tiles() {
283f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org    int rounded_value = fPicture->width();
284f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org    if (fPicture->width() % fTileMinPowerOf2Width != 0) {
285f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org        rounded_value = fPicture->width() - (fPicture->width() % fTileMinPowerOf2Width)
286f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org            + fTileMinPowerOf2Width;
287f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org    }
288f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org
28994acc70312d8fe6605dea99f27f62b180bf22284robertphillips@google.com    int num_bits = SkScalarCeilToInt(SkScalarLog2(SkIntToScalar(fPicture->width())));
290f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org    int largest_possible_tile_size = 1 << num_bits;
291f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org
292f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org    // The tile height is constant for a particular picture.
293f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org    for (int tile_y_start = 0; tile_y_start < fPicture->height(); tile_y_start += fTileHeight) {
294f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org        int tile_x_start = 0;
295f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org        int current_width = largest_possible_tile_size;
296acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com        // Set fTileWidth to be the width of the widest tile, so that each canvas is large enough
297acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com        // to draw each tile.
298acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com        fTileWidth = current_width;
299f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org
300f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org        while (current_width >= fTileMinPowerOf2Width) {
301f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org            // It is very important this is a bitwise AND.
302f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org            if (current_width & rounded_value) {
303acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com                *fTileRects.append() = SkRect::MakeXYWH(SkIntToScalar(tile_x_start),
304acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com                                                        SkIntToScalar(tile_y_start),
305acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com                                                        SkIntToScalar(current_width),
306acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com                                                        SkIntToScalar(fTileHeight));
307f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org                tile_x_start += current_width;
308f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org            }
309f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org
310f4959ab11827bef99e8985031feb457cae1f987akeyar@chromium.org            current_width >>= 1;
311451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org        }
312451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org    }
313451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org}
314451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org
315bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com/**
316bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com * Draw the specified playback to the canvas translated to rectangle provided, so that this mini
317bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com * canvas represents the rectangle's portion of the overall picture.
318bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com * Saves and restores so that the initial clip and matrix return to their state before this function
319bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com * is called.
320bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com */
321bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.comtemplate<class T>
322bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.comstatic void DrawTileToCanvas(SkCanvas* canvas, const SkRect& tileRect, T* playback) {
323bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    int saveCount = canvas->save();
324bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    // Translate so that we draw the correct portion of the picture
325bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    canvas->translate(-tileRect.fLeft, -tileRect.fTop);
326bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    playback->draw(canvas);
327bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    canvas->restoreToCount(saveCount);
328bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    canvas->flush();
329451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org}
330451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org
33158b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com///////////////////////////////////////////////////////////////////////////////////////////////
332bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com// Base class for data used both by pipe and clone picture multi threaded drawing.
333bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com
334bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.comstruct ThreadData {
335b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com    ThreadData(SkCanvas* target, int* tileCounter, SkTDArray<SkRect>* tileRects,
336b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com               const SkString* path, bool* success)
337bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    : fCanvas(target)
338b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com    , fPath(path)
339b8e404aebe0f0d6f2508899c3405876a85704aaescroggo@google.com    , fSuccess(success)
340b8e404aebe0f0d6f2508899c3405876a85704aaescroggo@google.com    , fTileCounter(tileCounter)
341b8e404aebe0f0d6f2508899c3405876a85704aaescroggo@google.com    , fTileRects(tileRects) {
342bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com        SkASSERT(target != NULL && tileCounter != NULL && tileRects != NULL);
343b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com        // Success must start off true, and it will be set to false upon failure.
344b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com        SkASSERT(success != NULL && *success);
345bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    }
346bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com
347b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com    int32_t nextTile(SkRect* rect) {
348b4773b4802236fab24cfc63ed8b9ed7eb35f65ccscroggo@google.com        int32_t i = sk_atomic_inc(fTileCounter);
349b4773b4802236fab24cfc63ed8b9ed7eb35f65ccscroggo@google.com        if (i < fTileRects->count()) {
350b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com            SkASSERT(rect != NULL);
351b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com            *rect = fTileRects->operator[](i);
352b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com            return i;
353bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com        }
354b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com        return -1;
355bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    }
356bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com
357bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    // All of these are pointers to objects owned elsewhere
358bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    SkCanvas*                fCanvas;
359b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com    const SkString*          fPath;
360b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com    bool*                    fSuccess;
361bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.comprivate:
362bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    // Shared by all threads, this states which is the next tile to be drawn.
363bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    int32_t*                 fTileCounter;
364bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    // Points to the array of rectangles. The array is already created before any threads are
365bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    // started and then it is unmodified, so there is no danger of race conditions.
366bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    const SkTDArray<SkRect>* fTileRects;
367bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com};
368bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com
369bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com///////////////////////////////////////////////////////////////////////////////////////////////
37058b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com// Draw using Pipe
37158b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com
372bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.comstruct TileData : public ThreadData {
373bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    TileData(ThreadSafePipeController* controller, SkCanvas* canvas, int* tileCounter,
374b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com             SkTDArray<SkRect>* tileRects, const SkString* path, bool* success)
375b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com    : INHERITED(canvas, tileCounter, tileRects, path, success)
376bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    , fController(controller) {}
377bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com
3788e073ba2d63f4d2aab7532f1421df00bb1f88003scroggo@google.com    ThreadSafePipeController* fController;
379bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com
380bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    typedef ThreadData INHERITED;
38158b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com};
38258b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com
38358b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.comstatic void DrawTile(void* data) {
38458b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com    SkGraphics::SetTLSFontCacheLimit(1 * 1024 * 1024);
38558b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com    TileData* tileData = static_cast<TileData*>(data);
38658b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com
387b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com    SkRect tileRect;
388b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com    int32_t i;
389b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com    while ((i = tileData->nextTile(&tileRect)) != -1) {
390b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com        DrawTileToCanvas(tileData->fCanvas, tileRect, tileData->fController);
391070d354d51dac52a70f07d4b102392b89f2da5d7borenet@google.com        if (NULL != tileData->fPath &&
392070d354d51dac52a70f07d4b102392b89f2da5d7borenet@google.com            !writeAppendNumber(tileData->fCanvas, tileData->fPath, i)) {
393b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com            *tileData->fSuccess = false;
394b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com            break;
395b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com        }
396bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    }
397bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    SkDELETE(tileData);
398bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com}
39958b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com
40058b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com///////////////////////////////////////////////////////////////////////////////////////////////
40158b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com// Draw using Picture
40258b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com
403bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.comstruct CloneData : public ThreadData {
404b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com    CloneData(SkPicture* clone, SkCanvas* target, int* tileCounter, SkTDArray<SkRect>* tileRects,
405b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com              const SkString* path, bool* success)
406b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com    : INHERITED(target, tileCounter, tileRects, path, success)
407bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    , fClone(clone) {}
408bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com
40958b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com    SkPicture* fClone;
410bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com
411bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    typedef ThreadData INHERITED;
41258b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com};
41358b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com
414bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.comstatic void DrawClonedTiles(void* data) {
41558b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com    SkGraphics::SetTLSFontCacheLimit(1 * 1024 * 1024);
41658b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com    CloneData* cloneData = static_cast<CloneData*>(data);
41758b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com
418b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com    SkRect tileRect;
419b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com    int32_t i;
420b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com    while ((i = cloneData->nextTile(&tileRect)) != -1) {
421b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com        DrawTileToCanvas(cloneData->fCanvas, tileRect, cloneData->fClone);
422070d354d51dac52a70f07d4b102392b89f2da5d7borenet@google.com        if (NULL != cloneData->fPath &&
423070d354d51dac52a70f07d4b102392b89f2da5d7borenet@google.com            !writeAppendNumber(cloneData->fCanvas, cloneData->fPath, i)) {
424b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com            *cloneData->fSuccess = false;
425b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com            break;
426b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com        }
427bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    }
428bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    SkDELETE(cloneData);
429bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com}
43058b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com
43158b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com///////////////////////////////////////////////////////////////////////////////////////////////
43258b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com
433bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.comvoid TiledPictureRenderer::setup() {
434bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    if (this->multiThreaded()) {
435bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com        // Reset to zero so we start with the first tile.
436bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com        fTileCounter = 0;
437bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com        if (fUsePipe) {
438bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com            // Record the picture into the pipe controller. It is done here because unlike
439bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com            // SkPicture, the pipe is modified (bitmaps can be removed) by drawing.
440bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com            // fPipeController is deleted here after each call to render() except the last one and
441bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com            // in end() for the last one.
442bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com            if (fPipeController != NULL) {
443bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com                SkDELETE(fPipeController);
444bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com            }
445bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com            fPipeController = SkNEW_ARGS(ThreadSafePipeController, (fTileRects.count()));
446bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com            SkGPipeWriter writer;
447bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com            SkCanvas* pipeCanvas = writer.startRecording(fPipeController,
448bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com                                                         SkGPipeWriter::kSimultaneousReaders_Flag);
449bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com            SkASSERT(fPicture != NULL);
450bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com            fPicture->draw(pipeCanvas);
451bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com            writer.endRecording();
452bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com        }
453bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    }
454bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com}
455bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com
45681f9d2e05be4902993345dac93337158345c660bscroggo@google.combool TiledPictureRenderer::render(const SkString* path) {
457acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com    SkASSERT(fPicture != NULL);
458acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com    if (NULL == fPicture) {
45981f9d2e05be4902993345dac93337158345c660bscroggo@google.com        return false;
460acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com    }
461acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com
462bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    if (this->multiThreaded()) {
463bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com        SkASSERT(fCanvasPool.count() == fNumThreads);
464bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com        SkTDArray<SkThread*> threads;
465bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com        SkThread::entryPointProc proc = fUsePipe ? DrawTile : DrawClonedTiles;
466b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com        bool success = true;
467bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com        for (int i = 0; i < fNumThreads; ++i) {
468bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com            // data will be deleted by the entryPointProc.
469bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com            ThreadData* data;
470bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com            if (fUsePipe) {
471b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com                data = SkNEW_ARGS(TileData, (fPipeController, fCanvasPool[i], &fTileCounter,
472b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com                                             &fTileRects, path, &success));
473bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com            } else {
474bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com                SkPicture* pic = (0 == i) ? fPicture : &fPictureClones[i-1];
475b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com                data = SkNEW_ARGS(CloneData, (pic, fCanvasPool[i], &fTileCounter, &fTileRects, path,
476b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com                                              &success));
47758b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com            }
478bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com            SkThread* thread = SkNEW_ARGS(SkThread, (proc, data));
479bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com            if (!thread->start()) {
480bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com                SkDebugf("Could not start %s thread %i.\n", (fUsePipe ? "pipe" : "picture"), i);
48158b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com            }
482bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com            *threads.append() = thread;
48358b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com        }
484bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com        SkASSERT(threads.count() == fNumThreads);
485bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com        for (int i = 0; i < fNumThreads; ++i) {
486bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com            SkThread* thread = threads[i];
487bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com            thread->join();
488bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com            SkDELETE(thread);
489bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com        }
490bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com        threads.reset();
491b6e806bf17ffcca0c147a7dab4fba104fe928a58scroggo@google.com        return success;
49258b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com    } else {
493bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com        // For single thread, we really only need one canvas total.
494acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com        SkCanvas* canvas = this->setupCanvas(fTileWidth, fTileHeight);
495acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com        SkAutoUnref aur(canvas);
496acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com
497070d354d51dac52a70f07d4b102392b89f2da5d7borenet@google.com        bool success = true;
498acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com        for (int i = 0; i < fTileRects.count(); ++i) {
499bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com            DrawTileToCanvas(canvas, fTileRects[i], fPicture);
500070d354d51dac52a70f07d4b102392b89f2da5d7borenet@google.com            if (NULL != path) {
501070d354d51dac52a70f07d4b102392b89f2da5d7borenet@google.com                success &= writeAppendNumber(canvas, path, i);
502acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com            }
50358b4ead36c62d8c0256ee4da554f3df2744d904cscroggo@google.com        }
504070d354d51dac52a70f07d4b102392b89f2da5d7borenet@google.com        return success;
505163b56734fe01c088581895a8e0b65ddf1cb4fa5keyar@chromium.org    }
506163b56734fe01c088581895a8e0b65ddf1cb4fa5keyar@chromium.org}
507163b56734fe01c088581895a8e0b65ddf1cb4fa5keyar@chromium.org
508bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.comSkCanvas* TiledPictureRenderer::setupCanvas(int width, int height) {
509bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    SkCanvas* canvas = this->INHERITED::setupCanvas(width, height);
510bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    SkASSERT(fPicture != NULL);
511bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    // Clip the tile to an area that is completely in what the SkPicture says is the
512bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    // drawn-to area. This is mostly important for tiles on the right and bottom edges
513bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    // as they may go over this area and the picture may have some commands that
514bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    // draw outside of this area and so should not actually be written.
515bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    SkRect clip = SkRect::MakeWH(SkIntToScalar(fPicture->width()),
516bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com                                 SkIntToScalar(fPicture->height()));
517bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    canvas->clipRect(clip);
518bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com    return canvas;
519bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com}
520bcdf2ec50dfd170959cc2db67c49f6dac084be03scroggo@google.com
521acfb30e5bb797249f4ec41edda4c4d4b86e0e5d0scroggo@google.com///////////////////////////////////////////////////////////////////////////////////////////////
5229a4125283ad56cea3b986337cb669dde14bf0ed8scroggo@google.com
5239a4125283ad56cea3b986337cb669dde14bf0ed8scroggo@google.comvoid PlaybackCreationRenderer::setup() {
5249a4125283ad56cea3b986337cb669dde14bf0ed8scroggo@google.com    SkCanvas* recorder = fReplayer.beginRecording(fPicture->width(), fPicture->height());
5259a4125283ad56cea3b986337cb669dde14bf0ed8scroggo@google.com    fPicture->draw(recorder);
5269a4125283ad56cea3b986337cb669dde14bf0ed8scroggo@google.com}
5279a4125283ad56cea3b986337cb669dde14bf0ed8scroggo@google.com
52881f9d2e05be4902993345dac93337158345c660bscroggo@google.combool PlaybackCreationRenderer::render(const SkString*) {
5299a4125283ad56cea3b986337cb669dde14bf0ed8scroggo@google.com    fReplayer.endRecording();
53081f9d2e05be4902993345dac93337158345c660bscroggo@google.com    // Since this class does not actually render, return false.
53181f9d2e05be4902993345dac93337158345c660bscroggo@google.com    return false;
532451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org}
533451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org
534451bb9f801d668275394ca5bd57f238e13cf3d17keyar@chromium.org}
535