blob: 19ee7b5f2a91c896916719000be7e4e4f7f008e7 [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"
fmalita50420202015-06-15 11:48:16 -070027#include "SkPaintFilterCanvas.h"
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000028#include "SkPicture.h"
robertphillips@google.com770963f2014-04-18 18:04:41 +000029#include "SkPictureRecorder.h"
scroggo@google.com1b1bcc32013-05-21 20:31:23 +000030#include "SkPictureUtils.h"
31#include "SkPixelRef.h"
scroggo895c43b2014-12-11 10:53:58 -080032#include "SkPixelSerializer.h"
keyar@chromium.orgea826952012-08-23 15:24:13 +000033#include "SkScalar.h"
scroggo@google.coma9e3a362012-11-07 17:52:48 +000034#include "SkStream.h"
keyar@chromium.org9299ede2012-08-21 19:05:08 +000035#include "SkString.h"
robertphillips78c71272014-10-09 04:59:19 -070036#include "SkSurface.h"
scroggo@google.com58b4ead2012-08-31 16:15:22 +000037#include "SkTemplates.h"
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000038#include "SkTDArray.h"
scroggo@google.com58b4ead2012-08-31 16:15:22 +000039#include "SkThreadUtils.h"
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000040#include "SkTypes.h"
robertphillips3e5c2b12015-03-23 05:46:51 -070041#include "sk_tool_utils.h"
keyar@chromium.org4ea96c52012-08-20 15:03:29 +000042
reed@google.come15b2f52013-12-18 04:59:26 +000043static inline SkScalar scalar_log2(SkScalar x) {
reed80ea19c2015-05-12 10:37:34 -070044 static const SkScalar log2_conversion_factor = SkScalarInvert(SkScalarLog(2));
skia.committer@gmail.com3b85deb2013-12-18 07:01:56 +000045
reed@google.come15b2f52013-12-18 04:59:26 +000046 return SkScalarLog(x) * log2_conversion_factor;
47}
48
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000049namespace sk_tools {
50
51enum {
52 kDefaultTileWidth = 256,
53 kDefaultTileHeight = 256
54};
55
mtklein2a65a232014-08-26 14:07:04 -070056void PictureRenderer::init(const SkPicture* pict,
57 const SkString* writePath,
robertphillipsce4dd3d2014-07-07 13:46:35 -070058 const SkString* mismatchPath,
mtklein2a65a232014-08-26 14:07:04 -070059 const SkString* inputFilename,
robertphillips78c71272014-10-09 04:59:19 -070060 bool useChecksumBasedFilenames,
61 bool useMultiPictureDraw) {
commit-bot@chromium.org3f045172014-05-15 15:10:48 +000062 this->CopyString(&fWritePath, writePath);
63 this->CopyString(&fMismatchPath, mismatchPath);
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +000064 this->CopyString(&fInputFilename, inputFilename);
65 fUseChecksumBasedFilenames = useChecksumBasedFilenames;
robertphillips78c71272014-10-09 04:59:19 -070066 fUseMultiPictureDraw = useMultiPictureDraw;
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +000067
halcanary96fcdcc2015-08-27 07:41:13 -070068 SkASSERT(nullptr == fPicture);
69 SkASSERT(nullptr == fCanvas.get());
bsalomon49f085d2014-09-05 13:34:00 -070070 if (fPicture || fCanvas.get()) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +000071 return;
72 }
73
halcanary96fcdcc2015-08-27 07:41:13 -070074 SkASSERT(pict != nullptr);
75 if (nullptr == pict) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +000076 return;
77 }
78
bungeman77a53de2015-10-01 12:28:49 -070079 fPicture.reset(SkRef(pict));
keyar@chromium.orga474ce32012-08-20 15:03:57 +000080 fCanvas.reset(this->setupCanvas());
81}
82
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +000083void PictureRenderer::CopyString(SkString* dest, const SkString* src) {
bsalomon49f085d2014-09-05 13:34:00 -070084 if (src) {
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +000085 dest->set(*src);
86 } else {
87 dest->reset();
88 }
89}
90
fmalita50420202015-06-15 11:48:16 -070091class FlagsFilterCanvas : public SkPaintFilterCanvas {
caryclark@google.coma3622372012-11-06 21:26:13 +000092public:
fmalita50420202015-06-15 11:48:16 -070093 FlagsFilterCanvas(SkCanvas* canvas, PictureRenderer::DrawFilterFlags* flags)
94 : INHERITED(canvas->imageInfo().width(), canvas->imageInfo().height())
95 , fFlags(flags) {
96 this->addCanvas(canvas);
97 }
caryclark@google.coma3622372012-11-06 21:26:13 +000098
fmalita50420202015-06-15 11:48:16 -070099protected:
100 void onFilterPaint(SkPaint* paint, Type t) const override {
caryclark@google.coma3622372012-11-06 21:26:13 +0000101 paint->setFlags(paint->getFlags() & ~fFlags[t] & SkPaint::kAllFlags);
robertphillips@google.com49149312013-07-03 15:34:35 +0000102 if (PictureRenderer::kMaskFilter_DrawFilterFlag & fFlags[t]) {
caryclark@google.coma3622372012-11-06 21:26:13 +0000103 SkMaskFilter* maskFilter = paint->getMaskFilter();
bsalomon49f085d2014-09-05 13:34:00 -0700104 if (maskFilter) {
halcanary96fcdcc2015-08-27 07:41:13 -0700105 paint->setMaskFilter(nullptr);
caryclark@google.coma3622372012-11-06 21:26:13 +0000106 }
107 }
108 if (PictureRenderer::kHinting_DrawFilterFlag & fFlags[t]) {
109 paint->setHinting(SkPaint::kNo_Hinting);
110 } else if (PictureRenderer::kSlightHinting_DrawFilterFlag & fFlags[t]) {
111 paint->setHinting(SkPaint::kSlight_Hinting);
112 }
113 }
114
115private:
fmalita50420202015-06-15 11:48:16 -0700116 const PictureRenderer::DrawFilterFlags* fFlags;
caryclark@google.coma3622372012-11-06 21:26:13 +0000117
fmalita50420202015-06-15 11:48:16 -0700118 typedef SkPaintFilterCanvas INHERITED;
119};
caryclark@google.coma3622372012-11-06 21:26:13 +0000120
keyar@chromium.orga474ce32012-08-20 15:03:57 +0000121SkCanvas* PictureRenderer::setupCanvas() {
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000122 const int width = this->getViewWidth();
123 const int height = this->getViewHeight();
124 return this->setupCanvas(width, height);
keyar@chromium.orga474ce32012-08-20 15:03:57 +0000125}
126
127SkCanvas* PictureRenderer::setupCanvas(int width, int height) {
fmalita50420202015-06-15 11:48:16 -0700128 SkAutoTUnref<SkCanvas> canvas;
129
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);
halcanary385fe4d2015-08-26 13:07:48 -0700134 canvas.reset(new 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
hendrikw885bf092015-08-27 10:38:39 -0700142#if SK_COMMAND_BUFFER
143 case kCommandBuffer_DeviceType:
144 // fall through
145#endif
rmistry@google.com6ab96732014-01-06 18:37:24 +0000146#if SK_MESA
147 case kMesa_DeviceType:
148 // fall through
149#endif
commit-bot@chromium.org0fd52702014-03-07 18:41:14 +0000150 case kGPU_DeviceType:
151 case kNVPR_DeviceType: {
commit-bot@chromium.orgae403b92013-04-10 17:27:30 +0000152 SkAutoTUnref<GrSurface> target;
scroggo@google.com0556ea02013-02-08 19:38:21 +0000153 if (fGrContext) {
154 // create a render target to back the device
bsalomonf2703d82014-10-28 14:33:06 -0700155 GrSurfaceDesc desc;
scroggo@google.com0556ea02013-02-08 19:38:21 +0000156 desc.fConfig = kSkia8888_GrPixelConfig;
bsalomonf2703d82014-10-28 14:33:06 -0700157 desc.fFlags = kRenderTarget_GrSurfaceFlag;
scroggo@google.com0556ea02013-02-08 19:38:21 +0000158 desc.fWidth = width;
159 desc.fHeight = height;
jvanverth@google.comf6a90332013-05-02 12:39:37 +0000160 desc.fSampleCnt = fSampleCount;
halcanary96fcdcc2015-08-27 07:41:13 -0700161 target.reset(fGrContext->textureProvider()->createTexture(desc, false, nullptr, 0));
scroggo@google.com0556ea02013-02-08 19:38:21 +0000162 }
bsalomonafe30052015-01-16 07:32:33 -0800163
bsalomonafcd7cd2015-08-31 12:39:41 -0700164 uint32_t flags = fUseDFText ? SkSurfaceProps::kUseDeviceIndependentFonts_Flag : 0;
bsalomonafe30052015-01-16 07:32:33 -0800165 SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
bsalomon74f681d2015-06-23 14:38:48 -0700166 SkAutoTUnref<SkGpuDevice> device(
167 SkGpuDevice::Create(target->asRenderTarget(), &props,
168 SkGpuDevice::kUninit_InitContents));
bsalomonafe30052015-01-16 07:32:33 -0800169 if (!device) {
halcanary96fcdcc2015-08-27 07:41:13 -0700170 return nullptr;
scroggo@google.com0556ea02013-02-08 19:38:21 +0000171 }
halcanary385fe4d2015-08-26 13:07:48 -0700172 canvas.reset(new SkCanvas(device));
scroggo@google.com0556ea02013-02-08 19:38:21 +0000173 break;
keyar@chromium.org4ea96c52012-08-20 15:03:29 +0000174 }
175#endif
176 default:
177 SkASSERT(0);
halcanary96fcdcc2015-08-27 07:41:13 -0700178 return nullptr;
keyar@chromium.org4ea96c52012-08-20 15:03:29 +0000179 }
fmalita50420202015-06-15 11:48:16 -0700180
181 if (fHasDrawFilters) {
182 if (fDrawFilters[0] & PictureRenderer::kAAClip_DrawFilterFlag) {
183 canvas->setAllowSoftClip(false);
184 }
185
halcanary385fe4d2015-08-26 13:07:48 -0700186 canvas.reset(new FlagsFilterCanvas(canvas.get(), fDrawFilters));
fmalita50420202015-06-15 11:48:16 -0700187 }
188
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000189 this->scaleToScaleFactor(canvas);
commit-bot@chromium.org17cc3ea2014-01-15 14:51:25 +0000190
191 // Pictures often lie about their extent (i.e., claim to be 100x100 but
192 // only ever draw to 90x100). Clear here so the undrawn portion will have
193 // a consistent color
194 canvas->clear(SK_ColorTRANSPARENT);
fmalita50420202015-06-15 11:48:16 -0700195 return canvas.detach();
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000196}
keyar@chromium.orga474ce32012-08-20 15:03:57 +0000197
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000198void PictureRenderer::scaleToScaleFactor(SkCanvas* canvas) {
halcanary96fcdcc2015-08-27 07:41:13 -0700199 SkASSERT(canvas != nullptr);
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000200 if (fScaleFactor != SK_Scalar1) {
201 canvas->scale(fScaleFactor, fScaleFactor);
202 }
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000203}
204
205void PictureRenderer::end() {
scroggo@google.com08085f82013-01-28 20:40:24 +0000206 this->resetState(true);
halcanary96fcdcc2015-08-27 07:41:13 -0700207 fPicture.reset(nullptr);
208 fCanvas.reset(nullptr);
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000209}
210
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000211int PictureRenderer::getViewWidth() {
halcanary96fcdcc2015-08-27 07:41:13 -0700212 SkASSERT(fPicture != nullptr);
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700213 int width = SkScalarCeilToInt(fPicture->cullRect().width() * fScaleFactor);
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000214 if (fViewport.width() > 0) {
215 width = SkMin32(width, fViewport.width());
216 }
217 return width;
218}
219
220int PictureRenderer::getViewHeight() {
halcanary96fcdcc2015-08-27 07:41:13 -0700221 SkASSERT(fPicture != nullptr);
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700222 int height = SkScalarCeilToInt(fPicture->cullRect().height() * fScaleFactor);
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000223 if (fViewport.height() > 0) {
224 height = SkMin32(height, fViewport.height());
225 }
226 return height;
227}
228
junov@chromium.org9313ca42012-11-02 18:11:49 +0000229/** Converts fPicture to a picture that uses a BBoxHierarchy.
230 * PictureRenderer subclasses that are used to test picture playback
231 * should call this method during init.
232 */
233void PictureRenderer::buildBBoxHierarchy() {
bsalomon49f085d2014-09-05 13:34:00 -0700234 SkASSERT(fPicture);
235 if (kNone_BBoxHierarchyType != fBBoxHierarchyType && fPicture) {
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000236 SkAutoTDelete<SkBBHFactory> factory(this->getFactory());
237 SkPictureRecorder recorder;
robertphillips81f71b62014-11-11 04:54:49 -0800238 uint32_t flags = this->recordFlags();
239 if (fUseMultiPictureDraw) {
240 flags |= SkPictureRecorder::kComputeSaveLayerInfo_RecordFlag;
241 }
mtklein703dd2e2015-01-09 06:41:48 -0800242 SkCanvas* canvas = recorder.beginRecording(fPicture->cullRect().width(),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700243 fPicture->cullRect().height(),
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000244 factory.get(),
robertphillips81f71b62014-11-11 04:54:49 -0800245 flags);
robertphillipsc5ba71d2014-09-04 08:42:50 -0700246 fPicture->playback(canvas);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000247 fPicture.reset(recorder.endRecording());
junov@chromium.org9313ca42012-11-02 18:11:49 +0000248 }
249}
250
scroggo@google.com08085f82013-01-28 20:40:24 +0000251void PictureRenderer::resetState(bool callFinish) {
keyar@chromium.org28136b32012-08-20 15:04:15 +0000252#if SK_SUPPORT_GPU
kkinnunen9e61bb72014-10-09 05:24:15 -0700253 SkGLContext* glContext = this->getGLContext();
halcanary96fcdcc2015-08-27 07:41:13 -0700254 if (nullptr == glContext) {
scroggo@google.com0556ea02013-02-08 19:38:21 +0000255 SkASSERT(kBitmap_DeviceType == fDeviceType);
256 return;
257 }
keyar@chromium.org28136b32012-08-20 15:04:15 +0000258
scroggo@google.com0556ea02013-02-08 19:38:21 +0000259 fGrContext->flush();
commit-bot@chromium.org51c040e2014-03-11 22:58:00 +0000260 glContext->swapBuffers();
scroggo@google.com0556ea02013-02-08 19:38:21 +0000261 if (callFinish) {
262 SK_GL(*glContext, Finish());
keyar@chromium.org77a55222012-08-20 15:03:47 +0000263 }
keyar@chromium.orga40c20d2012-08-20 15:04:12 +0000264#endif
keyar@chromium.org77a55222012-08-20 15:03:47 +0000265}
266
robertphillips@google.com94d8f1e2013-12-18 17:25:33 +0000267void PictureRenderer::purgeTextures() {
268 SkDiscardableMemoryPool* pool = SkGetGlobalDiscardableMemoryPool();
269
270 pool->dumpPool();
271
272#if SK_SUPPORT_GPU
kkinnunen9e61bb72014-10-09 05:24:15 -0700273 SkGLContext* glContext = this->getGLContext();
halcanary96fcdcc2015-08-27 07:41:13 -0700274 if (nullptr == glContext) {
robertphillips@google.com94d8f1e2013-12-18 17:25:33 +0000275 SkASSERT(kBitmap_DeviceType == fDeviceType);
276 return;
277 }
278
279 // resetState should've already done this
280 fGrContext->flush();
281
282 fGrContext->purgeAllUnlockedResources();
283#endif
284}
285
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000286/**
commit-bot@chromium.org4610a462014-04-29 19:39:22 +0000287 * Write the canvas to an image file and/or JSON summary.
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000288 *
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000289 * @param canvas Must be non-null. Canvas to be written to a file.
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000290 * @param writePath If nonempty, write the binary image to a file within this directory.
291 * @param mismatchPath If nonempty, write the binary image to a file within this directory,
292 * but only if the image does not match expectations.
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000293 * @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 +0000294 * @param jsonSummaryPtr If not null, add image results (checksum) to this summary.
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000295 * @param useChecksumBasedFilenames If true, use checksum-based filenames when writing to disk.
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000296 * @param tileNumberPtr If not null, which tile number this image contains.
commit-bot@chromium.orga3f882c2013-12-13 20:52:36 +0000297 *
commit-bot@chromium.org4610a462014-04-29 19:39:22 +0000298 * @return bool True if the operation completed successfully.
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000299 */
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000300static bool write(SkCanvas* canvas, const SkString& writePath, const SkString& mismatchPath,
301 const SkString& inputFilename, ImageResultsAndExpectations *jsonSummaryPtr,
halcanary96fcdcc2015-08-27 07:41:13 -0700302 bool useChecksumBasedFilenames, const int* tileNumberPtr=nullptr) {
303 SkASSERT(canvas != nullptr);
304 if (nullptr == canvas) {
keyar@chromium.org9299ede2012-08-21 19:05:08 +0000305 return false;
306 }
307
308 SkBitmap bitmap;
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000309 SkISize size = canvas->getDeviceSize();
commit-bot@chromium.org205ce482014-05-12 15:37:20 +0000310 setup_bitmap(&bitmap, size.width(), size.height());
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000311
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000312 canvas->readPixels(&bitmap, 0, 0);
commit-bot@chromium.org205ce482014-05-12 15:37:20 +0000313 force_all_opaque(bitmap);
314 BitmapAndDigest bitmapAndDigest(bitmap);
keyar@chromium.org9299ede2012-08-21 19:05:08 +0000315
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000316 SkString escapedInputFilename(inputFilename);
317 replace_char(&escapedInputFilename, '.', '_');
318
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000319 // TODO(epoger): what about including the config type within outputFilename? That way,
320 // we could combine results of different config types without conflicting filenames.
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000321 SkString outputFilename;
halcanary96fcdcc2015-08-27 07:41:13 -0700322 const char *outputSubdirPtr = nullptr;
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000323 if (useChecksumBasedFilenames) {
epoger85b438d2014-08-21 23:21:32 -0700324 ImageDigest *imageDigestPtr = bitmapAndDigest.getImageDigestPtr();
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000325 outputSubdirPtr = escapedInputFilename.c_str();
commit-bot@chromium.org205ce482014-05-12 15:37:20 +0000326 outputFilename.set(imageDigestPtr->getHashType());
327 outputFilename.append("_");
328 outputFilename.appendU64(imageDigestPtr->getHashValue());
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000329 } else {
330 outputFilename.set(escapedInputFilename);
bsalomon49f085d2014-09-05 13:34:00 -0700331 if (tileNumberPtr) {
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000332 outputFilename.append("-tile");
333 outputFilename.appendS32(*tileNumberPtr);
334 }
commit-bot@chromium.orga3f882c2013-12-13 20:52:36 +0000335 }
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000336 outputFilename.append(".png");
commit-bot@chromium.orga3f882c2013-12-13 20:52:36 +0000337
bsalomon49f085d2014-09-05 13:34:00 -0700338 if (jsonSummaryPtr) {
epoger85b438d2014-08-21 23:21:32 -0700339 ImageDigest *imageDigestPtr = bitmapAndDigest.getImageDigestPtr();
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000340 SkString outputRelativePath;
341 if (outputSubdirPtr) {
342 outputRelativePath.set(outputSubdirPtr);
343 outputRelativePath.append("/"); // always use "/", even on Windows
344 outputRelativePath.append(outputFilename);
345 } else {
346 outputRelativePath.set(outputFilename);
347 }
348
349 jsonSummaryPtr->add(inputFilename.c_str(), outputRelativePath.c_str(),
commit-bot@chromium.org205ce482014-05-12 15:37:20 +0000350 *imageDigestPtr, tileNumberPtr);
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000351 if (!mismatchPath.isEmpty() &&
epoger85b438d2014-08-21 23:21:32 -0700352 !jsonSummaryPtr->getExpectation(inputFilename.c_str(),
353 tileNumberPtr).matches(*imageDigestPtr)) {
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000354 if (!write_bitmap_to_disk(bitmap, mismatchPath, outputSubdirPtr, outputFilename)) {
355 return false;
356 }
357 }
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000358 }
359
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000360 if (writePath.isEmpty()) {
commit-bot@chromium.org4610a462014-04-29 19:39:22 +0000361 return true;
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000362 } else {
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000363 return write_bitmap_to_disk(bitmap, writePath, outputSubdirPtr, outputFilename);
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000364 }
keyar@chromium.org9299ede2012-08-21 19:05:08 +0000365}
366
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000367///////////////////////////////////////////////////////////////////////////////////////////////
368
djsollen@google.comfd9720c2012-11-06 16:54:40 +0000369SkCanvas* RecordPictureRenderer::setupCanvas(int width, int height) {
370 // defer the canvas setup until the render step
halcanary96fcdcc2015-08-27 07:41:13 -0700371 return nullptr;
djsollen@google.comfd9720c2012-11-06 16:54:40 +0000372}
373
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000374bool RecordPictureRenderer::render(SkBitmap** out) {
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000375 SkAutoTDelete<SkBBHFactory> factory(this->getFactory());
376 SkPictureRecorder recorder;
mtklein703dd2e2015-01-09 06:41:48 -0800377 SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(this->getViewWidth()),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700378 SkIntToScalar(this->getViewHeight()),
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000379 factory.get(),
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000380 this->recordFlags());
381 this->scaleToScaleFactor(canvas);
robertphillipsc5ba71d2014-09-04 08:42:50 -0700382 fPicture->playback(canvas);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000383 SkAutoTUnref<SkPicture> picture(recorder.endRecording());
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000384 if (!fWritePath.isEmpty()) {
scroggo@google.coma9e3a362012-11-07 17:52:48 +0000385 // Record the new picture as a new SKP with PNG encoded bitmaps.
tfarinaa8e2e152014-07-28 19:26:58 -0700386 SkString skpPath = SkOSPath::Join(fWritePath.c_str(), fInputFilename.c_str());
scroggo@google.coma9e3a362012-11-07 17:52:48 +0000387 SkFILEWStream stream(skpPath.c_str());
robertphillips3e5c2b12015-03-23 05:46:51 -0700388 sk_tool_utils::PngPixelSerializer serializer;
scroggo895c43b2014-12-11 10:53:58 -0800389 picture->serialize(&stream, &serializer);
scroggo@google.coma9e3a362012-11-07 17:52:48 +0000390 return true;
391 }
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000392 return false;
scroggo@google.com9a412522012-09-07 15:21:18 +0000393}
394
scroggo@google.com0a049b82012-11-02 22:01:26 +0000395SkString RecordPictureRenderer::getConfigNameInternal() {
396 return SkString("record");
397}
398
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000399///////////////////////////////////////////////////////////////////////////////////////////////
400
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000401bool PipePictureRenderer::render(SkBitmap** out) {
halcanary96fcdcc2015-08-27 07:41:13 -0700402 SkASSERT(fCanvas.get() != nullptr);
403 SkASSERT(fPicture != nullptr);
404 if (nullptr == fCanvas.get() || nullptr == fPicture) {
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000405 return false;
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000406 }
407
408 PipeController pipeController(fCanvas.get());
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000409 SkGPipeWriter writer;
410 SkCanvas* pipeCanvas = writer.startRecording(&pipeController);
robertphillips9b14f262014-06-04 05:40:44 -0700411 pipeCanvas->drawPicture(fPicture);
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000412 writer.endRecording();
scroggo@google.com9a412522012-09-07 15:21:18 +0000413 fCanvas->flush();
bsalomon49f085d2014-09-05 13:34:00 -0700414 if (out) {
halcanary385fe4d2015-08-26 13:07:48 -0700415 *out = new SkBitmap;
mtklein703dd2e2015-01-09 06:41:48 -0800416 setup_bitmap(*out, SkScalarCeilToInt(fPicture->cullRect().width()),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700417 SkScalarCeilToInt(fPicture->cullRect().height()));
edisonn@google.com84f548c2012-12-18 22:24:03 +0000418 fCanvas->readPixels(*out, 0, 0);
skia.committer@gmail.coma7d8e3e2012-12-19 02:01:38 +0000419 }
commit-bot@chromium.org8991c672014-05-22 00:36:05 +0000420 if (fEnableWrites) {
421 return write(fCanvas, fWritePath, fMismatchPath, fInputFilename, fJsonSummaryPtr,
422 fUseChecksumBasedFilenames);
423 } else {
424 return true;
425 }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000426}
427
scroggo@google.com0a049b82012-11-02 22:01:26 +0000428SkString PipePictureRenderer::getConfigNameInternal() {
429 return SkString("pipe");
430}
431
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000432///////////////////////////////////////////////////////////////////////////////////////////////
433
robertphillipsce4dd3d2014-07-07 13:46:35 -0700434void SimplePictureRenderer::init(const SkPicture* picture, const SkString* writePath,
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000435 const SkString* mismatchPath, const SkString* inputFilename,
robertphillips78c71272014-10-09 04:59:19 -0700436 bool useChecksumBasedFilenames, bool useMultiPictureDraw) {
mtklein703dd2e2015-01-09 06:41:48 -0800437 INHERITED::init(picture, writePath, mismatchPath, inputFilename,
robertphillips78c71272014-10-09 04:59:19 -0700438 useChecksumBasedFilenames, useMultiPictureDraw);
junov@chromium.org9313ca42012-11-02 18:11:49 +0000439 this->buildBBoxHierarchy();
440}
441
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000442bool SimplePictureRenderer::render(SkBitmap** out) {
halcanary96fcdcc2015-08-27 07:41:13 -0700443 SkASSERT(fCanvas.get() != nullptr);
bsalomon49f085d2014-09-05 13:34:00 -0700444 SkASSERT(fPicture);
halcanary96fcdcc2015-08-27 07:41:13 -0700445 if (nullptr == fCanvas.get() || nullptr == fPicture) {
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000446 return false;
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000447 }
448
robertphillips78c71272014-10-09 04:59:19 -0700449 if (fUseMultiPictureDraw) {
450 SkMultiPictureDraw mpd;
451
452 mpd.add(fCanvas, fPicture);
453
454 mpd.draw();
455 } else {
456 fCanvas->drawPicture(fPicture);
457 }
scroggo@google.com9a412522012-09-07 15:21:18 +0000458 fCanvas->flush();
bsalomon49f085d2014-09-05 13:34:00 -0700459 if (out) {
halcanary385fe4d2015-08-26 13:07:48 -0700460 *out = new SkBitmap;
mtklein703dd2e2015-01-09 06:41:48 -0800461 setup_bitmap(*out, SkScalarCeilToInt(fPicture->cullRect().width()),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700462 SkScalarCeilToInt(fPicture->cullRect().height()));
edisonn@google.com84f548c2012-12-18 22:24:03 +0000463 fCanvas->readPixels(*out, 0, 0);
464 }
commit-bot@chromium.org8991c672014-05-22 00:36:05 +0000465 if (fEnableWrites) {
466 return write(fCanvas, fWritePath, fMismatchPath, fInputFilename, fJsonSummaryPtr,
467 fUseChecksumBasedFilenames);
468 } else {
469 return true;
470 }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000471}
472
scroggo@google.com0a049b82012-11-02 22:01:26 +0000473SkString SimplePictureRenderer::getConfigNameInternal() {
474 return SkString("simple");
475}
476
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000477///////////////////////////////////////////////////////////////////////////////////////////////
478
krajcevskib1aded82014-08-18 07:52:17 -0700479#if SK_SUPPORT_GPU
bsalomon682c2692015-05-22 14:01:46 -0700480TiledPictureRenderer::TiledPictureRenderer(const GrContextOptions& opts)
mtklein2a65a232014-08-26 14:07:04 -0700481 : INHERITED(opts)
krajcevskib1aded82014-08-18 07:52:17 -0700482 , fTileWidth(kDefaultTileWidth)
483#else
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000484TiledPictureRenderer::TiledPictureRenderer()
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000485 : fTileWidth(kDefaultTileWidth)
krajcevskib1aded82014-08-18 07:52:17 -0700486#endif
rileya@google.comb947b912012-08-29 17:35:07 +0000487 , fTileHeight(kDefaultTileHeight)
rileya@google.coma04dc022012-09-10 19:01:38 +0000488 , fTileWidthPercentage(0.0)
rileya@google.comb947b912012-08-29 17:35:07 +0000489 , fTileHeightPercentage(0.0)
scroggo@google.comcbcef702012-12-13 22:09:28 +0000490 , fTileMinPowerOf2Width(0)
491 , fCurrentTileOffset(-1)
492 , fTilesX(0)
493 , fTilesY(0) { }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000494
robertphillipsce4dd3d2014-07-07 13:46:35 -0700495void TiledPictureRenderer::init(const SkPicture* pict, const SkString* writePath,
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000496 const SkString* mismatchPath, const SkString* inputFilename,
robertphillips78c71272014-10-09 04:59:19 -0700497 bool useChecksumBasedFilenames, bool useMultiPictureDraw) {
bsalomon49f085d2014-09-05 13:34:00 -0700498 SkASSERT(pict);
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000499 SkASSERT(0 == fTileRects.count());
halcanary96fcdcc2015-08-27 07:41:13 -0700500 if (nullptr == pict || fTileRects.count() != 0) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000501 return;
502 }
503
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000504 // Do not call INHERITED::init(), which would create a (potentially large) canvas which is not
505 // used by bench_pictures.
bungeman77a53de2015-10-01 12:28:49 -0700506 fPicture.reset(SkRef(pict));
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000507 this->CopyString(&fWritePath, writePath);
508 this->CopyString(&fMismatchPath, mismatchPath);
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000509 this->CopyString(&fInputFilename, inputFilename);
510 fUseChecksumBasedFilenames = useChecksumBasedFilenames;
robertphillips78c71272014-10-09 04:59:19 -0700511 fUseMultiPictureDraw = useMultiPictureDraw;
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000512 this->buildBBoxHierarchy();
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000513
514 if (fTileWidthPercentage > 0) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700515 fTileWidth = SkScalarCeilToInt(float(fTileWidthPercentage * fPicture->cullRect().width() / 100));
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000516 }
517 if (fTileHeightPercentage > 0) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700518 fTileHeight = SkScalarCeilToInt(float(fTileHeightPercentage * fPicture->cullRect().height() / 100));
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000519 }
520
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000521 if (fTileMinPowerOf2Width > 0) {
522 this->setupPowerOf2Tiles();
523 } else {
524 this->setupTiles();
525 }
scroggo@google.comcbcef702012-12-13 22:09:28 +0000526 fCanvas.reset(this->setupCanvas(fTileWidth, fTileHeight));
527 // Initialize to -1 so that the first call to nextTile will set this up to draw tile 0 on the
528 // first call to drawCurrentTile.
529 fCurrentTileOffset = -1;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000530}
531
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000532void TiledPictureRenderer::end() {
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000533 fTileRects.reset();
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000534 this->INHERITED::end();
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000535}
536
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000537void TiledPictureRenderer::setupTiles() {
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000538 // Only use enough tiles to cover the viewport
539 const int width = this->getViewWidth();
540 const int height = this->getViewHeight();
541
scroggo@google.comcbcef702012-12-13 22:09:28 +0000542 fTilesX = fTilesY = 0;
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000543 for (int tile_y_start = 0; tile_y_start < height; tile_y_start += fTileHeight) {
scroggo@google.comcbcef702012-12-13 22:09:28 +0000544 fTilesY++;
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000545 for (int tile_x_start = 0; tile_x_start < width; tile_x_start += fTileWidth) {
scroggo@google.comcbcef702012-12-13 22:09:28 +0000546 if (0 == tile_y_start) {
547 // Only count tiles in the X direction on the first pass.
548 fTilesX++;
549 }
robertphillips78c71272014-10-09 04:59:19 -0700550 *fTileRects.append() = SkIRect::MakeXYWH(tile_x_start, tile_y_start,
551 fTileWidth, fTileHeight);
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000552 }
553 }
554}
555
scroggo@google.comcbcef702012-12-13 22:09:28 +0000556bool TiledPictureRenderer::tileDimensions(int &x, int &y) {
halcanary96fcdcc2015-08-27 07:41:13 -0700557 if (fTileRects.count() == 0 || nullptr == fPicture) {
scroggo@google.comcbcef702012-12-13 22:09:28 +0000558 return false;
559 }
560 x = fTilesX;
561 y = fTilesY;
562 return true;
563}
564
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000565// The goal of the powers of two tiles is to minimize the amount of wasted tile
566// space in the width-wise direction and then minimize the number of tiles. The
567// constraints are that every tile must have a pixel width that is a power of
568// two and also be of some minimal width (that is also a power of two).
569//
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000570// This is solved by first taking our picture size and rounding it up to the
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000571// multiple of the minimal width. The binary representation of this rounded
572// value gives us the tiles we need: a bit of value one means we need a tile of
573// that size.
574void TiledPictureRenderer::setupPowerOf2Tiles() {
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000575 // Only use enough tiles to cover the viewport
576 const int width = this->getViewWidth();
577 const int height = this->getViewHeight();
578
579 int rounded_value = width;
580 if (width % fTileMinPowerOf2Width != 0) {
581 rounded_value = width - (width % fTileMinPowerOf2Width) + fTileMinPowerOf2Width;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000582 }
583
reed@google.come15b2f52013-12-18 04:59:26 +0000584 int num_bits = SkScalarCeilToInt(scalar_log2(SkIntToScalar(width)));
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000585 int largest_possible_tile_size = 1 << num_bits;
586
scroggo@google.comcbcef702012-12-13 22:09:28 +0000587 fTilesX = fTilesY = 0;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000588 // The tile height is constant for a particular picture.
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000589 for (int tile_y_start = 0; tile_y_start < height; tile_y_start += fTileHeight) {
scroggo@google.comcbcef702012-12-13 22:09:28 +0000590 fTilesY++;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000591 int tile_x_start = 0;
592 int current_width = largest_possible_tile_size;
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000593 // Set fTileWidth to be the width of the widest tile, so that each canvas is large enough
594 // to draw each tile.
595 fTileWidth = current_width;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000596
597 while (current_width >= fTileMinPowerOf2Width) {
598 // It is very important this is a bitwise AND.
599 if (current_width & rounded_value) {
scroggo@google.comcbcef702012-12-13 22:09:28 +0000600 if (0 == tile_y_start) {
601 // Only count tiles in the X direction on the first pass.
602 fTilesX++;
603 }
robertphillips78c71272014-10-09 04:59:19 -0700604 *fTileRects.append() = SkIRect::MakeXYWH(tile_x_start, tile_y_start,
605 current_width, fTileHeight);
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000606 tile_x_start += current_width;
607 }
608
609 current_width >>= 1;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000610 }
611 }
612}
613
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000614/**
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +0000615 * Draw the specified picture to the canvas translated to rectangle provided, so that this mini
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000616 * canvas represents the rectangle's portion of the overall picture.
617 * Saves and restores so that the initial clip and matrix return to their state before this function
618 * is called.
619 */
mtklein2a65a232014-08-26 14:07:04 -0700620static void draw_tile_to_canvas(SkCanvas* canvas,
robertphillips78c71272014-10-09 04:59:19 -0700621 const SkIRect& tileRect,
robertphillipsce4dd3d2014-07-07 13:46:35 -0700622 const SkPicture* picture) {
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000623 int saveCount = canvas->save();
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000624 // Translate so that we draw the correct portion of the picture.
625 // Perform a postTranslate so that the scaleFactor does not interfere with the positioning.
626 SkMatrix mat(canvas->getTotalMatrix());
robertphillips78c71272014-10-09 04:59:19 -0700627 mat.postTranslate(-SkIntToScalar(tileRect.fLeft), -SkIntToScalar(tileRect.fTop));
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000628 canvas->setMatrix(mat);
robertphillips43044dd2014-11-28 07:42:16 -0800629 canvas->clipRect(SkRect::Make(tileRect));
robertphillips4a36d9a2014-10-20 08:45:57 -0700630 canvas->clear(SK_ColorTRANSPARENT); // Not every picture covers the entirety of every tile
robertphillips9b14f262014-06-04 05:40:44 -0700631 canvas->drawPicture(picture);
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000632 canvas->restoreToCount(saveCount);
633 canvas->flush();
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000634}
635
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000636///////////////////////////////////////////////////////////////////////////////////////////////
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000637
commit-bot@chromium.orga3f882c2013-12-13 20:52:36 +0000638/**
639 * Copies the entirety of the src bitmap (typically a tile) into a portion of the dst bitmap.
640 * If the src bitmap is too large to fit within the dst bitmap after the x and y
641 * offsets have been applied, any excess will be ignored (so only the top-left portion of the
642 * src bitmap will be copied).
643 *
644 * @param src source bitmap
645 * @param dst destination bitmap
646 * @param xOffset x-offset within destination bitmap
647 * @param yOffset y-offset within destination bitmap
648 */
649static void bitmapCopyAtOffset(const SkBitmap& src, SkBitmap* dst,
650 int xOffset, int yOffset) {
651 for (int y = 0; y <src.height() && y + yOffset < dst->height() ; y++) {
652 for (int x = 0; x < src.width() && x + xOffset < dst->width() ; x++) {
653 *dst->getAddr32(xOffset + x, yOffset + y) = *src.getAddr32(x, y);
edisonn@google.com84f548c2012-12-18 22:24:03 +0000654 }
655 }
656}
657
scroggo@google.comcbcef702012-12-13 22:09:28 +0000658bool TiledPictureRenderer::nextTile(int &i, int &j) {
659 if (++fCurrentTileOffset < fTileRects.count()) {
660 i = fCurrentTileOffset % fTilesX;
661 j = fCurrentTileOffset / fTilesX;
662 return true;
663 }
664 return false;
665}
666
667void TiledPictureRenderer::drawCurrentTile() {
668 SkASSERT(fCurrentTileOffset >= 0 && fCurrentTileOffset < fTileRects.count());
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +0000669 draw_tile_to_canvas(fCanvas, fTileRects[fCurrentTileOffset], fPicture);
scroggo@google.comcbcef702012-12-13 22:09:28 +0000670}
671
mtklein703dd2e2015-01-09 06:41:48 -0800672bool TiledPictureRenderer::postRender(SkCanvas* canvas, const SkIRect& tileRect,
robertphillips78c71272014-10-09 04:59:19 -0700673 SkBitmap* tempBM, SkBitmap** out,
674 int tileNumber) {
675 bool success = true;
676
677 if (fEnableWrites) {
678 success &= write(canvas, fWritePath, fMismatchPath, fInputFilename, fJsonSummaryPtr,
679 fUseChecksumBasedFilenames, &tileNumber);
680 }
681 if (out) {
682 if (canvas->readPixels(tempBM, 0, 0)) {
683 // Add this tile to the entire bitmap.
684 bitmapCopyAtOffset(*tempBM, *out, tileRect.left(), tileRect.top());
685 } else {
686 success = false;
687 }
688 }
689
690 return success;
691}
692
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000693bool TiledPictureRenderer::render(SkBitmap** out) {
halcanary96fcdcc2015-08-27 07:41:13 -0700694 SkASSERT(fPicture != nullptr);
695 if (nullptr == fPicture) {
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000696 return false;
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000697 }
698
edisonn@google.com84f548c2012-12-18 22:24:03 +0000699 SkBitmap bitmap;
robertphillips78c71272014-10-09 04:59:19 -0700700 if (out) {
halcanary385fe4d2015-08-26 13:07:48 -0700701 *out = new SkBitmap;
mtklein703dd2e2015-01-09 06:41:48 -0800702 setup_bitmap(*out, SkScalarCeilToInt(fPicture->cullRect().width()),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700703 SkScalarCeilToInt(fPicture->cullRect().height()));
edisonn@google.com84f548c2012-12-18 22:24:03 +0000704 setup_bitmap(&bitmap, fTileWidth, fTileHeight);
705 }
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000706 bool success = true;
robertphillips78c71272014-10-09 04:59:19 -0700707
708 if (fUseMultiPictureDraw) {
709 SkMultiPictureDraw mpd;
710 SkTDArray<SkSurface*> surfaces;
711 surfaces.setReserve(fTileRects.count());
712
713 // Create a separate SkSurface/SkCanvas for each tile along with a
714 // translated version of the skp (to mimic Chrome's behavior) and
715 // feed all such pairs to the MultiPictureDraw.
716 for (int i = 0; i < fTileRects.count(); ++i) {
717 SkImageInfo ii = fCanvas->imageInfo().makeWH(fTileRects[i].width(),
718 fTileRects[i].height());
719 *surfaces.append() = fCanvas->newSurface(ii);
720 surfaces[i]->getCanvas()->setMatrix(fCanvas->getTotalMatrix());
721
722 SkPictureRecorder recorder;
robertphillips81f71b62014-11-11 04:54:49 -0800723 SkRTreeFactory bbhFactory;
724
robertphillips78c71272014-10-09 04:59:19 -0700725 SkCanvas* c = recorder.beginRecording(SkIntToScalar(fTileRects[i].width()),
robertphillips81f71b62014-11-11 04:54:49 -0800726 SkIntToScalar(fTileRects[i].height()),
727 &bbhFactory,
728 SkPictureRecorder::kComputeSaveLayerInfo_RecordFlag);
robertphillips78c71272014-10-09 04:59:19 -0700729 c->save();
730 SkMatrix mat;
731 mat.setTranslate(-SkIntToScalar(fTileRects[i].fLeft),
732 -SkIntToScalar(fTileRects[i].fTop));
733 c->setMatrix(mat);
734 c->drawPicture(fPicture);
735 c->restore();
736
737 SkAutoTUnref<SkPicture> xlatedPicture(recorder.endRecording());
738
739 mpd.add(surfaces[i]->getCanvas(), xlatedPicture);
commit-bot@chromium.org8991c672014-05-22 00:36:05 +0000740 }
robertphillips78c71272014-10-09 04:59:19 -0700741
742 // Render all the buffered SkCanvases/SkPictures
743 mpd.draw();
744
745 // Sort out the results and cleanup the allocated surfaces
746 for (int i = 0; i < fTileRects.count(); ++i) {
747 success &= this->postRender(surfaces[i]->getCanvas(), fTileRects[i], &bitmap, out, i);
748 surfaces[i]->unref();
749 }
750 } else {
751 for (int i = 0; i < fTileRects.count(); ++i) {
752 draw_tile_to_canvas(fCanvas, fTileRects[i], fPicture);
753 success &= this->postRender(fCanvas, fTileRects[i], &bitmap, out, i);
edisonn@google.com84f548c2012-12-18 22:24:03 +0000754 }
keyar@chromium.org163b5672012-08-01 17:53:29 +0000755 }
robertphillips78c71272014-10-09 04:59:19 -0700756
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000757 return success;
keyar@chromium.org163b5672012-08-01 17:53:29 +0000758}
759
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000760SkCanvas* TiledPictureRenderer::setupCanvas(int width, int height) {
761 SkCanvas* canvas = this->INHERITED::setupCanvas(width, height);
bsalomon49f085d2014-09-05 13:34:00 -0700762 SkASSERT(fPicture);
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000763 // Clip the tile to an area that is completely inside both the SkPicture and the viewport. This
764 // is mostly important for tiles on the right and bottom edges as they may go over this area and
765 // the picture may have some commands that draw outside of this area and so should not actually
766 // be written.
767 // Uses a clipRegion so that it will be unaffected by the scale factor, which may have been set
768 // by INHERITED::setupCanvas.
769 SkRegion clipRegion;
770 clipRegion.setRect(0, 0, this->getViewWidth(), this->getViewHeight());
771 canvas->clipRegion(clipRegion);
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000772 return canvas;
773}
scroggo@google.com0a049b82012-11-02 22:01:26 +0000774
775SkString TiledPictureRenderer::getConfigNameInternal() {
776 SkString name;
777 if (fTileMinPowerOf2Width > 0) {
778 name.append("pow2tile_");
779 name.appendf("%i", fTileMinPowerOf2Width);
780 } else {
781 name.append("tile_");
782 if (fTileWidthPercentage > 0) {
783 name.appendf("%.f%%", fTileWidthPercentage);
784 } else {
785 name.appendf("%i", fTileWidth);
786 }
787 }
788 name.append("x");
789 if (fTileHeightPercentage > 0) {
790 name.appendf("%.f%%", fTileHeightPercentage);
791 } else {
792 name.appendf("%i", fTileHeight);
793 }
794 return name;
795}
796
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000797///////////////////////////////////////////////////////////////////////////////////////////////
798
scroggo@google.com9a412522012-09-07 15:21:18 +0000799void PlaybackCreationRenderer::setup() {
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000800 SkAutoTDelete<SkBBHFactory> factory(this->getFactory());
halcanary385fe4d2015-08-26 13:07:48 -0700801 fRecorder.reset(new SkPictureRecorder);
mtklein703dd2e2015-01-09 06:41:48 -0800802 SkCanvas* canvas = fRecorder->beginRecording(SkIntToScalar(this->getViewWidth()),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700803 SkIntToScalar(this->getViewHeight()),
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000804 factory.get(),
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000805 this->recordFlags());
806 this->scaleToScaleFactor(canvas);
robertphillips9b14f262014-06-04 05:40:44 -0700807 canvas->drawPicture(fPicture);
scroggo@google.com9a412522012-09-07 15:21:18 +0000808}
809
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000810bool PlaybackCreationRenderer::render(SkBitmap** out) {
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000811 fPicture.reset(fRecorder->endRecording());
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000812 // Since this class does not actually render, return false.
813 return false;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000814}
815
scroggo@google.com0a049b82012-11-02 22:01:26 +0000816SkString PlaybackCreationRenderer::getConfigNameInternal() {
817 return SkString("playback_creation");
818}
819
junov@chromium.org9313ca42012-11-02 18:11:49 +0000820///////////////////////////////////////////////////////////////////////////////////////////////
821// SkPicture variants for each BBoxHierarchy type
822
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000823SkBBHFactory* PictureRenderer::getFactory() {
junov@chromium.org9313ca42012-11-02 18:11:49 +0000824 switch (fBBoxHierarchyType) {
825 case kNone_BBoxHierarchyType:
halcanary96fcdcc2015-08-27 07:41:13 -0700826 return nullptr;
junov@chromium.org9313ca42012-11-02 18:11:49 +0000827 case kRTree_BBoxHierarchyType:
halcanary385fe4d2015-08-26 13:07:48 -0700828 return new SkRTreeFactory;
junov@chromium.org9313ca42012-11-02 18:11:49 +0000829 }
830 SkASSERT(0); // invalid bbhType
halcanary96fcdcc2015-08-27 07:41:13 -0700831 return nullptr;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000832}
junov@chromium.org9313ca42012-11-02 18:11:49 +0000833
834} // namespace sk_tools