blob: 123cc2c5cccee9bc08a2d3486abbdd14f573a13b [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"
keyar@chromium.org4ea96c52012-08-20 15:03:29 +000040
reed@google.come15b2f52013-12-18 04:59:26 +000041static inline SkScalar scalar_log2(SkScalar x) {
42 static const SkScalar log2_conversion_factor = SkScalarDiv(1, SkScalarLog(2));
skia.committer@gmail.com3b85deb2013-12-18 07:01:56 +000043
reed@google.come15b2f52013-12-18 04:59:26 +000044 return SkScalarLog(x) * log2_conversion_factor;
45}
46
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000047namespace sk_tools {
48
49enum {
50 kDefaultTileWidth = 256,
51 kDefaultTileHeight = 256
52};
53
mtklein2a65a232014-08-26 14:07:04 -070054void PictureRenderer::init(const SkPicture* pict,
55 const SkString* writePath,
robertphillipsce4dd3d2014-07-07 13:46:35 -070056 const SkString* mismatchPath,
mtklein2a65a232014-08-26 14:07:04 -070057 const SkString* inputFilename,
robertphillips78c71272014-10-09 04:59:19 -070058 bool useChecksumBasedFilenames,
59 bool useMultiPictureDraw) {
commit-bot@chromium.org3f045172014-05-15 15:10:48 +000060 this->CopyString(&fWritePath, writePath);
61 this->CopyString(&fMismatchPath, mismatchPath);
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +000062 this->CopyString(&fInputFilename, inputFilename);
63 fUseChecksumBasedFilenames = useChecksumBasedFilenames;
robertphillips78c71272014-10-09 04:59:19 -070064 fUseMultiPictureDraw = useMultiPictureDraw;
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +000065
keyar@chromium.org78a35c52012-08-20 15:03:44 +000066 SkASSERT(NULL == fPicture);
67 SkASSERT(NULL == fCanvas.get());
bsalomon49f085d2014-09-05 13:34:00 -070068 if (fPicture || fCanvas.get()) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +000069 return;
70 }
71
72 SkASSERT(pict != NULL);
keyar@chromium.org78a35c52012-08-20 15:03:44 +000073 if (NULL == pict) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +000074 return;
75 }
76
robertphillips@google.com84b18c72014-04-13 19:09:42 +000077 fPicture.reset(pict)->ref();
keyar@chromium.orga474ce32012-08-20 15:03:57 +000078 fCanvas.reset(this->setupCanvas());
79}
80
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +000081void PictureRenderer::CopyString(SkString* dest, const SkString* src) {
bsalomon49f085d2014-09-05 13:34:00 -070082 if (src) {
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +000083 dest->set(*src);
84 } else {
85 dest->reset();
86 }
87}
88
caryclark@google.coma3622372012-11-06 21:26:13 +000089class FlagsDrawFilter : public SkDrawFilter {
90public:
91 FlagsDrawFilter(PictureRenderer::DrawFilterFlags* flags) :
92 fFlags(flags) {}
93
reed@google.com971aca72012-11-26 20:26:54 +000094 virtual bool filter(SkPaint* paint, Type t) {
caryclark@google.coma3622372012-11-06 21:26:13 +000095 paint->setFlags(paint->getFlags() & ~fFlags[t] & SkPaint::kAllFlags);
robertphillips@google.com49149312013-07-03 15:34:35 +000096 if (PictureRenderer::kMaskFilter_DrawFilterFlag & fFlags[t]) {
caryclark@google.coma3622372012-11-06 21:26:13 +000097 SkMaskFilter* maskFilter = paint->getMaskFilter();
bsalomon49f085d2014-09-05 13:34:00 -070098 if (maskFilter) {
reed@google.com457d8a72012-12-18 18:20:44 +000099 paint->setMaskFilter(NULL);
caryclark@google.coma3622372012-11-06 21:26:13 +0000100 }
101 }
102 if (PictureRenderer::kHinting_DrawFilterFlag & fFlags[t]) {
103 paint->setHinting(SkPaint::kNo_Hinting);
104 } else if (PictureRenderer::kSlightHinting_DrawFilterFlag & fFlags[t]) {
105 paint->setHinting(SkPaint::kSlight_Hinting);
106 }
reed@google.com971aca72012-11-26 20:26:54 +0000107 return true;
caryclark@google.coma3622372012-11-06 21:26:13 +0000108 }
109
110private:
111 PictureRenderer::DrawFilterFlags* fFlags;
112};
113
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000114static void setUpFilter(SkCanvas* canvas, PictureRenderer::DrawFilterFlags* drawFilters) {
caryclark@google.coma3622372012-11-06 21:26:13 +0000115 if (drawFilters && !canvas->getDrawFilter()) {
116 canvas->setDrawFilter(SkNEW_ARGS(FlagsDrawFilter, (drawFilters)))->unref();
caryclark@google.come3e940c2012-11-07 16:42:17 +0000117 if (drawFilters[0] & PictureRenderer::kAAClip_DrawFilterFlag) {
118 canvas->setAllowSoftClip(false);
119 }
caryclark@google.coma3622372012-11-06 21:26:13 +0000120 }
caryclark@google.coma3622372012-11-06 21:26:13 +0000121}
122
keyar@chromium.orga474ce32012-08-20 15:03:57 +0000123SkCanvas* PictureRenderer::setupCanvas() {
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000124 const int width = this->getViewWidth();
125 const int height = this->getViewHeight();
126 return this->setupCanvas(width, height);
keyar@chromium.orga474ce32012-08-20 15:03:57 +0000127}
128
129SkCanvas* PictureRenderer::setupCanvas(int width, int height) {
caryclark@google.coma3622372012-11-06 21:26:13 +0000130 SkCanvas* canvas;
keyar@chromium.org4ea96c52012-08-20 15:03:29 +0000131 switch(fDeviceType) {
132 case kBitmap_DeviceType: {
133 SkBitmap bitmap;
keyar@chromium.orga474ce32012-08-20 15:03:57 +0000134 sk_tools::setup_bitmap(&bitmap, width, height);
caryclark@google.coma3622372012-11-06 21:26:13 +0000135 canvas = SkNEW_ARGS(SkCanvas, (bitmap));
keyar@chromium.org4ea96c52012-08-20 15:03:29 +0000136 }
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000137 break;
keyar@chromium.org4ea96c52012-08-20 15:03:29 +0000138#if SK_SUPPORT_GPU
scroggo@google.com0556ea02013-02-08 19:38:21 +0000139#if SK_ANGLE
140 case kAngle_DeviceType:
141 // fall through
142#endif
rmistry@google.com6ab96732014-01-06 18:37:24 +0000143#if SK_MESA
144 case kMesa_DeviceType:
145 // fall through
146#endif
commit-bot@chromium.org0fd52702014-03-07 18:41:14 +0000147 case kGPU_DeviceType:
148 case kNVPR_DeviceType: {
commit-bot@chromium.orgae403b92013-04-10 17:27:30 +0000149 SkAutoTUnref<GrSurface> target;
scroggo@google.com0556ea02013-02-08 19:38:21 +0000150 if (fGrContext) {
151 // create a render target to back the device
bsalomonf2703d82014-10-28 14:33:06 -0700152 GrSurfaceDesc desc;
scroggo@google.com0556ea02013-02-08 19:38:21 +0000153 desc.fConfig = kSkia8888_GrPixelConfig;
bsalomonf2703d82014-10-28 14:33:06 -0700154 desc.fFlags = kRenderTarget_GrSurfaceFlag;
scroggo@google.com0556ea02013-02-08 19:38:21 +0000155 desc.fWidth = width;
156 desc.fHeight = height;
jvanverth@google.comf6a90332013-05-02 12:39:37 +0000157 desc.fSampleCnt = fSampleCount;
commit-bot@chromium.orgae403b92013-04-10 17:27:30 +0000158 target.reset(fGrContext->createUncachedTexture(desc, NULL, 0));
scroggo@google.com0556ea02013-02-08 19:38:21 +0000159 }
commit-bot@chromium.orgae403b92013-04-10 17:27:30 +0000160 if (NULL == target.get()) {
scroggo@google.com0556ea02013-02-08 19:38:21 +0000161 SkASSERT(0);
162 return NULL;
163 }
164
jvanverth4736e142014-11-07 07:12:46 -0800165 uint32_t flags = fUseDFText ? SkGpuDevice::kDFText_Flag : 0;
reed4a8126e2014-09-22 07:29:03 -0700166 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(target,
jvanverth4736e142014-11-07 07:12:46 -0800167 SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType),
168 flags));
caryclark@google.coma3622372012-11-06 21:26:13 +0000169 canvas = SkNEW_ARGS(SkCanvas, (device.get()));
scroggo@google.com0556ea02013-02-08 19:38:21 +0000170 break;
keyar@chromium.org4ea96c52012-08-20 15:03:29 +0000171 }
172#endif
173 default:
174 SkASSERT(0);
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000175 return NULL;
keyar@chromium.org4ea96c52012-08-20 15:03:29 +0000176 }
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000177 setUpFilter(canvas, fDrawFilters);
178 this->scaleToScaleFactor(canvas);
commit-bot@chromium.org17cc3ea2014-01-15 14:51:25 +0000179
180 // Pictures often lie about their extent (i.e., claim to be 100x100 but
181 // only ever draw to 90x100). Clear here so the undrawn portion will have
182 // a consistent color
183 canvas->clear(SK_ColorTRANSPARENT);
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000184 return canvas;
185}
keyar@chromium.orga474ce32012-08-20 15:03:57 +0000186
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000187void PictureRenderer::scaleToScaleFactor(SkCanvas* canvas) {
188 SkASSERT(canvas != NULL);
189 if (fScaleFactor != SK_Scalar1) {
190 canvas->scale(fScaleFactor, fScaleFactor);
191 }
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000192}
193
194void PictureRenderer::end() {
scroggo@google.com08085f82013-01-28 20:40:24 +0000195 this->resetState(true);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000196 fPicture.reset(NULL);
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000197 fCanvas.reset(NULL);
198}
199
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000200int PictureRenderer::getViewWidth() {
201 SkASSERT(fPicture != NULL);
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700202 int width = SkScalarCeilToInt(fPicture->cullRect().width() * fScaleFactor);
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000203 if (fViewport.width() > 0) {
204 width = SkMin32(width, fViewport.width());
205 }
206 return width;
207}
208
209int PictureRenderer::getViewHeight() {
210 SkASSERT(fPicture != NULL);
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700211 int height = SkScalarCeilToInt(fPicture->cullRect().height() * fScaleFactor);
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000212 if (fViewport.height() > 0) {
213 height = SkMin32(height, fViewport.height());
214 }
215 return height;
216}
217
junov@chromium.org9313ca42012-11-02 18:11:49 +0000218/** Converts fPicture to a picture that uses a BBoxHierarchy.
219 * PictureRenderer subclasses that are used to test picture playback
220 * should call this method during init.
221 */
222void PictureRenderer::buildBBoxHierarchy() {
bsalomon49f085d2014-09-05 13:34:00 -0700223 SkASSERT(fPicture);
224 if (kNone_BBoxHierarchyType != fBBoxHierarchyType && fPicture) {
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000225 SkAutoTDelete<SkBBHFactory> factory(this->getFactory());
226 SkPictureRecorder recorder;
robertphillips81f71b62014-11-11 04:54:49 -0800227 uint32_t flags = this->recordFlags();
228 if (fUseMultiPictureDraw) {
229 flags |= SkPictureRecorder::kComputeSaveLayerInfo_RecordFlag;
230 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700231 SkCanvas* canvas = recorder.beginRecording(fPicture->cullRect().width(),
232 fPicture->cullRect().height(),
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000233 factory.get(),
robertphillips81f71b62014-11-11 04:54:49 -0800234 flags);
robertphillipsc5ba71d2014-09-04 08:42:50 -0700235 fPicture->playback(canvas);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000236 fPicture.reset(recorder.endRecording());
junov@chromium.org9313ca42012-11-02 18:11:49 +0000237 }
238}
239
scroggo@google.com08085f82013-01-28 20:40:24 +0000240void PictureRenderer::resetState(bool callFinish) {
keyar@chromium.org28136b32012-08-20 15:04:15 +0000241#if SK_SUPPORT_GPU
kkinnunen9e61bb72014-10-09 05:24:15 -0700242 SkGLContext* glContext = this->getGLContext();
scroggo@google.com0556ea02013-02-08 19:38:21 +0000243 if (NULL == glContext) {
244 SkASSERT(kBitmap_DeviceType == fDeviceType);
245 return;
246 }
keyar@chromium.org28136b32012-08-20 15:04:15 +0000247
scroggo@google.com0556ea02013-02-08 19:38:21 +0000248 fGrContext->flush();
commit-bot@chromium.org51c040e2014-03-11 22:58:00 +0000249 glContext->swapBuffers();
scroggo@google.com0556ea02013-02-08 19:38:21 +0000250 if (callFinish) {
251 SK_GL(*glContext, Finish());
keyar@chromium.org77a55222012-08-20 15:03:47 +0000252 }
keyar@chromium.orga40c20d2012-08-20 15:04:12 +0000253#endif
keyar@chromium.org77a55222012-08-20 15:03:47 +0000254}
255
robertphillips@google.com94d8f1e2013-12-18 17:25:33 +0000256void PictureRenderer::purgeTextures() {
257 SkDiscardableMemoryPool* pool = SkGetGlobalDiscardableMemoryPool();
258
259 pool->dumpPool();
260
261#if SK_SUPPORT_GPU
kkinnunen9e61bb72014-10-09 05:24:15 -0700262 SkGLContext* glContext = this->getGLContext();
robertphillips@google.com94d8f1e2013-12-18 17:25:33 +0000263 if (NULL == glContext) {
264 SkASSERT(kBitmap_DeviceType == fDeviceType);
265 return;
266 }
267
268 // resetState should've already done this
269 fGrContext->flush();
270
271 fGrContext->purgeAllUnlockedResources();
272#endif
273}
274
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000275/**
commit-bot@chromium.org4610a462014-04-29 19:39:22 +0000276 * Write the canvas to an image file and/or JSON summary.
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000277 *
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000278 * @param canvas Must be non-null. Canvas to be written to a file.
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000279 * @param writePath If nonempty, write the binary image to a file within this directory.
280 * @param mismatchPath If nonempty, write the binary image to a file within this directory,
281 * but only if the image does not match expectations.
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000282 * @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 +0000283 * @param jsonSummaryPtr If not null, add image results (checksum) to this summary.
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000284 * @param useChecksumBasedFilenames If true, use checksum-based filenames when writing to disk.
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000285 * @param tileNumberPtr If not null, which tile number this image contains.
commit-bot@chromium.orga3f882c2013-12-13 20:52:36 +0000286 *
commit-bot@chromium.org4610a462014-04-29 19:39:22 +0000287 * @return bool True if the operation completed successfully.
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000288 */
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000289static bool write(SkCanvas* canvas, const SkString& writePath, const SkString& mismatchPath,
290 const SkString& inputFilename, ImageResultsAndExpectations *jsonSummaryPtr,
291 bool useChecksumBasedFilenames, const int* tileNumberPtr=NULL) {
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000292 SkASSERT(canvas != NULL);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000293 if (NULL == canvas) {
keyar@chromium.org9299ede2012-08-21 19:05:08 +0000294 return false;
295 }
296
297 SkBitmap bitmap;
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000298 SkISize size = canvas->getDeviceSize();
commit-bot@chromium.org205ce482014-05-12 15:37:20 +0000299 setup_bitmap(&bitmap, size.width(), size.height());
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000300
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000301 canvas->readPixels(&bitmap, 0, 0);
commit-bot@chromium.org205ce482014-05-12 15:37:20 +0000302 force_all_opaque(bitmap);
303 BitmapAndDigest bitmapAndDigest(bitmap);
keyar@chromium.org9299ede2012-08-21 19:05:08 +0000304
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000305 SkString escapedInputFilename(inputFilename);
306 replace_char(&escapedInputFilename, '.', '_');
307
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000308 // TODO(epoger): what about including the config type within outputFilename? That way,
309 // we could combine results of different config types without conflicting filenames.
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000310 SkString outputFilename;
311 const char *outputSubdirPtr = NULL;
312 if (useChecksumBasedFilenames) {
epoger85b438d2014-08-21 23:21:32 -0700313 ImageDigest *imageDigestPtr = bitmapAndDigest.getImageDigestPtr();
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000314 outputSubdirPtr = escapedInputFilename.c_str();
commit-bot@chromium.org205ce482014-05-12 15:37:20 +0000315 outputFilename.set(imageDigestPtr->getHashType());
316 outputFilename.append("_");
317 outputFilename.appendU64(imageDigestPtr->getHashValue());
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000318 } else {
319 outputFilename.set(escapedInputFilename);
bsalomon49f085d2014-09-05 13:34:00 -0700320 if (tileNumberPtr) {
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000321 outputFilename.append("-tile");
322 outputFilename.appendS32(*tileNumberPtr);
323 }
commit-bot@chromium.orga3f882c2013-12-13 20:52:36 +0000324 }
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000325 outputFilename.append(".png");
commit-bot@chromium.orga3f882c2013-12-13 20:52:36 +0000326
bsalomon49f085d2014-09-05 13:34:00 -0700327 if (jsonSummaryPtr) {
epoger85b438d2014-08-21 23:21:32 -0700328 ImageDigest *imageDigestPtr = bitmapAndDigest.getImageDigestPtr();
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000329 SkString outputRelativePath;
330 if (outputSubdirPtr) {
331 outputRelativePath.set(outputSubdirPtr);
332 outputRelativePath.append("/"); // always use "/", even on Windows
333 outputRelativePath.append(outputFilename);
334 } else {
335 outputRelativePath.set(outputFilename);
336 }
337
338 jsonSummaryPtr->add(inputFilename.c_str(), outputRelativePath.c_str(),
commit-bot@chromium.org205ce482014-05-12 15:37:20 +0000339 *imageDigestPtr, tileNumberPtr);
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000340 if (!mismatchPath.isEmpty() &&
epoger85b438d2014-08-21 23:21:32 -0700341 !jsonSummaryPtr->getExpectation(inputFilename.c_str(),
342 tileNumberPtr).matches(*imageDigestPtr)) {
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000343 if (!write_bitmap_to_disk(bitmap, mismatchPath, outputSubdirPtr, outputFilename)) {
344 return false;
345 }
346 }
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000347 }
348
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000349 if (writePath.isEmpty()) {
commit-bot@chromium.org4610a462014-04-29 19:39:22 +0000350 return true;
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000351 } else {
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000352 return write_bitmap_to_disk(bitmap, writePath, outputSubdirPtr, outputFilename);
commit-bot@chromium.org24c568c2014-04-10 15:39:02 +0000353 }
keyar@chromium.org9299ede2012-08-21 19:05:08 +0000354}
355
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000356///////////////////////////////////////////////////////////////////////////////////////////////
357
djsollen@google.comfd9720c2012-11-06 16:54:40 +0000358SkCanvas* RecordPictureRenderer::setupCanvas(int width, int height) {
359 // defer the canvas setup until the render step
360 return NULL;
361}
362
scroggo895c43b2014-12-11 10:53:58 -0800363// Encodes to PNG, unless there is already encoded data, in which case that gets
364// used.
365// FIXME: Share with PictureTest.cpp?
366
367class PngPixelSerializer : public SkPixelSerializer {
368public:
369 virtual bool onUseEncodedData(const void*, size_t) SK_OVERRIDE { return true; }
370 virtual SkData* onEncodePixels(const SkImageInfo& info, void* pixels,
371 size_t rowBytes) SK_OVERRIDE {
372 SkBitmap bm;
373 if (!bm.installPixels(info, pixels, rowBytes)) {
374 return NULL;
375 }
376 return SkImageEncoder::EncodeData(bm, SkImageEncoder::kPNG_Type, 100);
377 }
378};
scroggo@google.coma9e3a362012-11-07 17:52:48 +0000379
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000380bool RecordPictureRenderer::render(SkBitmap** out) {
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000381 SkAutoTDelete<SkBBHFactory> factory(this->getFactory());
382 SkPictureRecorder recorder;
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700383 SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(this->getViewWidth()),
384 SkIntToScalar(this->getViewHeight()),
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000385 factory.get(),
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000386 this->recordFlags());
387 this->scaleToScaleFactor(canvas);
robertphillipsc5ba71d2014-09-04 08:42:50 -0700388 fPicture->playback(canvas);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000389 SkAutoTUnref<SkPicture> picture(recorder.endRecording());
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000390 if (!fWritePath.isEmpty()) {
scroggo@google.coma9e3a362012-11-07 17:52:48 +0000391 // Record the new picture as a new SKP with PNG encoded bitmaps.
tfarinaa8e2e152014-07-28 19:26:58 -0700392 SkString skpPath = SkOSPath::Join(fWritePath.c_str(), fInputFilename.c_str());
scroggo@google.coma9e3a362012-11-07 17:52:48 +0000393 SkFILEWStream stream(skpPath.c_str());
scroggo895c43b2014-12-11 10:53:58 -0800394 PngPixelSerializer serializer;
395 picture->serialize(&stream, &serializer);
scroggo@google.coma9e3a362012-11-07 17:52:48 +0000396 return true;
397 }
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000398 return false;
scroggo@google.com9a412522012-09-07 15:21:18 +0000399}
400
scroggo@google.com0a049b82012-11-02 22:01:26 +0000401SkString RecordPictureRenderer::getConfigNameInternal() {
402 return SkString("record");
403}
404
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000405///////////////////////////////////////////////////////////////////////////////////////////////
406
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000407bool PipePictureRenderer::render(SkBitmap** out) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000408 SkASSERT(fCanvas.get() != NULL);
409 SkASSERT(fPicture != NULL);
keyar@chromium.org78a35c52012-08-20 15:03:44 +0000410 if (NULL == fCanvas.get() || NULL == fPicture) {
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000411 return false;
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000412 }
413
414 PipeController pipeController(fCanvas.get());
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000415 SkGPipeWriter writer;
416 SkCanvas* pipeCanvas = writer.startRecording(&pipeController);
robertphillips9b14f262014-06-04 05:40:44 -0700417 pipeCanvas->drawPicture(fPicture);
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000418 writer.endRecording();
scroggo@google.com9a412522012-09-07 15:21:18 +0000419 fCanvas->flush();
bsalomon49f085d2014-09-05 13:34:00 -0700420 if (out) {
edisonn@google.com84f548c2012-12-18 22:24:03 +0000421 *out = SkNEW(SkBitmap);
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700422 setup_bitmap(*out, SkScalarCeilToInt(fPicture->cullRect().width()),
423 SkScalarCeilToInt(fPicture->cullRect().height()));
edisonn@google.com84f548c2012-12-18 22:24:03 +0000424 fCanvas->readPixels(*out, 0, 0);
skia.committer@gmail.coma7d8e3e2012-12-19 02:01:38 +0000425 }
commit-bot@chromium.org8991c672014-05-22 00:36:05 +0000426 if (fEnableWrites) {
427 return write(fCanvas, fWritePath, fMismatchPath, fInputFilename, fJsonSummaryPtr,
428 fUseChecksumBasedFilenames);
429 } else {
430 return true;
431 }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000432}
433
scroggo@google.com0a049b82012-11-02 22:01:26 +0000434SkString PipePictureRenderer::getConfigNameInternal() {
435 return SkString("pipe");
436}
437
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000438///////////////////////////////////////////////////////////////////////////////////////////////
439
robertphillipsce4dd3d2014-07-07 13:46:35 -0700440void SimplePictureRenderer::init(const SkPicture* picture, const SkString* writePath,
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000441 const SkString* mismatchPath, const SkString* inputFilename,
robertphillips78c71272014-10-09 04:59:19 -0700442 bool useChecksumBasedFilenames, bool useMultiPictureDraw) {
443 INHERITED::init(picture, writePath, mismatchPath, inputFilename,
444 useChecksumBasedFilenames, useMultiPictureDraw);
junov@chromium.org9313ca42012-11-02 18:11:49 +0000445 this->buildBBoxHierarchy();
446}
447
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000448bool SimplePictureRenderer::render(SkBitmap** out) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000449 SkASSERT(fCanvas.get() != NULL);
bsalomon49f085d2014-09-05 13:34:00 -0700450 SkASSERT(fPicture);
keyar@chromium.org78a35c52012-08-20 15:03:44 +0000451 if (NULL == fCanvas.get() || NULL == fPicture) {
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000452 return false;
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000453 }
454
robertphillips78c71272014-10-09 04:59:19 -0700455 if (fUseMultiPictureDraw) {
456 SkMultiPictureDraw mpd;
457
458 mpd.add(fCanvas, fPicture);
459
460 mpd.draw();
461 } else {
462 fCanvas->drawPicture(fPicture);
463 }
scroggo@google.com9a412522012-09-07 15:21:18 +0000464 fCanvas->flush();
bsalomon49f085d2014-09-05 13:34:00 -0700465 if (out) {
edisonn@google.com84f548c2012-12-18 22:24:03 +0000466 *out = SkNEW(SkBitmap);
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700467 setup_bitmap(*out, SkScalarCeilToInt(fPicture->cullRect().width()),
468 SkScalarCeilToInt(fPicture->cullRect().height()));
edisonn@google.com84f548c2012-12-18 22:24:03 +0000469 fCanvas->readPixels(*out, 0, 0);
470 }
commit-bot@chromium.org8991c672014-05-22 00:36:05 +0000471 if (fEnableWrites) {
472 return write(fCanvas, fWritePath, fMismatchPath, fInputFilename, fJsonSummaryPtr,
473 fUseChecksumBasedFilenames);
474 } else {
475 return true;
476 }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000477}
478
scroggo@google.com0a049b82012-11-02 22:01:26 +0000479SkString SimplePictureRenderer::getConfigNameInternal() {
480 return SkString("simple");
481}
482
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000483///////////////////////////////////////////////////////////////////////////////////////////////
484
krajcevskib1aded82014-08-18 07:52:17 -0700485#if SK_SUPPORT_GPU
486TiledPictureRenderer::TiledPictureRenderer(const GrContext::Options& opts)
mtklein2a65a232014-08-26 14:07:04 -0700487 : INHERITED(opts)
krajcevskib1aded82014-08-18 07:52:17 -0700488 , fTileWidth(kDefaultTileWidth)
489#else
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000490TiledPictureRenderer::TiledPictureRenderer()
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000491 : fTileWidth(kDefaultTileWidth)
krajcevskib1aded82014-08-18 07:52:17 -0700492#endif
rileya@google.comb947b912012-08-29 17:35:07 +0000493 , fTileHeight(kDefaultTileHeight)
rileya@google.coma04dc022012-09-10 19:01:38 +0000494 , fTileWidthPercentage(0.0)
rileya@google.comb947b912012-08-29 17:35:07 +0000495 , fTileHeightPercentage(0.0)
scroggo@google.comcbcef702012-12-13 22:09:28 +0000496 , fTileMinPowerOf2Width(0)
497 , fCurrentTileOffset(-1)
498 , fTilesX(0)
499 , fTilesY(0) { }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000500
robertphillipsce4dd3d2014-07-07 13:46:35 -0700501void TiledPictureRenderer::init(const SkPicture* pict, const SkString* writePath,
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000502 const SkString* mismatchPath, const SkString* inputFilename,
robertphillips78c71272014-10-09 04:59:19 -0700503 bool useChecksumBasedFilenames, bool useMultiPictureDraw) {
bsalomon49f085d2014-09-05 13:34:00 -0700504 SkASSERT(pict);
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000505 SkASSERT(0 == fTileRects.count());
506 if (NULL == pict || fTileRects.count() != 0) {
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000507 return;
508 }
509
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000510 // Do not call INHERITED::init(), which would create a (potentially large) canvas which is not
511 // used by bench_pictures.
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000512 fPicture.reset(pict)->ref();
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000513 this->CopyString(&fWritePath, writePath);
514 this->CopyString(&fMismatchPath, mismatchPath);
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000515 this->CopyString(&fInputFilename, inputFilename);
516 fUseChecksumBasedFilenames = useChecksumBasedFilenames;
robertphillips78c71272014-10-09 04:59:19 -0700517 fUseMultiPictureDraw = useMultiPictureDraw;
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000518 this->buildBBoxHierarchy();
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000519
520 if (fTileWidthPercentage > 0) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700521 fTileWidth = SkScalarCeilToInt(float(fTileWidthPercentage * fPicture->cullRect().width() / 100));
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000522 }
523 if (fTileHeightPercentage > 0) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700524 fTileHeight = SkScalarCeilToInt(float(fTileHeightPercentage * fPicture->cullRect().height() / 100));
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000525 }
526
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000527 if (fTileMinPowerOf2Width > 0) {
528 this->setupPowerOf2Tiles();
529 } else {
530 this->setupTiles();
531 }
scroggo@google.comcbcef702012-12-13 22:09:28 +0000532 fCanvas.reset(this->setupCanvas(fTileWidth, fTileHeight));
533 // Initialize to -1 so that the first call to nextTile will set this up to draw tile 0 on the
534 // first call to drawCurrentTile.
535 fCurrentTileOffset = -1;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000536}
537
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000538void TiledPictureRenderer::end() {
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000539 fTileRects.reset();
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000540 this->INHERITED::end();
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000541}
542
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000543void TiledPictureRenderer::setupTiles() {
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000544 // Only use enough tiles to cover the viewport
545 const int width = this->getViewWidth();
546 const int height = this->getViewHeight();
547
scroggo@google.comcbcef702012-12-13 22:09:28 +0000548 fTilesX = fTilesY = 0;
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000549 for (int tile_y_start = 0; tile_y_start < height; tile_y_start += fTileHeight) {
scroggo@google.comcbcef702012-12-13 22:09:28 +0000550 fTilesY++;
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000551 for (int tile_x_start = 0; tile_x_start < width; tile_x_start += fTileWidth) {
scroggo@google.comcbcef702012-12-13 22:09:28 +0000552 if (0 == tile_y_start) {
553 // Only count tiles in the X direction on the first pass.
554 fTilesX++;
555 }
robertphillips78c71272014-10-09 04:59:19 -0700556 *fTileRects.append() = SkIRect::MakeXYWH(tile_x_start, tile_y_start,
557 fTileWidth, fTileHeight);
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000558 }
559 }
560}
561
scroggo@google.comcbcef702012-12-13 22:09:28 +0000562bool TiledPictureRenderer::tileDimensions(int &x, int &y) {
563 if (fTileRects.count() == 0 || NULL == fPicture) {
564 return false;
565 }
566 x = fTilesX;
567 y = fTilesY;
568 return true;
569}
570
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000571// The goal of the powers of two tiles is to minimize the amount of wasted tile
572// space in the width-wise direction and then minimize the number of tiles. The
573// constraints are that every tile must have a pixel width that is a power of
574// two and also be of some minimal width (that is also a power of two).
575//
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000576// This is solved by first taking our picture size and rounding it up to the
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000577// multiple of the minimal width. The binary representation of this rounded
578// value gives us the tiles we need: a bit of value one means we need a tile of
579// that size.
580void TiledPictureRenderer::setupPowerOf2Tiles() {
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000581 // Only use enough tiles to cover the viewport
582 const int width = this->getViewWidth();
583 const int height = this->getViewHeight();
584
585 int rounded_value = width;
586 if (width % fTileMinPowerOf2Width != 0) {
587 rounded_value = width - (width % fTileMinPowerOf2Width) + fTileMinPowerOf2Width;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000588 }
589
reed@google.come15b2f52013-12-18 04:59:26 +0000590 int num_bits = SkScalarCeilToInt(scalar_log2(SkIntToScalar(width)));
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000591 int largest_possible_tile_size = 1 << num_bits;
592
scroggo@google.comcbcef702012-12-13 22:09:28 +0000593 fTilesX = fTilesY = 0;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000594 // The tile height is constant for a particular picture.
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000595 for (int tile_y_start = 0; tile_y_start < height; tile_y_start += fTileHeight) {
scroggo@google.comcbcef702012-12-13 22:09:28 +0000596 fTilesY++;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000597 int tile_x_start = 0;
598 int current_width = largest_possible_tile_size;
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000599 // Set fTileWidth to be the width of the widest tile, so that each canvas is large enough
600 // to draw each tile.
601 fTileWidth = current_width;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000602
603 while (current_width >= fTileMinPowerOf2Width) {
604 // It is very important this is a bitwise AND.
605 if (current_width & rounded_value) {
scroggo@google.comcbcef702012-12-13 22:09:28 +0000606 if (0 == tile_y_start) {
607 // Only count tiles in the X direction on the first pass.
608 fTilesX++;
609 }
robertphillips78c71272014-10-09 04:59:19 -0700610 *fTileRects.append() = SkIRect::MakeXYWH(tile_x_start, tile_y_start,
611 current_width, fTileHeight);
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000612 tile_x_start += current_width;
613 }
614
615 current_width >>= 1;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000616 }
617 }
618}
619
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000620/**
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +0000621 * Draw the specified picture to the canvas translated to rectangle provided, so that this mini
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000622 * canvas represents the rectangle's portion of the overall picture.
623 * Saves and restores so that the initial clip and matrix return to their state before this function
624 * is called.
625 */
mtklein2a65a232014-08-26 14:07:04 -0700626static void draw_tile_to_canvas(SkCanvas* canvas,
robertphillips78c71272014-10-09 04:59:19 -0700627 const SkIRect& tileRect,
robertphillipsce4dd3d2014-07-07 13:46:35 -0700628 const SkPicture* picture) {
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000629 int saveCount = canvas->save();
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000630 // Translate so that we draw the correct portion of the picture.
631 // Perform a postTranslate so that the scaleFactor does not interfere with the positioning.
632 SkMatrix mat(canvas->getTotalMatrix());
robertphillips78c71272014-10-09 04:59:19 -0700633 mat.postTranslate(-SkIntToScalar(tileRect.fLeft), -SkIntToScalar(tileRect.fTop));
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000634 canvas->setMatrix(mat);
robertphillips43044dd2014-11-28 07:42:16 -0800635 canvas->clipRect(SkRect::Make(tileRect));
robertphillips4a36d9a2014-10-20 08:45:57 -0700636 canvas->clear(SK_ColorTRANSPARENT); // Not every picture covers the entirety of every tile
robertphillips9b14f262014-06-04 05:40:44 -0700637 canvas->drawPicture(picture);
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000638 canvas->restoreToCount(saveCount);
639 canvas->flush();
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000640}
641
scroggo@google.com58b4ead2012-08-31 16:15:22 +0000642///////////////////////////////////////////////////////////////////////////////////////////////
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000643
commit-bot@chromium.orga3f882c2013-12-13 20:52:36 +0000644/**
645 * Copies the entirety of the src bitmap (typically a tile) into a portion of the dst bitmap.
646 * If the src bitmap is too large to fit within the dst bitmap after the x and y
647 * offsets have been applied, any excess will be ignored (so only the top-left portion of the
648 * src bitmap will be copied).
649 *
650 * @param src source bitmap
651 * @param dst destination bitmap
652 * @param xOffset x-offset within destination bitmap
653 * @param yOffset y-offset within destination bitmap
654 */
655static void bitmapCopyAtOffset(const SkBitmap& src, SkBitmap* dst,
656 int xOffset, int yOffset) {
657 for (int y = 0; y <src.height() && y + yOffset < dst->height() ; y++) {
658 for (int x = 0; x < src.width() && x + xOffset < dst->width() ; x++) {
659 *dst->getAddr32(xOffset + x, yOffset + y) = *src.getAddr32(x, y);
edisonn@google.com84f548c2012-12-18 22:24:03 +0000660 }
661 }
662}
663
scroggo@google.comcbcef702012-12-13 22:09:28 +0000664bool TiledPictureRenderer::nextTile(int &i, int &j) {
665 if (++fCurrentTileOffset < fTileRects.count()) {
666 i = fCurrentTileOffset % fTilesX;
667 j = fCurrentTileOffset / fTilesX;
668 return true;
669 }
670 return false;
671}
672
673void TiledPictureRenderer::drawCurrentTile() {
674 SkASSERT(fCurrentTileOffset >= 0 && fCurrentTileOffset < fTileRects.count());
commit-bot@chromium.org145d1c02014-03-16 19:46:36 +0000675 draw_tile_to_canvas(fCanvas, fTileRects[fCurrentTileOffset], fPicture);
scroggo@google.comcbcef702012-12-13 22:09:28 +0000676}
677
robertphillips78c71272014-10-09 04:59:19 -0700678bool TiledPictureRenderer::postRender(SkCanvas* canvas, const SkIRect& tileRect,
679 SkBitmap* tempBM, SkBitmap** out,
680 int tileNumber) {
681 bool success = true;
682
683 if (fEnableWrites) {
684 success &= write(canvas, fWritePath, fMismatchPath, fInputFilename, fJsonSummaryPtr,
685 fUseChecksumBasedFilenames, &tileNumber);
686 }
687 if (out) {
688 if (canvas->readPixels(tempBM, 0, 0)) {
689 // Add this tile to the entire bitmap.
690 bitmapCopyAtOffset(*tempBM, *out, tileRect.left(), tileRect.top());
691 } else {
692 success = false;
693 }
694 }
695
696 return success;
697}
698
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000699bool TiledPictureRenderer::render(SkBitmap** out) {
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000700 SkASSERT(fPicture != NULL);
701 if (NULL == fPicture) {
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000702 return false;
scroggo@google.comacfb30e2012-09-18 14:32:35 +0000703 }
704
edisonn@google.com84f548c2012-12-18 22:24:03 +0000705 SkBitmap bitmap;
robertphillips78c71272014-10-09 04:59:19 -0700706 if (out) {
edisonn@google.com84f548c2012-12-18 22:24:03 +0000707 *out = SkNEW(SkBitmap);
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700708 setup_bitmap(*out, SkScalarCeilToInt(fPicture->cullRect().width()),
709 SkScalarCeilToInt(fPicture->cullRect().height()));
edisonn@google.com84f548c2012-12-18 22:24:03 +0000710 setup_bitmap(&bitmap, fTileWidth, fTileHeight);
711 }
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000712 bool success = true;
robertphillips78c71272014-10-09 04:59:19 -0700713
714 if (fUseMultiPictureDraw) {
715 SkMultiPictureDraw mpd;
716 SkTDArray<SkSurface*> surfaces;
717 surfaces.setReserve(fTileRects.count());
718
719 // Create a separate SkSurface/SkCanvas for each tile along with a
720 // translated version of the skp (to mimic Chrome's behavior) and
721 // feed all such pairs to the MultiPictureDraw.
722 for (int i = 0; i < fTileRects.count(); ++i) {
723 SkImageInfo ii = fCanvas->imageInfo().makeWH(fTileRects[i].width(),
724 fTileRects[i].height());
725 *surfaces.append() = fCanvas->newSurface(ii);
726 surfaces[i]->getCanvas()->setMatrix(fCanvas->getTotalMatrix());
727
728 SkPictureRecorder recorder;
robertphillips81f71b62014-11-11 04:54:49 -0800729 SkRTreeFactory bbhFactory;
730
robertphillips78c71272014-10-09 04:59:19 -0700731 SkCanvas* c = recorder.beginRecording(SkIntToScalar(fTileRects[i].width()),
robertphillips81f71b62014-11-11 04:54:49 -0800732 SkIntToScalar(fTileRects[i].height()),
733 &bbhFactory,
734 SkPictureRecorder::kComputeSaveLayerInfo_RecordFlag);
robertphillips78c71272014-10-09 04:59:19 -0700735 c->save();
736 SkMatrix mat;
737 mat.setTranslate(-SkIntToScalar(fTileRects[i].fLeft),
738 -SkIntToScalar(fTileRects[i].fTop));
739 c->setMatrix(mat);
740 c->drawPicture(fPicture);
741 c->restore();
742
743 SkAutoTUnref<SkPicture> xlatedPicture(recorder.endRecording());
744
745 mpd.add(surfaces[i]->getCanvas(), xlatedPicture);
commit-bot@chromium.org8991c672014-05-22 00:36:05 +0000746 }
robertphillips78c71272014-10-09 04:59:19 -0700747
748 // Render all the buffered SkCanvases/SkPictures
749 mpd.draw();
750
751 // Sort out the results and cleanup the allocated surfaces
752 for (int i = 0; i < fTileRects.count(); ++i) {
753 success &= this->postRender(surfaces[i]->getCanvas(), fTileRects[i], &bitmap, out, i);
754 surfaces[i]->unref();
755 }
756 } else {
757 for (int i = 0; i < fTileRects.count(); ++i) {
758 draw_tile_to_canvas(fCanvas, fTileRects[i], fPicture);
759 success &= this->postRender(fCanvas, fTileRects[i], &bitmap, out, i);
edisonn@google.com84f548c2012-12-18 22:24:03 +0000760 }
keyar@chromium.org163b5672012-08-01 17:53:29 +0000761 }
robertphillips78c71272014-10-09 04:59:19 -0700762
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000763 return success;
keyar@chromium.org163b5672012-08-01 17:53:29 +0000764}
765
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000766SkCanvas* TiledPictureRenderer::setupCanvas(int width, int height) {
767 SkCanvas* canvas = this->INHERITED::setupCanvas(width, height);
bsalomon49f085d2014-09-05 13:34:00 -0700768 SkASSERT(fPicture);
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000769 // Clip the tile to an area that is completely inside both the SkPicture and the viewport. This
770 // is mostly important for tiles on the right and bottom edges as they may go over this area and
771 // the picture may have some commands that draw outside of this area and so should not actually
772 // be written.
773 // Uses a clipRegion so that it will be unaffected by the scale factor, which may have been set
774 // by INHERITED::setupCanvas.
775 SkRegion clipRegion;
776 clipRegion.setRect(0, 0, this->getViewWidth(), this->getViewHeight());
777 canvas->clipRegion(clipRegion);
scroggo@google.combcdf2ec2012-09-20 14:42:33 +0000778 return canvas;
779}
scroggo@google.com0a049b82012-11-02 22:01:26 +0000780
781SkString TiledPictureRenderer::getConfigNameInternal() {
782 SkString name;
783 if (fTileMinPowerOf2Width > 0) {
784 name.append("pow2tile_");
785 name.appendf("%i", fTileMinPowerOf2Width);
786 } else {
787 name.append("tile_");
788 if (fTileWidthPercentage > 0) {
789 name.appendf("%.f%%", fTileWidthPercentage);
790 } else {
791 name.appendf("%i", fTileWidth);
792 }
793 }
794 name.append("x");
795 if (fTileHeightPercentage > 0) {
796 name.appendf("%.f%%", fTileHeightPercentage);
797 } else {
798 name.appendf("%i", fTileHeight);
799 }
800 return name;
801}
802
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000803///////////////////////////////////////////////////////////////////////////////////////////////
804
scroggo@google.com9a412522012-09-07 15:21:18 +0000805void PlaybackCreationRenderer::setup() {
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000806 SkAutoTDelete<SkBBHFactory> factory(this->getFactory());
807 fRecorder.reset(SkNEW(SkPictureRecorder));
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700808 SkCanvas* canvas = fRecorder->beginRecording(SkIntToScalar(this->getViewWidth()),
809 SkIntToScalar(this->getViewHeight()),
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000810 factory.get(),
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000811 this->recordFlags());
812 this->scaleToScaleFactor(canvas);
robertphillips9b14f262014-06-04 05:40:44 -0700813 canvas->drawPicture(fPicture);
scroggo@google.com9a412522012-09-07 15:21:18 +0000814}
815
commit-bot@chromium.orgf5e315c2014-03-19 17:26:07 +0000816bool PlaybackCreationRenderer::render(SkBitmap** out) {
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000817 fPicture.reset(fRecorder->endRecording());
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000818 // Since this class does not actually render, return false.
819 return false;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000820}
821
scroggo@google.com0a049b82012-11-02 22:01:26 +0000822SkString PlaybackCreationRenderer::getConfigNameInternal() {
823 return SkString("playback_creation");
824}
825
junov@chromium.org9313ca42012-11-02 18:11:49 +0000826///////////////////////////////////////////////////////////////////////////////////////////////
827// SkPicture variants for each BBoxHierarchy type
828
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000829SkBBHFactory* PictureRenderer::getFactory() {
junov@chromium.org9313ca42012-11-02 18:11:49 +0000830 switch (fBBoxHierarchyType) {
831 case kNone_BBoxHierarchyType:
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000832 return NULL;
junov@chromium.org9313ca42012-11-02 18:11:49 +0000833 case kRTree_BBoxHierarchyType:
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000834 return SkNEW(SkRTreeFactory);
junov@chromium.org7b537062012-11-06 18:58:43 +0000835 case kTileGrid_BBoxHierarchyType:
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000836 return SkNEW_ARGS(SkTileGridFactory, (fGridInfo));
junov@chromium.org9313ca42012-11-02 18:11:49 +0000837 }
838 SkASSERT(0); // invalid bbhType
839 return NULL;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000840}
junov@chromium.org9313ca42012-11-02 18:11:49 +0000841
reed@google.comfe7b1ed2012-11-29 21:00:39 +0000842///////////////////////////////////////////////////////////////////////////////
843
844class GatherRenderer : public PictureRenderer {
845public:
krajcevskib1aded82014-08-18 07:52:17 -0700846#if SK_SUPPORT_GPU
847 GatherRenderer(const GrContext::Options& opts) : INHERITED(opts) { }
848#endif
849
commit-bot@chromium.org8ddc26b2014-03-31 17:55:12 +0000850 virtual bool render(SkBitmap** out = NULL) SK_OVERRIDE {
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700851 SkRect bounds = SkRect::MakeWH(SkIntToScalar(fPicture->cullRect().width()),
852 SkIntToScalar(fPicture->cullRect().height()));
reed@google.comfe7b1ed2012-11-29 21:00:39 +0000853 SkData* data = SkPictureUtils::GatherPixelRefs(fPicture, bounds);
854 SkSafeUnref(data);
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +0000855
commit-bot@chromium.org3f045172014-05-15 15:10:48 +0000856 return (fWritePath.isEmpty()); // we don't have anything to write
reed@google.comfe7b1ed2012-11-29 21:00:39 +0000857 }
skia.committer@gmail.comc7b4be72012-12-11 02:01:20 +0000858
reed@google.comfe7b1ed2012-11-29 21:00:39 +0000859private:
860 virtual SkString getConfigNameInternal() SK_OVERRIDE {
861 return SkString("gather_pixelrefs");
862 }
krajcevskib1aded82014-08-18 07:52:17 -0700863
864 typedef PictureRenderer INHERITED;
reed@google.comfe7b1ed2012-11-29 21:00:39 +0000865};
866
krajcevskib1aded82014-08-18 07:52:17 -0700867#if SK_SUPPORT_GPU
868PictureRenderer* CreateGatherPixelRefsRenderer(const GrContext::Options& opts) {
869 return SkNEW_ARGS(GatherRenderer, (opts));
870}
871#else
reed@google.comfe7b1ed2012-11-29 21:00:39 +0000872PictureRenderer* CreateGatherPixelRefsRenderer() {
873 return SkNEW(GatherRenderer);
874}
krajcevskib1aded82014-08-18 07:52:17 -0700875#endif
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +0000876
junov@chromium.org9313ca42012-11-02 18:11:49 +0000877} // namespace sk_tools