blob: 85bd194bbe2d9fbcd6dd18504ba6176719128afc [file] [log] [blame]
keyar@chromium.orgb3fb7c12012-08-20 21:02:49 +00001/*
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
keyar@chromium.org451bb9f2012-07-26 17:27:57 +00008#include "PictureRenderer.h"
scroggo@google.com58b4ead2012-08-31 16:15:22 +00009#include "picture_utils.h"
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000010#include "SamplePipeControllers.h"
11#include "SkCanvas.h"
12#include "SkDevice.h"
13#include "SkGPipe.h"
scroggo@google.com58b4ead2012-08-31 16:15:22 +000014#if SK_SUPPORT_GPU
15#include "SkGpuDevice.h"
16#endif
17#include "SkGraphics.h"
18#include "SkImageEncoder.h"
keyar@chromium.orgea826952012-08-23 15:24:13 +000019#include "SkMatrix.h"
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000020#include "SkPicture.h"
keyar@chromium.orgea826952012-08-23 15:24:13 +000021#include "SkScalar.h"
keyar@chromium.org9299ede2012-08-21 19:05:08 +000022#include "SkString.h"
scroggo@google.com58b4ead2012-08-31 16:15:22 +000023#include "SkTemplates.h"
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000024#include "SkTDArray.h"
scroggo@google.com58b4ead2012-08-31 16:15:22 +000025#include "SkThreadUtils.h"
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000026#include "SkTypes.h"
keyar@chromium.org4ea96c52012-08-20 15:03:29 +000027
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000028namespace sk_tools {
29
30enum {
31 kDefaultTileWidth = 256,
32 kDefaultTileHeight = 256
33};
34
keyar@chromium.org9d696c02012-08-07 17:11:33 +000035void PictureRenderer::init(SkPicture* pict) {
keyar@chromium.org78a35c52012-08-20 15:03:44 +000036 SkASSERT(NULL == fPicture);
37 SkASSERT(NULL == fCanvas.get());
38 if (fPicture != NULL || NULL != fCanvas.get()) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +000039 return;
40 }
41
42 SkASSERT(pict != NULL);
keyar@chromium.org78a35c52012-08-20 15:03:44 +000043 if (NULL == pict) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +000044 return;
45 }
46
47 fPicture = pict;
keyar@chromium.orga474ce32012-08-20 15:03:57 +000048 fCanvas.reset(this->setupCanvas());
49}
50
51SkCanvas* PictureRenderer::setupCanvas() {
52 return this->setupCanvas(fPicture->width(), fPicture->height());
53}
54
55SkCanvas* PictureRenderer::setupCanvas(int width, int height) {
keyar@chromium.org4ea96c52012-08-20 15:03:29 +000056 switch(fDeviceType) {
57 case kBitmap_DeviceType: {
58 SkBitmap bitmap;
keyar@chromium.orga474ce32012-08-20 15:03:57 +000059 sk_tools::setup_bitmap(&bitmap, width, height);
60 return SkNEW_ARGS(SkCanvas, (bitmap));
keyar@chromium.org4ea96c52012-08-20 15:03:29 +000061 break;
62 }
63#if SK_SUPPORT_GPU
64 case kGPU_DeviceType: {
keyar@chromium.org4ea96c52012-08-20 15:03:29 +000065 SkAutoTUnref<SkGpuDevice> device(SkNEW_ARGS(SkGpuDevice,
keyar@chromium.org06125642012-08-20 15:03:33 +000066 (fGrContext, SkBitmap::kARGB_8888_Config,
keyar@chromium.orga474ce32012-08-20 15:03:57 +000067 width, height)));
68 return SkNEW_ARGS(SkCanvas, (device.get()));
keyar@chromium.org4ea96c52012-08-20 15:03:29 +000069 break;
70 }
71#endif
72 default:
73 SkASSERT(0);
74 }
keyar@chromium.orga474ce32012-08-20 15:03:57 +000075
76 return NULL;
keyar@chromium.org9d696c02012-08-07 17:11:33 +000077}
78
79void PictureRenderer::end() {
keyar@chromium.org77a55222012-08-20 15:03:47 +000080 this->resetState();
keyar@chromium.org9d696c02012-08-07 17:11:33 +000081 fPicture = NULL;
82 fCanvas.reset(NULL);
83}
84
keyar@chromium.org77a55222012-08-20 15:03:47 +000085void PictureRenderer::resetState() {
keyar@chromium.org28136b32012-08-20 15:04:15 +000086#if SK_SUPPORT_GPU
87 if (this->isUsingGpuDevice()) {
88 SkGLContext* glContext = fGrContextFactory.getGLContext(
89 GrContextFactory::kNative_GLContextType);
keyar@chromium.org28136b32012-08-20 15:04:15 +000090
91 SkASSERT(glContext != NULL);
92 if (NULL == glContext) {
93 return;
94 }
95
scroggo@google.com9a412522012-09-07 15:21:18 +000096 fGrContext->flush();
keyar@chromium.org77a55222012-08-20 15:03:47 +000097 SK_GL(*glContext, Finish());
keyar@chromium.org77a55222012-08-20 15:03:47 +000098 }
keyar@chromium.orga40c20d2012-08-20 15:04:12 +000099#endif
keyar@chromium.org77a55222012-08-20 15:03:47 +0000100}
101
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000102bool PictureRenderer::write(SkCanvas* canvas, SkString path) const {
103 SkASSERT(canvas != NULL);
keyar@chromium.org9299ede2012-08-21 19:05:08 +0000104 SkASSERT(fPicture != NULL);
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000105 if (NULL == canvas || NULL == fPicture) {
keyar@chromium.org9299ede2012-08-21 19:05:08 +0000106 return false;
107 }
108
109 SkBitmap bitmap;
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000110 SkISize size = canvas->getDeviceSize();
111 sk_tools::setup_bitmap(&bitmap, size.width(), size.height());
keyar@chromium.org9299ede2012-08-21 19:05:08 +0000112
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000113 canvas->readPixels(&bitmap, 0, 0);
keyar@chromium.org9299ede2012-08-21 19:05:08 +0000114 sk_tools::force_all_opaque(bitmap);
115
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000116 // Since path is passed in by value, it is okay to modify it.
117 path.append(".png");
keyar@chromium.org9299ede2012-08-21 19:05:08 +0000118 return SkImageEncoder::EncodeFile(path.c_str(), bitmap, SkImageEncoder::kPNG_Type, 100);
119}
120
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000121///////////////////////////////////////////////////////////////////////////////////////////////
122
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000123bool RecordPictureRenderer::render(const SkString*) {
scroggo@google.com9a412522012-09-07 15:21:18 +0000124 SkPicture replayer;
125 SkCanvas* recorder = replayer.beginRecording(fPicture->width(), fPicture->height());
126 fPicture->draw(recorder);
127 replayer.endRecording();
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000128 // Since this class does not actually render, return false.
129 return false;
scroggo@google.com9a412522012-09-07 15:21:18 +0000130}
131
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000132///////////////////////////////////////////////////////////////////////////////////////////////
133
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000134bool PipePictureRenderer::render(const SkString* path) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000135 SkASSERT(fCanvas.get() != NULL);
136 SkASSERT(fPicture != NULL);
keyar@chromium.org78a35c52012-08-20 15:03:44 +0000137 if (NULL == fCanvas.get() || NULL == fPicture) {
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000138 return false;
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000139 }
140
141 PipeController pipeController(fCanvas.get());
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000142 SkGPipeWriter writer;
143 SkCanvas* pipeCanvas = writer.startRecording(&pipeController);
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000144 pipeCanvas->drawPicture(*fPicture);
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000145 writer.endRecording();
scroggo@google.com9a412522012-09-07 15:21:18 +0000146 fCanvas->flush();
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000147 return path != NULL && this->write(fCanvas, *path);
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000148}
149
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000150///////////////////////////////////////////////////////////////////////////////////////////////
151
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000152bool SimplePictureRenderer::render(const SkString* path) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000153 SkASSERT(fCanvas.get() != NULL);
154 SkASSERT(fPicture != NULL);
keyar@chromium.org78a35c52012-08-20 15:03:44 +0000155 if (NULL == fCanvas.get() || NULL == fPicture) {
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000156 return false;
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000157 }
158
159 fCanvas->drawPicture(*fPicture);
scroggo@google.com9a412522012-09-07 15:21:18 +0000160 fCanvas->flush();
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000161 return path != NULL && this->write(fCanvas, *path);
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000162}
163
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000164///////////////////////////////////////////////////////////////////////////////////////////////
165
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000166TiledPictureRenderer::TiledPictureRenderer()
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000167 : fUsePipe(false)
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000168 , fTileWidth(kDefaultTileWidth)
rileya@google.comb947b912012-08-29 17:35:07 +0000169 , fTileHeight(kDefaultTileHeight)
rileya@google.coma04dc022012-09-10 19:01:38 +0000170 , fTileWidthPercentage(0.0)
rileya@google.comb947b912012-08-29 17:35:07 +0000171 , fTileHeightPercentage(0.0)
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000172 , fTileMinPowerOf2Width(0)
173 , fTileCounter(0)
174 , fNumThreads(1)
175 , fPictureClones(NULL)
176 , fPipeController(NULL) { }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000177
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000178void TiledPictureRenderer::init(SkPicture* pict) {
179 SkASSERT(pict != NULL);
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000180 SkASSERT(0 == fTileRects.count());
181 if (NULL == pict || fTileRects.count() != 0) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000182 return;
183 }
184
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000185 // Do not call INHERITED::init(), which would create a (potentially large) canvas which is not
186 // used by bench_pictures.
187 fPicture = pict;
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000188
189 if (fTileWidthPercentage > 0) {
robertphillips@google.com5d8d1862012-08-15 14:36:41 +0000190 fTileWidth = sk_float_ceil2int(float(fTileWidthPercentage * fPicture->width() / 100));
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000191 }
192 if (fTileHeightPercentage > 0) {
robertphillips@google.com5d8d1862012-08-15 14:36:41 +0000193 fTileHeight = sk_float_ceil2int(float(fTileHeightPercentage * fPicture->height() / 100));
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000194 }
195
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000196 if (fTileMinPowerOf2Width > 0) {
197 this->setupPowerOf2Tiles();
198 } else {
199 this->setupTiles();
200 }
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000201
202 if (this->multiThreaded()) {
203 for (int i = 0; i < fNumThreads; ++i) {
204 *fCanvasPool.append() = this->setupCanvas(fTileWidth, fTileHeight);
205 }
206 if (!fUsePipe) {
207 SkASSERT(NULL == fPictureClones);
208 // Only need to create fNumThreads - 1 clones, since one thread will use the base
209 // picture.
210 int numberOfClones = fNumThreads - 1;
211 // This will be deleted in end().
212 fPictureClones = SkNEW_ARRAY(SkPicture, numberOfClones);
213 fPictureClones->clone(fPictureClones, numberOfClones);
214 }
215 }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000216}
217
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000218void TiledPictureRenderer::end() {
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000219 fTileRects.reset();
220 SkDELETE_ARRAY(fPictureClones);
221 fPictureClones = NULL;
222 fCanvasPool.unrefAll();
223 if (fPipeController != NULL) {
224 SkASSERT(fUsePipe);
225 SkDELETE(fPipeController);
226 fPipeController = NULL;
227 }
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000228 this->INHERITED::end();
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000229}
230
231TiledPictureRenderer::~TiledPictureRenderer() {
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000232 // end() must be called to delete fPictureClones and fPipeController
233 SkASSERT(NULL == fPictureClones);
234 SkASSERT(NULL == fPipeController);
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000235}
236
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000237void TiledPictureRenderer::setupTiles() {
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000238 for (int tile_y_start = 0; tile_y_start < fPicture->height(); tile_y_start += fTileHeight) {
239 for (int tile_x_start = 0; tile_x_start < fPicture->width(); tile_x_start += fTileWidth) {
240 *fTileRects.append() = SkRect::MakeXYWH(SkIntToScalar(tile_x_start),
241 SkIntToScalar(tile_y_start),
242 SkIntToScalar(fTileWidth),
243 SkIntToScalar(fTileHeight));
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000244 }
245 }
246}
247
248// The goal of the powers of two tiles is to minimize the amount of wasted tile
249// space in the width-wise direction and then minimize the number of tiles. The
250// constraints are that every tile must have a pixel width that is a power of
251// two and also be of some minimal width (that is also a power of two).
252//
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000253// This is solved by first taking our picture size and rounding it up to the
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000254// multiple of the minimal width. The binary representation of this rounded
255// value gives us the tiles we need: a bit of value one means we need a tile of
256// that size.
257void TiledPictureRenderer::setupPowerOf2Tiles() {
258 int rounded_value = fPicture->width();
259 if (fPicture->width() % fTileMinPowerOf2Width != 0) {
260 rounded_value = fPicture->width() - (fPicture->width() % fTileMinPowerOf2Width)
261 + fTileMinPowerOf2Width;
262 }
263
robertphillips@google.com94acc702012-09-06 18:43:21 +0000264 int num_bits = SkScalarCeilToInt(SkScalarLog2(SkIntToScalar(fPicture->width())));
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000265 int largest_possible_tile_size = 1 << num_bits;
266
267 // The tile height is constant for a particular picture.
268 for (int tile_y_start = 0; tile_y_start < fPicture->height(); tile_y_start += fTileHeight) {
269 int tile_x_start = 0;
270 int current_width = largest_possible_tile_size;
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000271 // Set fTileWidth to be the width of the widest tile, so that each canvas is large enough
272 // to draw each tile.
273 fTileWidth = current_width;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000274
275 while (current_width >= fTileMinPowerOf2Width) {
276 // It is very important this is a bitwise AND.
277 if (current_width & rounded_value) {
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000278 *fTileRects.append() = SkRect::MakeXYWH(SkIntToScalar(tile_x_start),
279 SkIntToScalar(tile_y_start),
280 SkIntToScalar(current_width),
281 SkIntToScalar(fTileHeight));
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000282 tile_x_start += current_width;
283 }
284
285 current_width >>= 1;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000286 }
287 }
288}
289
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000290/**
291 * Draw the specified playback to the canvas translated to rectangle provided, so that this mini
292 * canvas represents the rectangle's portion of the overall picture.
293 * Saves and restores so that the initial clip and matrix return to their state before this function
294 * is called.
295 */
296template<class T>
297static void DrawTileToCanvas(SkCanvas* canvas, const SkRect& tileRect, T* playback) {
298 int saveCount = canvas->save();
299 // Translate so that we draw the correct portion of the picture
300 canvas->translate(-tileRect.fLeft, -tileRect.fTop);
301 playback->draw(canvas);
302 canvas->restoreToCount(saveCount);
303 canvas->flush();
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000304}
305
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000306///////////////////////////////////////////////////////////////////////////////////////////////
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000307// Base class for data used both by pipe and clone picture multi threaded drawing.
308
309struct ThreadData {
310 ThreadData(SkCanvas* target, int* tileCounter, SkTDArray<SkRect>* tileRects)
311 : fCanvas(target)
312 , fTileCounter(tileCounter)
313 , fTileRects(tileRects) {
314 SkASSERT(target != NULL && tileCounter != NULL && tileRects != NULL);
315 }
316
317 const SkRect* nextTile() {
318 if (int32_t i = sk_atomic_inc(fTileCounter) < fTileRects->count()) {
319 return &fTileRects->operator[](i);
320 }
321 return NULL;
322 }
323
324 // All of these are pointers to objects owned elsewhere
325 SkCanvas* fCanvas;
326private:
327 // Shared by all threads, this states which is the next tile to be drawn.
328 int32_t* fTileCounter;
329 // Points to the array of rectangles. The array is already created before any threads are
330 // started and then it is unmodified, so there is no danger of race conditions.
331 const SkTDArray<SkRect>* fTileRects;
332};
333
334///////////////////////////////////////////////////////////////////////////////////////////////
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000335// Draw using Pipe
336
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000337struct TileData : public ThreadData {
338 TileData(ThreadSafePipeController* controller, SkCanvas* canvas, int* tileCounter,
339 SkTDArray<SkRect>* tileRects)
340 : INHERITED(canvas, tileCounter, tileRects)
341 , fController(controller) {}
342
scroggo@google.com8e073ba2012-08-31 16:25:46 +0000343 ThreadSafePipeController* fController;
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000344
345 typedef ThreadData INHERITED;
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000346};
347
348static void DrawTile(void* data) {
349 SkGraphics::SetTLSFontCacheLimit(1 * 1024 * 1024);
350 TileData* tileData = static_cast<TileData*>(data);
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000351
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000352 const SkRect* tileRect;
353 while ((tileRect = tileData->nextTile()) != NULL) {
354 DrawTileToCanvas(tileData->fCanvas, *tileRect, tileData->fController);
355 }
356 SkDELETE(tileData);
357}
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000358
359///////////////////////////////////////////////////////////////////////////////////////////////
360// Draw using Picture
361
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000362struct CloneData : public ThreadData {
363 CloneData(SkPicture* clone, SkCanvas* target, int* tileCounter, SkTDArray<SkRect>* tileRects)
364 : INHERITED(target, tileCounter, tileRects)
365 , fClone(clone) {}
366
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000367 SkPicture* fClone;
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000368
369 typedef ThreadData INHERITED;
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000370};
371
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000372static void DrawClonedTiles(void* data) {
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000373 SkGraphics::SetTLSFontCacheLimit(1 * 1024 * 1024);
374 CloneData* cloneData = static_cast<CloneData*>(data);
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000375
376 const SkRect* tileRect;
377 while ((tileRect = cloneData->nextTile()) != NULL) {
378 DrawTileToCanvas(cloneData->fCanvas, *tileRect, cloneData->fClone);
379 }
380 SkDELETE(cloneData);
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000381}
382
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000383///////////////////////////////////////////////////////////////////////////////////////////////
384
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000385void TiledPictureRenderer::setup() {
386 if (this->multiThreaded()) {
387 // Reset to zero so we start with the first tile.
388 fTileCounter = 0;
389 if (fUsePipe) {
390 // Record the picture into the pipe controller. It is done here because unlike
391 // SkPicture, the pipe is modified (bitmaps can be removed) by drawing.
392 // fPipeController is deleted here after each call to render() except the last one and
393 // in end() for the last one.
394 if (fPipeController != NULL) {
395 SkDELETE(fPipeController);
396 }
397 fPipeController = SkNEW_ARGS(ThreadSafePipeController, (fTileRects.count()));
398 SkGPipeWriter writer;
399 SkCanvas* pipeCanvas = writer.startRecording(fPipeController,
400 SkGPipeWriter::kSimultaneousReaders_Flag);
401 SkASSERT(fPicture != NULL);
402 fPicture->draw(pipeCanvas);
403 writer.endRecording();
404 }
405 }
406}
407
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000408bool TiledPictureRenderer::render(const SkString* path) {
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000409 SkASSERT(fPicture != NULL);
410 if (NULL == fPicture) {
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000411 return false;
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000412 }
413
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000414 if (this->multiThreaded()) {
415 SkASSERT(fCanvasPool.count() == fNumThreads);
416 SkTDArray<SkThread*> threads;
417 SkThread::entryPointProc proc = fUsePipe ? DrawTile : DrawClonedTiles;
418 for (int i = 0; i < fNumThreads; ++i) {
419 // data will be deleted by the entryPointProc.
420 ThreadData* data;
421 if (fUsePipe) {
422 data = SkNEW_ARGS(TileData,
423 (fPipeController, fCanvasPool[i], &fTileCounter, &fTileRects));
424 } else {
425 SkPicture* pic = (0 == i) ? fPicture : &fPictureClones[i-1];
426 data = SkNEW_ARGS(CloneData, (pic, fCanvasPool[i], &fTileCounter, &fTileRects));
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000427 }
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000428 SkThread* thread = SkNEW_ARGS(SkThread, (proc, data));
429 if (!thread->start()) {
430 SkDebugf("Could not start %s thread %i.\n", (fUsePipe ? "pipe" : "picture"), i);
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000431 }
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000432 *threads.append() = thread;
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000433 }
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000434 SkASSERT(threads.count() == fNumThreads);
435 for (int i = 0; i < fNumThreads; ++i) {
436 SkThread* thread = threads[i];
437 thread->join();
438 SkDELETE(thread);
439 }
440 threads.reset();
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000441 // Currently multithreaded is not an option for render_pictures
442 return false;
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000443 } else {
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000444 // For single thread, we really only need one canvas total.
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000445 SkCanvas* canvas = this->setupCanvas(fTileWidth, fTileHeight);
446 SkAutoUnref aur(canvas);
447
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000448 for (int i = 0; i < fTileRects.count(); ++i) {
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000449 DrawTileToCanvas(canvas, fTileRects[i], fPicture);
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000450 if (path != NULL) {
451 SkString tilePath(*path);
452 tilePath.appendf("%i", i);
453 if (!this->write(canvas, tilePath)) {
454 return false;
455 }
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000456 }
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000457 }
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000458 return path != NULL;
keyar@chromium.org163b5672012-08-01 17:53:29 +0000459 }
460}
461
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000462SkCanvas* TiledPictureRenderer::setupCanvas(int width, int height) {
463 SkCanvas* canvas = this->INHERITED::setupCanvas(width, height);
464 SkASSERT(fPicture != NULL);
465 // Clip the tile to an area that is completely in what the SkPicture says is the
466 // drawn-to area. This is mostly important for tiles on the right and bottom edges
467 // as they may go over this area and the picture may have some commands that
468 // draw outside of this area and so should not actually be written.
469 SkRect clip = SkRect::MakeWH(SkIntToScalar(fPicture->width()),
470 SkIntToScalar(fPicture->height()));
471 canvas->clipRect(clip);
472 return canvas;
473}
474
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000475///////////////////////////////////////////////////////////////////////////////////////////////
scroggo@google.com9a412522012-09-07 15:21:18 +0000476
477void PlaybackCreationRenderer::setup() {
478 SkCanvas* recorder = fReplayer.beginRecording(fPicture->width(), fPicture->height());
479 fPicture->draw(recorder);
480}
481
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000482bool PlaybackCreationRenderer::render(const SkString*) {
scroggo@google.com9a412522012-09-07 15:21:18 +0000483 fReplayer.endRecording();
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000484 // Since this class does not actually render, return false.
485 return false;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000486}
487
488}