blob: 96649de3b83c48e3e6d3d191c64ace0a0a0b77f1 [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
keyar@chromium.org9299ede2012-08-21 19:05:08 +0000102bool PictureRenderer::write(const SkString& path) const {
103 SkASSERT(fCanvas.get() != NULL);
104 SkASSERT(fPicture != NULL);
105 if (NULL == fCanvas.get() || NULL == fPicture) {
106 return false;
107 }
108
109 SkBitmap bitmap;
110 sk_tools::setup_bitmap(&bitmap, fPicture->width(), fPicture->height());
111
112 fCanvas->readPixels(&bitmap, 0, 0);
113 sk_tools::force_all_opaque(bitmap);
114
115 return SkImageEncoder::EncodeFile(path.c_str(), bitmap, SkImageEncoder::kPNG_Type, 100);
116}
117
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000118///////////////////////////////////////////////////////////////////////////////////////////////
119
scroggo@google.com9a412522012-09-07 15:21:18 +0000120void RecordPictureRenderer::render(bool doExtraWorkToDrawToBaseCanvas) {
121 SkPicture replayer;
122 SkCanvas* recorder = replayer.beginRecording(fPicture->width(), fPicture->height());
123 fPicture->draw(recorder);
124 replayer.endRecording();
125}
126
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000127///////////////////////////////////////////////////////////////////////////////////////////////
128
scroggo@google.com9a412522012-09-07 15:21:18 +0000129void PipePictureRenderer::render(bool doExtraWorkToDrawToBaseCanvas) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000130 SkASSERT(fCanvas.get() != NULL);
131 SkASSERT(fPicture != NULL);
keyar@chromium.org78a35c52012-08-20 15:03:44 +0000132 if (NULL == fCanvas.get() || NULL == fPicture) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000133 return;
134 }
135
136 PipeController pipeController(fCanvas.get());
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000137 SkGPipeWriter writer;
138 SkCanvas* pipeCanvas = writer.startRecording(&pipeController);
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000139 pipeCanvas->drawPicture(*fPicture);
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000140 writer.endRecording();
scroggo@google.com9a412522012-09-07 15:21:18 +0000141 fCanvas->flush();
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000142}
143
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000144///////////////////////////////////////////////////////////////////////////////////////////////
145
scroggo@google.com9a412522012-09-07 15:21:18 +0000146void SimplePictureRenderer::render(bool doExtraWorkToDrawToBaseCanvas) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000147 SkASSERT(fCanvas.get() != NULL);
148 SkASSERT(fPicture != NULL);
keyar@chromium.org78a35c52012-08-20 15:03:44 +0000149 if (NULL == fCanvas.get() || NULL == fPicture) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000150 return;
151 }
152
153 fCanvas->drawPicture(*fPicture);
scroggo@google.com9a412522012-09-07 15:21:18 +0000154 fCanvas->flush();
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000155}
156
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000157///////////////////////////////////////////////////////////////////////////////////////////////
158
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000159TiledPictureRenderer::TiledPictureRenderer()
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000160 : fUsePipe(false)
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000161 , fTileWidth(kDefaultTileWidth)
rileya@google.comb947b912012-08-29 17:35:07 +0000162 , fTileHeight(kDefaultTileHeight)
rileya@google.coma04dc022012-09-10 19:01:38 +0000163 , fTileWidthPercentage(0.0)
rileya@google.comb947b912012-08-29 17:35:07 +0000164 , fTileHeightPercentage(0.0)
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000165 , fTileMinPowerOf2Width(0)
166 , fTileCounter(0)
167 , fNumThreads(1)
168 , fPictureClones(NULL)
169 , fPipeController(NULL) { }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000170
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000171void TiledPictureRenderer::init(SkPicture* pict) {
172 SkASSERT(pict != NULL);
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000173 SkASSERT(0 == fTileRects.count());
174 if (NULL == pict || fTileRects.count() != 0) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000175 return;
176 }
177
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000178 // Do not call INHERITED::init(), which would create a (potentially large) canvas which is not
179 // used by bench_pictures.
180 fPicture = pict;
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000181
182 if (fTileWidthPercentage > 0) {
robertphillips@google.com5d8d1862012-08-15 14:36:41 +0000183 fTileWidth = sk_float_ceil2int(float(fTileWidthPercentage * fPicture->width() / 100));
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000184 }
185 if (fTileHeightPercentage > 0) {
robertphillips@google.com5d8d1862012-08-15 14:36:41 +0000186 fTileHeight = sk_float_ceil2int(float(fTileHeightPercentage * fPicture->height() / 100));
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000187 }
188
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000189 if (fTileMinPowerOf2Width > 0) {
190 this->setupPowerOf2Tiles();
191 } else {
192 this->setupTiles();
193 }
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000194
195 if (this->multiThreaded()) {
196 for (int i = 0; i < fNumThreads; ++i) {
197 *fCanvasPool.append() = this->setupCanvas(fTileWidth, fTileHeight);
198 }
199 if (!fUsePipe) {
200 SkASSERT(NULL == fPictureClones);
201 // Only need to create fNumThreads - 1 clones, since one thread will use the base
202 // picture.
203 int numberOfClones = fNumThreads - 1;
204 // This will be deleted in end().
205 fPictureClones = SkNEW_ARRAY(SkPicture, numberOfClones);
206 fPictureClones->clone(fPictureClones, numberOfClones);
207 }
208 }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000209}
210
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000211void TiledPictureRenderer::end() {
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000212 fTileRects.reset();
213 SkDELETE_ARRAY(fPictureClones);
214 fPictureClones = NULL;
215 fCanvasPool.unrefAll();
216 if (fPipeController != NULL) {
217 SkASSERT(fUsePipe);
218 SkDELETE(fPipeController);
219 fPipeController = NULL;
220 }
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000221 this->INHERITED::end();
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000222}
223
224TiledPictureRenderer::~TiledPictureRenderer() {
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000225 // end() must be called to delete fPictureClones and fPipeController
226 SkASSERT(NULL == fPictureClones);
227 SkASSERT(NULL == fPipeController);
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000228}
229
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000230void TiledPictureRenderer::setupTiles() {
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000231 for (int tile_y_start = 0; tile_y_start < fPicture->height(); tile_y_start += fTileHeight) {
232 for (int tile_x_start = 0; tile_x_start < fPicture->width(); tile_x_start += fTileWidth) {
233 *fTileRects.append() = SkRect::MakeXYWH(SkIntToScalar(tile_x_start),
234 SkIntToScalar(tile_y_start),
235 SkIntToScalar(fTileWidth),
236 SkIntToScalar(fTileHeight));
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000237 }
238 }
239}
240
241// The goal of the powers of two tiles is to minimize the amount of wasted tile
242// space in the width-wise direction and then minimize the number of tiles. The
243// constraints are that every tile must have a pixel width that is a power of
244// two and also be of some minimal width (that is also a power of two).
245//
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000246// This is solved by first taking our picture size and rounding it up to the
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000247// multiple of the minimal width. The binary representation of this rounded
248// value gives us the tiles we need: a bit of value one means we need a tile of
249// that size.
250void TiledPictureRenderer::setupPowerOf2Tiles() {
251 int rounded_value = fPicture->width();
252 if (fPicture->width() % fTileMinPowerOf2Width != 0) {
253 rounded_value = fPicture->width() - (fPicture->width() % fTileMinPowerOf2Width)
254 + fTileMinPowerOf2Width;
255 }
256
robertphillips@google.com94acc702012-09-06 18:43:21 +0000257 int num_bits = SkScalarCeilToInt(SkScalarLog2(SkIntToScalar(fPicture->width())));
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000258 int largest_possible_tile_size = 1 << num_bits;
259
260 // The tile height is constant for a particular picture.
261 for (int tile_y_start = 0; tile_y_start < fPicture->height(); tile_y_start += fTileHeight) {
262 int tile_x_start = 0;
263 int current_width = largest_possible_tile_size;
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000264 // Set fTileWidth to be the width of the widest tile, so that each canvas is large enough
265 // to draw each tile.
266 fTileWidth = current_width;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000267
268 while (current_width >= fTileMinPowerOf2Width) {
269 // It is very important this is a bitwise AND.
270 if (current_width & rounded_value) {
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000271 *fTileRects.append() = SkRect::MakeXYWH(SkIntToScalar(tile_x_start),
272 SkIntToScalar(tile_y_start),
273 SkIntToScalar(current_width),
274 SkIntToScalar(fTileHeight));
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000275 tile_x_start += current_width;
276 }
277
278 current_width >>= 1;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000279 }
280 }
281}
282
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000283/**
284 * Draw the specified playback to the canvas translated to rectangle provided, so that this mini
285 * canvas represents the rectangle's portion of the overall picture.
286 * Saves and restores so that the initial clip and matrix return to their state before this function
287 * is called.
288 */
289template<class T>
290static void DrawTileToCanvas(SkCanvas* canvas, const SkRect& tileRect, T* playback) {
291 int saveCount = canvas->save();
292 // Translate so that we draw the correct portion of the picture
293 canvas->translate(-tileRect.fLeft, -tileRect.fTop);
294 playback->draw(canvas);
295 canvas->restoreToCount(saveCount);
296 canvas->flush();
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000297}
298
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000299///////////////////////////////////////////////////////////////////////////////////////////////
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000300// Base class for data used both by pipe and clone picture multi threaded drawing.
301
302struct ThreadData {
303 ThreadData(SkCanvas* target, int* tileCounter, SkTDArray<SkRect>* tileRects)
304 : fCanvas(target)
305 , fTileCounter(tileCounter)
306 , fTileRects(tileRects) {
307 SkASSERT(target != NULL && tileCounter != NULL && tileRects != NULL);
308 }
309
310 const SkRect* nextTile() {
311 if (int32_t i = sk_atomic_inc(fTileCounter) < fTileRects->count()) {
312 return &fTileRects->operator[](i);
313 }
314 return NULL;
315 }
316
317 // All of these are pointers to objects owned elsewhere
318 SkCanvas* fCanvas;
319private:
320 // Shared by all threads, this states which is the next tile to be drawn.
321 int32_t* fTileCounter;
322 // Points to the array of rectangles. The array is already created before any threads are
323 // started and then it is unmodified, so there is no danger of race conditions.
324 const SkTDArray<SkRect>* fTileRects;
325};
326
327///////////////////////////////////////////////////////////////////////////////////////////////
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000328// Draw using Pipe
329
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000330struct TileData : public ThreadData {
331 TileData(ThreadSafePipeController* controller, SkCanvas* canvas, int* tileCounter,
332 SkTDArray<SkRect>* tileRects)
333 : INHERITED(canvas, tileCounter, tileRects)
334 , fController(controller) {}
335
scroggo@google.com8e073ba2012-08-31 16:25:46 +0000336 ThreadSafePipeController* fController;
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000337
338 typedef ThreadData INHERITED;
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000339};
340
341static void DrawTile(void* data) {
342 SkGraphics::SetTLSFontCacheLimit(1 * 1024 * 1024);
343 TileData* tileData = static_cast<TileData*>(data);
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000344
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000345 const SkRect* tileRect;
346 while ((tileRect = tileData->nextTile()) != NULL) {
347 DrawTileToCanvas(tileData->fCanvas, *tileRect, tileData->fController);
348 }
349 SkDELETE(tileData);
350}
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000351
352///////////////////////////////////////////////////////////////////////////////////////////////
353// Draw using Picture
354
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000355struct CloneData : public ThreadData {
356 CloneData(SkPicture* clone, SkCanvas* target, int* tileCounter, SkTDArray<SkRect>* tileRects)
357 : INHERITED(target, tileCounter, tileRects)
358 , fClone(clone) {}
359
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000360 SkPicture* fClone;
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000361
362 typedef ThreadData INHERITED;
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000363};
364
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000365static void DrawClonedTiles(void* data) {
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000366 SkGraphics::SetTLSFontCacheLimit(1 * 1024 * 1024);
367 CloneData* cloneData = static_cast<CloneData*>(data);
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000368
369 const SkRect* tileRect;
370 while ((tileRect = cloneData->nextTile()) != NULL) {
371 DrawTileToCanvas(cloneData->fCanvas, *tileRect, cloneData->fClone);
372 }
373 SkDELETE(cloneData);
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000374}
375
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000376///////////////////////////////////////////////////////////////////////////////////////////////
377
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000378void TiledPictureRenderer::setup() {
379 if (this->multiThreaded()) {
380 // Reset to zero so we start with the first tile.
381 fTileCounter = 0;
382 if (fUsePipe) {
383 // Record the picture into the pipe controller. It is done here because unlike
384 // SkPicture, the pipe is modified (bitmaps can be removed) by drawing.
385 // fPipeController is deleted here after each call to render() except the last one and
386 // in end() for the last one.
387 if (fPipeController != NULL) {
388 SkDELETE(fPipeController);
389 }
390 fPipeController = SkNEW_ARGS(ThreadSafePipeController, (fTileRects.count()));
391 SkGPipeWriter writer;
392 SkCanvas* pipeCanvas = writer.startRecording(fPipeController,
393 SkGPipeWriter::kSimultaneousReaders_Flag);
394 SkASSERT(fPicture != NULL);
395 fPicture->draw(pipeCanvas);
396 writer.endRecording();
397 }
398 }
399}
400
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000401void TiledPictureRenderer::render(bool doExtraWorkToDrawToBaseCanvas) {
402 SkASSERT(fPicture != NULL);
403 if (NULL == fPicture) {
404 return;
405 }
406
407 if (doExtraWorkToDrawToBaseCanvas) {
408 if (NULL == fCanvas.get()) {
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000409 fCanvas.reset(this->INHERITED::setupCanvas());
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000410 }
411 }
412
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000413 if (this->multiThreaded()) {
414 SkASSERT(fCanvasPool.count() == fNumThreads);
415 SkTDArray<SkThread*> threads;
416 SkThread::entryPointProc proc = fUsePipe ? DrawTile : DrawClonedTiles;
417 for (int i = 0; i < fNumThreads; ++i) {
418 // data will be deleted by the entryPointProc.
419 ThreadData* data;
420 if (fUsePipe) {
421 data = SkNEW_ARGS(TileData,
422 (fPipeController, fCanvasPool[i], &fTileCounter, &fTileRects));
423 } else {
424 SkPicture* pic = (0 == i) ? fPicture : &fPictureClones[i-1];
425 data = SkNEW_ARGS(CloneData, (pic, fCanvasPool[i], &fTileCounter, &fTileRects));
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000426 }
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000427 SkThread* thread = SkNEW_ARGS(SkThread, (proc, data));
428 if (!thread->start()) {
429 SkDebugf("Could not start %s thread %i.\n", (fUsePipe ? "pipe" : "picture"), i);
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000430 }
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000431 *threads.append() = thread;
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000432 }
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000433 SkASSERT(threads.count() == fNumThreads);
434 for (int i = 0; i < fNumThreads; ++i) {
435 SkThread* thread = threads[i];
436 thread->join();
437 SkDELETE(thread);
438 }
439 threads.reset();
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000440 } else {
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000441 // For single thread, we really only need one canvas total.
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000442 SkCanvas* canvas = this->setupCanvas(fTileWidth, fTileHeight);
443 SkAutoUnref aur(canvas);
444
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000445 for (int i = 0; i < fTileRects.count(); ++i) {
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000446 DrawTileToCanvas(canvas, fTileRects[i], fPicture);
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000447 if (doExtraWorkToDrawToBaseCanvas) {
448 SkASSERT(fCanvas.get() != NULL);
449 SkBitmap source = canvas->getDevice()->accessBitmap(false);
450 fCanvas->drawBitmap(source, fTileRects[i].fLeft, fTileRects[i].fTop);
451 fCanvas->flush();
452 }
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000453 }
keyar@chromium.org163b5672012-08-01 17:53:29 +0000454 }
455}
456
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000457SkCanvas* TiledPictureRenderer::setupCanvas(int width, int height) {
458 SkCanvas* canvas = this->INHERITED::setupCanvas(width, height);
459 SkASSERT(fPicture != NULL);
460 // Clip the tile to an area that is completely in what the SkPicture says is the
461 // drawn-to area. This is mostly important for tiles on the right and bottom edges
462 // as they may go over this area and the picture may have some commands that
463 // draw outside of this area and so should not actually be written.
464 SkRect clip = SkRect::MakeWH(SkIntToScalar(fPicture->width()),
465 SkIntToScalar(fPicture->height()));
466 canvas->clipRect(clip);
467 return canvas;
468}
469
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000470///////////////////////////////////////////////////////////////////////////////////////////////
scroggo@google.com9a412522012-09-07 15:21:18 +0000471
472void PlaybackCreationRenderer::setup() {
473 SkCanvas* recorder = fReplayer.beginRecording(fPicture->width(), fPicture->height());
474 fPicture->draw(recorder);
475}
476
477void PlaybackCreationRenderer::render(bool doExtraWorkToDrawToBaseCanvas) {
478 fReplayer.endRecording();
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000479}
480
481}