blob: aec153d953fe7c74b71e5a6e60cbb9098b26e6c3 [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"
scroggo895c43b2014-12-11 10:53:58 -080031#include "SkPixelSerializer.h"
keyar@chromium.orgea826952012-08-23 15:24:13 +000032#include "SkScalar.h"
scroggo@google.coma9e3a362012-11-07 17:52:48 +000033#include "SkStream.h"
keyar@chromium.org9299ede2012-08-21 19:05:08 +000034#include "SkString.h"
robertphillips78c71272014-10-09 04:59:19 -070035#include "SkSurface.h"
scroggo@google.com58b4ead2012-08-31 16:15:22 +000036#include "SkTemplates.h"
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000037#include "SkTDArray.h"
scroggo@google.com58b4ead2012-08-31 16:15:22 +000038#include "SkThreadUtils.h"
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000039#include "SkTypes.h"
robertphillips3e5c2b12015-03-23 05:46:51 -070040#include "sk_tool_utils.h"
keyar@chromium.org4ea96c52012-08-20 15:03:29 +000041
reed@google.come15b2f52013-12-18 04:59:26 +000042static inline SkScalar scalar_log2(SkScalar x) {
43 static const SkScalar log2_conversion_factor = SkScalarDiv(1, SkScalarLog(2));
skia.committer@gmail.com3b85deb2013-12-18 07:01:56 +000044
reed@google.come15b2f52013-12-18 04:59:26 +000045 return SkScalarLog(x) * log2_conversion_factor;
46}
47
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000048namespace sk_tools {
49
50enum {
51 kDefaultTileWidth = 256,
52 kDefaultTileHeight = 256
53};
54
mtklein2a65a232014-08-26 14:07:04 -070055void PictureRenderer::init(const SkPicture* pict,
56 const SkString* writePath,
robertphillipsce4dd3d2014-07-07 13:46:35 -070057 const SkString* mismatchPath,
mtklein2a65a232014-08-26 14:07:04 -070058 const SkString* inputFilename,
robertphillips78c71272014-10-09 04:59:19 -070059 bool useChecksumBasedFilenames,
60 bool useMultiPictureDraw) {
commit-bot@chromium.org3f045172014-05-15 15:10:48 +000061 this->CopyString(&fWritePath, writePath);
62 this->CopyString(&fMismatchPath, mismatchPath);
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +000063 this->CopyString(&fInputFilename, inputFilename);
64 fUseChecksumBasedFilenames = useChecksumBasedFilenames;
robertphillips78c71272014-10-09 04:59:19 -070065 fUseMultiPictureDraw = useMultiPictureDraw;
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +000066
keyar@chromium.org78a35c52012-08-20 15:03:44 +000067 SkASSERT(NULL == fPicture);
68 SkASSERT(NULL == fCanvas.get());
bsalomon49f085d2014-09-05 13:34:00 -070069 if (fPicture || fCanvas.get()) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +000070 return;
71 }
72
73 SkASSERT(pict != NULL);
keyar@chromium.org78a35c52012-08-20 15:03:44 +000074 if (NULL == pict) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +000075 return;
76 }
77
robertphillips@google.com84b18c72014-04-13 19:09:42 +000078 fPicture.reset(pict)->ref();
keyar@chromium.orga474ce32012-08-20 15:03:57 +000079 fCanvas.reset(this->setupCanvas());
80}
81
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +000082void PictureRenderer::CopyString(SkString* dest, const SkString* src) {
bsalomon49f085d2014-09-05 13:34:00 -070083 if (src) {
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +000084 dest->set(*src);
85 } else {
86 dest->reset();
87 }
88}
89
caryclark@google.coma3622372012-11-06 21:26:13 +000090class FlagsDrawFilter : public SkDrawFilter {
91public:
92 FlagsDrawFilter(PictureRenderer::DrawFilterFlags* flags) :
93 fFlags(flags) {}
94
reed@google.com971aca72012-11-26 20:26:54 +000095 virtual bool filter(SkPaint* paint, Type t) {
caryclark@google.coma3622372012-11-06 21:26:13 +000096 paint->setFlags(paint->getFlags() & ~fFlags[t] & SkPaint::kAllFlags);
robertphillips@google.com49149312013-07-03 15:34:35 +000097 if (PictureRenderer::kMaskFilter_DrawFilterFlag & fFlags[t]) {
caryclark@google.coma3622372012-11-06 21:26:13 +000098 SkMaskFilter* maskFilter = paint->getMaskFilter();
bsalomon49f085d2014-09-05 13:34:00 -070099 if (maskFilter) {
reed@google.com457d8a72012-12-18 18:20:44 +0000100 paint->setMaskFilter(NULL);
caryclark@google.coma3622372012-11-06 21:26:13 +0000101 }
102 }
103 if (PictureRenderer::kHinting_DrawFilterFlag & fFlags[t]) {
104 paint->setHinting(SkPaint::kNo_Hinting);
105 } else if (PictureRenderer::kSlightHinting_DrawFilterFlag & fFlags[t]) {
106 paint->setHinting(SkPaint::kSlight_Hinting);
107 }
reed@google.com971aca72012-11-26 20:26:54 +0000108 return true;
caryclark@google.coma3622372012-11-06 21:26:13 +0000109 }
110
111private:
112 PictureRenderer::DrawFilterFlags* fFlags;
113};
114
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000115static void setUpFilter(SkCanvas* canvas, PictureRenderer::DrawFilterFlags* drawFilters) {
caryclark@google.coma3622372012-11-06 21:26:13 +0000116 if (drawFilters && !canvas->getDrawFilter()) {
117 canvas->setDrawFilter(SkNEW_ARGS(FlagsDrawFilter, (drawFilters)))->unref();
caryclark@google.come3e940c2012-11-07 16:42:17 +0000118 if (drawFilters[0] & PictureRenderer::kAAClip_DrawFilterFlag) {
119 canvas->setAllowSoftClip(false);
120 }
caryclark@google.coma3622372012-11-06 21:26:13 +0000121 }
caryclark@google.coma3622372012-11-06 21:26:13 +0000122}
123
keyar@chromium.orga474ce32012-08-20 15:03:57 +0000124SkCanvas* PictureRenderer::setupCanvas() {
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000125 const int width = this->getViewWidth();
126 const int height = this->getViewHeight();
127 return this->setupCanvas(width, height);
keyar@chromium.orga474ce32012-08-20 15:03:57 +0000128}
129
130SkCanvas* PictureRenderer::setupCanvas(int width, int height) {
caryclark@google.coma3622372012-11-06 21:26:13 +0000131 SkCanvas* canvas;
keyar@chromium.org4ea96c52012-08-20 15:03:29 +0000132 switch(fDeviceType) {
133 case kBitmap_DeviceType: {
134 SkBitmap bitmap;
keyar@chromium.orga474ce32012-08-20 15:03:57 +0000135 sk_tools::setup_bitmap(&bitmap, width, height);
caryclark@google.coma3622372012-11-06 21:26:13 +0000136 canvas = SkNEW_ARGS(SkCanvas, (bitmap));
keyar@chromium.org4ea96c52012-08-20 15:03:29 +0000137 }
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000138 break;
keyar@chromium.org4ea96c52012-08-20 15:03:29 +0000139#if SK_SUPPORT_GPU
scroggo@google.com0556ea02013-02-08 19:38:21 +0000140#if SK_ANGLE
141 case kAngle_DeviceType:
142 // fall through
143#endif
rmistry@google.com6ab96732014-01-06 18:37:24 +0000144#if SK_MESA
145 case kMesa_DeviceType:
146 // fall through
147#endif
commit-bot@chromium.org0fd52702014-03-07 18:41:14 +0000148 case kGPU_DeviceType:
149 case kNVPR_DeviceType: {
commit-bot@chromium.orgae403b92013-04-10 17:27:30 +0000150 SkAutoTUnref<GrSurface> target;
scroggo@google.com0556ea02013-02-08 19:38:21 +0000151 if (fGrContext) {
152 // create a render target to back the device
bsalomonf2703d82014-10-28 14:33:06 -0700153 GrSurfaceDesc desc;
scroggo@google.com0556ea02013-02-08 19:38:21 +0000154 desc.fConfig = kSkia8888_GrPixelConfig;
bsalomonf2703d82014-10-28 14:33:06 -0700155 desc.fFlags = kRenderTarget_GrSurfaceFlag;
scroggo@google.com0556ea02013-02-08 19:38:21 +0000156 desc.fWidth = width;
157 desc.fHeight = height;
jvanverth@google.comf6a90332013-05-02 12:39:37 +0000158 desc.fSampleCnt = fSampleCount;
bsalomond0423582015-02-06 08:49:24 -0800159 target.reset(fGrContext->createTexture(desc, false, NULL, 0));
scroggo@google.com0556ea02013-02-08 19:38:21 +0000160 }
bsalomonafe30052015-01-16 07:32:33 -0800161
162 uint32_t flags = fUseDFText ? SkSurfaceProps::kUseDistanceFieldFonts_Flag : 0;
163 SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
164 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(target->asRenderTarget(), &props));
165 if (!device) {
scroggo@google.com0556ea02013-02-08 19:38:21 +0000166 return NULL;
167 }
bsalomonafe30052015-01-16 07:32:33 -0800168 canvas = SkNEW_ARGS(SkCanvas, (device));
scroggo@google.com0556ea02013-02-08 19:38:21 +0000169 break;
keyar@chromium.org4ea96c52012-08-20 15:03:29 +0000170 }
171#endif
172 default:
173 SkASSERT(0);
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000174 return NULL;
keyar@chromium.org4ea96c52012-08-20 15:03:29 +0000175 }
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000176 setUpFilter(canvas, fDrawFilters);
177 this->scaleToScaleFactor(canvas);
commit-bot@chromium.org17cc3ea2014-01-15 14:51:25 +0000178
179 // Pictures often lie about their extent (i.e., claim to be 100x100 but
180 // only ever draw to 90x100). Clear here so the undrawn portion will have
181 // a consistent color
182 canvas->clear(SK_ColorTRANSPARENT);
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000183 return canvas;
184}
keyar@chromium.orga474ce32012-08-20 15:03:57 +0000185
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000186void PictureRenderer::scaleToScaleFactor(SkCanvas* canvas) {
187 SkASSERT(canvas != NULL);
188 if (fScaleFactor != SK_Scalar1) {
189 canvas->scale(fScaleFactor, fScaleFactor);
190 }
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000191}
192
193void PictureRenderer::end() {
scroggo@google.com08085f82013-01-28 20:40:24 +0000194 this->resetState(true);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000195 fPicture.reset(NULL);
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000196 fCanvas.reset(NULL);
197}
198
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000199int PictureRenderer::getViewWidth() {
200 SkASSERT(fPicture != NULL);
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700201 int width = SkScalarCeilToInt(fPicture->cullRect().width() * fScaleFactor);
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000202 if (fViewport.width() > 0) {
203 width = SkMin32(width, fViewport.width());
204 }
205 return width;
206}
207
208int PictureRenderer::getViewHeight() {
209 SkASSERT(fPicture != NULL);
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700210 int height = SkScalarCeilToInt(fPicture->cullRect().height() * fScaleFactor);
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000211 if (fViewport.height() > 0) {
212 height = SkMin32(height, fViewport.height());
213 }
214 return height;
215}
216
junov@chromium.org9313ca42012-11-02 18:11:49 +0000217/** Converts fPicture to a picture that uses a BBoxHierarchy.
218 * PictureRenderer subclasses that are used to test picture playback
219 * should call this method during init.
220 */
221void PictureRenderer::buildBBoxHierarchy() {
bsalomon49f085d2014-09-05 13:34:00 -0700222 SkASSERT(fPicture);
223 if (kNone_BBoxHierarchyType != fBBoxHierarchyType && fPicture) {
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000224 SkAutoTDelete<SkBBHFactory> factory(this->getFactory());
225 SkPictureRecorder recorder;
robertphillips81f71b62014-11-11 04:54:49 -0800226 uint32_t flags = this->recordFlags();
227 if (fUseMultiPictureDraw) {
228 flags |= SkPictureRecorder::kComputeSaveLayerInfo_RecordFlag;
229 }
mtklein703dd2e2015-01-09 06:41:48 -0800230 SkCanvas* canvas = recorder.beginRecording(fPicture->cullRect().width(),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700231 fPicture->cullRect().height(),
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000232 factory.get(),
robertphillips81f71b62014-11-11 04:54:49 -0800233 flags);
robertphillipsc5ba71d2014-09-04 08:42:50 -0700234 fPicture->playback(canvas);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000235 fPicture.reset(recorder.endRecording());
junov@chromium.org9313ca42012-11-02 18:11:49 +0000236 }
237}
238
scroggo@google.com08085f82013-01-28 20:40:24 +0000239void PictureRenderer::resetState(bool callFinish) {
keyar@chromium.org28136b32012-08-20 15:04:15 +0000240#if SK_SUPPORT_GPU
kkinnunen9e61bb72014-10-09 05:24:15 -0700241 SkGLContext* glContext = this->getGLContext();
scroggo@google.com0556ea02013-02-08 19:38:21 +0000242 if (NULL == glContext) {
243 SkASSERT(kBitmap_DeviceType == fDeviceType);
244 return;
245 }
keyar@chromium.org28136b32012-08-20 15:04:15 +0000246
scroggo@google.com0556ea02013-02-08 19:38:21 +0000247 fGrContext->flush();
commit-bot@chromium.org51c040e2014-03-11 22:58:00 +0000248 glContext->swapBuffers();
scroggo@google.com0556ea02013-02-08 19:38:21 +0000249 if (callFinish) {
250 SK_GL(*glContext, Finish());
keyar@chromium.org77a55222012-08-20 15:03:47 +0000251 }
keyar@chromium.orga40c20d2012-08-20 15:04:12 +0000252#endif
keyar@chromium.org77a55222012-08-20 15:03:47 +0000253}
254
robertphillips@google.com94d8f1e2013-12-18 17:25:33 +0000255void PictureRenderer::purgeTextures() {
256 SkDiscardableMemoryPool* pool = SkGetGlobalDiscardableMemoryPool();
257
258 pool->dumpPool();
259
260#if SK_SUPPORT_GPU
kkinnunen9e61bb72014-10-09 05:24:15 -0700261 SkGLContext* glContext = this->getGLContext();
robertphillips@google.com94d8f1e2013-12-18 17:25:33 +0000262 if (NULL == glContext) {
263 SkASSERT(kBitmap_DeviceType == fDeviceType);
264 return;
265 }
266
267 // resetState should've already done this
268 fGrContext->flush();
269
270 fGrContext->purgeAllUnlockedResources();
271#endif
272}
273
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000274/**
commit-bot@chromium.org4610a462014-04-29 19:39:22 +0000275 * Write the canvas to an image file and/or JSON summary.
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000276 *
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000277 * @param canvas Must be non-null. Canvas to be written to a file.
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000278 * @param writePath If nonempty, write the binary image to a file within this directory.
279 * @param mismatchPath If nonempty, write the binary image to a file within this directory,
280 * but only if the image does not match expectations.
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000281 * @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 +0000282 * @param jsonSummaryPtr If not null, add image results (checksum) to this summary.
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000283 * @param useChecksumBasedFilenames If true, use checksum-based filenames when writing to disk.
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000284 * @param tileNumberPtr If not null, which tile number this image contains.
commit-bot@chromium.orga3f882c2013-12-13 20:52:36 +0000285 *
commit-bot@chromium.org4610a462014-04-29 19:39:22 +0000286 * @return bool True if the operation completed successfully.
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000287 */
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000288static bool write(SkCanvas* canvas, const SkString& writePath, const SkString& mismatchPath,
289 const SkString& inputFilename, ImageResultsAndExpectations *jsonSummaryPtr,
290 bool useChecksumBasedFilenames, const int* tileNumberPtr=NULL) {
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000291 SkASSERT(canvas != NULL);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000292 if (NULL == canvas) {
keyar@chromium.org9299ede2012-08-21 19:05:08 +0000293 return false;
294 }
295
296 SkBitmap bitmap;
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000297 SkISize size = canvas->getDeviceSize();
commit-bot@chromium.org205ce482014-05-12 15:37:20 +0000298 setup_bitmap(&bitmap, size.width(), size.height());
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000299
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000300 canvas->readPixels(&bitmap, 0, 0);
commit-bot@chromium.org205ce482014-05-12 15:37:20 +0000301 force_all_opaque(bitmap);
302 BitmapAndDigest bitmapAndDigest(bitmap);
keyar@chromium.org9299ede2012-08-21 19:05:08 +0000303
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000304 SkString escapedInputFilename(inputFilename);
305 replace_char(&escapedInputFilename, '.', '_');
306
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000307 // TODO(epoger): what about including the config type within outputFilename? That way,
308 // we could combine results of different config types without conflicting filenames.
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000309 SkString outputFilename;
310 const char *outputSubdirPtr = NULL;
311 if (useChecksumBasedFilenames) {
epoger85b438d2014-08-21 23:21:32 -0700312 ImageDigest *imageDigestPtr = bitmapAndDigest.getImageDigestPtr();
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000313 outputSubdirPtr = escapedInputFilename.c_str();
commit-bot@chromium.org205ce482014-05-12 15:37:20 +0000314 outputFilename.set(imageDigestPtr->getHashType());
315 outputFilename.append("_");
316 outputFilename.appendU64(imageDigestPtr->getHashValue());
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000317 } else {
318 outputFilename.set(escapedInputFilename);
bsalomon49f085d2014-09-05 13:34:00 -0700319 if (tileNumberPtr) {
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000320 outputFilename.append("-tile");
321 outputFilename.appendS32(*tileNumberPtr);
322 }
commit-bot@chromium.orga3f882c2013-12-13 20:52:36 +0000323 }
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000324 outputFilename.append(".png");
commit-bot@chromium.orga3f882c2013-12-13 20:52:36 +0000325
bsalomon49f085d2014-09-05 13:34:00 -0700326 if (jsonSummaryPtr) {
epoger85b438d2014-08-21 23:21:32 -0700327 ImageDigest *imageDigestPtr = bitmapAndDigest.getImageDigestPtr();
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000328 SkString outputRelativePath;
329 if (outputSubdirPtr) {
330 outputRelativePath.set(outputSubdirPtr);
331 outputRelativePath.append("/"); // always use "/", even on Windows
332 outputRelativePath.append(outputFilename);
333 } else {
334 outputRelativePath.set(outputFilename);
335 }
336
337 jsonSummaryPtr->add(inputFilename.c_str(), outputRelativePath.c_str(),
commit-bot@chromium.org205ce482014-05-12 15:37:20 +0000338 *imageDigestPtr, tileNumberPtr);
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000339 if (!mismatchPath.isEmpty() &&
epoger85b438d2014-08-21 23:21:32 -0700340 !jsonSummaryPtr->getExpectation(inputFilename.c_str(),
341 tileNumberPtr).matches(*imageDigestPtr)) {
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000342 if (!write_bitmap_to_disk(bitmap, mismatchPath, outputSubdirPtr, outputFilename)) {
343 return false;
344 }
345 }
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000346 }
347
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000348 if (writePath.isEmpty()) {
commit-bot@chromium.org4610a462014-04-29 19:39:22 +0000349 return true;
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000350 } else {
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000351 return write_bitmap_to_disk(bitmap, writePath, outputSubdirPtr, outputFilename);
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000352 }
keyar@chromium.org9299ede2012-08-21 19:05:08 +0000353}
354
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000355///////////////////////////////////////////////////////////////////////////////////////////////
356
djsollen@google.comfd9720c2012-11-06 16:54:40 +0000357SkCanvas* RecordPictureRenderer::setupCanvas(int width, int height) {
358 // defer the canvas setup until the render step
359 return NULL;
360}
361
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000362bool RecordPictureRenderer::render(SkBitmap** out) {
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000363 SkAutoTDelete<SkBBHFactory> factory(this->getFactory());
364 SkPictureRecorder recorder;
mtklein703dd2e2015-01-09 06:41:48 -0800365 SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(this->getViewWidth()),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700366 SkIntToScalar(this->getViewHeight()),
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000367 factory.get(),
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000368 this->recordFlags());
369 this->scaleToScaleFactor(canvas);
robertphillipsc5ba71d2014-09-04 08:42:50 -0700370 fPicture->playback(canvas);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000371 SkAutoTUnref<SkPicture> picture(recorder.endRecording());
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000372 if (!fWritePath.isEmpty()) {
scroggo@google.coma9e3a362012-11-07 17:52:48 +0000373 // Record the new picture as a new SKP with PNG encoded bitmaps.
tfarinaa8e2e152014-07-28 19:26:58 -0700374 SkString skpPath = SkOSPath::Join(fWritePath.c_str(), fInputFilename.c_str());
scroggo@google.coma9e3a362012-11-07 17:52:48 +0000375 SkFILEWStream stream(skpPath.c_str());
robertphillips3e5c2b12015-03-23 05:46:51 -0700376 sk_tool_utils::PngPixelSerializer serializer;
scroggo895c43b2014-12-11 10:53:58 -0800377 picture->serialize(&stream, &serializer);
scroggo@google.coma9e3a362012-11-07 17:52:48 +0000378 return true;
379 }
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000380 return false;
scroggo@google.com9a412522012-09-07 15:21:18 +0000381}
382
scroggo@google.com0a049b82012-11-02 22:01:26 +0000383SkString RecordPictureRenderer::getConfigNameInternal() {
384 return SkString("record");
385}
386
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000387///////////////////////////////////////////////////////////////////////////////////////////////
388
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000389bool PipePictureRenderer::render(SkBitmap** out) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000390 SkASSERT(fCanvas.get() != NULL);
391 SkASSERT(fPicture != NULL);
keyar@chromium.org78a35c52012-08-20 15:03:44 +0000392 if (NULL == fCanvas.get() || NULL == fPicture) {
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000393 return false;
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000394 }
395
396 PipeController pipeController(fCanvas.get());
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000397 SkGPipeWriter writer;
398 SkCanvas* pipeCanvas = writer.startRecording(&pipeController);
robertphillips9b14f262014-06-04 05:40:44 -0700399 pipeCanvas->drawPicture(fPicture);
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000400 writer.endRecording();
scroggo@google.com9a412522012-09-07 15:21:18 +0000401 fCanvas->flush();
bsalomon49f085d2014-09-05 13:34:00 -0700402 if (out) {
edisonn@google.com84f548c2012-12-18 22:24:03 +0000403 *out = SkNEW(SkBitmap);
mtklein703dd2e2015-01-09 06:41:48 -0800404 setup_bitmap(*out, SkScalarCeilToInt(fPicture->cullRect().width()),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700405 SkScalarCeilToInt(fPicture->cullRect().height()));
edisonn@google.com84f548c2012-12-18 22:24:03 +0000406 fCanvas->readPixels(*out, 0, 0);
skia.committer@gmail.coma7d8e3e2012-12-19 02:01:38 +0000407 }
commit-bot@chromium.org8991c672014-05-22 00:36:05 +0000408 if (fEnableWrites) {
409 return write(fCanvas, fWritePath, fMismatchPath, fInputFilename, fJsonSummaryPtr,
410 fUseChecksumBasedFilenames);
411 } else {
412 return true;
413 }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000414}
415
scroggo@google.com0a049b82012-11-02 22:01:26 +0000416SkString PipePictureRenderer::getConfigNameInternal() {
417 return SkString("pipe");
418}
419
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000420///////////////////////////////////////////////////////////////////////////////////////////////
421
robertphillipsce4dd3d2014-07-07 13:46:35 -0700422void SimplePictureRenderer::init(const SkPicture* picture, const SkString* writePath,
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000423 const SkString* mismatchPath, const SkString* inputFilename,
robertphillips78c71272014-10-09 04:59:19 -0700424 bool useChecksumBasedFilenames, bool useMultiPictureDraw) {
mtklein703dd2e2015-01-09 06:41:48 -0800425 INHERITED::init(picture, writePath, mismatchPath, inputFilename,
robertphillips78c71272014-10-09 04:59:19 -0700426 useChecksumBasedFilenames, useMultiPictureDraw);
junov@chromium.org9313ca42012-11-02 18:11:49 +0000427 this->buildBBoxHierarchy();
428}
429
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000430bool SimplePictureRenderer::render(SkBitmap** out) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000431 SkASSERT(fCanvas.get() != NULL);
bsalomon49f085d2014-09-05 13:34:00 -0700432 SkASSERT(fPicture);
keyar@chromium.org78a35c52012-08-20 15:03:44 +0000433 if (NULL == fCanvas.get() || NULL == fPicture) {
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000434 return false;
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000435 }
436
robertphillips78c71272014-10-09 04:59:19 -0700437 if (fUseMultiPictureDraw) {
438 SkMultiPictureDraw mpd;
439
440 mpd.add(fCanvas, fPicture);
441
442 mpd.draw();
443 } else {
444 fCanvas->drawPicture(fPicture);
445 }
scroggo@google.com9a412522012-09-07 15:21:18 +0000446 fCanvas->flush();
bsalomon49f085d2014-09-05 13:34:00 -0700447 if (out) {
edisonn@google.com84f548c2012-12-18 22:24:03 +0000448 *out = SkNEW(SkBitmap);
mtklein703dd2e2015-01-09 06:41:48 -0800449 setup_bitmap(*out, SkScalarCeilToInt(fPicture->cullRect().width()),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700450 SkScalarCeilToInt(fPicture->cullRect().height()));
edisonn@google.com84f548c2012-12-18 22:24:03 +0000451 fCanvas->readPixels(*out, 0, 0);
452 }
commit-bot@chromium.org8991c672014-05-22 00:36:05 +0000453 if (fEnableWrites) {
454 return write(fCanvas, fWritePath, fMismatchPath, fInputFilename, fJsonSummaryPtr,
455 fUseChecksumBasedFilenames);
456 } else {
457 return true;
458 }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000459}
460
scroggo@google.com0a049b82012-11-02 22:01:26 +0000461SkString SimplePictureRenderer::getConfigNameInternal() {
462 return SkString("simple");
463}
464
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000465///////////////////////////////////////////////////////////////////////////////////////////////
466
krajcevskib1aded82014-08-18 07:52:17 -0700467#if SK_SUPPORT_GPU
468TiledPictureRenderer::TiledPictureRenderer(const GrContext::Options& opts)
mtklein2a65a232014-08-26 14:07:04 -0700469 : INHERITED(opts)
krajcevskib1aded82014-08-18 07:52:17 -0700470 , fTileWidth(kDefaultTileWidth)
471#else
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000472TiledPictureRenderer::TiledPictureRenderer()
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000473 : fTileWidth(kDefaultTileWidth)
krajcevskib1aded82014-08-18 07:52:17 -0700474#endif
rileya@google.comb947b912012-08-29 17:35:07 +0000475 , fTileHeight(kDefaultTileHeight)
rileya@google.coma04dc022012-09-10 19:01:38 +0000476 , fTileWidthPercentage(0.0)
rileya@google.comb947b912012-08-29 17:35:07 +0000477 , fTileHeightPercentage(0.0)
scroggo@google.comcbcef702012-12-13 22:09:28 +0000478 , fTileMinPowerOf2Width(0)
479 , fCurrentTileOffset(-1)
480 , fTilesX(0)
481 , fTilesY(0) { }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000482
robertphillipsce4dd3d2014-07-07 13:46:35 -0700483void TiledPictureRenderer::init(const SkPicture* pict, const SkString* writePath,
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000484 const SkString* mismatchPath, const SkString* inputFilename,
robertphillips78c71272014-10-09 04:59:19 -0700485 bool useChecksumBasedFilenames, bool useMultiPictureDraw) {
bsalomon49f085d2014-09-05 13:34:00 -0700486 SkASSERT(pict);
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000487 SkASSERT(0 == fTileRects.count());
488 if (NULL == pict || fTileRects.count() != 0) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000489 return;
490 }
491
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000492 // Do not call INHERITED::init(), which would create a (potentially large) canvas which is not
493 // used by bench_pictures.
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000494 fPicture.reset(pict)->ref();
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000495 this->CopyString(&fWritePath, writePath);
496 this->CopyString(&fMismatchPath, mismatchPath);
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000497 this->CopyString(&fInputFilename, inputFilename);
498 fUseChecksumBasedFilenames = useChecksumBasedFilenames;
robertphillips78c71272014-10-09 04:59:19 -0700499 fUseMultiPictureDraw = useMultiPictureDraw;
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000500 this->buildBBoxHierarchy();
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000501
502 if (fTileWidthPercentage > 0) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700503 fTileWidth = SkScalarCeilToInt(float(fTileWidthPercentage * fPicture->cullRect().width() / 100));
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000504 }
505 if (fTileHeightPercentage > 0) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700506 fTileHeight = SkScalarCeilToInt(float(fTileHeightPercentage * fPicture->cullRect().height() / 100));
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000507 }
508
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000509 if (fTileMinPowerOf2Width > 0) {
510 this->setupPowerOf2Tiles();
511 } else {
512 this->setupTiles();
513 }
scroggo@google.comcbcef702012-12-13 22:09:28 +0000514 fCanvas.reset(this->setupCanvas(fTileWidth, fTileHeight));
515 // Initialize to -1 so that the first call to nextTile will set this up to draw tile 0 on the
516 // first call to drawCurrentTile.
517 fCurrentTileOffset = -1;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000518}
519
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000520void TiledPictureRenderer::end() {
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000521 fTileRects.reset();
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000522 this->INHERITED::end();
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000523}
524
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000525void TiledPictureRenderer::setupTiles() {
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000526 // Only use enough tiles to cover the viewport
527 const int width = this->getViewWidth();
528 const int height = this->getViewHeight();
529
scroggo@google.comcbcef702012-12-13 22:09:28 +0000530 fTilesX = fTilesY = 0;
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000531 for (int tile_y_start = 0; tile_y_start < height; tile_y_start += fTileHeight) {
scroggo@google.comcbcef702012-12-13 22:09:28 +0000532 fTilesY++;
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000533 for (int tile_x_start = 0; tile_x_start < width; tile_x_start += fTileWidth) {
scroggo@google.comcbcef702012-12-13 22:09:28 +0000534 if (0 == tile_y_start) {
535 // Only count tiles in the X direction on the first pass.
536 fTilesX++;
537 }
robertphillips78c71272014-10-09 04:59:19 -0700538 *fTileRects.append() = SkIRect::MakeXYWH(tile_x_start, tile_y_start,
539 fTileWidth, fTileHeight);
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000540 }
541 }
542}
543
scroggo@google.comcbcef702012-12-13 22:09:28 +0000544bool TiledPictureRenderer::tileDimensions(int &x, int &y) {
545 if (fTileRects.count() == 0 || NULL == fPicture) {
546 return false;
547 }
548 x = fTilesX;
549 y = fTilesY;
550 return true;
551}
552
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000553// The goal of the powers of two tiles is to minimize the amount of wasted tile
554// space in the width-wise direction and then minimize the number of tiles. The
555// constraints are that every tile must have a pixel width that is a power of
556// two and also be of some minimal width (that is also a power of two).
557//
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000558// This is solved by first taking our picture size and rounding it up to the
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000559// multiple of the minimal width. The binary representation of this rounded
560// value gives us the tiles we need: a bit of value one means we need a tile of
561// that size.
562void TiledPictureRenderer::setupPowerOf2Tiles() {
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000563 // Only use enough tiles to cover the viewport
564 const int width = this->getViewWidth();
565 const int height = this->getViewHeight();
566
567 int rounded_value = width;
568 if (width % fTileMinPowerOf2Width != 0) {
569 rounded_value = width - (width % fTileMinPowerOf2Width) + fTileMinPowerOf2Width;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000570 }
571
reed@google.come15b2f52013-12-18 04:59:26 +0000572 int num_bits = SkScalarCeilToInt(scalar_log2(SkIntToScalar(width)));
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000573 int largest_possible_tile_size = 1 << num_bits;
574
scroggo@google.comcbcef702012-12-13 22:09:28 +0000575 fTilesX = fTilesY = 0;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000576 // The tile height is constant for a particular picture.
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000577 for (int tile_y_start = 0; tile_y_start < height; tile_y_start += fTileHeight) {
scroggo@google.comcbcef702012-12-13 22:09:28 +0000578 fTilesY++;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000579 int tile_x_start = 0;
580 int current_width = largest_possible_tile_size;
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000581 // Set fTileWidth to be the width of the widest tile, so that each canvas is large enough
582 // to draw each tile.
583 fTileWidth = current_width;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000584
585 while (current_width >= fTileMinPowerOf2Width) {
586 // It is very important this is a bitwise AND.
587 if (current_width & rounded_value) {
scroggo@google.comcbcef702012-12-13 22:09:28 +0000588 if (0 == tile_y_start) {
589 // Only count tiles in the X direction on the first pass.
590 fTilesX++;
591 }
robertphillips78c71272014-10-09 04:59:19 -0700592 *fTileRects.append() = SkIRect::MakeXYWH(tile_x_start, tile_y_start,
593 current_width, fTileHeight);
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000594 tile_x_start += current_width;
595 }
596
597 current_width >>= 1;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000598 }
599 }
600}
601
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000602/**
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +0000603 * Draw the specified picture to the canvas translated to rectangle provided, so that this mini
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000604 * canvas represents the rectangle's portion of the overall picture.
605 * Saves and restores so that the initial clip and matrix return to their state before this function
606 * is called.
607 */
mtklein2a65a232014-08-26 14:07:04 -0700608static void draw_tile_to_canvas(SkCanvas* canvas,
robertphillips78c71272014-10-09 04:59:19 -0700609 const SkIRect& tileRect,
robertphillipsce4dd3d2014-07-07 13:46:35 -0700610 const SkPicture* picture) {
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000611 int saveCount = canvas->save();
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000612 // Translate so that we draw the correct portion of the picture.
613 // Perform a postTranslate so that the scaleFactor does not interfere with the positioning.
614 SkMatrix mat(canvas->getTotalMatrix());
robertphillips78c71272014-10-09 04:59:19 -0700615 mat.postTranslate(-SkIntToScalar(tileRect.fLeft), -SkIntToScalar(tileRect.fTop));
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000616 canvas->setMatrix(mat);
robertphillips43044dd2014-11-28 07:42:16 -0800617 canvas->clipRect(SkRect::Make(tileRect));
robertphillips4a36d9a2014-10-20 08:45:57 -0700618 canvas->clear(SK_ColorTRANSPARENT); // Not every picture covers the entirety of every tile
robertphillips9b14f262014-06-04 05:40:44 -0700619 canvas->drawPicture(picture);
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000620 canvas->restoreToCount(saveCount);
621 canvas->flush();
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000622}
623
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000624///////////////////////////////////////////////////////////////////////////////////////////////
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000625
commit-bot@chromium.orga3f882c2013-12-13 20:52:36 +0000626/**
627 * Copies the entirety of the src bitmap (typically a tile) into a portion of the dst bitmap.
628 * If the src bitmap is too large to fit within the dst bitmap after the x and y
629 * offsets have been applied, any excess will be ignored (so only the top-left portion of the
630 * src bitmap will be copied).
631 *
632 * @param src source bitmap
633 * @param dst destination bitmap
634 * @param xOffset x-offset within destination bitmap
635 * @param yOffset y-offset within destination bitmap
636 */
637static void bitmapCopyAtOffset(const SkBitmap& src, SkBitmap* dst,
638 int xOffset, int yOffset) {
639 for (int y = 0; y <src.height() && y + yOffset < dst->height() ; y++) {
640 for (int x = 0; x < src.width() && x + xOffset < dst->width() ; x++) {
641 *dst->getAddr32(xOffset + x, yOffset + y) = *src.getAddr32(x, y);
edisonn@google.com84f548c2012-12-18 22:24:03 +0000642 }
643 }
644}
645
scroggo@google.comcbcef702012-12-13 22:09:28 +0000646bool TiledPictureRenderer::nextTile(int &i, int &j) {
647 if (++fCurrentTileOffset < fTileRects.count()) {
648 i = fCurrentTileOffset % fTilesX;
649 j = fCurrentTileOffset / fTilesX;
650 return true;
651 }
652 return false;
653}
654
655void TiledPictureRenderer::drawCurrentTile() {
656 SkASSERT(fCurrentTileOffset >= 0 && fCurrentTileOffset < fTileRects.count());
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +0000657 draw_tile_to_canvas(fCanvas, fTileRects[fCurrentTileOffset], fPicture);
scroggo@google.comcbcef702012-12-13 22:09:28 +0000658}
659
mtklein703dd2e2015-01-09 06:41:48 -0800660bool TiledPictureRenderer::postRender(SkCanvas* canvas, const SkIRect& tileRect,
robertphillips78c71272014-10-09 04:59:19 -0700661 SkBitmap* tempBM, SkBitmap** out,
662 int tileNumber) {
663 bool success = true;
664
665 if (fEnableWrites) {
666 success &= write(canvas, fWritePath, fMismatchPath, fInputFilename, fJsonSummaryPtr,
667 fUseChecksumBasedFilenames, &tileNumber);
668 }
669 if (out) {
670 if (canvas->readPixels(tempBM, 0, 0)) {
671 // Add this tile to the entire bitmap.
672 bitmapCopyAtOffset(*tempBM, *out, tileRect.left(), tileRect.top());
673 } else {
674 success = false;
675 }
676 }
677
678 return success;
679}
680
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000681bool TiledPictureRenderer::render(SkBitmap** out) {
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000682 SkASSERT(fPicture != NULL);
683 if (NULL == fPicture) {
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000684 return false;
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000685 }
686
edisonn@google.com84f548c2012-12-18 22:24:03 +0000687 SkBitmap bitmap;
robertphillips78c71272014-10-09 04:59:19 -0700688 if (out) {
edisonn@google.com84f548c2012-12-18 22:24:03 +0000689 *out = SkNEW(SkBitmap);
mtklein703dd2e2015-01-09 06:41:48 -0800690 setup_bitmap(*out, SkScalarCeilToInt(fPicture->cullRect().width()),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700691 SkScalarCeilToInt(fPicture->cullRect().height()));
edisonn@google.com84f548c2012-12-18 22:24:03 +0000692 setup_bitmap(&bitmap, fTileWidth, fTileHeight);
693 }
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000694 bool success = true;
robertphillips78c71272014-10-09 04:59:19 -0700695
696 if (fUseMultiPictureDraw) {
697 SkMultiPictureDraw mpd;
698 SkTDArray<SkSurface*> surfaces;
699 surfaces.setReserve(fTileRects.count());
700
701 // Create a separate SkSurface/SkCanvas for each tile along with a
702 // translated version of the skp (to mimic Chrome's behavior) and
703 // feed all such pairs to the MultiPictureDraw.
704 for (int i = 0; i < fTileRects.count(); ++i) {
705 SkImageInfo ii = fCanvas->imageInfo().makeWH(fTileRects[i].width(),
706 fTileRects[i].height());
707 *surfaces.append() = fCanvas->newSurface(ii);
708 surfaces[i]->getCanvas()->setMatrix(fCanvas->getTotalMatrix());
709
710 SkPictureRecorder recorder;
robertphillips81f71b62014-11-11 04:54:49 -0800711 SkRTreeFactory bbhFactory;
712
robertphillips78c71272014-10-09 04:59:19 -0700713 SkCanvas* c = recorder.beginRecording(SkIntToScalar(fTileRects[i].width()),
robertphillips81f71b62014-11-11 04:54:49 -0800714 SkIntToScalar(fTileRects[i].height()),
715 &bbhFactory,
716 SkPictureRecorder::kComputeSaveLayerInfo_RecordFlag);
robertphillips78c71272014-10-09 04:59:19 -0700717 c->save();
718 SkMatrix mat;
719 mat.setTranslate(-SkIntToScalar(fTileRects[i].fLeft),
720 -SkIntToScalar(fTileRects[i].fTop));
721 c->setMatrix(mat);
722 c->drawPicture(fPicture);
723 c->restore();
724
725 SkAutoTUnref<SkPicture> xlatedPicture(recorder.endRecording());
726
727 mpd.add(surfaces[i]->getCanvas(), xlatedPicture);
commit-bot@chromium.org8991c672014-05-22 00:36:05 +0000728 }
robertphillips78c71272014-10-09 04:59:19 -0700729
730 // Render all the buffered SkCanvases/SkPictures
731 mpd.draw();
732
733 // Sort out the results and cleanup the allocated surfaces
734 for (int i = 0; i < fTileRects.count(); ++i) {
735 success &= this->postRender(surfaces[i]->getCanvas(), fTileRects[i], &bitmap, out, i);
736 surfaces[i]->unref();
737 }
738 } else {
739 for (int i = 0; i < fTileRects.count(); ++i) {
740 draw_tile_to_canvas(fCanvas, fTileRects[i], fPicture);
741 success &= this->postRender(fCanvas, fTileRects[i], &bitmap, out, i);
edisonn@google.com84f548c2012-12-18 22:24:03 +0000742 }
keyar@chromium.org163b5672012-08-01 17:53:29 +0000743 }
robertphillips78c71272014-10-09 04:59:19 -0700744
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000745 return success;
keyar@chromium.org163b5672012-08-01 17:53:29 +0000746}
747
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000748SkCanvas* TiledPictureRenderer::setupCanvas(int width, int height) {
749 SkCanvas* canvas = this->INHERITED::setupCanvas(width, height);
bsalomon49f085d2014-09-05 13:34:00 -0700750 SkASSERT(fPicture);
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000751 // Clip the tile to an area that is completely inside both the SkPicture and the viewport. This
752 // is mostly important for tiles on the right and bottom edges as they may go over this area and
753 // the picture may have some commands that draw outside of this area and so should not actually
754 // be written.
755 // Uses a clipRegion so that it will be unaffected by the scale factor, which may have been set
756 // by INHERITED::setupCanvas.
757 SkRegion clipRegion;
758 clipRegion.setRect(0, 0, this->getViewWidth(), this->getViewHeight());
759 canvas->clipRegion(clipRegion);
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000760 return canvas;
761}
scroggo@google.com0a049b82012-11-02 22:01:26 +0000762
763SkString TiledPictureRenderer::getConfigNameInternal() {
764 SkString name;
765 if (fTileMinPowerOf2Width > 0) {
766 name.append("pow2tile_");
767 name.appendf("%i", fTileMinPowerOf2Width);
768 } else {
769 name.append("tile_");
770 if (fTileWidthPercentage > 0) {
771 name.appendf("%.f%%", fTileWidthPercentage);
772 } else {
773 name.appendf("%i", fTileWidth);
774 }
775 }
776 name.append("x");
777 if (fTileHeightPercentage > 0) {
778 name.appendf("%.f%%", fTileHeightPercentage);
779 } else {
780 name.appendf("%i", fTileHeight);
781 }
782 return name;
783}
784
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000785///////////////////////////////////////////////////////////////////////////////////////////////
786
scroggo@google.com9a412522012-09-07 15:21:18 +0000787void PlaybackCreationRenderer::setup() {
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000788 SkAutoTDelete<SkBBHFactory> factory(this->getFactory());
789 fRecorder.reset(SkNEW(SkPictureRecorder));
mtklein703dd2e2015-01-09 06:41:48 -0800790 SkCanvas* canvas = fRecorder->beginRecording(SkIntToScalar(this->getViewWidth()),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700791 SkIntToScalar(this->getViewHeight()),
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000792 factory.get(),
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000793 this->recordFlags());
794 this->scaleToScaleFactor(canvas);
robertphillips9b14f262014-06-04 05:40:44 -0700795 canvas->drawPicture(fPicture);
scroggo@google.com9a412522012-09-07 15:21:18 +0000796}
797
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000798bool PlaybackCreationRenderer::render(SkBitmap** out) {
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000799 fPicture.reset(fRecorder->endRecording());
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000800 // Since this class does not actually render, return false.
801 return false;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000802}
803
scroggo@google.com0a049b82012-11-02 22:01:26 +0000804SkString PlaybackCreationRenderer::getConfigNameInternal() {
805 return SkString("playback_creation");
806}
807
junov@chromium.org9313ca42012-11-02 18:11:49 +0000808///////////////////////////////////////////////////////////////////////////////////////////////
809// SkPicture variants for each BBoxHierarchy type
810
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000811SkBBHFactory* PictureRenderer::getFactory() {
junov@chromium.org9313ca42012-11-02 18:11:49 +0000812 switch (fBBoxHierarchyType) {
813 case kNone_BBoxHierarchyType:
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000814 return NULL;
junov@chromium.org9313ca42012-11-02 18:11:49 +0000815 case kRTree_BBoxHierarchyType:
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000816 return SkNEW(SkRTreeFactory);
junov@chromium.org9313ca42012-11-02 18:11:49 +0000817 }
818 SkASSERT(0); // invalid bbhType
819 return NULL;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000820}
junov@chromium.org9313ca42012-11-02 18:11:49 +0000821
822} // namespace sk_tools