PictureRenderer.cpp revision a04dc02b118363fedf3a7b11cfcdab886d368f8a
1/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "PictureRenderer.h"
9#include "picture_utils.h"
10#include "SamplePipeControllers.h"
11#include "SkCanvas.h"
12#include "SkDevice.h"
13#include "SkGPipe.h"
14#if SK_SUPPORT_GPU
15#include "SkGpuDevice.h"
16#endif
17#include "SkGraphics.h"
18#include "SkImageEncoder.h"
19#include "SkMatrix.h"
20#include "SkPicture.h"
21#include "SkScalar.h"
22#include "SkString.h"
23#include "SkTemplates.h"
24#include "SkTDArray.h"
25#include "SkThreadUtils.h"
26#include "SkTypes.h"
27
28namespace sk_tools {
29
30enum {
31    kDefaultTileWidth = 256,
32    kDefaultTileHeight = 256
33};
34
35void PictureRenderer::init(SkPicture* pict) {
36    SkASSERT(NULL == fPicture);
37    SkASSERT(NULL == fCanvas.get());
38    if (fPicture != NULL || NULL != fCanvas.get()) {
39        return;
40    }
41
42    SkASSERT(pict != NULL);
43    if (NULL == pict) {
44        return;
45    }
46
47    fPicture = pict;
48    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) {
56    switch(fDeviceType) {
57        case kBitmap_DeviceType: {
58            SkBitmap bitmap;
59            sk_tools::setup_bitmap(&bitmap, width, height);
60            return SkNEW_ARGS(SkCanvas, (bitmap));
61            break;
62        }
63#if SK_SUPPORT_GPU
64        case kGPU_DeviceType: {
65            SkAutoTUnref<SkGpuDevice> device(SkNEW_ARGS(SkGpuDevice,
66                                                    (fGrContext, SkBitmap::kARGB_8888_Config,
67                                                    width, height)));
68            return SkNEW_ARGS(SkCanvas, (device.get()));
69            break;
70        }
71#endif
72        default:
73            SkASSERT(0);
74    }
75
76    return NULL;
77}
78
79void PictureRenderer::end() {
80    this->resetState();
81    fPicture = NULL;
82    fCanvas.reset(NULL);
83}
84
85void PictureRenderer::resetState() {
86#if SK_SUPPORT_GPU
87    if (this->isUsingGpuDevice()) {
88        SkGLContext* glContext = fGrContextFactory.getGLContext(
89            GrContextFactory::kNative_GLContextType);
90
91        SkASSERT(glContext != NULL);
92        if (NULL == glContext) {
93            return;
94        }
95
96        fGrContext->flush();
97        SK_GL(*glContext, Finish());
98    }
99#endif
100}
101
102bool 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
118void RecordPictureRenderer::render(bool doExtraWorkToDrawToBaseCanvas) {
119    SkPicture replayer;
120    SkCanvas* recorder = replayer.beginRecording(fPicture->width(), fPicture->height());
121    fPicture->draw(recorder);
122    replayer.endRecording();
123}
124
125void PipePictureRenderer::render(bool doExtraWorkToDrawToBaseCanvas) {
126    SkASSERT(fCanvas.get() != NULL);
127    SkASSERT(fPicture != NULL);
128    if (NULL == fCanvas.get() || NULL == fPicture) {
129        return;
130    }
131
132    PipeController pipeController(fCanvas.get());
133    SkGPipeWriter writer;
134    SkCanvas* pipeCanvas = writer.startRecording(&pipeController);
135    pipeCanvas->drawPicture(*fPicture);
136    writer.endRecording();
137    fCanvas->flush();
138}
139
140void SimplePictureRenderer::render(bool doExtraWorkToDrawToBaseCanvas) {
141    SkASSERT(fCanvas.get() != NULL);
142    SkASSERT(fPicture != NULL);
143    if (NULL == fCanvas.get() || NULL == fPicture) {
144        return;
145    }
146
147    fCanvas->drawPicture(*fPicture);
148    fCanvas->flush();
149}
150
151TiledPictureRenderer::TiledPictureRenderer()
152    : fMultiThreaded(false)
153    , fUsePipe(false)
154    , fTileWidth(kDefaultTileWidth)
155    , fTileHeight(kDefaultTileHeight)
156    , fTileWidthPercentage(0.0)
157    , fTileHeightPercentage(0.0)
158    , fTileMinPowerOf2Width(0) { }
159
160void TiledPictureRenderer::init(SkPicture* pict) {
161    SkASSERT(pict != NULL);
162    SkASSERT(0 == fTiles.count());
163    if (NULL == pict || fTiles.count() != 0) {
164        return;
165    }
166
167    this->INHERITED::init(pict);
168
169    if (fTileWidthPercentage > 0) {
170        fTileWidth = sk_float_ceil2int(float(fTileWidthPercentage * fPicture->width() / 100));
171    }
172    if (fTileHeightPercentage > 0) {
173        fTileHeight = sk_float_ceil2int(float(fTileHeightPercentage * fPicture->height() / 100));
174    }
175
176    if (fTileMinPowerOf2Width > 0) {
177        this->setupPowerOf2Tiles();
178    } else {
179        this->setupTiles();
180    }
181}
182
183void TiledPictureRenderer::render(bool doExtraWorkToDrawToBaseCanvas) {
184    SkASSERT(fCanvas.get() != NULL);
185    SkASSERT(fPicture != NULL);
186    if (NULL == fCanvas.get() || NULL == fPicture) {
187        return;
188    }
189
190    this->drawTiles();
191    if (doExtraWorkToDrawToBaseCanvas) {
192        this->copyTilesToCanvas();
193    }
194}
195
196void TiledPictureRenderer::end() {
197    this->deleteTiles();
198    this->INHERITED::end();
199}
200
201TiledPictureRenderer::~TiledPictureRenderer() {
202    this->deleteTiles();
203}
204
205void TiledPictureRenderer::clipTile(SkCanvas* tile) {
206    SkRect clip = SkRect::MakeWH(SkIntToScalar(fPicture->width()),
207                                 SkIntToScalar(fPicture->height()));
208    tile->clipRect(clip);
209}
210
211void TiledPictureRenderer::addTile(int tile_x_start, int tile_y_start, int width, int height) {
212    SkCanvas* tile = this->setupCanvas(width, height);
213
214    tile->translate(SkIntToScalar(-tile_x_start), SkIntToScalar(-tile_y_start));
215    this->clipTile(tile);
216
217    fTiles.push(tile);
218}
219
220void TiledPictureRenderer::setupTiles() {
221    for (int tile_y_start = 0; tile_y_start < fPicture->height();
222         tile_y_start += fTileHeight) {
223        for (int tile_x_start = 0; tile_x_start < fPicture->width();
224             tile_x_start += fTileWidth) {
225            this->addTile(tile_x_start, tile_y_start, fTileWidth, fTileHeight);
226        }
227    }
228}
229
230// The goal of the powers of two tiles is to minimize the amount of wasted tile
231// space in the width-wise direction and then minimize the number of tiles. The
232// constraints are that every tile must have a pixel width that is a power of
233// two and also be of some minimal width (that is also a power of two).
234//
235// This is solved by first taking our picture size and rounding it up to the
236// multiple of the minimal width. The binary representation of this rounded
237// value gives us the tiles we need: a bit of value one means we need a tile of
238// that size.
239void TiledPictureRenderer::setupPowerOf2Tiles() {
240    int rounded_value = fPicture->width();
241    if (fPicture->width() % fTileMinPowerOf2Width != 0) {
242        rounded_value = fPicture->width() - (fPicture->width() % fTileMinPowerOf2Width)
243            + fTileMinPowerOf2Width;
244    }
245
246    int num_bits = SkScalarCeilToInt(SkScalarLog2(SkIntToScalar(fPicture->width())));
247    int largest_possible_tile_size = 1 << num_bits;
248
249    // The tile height is constant for a particular picture.
250    for (int tile_y_start = 0; tile_y_start < fPicture->height(); tile_y_start += fTileHeight) {
251        int tile_x_start = 0;
252        int current_width = largest_possible_tile_size;
253
254        while (current_width >= fTileMinPowerOf2Width) {
255            // It is very important this is a bitwise AND.
256            if (current_width & rounded_value) {
257                this->addTile(tile_x_start, tile_y_start, current_width, fTileHeight);
258                tile_x_start += current_width;
259            }
260
261            current_width >>= 1;
262        }
263    }
264}
265
266void TiledPictureRenderer::deleteTiles() {
267    for (int i = 0; i < fTiles.count(); ++i) {
268        SkDELETE(fTiles[i]);
269    }
270
271    fTiles.reset();
272}
273
274///////////////////////////////////////////////////////////////////////////////////////////////
275// Draw using Pipe
276
277struct TileData {
278    TileData(SkCanvas* canvas, ThreadSafePipeController* controller);
279    SkCanvas* fCanvas;
280    ThreadSafePipeController* fController;
281    SkThread fThread;
282};
283
284static void DrawTile(void* data) {
285    SkGraphics::SetTLSFontCacheLimit(1 * 1024 * 1024);
286    TileData* tileData = static_cast<TileData*>(data);
287    tileData->fController->playback(tileData->fCanvas);
288    tileData->fCanvas->flush();
289}
290
291TileData::TileData(SkCanvas* canvas, ThreadSafePipeController* controller)
292: fCanvas(canvas)
293, fController(controller)
294, fThread(&DrawTile, static_cast<void*>(this)) {}
295
296///////////////////////////////////////////////////////////////////////////////////////////////
297// Draw using Picture
298
299struct CloneData {
300    CloneData(SkCanvas* target, SkPicture* original);
301    SkCanvas* fCanvas;
302    SkPicture* fClone;
303    SkThread fThread;
304};
305
306static void DrawClonedTile(void* data) {
307    SkGraphics::SetTLSFontCacheLimit(1 * 1024 * 1024);
308    CloneData* cloneData = static_cast<CloneData*>(data);
309    cloneData->fCanvas->drawPicture(*cloneData->fClone);
310    cloneData->fCanvas->flush();
311}
312
313CloneData::CloneData(SkCanvas* target, SkPicture* clone)
314: fCanvas(target)
315, fClone(clone)
316, fThread(&DrawClonedTile, static_cast<void*>(this)) {}
317
318///////////////////////////////////////////////////////////////////////////////////////////////
319
320void TiledPictureRenderer::drawTiles() {
321    if (fMultiThreaded) {
322        if (fUsePipe) {
323            // First, draw into a pipe controller
324            SkGPipeWriter writer;
325            ThreadSafePipeController controller(fTiles.count());
326            SkCanvas* pipeCanvas = writer.startRecording(&controller,
327                                                         SkGPipeWriter::kSimultaneousReaders_Flag);
328            pipeCanvas->drawPicture(*(fPicture));
329            writer.endRecording();
330
331            // Create and start the threads.
332            TileData** tileData = SkNEW_ARRAY(TileData*, fTiles.count());
333            SkAutoTDeleteArray<TileData*> deleteTileData(tileData);
334            for (int i = 0; i < fTiles.count(); i++) {
335                tileData[i] = SkNEW_ARGS(TileData, (fTiles[i], &controller));
336                if (!tileData[i]->fThread.start()) {
337                    SkDebugf("could not start thread %i\n", i);
338                }
339            }
340            for (int i = 0; i < fTiles.count(); i++) {
341                tileData[i]->fThread.join();
342                SkDELETE(tileData[i]);
343            }
344        } else {
345            SkPicture* clones = SkNEW_ARRAY(SkPicture, fTiles.count());
346            SkAutoTDeleteArray<SkPicture> autodelete(clones);
347            fPicture->clone(clones, fTiles.count());
348            CloneData** cloneData = SkNEW_ARRAY(CloneData*, fTiles.count());
349            SkAutoTDeleteArray<CloneData*> deleteCloneData(cloneData);
350            for (int i = 0; i < fTiles.count(); i++) {
351                cloneData[i] = SkNEW_ARGS(CloneData, (fTiles[i], &clones[i]));
352                if (!cloneData[i]->fThread.start()) {
353                    SkDebugf("Could not start picture thread %i\n", i);
354                }
355            }
356            for (int i = 0; i < fTiles.count(); i++) {
357                cloneData[i]->fThread.join();
358                SkDELETE(cloneData[i]);
359            }
360        }
361    } else {
362        for (int i = 0; i < fTiles.count(); ++i) {
363            fTiles[i]->drawPicture(*(fPicture));
364            fTiles[i]->flush();
365        }
366    }
367}
368
369void TiledPictureRenderer::copyTilesToCanvas() {
370    for (int i = 0; i < fTiles.count(); ++i) {
371        // Since SkPicture performs a save and restore when being drawn to a
372        // canvas, we can be confident that the transform matrix of the canvas
373        // is what we set when creating the tiles.
374        SkMatrix matrix = fTiles[i]->getTotalMatrix();
375        SkScalar tile_x_start = matrix.getTranslateX();
376        SkScalar tile_y_start = matrix.getTranslateY();
377
378        SkBitmap source = fTiles[i]->getDevice()->accessBitmap(false);
379
380        fCanvas->drawBitmap(source, -tile_x_start, -tile_y_start);
381    }
382    fCanvas->flush();
383}
384
385void PlaybackCreationRenderer::setup() {
386    SkCanvas* recorder = fReplayer.beginRecording(fPicture->width(), fPicture->height());
387    fPicture->draw(recorder);
388}
389
390void PlaybackCreationRenderer::render(bool doExtraWorkToDrawToBaseCanvas) {
391    fReplayer.endRecording();
392}
393
394}
395