blob: 745bec00f18336f0e867a6a4b5310d470a9e3c63 [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"
junov@chromium.org9313ca42012-11-02 18:11:49 +000021#include "SkRTree.h"
keyar@chromium.orgea826952012-08-23 15:24:13 +000022#include "SkScalar.h"
keyar@chromium.org9299ede2012-08-21 19:05:08 +000023#include "SkString.h"
scroggo@google.com58b4ead2012-08-31 16:15:22 +000024#include "SkTemplates.h"
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000025#include "SkTDArray.h"
scroggo@google.com58b4ead2012-08-31 16:15:22 +000026#include "SkThreadUtils.h"
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000027#include "SkTypes.h"
keyar@chromium.org4ea96c52012-08-20 15:03:29 +000028
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000029namespace sk_tools {
30
31enum {
32 kDefaultTileWidth = 256,
33 kDefaultTileHeight = 256
34};
35
keyar@chromium.org9d696c02012-08-07 17:11:33 +000036void PictureRenderer::init(SkPicture* pict) {
keyar@chromium.org78a35c52012-08-20 15:03:44 +000037 SkASSERT(NULL == fPicture);
38 SkASSERT(NULL == fCanvas.get());
39 if (fPicture != NULL || NULL != fCanvas.get()) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +000040 return;
41 }
42
43 SkASSERT(pict != NULL);
keyar@chromium.org78a35c52012-08-20 15:03:44 +000044 if (NULL == pict) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +000045 return;
46 }
47
48 fPicture = pict;
junov@chromium.org9313ca42012-11-02 18:11:49 +000049 fPicture->ref();
keyar@chromium.orga474ce32012-08-20 15:03:57 +000050 fCanvas.reset(this->setupCanvas());
51}
52
53SkCanvas* PictureRenderer::setupCanvas() {
54 return this->setupCanvas(fPicture->width(), fPicture->height());
55}
56
57SkCanvas* PictureRenderer::setupCanvas(int width, int height) {
keyar@chromium.org4ea96c52012-08-20 15:03:29 +000058 switch(fDeviceType) {
59 case kBitmap_DeviceType: {
60 SkBitmap bitmap;
keyar@chromium.orga474ce32012-08-20 15:03:57 +000061 sk_tools::setup_bitmap(&bitmap, width, height);
62 return SkNEW_ARGS(SkCanvas, (bitmap));
keyar@chromium.org4ea96c52012-08-20 15:03:29 +000063 break;
64 }
65#if SK_SUPPORT_GPU
66 case kGPU_DeviceType: {
keyar@chromium.org4ea96c52012-08-20 15:03:29 +000067 SkAutoTUnref<SkGpuDevice> device(SkNEW_ARGS(SkGpuDevice,
keyar@chromium.org06125642012-08-20 15:03:33 +000068 (fGrContext, SkBitmap::kARGB_8888_Config,
keyar@chromium.orga474ce32012-08-20 15:03:57 +000069 width, height)));
70 return SkNEW_ARGS(SkCanvas, (device.get()));
keyar@chromium.org4ea96c52012-08-20 15:03:29 +000071 break;
72 }
73#endif
74 default:
75 SkASSERT(0);
76 }
keyar@chromium.orga474ce32012-08-20 15:03:57 +000077
78 return NULL;
keyar@chromium.org9d696c02012-08-07 17:11:33 +000079}
80
81void PictureRenderer::end() {
keyar@chromium.org77a55222012-08-20 15:03:47 +000082 this->resetState();
junov@chromium.org9313ca42012-11-02 18:11:49 +000083 SkSafeUnref(fPicture);
keyar@chromium.org9d696c02012-08-07 17:11:33 +000084 fPicture = NULL;
85 fCanvas.reset(NULL);
86}
87
junov@chromium.org9313ca42012-11-02 18:11:49 +000088/** Converts fPicture to a picture that uses a BBoxHierarchy.
89 * PictureRenderer subclasses that are used to test picture playback
90 * should call this method during init.
91 */
92void PictureRenderer::buildBBoxHierarchy() {
93 SkASSERT(NULL != fPicture);
94 if (kNone_BBoxHierarchyType != fBBoxHierarchyType && NULL != fPicture) {
95 SkPicture* newPicture = this->createPicture();
96 SkCanvas* recorder = newPicture->beginRecording(fPicture->width(), fPicture->height(),
97 this->recordFlags());
98 fPicture->draw(recorder);
99 newPicture->endRecording();
100 fPicture->unref();
101 fPicture = newPicture;
102 }
103}
104
keyar@chromium.org77a55222012-08-20 15:03:47 +0000105void PictureRenderer::resetState() {
keyar@chromium.org28136b32012-08-20 15:04:15 +0000106#if SK_SUPPORT_GPU
107 if (this->isUsingGpuDevice()) {
108 SkGLContext* glContext = fGrContextFactory.getGLContext(
109 GrContextFactory::kNative_GLContextType);
keyar@chromium.org28136b32012-08-20 15:04:15 +0000110
111 SkASSERT(glContext != NULL);
112 if (NULL == glContext) {
113 return;
114 }
115
scroggo@google.com9a412522012-09-07 15:21:18 +0000116 fGrContext->flush();
keyar@chromium.org77a55222012-08-20 15:03:47 +0000117 SK_GL(*glContext, Finish());
keyar@chromium.org77a55222012-08-20 15:03:47 +0000118 }
keyar@chromium.orga40c20d2012-08-20 15:04:12 +0000119#endif
keyar@chromium.org77a55222012-08-20 15:03:47 +0000120}
121
junov@chromium.org9313ca42012-11-02 18:11:49 +0000122uint32_t PictureRenderer::recordFlags() {
123 return kNone_BBoxHierarchyType == fBBoxHierarchyType ? 0 :
124 SkPicture::kOptimizeForClippedPlayback_RecordingFlag;
125}
126
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000127/**
128 * Write the canvas to the specified path.
129 * @param canvas Must be non-null. Canvas to be written to a file.
130 * @param path Path for the file to be written. Should have no extension; write() will append
131 * an appropriate one. Passed in by value so it can be modified.
132 * @return bool True if the Canvas is written to a file.
133 */
134static bool write(SkCanvas* canvas, SkString path) {
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000135 SkASSERT(canvas != NULL);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000136 if (NULL == canvas) {
keyar@chromium.org9299ede2012-08-21 19:05:08 +0000137 return false;
138 }
139
140 SkBitmap bitmap;
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000141 SkISize size = canvas->getDeviceSize();
142 sk_tools::setup_bitmap(&bitmap, size.width(), size.height());
keyar@chromium.org9299ede2012-08-21 19:05:08 +0000143
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000144 canvas->readPixels(&bitmap, 0, 0);
keyar@chromium.org9299ede2012-08-21 19:05:08 +0000145 sk_tools::force_all_opaque(bitmap);
146
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000147 // Since path is passed in by value, it is okay to modify it.
148 path.append(".png");
keyar@chromium.org9299ede2012-08-21 19:05:08 +0000149 return SkImageEncoder::EncodeFile(path.c_str(), bitmap, SkImageEncoder::kPNG_Type, 100);
150}
151
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000152/**
153 * If path is non NULL, append number to it, and call write(SkCanvas*, SkString) to write the
154 * provided canvas to a file. Returns true if path is NULL or if write() succeeds.
155 */
156static bool writeAppendNumber(SkCanvas* canvas, const SkString* path, int number) {
157 if (NULL == path) {
158 return true;
159 }
160 SkString pathWithNumber(*path);
161 pathWithNumber.appendf("%i", number);
162 return write(canvas, pathWithNumber);
163}
164
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000165///////////////////////////////////////////////////////////////////////////////////////////////
166
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000167bool RecordPictureRenderer::render(const SkString*) {
junov@chromium.org9313ca42012-11-02 18:11:49 +0000168 SkAutoTUnref<SkPicture> replayer(this->createPicture());
169 SkCanvas* recorder = replayer->beginRecording(fPicture->width(), fPicture->height(),
170 this->recordFlags());
scroggo@google.com9a412522012-09-07 15:21:18 +0000171 fPicture->draw(recorder);
junov@chromium.org9313ca42012-11-02 18:11:49 +0000172 replayer->endRecording();
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000173 // Since this class does not actually render, return false.
174 return false;
scroggo@google.com9a412522012-09-07 15:21:18 +0000175}
176
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000177///////////////////////////////////////////////////////////////////////////////////////////////
178
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000179bool PipePictureRenderer::render(const SkString* path) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000180 SkASSERT(fCanvas.get() != NULL);
181 SkASSERT(fPicture != NULL);
keyar@chromium.org78a35c52012-08-20 15:03:44 +0000182 if (NULL == fCanvas.get() || NULL == fPicture) {
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000183 return false;
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000184 }
185
186 PipeController pipeController(fCanvas.get());
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000187 SkGPipeWriter writer;
188 SkCanvas* pipeCanvas = writer.startRecording(&pipeController);
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000189 pipeCanvas->drawPicture(*fPicture);
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000190 writer.endRecording();
scroggo@google.com9a412522012-09-07 15:21:18 +0000191 fCanvas->flush();
borenet@google.com070d3542012-10-26 13:26:55 +0000192 if (NULL != path) {
193 return write(fCanvas, *path);
194 }
195 return true;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000196}
197
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000198///////////////////////////////////////////////////////////////////////////////////////////////
199
junov@chromium.org9313ca42012-11-02 18:11:49 +0000200void SimplePictureRenderer::init(SkPicture* picture) {
201 INHERITED::init(picture);
202 this->buildBBoxHierarchy();
203}
204
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000205bool SimplePictureRenderer::render(const SkString* path) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000206 SkASSERT(fCanvas.get() != NULL);
207 SkASSERT(fPicture != NULL);
keyar@chromium.org78a35c52012-08-20 15:03:44 +0000208 if (NULL == fCanvas.get() || NULL == fPicture) {
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000209 return false;
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000210 }
211
212 fCanvas->drawPicture(*fPicture);
scroggo@google.com9a412522012-09-07 15:21:18 +0000213 fCanvas->flush();
borenet@google.com070d3542012-10-26 13:26:55 +0000214 if (NULL != path) {
215 return write(fCanvas, *path);
216 }
217 return true;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000218}
219
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000220///////////////////////////////////////////////////////////////////////////////////////////////
221
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000222TiledPictureRenderer::TiledPictureRenderer()
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000223 : fTileWidth(kDefaultTileWidth)
rileya@google.comb947b912012-08-29 17:35:07 +0000224 , fTileHeight(kDefaultTileHeight)
rileya@google.coma04dc022012-09-10 19:01:38 +0000225 , fTileWidthPercentage(0.0)
rileya@google.comb947b912012-08-29 17:35:07 +0000226 , fTileHeightPercentage(0.0)
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000227 , fTileMinPowerOf2Width(0) { }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000228
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000229void TiledPictureRenderer::init(SkPicture* pict) {
230 SkASSERT(pict != NULL);
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000231 SkASSERT(0 == fTileRects.count());
232 if (NULL == pict || fTileRects.count() != 0) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000233 return;
234 }
235
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000236 // Do not call INHERITED::init(), which would create a (potentially large) canvas which is not
237 // used by bench_pictures.
238 fPicture = pict;
junov@chromium.org9313ca42012-11-02 18:11:49 +0000239 fPicture->ref();
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000240 this->buildBBoxHierarchy();
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000241
242 if (fTileWidthPercentage > 0) {
robertphillips@google.com5d8d1862012-08-15 14:36:41 +0000243 fTileWidth = sk_float_ceil2int(float(fTileWidthPercentage * fPicture->width() / 100));
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000244 }
245 if (fTileHeightPercentage > 0) {
robertphillips@google.com5d8d1862012-08-15 14:36:41 +0000246 fTileHeight = sk_float_ceil2int(float(fTileHeightPercentage * fPicture->height() / 100));
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000247 }
248
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000249 if (fTileMinPowerOf2Width > 0) {
250 this->setupPowerOf2Tiles();
251 } else {
252 this->setupTiles();
253 }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000254}
255
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000256void TiledPictureRenderer::end() {
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000257 fTileRects.reset();
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000258 this->INHERITED::end();
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000259}
260
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000261void TiledPictureRenderer::setupTiles() {
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000262 for (int tile_y_start = 0; tile_y_start < fPicture->height(); tile_y_start += fTileHeight) {
263 for (int tile_x_start = 0; tile_x_start < fPicture->width(); tile_x_start += fTileWidth) {
264 *fTileRects.append() = SkRect::MakeXYWH(SkIntToScalar(tile_x_start),
265 SkIntToScalar(tile_y_start),
266 SkIntToScalar(fTileWidth),
267 SkIntToScalar(fTileHeight));
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000268 }
269 }
270}
271
272// The goal of the powers of two tiles is to minimize the amount of wasted tile
273// space in the width-wise direction and then minimize the number of tiles. The
274// constraints are that every tile must have a pixel width that is a power of
275// two and also be of some minimal width (that is also a power of two).
276//
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000277// This is solved by first taking our picture size and rounding it up to the
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000278// multiple of the minimal width. The binary representation of this rounded
279// value gives us the tiles we need: a bit of value one means we need a tile of
280// that size.
281void TiledPictureRenderer::setupPowerOf2Tiles() {
282 int rounded_value = fPicture->width();
283 if (fPicture->width() % fTileMinPowerOf2Width != 0) {
284 rounded_value = fPicture->width() - (fPicture->width() % fTileMinPowerOf2Width)
285 + fTileMinPowerOf2Width;
286 }
287
robertphillips@google.com94acc702012-09-06 18:43:21 +0000288 int num_bits = SkScalarCeilToInt(SkScalarLog2(SkIntToScalar(fPicture->width())));
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000289 int largest_possible_tile_size = 1 << num_bits;
290
291 // The tile height is constant for a particular picture.
292 for (int tile_y_start = 0; tile_y_start < fPicture->height(); tile_y_start += fTileHeight) {
293 int tile_x_start = 0;
294 int current_width = largest_possible_tile_size;
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000295 // Set fTileWidth to be the width of the widest tile, so that each canvas is large enough
296 // to draw each tile.
297 fTileWidth = current_width;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000298
299 while (current_width >= fTileMinPowerOf2Width) {
300 // It is very important this is a bitwise AND.
301 if (current_width & rounded_value) {
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000302 *fTileRects.append() = SkRect::MakeXYWH(SkIntToScalar(tile_x_start),
303 SkIntToScalar(tile_y_start),
304 SkIntToScalar(current_width),
305 SkIntToScalar(fTileHeight));
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000306 tile_x_start += current_width;
307 }
308
309 current_width >>= 1;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000310 }
311 }
312}
313
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000314/**
315 * Draw the specified playback to the canvas translated to rectangle provided, so that this mini
316 * canvas represents the rectangle's portion of the overall picture.
317 * Saves and restores so that the initial clip and matrix return to their state before this function
318 * is called.
319 */
320template<class T>
321static void DrawTileToCanvas(SkCanvas* canvas, const SkRect& tileRect, T* playback) {
322 int saveCount = canvas->save();
323 // Translate so that we draw the correct portion of the picture
324 canvas->translate(-tileRect.fLeft, -tileRect.fTop);
325 playback->draw(canvas);
326 canvas->restoreToCount(saveCount);
327 canvas->flush();
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000328}
329
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000330///////////////////////////////////////////////////////////////////////////////////////////////
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000331
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000332bool TiledPictureRenderer::render(const SkString* path) {
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000333 SkASSERT(fPicture != NULL);
334 if (NULL == fPicture) {
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000335 return false;
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000336 }
337
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000338 // Reuse one canvas for all tiles.
339 SkCanvas* canvas = this->setupCanvas(fTileWidth, fTileHeight);
340 SkAutoUnref aur(canvas);
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000341
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000342 bool success = true;
343 for (int i = 0; i < fTileRects.count(); ++i) {
344 DrawTileToCanvas(canvas, fTileRects[i], fPicture);
345 if (NULL != path) {
346 success &= writeAppendNumber(canvas, path, i);
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000347 }
keyar@chromium.org163b5672012-08-01 17:53:29 +0000348 }
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000349 return success;
keyar@chromium.org163b5672012-08-01 17:53:29 +0000350}
351
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000352SkCanvas* TiledPictureRenderer::setupCanvas(int width, int height) {
353 SkCanvas* canvas = this->INHERITED::setupCanvas(width, height);
354 SkASSERT(fPicture != NULL);
355 // Clip the tile to an area that is completely in what the SkPicture says is the
356 // drawn-to area. This is mostly important for tiles on the right and bottom edges
357 // as they may go over this area and the picture may have some commands that
358 // draw outside of this area and so should not actually be written.
359 SkRect clip = SkRect::MakeWH(SkIntToScalar(fPicture->width()),
360 SkIntToScalar(fPicture->height()));
361 canvas->clipRect(clip);
362 return canvas;
363}
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000364///////////////////////////////////////////////////////////////////////////////////////////////
365
366// Holds all of the information needed to draw a set of tiles.
367class CloneData : public SkRunnable {
368
369public:
370 CloneData(SkPicture* clone, SkCanvas* canvas, SkTDArray<SkRect>& rects, int start, int end,
371 SkRunnable* done)
372 : fClone(clone)
373 , fCanvas(canvas)
374 , fPath(NULL)
375 , fRects(rects)
376 , fStart(start)
377 , fEnd(end)
378 , fSuccess(NULL)
379 , fDone(done) {
380 SkASSERT(fDone != NULL);
381 }
382
383 virtual void run() SK_OVERRIDE {
384 SkGraphics::SetTLSFontCacheLimit(1024 * 1024);
385 for (int i = fStart; i < fEnd; i++) {
386 DrawTileToCanvas(fCanvas, fRects[i], fClone);
387 if (fPath != NULL && !writeAppendNumber(fCanvas, fPath, i)
388 && fSuccess != NULL) {
389 *fSuccess = false;
390 // If one tile fails to write to a file, do not continue drawing the rest.
391 break;
392 }
393 }
394 fDone->run();
395 }
396
397 void setPathAndSuccess(const SkString* path, bool* success) {
398 fPath = path;
399 fSuccess = success;
400 }
401
402private:
403 // All pointers unowned.
404 SkPicture* fClone; // Picture to draw from. Each CloneData has a unique one which
405 // is threadsafe.
406 SkCanvas* fCanvas; // Canvas to draw to. Reused for each tile.
407 const SkString* fPath; // If non-null, path to write the result to as a PNG.
408 SkTDArray<SkRect>& fRects; // All tiles of the picture.
409 const int fStart; // Range of tiles drawn by this thread.
410 const int fEnd;
411 bool* fSuccess; // Only meaningful if path is non-null. Shared by all threads,
412 // and only set to false upon failure to write to a PNG.
413 SkRunnable* fDone;
414};
415
416MultiCorePictureRenderer::MultiCorePictureRenderer(int threadCount)
417: fNumThreads(threadCount)
418, fThreadPool(threadCount)
419, fCountdown(threadCount) {
420 // Only need to create fNumThreads - 1 clones, since one thread will use the base
421 // picture.
422 fPictureClones = SkNEW_ARRAY(SkPicture, fNumThreads - 1);
423 fCloneData = SkNEW_ARRAY(CloneData*, fNumThreads);
424}
425
426void MultiCorePictureRenderer::init(SkPicture *pict) {
427 // Set fPicture and the tiles.
428 this->INHERITED::init(pict);
429 for (int i = 0; i < fNumThreads; ++i) {
430 *fCanvasPool.append() = this->setupCanvas(this->getTileWidth(), this->getTileHeight());
431 }
432 // Only need to create fNumThreads - 1 clones, since one thread will use the base picture.
433 fPicture->clone(fPictureClones, fNumThreads - 1);
434 // Populate each thread with the appropriate data.
435 // Group the tiles into nearly equal size chunks, rounding up so we're sure to cover them all.
436 const int chunkSize = (fTileRects.count() + fNumThreads - 1) / fNumThreads;
437
438 for (int i = 0; i < fNumThreads; i++) {
439 SkPicture* pic;
440 if (i == fNumThreads-1) {
441 // The last set will use the original SkPicture.
442 pic = fPicture;
443 } else {
444 pic = &fPictureClones[i];
445 }
446 const int start = i * chunkSize;
447 const int end = SkMin32(start + chunkSize, fTileRects.count());
448 fCloneData[i] = SkNEW_ARGS(CloneData,
449 (pic, fCanvasPool[i], fTileRects, start, end, &fCountdown));
450 }
451}
452
453bool MultiCorePictureRenderer::render(const SkString *path) {
454 bool success = true;
455 if (path != NULL) {
456 for (int i = 0; i < fNumThreads-1; i++) {
457 fCloneData[i]->setPathAndSuccess(path, &success);
458 }
459 }
460
461 fCountdown.reset(fNumThreads);
462 for (int i = 0; i < fNumThreads; i++) {
463 fThreadPool.add(fCloneData[i]);
464 }
465 fCountdown.wait();
466
467 return success;
468}
469
470void MultiCorePictureRenderer::end() {
471 for (int i = 0; i < fNumThreads - 1; i++) {
472 SkDELETE(fCloneData[i]);
473 fCloneData[i] = NULL;
474 }
475
476 fCanvasPool.unrefAll();
477
478 this->INHERITED::end();
479}
480
481MultiCorePictureRenderer::~MultiCorePictureRenderer() {
482 // Each individual CloneData was deleted in end.
483 SkDELETE_ARRAY(fCloneData);
484 SkDELETE_ARRAY(fPictureClones);
485}
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000486
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000487///////////////////////////////////////////////////////////////////////////////////////////////
scroggo@google.com9a412522012-09-07 15:21:18 +0000488
489void PlaybackCreationRenderer::setup() {
junov@chromium.org9313ca42012-11-02 18:11:49 +0000490 fReplayer.reset(this->createPicture());
491 SkCanvas* recorder = fReplayer->beginRecording(fPicture->width(), fPicture->height(),
492 this->recordFlags());
scroggo@google.com9a412522012-09-07 15:21:18 +0000493 fPicture->draw(recorder);
494}
495
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000496bool PlaybackCreationRenderer::render(const SkString*) {
junov@chromium.org9313ca42012-11-02 18:11:49 +0000497 fReplayer->endRecording();
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000498 // Since this class does not actually render, return false.
499 return false;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000500}
501
junov@chromium.org9313ca42012-11-02 18:11:49 +0000502///////////////////////////////////////////////////////////////////////////////////////////////
503// SkPicture variants for each BBoxHierarchy type
504
505class RTreePicture : public SkPicture {
506public:
507 virtual SkBBoxHierarchy* createBBoxHierarchy() const SK_OVERRIDE{
508 static const int kRTreeMinChildren = 6;
509 static const int kRTreeMaxChildren = 11;
510 SkScalar aspectRatio = SkScalarDiv(SkIntToScalar(fWidth),
511 SkIntToScalar(fHeight));
512 return SkRTree::Create(kRTreeMinChildren, kRTreeMaxChildren,
513 aspectRatio);
514 }
515};
516
517SkPicture* PictureRenderer::createPicture() {
518 switch (fBBoxHierarchyType) {
519 case kNone_BBoxHierarchyType:
520 return SkNEW(SkPicture);
521 case kRTree_BBoxHierarchyType:
522 return SkNEW(RTreePicture);
523 }
524 SkASSERT(0); // invalid bbhType
525 return NULL;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000526}
junov@chromium.org9313ca42012-11-02 18:11:49 +0000527
528} // namespace sk_tools