blob: e4a69986db21817aba418e6a62718873cb305c9c [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"
commit-bot@chromium.orga3f882c2013-12-13 20:52:36 +000011#include "SkBitmapHasher.h"
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000012#include "SkCanvas.h"
scroggo@google.com1b1bcc32013-05-21 20:31:23 +000013#include "SkData.h"
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000014#include "SkDevice.h"
robertphillips@google.com94d8f1e2013-12-18 17:25:33 +000015#include "SkDiscardableMemoryPool.h"
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000016#include "SkGPipe.h"
scroggo@google.com58b4ead2012-08-31 16:15:22 +000017#if SK_SUPPORT_GPU
robertphillips@google.comfe1b5362013-02-07 19:45:46 +000018#include "gl/GrGLDefines.h"
scroggo@google.com58b4ead2012-08-31 16:15:22 +000019#include "SkGpuDevice.h"
20#endif
21#include "SkGraphics.h"
22#include "SkImageEncoder.h"
caryclark@google.coma3622372012-11-06 21:26:13 +000023#include "SkMaskFilter.h"
keyar@chromium.orgea826952012-08-23 15:24:13 +000024#include "SkMatrix.h"
robertphillips78c71272014-10-09 04:59:19 -070025#include "SkMultiPictureDraw.h"
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +000026#include "SkOSFile.h"
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000027#include "SkPicture.h"
robertphillips@google.com770963f2014-04-18 18:04:41 +000028#include "SkPictureRecorder.h"
scroggo@google.com1b1bcc32013-05-21 20:31:23 +000029#include "SkPictureUtils.h"
30#include "SkPixelRef.h"
keyar@chromium.orgea826952012-08-23 15:24:13 +000031#include "SkScalar.h"
scroggo@google.coma9e3a362012-11-07 17:52:48 +000032#include "SkStream.h"
keyar@chromium.org9299ede2012-08-21 19:05:08 +000033#include "SkString.h"
robertphillips78c71272014-10-09 04:59:19 -070034#include "SkSurface.h"
scroggo@google.com58b4ead2012-08-31 16:15:22 +000035#include "SkTemplates.h"
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000036#include "SkTDArray.h"
scroggo@google.com58b4ead2012-08-31 16:15:22 +000037#include "SkThreadUtils.h"
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000038#include "SkTypes.h"
keyar@chromium.org4ea96c52012-08-20 15:03:29 +000039
reed@google.come15b2f52013-12-18 04:59:26 +000040static inline SkScalar scalar_log2(SkScalar x) {
41 static const SkScalar log2_conversion_factor = SkScalarDiv(1, SkScalarLog(2));
skia.committer@gmail.com3b85deb2013-12-18 07:01:56 +000042
reed@google.come15b2f52013-12-18 04:59:26 +000043 return SkScalarLog(x) * log2_conversion_factor;
44}
45
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000046namespace sk_tools {
47
48enum {
49 kDefaultTileWidth = 256,
50 kDefaultTileHeight = 256
51};
52
mtklein2a65a232014-08-26 14:07:04 -070053void PictureRenderer::init(const SkPicture* pict,
54 const SkString* writePath,
robertphillipsce4dd3d2014-07-07 13:46:35 -070055 const SkString* mismatchPath,
mtklein2a65a232014-08-26 14:07:04 -070056 const SkString* inputFilename,
robertphillips78c71272014-10-09 04:59:19 -070057 bool useChecksumBasedFilenames,
58 bool useMultiPictureDraw) {
commit-bot@chromium.org3f045172014-05-15 15:10:48 +000059 this->CopyString(&fWritePath, writePath);
60 this->CopyString(&fMismatchPath, mismatchPath);
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +000061 this->CopyString(&fInputFilename, inputFilename);
62 fUseChecksumBasedFilenames = useChecksumBasedFilenames;
robertphillips78c71272014-10-09 04:59:19 -070063 fUseMultiPictureDraw = useMultiPictureDraw;
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +000064
keyar@chromium.org78a35c52012-08-20 15:03:44 +000065 SkASSERT(NULL == fPicture);
66 SkASSERT(NULL == fCanvas.get());
bsalomon49f085d2014-09-05 13:34:00 -070067 if (fPicture || fCanvas.get()) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +000068 return;
69 }
70
71 SkASSERT(pict != NULL);
keyar@chromium.org78a35c52012-08-20 15:03:44 +000072 if (NULL == pict) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +000073 return;
74 }
75
robertphillips@google.com84b18c72014-04-13 19:09:42 +000076 fPicture.reset(pict)->ref();
keyar@chromium.orga474ce32012-08-20 15:03:57 +000077 fCanvas.reset(this->setupCanvas());
78}
79
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +000080void PictureRenderer::CopyString(SkString* dest, const SkString* src) {
bsalomon49f085d2014-09-05 13:34:00 -070081 if (src) {
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +000082 dest->set(*src);
83 } else {
84 dest->reset();
85 }
86}
87
caryclark@google.coma3622372012-11-06 21:26:13 +000088class FlagsDrawFilter : public SkDrawFilter {
89public:
90 FlagsDrawFilter(PictureRenderer::DrawFilterFlags* flags) :
91 fFlags(flags) {}
92
reed@google.com971aca72012-11-26 20:26:54 +000093 virtual bool filter(SkPaint* paint, Type t) {
caryclark@google.coma3622372012-11-06 21:26:13 +000094 paint->setFlags(paint->getFlags() & ~fFlags[t] & SkPaint::kAllFlags);
robertphillips@google.com49149312013-07-03 15:34:35 +000095 if (PictureRenderer::kMaskFilter_DrawFilterFlag & fFlags[t]) {
caryclark@google.coma3622372012-11-06 21:26:13 +000096 SkMaskFilter* maskFilter = paint->getMaskFilter();
bsalomon49f085d2014-09-05 13:34:00 -070097 if (maskFilter) {
reed@google.com457d8a72012-12-18 18:20:44 +000098 paint->setMaskFilter(NULL);
caryclark@google.coma3622372012-11-06 21:26:13 +000099 }
100 }
101 if (PictureRenderer::kHinting_DrawFilterFlag & fFlags[t]) {
102 paint->setHinting(SkPaint::kNo_Hinting);
103 } else if (PictureRenderer::kSlightHinting_DrawFilterFlag & fFlags[t]) {
104 paint->setHinting(SkPaint::kSlight_Hinting);
105 }
reed@google.com971aca72012-11-26 20:26:54 +0000106 return true;
caryclark@google.coma3622372012-11-06 21:26:13 +0000107 }
108
109private:
110 PictureRenderer::DrawFilterFlags* fFlags;
111};
112
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000113static void setUpFilter(SkCanvas* canvas, PictureRenderer::DrawFilterFlags* drawFilters) {
caryclark@google.coma3622372012-11-06 21:26:13 +0000114 if (drawFilters && !canvas->getDrawFilter()) {
115 canvas->setDrawFilter(SkNEW_ARGS(FlagsDrawFilter, (drawFilters)))->unref();
caryclark@google.come3e940c2012-11-07 16:42:17 +0000116 if (drawFilters[0] & PictureRenderer::kAAClip_DrawFilterFlag) {
117 canvas->setAllowSoftClip(false);
118 }
caryclark@google.coma3622372012-11-06 21:26:13 +0000119 }
caryclark@google.coma3622372012-11-06 21:26:13 +0000120}
121
keyar@chromium.orga474ce32012-08-20 15:03:57 +0000122SkCanvas* PictureRenderer::setupCanvas() {
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000123 const int width = this->getViewWidth();
124 const int height = this->getViewHeight();
125 return this->setupCanvas(width, height);
keyar@chromium.orga474ce32012-08-20 15:03:57 +0000126}
127
128SkCanvas* PictureRenderer::setupCanvas(int width, int height) {
caryclark@google.coma3622372012-11-06 21:26:13 +0000129 SkCanvas* canvas;
keyar@chromium.org4ea96c52012-08-20 15:03:29 +0000130 switch(fDeviceType) {
131 case kBitmap_DeviceType: {
132 SkBitmap bitmap;
keyar@chromium.orga474ce32012-08-20 15:03:57 +0000133 sk_tools::setup_bitmap(&bitmap, width, height);
caryclark@google.coma3622372012-11-06 21:26:13 +0000134 canvas = SkNEW_ARGS(SkCanvas, (bitmap));
keyar@chromium.org4ea96c52012-08-20 15:03:29 +0000135 }
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000136 break;
keyar@chromium.org4ea96c52012-08-20 15:03:29 +0000137#if SK_SUPPORT_GPU
scroggo@google.com0556ea02013-02-08 19:38:21 +0000138#if SK_ANGLE
139 case kAngle_DeviceType:
140 // fall through
141#endif
rmistry@google.com6ab96732014-01-06 18:37:24 +0000142#if SK_MESA
143 case kMesa_DeviceType:
144 // fall through
145#endif
commit-bot@chromium.org0fd52702014-03-07 18:41:14 +0000146 case kGPU_DeviceType:
147 case kNVPR_DeviceType: {
commit-bot@chromium.orgae403b92013-04-10 17:27:30 +0000148 SkAutoTUnref<GrSurface> target;
scroggo@google.com0556ea02013-02-08 19:38:21 +0000149 if (fGrContext) {
150 // create a render target to back the device
bsalomonf2703d82014-10-28 14:33:06 -0700151 GrSurfaceDesc desc;
scroggo@google.com0556ea02013-02-08 19:38:21 +0000152 desc.fConfig = kSkia8888_GrPixelConfig;
bsalomonf2703d82014-10-28 14:33:06 -0700153 desc.fFlags = kRenderTarget_GrSurfaceFlag;
scroggo@google.com0556ea02013-02-08 19:38:21 +0000154 desc.fWidth = width;
155 desc.fHeight = height;
jvanverth@google.comf6a90332013-05-02 12:39:37 +0000156 desc.fSampleCnt = fSampleCount;
commit-bot@chromium.orgae403b92013-04-10 17:27:30 +0000157 target.reset(fGrContext->createUncachedTexture(desc, NULL, 0));
scroggo@google.com0556ea02013-02-08 19:38:21 +0000158 }
commit-bot@chromium.orgae403b92013-04-10 17:27:30 +0000159 if (NULL == target.get()) {
scroggo@google.com0556ea02013-02-08 19:38:21 +0000160 SkASSERT(0);
161 return NULL;
162 }
163
reed4a8126e2014-09-22 07:29:03 -0700164 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(target,
165 SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType)));
caryclark@google.coma3622372012-11-06 21:26:13 +0000166 canvas = SkNEW_ARGS(SkCanvas, (device.get()));
scroggo@google.com0556ea02013-02-08 19:38:21 +0000167 break;
keyar@chromium.org4ea96c52012-08-20 15:03:29 +0000168 }
169#endif
170 default:
171 SkASSERT(0);
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000172 return NULL;
keyar@chromium.org4ea96c52012-08-20 15:03:29 +0000173 }
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000174 setUpFilter(canvas, fDrawFilters);
175 this->scaleToScaleFactor(canvas);
commit-bot@chromium.org17cc3ea2014-01-15 14:51:25 +0000176
177 // Pictures often lie about their extent (i.e., claim to be 100x100 but
178 // only ever draw to 90x100). Clear here so the undrawn portion will have
179 // a consistent color
180 canvas->clear(SK_ColorTRANSPARENT);
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000181 return canvas;
182}
keyar@chromium.orga474ce32012-08-20 15:03:57 +0000183
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000184void PictureRenderer::scaleToScaleFactor(SkCanvas* canvas) {
185 SkASSERT(canvas != NULL);
186 if (fScaleFactor != SK_Scalar1) {
187 canvas->scale(fScaleFactor, fScaleFactor);
188 }
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000189}
190
191void PictureRenderer::end() {
scroggo@google.com08085f82013-01-28 20:40:24 +0000192 this->resetState(true);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000193 fPicture.reset(NULL);
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000194 fCanvas.reset(NULL);
195}
196
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000197int PictureRenderer::getViewWidth() {
198 SkASSERT(fPicture != NULL);
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700199 int width = SkScalarCeilToInt(fPicture->cullRect().width() * fScaleFactor);
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000200 if (fViewport.width() > 0) {
201 width = SkMin32(width, fViewport.width());
202 }
203 return width;
204}
205
206int PictureRenderer::getViewHeight() {
207 SkASSERT(fPicture != NULL);
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700208 int height = SkScalarCeilToInt(fPicture->cullRect().height() * fScaleFactor);
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000209 if (fViewport.height() > 0) {
210 height = SkMin32(height, fViewport.height());
211 }
212 return height;
213}
214
junov@chromium.org9313ca42012-11-02 18:11:49 +0000215/** Converts fPicture to a picture that uses a BBoxHierarchy.
216 * PictureRenderer subclasses that are used to test picture playback
217 * should call this method during init.
218 */
219void PictureRenderer::buildBBoxHierarchy() {
bsalomon49f085d2014-09-05 13:34:00 -0700220 SkASSERT(fPicture);
221 if (kNone_BBoxHierarchyType != fBBoxHierarchyType && fPicture) {
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000222 SkAutoTDelete<SkBBHFactory> factory(this->getFactory());
223 SkPictureRecorder recorder;
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700224 SkCanvas* canvas = recorder.beginRecording(fPicture->cullRect().width(),
225 fPicture->cullRect().height(),
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000226 factory.get(),
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000227 this->recordFlags());
robertphillipsc5ba71d2014-09-04 08:42:50 -0700228 fPicture->playback(canvas);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000229 fPicture.reset(recorder.endRecording());
junov@chromium.org9313ca42012-11-02 18:11:49 +0000230 }
231}
232
scroggo@google.com08085f82013-01-28 20:40:24 +0000233void PictureRenderer::resetState(bool callFinish) {
keyar@chromium.org28136b32012-08-20 15:04:15 +0000234#if SK_SUPPORT_GPU
kkinnunen9e61bb72014-10-09 05:24:15 -0700235 SkGLContext* glContext = this->getGLContext();
scroggo@google.com0556ea02013-02-08 19:38:21 +0000236 if (NULL == glContext) {
237 SkASSERT(kBitmap_DeviceType == fDeviceType);
238 return;
239 }
keyar@chromium.org28136b32012-08-20 15:04:15 +0000240
scroggo@google.com0556ea02013-02-08 19:38:21 +0000241 fGrContext->flush();
commit-bot@chromium.org51c040e2014-03-11 22:58:00 +0000242 glContext->swapBuffers();
scroggo@google.com0556ea02013-02-08 19:38:21 +0000243 if (callFinish) {
244 SK_GL(*glContext, Finish());
keyar@chromium.org77a55222012-08-20 15:03:47 +0000245 }
keyar@chromium.orga40c20d2012-08-20 15:04:12 +0000246#endif
keyar@chromium.org77a55222012-08-20 15:03:47 +0000247}
248
robertphillips@google.com94d8f1e2013-12-18 17:25:33 +0000249void PictureRenderer::purgeTextures() {
250 SkDiscardableMemoryPool* pool = SkGetGlobalDiscardableMemoryPool();
251
252 pool->dumpPool();
253
254#if SK_SUPPORT_GPU
kkinnunen9e61bb72014-10-09 05:24:15 -0700255 SkGLContext* glContext = this->getGLContext();
robertphillips@google.com94d8f1e2013-12-18 17:25:33 +0000256 if (NULL == glContext) {
257 SkASSERT(kBitmap_DeviceType == fDeviceType);
258 return;
259 }
260
261 // resetState should've already done this
262 fGrContext->flush();
263
264 fGrContext->purgeAllUnlockedResources();
265#endif
266}
267
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000268/**
commit-bot@chromium.org4610a462014-04-29 19:39:22 +0000269 * Write the canvas to an image file and/or JSON summary.
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000270 *
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000271 * @param canvas Must be non-null. Canvas to be written to a file.
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000272 * @param writePath If nonempty, write the binary image to a file within this directory.
273 * @param mismatchPath If nonempty, write the binary image to a file within this directory,
274 * but only if the image does not match expectations.
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000275 * @param inputFilename If we are writing out a binary image, use this to build its filename.
commit-bot@chromium.org4610a462014-04-29 19:39:22 +0000276 * @param jsonSummaryPtr If not null, add image results (checksum) to this summary.
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000277 * @param useChecksumBasedFilenames If true, use checksum-based filenames when writing to disk.
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000278 * @param tileNumberPtr If not null, which tile number this image contains.
commit-bot@chromium.orga3f882c2013-12-13 20:52:36 +0000279 *
commit-bot@chromium.org4610a462014-04-29 19:39:22 +0000280 * @return bool True if the operation completed successfully.
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000281 */
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000282static bool write(SkCanvas* canvas, const SkString& writePath, const SkString& mismatchPath,
283 const SkString& inputFilename, ImageResultsAndExpectations *jsonSummaryPtr,
284 bool useChecksumBasedFilenames, const int* tileNumberPtr=NULL) {
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000285 SkASSERT(canvas != NULL);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000286 if (NULL == canvas) {
keyar@chromium.org9299ede2012-08-21 19:05:08 +0000287 return false;
288 }
289
290 SkBitmap bitmap;
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000291 SkISize size = canvas->getDeviceSize();
commit-bot@chromium.org205ce482014-05-12 15:37:20 +0000292 setup_bitmap(&bitmap, size.width(), size.height());
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000293
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000294 canvas->readPixels(&bitmap, 0, 0);
commit-bot@chromium.org205ce482014-05-12 15:37:20 +0000295 force_all_opaque(bitmap);
296 BitmapAndDigest bitmapAndDigest(bitmap);
keyar@chromium.org9299ede2012-08-21 19:05:08 +0000297
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000298 SkString escapedInputFilename(inputFilename);
299 replace_char(&escapedInputFilename, '.', '_');
300
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000301 // TODO(epoger): what about including the config type within outputFilename? That way,
302 // we could combine results of different config types without conflicting filenames.
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000303 SkString outputFilename;
304 const char *outputSubdirPtr = NULL;
305 if (useChecksumBasedFilenames) {
epoger85b438d2014-08-21 23:21:32 -0700306 ImageDigest *imageDigestPtr = bitmapAndDigest.getImageDigestPtr();
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000307 outputSubdirPtr = escapedInputFilename.c_str();
commit-bot@chromium.org205ce482014-05-12 15:37:20 +0000308 outputFilename.set(imageDigestPtr->getHashType());
309 outputFilename.append("_");
310 outputFilename.appendU64(imageDigestPtr->getHashValue());
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000311 } else {
312 outputFilename.set(escapedInputFilename);
bsalomon49f085d2014-09-05 13:34:00 -0700313 if (tileNumberPtr) {
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000314 outputFilename.append("-tile");
315 outputFilename.appendS32(*tileNumberPtr);
316 }
commit-bot@chromium.orga3f882c2013-12-13 20:52:36 +0000317 }
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000318 outputFilename.append(".png");
commit-bot@chromium.orga3f882c2013-12-13 20:52:36 +0000319
bsalomon49f085d2014-09-05 13:34:00 -0700320 if (jsonSummaryPtr) {
epoger85b438d2014-08-21 23:21:32 -0700321 ImageDigest *imageDigestPtr = bitmapAndDigest.getImageDigestPtr();
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000322 SkString outputRelativePath;
323 if (outputSubdirPtr) {
324 outputRelativePath.set(outputSubdirPtr);
325 outputRelativePath.append("/"); // always use "/", even on Windows
326 outputRelativePath.append(outputFilename);
327 } else {
328 outputRelativePath.set(outputFilename);
329 }
330
331 jsonSummaryPtr->add(inputFilename.c_str(), outputRelativePath.c_str(),
commit-bot@chromium.org205ce482014-05-12 15:37:20 +0000332 *imageDigestPtr, tileNumberPtr);
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000333 if (!mismatchPath.isEmpty() &&
epoger85b438d2014-08-21 23:21:32 -0700334 !jsonSummaryPtr->getExpectation(inputFilename.c_str(),
335 tileNumberPtr).matches(*imageDigestPtr)) {
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000336 if (!write_bitmap_to_disk(bitmap, mismatchPath, outputSubdirPtr, outputFilename)) {
337 return false;
338 }
339 }
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000340 }
341
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000342 if (writePath.isEmpty()) {
commit-bot@chromium.org4610a462014-04-29 19:39:22 +0000343 return true;
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000344 } else {
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000345 return write_bitmap_to_disk(bitmap, writePath, outputSubdirPtr, outputFilename);
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000346 }
keyar@chromium.org9299ede2012-08-21 19:05:08 +0000347}
348
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000349///////////////////////////////////////////////////////////////////////////////////////////////
350
djsollen@google.comfd9720c2012-11-06 16:54:40 +0000351SkCanvas* RecordPictureRenderer::setupCanvas(int width, int height) {
352 // defer the canvas setup until the render step
353 return NULL;
354}
355
reed@google.com672588b2014-01-08 15:42:01 +0000356// the size_t* parameter is deprecated, so we ignore it
357static SkData* encode_bitmap_to_data(size_t*, const SkBitmap& bm) {
scroggo@google.com1b1bcc32013-05-21 20:31:23 +0000358 return SkImageEncoder::EncodeData(bm, SkImageEncoder::kPNG_Type, 100);
scroggo@google.coma9e3a362012-11-07 17:52:48 +0000359}
360
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000361bool RecordPictureRenderer::render(SkBitmap** out) {
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000362 SkAutoTDelete<SkBBHFactory> factory(this->getFactory());
363 SkPictureRecorder recorder;
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700364 SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(this->getViewWidth()),
365 SkIntToScalar(this->getViewHeight()),
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000366 factory.get(),
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000367 this->recordFlags());
368 this->scaleToScaleFactor(canvas);
robertphillipsc5ba71d2014-09-04 08:42:50 -0700369 fPicture->playback(canvas);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000370 SkAutoTUnref<SkPicture> picture(recorder.endRecording());
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000371 if (!fWritePath.isEmpty()) {
scroggo@google.coma9e3a362012-11-07 17:52:48 +0000372 // Record the new picture as a new SKP with PNG encoded bitmaps.
tfarinaa8e2e152014-07-28 19:26:58 -0700373 SkString skpPath = SkOSPath::Join(fWritePath.c_str(), fInputFilename.c_str());
scroggo@google.coma9e3a362012-11-07 17:52:48 +0000374 SkFILEWStream stream(skpPath.c_str());
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000375 picture->serialize(&stream, &encode_bitmap_to_data);
scroggo@google.coma9e3a362012-11-07 17:52:48 +0000376 return true;
377 }
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000378 return false;
scroggo@google.com9a412522012-09-07 15:21:18 +0000379}
380
scroggo@google.com0a049b82012-11-02 22:01:26 +0000381SkString RecordPictureRenderer::getConfigNameInternal() {
382 return SkString("record");
383}
384
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000385///////////////////////////////////////////////////////////////////////////////////////////////
386
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000387bool PipePictureRenderer::render(SkBitmap** out) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000388 SkASSERT(fCanvas.get() != NULL);
389 SkASSERT(fPicture != NULL);
keyar@chromium.org78a35c52012-08-20 15:03:44 +0000390 if (NULL == fCanvas.get() || NULL == fPicture) {
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000391 return false;
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000392 }
393
394 PipeController pipeController(fCanvas.get());
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000395 SkGPipeWriter writer;
396 SkCanvas* pipeCanvas = writer.startRecording(&pipeController);
robertphillips9b14f262014-06-04 05:40:44 -0700397 pipeCanvas->drawPicture(fPicture);
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000398 writer.endRecording();
scroggo@google.com9a412522012-09-07 15:21:18 +0000399 fCanvas->flush();
bsalomon49f085d2014-09-05 13:34:00 -0700400 if (out) {
edisonn@google.com84f548c2012-12-18 22:24:03 +0000401 *out = SkNEW(SkBitmap);
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700402 setup_bitmap(*out, SkScalarCeilToInt(fPicture->cullRect().width()),
403 SkScalarCeilToInt(fPicture->cullRect().height()));
edisonn@google.com84f548c2012-12-18 22:24:03 +0000404 fCanvas->readPixels(*out, 0, 0);
skia.committer@gmail.coma7d8e3e2012-12-19 02:01:38 +0000405 }
commit-bot@chromium.org8991c672014-05-22 00:36:05 +0000406 if (fEnableWrites) {
407 return write(fCanvas, fWritePath, fMismatchPath, fInputFilename, fJsonSummaryPtr,
408 fUseChecksumBasedFilenames);
409 } else {
410 return true;
411 }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000412}
413
scroggo@google.com0a049b82012-11-02 22:01:26 +0000414SkString PipePictureRenderer::getConfigNameInternal() {
415 return SkString("pipe");
416}
417
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000418///////////////////////////////////////////////////////////////////////////////////////////////
419
robertphillipsce4dd3d2014-07-07 13:46:35 -0700420void SimplePictureRenderer::init(const SkPicture* picture, const SkString* writePath,
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000421 const SkString* mismatchPath, const SkString* inputFilename,
robertphillips78c71272014-10-09 04:59:19 -0700422 bool useChecksumBasedFilenames, bool useMultiPictureDraw) {
423 INHERITED::init(picture, writePath, mismatchPath, inputFilename,
424 useChecksumBasedFilenames, useMultiPictureDraw);
junov@chromium.org9313ca42012-11-02 18:11:49 +0000425 this->buildBBoxHierarchy();
426}
427
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000428bool SimplePictureRenderer::render(SkBitmap** out) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000429 SkASSERT(fCanvas.get() != NULL);
bsalomon49f085d2014-09-05 13:34:00 -0700430 SkASSERT(fPicture);
keyar@chromium.org78a35c52012-08-20 15:03:44 +0000431 if (NULL == fCanvas.get() || NULL == fPicture) {
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000432 return false;
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000433 }
434
robertphillips78c71272014-10-09 04:59:19 -0700435 if (fUseMultiPictureDraw) {
436 SkMultiPictureDraw mpd;
437
438 mpd.add(fCanvas, fPicture);
439
440 mpd.draw();
441 } else {
442 fCanvas->drawPicture(fPicture);
443 }
scroggo@google.com9a412522012-09-07 15:21:18 +0000444 fCanvas->flush();
bsalomon49f085d2014-09-05 13:34:00 -0700445 if (out) {
edisonn@google.com84f548c2012-12-18 22:24:03 +0000446 *out = SkNEW(SkBitmap);
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700447 setup_bitmap(*out, SkScalarCeilToInt(fPicture->cullRect().width()),
448 SkScalarCeilToInt(fPicture->cullRect().height()));
edisonn@google.com84f548c2012-12-18 22:24:03 +0000449 fCanvas->readPixels(*out, 0, 0);
450 }
commit-bot@chromium.org8991c672014-05-22 00:36:05 +0000451 if (fEnableWrites) {
452 return write(fCanvas, fWritePath, fMismatchPath, fInputFilename, fJsonSummaryPtr,
453 fUseChecksumBasedFilenames);
454 } else {
455 return true;
456 }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000457}
458
scroggo@google.com0a049b82012-11-02 22:01:26 +0000459SkString SimplePictureRenderer::getConfigNameInternal() {
460 return SkString("simple");
461}
462
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000463///////////////////////////////////////////////////////////////////////////////////////////////
464
krajcevskib1aded82014-08-18 07:52:17 -0700465#if SK_SUPPORT_GPU
466TiledPictureRenderer::TiledPictureRenderer(const GrContext::Options& opts)
mtklein2a65a232014-08-26 14:07:04 -0700467 : INHERITED(opts)
krajcevskib1aded82014-08-18 07:52:17 -0700468 , fTileWidth(kDefaultTileWidth)
469#else
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000470TiledPictureRenderer::TiledPictureRenderer()
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000471 : fTileWidth(kDefaultTileWidth)
krajcevskib1aded82014-08-18 07:52:17 -0700472#endif
rileya@google.comb947b912012-08-29 17:35:07 +0000473 , fTileHeight(kDefaultTileHeight)
rileya@google.coma04dc022012-09-10 19:01:38 +0000474 , fTileWidthPercentage(0.0)
rileya@google.comb947b912012-08-29 17:35:07 +0000475 , fTileHeightPercentage(0.0)
scroggo@google.comcbcef702012-12-13 22:09:28 +0000476 , fTileMinPowerOf2Width(0)
477 , fCurrentTileOffset(-1)
478 , fTilesX(0)
479 , fTilesY(0) { }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000480
robertphillipsce4dd3d2014-07-07 13:46:35 -0700481void TiledPictureRenderer::init(const SkPicture* pict, const SkString* writePath,
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000482 const SkString* mismatchPath, const SkString* inputFilename,
robertphillips78c71272014-10-09 04:59:19 -0700483 bool useChecksumBasedFilenames, bool useMultiPictureDraw) {
bsalomon49f085d2014-09-05 13:34:00 -0700484 SkASSERT(pict);
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000485 SkASSERT(0 == fTileRects.count());
486 if (NULL == pict || fTileRects.count() != 0) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000487 return;
488 }
489
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000490 // Do not call INHERITED::init(), which would create a (potentially large) canvas which is not
491 // used by bench_pictures.
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000492 fPicture.reset(pict)->ref();
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000493 this->CopyString(&fWritePath, writePath);
494 this->CopyString(&fMismatchPath, mismatchPath);
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000495 this->CopyString(&fInputFilename, inputFilename);
496 fUseChecksumBasedFilenames = useChecksumBasedFilenames;
robertphillips78c71272014-10-09 04:59:19 -0700497 fUseMultiPictureDraw = useMultiPictureDraw;
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000498 this->buildBBoxHierarchy();
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000499
500 if (fTileWidthPercentage > 0) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700501 fTileWidth = SkScalarCeilToInt(float(fTileWidthPercentage * fPicture->cullRect().width() / 100));
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000502 }
503 if (fTileHeightPercentage > 0) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700504 fTileHeight = SkScalarCeilToInt(float(fTileHeightPercentage * fPicture->cullRect().height() / 100));
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000505 }
506
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000507 if (fTileMinPowerOf2Width > 0) {
508 this->setupPowerOf2Tiles();
509 } else {
510 this->setupTiles();
511 }
scroggo@google.comcbcef702012-12-13 22:09:28 +0000512 fCanvas.reset(this->setupCanvas(fTileWidth, fTileHeight));
513 // Initialize to -1 so that the first call to nextTile will set this up to draw tile 0 on the
514 // first call to drawCurrentTile.
515 fCurrentTileOffset = -1;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000516}
517
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000518void TiledPictureRenderer::end() {
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000519 fTileRects.reset();
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000520 this->INHERITED::end();
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000521}
522
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000523void TiledPictureRenderer::setupTiles() {
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000524 // Only use enough tiles to cover the viewport
525 const int width = this->getViewWidth();
526 const int height = this->getViewHeight();
527
scroggo@google.comcbcef702012-12-13 22:09:28 +0000528 fTilesX = fTilesY = 0;
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000529 for (int tile_y_start = 0; tile_y_start < height; tile_y_start += fTileHeight) {
scroggo@google.comcbcef702012-12-13 22:09:28 +0000530 fTilesY++;
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000531 for (int tile_x_start = 0; tile_x_start < width; tile_x_start += fTileWidth) {
scroggo@google.comcbcef702012-12-13 22:09:28 +0000532 if (0 == tile_y_start) {
533 // Only count tiles in the X direction on the first pass.
534 fTilesX++;
535 }
robertphillips78c71272014-10-09 04:59:19 -0700536 *fTileRects.append() = SkIRect::MakeXYWH(tile_x_start, tile_y_start,
537 fTileWidth, fTileHeight);
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000538 }
539 }
540}
541
scroggo@google.comcbcef702012-12-13 22:09:28 +0000542bool TiledPictureRenderer::tileDimensions(int &x, int &y) {
543 if (fTileRects.count() == 0 || NULL == fPicture) {
544 return false;
545 }
546 x = fTilesX;
547 y = fTilesY;
548 return true;
549}
550
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000551// The goal of the powers of two tiles is to minimize the amount of wasted tile
552// space in the width-wise direction and then minimize the number of tiles. The
553// constraints are that every tile must have a pixel width that is a power of
554// two and also be of some minimal width (that is also a power of two).
555//
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000556// This is solved by first taking our picture size and rounding it up to the
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000557// multiple of the minimal width. The binary representation of this rounded
558// value gives us the tiles we need: a bit of value one means we need a tile of
559// that size.
560void TiledPictureRenderer::setupPowerOf2Tiles() {
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000561 // Only use enough tiles to cover the viewport
562 const int width = this->getViewWidth();
563 const int height = this->getViewHeight();
564
565 int rounded_value = width;
566 if (width % fTileMinPowerOf2Width != 0) {
567 rounded_value = width - (width % fTileMinPowerOf2Width) + fTileMinPowerOf2Width;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000568 }
569
reed@google.come15b2f52013-12-18 04:59:26 +0000570 int num_bits = SkScalarCeilToInt(scalar_log2(SkIntToScalar(width)));
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000571 int largest_possible_tile_size = 1 << num_bits;
572
scroggo@google.comcbcef702012-12-13 22:09:28 +0000573 fTilesX = fTilesY = 0;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000574 // The tile height is constant for a particular picture.
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000575 for (int tile_y_start = 0; tile_y_start < height; tile_y_start += fTileHeight) {
scroggo@google.comcbcef702012-12-13 22:09:28 +0000576 fTilesY++;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000577 int tile_x_start = 0;
578 int current_width = largest_possible_tile_size;
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000579 // Set fTileWidth to be the width of the widest tile, so that each canvas is large enough
580 // to draw each tile.
581 fTileWidth = current_width;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000582
583 while (current_width >= fTileMinPowerOf2Width) {
584 // It is very important this is a bitwise AND.
585 if (current_width & rounded_value) {
scroggo@google.comcbcef702012-12-13 22:09:28 +0000586 if (0 == tile_y_start) {
587 // Only count tiles in the X direction on the first pass.
588 fTilesX++;
589 }
robertphillips78c71272014-10-09 04:59:19 -0700590 *fTileRects.append() = SkIRect::MakeXYWH(tile_x_start, tile_y_start,
591 current_width, fTileHeight);
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000592 tile_x_start += current_width;
593 }
594
595 current_width >>= 1;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000596 }
597 }
598}
599
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000600/**
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +0000601 * Draw the specified picture to the canvas translated to rectangle provided, so that this mini
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000602 * canvas represents the rectangle's portion of the overall picture.
603 * Saves and restores so that the initial clip and matrix return to their state before this function
604 * is called.
605 */
mtklein2a65a232014-08-26 14:07:04 -0700606static void draw_tile_to_canvas(SkCanvas* canvas,
robertphillips78c71272014-10-09 04:59:19 -0700607 const SkIRect& tileRect,
robertphillipsce4dd3d2014-07-07 13:46:35 -0700608 const SkPicture* picture) {
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000609 int saveCount = canvas->save();
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000610 // Translate so that we draw the correct portion of the picture.
611 // Perform a postTranslate so that the scaleFactor does not interfere with the positioning.
612 SkMatrix mat(canvas->getTotalMatrix());
robertphillips78c71272014-10-09 04:59:19 -0700613 mat.postTranslate(-SkIntToScalar(tileRect.fLeft), -SkIntToScalar(tileRect.fTop));
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000614 canvas->setMatrix(mat);
robertphillips4a36d9a2014-10-20 08:45:57 -0700615 canvas->clear(SK_ColorTRANSPARENT); // Not every picture covers the entirety of every tile
robertphillips9b14f262014-06-04 05:40:44 -0700616 canvas->drawPicture(picture);
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000617 canvas->restoreToCount(saveCount);
618 canvas->flush();
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000619}
620
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000621///////////////////////////////////////////////////////////////////////////////////////////////
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000622
commit-bot@chromium.orga3f882c2013-12-13 20:52:36 +0000623/**
624 * Copies the entirety of the src bitmap (typically a tile) into a portion of the dst bitmap.
625 * If the src bitmap is too large to fit within the dst bitmap after the x and y
626 * offsets have been applied, any excess will be ignored (so only the top-left portion of the
627 * src bitmap will be copied).
628 *
629 * @param src source bitmap
630 * @param dst destination bitmap
631 * @param xOffset x-offset within destination bitmap
632 * @param yOffset y-offset within destination bitmap
633 */
634static void bitmapCopyAtOffset(const SkBitmap& src, SkBitmap* dst,
635 int xOffset, int yOffset) {
636 for (int y = 0; y <src.height() && y + yOffset < dst->height() ; y++) {
637 for (int x = 0; x < src.width() && x + xOffset < dst->width() ; x++) {
638 *dst->getAddr32(xOffset + x, yOffset + y) = *src.getAddr32(x, y);
edisonn@google.com84f548c2012-12-18 22:24:03 +0000639 }
640 }
641}
642
scroggo@google.comcbcef702012-12-13 22:09:28 +0000643bool TiledPictureRenderer::nextTile(int &i, int &j) {
644 if (++fCurrentTileOffset < fTileRects.count()) {
645 i = fCurrentTileOffset % fTilesX;
646 j = fCurrentTileOffset / fTilesX;
647 return true;
648 }
649 return false;
650}
651
652void TiledPictureRenderer::drawCurrentTile() {
653 SkASSERT(fCurrentTileOffset >= 0 && fCurrentTileOffset < fTileRects.count());
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +0000654 draw_tile_to_canvas(fCanvas, fTileRects[fCurrentTileOffset], fPicture);
scroggo@google.comcbcef702012-12-13 22:09:28 +0000655}
656
robertphillips78c71272014-10-09 04:59:19 -0700657bool TiledPictureRenderer::postRender(SkCanvas* canvas, const SkIRect& tileRect,
658 SkBitmap* tempBM, SkBitmap** out,
659 int tileNumber) {
660 bool success = true;
661
662 if (fEnableWrites) {
663 success &= write(canvas, fWritePath, fMismatchPath, fInputFilename, fJsonSummaryPtr,
664 fUseChecksumBasedFilenames, &tileNumber);
665 }
666 if (out) {
667 if (canvas->readPixels(tempBM, 0, 0)) {
668 // Add this tile to the entire bitmap.
669 bitmapCopyAtOffset(*tempBM, *out, tileRect.left(), tileRect.top());
670 } else {
671 success = false;
672 }
673 }
674
675 return success;
676}
677
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000678bool TiledPictureRenderer::render(SkBitmap** out) {
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000679 SkASSERT(fPicture != NULL);
680 if (NULL == fPicture) {
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000681 return false;
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000682 }
683
edisonn@google.com84f548c2012-12-18 22:24:03 +0000684 SkBitmap bitmap;
robertphillips78c71272014-10-09 04:59:19 -0700685 if (out) {
edisonn@google.com84f548c2012-12-18 22:24:03 +0000686 *out = SkNEW(SkBitmap);
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700687 setup_bitmap(*out, SkScalarCeilToInt(fPicture->cullRect().width()),
688 SkScalarCeilToInt(fPicture->cullRect().height()));
edisonn@google.com84f548c2012-12-18 22:24:03 +0000689 setup_bitmap(&bitmap, fTileWidth, fTileHeight);
690 }
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000691 bool success = true;
robertphillips78c71272014-10-09 04:59:19 -0700692
693 if (fUseMultiPictureDraw) {
694 SkMultiPictureDraw mpd;
695 SkTDArray<SkSurface*> surfaces;
696 surfaces.setReserve(fTileRects.count());
697
698 // Create a separate SkSurface/SkCanvas for each tile along with a
699 // translated version of the skp (to mimic Chrome's behavior) and
700 // feed all such pairs to the MultiPictureDraw.
701 for (int i = 0; i < fTileRects.count(); ++i) {
702 SkImageInfo ii = fCanvas->imageInfo().makeWH(fTileRects[i].width(),
703 fTileRects[i].height());
704 *surfaces.append() = fCanvas->newSurface(ii);
705 surfaces[i]->getCanvas()->setMatrix(fCanvas->getTotalMatrix());
706
707 SkPictureRecorder recorder;
708 SkCanvas* c = recorder.beginRecording(SkIntToScalar(fTileRects[i].width()),
709 SkIntToScalar(fTileRects[i].height()));
710 c->save();
711 SkMatrix mat;
712 mat.setTranslate(-SkIntToScalar(fTileRects[i].fLeft),
713 -SkIntToScalar(fTileRects[i].fTop));
714 c->setMatrix(mat);
715 c->drawPicture(fPicture);
716 c->restore();
717
718 SkAutoTUnref<SkPicture> xlatedPicture(recorder.endRecording());
719
720 mpd.add(surfaces[i]->getCanvas(), xlatedPicture);
commit-bot@chromium.org8991c672014-05-22 00:36:05 +0000721 }
robertphillips78c71272014-10-09 04:59:19 -0700722
723 // Render all the buffered SkCanvases/SkPictures
724 mpd.draw();
725
726 // Sort out the results and cleanup the allocated surfaces
727 for (int i = 0; i < fTileRects.count(); ++i) {
728 success &= this->postRender(surfaces[i]->getCanvas(), fTileRects[i], &bitmap, out, i);
729 surfaces[i]->unref();
730 }
731 } else {
732 for (int i = 0; i < fTileRects.count(); ++i) {
733 draw_tile_to_canvas(fCanvas, fTileRects[i], fPicture);
734 success &= this->postRender(fCanvas, fTileRects[i], &bitmap, out, i);
edisonn@google.com84f548c2012-12-18 22:24:03 +0000735 }
keyar@chromium.org163b5672012-08-01 17:53:29 +0000736 }
robertphillips78c71272014-10-09 04:59:19 -0700737
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000738 return success;
keyar@chromium.org163b5672012-08-01 17:53:29 +0000739}
740
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000741SkCanvas* TiledPictureRenderer::setupCanvas(int width, int height) {
742 SkCanvas* canvas = this->INHERITED::setupCanvas(width, height);
bsalomon49f085d2014-09-05 13:34:00 -0700743 SkASSERT(fPicture);
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000744 // Clip the tile to an area that is completely inside both the SkPicture and the viewport. This
745 // is mostly important for tiles on the right and bottom edges as they may go over this area and
746 // the picture may have some commands that draw outside of this area and so should not actually
747 // be written.
748 // Uses a clipRegion so that it will be unaffected by the scale factor, which may have been set
749 // by INHERITED::setupCanvas.
750 SkRegion clipRegion;
751 clipRegion.setRect(0, 0, this->getViewWidth(), this->getViewHeight());
752 canvas->clipRegion(clipRegion);
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000753 return canvas;
754}
scroggo@google.com0a049b82012-11-02 22:01:26 +0000755
756SkString TiledPictureRenderer::getConfigNameInternal() {
757 SkString name;
758 if (fTileMinPowerOf2Width > 0) {
759 name.append("pow2tile_");
760 name.appendf("%i", fTileMinPowerOf2Width);
761 } else {
762 name.append("tile_");
763 if (fTileWidthPercentage > 0) {
764 name.appendf("%.f%%", fTileWidthPercentage);
765 } else {
766 name.appendf("%i", fTileWidth);
767 }
768 }
769 name.append("x");
770 if (fTileHeightPercentage > 0) {
771 name.appendf("%.f%%", fTileHeightPercentage);
772 } else {
773 name.appendf("%i", fTileHeight);
774 }
775 return name;
776}
777
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000778///////////////////////////////////////////////////////////////////////////////////////////////
779
scroggo@google.com9a412522012-09-07 15:21:18 +0000780void PlaybackCreationRenderer::setup() {
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000781 SkAutoTDelete<SkBBHFactory> factory(this->getFactory());
782 fRecorder.reset(SkNEW(SkPictureRecorder));
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700783 SkCanvas* canvas = fRecorder->beginRecording(SkIntToScalar(this->getViewWidth()),
784 SkIntToScalar(this->getViewHeight()),
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000785 factory.get(),
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000786 this->recordFlags());
787 this->scaleToScaleFactor(canvas);
robertphillips9b14f262014-06-04 05:40:44 -0700788 canvas->drawPicture(fPicture);
scroggo@google.com9a412522012-09-07 15:21:18 +0000789}
790
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000791bool PlaybackCreationRenderer::render(SkBitmap** out) {
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000792 fPicture.reset(fRecorder->endRecording());
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000793 // Since this class does not actually render, return false.
794 return false;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000795}
796
scroggo@google.com0a049b82012-11-02 22:01:26 +0000797SkString PlaybackCreationRenderer::getConfigNameInternal() {
798 return SkString("playback_creation");
799}
800
junov@chromium.org9313ca42012-11-02 18:11:49 +0000801///////////////////////////////////////////////////////////////////////////////////////////////
802// SkPicture variants for each BBoxHierarchy type
803
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000804SkBBHFactory* PictureRenderer::getFactory() {
junov@chromium.org9313ca42012-11-02 18:11:49 +0000805 switch (fBBoxHierarchyType) {
806 case kNone_BBoxHierarchyType:
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000807 return NULL;
junov@chromium.org9313ca42012-11-02 18:11:49 +0000808 case kRTree_BBoxHierarchyType:
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000809 return SkNEW(SkRTreeFactory);
junov@chromium.org7b537062012-11-06 18:58:43 +0000810 case kTileGrid_BBoxHierarchyType:
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000811 return SkNEW_ARGS(SkTileGridFactory, (fGridInfo));
junov@chromium.org9313ca42012-11-02 18:11:49 +0000812 }
813 SkASSERT(0); // invalid bbhType
814 return NULL;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000815}
junov@chromium.org9313ca42012-11-02 18:11:49 +0000816
reed@google.comfe7b1ed2012-11-29 21:00:39 +0000817///////////////////////////////////////////////////////////////////////////////
818
819class GatherRenderer : public PictureRenderer {
820public:
krajcevskib1aded82014-08-18 07:52:17 -0700821#if SK_SUPPORT_GPU
822 GatherRenderer(const GrContext::Options& opts) : INHERITED(opts) { }
823#endif
824
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000825 virtual bool render(SkBitmap** out = NULL) SK_OVERRIDE {
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700826 SkRect bounds = SkRect::MakeWH(SkIntToScalar(fPicture->cullRect().width()),
827 SkIntToScalar(fPicture->cullRect().height()));
reed@google.comfe7b1ed2012-11-29 21:00:39 +0000828 SkData* data = SkPictureUtils::GatherPixelRefs(fPicture, bounds);
829 SkSafeUnref(data);
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +0000830
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000831 return (fWritePath.isEmpty()); // we don't have anything to write
reed@google.comfe7b1ed2012-11-29 21:00:39 +0000832 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +0000833
reed@google.comfe7b1ed2012-11-29 21:00:39 +0000834private:
835 virtual SkString getConfigNameInternal() SK_OVERRIDE {
836 return SkString("gather_pixelrefs");
837 }
krajcevskib1aded82014-08-18 07:52:17 -0700838
839 typedef PictureRenderer INHERITED;
reed@google.comfe7b1ed2012-11-29 21:00:39 +0000840};
841
krajcevskib1aded82014-08-18 07:52:17 -0700842#if SK_SUPPORT_GPU
843PictureRenderer* CreateGatherPixelRefsRenderer(const GrContext::Options& opts) {
844 return SkNEW_ARGS(GatherRenderer, (opts));
845}
846#else
reed@google.comfe7b1ed2012-11-29 21:00:39 +0000847PictureRenderer* CreateGatherPixelRefsRenderer() {
848 return SkNEW(GatherRenderer);
849}
krajcevskib1aded82014-08-18 07:52:17 -0700850#endif
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +0000851
junov@chromium.org9313ca42012-11-02 18:11:49 +0000852} // namespace sk_tools