blob: fa600ff4eb33bc07ba22c6d0eebe46e435085b52 [file] [log] [blame]
scroggo478652e2015-03-25 07:11:02 -07001/*
2 * Copyright 2015 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
mtklein748ca3b2015-01-15 10:56:12 -08008#include "DMSrcSink.h"
9#include "SamplePipeControllers.h"
msarett3d9d7a72015-10-21 10:27:10 -070010#include "SkAndroidCodec.h"
scroggof24f2242015-03-03 08:59:20 -080011#include "SkCodec.h"
mtkleina16e69e2015-05-05 11:38:45 -070012#include "SkCommonFlags.h"
mtkleinb3e5e4d2015-03-25 13:13:43 -070013#include "SkData.h"
mtklein748ca3b2015-01-15 10:56:12 -080014#include "SkDocument.h"
joshualitt5f5a8d72015-02-25 14:09:45 -080015#include "SkError.h"
mtkleinb3e5e4d2015-03-25 13:13:43 -070016#include "SkImageGenerator.h"
mtkleinc8be09a2016-01-04 18:56:57 -080017#include "SkMallocPixelRef.h"
mtklein748ca3b2015-01-15 10:56:12 -080018#include "SkMultiPictureDraw.h"
mtkleinad66f9b2015-02-13 15:11:10 -080019#include "SkNullCanvas.h"
mtklein748ca3b2015-01-15 10:56:12 -080020#include "SkOSFile.h"
mtkleinffa901a2015-03-16 10:38:07 -070021#include "SkPictureData.h"
mtklein748ca3b2015-01-15 10:56:12 -080022#include "SkPictureRecorder.h"
23#include "SkRandom.h"
mtkleind31c13d2015-05-05 12:59:56 -070024#include "SkRecordDraw.h"
25#include "SkRecorder.h"
mtklein2e2ea382015-10-16 10:29:41 -070026#include "SkRemote.h"
fmalita2aafe6f2015-02-06 12:51:10 -080027#include "SkSVGCanvas.h"
scroggoa1193e42015-01-21 12:09:53 -080028#include "SkStream.h"
mtklein449d9b72015-09-28 10:33:02 -070029#include "SkTLogic.h"
fmalita2aafe6f2015-02-06 12:51:10 -080030#include "SkXMLWriter.h"
msarette6dd0042015-10-09 11:07:34 -070031#include "SkSwizzler.h"
mtklein64593522015-11-12 10:41:05 -080032#include <functional>
mtklein748ca3b2015-01-15 10:56:12 -080033
halcanary7e798182015-04-14 14:06:18 -070034DEFINE_bool(multiPage, false, "For document-type backends, render the source"
35 " into multiple pages");
36
mtkleinb3e5e4d2015-03-25 13:13:43 -070037static bool lazy_decode_bitmap(const void* src, size_t size, SkBitmap* dst) {
38 SkAutoTUnref<SkData> encoded(SkData::NewWithCopy(src, size));
reedd1146452015-09-25 06:56:57 -070039 return encoded && SkDEPRECATED_InstallDiscardablePixelRef(encoded, dst);
mtkleinb3e5e4d2015-03-25 13:13:43 -070040}
41
mtklein748ca3b2015-01-15 10:56:12 -080042namespace DM {
43
mtklein748ca3b2015-01-15 10:56:12 -080044GMSrc::GMSrc(skiagm::GMRegistry::Factory factory) : fFactory(factory) {}
45
46Error GMSrc::draw(SkCanvas* canvas) const {
halcanary96fcdcc2015-08-27 07:41:13 -070047 SkAutoTDelete<skiagm::GM> gm(fFactory(nullptr));
mtklein748ca3b2015-01-15 10:56:12 -080048 canvas->concat(gm->getInitialTransform());
49 gm->draw(canvas);
50 return "";
51}
52
53SkISize GMSrc::size() const {
halcanary96fcdcc2015-08-27 07:41:13 -070054 SkAutoTDelete<skiagm::GM> gm(fFactory(nullptr));
mtklein748ca3b2015-01-15 10:56:12 -080055 return gm->getISize();
56}
57
58Name GMSrc::name() const {
halcanary96fcdcc2015-08-27 07:41:13 -070059 SkAutoTDelete<skiagm::GM> gm(fFactory(nullptr));
mtklein748ca3b2015-01-15 10:56:12 -080060 return gm->getName();
61}
62
bsalomon4ee6bd82015-05-27 13:23:23 -070063void GMSrc::modifyGrContextOptions(GrContextOptions* options) const {
halcanary96fcdcc2015-08-27 07:41:13 -070064 SkAutoTDelete<skiagm::GM> gm(fFactory(nullptr));
bsalomon4ee6bd82015-05-27 13:23:23 -070065 gm->modifyGrContextOptions(options);
66}
67
mtklein748ca3b2015-01-15 10:56:12 -080068/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
69
msarett5cb48852015-11-06 08:56:32 -080070BRDSrc::BRDSrc(Path path, SkBitmapRegionDecoder::Strategy strategy, Mode mode,
msaretta5783ae2015-09-08 15:35:32 -070071 CodecSrc::DstColorType dstColorType, uint32_t sampleSize)
72 : fPath(path)
73 , fStrategy(strategy)
74 , fMode(mode)
75 , fDstColorType(dstColorType)
76 , fSampleSize(sampleSize)
77{}
78
79bool BRDSrc::veto(SinkFlags flags) const {
80 // No need to test to non-raster or indirect backends.
81 return flags.type != SinkFlags::kRaster
82 || flags.approach != SinkFlags::kDirect;
83}
84
msarett5cb48852015-11-06 08:56:32 -080085static SkBitmapRegionDecoder* create_brd(Path path,
86 SkBitmapRegionDecoder::Strategy strategy) {
msaretta5783ae2015-09-08 15:35:32 -070087 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(path.c_str()));
88 if (!encoded) {
89 return NULL;
90 }
msarett5cb48852015-11-06 08:56:32 -080091 return SkBitmapRegionDecoder::Create(encoded, strategy);
msaretta5783ae2015-09-08 15:35:32 -070092}
93
94Error BRDSrc::draw(SkCanvas* canvas) const {
95 SkColorType colorType = canvas->imageInfo().colorType();
96 if (kRGB_565_SkColorType == colorType &&
97 CodecSrc::kGetFromCanvas_DstColorType != fDstColorType) {
98 return Error::Nonfatal("Testing non-565 to 565 is uninteresting.");
99 }
100 switch (fDstColorType) {
101 case CodecSrc::kGetFromCanvas_DstColorType:
102 break;
103 case CodecSrc::kIndex8_Always_DstColorType:
104 colorType = kIndex_8_SkColorType;
105 break;
106 case CodecSrc::kGrayscale_Always_DstColorType:
107 colorType = kGray_8_SkColorType;
108 break;
109 }
110
msarett5cb48852015-11-06 08:56:32 -0800111 SkAutoTDelete<SkBitmapRegionDecoder> brd(create_brd(fPath, fStrategy));
msaretta5783ae2015-09-08 15:35:32 -0700112 if (nullptr == brd.get()) {
113 return Error::Nonfatal(SkStringPrintf("Could not create brd for %s.", fPath.c_str()));
114 }
115
msarett04965c62015-10-12 10:24:38 -0700116 if (!brd->conversionSupported(colorType)) {
mtklein9b439152015-12-09 13:02:26 -0800117 return Error::Nonfatal("Cannot convert to color type.");
msarett04965c62015-10-12 10:24:38 -0700118 }
119
msaretta5783ae2015-09-08 15:35:32 -0700120 const uint32_t width = brd->width();
121 const uint32_t height = brd->height();
122 // Visually inspecting very small output images is not necessary.
123 if ((width / fSampleSize <= 10 || height / fSampleSize <= 10) && 1 != fSampleSize) {
124 return Error::Nonfatal("Scaling very small images is uninteresting.");
125 }
126 switch (fMode) {
127 case kFullImage_Mode: {
msarett35e5d1b2015-10-27 12:50:25 -0700128 SkBitmap bitmap;
129 if (!brd->decodeRegion(&bitmap, nullptr, SkIRect::MakeXYWH(0, 0, width, height),
130 fSampleSize, colorType, false)) {
mtklein9b439152015-12-09 13:02:26 -0800131 return "Cannot decode (full) region.";
msarett35e5d1b2015-10-27 12:50:25 -0700132 }
133 if (colorType != bitmap.colorType()) {
mtklein9b439152015-12-09 13:02:26 -0800134 return Error::Nonfatal("Cannot convert to color type.");
msaretta5783ae2015-09-08 15:35:32 -0700135 }
msarett35e5d1b2015-10-27 12:50:25 -0700136 canvas->drawBitmap(bitmap, 0, 0);
msaretta5783ae2015-09-08 15:35:32 -0700137 return "";
138 }
139 case kDivisor_Mode: {
140 const uint32_t divisor = 2;
141 if (width < divisor || height < divisor) {
mtklein9b439152015-12-09 13:02:26 -0800142 return Error::Nonfatal("Divisor is larger than image dimension.");
msaretta5783ae2015-09-08 15:35:32 -0700143 }
144
145 // Use a border to test subsets that extend outside the image.
146 // We will not allow the border to be larger than the image dimensions. Allowing
147 // these large borders causes off by one errors that indicate a problem with the
148 // test suite, not a problem with the implementation.
149 const uint32_t maxBorder = SkTMin(width, height) / (fSampleSize * divisor);
150 const uint32_t scaledBorder = SkTMin(5u, maxBorder);
151 const uint32_t unscaledBorder = scaledBorder * fSampleSize;
152
153 // We may need to clear the canvas to avoid uninitialized memory.
154 // Assume we are scaling a 780x780 image with sampleSize = 8.
155 // The output image should be 97x97.
156 // Each subset will be 390x390.
157 // Each scaled subset be 48x48.
158 // Four scaled subsets will only fill a 96x96 image.
159 // The bottom row and last column will not be touched.
160 // This is an unfortunate result of our rounding rules when scaling.
161 // Maybe we need to consider testing scaled subsets without trying to
162 // combine them to match the full scaled image? Or maybe this is the
163 // best we can do?
164 canvas->clear(0);
165
166 for (uint32_t x = 0; x < divisor; x++) {
167 for (uint32_t y = 0; y < divisor; y++) {
168 // Calculate the subset dimensions
169 uint32_t subsetWidth = width / divisor;
170 uint32_t subsetHeight = height / divisor;
171 const int left = x * subsetWidth;
172 const int top = y * subsetHeight;
173
174 // Increase the size of the last subset in each row or column, when the
175 // divisor does not divide evenly into the image dimensions
176 subsetWidth += (x + 1 == divisor) ? (width % divisor) : 0;
177 subsetHeight += (y + 1 == divisor) ? (height % divisor) : 0;
178
179 // Increase the size of the subset in order to have a border on each side
180 const int decodeLeft = left - unscaledBorder;
181 const int decodeTop = top - unscaledBorder;
182 const uint32_t decodeWidth = subsetWidth + unscaledBorder * 2;
183 const uint32_t decodeHeight = subsetHeight + unscaledBorder * 2;
msarett35e5d1b2015-10-27 12:50:25 -0700184 SkBitmap bitmap;
185 if (!brd->decodeRegion(&bitmap, nullptr, SkIRect::MakeXYWH(decodeLeft,
186 decodeTop, decodeWidth, decodeHeight), fSampleSize, colorType, false)) {
mtklein9b439152015-12-09 13:02:26 -0800187 return "Cannot decode region.";
msarett35e5d1b2015-10-27 12:50:25 -0700188 }
189 if (colorType != bitmap.colorType()) {
mtklein9b439152015-12-09 13:02:26 -0800190 return Error::Nonfatal("Cannot convert to color type.");
msaretta5783ae2015-09-08 15:35:32 -0700191 }
192
msarett35e5d1b2015-10-27 12:50:25 -0700193 canvas->drawBitmapRect(bitmap,
msaretta5783ae2015-09-08 15:35:32 -0700194 SkRect::MakeXYWH((SkScalar) scaledBorder, (SkScalar) scaledBorder,
195 (SkScalar) (subsetWidth / fSampleSize),
196 (SkScalar) (subsetHeight / fSampleSize)),
197 SkRect::MakeXYWH((SkScalar) (left / fSampleSize),
198 (SkScalar) (top / fSampleSize),
199 (SkScalar) (subsetWidth / fSampleSize),
200 (SkScalar) (subsetHeight / fSampleSize)),
201 nullptr);
202 }
203 }
204 return "";
205 }
206 default:
207 SkASSERT(false);
mtklein9b439152015-12-09 13:02:26 -0800208 return "Error: Should not be reached.";
msaretta5783ae2015-09-08 15:35:32 -0700209 }
210}
211
212SkISize BRDSrc::size() const {
msarett5cb48852015-11-06 08:56:32 -0800213 SkAutoTDelete<SkBitmapRegionDecoder> brd(create_brd(fPath, fStrategy));
msaretta5783ae2015-09-08 15:35:32 -0700214 if (brd) {
215 return SkISize::Make(SkTMax(1, brd->width() / (int) fSampleSize),
216 SkTMax(1, brd->height() / (int) fSampleSize));
217 }
218 return SkISize::Make(0, 0);
219}
220
221static SkString get_scaled_name(const Path& path, float scale) {
222 return SkStringPrintf("%s_%.3f", SkOSPath::Basename(path.c_str()).c_str(), scale);
223}
224
225Name BRDSrc::name() const {
226 // We will replicate the names used by CodecSrc so that images can
227 // be compared in Gold.
228 if (1 == fSampleSize) {
229 return SkOSPath::Basename(fPath.c_str());
230 }
msarett4b0778e2015-11-13 09:59:11 -0800231 return get_scaled_name(fPath, 1.0f / (float) fSampleSize);
msaretta5783ae2015-09-08 15:35:32 -0700232}
233
234/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
235
msarett0a242972015-06-11 14:27:27 -0700236CodecSrc::CodecSrc(Path path, Mode mode, DstColorType dstColorType, float scale)
msarett438b2ad2015-04-09 12:43:10 -0700237 : fPath(path)
238 , fMode(mode)
239 , fDstColorType(dstColorType)
msarett0a242972015-06-11 14:27:27 -0700240 , fScale(scale)
msarett438b2ad2015-04-09 12:43:10 -0700241{}
mtklein748ca3b2015-01-15 10:56:12 -0800242
mtklein99cab4e2015-07-31 06:43:04 -0700243bool CodecSrc::veto(SinkFlags flags) const {
244 // No need to test decoding to non-raster or indirect backend.
mtkleine0effd62015-07-29 06:37:28 -0700245 // TODO: Once we implement GPU paths (e.g. JPEG YUV), we should use a deferred decode to
246 // let the GPU handle it.
mtklein99cab4e2015-07-31 06:43:04 -0700247 return flags.type != SinkFlags::kRaster
248 || flags.approach != SinkFlags::kDirect;
mtkleine0effd62015-07-29 06:37:28 -0700249}
scroggo9b77ddd2015-03-19 06:03:39 -0700250
msarett3d9d7a72015-10-21 10:27:10 -0700251bool get_decode_info(SkImageInfo* decodeInfo, const SkImageInfo& defaultInfo,
252 SkColorType canvasColorType, CodecSrc::DstColorType dstColorType) {
253 switch (dstColorType) {
254 case CodecSrc::kIndex8_Always_DstColorType:
255 if (kRGB_565_SkColorType == canvasColorType) {
256 return false;
257 }
258 *decodeInfo = defaultInfo.makeColorType(kIndex_8_SkColorType);
259 break;
260 case CodecSrc::kGrayscale_Always_DstColorType:
261 if (kRGB_565_SkColorType == canvasColorType) {
262 return false;
263 }
264 *decodeInfo = defaultInfo.makeColorType(kGray_8_SkColorType);
265 break;
266 default:
267 *decodeInfo = defaultInfo.makeColorType(canvasColorType);
268 break;
269 }
270
271 // FIXME: Currently we cannot draw unpremultiplied sources.
272 if (decodeInfo->alphaType() == kUnpremul_SkAlphaType) {
msarett90978142015-10-27 07:12:24 -0700273 *decodeInfo = decodeInfo->makeAlphaType(kPremul_SkAlphaType);
msarett3d9d7a72015-10-21 10:27:10 -0700274 }
275 return true;
276}
277
mtkleine0effd62015-07-29 06:37:28 -0700278Error CodecSrc::draw(SkCanvas* canvas) const {
mtklein75d98fd2015-01-18 07:05:01 -0800279 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str()));
mtklein748ca3b2015-01-15 10:56:12 -0800280 if (!encoded) {
281 return SkStringPrintf("Couldn't read %s.", fPath.c_str());
282 }
msarett3d9d7a72015-10-21 10:27:10 -0700283 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded));
msarett9e707a02015-09-01 14:57:57 -0700284 if (nullptr == codec.get()) {
285 return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str());
scroggo9b77ddd2015-03-19 06:03:39 -0700286 }
287
msarett3d9d7a72015-10-21 10:27:10 -0700288 SkImageInfo decodeInfo;
289 if (!get_decode_info(&decodeInfo, codec->getInfo(), canvas->imageInfo().colorType(),
290 fDstColorType)) {
291 return Error::Nonfatal("Testing non-565 to 565 is uninteresting.");
msarett438b2ad2015-04-09 12:43:10 -0700292 }
293
msarett0a242972015-06-11 14:27:27 -0700294 // Try to scale the image if it is desired
295 SkISize size = codec->getScaledDimensions(fScale);
296 if (size == decodeInfo.dimensions() && 1.0f != fScale) {
297 return Error::Nonfatal("Test without scaling is uninteresting.");
298 }
msarettb32758a2015-08-18 13:22:46 -0700299
300 // Visually inspecting very small output images is not necessary. We will
301 // cover these cases in unit testing.
302 if ((size.width() <= 10 || size.height() <= 10) && 1.0f != fScale) {
303 return Error::Nonfatal("Scaling very small images is uninteresting.");
304 }
msarett0a242972015-06-11 14:27:27 -0700305 decodeInfo = decodeInfo.makeWH(size.width(), size.height());
306
msarett438b2ad2015-04-09 12:43:10 -0700307 // Construct a color table for the decode if necessary
halcanary96fcdcc2015-08-27 07:41:13 -0700308 SkAutoTUnref<SkColorTable> colorTable(nullptr);
309 SkPMColor* colorPtr = nullptr;
310 int* colorCountPtr = nullptr;
msarett438b2ad2015-04-09 12:43:10 -0700311 int maxColors = 256;
312 if (kIndex_8_SkColorType == decodeInfo.colorType()) {
313 SkPMColor colors[256];
halcanary385fe4d2015-08-26 13:07:48 -0700314 colorTable.reset(new SkColorTable(colors, maxColors));
msarett438b2ad2015-04-09 12:43:10 -0700315 colorPtr = const_cast<SkPMColor*>(colorTable->readColors());
316 colorCountPtr = &maxColors;
317 }
318
scroggo9b77ddd2015-03-19 06:03:39 -0700319 SkBitmap bitmap;
halcanary96fcdcc2015-08-27 07:41:13 -0700320 if (!bitmap.tryAllocPixels(decodeInfo, nullptr, colorTable.get())) {
mtklein9b439152015-12-09 13:02:26 -0800321 return SkStringPrintf("Image(%s) is too large (%d x %d)", fPath.c_str(),
scroggo9b77ddd2015-03-19 06:03:39 -0700322 decodeInfo.width(), decodeInfo.height());
323 }
324
scroggo9c59ebc2015-03-25 13:48:49 -0700325 switch (fMode) {
msarett9e707a02015-09-01 14:57:57 -0700326 case kCodec_Mode: {
halcanary96fcdcc2015-08-27 07:41:13 -0700327 switch (codec->getPixels(decodeInfo, bitmap.getPixels(), bitmap.rowBytes(), nullptr,
msarett438b2ad2015-04-09 12:43:10 -0700328 colorPtr, colorCountPtr)) {
scroggoeb602a52015-07-09 08:16:03 -0700329 case SkCodec::kSuccess:
scroggo9c59ebc2015-03-25 13:48:49 -0700330 // We consider incomplete to be valid, since we should still decode what is
331 // available.
scroggoeb602a52015-07-09 08:16:03 -0700332 case SkCodec::kIncompleteInput:
scroggo9c59ebc2015-03-25 13:48:49 -0700333 break;
scroggoeb602a52015-07-09 08:16:03 -0700334 case SkCodec::kInvalidConversion:
scroggo9c59ebc2015-03-25 13:48:49 -0700335 return Error::Nonfatal("Incompatible colortype conversion");
336 default:
337 // Everything else is considered a failure.
338 return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str());
339 }
emmaleer97002062015-05-27 12:36:10 -0700340 canvas->drawBitmap(bitmap, 0, 0);
scroggo9c59ebc2015-03-25 13:48:49 -0700341 break;
emmaleer0a4c3cb2015-06-22 10:40:21 -0700342 }
scroggo9c59ebc2015-03-25 13:48:49 -0700343 case kScanline_Mode: {
scroggo46c57472015-09-30 08:57:13 -0700344 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, NULL, colorPtr,
345 colorCountPtr)) {
msarett9e707a02015-09-01 14:57:57 -0700346 return Error::Nonfatal("Could not start scanline decoder");
scroggo9c59ebc2015-03-25 13:48:49 -0700347 }
scroggo1c005e42015-08-04 09:24:45 -0700348
msarette6dd0042015-10-09 11:07:34 -0700349 void* dst = bitmap.getAddr(0, 0);
350 size_t rowBytes = bitmap.rowBytes();
351 uint32_t height = decodeInfo.height();
scroggo46c57472015-09-30 08:57:13 -0700352 switch (codec->getScanlineOrder()) {
353 case SkCodec::kTopDown_SkScanlineOrder:
354 case SkCodec::kBottomUp_SkScanlineOrder:
355 case SkCodec::kNone_SkScanlineOrder:
msarette6dd0042015-10-09 11:07:34 -0700356 // We do not need to check the return value. On an incomplete
357 // image, memory will be filled with a default value.
358 codec->getScanlines(dst, height, rowBytes);
msarett10522ff2015-09-07 08:54:01 -0700359 break;
scroggo46c57472015-09-30 08:57:13 -0700360 case SkCodec::kOutOfOrder_SkScanlineOrder: {
msarett10522ff2015-09-07 08:54:01 -0700361 for (int y = 0; y < decodeInfo.height(); y++) {
msarette6dd0042015-10-09 11:07:34 -0700362 int dstY = codec->outputScanline(y);
msarett10522ff2015-09-07 08:54:01 -0700363 void* dstPtr = bitmap.getAddr(0, dstY);
msarette6dd0042015-10-09 11:07:34 -0700364 // We complete the loop, even if this call begins to fail
365 // due to an incomplete image. This ensures any uninitialized
366 // memory will be filled with the proper value.
367 codec->getScanlines(dstPtr, 1, bitmap.rowBytes());
msarett10522ff2015-09-07 08:54:01 -0700368 }
369 break;
370 }
371 }
372
emmaleer97002062015-05-27 12:36:10 -0700373 canvas->drawBitmap(bitmap, 0, 0);
374 break;
375 }
msarett0a242972015-06-11 14:27:27 -0700376 case kStripe_Mode: {
377 const int height = decodeInfo.height();
378 // This value is chosen arbitrarily. We exercise more cases by choosing a value that
379 // does not align with image blocks.
380 const int stripeHeight = 37;
381 const int numStripes = (height + stripeHeight - 1) / stripeHeight;
382
383 // Decode odd stripes
scroggo46c57472015-09-30 08:57:13 -0700384 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, NULL, colorPtr,
385 colorCountPtr)
386 || SkCodec::kTopDown_SkScanlineOrder != codec->getScanlineOrder()) {
msarett9e707a02015-09-01 14:57:57 -0700387 // This mode was designed to test the new skip scanlines API in libjpeg-turbo.
388 // Jpegs have kTopDown_SkScanlineOrder, and at this time, it is not interesting
389 // to run this test for image types that do not have this scanline ordering.
msarett5406d6f2015-08-31 06:55:13 -0700390 return Error::Nonfatal("Could not start top-down scanline decoder");
msarett0a242972015-06-11 14:27:27 -0700391 }
msarette6dd0042015-10-09 11:07:34 -0700392
msarett0a242972015-06-11 14:27:27 -0700393 for (int i = 0; i < numStripes; i += 2) {
394 // Skip a stripe
395 const int linesToSkip = SkTMin(stripeHeight, height - i * stripeHeight);
msarette6dd0042015-10-09 11:07:34 -0700396 codec->skipScanlines(linesToSkip);
msarett0a242972015-06-11 14:27:27 -0700397
398 // Read a stripe
399 const int startY = (i + 1) * stripeHeight;
400 const int linesToRead = SkTMin(stripeHeight, height - startY);
401 if (linesToRead > 0) {
msarette6dd0042015-10-09 11:07:34 -0700402 codec->getScanlines(bitmap.getAddr(0, startY), linesToRead, bitmap.rowBytes());
msarett0a242972015-06-11 14:27:27 -0700403 }
404 }
405
406 // Decode even stripes
scroggo46c57472015-09-30 08:57:13 -0700407 const SkCodec::Result startResult = codec->startScanlineDecode(decodeInfo, nullptr,
408 colorPtr, colorCountPtr);
scroggo1c005e42015-08-04 09:24:45 -0700409 if (SkCodec::kSuccess != startResult) {
410 return "Failed to restart scanline decoder with same parameters.";
msarett0a242972015-06-11 14:27:27 -0700411 }
412 for (int i = 0; i < numStripes; i += 2) {
413 // Read a stripe
414 const int startY = i * stripeHeight;
415 const int linesToRead = SkTMin(stripeHeight, height - startY);
msarette6dd0042015-10-09 11:07:34 -0700416 codec->getScanlines(bitmap.getAddr(0, startY), linesToRead, bitmap.rowBytes());
msarett0a242972015-06-11 14:27:27 -0700417
418 // Skip a stripe
msarettf6db27e2015-06-12 09:34:04 -0700419 const int linesToSkip = SkTMin(stripeHeight, height - (i + 1) * stripeHeight);
420 if (linesToSkip > 0) {
msarette6dd0042015-10-09 11:07:34 -0700421 codec->skipScanlines(linesToSkip);
msarett0a242972015-06-11 14:27:27 -0700422 }
423 }
424 canvas->drawBitmap(bitmap, 0, 0);
emmaleer0a4c3cb2015-06-22 10:40:21 -0700425 break;
msarett0a242972015-06-11 14:27:27 -0700426 }
scroggob636b452015-07-22 07:16:20 -0700427 case kSubset_Mode: {
428 // Arbitrarily choose a divisor.
429 int divisor = 2;
430 // Total width/height of the image.
431 const int W = codec->getInfo().width();
432 const int H = codec->getInfo().height();
433 if (divisor > W || divisor > H) {
434 return Error::Nonfatal(SkStringPrintf("Cannot codec subset: divisor %d is too big "
435 "for %s with dimensions (%d x %d)", divisor,
436 fPath.c_str(), W, H));
437 }
438 // subset dimensions
439 // SkWebpCodec, the only one that supports subsets, requires even top/left boundaries.
440 const int w = SkAlign2(W / divisor);
441 const int h = SkAlign2(H / divisor);
442 SkIRect subset;
443 SkCodec::Options opts;
444 opts.fSubset = &subset;
445 SkBitmap subsetBm;
446 // We will reuse pixel memory from bitmap.
447 void* pixels = bitmap.getPixels();
448 // Keep track of left and top (for drawing subsetBm into canvas). We could use
449 // fScale * x and fScale * y, but we want integers such that the next subset will start
450 // where the last one ended. So we'll add decodeInfo.width() and height().
451 int left = 0;
452 for (int x = 0; x < W; x += w) {
453 int top = 0;
454 for (int y = 0; y < H; y+= h) {
455 // Do not make the subset go off the edge of the image.
456 const int preScaleW = SkTMin(w, W - x);
457 const int preScaleH = SkTMin(h, H - y);
458 subset.setXYWH(x, y, preScaleW, preScaleH);
459 // And scale
460 // FIXME: Should we have a version of getScaledDimensions that takes a subset
461 // into account?
msarette6dd0042015-10-09 11:07:34 -0700462 decodeInfo = decodeInfo.makeWH(
463 SkTMax(1, SkScalarRoundToInt(preScaleW * fScale)),
464 SkTMax(1, SkScalarRoundToInt(preScaleH * fScale)));
scroggob636b452015-07-22 07:16:20 -0700465 size_t rowBytes = decodeInfo.minRowBytes();
466 if (!subsetBm.installPixels(decodeInfo, pixels, rowBytes, colorTable.get(),
halcanary96fcdcc2015-08-27 07:41:13 -0700467 nullptr, nullptr)) {
scroggob636b452015-07-22 07:16:20 -0700468 return SkStringPrintf("could not install pixels for %s.", fPath.c_str());
469 }
470 const SkCodec::Result result = codec->getPixels(decodeInfo, pixels, rowBytes,
471 &opts, colorPtr, colorCountPtr);
472 switch (result) {
473 case SkCodec::kSuccess:
474 case SkCodec::kIncompleteInput:
475 break;
476 case SkCodec::kInvalidConversion:
477 if (0 == (x|y)) {
478 // First subset is okay to return unimplemented.
479 return Error::Nonfatal("Incompatible colortype conversion");
480 }
481 // If the first subset succeeded, a later one should not fail.
482 // fall through to failure
483 case SkCodec::kUnimplemented:
484 if (0 == (x|y)) {
485 // First subset is okay to return unimplemented.
486 return Error::Nonfatal("subset codec not supported");
487 }
488 // If the first subset succeeded, why would a later one fail?
489 // fall through to failure
490 default:
491 return SkStringPrintf("subset codec failed to decode (%d, %d, %d, %d) "
492 "from %s with dimensions (%d x %d)\t error %d",
493 x, y, decodeInfo.width(), decodeInfo.height(),
494 fPath.c_str(), W, H, result);
495 }
496 canvas->drawBitmap(subsetBm, SkIntToScalar(left), SkIntToScalar(top));
497 // translate by the scaled height.
498 top += decodeInfo.height();
499 }
500 // translate by the scaled width.
501 left += decodeInfo.width();
502 }
503 return "";
504 }
scroggo9b77ddd2015-03-19 06:03:39 -0700505 }
scroggo9c59ebc2015-03-25 13:48:49 -0700506 return "";
scroggo9b77ddd2015-03-19 06:03:39 -0700507}
508
509SkISize CodecSrc::size() const {
510 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str()));
msarett3d9d7a72015-10-21 10:27:10 -0700511 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded));
scroggo7fac5af2015-09-30 11:33:12 -0700512 if (nullptr == codec) {
513 return SkISize::Make(0, 0);
514 }
515 return codec->getScaledDimensions(fScale);
scroggo9b77ddd2015-03-19 06:03:39 -0700516}
517
518Name CodecSrc::name() const {
msarett0a242972015-06-11 14:27:27 -0700519 if (1.0f == fScale) {
520 return SkOSPath::Basename(fPath.c_str());
msarett0a242972015-06-11 14:27:27 -0700521 }
msaretta5783ae2015-09-08 15:35:32 -0700522 return get_scaled_name(fPath, fScale);
scroggo9b77ddd2015-03-19 06:03:39 -0700523}
524
525/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
526
msarett3d9d7a72015-10-21 10:27:10 -0700527AndroidCodecSrc::AndroidCodecSrc(Path path, Mode mode, CodecSrc::DstColorType dstColorType,
528 int sampleSize)
529 : fPath(path)
530 , fMode(mode)
531 , fDstColorType(dstColorType)
532 , fSampleSize(sampleSize)
533{}
534
535bool AndroidCodecSrc::veto(SinkFlags flags) const {
536 // No need to test decoding to non-raster or indirect backend.
537 // TODO: Once we implement GPU paths (e.g. JPEG YUV), we should use a deferred decode to
538 // let the GPU handle it.
539 return flags.type != SinkFlags::kRaster
540 || flags.approach != SinkFlags::kDirect;
541}
542
543Error AndroidCodecSrc::draw(SkCanvas* canvas) const {
544 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str()));
545 if (!encoded) {
546 return SkStringPrintf("Couldn't read %s.", fPath.c_str());
547 }
548 SkAutoTDelete<SkAndroidCodec> codec(SkAndroidCodec::NewFromData(encoded));
549 if (nullptr == codec.get()) {
550 return SkStringPrintf("Couldn't create android codec for %s.", fPath.c_str());
551 }
552
553 SkImageInfo decodeInfo;
554 if (!get_decode_info(&decodeInfo, codec->getInfo(), canvas->imageInfo().colorType(),
555 fDstColorType)) {
556 return Error::Nonfatal("Testing non-565 to 565 is uninteresting.");
557 }
558
559 // Scale the image if it is desired.
560 SkISize size = codec->getSampledDimensions(fSampleSize);
561
562 // Visually inspecting very small output images is not necessary. We will
563 // cover these cases in unit testing.
564 if ((size.width() <= 10 || size.height() <= 10) && 1 != fSampleSize) {
565 return Error::Nonfatal("Scaling very small images is uninteresting.");
566 }
567 decodeInfo = decodeInfo.makeWH(size.width(), size.height());
568
569 // Construct a color table for the decode if necessary
570 SkAutoTUnref<SkColorTable> colorTable(nullptr);
571 SkPMColor* colorPtr = nullptr;
572 int* colorCountPtr = nullptr;
573 int maxColors = 256;
574 if (kIndex_8_SkColorType == decodeInfo.colorType()) {
575 SkPMColor colors[256];
576 colorTable.reset(new SkColorTable(colors, maxColors));
577 colorPtr = const_cast<SkPMColor*>(colorTable->readColors());
578 colorCountPtr = &maxColors;
579 }
580
581 SkBitmap bitmap;
582 if (!bitmap.tryAllocPixels(decodeInfo, nullptr, colorTable.get())) {
mtklein9b439152015-12-09 13:02:26 -0800583 return SkStringPrintf("Image(%s) is too large (%d x %d)", fPath.c_str(),
msarett3d9d7a72015-10-21 10:27:10 -0700584 decodeInfo.width(), decodeInfo.height());
585 }
586
587 // Create options for the codec.
588 SkAndroidCodec::AndroidOptions options;
589 options.fColorPtr = colorPtr;
590 options.fColorCount = colorCountPtr;
591 options.fSampleSize = fSampleSize;
592
593 switch (fMode) {
594 case kFullImage_Mode: {
595 switch (codec->getAndroidPixels(decodeInfo, bitmap.getPixels(), bitmap.rowBytes(),
596 &options)) {
597 case SkCodec::kSuccess:
598 case SkCodec::kIncompleteInput:
599 break;
600 case SkCodec::kInvalidConversion:
mtklein9b439152015-12-09 13:02:26 -0800601 return Error::Nonfatal("Cannot convert to requested color type.");
msarett3d9d7a72015-10-21 10:27:10 -0700602 default:
603 return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str());
604 }
605 canvas->drawBitmap(bitmap, 0, 0);
606 return "";
607 }
608 case kDivisor_Mode: {
609 const int width = codec->getInfo().width();
610 const int height = codec->getInfo().height();
611 const int divisor = 2;
612 if (width < divisor || height < divisor) {
mtklein9b439152015-12-09 13:02:26 -0800613 return Error::Nonfatal("Divisor is larger than image dimension.");
msarett3d9d7a72015-10-21 10:27:10 -0700614 }
615
msarettfa23a9e2015-10-21 13:26:59 -0700616 // Keep track of the final decoded dimensions.
617 int finalScaledWidth = 0;
618 int finalScaledHeight = 0;
msarett3d9d7a72015-10-21 10:27:10 -0700619 for (int x = 0; x < divisor; x++) {
620 for (int y = 0; y < divisor; y++) {
621 // Calculate the subset dimensions
622 int subsetWidth = width / divisor;
623 int subsetHeight = height / divisor;
624 const int left = x * subsetWidth;
625 const int top = y * subsetHeight;
626
627 // Increase the size of the last subset in each row or column, when the
628 // divisor does not divide evenly into the image dimensions
629 subsetWidth += (x + 1 == divisor) ? (width % divisor) : 0;
630 subsetHeight += (y + 1 == divisor) ? (height % divisor) : 0;
631 SkIRect subset = SkIRect::MakeXYWH(left, top, subsetWidth, subsetHeight);
632 if (!codec->getSupportedSubset(&subset)) {
mtklein9b439152015-12-09 13:02:26 -0800633 return "Could not get supported subset to decode.";
msarett3d9d7a72015-10-21 10:27:10 -0700634 }
635 options.fSubset = &subset;
msarettfa23a9e2015-10-21 13:26:59 -0700636 const int scaledWidthOffset = subset.left() / fSampleSize;
637 const int scaledHeightOffset = subset.top() / fSampleSize;
638 void* pixels = bitmap.getAddr(scaledWidthOffset, scaledHeightOffset);
msarett3d9d7a72015-10-21 10:27:10 -0700639 SkISize scaledSubsetSize = codec->getSampledSubsetDimensions(fSampleSize,
640 subset);
641 SkImageInfo subsetDecodeInfo = decodeInfo.makeWH(scaledSubsetSize.width(),
642 scaledSubsetSize.height());
643
msarettfa23a9e2015-10-21 13:26:59 -0700644 if (x + 1 == divisor && y + 1 == divisor) {
645 finalScaledWidth = scaledWidthOffset + scaledSubsetSize.width();
646 finalScaledHeight = scaledHeightOffset + scaledSubsetSize.height();
647 }
648
msarett3d9d7a72015-10-21 10:27:10 -0700649 switch (codec->getAndroidPixels(subsetDecodeInfo, pixels, bitmap.rowBytes(),
650 &options)) {
651 case SkCodec::kSuccess:
652 case SkCodec::kIncompleteInput:
653 break;
654 case SkCodec::kInvalidConversion:
mtklein9b439152015-12-09 13:02:26 -0800655 return Error::Nonfatal("Cannot convert to requested color type.");
msarett3d9d7a72015-10-21 10:27:10 -0700656 default:
657 return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str());
658 }
659 }
660 }
msarettfa23a9e2015-10-21 13:26:59 -0700661
662 SkRect rect = SkRect::MakeXYWH(0, 0, (SkScalar) finalScaledWidth,
663 (SkScalar) finalScaledHeight);
664 canvas->drawBitmapRect(bitmap, rect, rect, nullptr);
msarett3d9d7a72015-10-21 10:27:10 -0700665 return "";
666 }
667 default:
668 SkASSERT(false);
mtklein9b439152015-12-09 13:02:26 -0800669 return "Error: Should not be reached.";
msarett3d9d7a72015-10-21 10:27:10 -0700670 }
671}
672
673SkISize AndroidCodecSrc::size() const {
674 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str()));
675 SkAutoTDelete<SkAndroidCodec> codec(SkAndroidCodec::NewFromData(encoded));
676 if (nullptr == codec) {
677 return SkISize::Make(0, 0);
678 }
679 return codec->getSampledDimensions(fSampleSize);
680}
681
682Name AndroidCodecSrc::name() const {
683 // We will replicate the names used by CodecSrc so that images can
684 // be compared in Gold.
685 if (1 == fSampleSize) {
686 return SkOSPath::Basename(fPath.c_str());
687 }
msarett4b0778e2015-11-13 09:59:11 -0800688 return get_scaled_name(fPath, 1.0f / (float) fSampleSize);
msarett3d9d7a72015-10-21 10:27:10 -0700689}
690
691/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
692
msarett164d3022015-11-10 15:09:03 -0800693ImageSrc::ImageSrc(Path path) : fPath(path) {}
scroggo9b77ddd2015-03-19 06:03:39 -0700694
mtklein99cab4e2015-07-31 06:43:04 -0700695bool ImageSrc::veto(SinkFlags flags) const {
696 // No need to test decoding to non-raster or indirect backend.
mtkleine0effd62015-07-29 06:37:28 -0700697 // TODO: Instead, use lazy decoding to allow the GPU to handle cases like YUV.
mtklein99cab4e2015-07-31 06:43:04 -0700698 return flags.type != SinkFlags::kRaster
699 || flags.approach != SinkFlags::kDirect;
mtkleine0effd62015-07-29 06:37:28 -0700700}
scroggo9b77ddd2015-03-19 06:03:39 -0700701
mtkleine0effd62015-07-29 06:37:28 -0700702Error ImageSrc::draw(SkCanvas* canvas) const {
scroggo9b77ddd2015-03-19 06:03:39 -0700703 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str()));
704 if (!encoded) {
705 return SkStringPrintf("Couldn't read %s.", fPath.c_str());
706 }
mtkleine0effd62015-07-29 06:37:28 -0700707 const SkColorType dstColorType = canvas->imageInfo().colorType();
mtkleinedc93bc2015-01-30 13:22:23 -0800708
msarett164d3022015-11-10 15:09:03 -0800709 // Decode the full image.
710 SkBitmap bitmap;
711 if (!SkImageDecoder::DecodeMemory(encoded->data(), encoded->size(), &bitmap,
712 dstColorType, SkImageDecoder::kDecodePixels_Mode)) {
713 return SkStringPrintf("Couldn't decode %s.", fPath.c_str());
mtkleinedc93bc2015-01-30 13:22:23 -0800714 }
msarett164d3022015-11-10 15:09:03 -0800715 if (kRGB_565_SkColorType == dstColorType && !bitmap.isOpaque()) {
716 // Do not draw a bitmap with alpha to a destination without alpha.
717 return Error::Nonfatal("Uninteresting to decode image with alpha into 565.");
mtklein748ca3b2015-01-15 10:56:12 -0800718 }
msarett164d3022015-11-10 15:09:03 -0800719 encoded.reset((SkData*)nullptr); // Might as well drop this when we're done with it.
720 canvas->drawBitmap(bitmap, 0,0);
mtklein748ca3b2015-01-15 10:56:12 -0800721 return "";
722}
723
724SkISize ImageSrc::size() const {
mtklein75d98fd2015-01-18 07:05:01 -0800725 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str()));
scroggo9b77ddd2015-03-19 06:03:39 -0700726 SkBitmap bitmap;
727 if (!encoded || !SkImageDecoder::DecodeMemory(encoded->data(),
728 encoded->size(),
729 &bitmap,
730 kUnknown_SkColorType,
731 SkImageDecoder::kDecodeBounds_Mode)) {
732 return SkISize::Make(0,0);
mtklein748ca3b2015-01-15 10:56:12 -0800733 }
scroggo9b77ddd2015-03-19 06:03:39 -0700734 return bitmap.dimensions();
mtklein748ca3b2015-01-15 10:56:12 -0800735}
736
mtklein9264a952015-01-20 10:11:53 -0800737Name ImageSrc::name() const {
mtkleinedc93bc2015-01-30 13:22:23 -0800738 return SkOSPath::Basename(fPath.c_str());
mtklein9264a952015-01-20 10:11:53 -0800739}
mtklein748ca3b2015-01-15 10:56:12 -0800740
741/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
742
mtkleinf4ba3212015-01-28 15:32:24 -0800743static const SkRect kSKPViewport = {0,0, 1000,1000};
744
mtklein8d17a132015-01-30 11:42:31 -0800745SKPSrc::SKPSrc(Path path) : fPath(path) {}
mtklein748ca3b2015-01-15 10:56:12 -0800746
747Error SKPSrc::draw(SkCanvas* canvas) const {
scroggoa1193e42015-01-21 12:09:53 -0800748 SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(fPath.c_str()));
mtklein75d98fd2015-01-18 07:05:01 -0800749 if (!stream) {
mtklein748ca3b2015-01-15 10:56:12 -0800750 return SkStringPrintf("Couldn't read %s.", fPath.c_str());
751 }
mtkleinb3e5e4d2015-03-25 13:13:43 -0700752 SkAutoTUnref<SkPicture> pic(SkPicture::CreateFromStream(stream, &lazy_decode_bitmap));
mtklein75d98fd2015-01-18 07:05:01 -0800753 if (!pic) {
754 return SkStringPrintf("Couldn't decode %s as a picture.", fPath.c_str());
755 }
halcanary96fcdcc2015-08-27 07:41:13 -0700756 stream.reset((SkStream*)nullptr); // Might as well drop this when we're done with it.
joshualitt7c3a2f82015-03-31 13:32:05 -0700757
mtkleinf4ba3212015-01-28 15:32:24 -0800758 canvas->clipRect(kSKPViewport);
mtklein748ca3b2015-01-15 10:56:12 -0800759 canvas->drawPicture(pic);
760 return "";
761}
762
763SkISize SKPSrc::size() const {
mtkleinffa901a2015-03-16 10:38:07 -0700764 SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(fPath.c_str()));
765 if (!stream) {
766 return SkISize::Make(0,0);
767 }
768 SkPictInfo info;
769 if (!SkPicture::InternalOnly_StreamIsSKP(stream, &info)) {
770 return SkISize::Make(0,0);
771 }
772 SkRect viewport = kSKPViewport;
773 if (!viewport.intersect(info.fCullRect)) {
774 return SkISize::Make(0,0);
775 }
776 return viewport.roundOut().size();
mtklein748ca3b2015-01-15 10:56:12 -0800777}
778
779Name SKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); }
780
781/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
782
mtkleinad66f9b2015-02-13 15:11:10 -0800783Error NullSink::draw(const Src& src, SkBitmap*, SkWStream*, SkString*) const {
784 SkAutoTDelete<SkCanvas> canvas(SkCreateNullCanvas());
785 return src.draw(canvas);
786}
787
788/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
789
mtkleinb9eb4ac2015-02-02 18:26:03 -0800790DEFINE_bool(gpuStats, false, "Append GPU stats to the log for each GPU task?");
791
mtklein82d28432015-01-15 12:46:02 -0800792GPUSink::GPUSink(GrContextFactory::GLContextType ct,
kkinnunen5219fd92015-12-10 06:28:13 -0800793 GrContextFactory::GLContextOptions options,
mtklein82d28432015-01-15 12:46:02 -0800794 int samples,
bsalomonafcd7cd2015-08-31 12:39:41 -0700795 bool diText,
mtklein82d28432015-01-15 12:46:02 -0800796 bool threaded)
mtklein748ca3b2015-01-15 10:56:12 -0800797 : fContextType(ct)
kkinnunen5219fd92015-12-10 06:28:13 -0800798 , fContextOptions(options)
mtklein748ca3b2015-01-15 10:56:12 -0800799 , fSampleCount(samples)
bsalomonafcd7cd2015-08-31 12:39:41 -0700800 , fUseDIText(diText)
mtklein82d28432015-01-15 12:46:02 -0800801 , fThreaded(threaded) {}
mtklein748ca3b2015-01-15 10:56:12 -0800802
803int GPUSink::enclave() const {
mtklein55e88b22015-01-21 15:50:13 -0800804 return fThreaded ? kAnyThread_Enclave : kGPU_Enclave;
mtklein748ca3b2015-01-15 10:56:12 -0800805}
806
joshualitt5f5a8d72015-02-25 14:09:45 -0800807void PreAbandonGpuContextErrorHandler(SkError, void*) {}
808
bsalomon648c6962015-10-23 09:06:59 -0700809DEFINE_bool(imm, false, "Run gpu configs in immediate mode.");
bsalomon69cfe952015-11-30 13:27:47 -0800810DEFINE_bool(batchClip, false, "Clip each GrBatch to its device bounds for testing.");
bsalomon6dea83f2015-12-03 12:58:06 -0800811DEFINE_bool(batchBounds, false, "Draw a wireframe bounds of each GrBatch.");
bsalomon489147c2015-12-14 12:13:09 -0800812DEFINE_int32(batchLookback, -1, "Maximum GrBatch lookback for combining, negative means default.");
bsalomon648c6962015-10-23 09:06:59 -0700813
mtkleinb9eb4ac2015-02-02 18:26:03 -0800814Error GPUSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log) const {
kkinnunen5219fd92015-12-10 06:28:13 -0800815 GrContextOptions grOptions;
bsalomon489147c2015-12-14 12:13:09 -0800816 grOptions.fImmediateMode = FLAGS_imm;
817 grOptions.fClipBatchToBounds = FLAGS_batchClip;
818 grOptions.fDrawBatchBounds = FLAGS_batchBounds;
819 grOptions.fMaxBatchLookback = FLAGS_batchLookback;
kkinnunen64492c42015-12-08 01:24:40 -0800820
kkinnunen5219fd92015-12-10 06:28:13 -0800821 src.modifyGrContextOptions(&grOptions);
822
823 GrContextFactory factory(grOptions);
mtkleinf4ba3212015-01-28 15:32:24 -0800824 const SkISize size = src.size();
mtklein748ca3b2015-01-15 10:56:12 -0800825 const SkImageInfo info =
826 SkImageInfo::Make(size.width(), size.height(), kN32_SkColorType, kPremul_SkAlphaType);
827 SkAutoTUnref<SkSurface> surface(
kkinnunen3e980c32015-12-23 01:33:00 -0800828 NewGpuSurface(&factory, fContextType, fContextOptions, info, fSampleCount, fUseDIText));
mtklein748ca3b2015-01-15 10:56:12 -0800829 if (!surface) {
830 return "Could not create a surface.";
831 }
joshualitt5f5a8d72015-02-25 14:09:45 -0800832 if (FLAGS_preAbandonGpuContext) {
halcanary96fcdcc2015-08-27 07:41:13 -0700833 SkSetErrorCallback(&PreAbandonGpuContextErrorHandler, nullptr);
joshualitt5f5a8d72015-02-25 14:09:45 -0800834 factory.abandonContexts();
835 }
mtklein748ca3b2015-01-15 10:56:12 -0800836 SkCanvas* canvas = surface->getCanvas();
837 Error err = src.draw(canvas);
838 if (!err.isEmpty()) {
839 return err;
840 }
841 canvas->flush();
mtkleinb9eb4ac2015-02-02 18:26:03 -0800842 if (FLAGS_gpuStats) {
843 canvas->getGrContext()->dumpCacheStats(log);
844 canvas->getGrContext()->dumpGpuStats(log);
845 }
mtklein748ca3b2015-01-15 10:56:12 -0800846 dst->allocPixels(info);
joshualitt5f5a8d72015-02-25 14:09:45 -0800847 canvas->readPixels(dst, 0, 0);
mtklein55e88b22015-01-21 15:50:13 -0800848 if (FLAGS_abandonGpuContext) {
849 factory.abandonContexts();
850 }
mtklein748ca3b2015-01-15 10:56:12 -0800851 return "";
852}
853
854/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
855
halcanary47ef4d52015-03-03 09:13:09 -0800856static Error draw_skdocument(const Src& src, SkDocument* doc, SkWStream* dst) {
857 // Print the given DM:Src to a document, breaking on 8.5x11 pages.
858 SkASSERT(doc);
halcanaryfd4a9932015-01-28 11:45:58 -0800859 int width = src.size().width(),
860 height = src.size().height();
861
halcanary7e798182015-04-14 14:06:18 -0700862 if (FLAGS_multiPage) {
863 const int kLetterWidth = 612, // 8.5 * 72
864 kLetterHeight = 792; // 11 * 72
865 const SkRect letter = SkRect::MakeWH(SkIntToScalar(kLetterWidth),
866 SkIntToScalar(kLetterHeight));
halcanaryfd4a9932015-01-28 11:45:58 -0800867
halcanary7e798182015-04-14 14:06:18 -0700868 int xPages = ((width - 1) / kLetterWidth) + 1;
869 int yPages = ((height - 1) / kLetterHeight) + 1;
halcanaryfd4a9932015-01-28 11:45:58 -0800870
halcanary7e798182015-04-14 14:06:18 -0700871 for (int y = 0; y < yPages; ++y) {
872 for (int x = 0; x < xPages; ++x) {
873 int w = SkTMin(kLetterWidth, width - (x * kLetterWidth));
874 int h = SkTMin(kLetterHeight, height - (y * kLetterHeight));
875 SkCanvas* canvas =
876 doc->beginPage(SkIntToScalar(w), SkIntToScalar(h));
877 if (!canvas) {
halcanary96fcdcc2015-08-27 07:41:13 -0700878 return "SkDocument::beginPage(w,h) returned nullptr";
halcanary7e798182015-04-14 14:06:18 -0700879 }
880 canvas->clipRect(letter);
881 canvas->translate(-letter.width() * x, -letter.height() * y);
882 Error err = src.draw(canvas);
883 if (!err.isEmpty()) {
884 return err;
885 }
886 doc->endPage();
djsollen2ab90002015-04-03 06:38:31 -0700887 }
halcanaryfd4a9932015-01-28 11:45:58 -0800888 }
halcanary7e798182015-04-14 14:06:18 -0700889 } else {
890 SkCanvas* canvas =
891 doc->beginPage(SkIntToScalar(width), SkIntToScalar(height));
892 if (!canvas) {
halcanary96fcdcc2015-08-27 07:41:13 -0700893 return "SkDocument::beginPage(w,h) returned nullptr";
halcanary7e798182015-04-14 14:06:18 -0700894 }
895 Error err = src.draw(canvas);
896 if (!err.isEmpty()) {
897 return err;
898 }
899 doc->endPage();
mtklein748ca3b2015-01-15 10:56:12 -0800900 }
halcanary7e798182015-04-14 14:06:18 -0700901 if (!doc->close()) {
902 return "SkDocument::close() returned false";
903 }
halcanaryfd4a9932015-01-28 11:45:58 -0800904 dst->flush();
mtklein748ca3b2015-01-15 10:56:12 -0800905 return "";
906}
907
halcanaryc11c62f2015-09-28 11:51:54 -0700908PDFSink::PDFSink(const char* rasterizer) : fRasterizer(rasterizer) {}
halcanary47ef4d52015-03-03 09:13:09 -0800909
910Error PDFSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
911 SkAutoTUnref<SkDocument> doc(SkDocument::CreatePDF(dst));
912 if (!doc) {
halcanary96fcdcc2015-08-27 07:41:13 -0700913 return "SkDocument::CreatePDF() returned nullptr";
halcanary47ef4d52015-03-03 09:13:09 -0800914 }
halcanaryf12a1672015-09-23 12:45:49 -0700915 SkTArray<SkDocument::Attribute> info;
916 info.emplace_back(SkString("Title"), src.name());
917 info.emplace_back(SkString("Subject"),
918 SkString("rendering correctness test"));
919 info.emplace_back(SkString("Creator"), SkString("Skia/DM"));
halcanaryc11c62f2015-09-28 11:51:54 -0700920
921 info.emplace_back(SkString("Keywords"),
922 SkStringPrintf("Rasterizer:%s;", fRasterizer));
halcanaryf12a1672015-09-23 12:45:49 -0700923 doc->setMetadata(info, nullptr, nullptr);
halcanary47ef4d52015-03-03 09:13:09 -0800924 return draw_skdocument(src, doc.get(), dst);
925}
926
927/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
928
929XPSSink::XPSSink() {}
930
931Error XPSSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
932 SkAutoTUnref<SkDocument> doc(SkDocument::CreateXPS(dst));
933 if (!doc) {
halcanary96fcdcc2015-08-27 07:41:13 -0700934 return "SkDocument::CreateXPS() returned nullptr";
halcanary47ef4d52015-03-03 09:13:09 -0800935 }
936 return draw_skdocument(src, doc.get(), dst);
937}
mtklein748ca3b2015-01-15 10:56:12 -0800938/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
939
mtklein9c3f17d2015-01-28 11:35:18 -0800940SKPSink::SKPSink() {}
941
mtkleinb9eb4ac2015-02-02 18:26:03 -0800942Error SKPSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
mtklein9c3f17d2015-01-28 11:35:18 -0800943 SkSize size;
944 size = src.size();
945 SkPictureRecorder recorder;
946 Error err = src.draw(recorder.beginRecording(size.width(), size.height()));
947 if (!err.isEmpty()) {
948 return err;
949 }
950 SkAutoTUnref<SkPicture> pic(recorder.endRecording());
951 pic->serialize(dst);
952 return "";
953}
954
955/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
956
mtklein8a4527e2015-01-31 20:00:58 -0800957SVGSink::SVGSink() {}
958
mtkleinb9eb4ac2015-02-02 18:26:03 -0800959Error SVGSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
halcanary385fe4d2015-08-26 13:07:48 -0700960 SkAutoTDelete<SkXMLWriter> xmlWriter(new SkXMLStreamWriter(dst));
fmalita2aafe6f2015-02-06 12:51:10 -0800961 SkAutoTUnref<SkCanvas> canvas(SkSVGCanvas::Create(
962 SkRect::MakeWH(SkIntToScalar(src.size().width()), SkIntToScalar(src.size().height())),
963 xmlWriter));
964 return src.draw(canvas);
mtklein8a4527e2015-01-31 20:00:58 -0800965}
966
967/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
968
mtklein748ca3b2015-01-15 10:56:12 -0800969RasterSink::RasterSink(SkColorType colorType) : fColorType(colorType) {}
970
mtkleinb9eb4ac2015-02-02 18:26:03 -0800971Error RasterSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString*) const {
mtkleinf4ba3212015-01-28 15:32:24 -0800972 const SkISize size = src.size();
mtklein748ca3b2015-01-15 10:56:12 -0800973 // If there's an appropriate alpha type for this color type, use it, otherwise use premul.
974 SkAlphaType alphaType = kPremul_SkAlphaType;
975 (void)SkColorTypeValidateAlphaType(fColorType, alphaType, &alphaType);
976
mtkleinc8be09a2016-01-04 18:56:57 -0800977 SkMallocPixelRef::ZeroedPRFactory factory;
978 dst->allocPixels(SkImageInfo::Make(size.width(), size.height(), fColorType, alphaType),
979 &factory,
980 nullptr/*colortable*/);
mtklein748ca3b2015-01-15 10:56:12 -0800981 SkCanvas canvas(*dst);
982 return src.draw(&canvas);
983}
984
985/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
986
mtkleina16e69e2015-05-05 11:38:45 -0700987// Handy for front-patching a Src. Do whatever up-front work you need, then call draw_to_canvas(),
mtkleine44b5082015-05-07 10:53:34 -0700988// passing the Sink draw() arguments, a size, and a function draws into an SkCanvas.
mtkleina16e69e2015-05-05 11:38:45 -0700989// Several examples below.
990
msarett62d3b102015-12-10 15:14:27 -0800991static Error draw_to_canvas(Sink* sink, SkBitmap* bitmap, SkWStream* stream, SkString* log,
mtklein64593522015-11-12 10:41:05 -0800992 SkISize size, std::function<Error(SkCanvas*)> draw) {
mtkleina16e69e2015-05-05 11:38:45 -0700993 class ProxySrc : public Src {
994 public:
msarett62d3b102015-12-10 15:14:27 -0800995 ProxySrc(SkISize size, std::function<Error(SkCanvas*)> draw) : fSize(size), fDraw(draw) {}
mtkleina16e69e2015-05-05 11:38:45 -0700996 Error draw(SkCanvas* canvas) const override { return fDraw(canvas); }
msarett62d3b102015-12-10 15:14:27 -0800997 Name name() const override { sk_throw(); return ""; } // Won't be called.
mtkleina16e69e2015-05-05 11:38:45 -0700998 SkISize size() const override { return fSize; }
999 private:
mtklein64593522015-11-12 10:41:05 -08001000 SkISize fSize;
1001 std::function<Error(SkCanvas*)> fDraw;
mtkleina16e69e2015-05-05 11:38:45 -07001002 };
msarett62d3b102015-12-10 15:14:27 -08001003 return sink->draw(ProxySrc(size, draw), bitmap, stream, log);
mtkleina16e69e2015-05-05 11:38:45 -07001004}
1005
1006/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1007
mtkleind603b222015-02-17 11:13:33 -08001008static SkISize auto_compute_translate(SkMatrix* matrix, int srcW, int srcH) {
1009 SkRect bounds = SkRect::MakeIWH(srcW, srcH);
1010 matrix->mapRect(&bounds);
1011 matrix->postTranslate(-bounds.x(), -bounds.y());
1012 return SkISize::Make(SkScalarRoundToInt(bounds.width()), SkScalarRoundToInt(bounds.height()));
1013}
1014
msarett62d3b102015-12-10 15:14:27 -08001015ViaMatrix::ViaMatrix(SkMatrix matrix, Sink* sink) : Via(sink), fMatrix(matrix) {}
mtklein748ca3b2015-01-15 10:56:12 -08001016
mtkleinb9eb4ac2015-02-02 18:26:03 -08001017Error ViaMatrix::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
mtkleina16e69e2015-05-05 11:38:45 -07001018 SkMatrix matrix = fMatrix;
1019 SkISize size = auto_compute_translate(&matrix, src.size().width(), src.size().height());
msarett62d3b102015-12-10 15:14:27 -08001020 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) {
mtkleina16e69e2015-05-05 11:38:45 -07001021 canvas->concat(matrix);
1022 return src.draw(canvas);
1023 });
mtklein748ca3b2015-01-15 10:56:12 -08001024}
1025
mtkleind603b222015-02-17 11:13:33 -08001026// Undoes any flip or 90 degree rotate without changing the scale of the bitmap.
1027// This should be pixel-preserving.
msarett62d3b102015-12-10 15:14:27 -08001028ViaUpright::ViaUpright(SkMatrix matrix, Sink* sink) : Via(sink), fMatrix(matrix) {}
mtkleind603b222015-02-17 11:13:33 -08001029
1030Error ViaUpright::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1031 Error err = fSink->draw(src, bitmap, stream, log);
1032 if (!err.isEmpty()) {
1033 return err;
1034 }
1035
1036 SkMatrix inverse;
1037 if (!fMatrix.rectStaysRect() || !fMatrix.invert(&inverse)) {
1038 return "Cannot upright --matrix.";
1039 }
1040 SkMatrix upright = SkMatrix::I();
1041 upright.setScaleX(SkScalarSignAsScalar(inverse.getScaleX()));
1042 upright.setScaleY(SkScalarSignAsScalar(inverse.getScaleY()));
1043 upright.setSkewX(SkScalarSignAsScalar(inverse.getSkewX()));
1044 upright.setSkewY(SkScalarSignAsScalar(inverse.getSkewY()));
1045
1046 SkBitmap uprighted;
1047 SkISize size = auto_compute_translate(&upright, bitmap->width(), bitmap->height());
1048 uprighted.allocPixels(bitmap->info().makeWH(size.width(), size.height()));
1049
1050 SkCanvas canvas(uprighted);
1051 canvas.concat(upright);
1052 SkPaint paint;
1053 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
1054 canvas.drawBitmap(*bitmap, 0, 0, &paint);
1055
1056 *bitmap = uprighted;
1057 bitmap->lockPixels();
1058 return "";
1059}
1060
mtklein748ca3b2015-01-15 10:56:12 -08001061/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1062
mtkleinb9eb4ac2015-02-02 18:26:03 -08001063Error ViaPipe::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
mtkleina16e69e2015-05-05 11:38:45 -07001064 auto size = src.size();
msarett62d3b102015-12-10 15:14:27 -08001065 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) {
mtkleina16e69e2015-05-05 11:38:45 -07001066 PipeController controller(canvas, &SkImageDecoder::DecodeMemory);
1067 SkGPipeWriter pipe;
reed451af502015-08-19 08:18:04 -07001068 const uint32_t kFlags = 0;
mtkleina16e69e2015-05-05 11:38:45 -07001069 return src.draw(pipe.startRecording(&controller, kFlags, size.width(), size.height()));
1070 });
mtklein748ca3b2015-01-15 10:56:12 -08001071}
1072
mtklein2e2ea382015-10-16 10:29:41 -07001073Error ViaRemote::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
msarett62d3b102015-12-10 15:14:27 -08001074 return draw_to_canvas(fSink, bitmap, stream, log, src.size(), [&](SkCanvas* target) {
mtklein479fe772015-10-21 12:34:01 -07001075 SkAutoTDelete<SkRemote::Encoder> decoder(SkRemote::NewDecoder(target));
1076 SkAutoTDelete<SkRemote::Encoder> cache(fCache ? SkRemote::NewCachingEncoder(decoder)
1077 : nullptr);
1078 SkAutoTDelete<SkCanvas> canvas(SkRemote::NewCanvas(cache ? cache : decoder));
1079 return src.draw(canvas);
mtklein2e2ea382015-10-16 10:29:41 -07001080 });
1081}
1082
mtklein748ca3b2015-01-15 10:56:12 -08001083/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
mtkleina16e69e2015-05-05 11:38:45 -07001084
mtkleina16e69e2015-05-05 11:38:45 -07001085Error ViaSerialization::draw(
1086 const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
mtklein748ca3b2015-01-15 10:56:12 -08001087 // Record our Src into a picture.
mtkleina16e69e2015-05-05 11:38:45 -07001088 auto size = src.size();
mtklein748ca3b2015-01-15 10:56:12 -08001089 SkPictureRecorder recorder;
mtkleina16e69e2015-05-05 11:38:45 -07001090 Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
1091 SkIntToScalar(size.height())));
mtklein748ca3b2015-01-15 10:56:12 -08001092 if (!err.isEmpty()) {
1093 return err;
1094 }
1095 SkAutoTUnref<SkPicture> pic(recorder.endRecording());
1096
1097 // Serialize it and then deserialize it.
1098 SkDynamicMemoryWStream wStream;
1099 pic->serialize(&wStream);
scroggoa1193e42015-01-21 12:09:53 -08001100 SkAutoTDelete<SkStream> rStream(wStream.detachAsStream());
mtkleinb3e5e4d2015-03-25 13:13:43 -07001101 SkAutoTUnref<SkPicture> deserialized(SkPicture::CreateFromStream(rStream, &lazy_decode_bitmap));
mtklein748ca3b2015-01-15 10:56:12 -08001102
msarett62d3b102015-12-10 15:14:27 -08001103 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) {
mtkleina16e69e2015-05-05 11:38:45 -07001104 canvas->drawPicture(deserialized);
1105 return "";
1106 });
mtklein748ca3b2015-01-15 10:56:12 -08001107}
1108
1109/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1110
msarett62d3b102015-12-10 15:14:27 -08001111ViaTiles::ViaTiles(int w, int h, SkBBHFactory* factory, Sink* sink)
1112 : Via(sink)
mtklein78829242015-05-06 07:54:07 -07001113 , fW(w)
mtklein748ca3b2015-01-15 10:56:12 -08001114 , fH(h)
mtklein78829242015-05-06 07:54:07 -07001115 , fFactory(factory) {}
mtklein748ca3b2015-01-15 10:56:12 -08001116
mtkleinb9eb4ac2015-02-02 18:26:03 -08001117Error ViaTiles::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
mtkleina16e69e2015-05-05 11:38:45 -07001118 auto size = src.size();
mtklein748ca3b2015-01-15 10:56:12 -08001119 SkPictureRecorder recorder;
mtkleina16e69e2015-05-05 11:38:45 -07001120 Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
1121 SkIntToScalar(size.height()),
1122 fFactory.get()));
mtklein748ca3b2015-01-15 10:56:12 -08001123 if (!err.isEmpty()) {
1124 return err;
1125 }
mtkleinb7e8d692015-04-07 08:30:32 -07001126 SkAutoTUnref<SkPicture> pic(recorder.endRecordingAsPicture());
mtklein748ca3b2015-01-15 10:56:12 -08001127
msarett62d3b102015-12-10 15:14:27 -08001128 return draw_to_canvas(fSink, bitmap, stream, log, src.size(), [&](SkCanvas* canvas) {
mtkleina16e69e2015-05-05 11:38:45 -07001129 const int xTiles = (size.width() + fW - 1) / fW,
1130 yTiles = (size.height() + fH - 1) / fH;
1131 SkMultiPictureDraw mpd(xTiles*yTiles);
1132 SkTDArray<SkSurface*> surfaces;
1133 surfaces.setReserve(xTiles*yTiles);
mtklein748ca3b2015-01-15 10:56:12 -08001134
mtkleina16e69e2015-05-05 11:38:45 -07001135 SkImageInfo info = canvas->imageInfo().makeWH(fW, fH);
1136 for (int j = 0; j < yTiles; j++) {
1137 for (int i = 0; i < xTiles; i++) {
1138 // This lets our ultimate Sink determine the best kind of surface.
1139 // E.g., if it's a GpuSink, the surfaces and images are textures.
1140 SkSurface* s = canvas->newSurface(info);
1141 if (!s) {
1142 s = SkSurface::NewRaster(info); // Some canvases can't create surfaces.
mtklein748ca3b2015-01-15 10:56:12 -08001143 }
mtkleina16e69e2015-05-05 11:38:45 -07001144 surfaces.push(s);
1145 SkCanvas* c = s->getCanvas();
1146 c->translate(SkIntToScalar(-i * fW),
1147 SkIntToScalar(-j * fH)); // Line up the canvas with this tile.
1148 mpd.add(c, pic);
mtklein748ca3b2015-01-15 10:56:12 -08001149 }
mtklein748ca3b2015-01-15 10:56:12 -08001150 }
mtkleina16e69e2015-05-05 11:38:45 -07001151 mpd.draw();
1152 for (int j = 0; j < yTiles; j++) {
1153 for (int i = 0; i < xTiles; i++) {
1154 SkAutoTUnref<SkImage> image(surfaces[i+xTiles*j]->newImageSnapshot());
1155 canvas->drawImage(image, SkIntToScalar(i*fW), SkIntToScalar(j*fH));
1156 }
1157 }
1158 surfaces.unrefAll();
1159 return "";
1160 });
mtklein748ca3b2015-01-15 10:56:12 -08001161}
1162
mtkleinb7e8d692015-04-07 08:30:32 -07001163/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1164
mtkleinb7e8d692015-04-07 08:30:32 -07001165// Draw the Src into two pictures, then draw the second picture into the wrapped Sink.
1166// This tests that any shortcuts we may take while recording that second picture are legal.
1167Error ViaSecondPicture::draw(
1168 const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
mtkleina16e69e2015-05-05 11:38:45 -07001169 auto size = src.size();
msarett62d3b102015-12-10 15:14:27 -08001170 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error {
mtkleina16e69e2015-05-05 11:38:45 -07001171 SkPictureRecorder recorder;
1172 SkAutoTUnref<SkPicture> pic;
1173 for (int i = 0; i < 2; i++) {
1174 Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
1175 SkIntToScalar(size.height())));
1176 if (!err.isEmpty()) {
1177 return err;
mtkleinb7e8d692015-04-07 08:30:32 -07001178 }
mtkleina16e69e2015-05-05 11:38:45 -07001179 pic.reset(recorder.endRecordingAsPicture());
mtkleinb7e8d692015-04-07 08:30:32 -07001180 }
mtkleina16e69e2015-05-05 11:38:45 -07001181 canvas->drawPicture(pic);
1182 return "";
1183 });
mtkleinb7e8d692015-04-07 08:30:32 -07001184}
1185
mtkleind31c13d2015-05-05 12:59:56 -07001186/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1187
mtklein6fbf4b32015-05-06 11:35:40 -07001188// Draw the Src twice. This can help exercise caching.
1189Error ViaTwice::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
msarett62d3b102015-12-10 15:14:27 -08001190 return draw_to_canvas(fSink, bitmap, stream, log, src.size(), [&](SkCanvas* canvas) -> Error {
mtklein6fbf4b32015-05-06 11:35:40 -07001191 for (int i = 0; i < 2; i++) {
1192 SkAutoCanvasRestore acr(canvas, true/*save now*/);
1193 canvas->clear(SK_ColorTRANSPARENT);
1194 Error err = src.draw(canvas);
1195 if (err.isEmpty()) {
1196 return err;
1197 }
1198 }
1199 return "";
1200 });
1201}
1202
1203/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1204
mtkleind31c13d2015-05-05 12:59:56 -07001205// This is like SkRecords::Draw, in that it plays back SkRecords ops into a Canvas.
1206// Unlike SkRecords::Draw, it builds a single-op sub-picture out of each Draw-type op.
1207// This is an only-slightly-exaggerated simluation of Blink's Slimming Paint pictures.
1208struct DrawsAsSingletonPictures {
1209 SkCanvas* fCanvas;
mtkleind2baa902015-07-07 09:43:28 -07001210 const SkDrawableList& fDrawables;
mtkleind31c13d2015-05-05 12:59:56 -07001211
mtkleind31c13d2015-05-05 12:59:56 -07001212 template <typename T>
1213 void draw(const T& op, SkCanvas* canvas) {
1214 // We must pass SkMatrix::I() as our initial matrix.
1215 // By default SkRecords::Draw() uses the canvas' matrix as its initial matrix,
1216 // which would have the funky effect of applying transforms over and over.
mtkleind2baa902015-07-07 09:43:28 -07001217 SkRecords::Draw d(canvas, nullptr, fDrawables.begin(), fDrawables.count(), &SkMatrix::I());
1218 d(op);
mtkleind31c13d2015-05-05 12:59:56 -07001219 }
1220
mtklein449d9b72015-09-28 10:33:02 -07001221 // Draws get their own picture.
mtkleind31c13d2015-05-05 12:59:56 -07001222 template <typename T>
mtklein449d9b72015-09-28 10:33:02 -07001223 SK_WHEN(T::kTags & SkRecords::kDraw_Tag, void) operator()(const T& op) {
mtkleind31c13d2015-05-05 12:59:56 -07001224 SkPictureRecorder rec;
1225 this->draw(op, rec.beginRecording(SkRect::MakeLargest()));
1226 SkAutoTUnref<SkPicture> pic(rec.endRecordingAsPicture());
1227 fCanvas->drawPicture(pic);
1228 }
1229
mtklein449d9b72015-09-28 10:33:02 -07001230 // We'll just issue non-draws directly.
mtkleind31c13d2015-05-05 12:59:56 -07001231 template <typename T>
mtklein449d9b72015-09-28 10:33:02 -07001232 skstd::enable_if_t<!(T::kTags & SkRecords::kDraw_Tag), void> operator()(const T& op) {
1233 this->draw(op, fCanvas);
1234 }
mtkleind31c13d2015-05-05 12:59:56 -07001235};
1236
mtkleind31c13d2015-05-05 12:59:56 -07001237// Record Src into a picture, then record it into a macro picture with a sub-picture for each draw.
1238// Then play back that macro picture into our wrapped sink.
1239Error ViaSingletonPictures::draw(
1240 const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
1241 auto size = src.size();
msarett62d3b102015-12-10 15:14:27 -08001242 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error {
mtkleind31c13d2015-05-05 12:59:56 -07001243 // Use low-level (Skia-private) recording APIs so we can read the SkRecord.
1244 SkRecord skr;
1245 SkRecorder recorder(&skr, size.width(), size.height());
1246 Error err = src.draw(&recorder);
1247 if (!err.isEmpty()) {
1248 return err;
1249 }
1250
1251 // Record our macro-picture, with each draw op as its own sub-picture.
1252 SkPictureRecorder macroRec;
1253 SkCanvas* macroCanvas = macroRec.beginRecording(SkIntToScalar(size.width()),
1254 SkIntToScalar(size.height()));
mtkleind2baa902015-07-07 09:43:28 -07001255
1256 SkAutoTDelete<SkDrawableList> drawables(recorder.detachDrawableList());
1257 const SkDrawableList empty;
1258
1259 DrawsAsSingletonPictures drawsAsSingletonPictures = {
1260 macroCanvas,
1261 drawables ? *drawables : empty,
1262 };
mtkleinc6ad06a2015-08-19 09:51:00 -07001263 for (int i = 0; i < skr.count(); i++) {
mtkleind31c13d2015-05-05 12:59:56 -07001264 skr.visit<void>(i, drawsAsSingletonPictures);
1265 }
1266 SkAutoTUnref<SkPicture> macroPic(macroRec.endRecordingAsPicture());
1267
1268 canvas->drawPicture(macroPic);
1269 return "";
1270 });
1271}
1272
mtklein748ca3b2015-01-15 10:56:12 -08001273} // namespace DM