DMSrcSink.cpp revision 45420a945cfce1b83da954ab5fcb63516f646c0f
1/* 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 8#include "DMSrcSink.h" 9#include "Resources.h" 10#include "SkAndroidCodec.h" 11#include "SkCodec.h" 12#include "SkCodecImageGenerator.h" 13#include "SkColorSpace.h" 14#include "SkColorSpace_Base.h" 15#include "SkColorSpaceXform.h" 16#include "SkCommonFlags.h" 17#include "SkData.h" 18#include "SkDocument.h" 19#include "SkError.h" 20#include "SkImageGenerator.h" 21#include "SkImageGeneratorCG.h" 22#include "SkImageGeneratorWIC.h" 23#include "SkMallocPixelRef.h" 24#include "SkMultiPictureDraw.h" 25#include "SkNullCanvas.h" 26#include "SkOSFile.h" 27#include "SkOpts.h" 28#include "SkPictureData.h" 29#include "SkPictureRecorder.h" 30#include "SkRandom.h" 31#include "SkRecordDraw.h" 32#include "SkRecorder.h" 33#include "SkSVGCanvas.h" 34#include "SkStream.h" 35#include "SkTLogic.h" 36#include "SkXMLWriter.h" 37#include "SkSwizzler.h" 38#include <functional> 39 40#if defined(SK_BUILD_FOR_WIN) 41 #include "SkAutoCoInitialize.h" 42#endif 43 44#if !defined(GOOGLE3) 45 #include "qcms.h" 46#endif 47 48DEFINE_bool(multiPage, false, "For document-type backends, render the source" 49 " into multiple pages"); 50DEFINE_bool(RAW_threading, true, "Allow RAW decodes to run on multiple threads?"); 51 52using sk_gpu_test::GrContextFactory; 53 54namespace DM { 55 56GMSrc::GMSrc(skiagm::GMRegistry::Factory factory) : fFactory(factory) {} 57 58Error GMSrc::draw(SkCanvas* canvas) const { 59 SkAutoTDelete<skiagm::GM> gm(fFactory(nullptr)); 60 canvas->concat(gm->getInitialTransform()); 61 gm->draw(canvas); 62 return ""; 63} 64 65SkISize GMSrc::size() const { 66 SkAutoTDelete<skiagm::GM> gm(fFactory(nullptr)); 67 return gm->getISize(); 68} 69 70Name GMSrc::name() const { 71 SkAutoTDelete<skiagm::GM> gm(fFactory(nullptr)); 72 return gm->getName(); 73} 74 75void GMSrc::modifyGrContextOptions(GrContextOptions* options) const { 76 SkAutoTDelete<skiagm::GM> gm(fFactory(nullptr)); 77 gm->modifyGrContextOptions(options); 78} 79 80/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 81 82BRDSrc::BRDSrc(Path path, Mode mode, CodecSrc::DstColorType dstColorType, uint32_t sampleSize) 83 : fPath(path) 84 , fMode(mode) 85 , fDstColorType(dstColorType) 86 , fSampleSize(sampleSize) 87{} 88 89bool BRDSrc::veto(SinkFlags flags) const { 90 // No need to test to non-raster or indirect backends. 91 return flags.type != SinkFlags::kRaster 92 || flags.approach != SinkFlags::kDirect; 93} 94 95static SkBitmapRegionDecoder* create_brd(Path path) { 96 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(path.c_str())); 97 if (!encoded) { 98 return NULL; 99 } 100 return SkBitmapRegionDecoder::Create(encoded, SkBitmapRegionDecoder::kAndroidCodec_Strategy); 101} 102 103Error BRDSrc::draw(SkCanvas* canvas) const { 104 SkColorType colorType = canvas->imageInfo().colorType(); 105 if (kRGB_565_SkColorType == colorType && 106 CodecSrc::kGetFromCanvas_DstColorType != fDstColorType) { 107 return Error::Nonfatal("Testing non-565 to 565 is uninteresting."); 108 } 109 switch (fDstColorType) { 110 case CodecSrc::kGetFromCanvas_DstColorType: 111 break; 112 case CodecSrc::kIndex8_Always_DstColorType: 113 colorType = kIndex_8_SkColorType; 114 break; 115 case CodecSrc::kGrayscale_Always_DstColorType: 116 colorType = kGray_8_SkColorType; 117 break; 118 default: 119 SkASSERT(false); 120 break; 121 } 122 123 SkAutoTDelete<SkBitmapRegionDecoder> brd(create_brd(fPath)); 124 if (nullptr == brd.get()) { 125 return Error::Nonfatal(SkStringPrintf("Could not create brd for %s.", fPath.c_str())); 126 } 127 128 if (!brd->conversionSupported(colorType)) { 129 return Error::Nonfatal("Cannot convert to color type."); 130 } 131 132 const uint32_t width = brd->width(); 133 const uint32_t height = brd->height(); 134 // Visually inspecting very small output images is not necessary. 135 if ((width / fSampleSize <= 10 || height / fSampleSize <= 10) && 1 != fSampleSize) { 136 return Error::Nonfatal("Scaling very small images is uninteresting."); 137 } 138 switch (fMode) { 139 case kFullImage_Mode: { 140 SkBitmap bitmap; 141 if (!brd->decodeRegion(&bitmap, nullptr, SkIRect::MakeXYWH(0, 0, width, height), 142 fSampleSize, colorType, false)) { 143 return "Cannot decode (full) region."; 144 } 145 if (colorType != bitmap.colorType()) { 146 return Error::Nonfatal("Cannot convert to color type."); 147 } 148 canvas->drawBitmap(bitmap, 0, 0); 149 return ""; 150 } 151 case kDivisor_Mode: { 152 const uint32_t divisor = 2; 153 if (width < divisor || height < divisor) { 154 return Error::Nonfatal("Divisor is larger than image dimension."); 155 } 156 157 // Use a border to test subsets that extend outside the image. 158 // We will not allow the border to be larger than the image dimensions. Allowing 159 // these large borders causes off by one errors that indicate a problem with the 160 // test suite, not a problem with the implementation. 161 const uint32_t maxBorder = SkTMin(width, height) / (fSampleSize * divisor); 162 const uint32_t scaledBorder = SkTMin(5u, maxBorder); 163 const uint32_t unscaledBorder = scaledBorder * fSampleSize; 164 165 // We may need to clear the canvas to avoid uninitialized memory. 166 // Assume we are scaling a 780x780 image with sampleSize = 8. 167 // The output image should be 97x97. 168 // Each subset will be 390x390. 169 // Each scaled subset be 48x48. 170 // Four scaled subsets will only fill a 96x96 image. 171 // The bottom row and last column will not be touched. 172 // This is an unfortunate result of our rounding rules when scaling. 173 // Maybe we need to consider testing scaled subsets without trying to 174 // combine them to match the full scaled image? Or maybe this is the 175 // best we can do? 176 canvas->clear(0); 177 178 for (uint32_t x = 0; x < divisor; x++) { 179 for (uint32_t y = 0; y < divisor; y++) { 180 // Calculate the subset dimensions 181 uint32_t subsetWidth = width / divisor; 182 uint32_t subsetHeight = height / divisor; 183 const int left = x * subsetWidth; 184 const int top = y * subsetHeight; 185 186 // Increase the size of the last subset in each row or column, when the 187 // divisor does not divide evenly into the image dimensions 188 subsetWidth += (x + 1 == divisor) ? (width % divisor) : 0; 189 subsetHeight += (y + 1 == divisor) ? (height % divisor) : 0; 190 191 // Increase the size of the subset in order to have a border on each side 192 const int decodeLeft = left - unscaledBorder; 193 const int decodeTop = top - unscaledBorder; 194 const uint32_t decodeWidth = subsetWidth + unscaledBorder * 2; 195 const uint32_t decodeHeight = subsetHeight + unscaledBorder * 2; 196 SkBitmap bitmap; 197 if (!brd->decodeRegion(&bitmap, nullptr, SkIRect::MakeXYWH(decodeLeft, 198 decodeTop, decodeWidth, decodeHeight), fSampleSize, colorType, false)) { 199 return "Cannot decode region."; 200 } 201 if (colorType != bitmap.colorType()) { 202 return Error::Nonfatal("Cannot convert to color type."); 203 } 204 205 canvas->drawBitmapRect(bitmap, 206 SkRect::MakeXYWH((SkScalar) scaledBorder, (SkScalar) scaledBorder, 207 (SkScalar) (subsetWidth / fSampleSize), 208 (SkScalar) (subsetHeight / fSampleSize)), 209 SkRect::MakeXYWH((SkScalar) (left / fSampleSize), 210 (SkScalar) (top / fSampleSize), 211 (SkScalar) (subsetWidth / fSampleSize), 212 (SkScalar) (subsetHeight / fSampleSize)), 213 nullptr); 214 } 215 } 216 return ""; 217 } 218 default: 219 SkASSERT(false); 220 return "Error: Should not be reached."; 221 } 222} 223 224SkISize BRDSrc::size() const { 225 SkAutoTDelete<SkBitmapRegionDecoder> brd(create_brd(fPath)); 226 if (brd) { 227 return SkISize::Make(SkTMax(1, brd->width() / (int) fSampleSize), 228 SkTMax(1, brd->height() / (int) fSampleSize)); 229 } 230 return SkISize::Make(0, 0); 231} 232 233static SkString get_scaled_name(const Path& path, float scale) { 234 return SkStringPrintf("%s_%.3f", SkOSPath::Basename(path.c_str()).c_str(), scale); 235} 236 237Name BRDSrc::name() const { 238 // We will replicate the names used by CodecSrc so that images can 239 // be compared in Gold. 240 if (1 == fSampleSize) { 241 return SkOSPath::Basename(fPath.c_str()); 242 } 243 return get_scaled_name(fPath, 1.0f / (float) fSampleSize); 244} 245 246/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 247 248static bool serial_from_path_name(const SkString& path) { 249 if (!FLAGS_RAW_threading) { 250 static const char* const exts[] = { 251 "arw", "cr2", "dng", "nef", "nrw", "orf", "raf", "rw2", "pef", "srw", 252 "ARW", "CR2", "DNG", "NEF", "NRW", "ORF", "RAF", "RW2", "PEF", "SRW", 253 }; 254 const char* actualExt = strrchr(path.c_str(), '.'); 255 if (actualExt) { 256 actualExt++; 257 for (auto* ext : exts) { 258 if (0 == strcmp(ext, actualExt)) { 259 return true; 260 } 261 } 262 } 263 } 264 return false; 265} 266 267CodecSrc::CodecSrc(Path path, Mode mode, DstColorType dstColorType, SkAlphaType dstAlphaType, 268 float scale) 269 : fPath(path) 270 , fMode(mode) 271 , fDstColorType(dstColorType) 272 , fDstAlphaType(dstAlphaType) 273 , fScale(scale) 274 , fRunSerially(serial_from_path_name(path)) 275{} 276 277bool CodecSrc::veto(SinkFlags flags) const { 278 // Test to direct raster backends (8888 and 565). 279 return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDirect; 280} 281 282// Allows us to test decodes to non-native 8888. 283static void swap_rb_if_necessary(SkBitmap& bitmap, CodecSrc::DstColorType dstColorType) { 284 if (CodecSrc::kNonNative8888_Always_DstColorType != dstColorType) { 285 return; 286 } 287 288 for (int y = 0; y < bitmap.height(); y++) { 289 uint32_t* row = (uint32_t*) bitmap.getAddr(0, y); 290 SkOpts::RGBA_to_BGRA(row, row, bitmap.width()); 291 } 292} 293 294// FIXME: Currently we cannot draw unpremultiplied sources. skbug.com/3338 and skbug.com/3339. 295// This allows us to still test unpremultiplied decodes. 296static void premultiply_if_necessary(SkBitmap& bitmap) { 297 if (kUnpremul_SkAlphaType != bitmap.alphaType()) { 298 return; 299 } 300 301 switch (bitmap.colorType()) { 302 case kN32_SkColorType: 303 for (int y = 0; y < bitmap.height(); y++) { 304 uint32_t* row = (uint32_t*) bitmap.getAddr(0, y); 305 SkOpts::RGBA_to_rgbA(row, row, bitmap.width()); 306 } 307 break; 308 case kIndex_8_SkColorType: { 309 SkColorTable* colorTable = bitmap.getColorTable(); 310 SkPMColor* colorPtr = const_cast<SkPMColor*>(colorTable->readColors()); 311 SkOpts::RGBA_to_rgbA(colorPtr, colorPtr, colorTable->count()); 312 break; 313 } 314 default: 315 // No need to premultiply kGray or k565 outputs. 316 break; 317 } 318 319 // In the kIndex_8 case, the canvas won't even try to draw unless we mark the 320 // bitmap as kPremul. 321 bitmap.setAlphaType(kPremul_SkAlphaType); 322} 323 324static bool get_decode_info(SkImageInfo* decodeInfo, SkColorType canvasColorType, 325 CodecSrc::DstColorType dstColorType, SkAlphaType dstAlphaType) { 326 switch (dstColorType) { 327 case CodecSrc::kIndex8_Always_DstColorType: 328 if (kRGB_565_SkColorType == canvasColorType) { 329 return false; 330 } 331 *decodeInfo = decodeInfo->makeColorType(kIndex_8_SkColorType); 332 break; 333 case CodecSrc::kGrayscale_Always_DstColorType: 334 if (kRGB_565_SkColorType == canvasColorType) { 335 return false; 336 } 337 *decodeInfo = decodeInfo->makeColorType(kGray_8_SkColorType); 338 break; 339 case CodecSrc::kNonNative8888_Always_DstColorType: 340 if (kRGB_565_SkColorType == canvasColorType) { 341 return false; 342 } 343#ifdef SK_PMCOLOR_IS_RGBA 344 *decodeInfo = decodeInfo->makeColorType(kBGRA_8888_SkColorType); 345#else 346 *decodeInfo = decodeInfo->makeColorType(kRGBA_8888_SkColorType); 347#endif 348 break; 349 default: 350 if (kRGB_565_SkColorType == canvasColorType && 351 kOpaque_SkAlphaType != decodeInfo->alphaType()) { 352 return false; 353 } 354 *decodeInfo = decodeInfo->makeColorType(canvasColorType); 355 break; 356 } 357 358 *decodeInfo = decodeInfo->makeAlphaType(dstAlphaType); 359 return true; 360} 361 362static void draw_to_canvas(SkCanvas* canvas, const SkImageInfo& info, void* pixels, size_t rowBytes, 363 SkPMColor* colorPtr, int colorCount, CodecSrc::DstColorType dstColorType, 364 SkScalar left = 0, SkScalar top = 0) { 365 SkAutoTUnref<SkColorTable> colorTable(new SkColorTable(colorPtr, colorCount)); 366 SkBitmap bitmap; 367 bitmap.installPixels(info, pixels, rowBytes, colorTable.get(), nullptr, nullptr); 368 premultiply_if_necessary(bitmap); 369 swap_rb_if_necessary(bitmap, dstColorType); 370 canvas->drawBitmap(bitmap, left, top); 371} 372 373Error CodecSrc::draw(SkCanvas* canvas) const { 374 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); 375 if (!encoded) { 376 return SkStringPrintf("Couldn't read %s.", fPath.c_str()); 377 } 378 379 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded)); 380 if (nullptr == codec.get()) { 381 return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str()); 382 } 383 384 SkImageInfo decodeInfo = codec->getInfo(); 385 if (!get_decode_info(&decodeInfo, canvas->imageInfo().colorType(), fDstColorType, 386 fDstAlphaType)) { 387 return Error::Nonfatal("Testing non-565 to 565 is uninteresting."); 388 } 389 390 // Try to scale the image if it is desired 391 SkISize size = codec->getScaledDimensions(fScale); 392 if (size == decodeInfo.dimensions() && 1.0f != fScale) { 393 return Error::Nonfatal("Test without scaling is uninteresting."); 394 } 395 396 // Visually inspecting very small output images is not necessary. We will 397 // cover these cases in unit testing. 398 if ((size.width() <= 10 || size.height() <= 10) && 1.0f != fScale) { 399 return Error::Nonfatal("Scaling very small images is uninteresting."); 400 } 401 decodeInfo = decodeInfo.makeWH(size.width(), size.height()); 402 403 const int bpp = SkColorTypeBytesPerPixel(decodeInfo.colorType()); 404 const size_t rowBytes = size.width() * bpp; 405 SkAutoMalloc pixels(decodeInfo.getSafeSize(rowBytes)); 406 SkPMColor colorPtr[256]; 407 int colorCount = 256; 408 409 SkCodec::Options options; 410 if (kCodecZeroInit_Mode == fMode) { 411 memset(pixels.get(), 0, size.height() * rowBytes); 412 options.fZeroInitialized = SkCodec::kYes_ZeroInitialized; 413 } 414 415 SkImageInfo bitmapInfo = decodeInfo; 416 if (kRGBA_8888_SkColorType == decodeInfo.colorType() || 417 kBGRA_8888_SkColorType == decodeInfo.colorType()) { 418 bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType); 419 } 420 421 switch (fMode) { 422 case kCodecZeroInit_Mode: 423 case kCodec_Mode: { 424 switch (codec->getPixels(decodeInfo, pixels.get(), rowBytes, &options, 425 colorPtr, &colorCount)) { 426 case SkCodec::kSuccess: 427 // We consider incomplete to be valid, since we should still decode what is 428 // available. 429 case SkCodec::kIncompleteInput: 430 break; 431 default: 432 // Everything else is considered a failure. 433 return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str()); 434 } 435 436 draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, colorPtr, colorCount, 437 fDstColorType); 438 break; 439 } 440 case kScanline_Mode: { 441 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, NULL, colorPtr, 442 &colorCount)) { 443 return "Could not start scanline decoder"; 444 } 445 446 void* dst = pixels.get(); 447 uint32_t height = decodeInfo.height(); 448 switch (codec->getScanlineOrder()) { 449 case SkCodec::kTopDown_SkScanlineOrder: 450 case SkCodec::kBottomUp_SkScanlineOrder: 451 case SkCodec::kNone_SkScanlineOrder: 452 // We do not need to check the return value. On an incomplete 453 // image, memory will be filled with a default value. 454 codec->getScanlines(dst, height, rowBytes); 455 break; 456 case SkCodec::kOutOfOrder_SkScanlineOrder: { 457 for (int y = 0; y < decodeInfo.height(); y++) { 458 int dstY = codec->outputScanline(y); 459 void* dstPtr = SkTAddOffset<void>(dst, rowBytes * dstY); 460 // We complete the loop, even if this call begins to fail 461 // due to an incomplete image. This ensures any uninitialized 462 // memory will be filled with the proper value. 463 codec->getScanlines(dstPtr, 1, rowBytes); 464 } 465 break; 466 } 467 } 468 469 draw_to_canvas(canvas, bitmapInfo, dst, rowBytes, colorPtr, colorCount, fDstColorType); 470 break; 471 } 472 case kStripe_Mode: { 473 const int height = decodeInfo.height(); 474 // This value is chosen arbitrarily. We exercise more cases by choosing a value that 475 // does not align with image blocks. 476 const int stripeHeight = 37; 477 const int numStripes = (height + stripeHeight - 1) / stripeHeight; 478 void* dst = pixels.get(); 479 480 // Decode odd stripes 481 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, nullptr, colorPtr, 482 &colorCount)) { 483 return "Could not start scanline decoder"; 484 } 485 486 // This mode was designed to test the new skip scanlines API in libjpeg-turbo. 487 // Jpegs have kTopDown_SkScanlineOrder, and at this time, it is not interesting 488 // to run this test for image types that do not have this scanline ordering. 489 // We only run this on Jpeg, which is always kTopDown. 490 SkASSERT(SkCodec::kTopDown_SkScanlineOrder == codec->getScanlineOrder()); 491 492 for (int i = 0; i < numStripes; i += 2) { 493 // Skip a stripe 494 const int linesToSkip = SkTMin(stripeHeight, height - i * stripeHeight); 495 codec->skipScanlines(linesToSkip); 496 497 // Read a stripe 498 const int startY = (i + 1) * stripeHeight; 499 const int linesToRead = SkTMin(stripeHeight, height - startY); 500 if (linesToRead > 0) { 501 codec->getScanlines(SkTAddOffset<void>(dst, rowBytes * startY), linesToRead, 502 rowBytes); 503 } 504 } 505 506 // Decode even stripes 507 const SkCodec::Result startResult = codec->startScanlineDecode(decodeInfo, nullptr, 508 colorPtr, &colorCount); 509 if (SkCodec::kSuccess != startResult) { 510 return "Failed to restart scanline decoder with same parameters."; 511 } 512 for (int i = 0; i < numStripes; i += 2) { 513 // Read a stripe 514 const int startY = i * stripeHeight; 515 const int linesToRead = SkTMin(stripeHeight, height - startY); 516 codec->getScanlines(SkTAddOffset<void>(dst, rowBytes * startY), linesToRead, 517 rowBytes); 518 519 // Skip a stripe 520 const int linesToSkip = SkTMin(stripeHeight, height - (i + 1) * stripeHeight); 521 if (linesToSkip > 0) { 522 codec->skipScanlines(linesToSkip); 523 } 524 } 525 526 draw_to_canvas(canvas, bitmapInfo, dst, rowBytes, colorPtr, colorCount, fDstColorType); 527 break; 528 } 529 case kCroppedScanline_Mode: { 530 const int width = decodeInfo.width(); 531 const int height = decodeInfo.height(); 532 // This value is chosen because, as we move across the image, it will sometimes 533 // align with the jpeg block sizes and it will sometimes not. This allows us 534 // to test interestingly different code paths in the implementation. 535 const int tileSize = 36; 536 537 SkCodec::Options opts; 538 SkIRect subset; 539 for (int x = 0; x < width; x += tileSize) { 540 subset = SkIRect::MakeXYWH(x, 0, SkTMin(tileSize, width - x), height); 541 opts.fSubset = ⊂ 542 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, &opts, 543 colorPtr, &colorCount)) { 544 return "Could not start scanline decoder."; 545 } 546 547 codec->getScanlines(SkTAddOffset<void>(pixels.get(), x * bpp), height, rowBytes); 548 } 549 550 draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, colorPtr, colorCount, 551 fDstColorType); 552 break; 553 } 554 case kSubset_Mode: { 555 // Arbitrarily choose a divisor. 556 int divisor = 2; 557 // Total width/height of the image. 558 const int W = codec->getInfo().width(); 559 const int H = codec->getInfo().height(); 560 if (divisor > W || divisor > H) { 561 return Error::Nonfatal(SkStringPrintf("Cannot codec subset: divisor %d is too big " 562 "for %s with dimensions (%d x %d)", divisor, 563 fPath.c_str(), W, H)); 564 } 565 // subset dimensions 566 // SkWebpCodec, the only one that supports subsets, requires even top/left boundaries. 567 const int w = SkAlign2(W / divisor); 568 const int h = SkAlign2(H / divisor); 569 SkIRect subset; 570 SkCodec::Options opts; 571 opts.fSubset = ⊂ 572 SkBitmap subsetBm; 573 // We will reuse pixel memory from bitmap. 574 void* dst = pixels.get(); 575 // Keep track of left and top (for drawing subsetBm into canvas). We could use 576 // fScale * x and fScale * y, but we want integers such that the next subset will start 577 // where the last one ended. So we'll add decodeInfo.width() and height(). 578 int left = 0; 579 for (int x = 0; x < W; x += w) { 580 int top = 0; 581 for (int y = 0; y < H; y+= h) { 582 // Do not make the subset go off the edge of the image. 583 const int preScaleW = SkTMin(w, W - x); 584 const int preScaleH = SkTMin(h, H - y); 585 subset.setXYWH(x, y, preScaleW, preScaleH); 586 // And scale 587 // FIXME: Should we have a version of getScaledDimensions that takes a subset 588 // into account? 589 const int scaledW = SkTMax(1, SkScalarRoundToInt(preScaleW * fScale)); 590 const int scaledH = SkTMax(1, SkScalarRoundToInt(preScaleH * fScale)); 591 decodeInfo = decodeInfo.makeWH(scaledW, scaledH); 592 SkImageInfo subsetBitmapInfo = bitmapInfo.makeWH(scaledW, scaledH); 593 size_t subsetRowBytes = subsetBitmapInfo.minRowBytes(); 594 const SkCodec::Result result = codec->getPixels(decodeInfo, dst, subsetRowBytes, 595 &opts, colorPtr, &colorCount); 596 switch (result) { 597 case SkCodec::kSuccess: 598 case SkCodec::kIncompleteInput: 599 break; 600 default: 601 return SkStringPrintf("subset codec failed to decode (%d, %d, %d, %d) " 602 "from %s with dimensions (%d x %d)\t error %d", 603 x, y, decodeInfo.width(), decodeInfo.height(), 604 fPath.c_str(), W, H, result); 605 } 606 draw_to_canvas(canvas, subsetBitmapInfo, dst, subsetRowBytes, colorPtr, 607 colorCount, fDstColorType, SkIntToScalar(left), 608 SkIntToScalar(top)); 609 610 // translate by the scaled height. 611 top += decodeInfo.height(); 612 } 613 // translate by the scaled width. 614 left += decodeInfo.width(); 615 } 616 return ""; 617 } 618 default: 619 SkASSERT(false); 620 return "Invalid fMode"; 621 } 622 return ""; 623} 624 625SkISize CodecSrc::size() const { 626 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); 627 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded)); 628 if (nullptr == codec) { 629 return SkISize::Make(0, 0); 630 } 631 return codec->getScaledDimensions(fScale); 632} 633 634Name CodecSrc::name() const { 635 if (1.0f == fScale) { 636 return SkOSPath::Basename(fPath.c_str()); 637 } 638 return get_scaled_name(fPath, fScale); 639} 640 641/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 642 643AndroidCodecSrc::AndroidCodecSrc(Path path, CodecSrc::DstColorType dstColorType, 644 SkAlphaType dstAlphaType, int sampleSize) 645 : fPath(path) 646 , fDstColorType(dstColorType) 647 , fDstAlphaType(dstAlphaType) 648 , fSampleSize(sampleSize) 649 , fRunSerially(serial_from_path_name(path)) 650{} 651 652bool AndroidCodecSrc::veto(SinkFlags flags) const { 653 // No need to test decoding to non-raster or indirect backend. 654 return flags.type != SinkFlags::kRaster 655 || flags.approach != SinkFlags::kDirect; 656} 657 658Error AndroidCodecSrc::draw(SkCanvas* canvas) const { 659 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); 660 if (!encoded) { 661 return SkStringPrintf("Couldn't read %s.", fPath.c_str()); 662 } 663 SkAutoTDelete<SkAndroidCodec> codec(SkAndroidCodec::NewFromData(encoded)); 664 if (nullptr == codec.get()) { 665 return SkStringPrintf("Couldn't create android codec for %s.", fPath.c_str()); 666 } 667 668 SkImageInfo decodeInfo = codec->getInfo(); 669 if (!get_decode_info(&decodeInfo, canvas->imageInfo().colorType(), fDstColorType, 670 fDstAlphaType)) { 671 return Error::Nonfatal("Testing non-565 to 565 is uninteresting."); 672 } 673 674 // Scale the image if it is desired. 675 SkISize size = codec->getSampledDimensions(fSampleSize); 676 677 // Visually inspecting very small output images is not necessary. We will 678 // cover these cases in unit testing. 679 if ((size.width() <= 10 || size.height() <= 10) && 1 != fSampleSize) { 680 return Error::Nonfatal("Scaling very small images is uninteresting."); 681 } 682 decodeInfo = decodeInfo.makeWH(size.width(), size.height()); 683 684 int bpp = SkColorTypeBytesPerPixel(decodeInfo.colorType()); 685 size_t rowBytes = size.width() * bpp; 686 SkAutoMalloc pixels(size.height() * rowBytes); 687 SkPMColor colorPtr[256]; 688 int colorCount = 256; 689 690 SkBitmap bitmap; 691 SkImageInfo bitmapInfo = decodeInfo; 692 if (kRGBA_8888_SkColorType == decodeInfo.colorType() || 693 kBGRA_8888_SkColorType == decodeInfo.colorType()) { 694 bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType); 695 } 696 697 // Create options for the codec. 698 SkAndroidCodec::AndroidOptions options; 699 options.fColorPtr = colorPtr; 700 options.fColorCount = &colorCount; 701 options.fSampleSize = fSampleSize; 702 703 switch (codec->getAndroidPixels(decodeInfo, pixels.get(), rowBytes, &options)) { 704 case SkCodec::kSuccess: 705 case SkCodec::kIncompleteInput: 706 break; 707 default: 708 return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str()); 709 } 710 draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, colorPtr, colorCount, fDstColorType); 711 return ""; 712} 713 714SkISize AndroidCodecSrc::size() const { 715 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); 716 SkAutoTDelete<SkAndroidCodec> codec(SkAndroidCodec::NewFromData(encoded)); 717 if (nullptr == codec) { 718 return SkISize::Make(0, 0); 719 } 720 return codec->getSampledDimensions(fSampleSize); 721} 722 723Name AndroidCodecSrc::name() const { 724 // We will replicate the names used by CodecSrc so that images can 725 // be compared in Gold. 726 if (1 == fSampleSize) { 727 return SkOSPath::Basename(fPath.c_str()); 728 } 729 return get_scaled_name(fPath, 1.0f / (float) fSampleSize); 730} 731 732/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 733 734ImageGenSrc::ImageGenSrc(Path path, Mode mode, SkAlphaType alphaType, bool isGpu) 735 : fPath(path) 736 , fMode(mode) 737 , fDstAlphaType(alphaType) 738 , fIsGpu(isGpu) 739 , fRunSerially(serial_from_path_name(path)) 740{} 741 742bool ImageGenSrc::veto(SinkFlags flags) const { 743 if (fIsGpu) { 744 return flags.type != SinkFlags::kGPU || flags.approach != SinkFlags::kDirect; 745 } 746 747 return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDirect; 748} 749 750Error ImageGenSrc::draw(SkCanvas* canvas) const { 751 if (kRGB_565_SkColorType == canvas->imageInfo().colorType()) { 752 return Error::Nonfatal("Uninteresting to test image generator to 565."); 753 } 754 755 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); 756 if (!encoded) { 757 return SkStringPrintf("Couldn't read %s.", fPath.c_str()); 758 } 759 760#if defined(SK_BUILD_FOR_WIN) 761 // Initialize COM in order to test with WIC. 762 SkAutoCoInitialize com; 763 if (!com.succeeded()) { 764 return "Could not initialize COM."; 765 } 766#endif 767 768 SkAutoTDelete<SkImageGenerator> gen(nullptr); 769 switch (fMode) { 770 case kCodec_Mode: 771 gen.reset(SkCodecImageGenerator::NewFromEncodedCodec(encoded)); 772 if (!gen) { 773 return "Could not create codec image generator."; 774 } 775 break; 776 case kPlatform_Mode: { 777#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) 778 gen.reset(SkImageGeneratorCG::NewFromEncodedCG(encoded)); 779#elif defined(SK_BUILD_FOR_WIN) 780 gen.reset(SkImageGeneratorWIC::NewFromEncodedWIC(encoded)); 781#endif 782 783 if (!gen) { 784 return "Could not create platform image generator."; 785 } 786 break; 787 } 788 default: 789 SkASSERT(false); 790 return "Invalid image generator mode"; 791 } 792 793 // Test deferred decoding path on GPU 794 if (fIsGpu) { 795 sk_sp<SkImage> image(SkImage::MakeFromGenerator(gen.release(), nullptr)); 796 if (!image) { 797 return "Could not create image from codec image generator."; 798 } 799 canvas->drawImage(image, 0, 0); 800 return ""; 801 } 802 803 // Test various color and alpha types on CPU 804 SkImageInfo decodeInfo = gen->getInfo().makeAlphaType(fDstAlphaType); 805 806 int bpp = SkColorTypeBytesPerPixel(decodeInfo.colorType()); 807 size_t rowBytes = decodeInfo.width() * bpp; 808 SkAutoMalloc pixels(decodeInfo.height() * rowBytes); 809 SkPMColor colorPtr[256]; 810 int colorCount = 256; 811 812 if (!gen->getPixels(decodeInfo, pixels.get(), rowBytes, colorPtr, &colorCount)) { 813 return SkStringPrintf("Image generator could not getPixels() for %s\n", fPath.c_str()); 814 } 815 816 draw_to_canvas(canvas, decodeInfo, pixels.get(), rowBytes, colorPtr, colorCount, 817 CodecSrc::kGetFromCanvas_DstColorType); 818 return ""; 819} 820 821SkISize ImageGenSrc::size() const { 822 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); 823 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded)); 824 if (nullptr == codec) { 825 return SkISize::Make(0, 0); 826 } 827 return codec->getInfo().dimensions(); 828} 829 830Name ImageGenSrc::name() const { 831 return SkOSPath::Basename(fPath.c_str()); 832} 833 834/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 835 836ColorCodecSrc::ColorCodecSrc(Path path, Mode mode) 837 : fPath(path) 838 , fMode(mode) 839{} 840 841bool ColorCodecSrc::veto(SinkFlags flags) const { 842 // Test to direct raster backends (8888 and 565). 843 return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDirect; 844} 845 846Error ColorCodecSrc::draw(SkCanvas* canvas) const { 847 if (kRGB_565_SkColorType == canvas->imageInfo().colorType()) { 848 return Error::Nonfatal("No need to test color correction to 565 backend."); 849 } 850 851 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); 852 if (!encoded) { 853 return SkStringPrintf("Couldn't read %s.", fPath.c_str()); 854 } 855 856 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded)); 857 if (nullptr == codec.get()) { 858 return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str()); 859 } 860 861 SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType); 862 SkBitmap bitmap; 863 if (!bitmap.tryAllocPixels(info)) { 864 return SkStringPrintf("Image(%s) is too large (%d x %d)", fPath.c_str(), 865 info.width(), info.height()); 866 } 867 868 SkImageInfo decodeInfo = info; 869 if (kBaseline_Mode != fMode) { 870 decodeInfo = decodeInfo.makeColorType(kRGBA_8888_SkColorType); 871 } 872 873 SkCodec::Result r = codec->getPixels(decodeInfo, bitmap.getPixels(), bitmap.rowBytes()); 874 if (SkCodec::kSuccess != r) { 875 return SkStringPrintf("Couldn't getPixels %s. Error code %d", fPath.c_str(), r); 876 } 877 878 // Load the dst ICC profile. This particular dst is fairly similar to Adobe RGB. 879 sk_sp<SkData> dstData = SkData::MakeFromFileName( 880 GetResourcePath("monitor_profiles/HP_ZR30w.icc").c_str()); 881 if (!dstData) { 882 return "Cannot read monitor profile. Is the resource path set correctly?"; 883 } 884 885 switch (fMode) { 886 case kBaseline_Mode: 887 canvas->drawBitmap(bitmap, 0, 0); 888 break; 889 case kDst_HPZR30w_Mode: { 890 sk_sp<SkColorSpace> srcSpace = sk_ref_sp(codec->getColorSpace()); 891 sk_sp<SkColorSpace> dstSpace = SkColorSpace::NewICC(dstData->data(), dstData->size()); 892 SkASSERT(dstSpace); 893 894 std::unique_ptr<SkColorSpaceXform> xform = SkColorSpaceXform::New(srcSpace, dstSpace); 895 if (!xform) { 896 // FIXME (msarett): 897 // I haven't implemented conversions for all of the images that I've uploaded for 898 // testing. Once we support all of them, this should be a fatal error. 899 return Error::Nonfatal("Unimplemented color conversion."); 900 } 901 902 uint32_t* row = (uint32_t*) bitmap.getPixels(); 903 for (int y = 0; y < info.height(); y++) { 904 xform->xform_RGBA_8888(row, row, info.width()); 905 row = SkTAddOffset<uint32_t>(row, bitmap.rowBytes()); 906 } 907 908 canvas->drawBitmap(bitmap, 0, 0); 909 break; 910 } 911#if !defined(GOOGLE3) 912 case kQCMS_HPZR30w_Mode: { 913 sk_sp<SkData> srcData = codec->getICCData(); 914 SkAutoTCallVProc<qcms_profile, qcms_profile_release> 915 srcSpace(qcms_profile_from_memory(srcData->data(), srcData->size())); 916 if (!srcSpace) { 917 return Error::Nonfatal(SkStringPrintf("QCMS cannot create profile for %s.\n", 918 fPath.c_str())); 919 } 920 921 SkAutoTCallVProc<qcms_profile, qcms_profile_release> 922 dstSpace(qcms_profile_from_memory(dstData->data(), dstData->size())); 923 SkASSERT(dstSpace); 924 SkAutoTCallVProc<qcms_transform, qcms_transform_release> 925 transform (qcms_transform_create(srcSpace, QCMS_DATA_RGBA_8, dstSpace, 926 QCMS_DATA_RGBA_8, QCMS_INTENT_PERCEPTUAL)); 927 if (!transform) { 928 return SkStringPrintf("QCMS cannot create transform for %s.\n", fPath.c_str()); 929 } 930 931#ifdef SK_PMCOLOR_IS_RGBA 932 qcms_output_type outType = QCMS_OUTPUT_RGBX; 933#else 934 qcms_output_type outType = QCMS_OUTPUT_BGRX; 935#endif 936 937 // Perform color correction. 938 uint32_t* row = (uint32_t*) bitmap.getPixels(); 939 for (int y = 0; y < info.height(); y++) { 940 qcms_transform_data_type(transform, row, row, info.width(), outType); 941 row = SkTAddOffset<uint32_t>(row, bitmap.rowBytes()); 942 } 943 944 canvas->drawBitmap(bitmap, 0, 0); 945 break; 946 } 947#endif 948 default: 949 SkASSERT(false); 950 return "Invalid fMode"; 951 } 952 return ""; 953} 954 955SkISize ColorCodecSrc::size() const { 956 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); 957 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded)); 958 if (nullptr == codec) { 959 return SkISize::Make(0, 0); 960 } 961 return SkISize::Make(codec->getInfo().width(), codec->getInfo().height()); 962} 963 964Name ColorCodecSrc::name() const { 965 return SkOSPath::Basename(fPath.c_str()); 966} 967 968/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 969 970static const SkRect kSKPViewport = {0,0, 1000,1000}; 971 972SKPSrc::SKPSrc(Path path) : fPath(path) {} 973 974Error SKPSrc::draw(SkCanvas* canvas) const { 975 SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(fPath.c_str())); 976 if (!stream) { 977 return SkStringPrintf("Couldn't read %s.", fPath.c_str()); 978 } 979 sk_sp<SkPicture> pic(SkPicture::MakeFromStream(stream)); 980 if (!pic) { 981 return SkStringPrintf("Couldn't decode %s as a picture.", fPath.c_str()); 982 } 983 stream.reset((SkStream*)nullptr); // Might as well drop this when we're done with it. 984 985 canvas->clipRect(kSKPViewport); 986 canvas->drawPicture(pic); 987 return ""; 988} 989 990SkISize SKPSrc::size() const { 991 SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(fPath.c_str())); 992 if (!stream) { 993 return SkISize::Make(0,0); 994 } 995 SkPictInfo info; 996 if (!SkPicture::InternalOnly_StreamIsSKP(stream, &info)) { 997 return SkISize::Make(0,0); 998 } 999 SkRect viewport = kSKPViewport; 1000 if (!viewport.intersect(info.fCullRect)) { 1001 return SkISize::Make(0,0); 1002 } 1003 return viewport.roundOut().size(); 1004} 1005 1006Name SKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); } 1007 1008/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1009 1010MSKPSrc::MSKPSrc(Path path) : fPath(path) { 1011 std::unique_ptr<SkStreamAsset> stream(SkStream::NewFromFile(fPath.c_str())); 1012 (void)fReader.init(stream.get()); 1013} 1014 1015int MSKPSrc::pageCount() const { return fReader.pageCount(); } 1016 1017SkISize MSKPSrc::size() const { return this->size(0); } 1018SkISize MSKPSrc::size(int i) const { return fReader.pageSize(i).toCeil(); } 1019 1020Error MSKPSrc::draw(SkCanvas* c) const { return this->draw(0, c); } 1021Error MSKPSrc::draw(int i, SkCanvas* canvas) const { 1022 std::unique_ptr<SkStreamAsset> stream(SkStream::NewFromFile(fPath.c_str())); 1023 if (!stream) { 1024 return SkStringPrintf("Unable to open file: %s", fPath.c_str()); 1025 } 1026 if (fReader.pageCount() == 0) { 1027 return SkStringPrintf("Unable to parse MultiPictureDocument file: %s", fPath.c_str()); 1028 } 1029 if (i >= fReader.pageCount()) { 1030 return SkStringPrintf("MultiPictureDocument page number out of range: %d", i); 1031 } 1032 sk_sp<SkPicture> page = fReader.readPage(stream.get(), i); 1033 if (!page) { 1034 return SkStringPrintf("SkMultiPictureDocumentReader failed on page %d: %s", 1035 i, fPath.c_str()); 1036 } 1037 canvas->drawPicture(page); 1038 return ""; 1039} 1040 1041Name MSKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); } 1042 1043/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1044 1045Error NullSink::draw(const Src& src, SkBitmap*, SkWStream*, SkString*) const { 1046 SkAutoTDelete<SkCanvas> canvas(SkCreateNullCanvas()); 1047 return src.draw(canvas); 1048} 1049 1050/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1051 1052DEFINE_bool(gpuStats, false, "Append GPU stats to the log for each GPU task?"); 1053 1054GPUSink::GPUSink(GrContextFactory::ContextType ct, 1055 GrContextFactory::ContextOptions options, 1056 int samples, 1057 bool diText, 1058 SkColorType colorType, 1059 SkColorProfileType profileType, 1060 bool threaded) 1061 : fContextType(ct) 1062 , fContextOptions(options) 1063 , fSampleCount(samples) 1064 , fUseDIText(diText) 1065 , fColorType(colorType) 1066 , fProfileType(profileType) 1067 , fThreaded(threaded) {} 1068 1069void PreAbandonGpuContextErrorHandler(SkError, void*) {} 1070 1071DEFINE_bool(imm, false, "Run gpu configs in immediate mode."); 1072DEFINE_bool(batchClip, false, "Clip each GrBatch to its device bounds for testing."); 1073DEFINE_bool(batchBounds, false, "Draw a wireframe bounds of each GrBatch."); 1074DEFINE_int32(batchLookback, -1, "Maximum GrBatch lookback for combining, negative means default."); 1075DEFINE_int32(batchLookahead, -1, "Maximum GrBatch lookahead for combining, negative means " 1076 "default."); 1077 1078Error GPUSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log) const { 1079 GrContextOptions grOptions; 1080 grOptions.fImmediateMode = FLAGS_imm; 1081 grOptions.fClipBatchToBounds = FLAGS_batchClip; 1082 grOptions.fDrawBatchBounds = FLAGS_batchBounds; 1083 grOptions.fMaxBatchLookback = FLAGS_batchLookback; 1084 grOptions.fMaxBatchLookahead = FLAGS_batchLookahead; 1085 1086 src.modifyGrContextOptions(&grOptions); 1087 1088 GrContextFactory factory(grOptions); 1089 const SkISize size = src.size(); 1090 const SkImageInfo info = 1091 SkImageInfo::Make(size.width(), size.height(), fColorType, 1092 kPremul_SkAlphaType, fProfileType); 1093#if SK_SUPPORT_GPU 1094 GrContext* context = factory.getContextInfo(fContextType, fContextOptions).grContext(); 1095 const int maxDimension = context->caps()->maxTextureSize(); 1096 if (maxDimension < SkTMax(size.width(), size.height())) { 1097 return Error::Nonfatal("Src too large to create a texture.\n"); 1098 } 1099#endif 1100 1101 auto surface( 1102 NewGpuSurface(&factory, fContextType, fContextOptions, info, fSampleCount, fUseDIText)); 1103 if (!surface) { 1104 return "Could not create a surface."; 1105 } 1106 if (FLAGS_preAbandonGpuContext) { 1107 SkSetErrorCallback(&PreAbandonGpuContextErrorHandler, nullptr); 1108 factory.abandonContexts(); 1109 } 1110 SkCanvas* canvas = surface->getCanvas(); 1111 Error err = src.draw(canvas); 1112 if (!err.isEmpty()) { 1113 return err; 1114 } 1115 canvas->flush(); 1116 if (FLAGS_gpuStats) { 1117 canvas->getGrContext()->dumpCacheStats(log); 1118 canvas->getGrContext()->dumpGpuStats(log); 1119 } 1120 dst->allocPixels(info); 1121 canvas->readPixels(dst, 0, 0); 1122 if (FLAGS_abandonGpuContext) { 1123 factory.abandonContexts(); 1124 } else if (FLAGS_releaseAndAbandonGpuContext) { 1125 factory.releaseResourcesAndAbandonContexts(); 1126 } 1127 return ""; 1128} 1129 1130/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1131 1132static Error draw_skdocument(const Src& src, SkDocument* doc, SkWStream* dst) { 1133 if (src.size().isEmpty()) { 1134 return "Source has empty dimensions"; 1135 } 1136 SkASSERT(doc); 1137 int pageCount = src.pageCount(); 1138 for (int i = 0; i < pageCount; ++i) { 1139 int width = src.size(i).width(), height = src.size(i).height(); 1140 SkCanvas* canvas = 1141 doc->beginPage(SkIntToScalar(width), SkIntToScalar(height)); 1142 if (!canvas) { 1143 return "SkDocument::beginPage(w,h) returned nullptr"; 1144 } 1145 Error err = src.draw(i, canvas); 1146 if (!err.isEmpty()) { 1147 return err; 1148 } 1149 doc->endPage(); 1150 } 1151 if (!doc->close()) { 1152 return "SkDocument::close() returned false"; 1153 } 1154 dst->flush(); 1155 return ""; 1156} 1157 1158Error PDFSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const { 1159 SkDocument::PDFMetadata metadata; 1160 metadata.fTitle = src.name(); 1161 metadata.fSubject = "rendering correctness test"; 1162 metadata.fCreator = "Skia/DM"; 1163 sk_sp<SkDocument> doc = SkDocument::MakePDF(dst, SK_ScalarDefaultRasterDPI, 1164 metadata, nullptr, fPDFA); 1165 if (!doc) { 1166 return "SkDocument::MakePDF() returned nullptr"; 1167 } 1168 return draw_skdocument(src, doc.get(), dst); 1169} 1170 1171/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1172 1173XPSSink::XPSSink() {} 1174 1175Error XPSSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const { 1176 sk_sp<SkDocument> doc(SkDocument::MakeXPS(dst)); 1177 if (!doc) { 1178 return "SkDocument::MakeXPS() returned nullptr"; 1179 } 1180 return draw_skdocument(src, doc.get(), dst); 1181} 1182/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1183 1184SKPSink::SKPSink() {} 1185 1186Error SKPSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const { 1187 SkSize size; 1188 size = src.size(); 1189 SkPictureRecorder recorder; 1190 Error err = src.draw(recorder.beginRecording(size.width(), size.height())); 1191 if (!err.isEmpty()) { 1192 return err; 1193 } 1194 recorder.finishRecordingAsPicture()->serialize(dst); 1195 return ""; 1196} 1197 1198/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1199 1200SVGSink::SVGSink() {} 1201 1202Error SVGSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const { 1203 SkAutoTDelete<SkXMLWriter> xmlWriter(new SkXMLStreamWriter(dst)); 1204 SkAutoTUnref<SkCanvas> canvas(SkSVGCanvas::Create( 1205 SkRect::MakeWH(SkIntToScalar(src.size().width()), SkIntToScalar(src.size().height())), 1206 xmlWriter)); 1207 return src.draw(canvas); 1208} 1209 1210/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1211 1212RasterSink::RasterSink(SkColorType colorType, SkColorProfileType profileType) 1213 : fColorType(colorType) 1214 , fProfileType(profileType) {} 1215 1216Error RasterSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString*) const { 1217 const SkISize size = src.size(); 1218 // If there's an appropriate alpha type for this color type, use it, otherwise use premul. 1219 SkAlphaType alphaType = kPremul_SkAlphaType; 1220 (void)SkColorTypeValidateAlphaType(fColorType, alphaType, &alphaType); 1221 1222 SkMallocPixelRef::ZeroedPRFactory factory; 1223 dst->allocPixels(SkImageInfo::Make(size.width(), size.height(), 1224 fColorType, alphaType, fProfileType), 1225 &factory, 1226 nullptr/*colortable*/); 1227 SkCanvas canvas(*dst); 1228 return src.draw(&canvas); 1229} 1230 1231/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1232 1233// Handy for front-patching a Src. Do whatever up-front work you need, then call draw_to_canvas(), 1234// passing the Sink draw() arguments, a size, and a function draws into an SkCanvas. 1235// Several examples below. 1236 1237template <typename Fn> 1238static Error draw_to_canvas(Sink* sink, SkBitmap* bitmap, SkWStream* stream, SkString* log, 1239 SkISize size, const Fn& draw) { 1240 class ProxySrc : public Src { 1241 public: 1242 ProxySrc(SkISize size, const Fn& draw) : fSize(size), fDraw(draw) {} 1243 Error draw(SkCanvas* canvas) const override { return fDraw(canvas); } 1244 Name name() const override { return "ProxySrc"; } 1245 SkISize size() const override { return fSize; } 1246 private: 1247 SkISize fSize; 1248 const Fn& fDraw; 1249 }; 1250 return sink->draw(ProxySrc(size, draw), bitmap, stream, log); 1251} 1252 1253/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1254 1255DEFINE_bool(check, true, "If true, have most Via- modes fail if they affect the output."); 1256 1257// Is *bitmap identical to what you get drawing src into sink? 1258static Error check_against_reference(const SkBitmap* bitmap, const Src& src, Sink* sink) { 1259 // We can only check raster outputs. 1260 // (Non-raster outputs like .pdf, .skp, .svg may differ but still draw identically.) 1261 if (FLAGS_check && bitmap) { 1262 SkBitmap reference; 1263 SkString log; 1264 SkDynamicMemoryWStream wStream; 1265 Error err = sink->draw(src, &reference, &wStream, &log); 1266 // If we can draw into this Sink via some pipeline, we should be able to draw directly. 1267 SkASSERT(err.isEmpty()); 1268 if (!err.isEmpty()) { 1269 return err; 1270 } 1271 // The dimensions are a property of the Src only, and so should be identical. 1272 SkASSERT(reference.getSize() == bitmap->getSize()); 1273 if (reference.getSize() != bitmap->getSize()) { 1274 return "Dimensions don't match reference"; 1275 } 1276 // All SkBitmaps in DM are pre-locked and tight, so this comparison is easy. 1277 if (0 != memcmp(reference.getPixels(), bitmap->getPixels(), reference.getSize())) { 1278 return "Pixels don't match reference"; 1279 } 1280 } 1281 return ""; 1282} 1283 1284/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1285 1286static SkISize auto_compute_translate(SkMatrix* matrix, int srcW, int srcH) { 1287 SkRect bounds = SkRect::MakeIWH(srcW, srcH); 1288 matrix->mapRect(&bounds); 1289 matrix->postTranslate(-bounds.x(), -bounds.y()); 1290 return SkISize::Make(SkScalarRoundToInt(bounds.width()), SkScalarRoundToInt(bounds.height())); 1291} 1292 1293ViaMatrix::ViaMatrix(SkMatrix matrix, Sink* sink) : Via(sink), fMatrix(matrix) {} 1294 1295Error ViaMatrix::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 1296 SkMatrix matrix = fMatrix; 1297 SkISize size = auto_compute_translate(&matrix, src.size().width(), src.size().height()); 1298 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) { 1299 canvas->concat(matrix); 1300 return src.draw(canvas); 1301 }); 1302} 1303 1304// Undoes any flip or 90 degree rotate without changing the scale of the bitmap. 1305// This should be pixel-preserving. 1306ViaUpright::ViaUpright(SkMatrix matrix, Sink* sink) : Via(sink), fMatrix(matrix) {} 1307 1308Error ViaUpright::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 1309 Error err = fSink->draw(src, bitmap, stream, log); 1310 if (!err.isEmpty()) { 1311 return err; 1312 } 1313 1314 SkMatrix inverse; 1315 if (!fMatrix.rectStaysRect() || !fMatrix.invert(&inverse)) { 1316 return "Cannot upright --matrix."; 1317 } 1318 SkMatrix upright = SkMatrix::I(); 1319 upright.setScaleX(SkScalarSignAsScalar(inverse.getScaleX())); 1320 upright.setScaleY(SkScalarSignAsScalar(inverse.getScaleY())); 1321 upright.setSkewX(SkScalarSignAsScalar(inverse.getSkewX())); 1322 upright.setSkewY(SkScalarSignAsScalar(inverse.getSkewY())); 1323 1324 SkBitmap uprighted; 1325 SkISize size = auto_compute_translate(&upright, bitmap->width(), bitmap->height()); 1326 uprighted.allocPixels(bitmap->info().makeWH(size.width(), size.height())); 1327 1328 SkCanvas canvas(uprighted); 1329 canvas.concat(upright); 1330 SkPaint paint; 1331 paint.setXfermodeMode(SkXfermode::kSrc_Mode); 1332 canvas.drawBitmap(*bitmap, 0, 0, &paint); 1333 1334 *bitmap = uprighted; 1335 bitmap->lockPixels(); 1336 return ""; 1337} 1338 1339/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1340 1341Error ViaSerialization::draw( 1342 const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 1343 // Record our Src into a picture. 1344 auto size = src.size(); 1345 SkPictureRecorder recorder; 1346 Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()), 1347 SkIntToScalar(size.height()))); 1348 if (!err.isEmpty()) { 1349 return err; 1350 } 1351 sk_sp<SkPicture> pic(recorder.finishRecordingAsPicture()); 1352 1353 // Serialize it and then deserialize it. 1354 SkDynamicMemoryWStream wStream; 1355 pic->serialize(&wStream); 1356 SkAutoTDelete<SkStream> rStream(wStream.detachAsStream()); 1357 sk_sp<SkPicture> deserialized(SkPicture::MakeFromStream(rStream)); 1358 1359 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) { 1360 canvas->drawPicture(deserialized); 1361 return check_against_reference(bitmap, src, fSink); 1362 }); 1363} 1364 1365/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1366 1367ViaTiles::ViaTiles(int w, int h, SkBBHFactory* factory, Sink* sink) 1368 : Via(sink) 1369 , fW(w) 1370 , fH(h) 1371 , fFactory(factory) {} 1372 1373Error ViaTiles::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 1374 auto size = src.size(); 1375 SkPictureRecorder recorder; 1376 Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()), 1377 SkIntToScalar(size.height()), 1378 fFactory.get())); 1379 if (!err.isEmpty()) { 1380 return err; 1381 } 1382 sk_sp<SkPicture> pic(recorder.finishRecordingAsPicture()); 1383 1384 return draw_to_canvas(fSink, bitmap, stream, log, src.size(), [&](SkCanvas* canvas) { 1385 const int xTiles = (size.width() + fW - 1) / fW, 1386 yTiles = (size.height() + fH - 1) / fH; 1387 SkMultiPictureDraw mpd(xTiles*yTiles); 1388 SkTArray<sk_sp<SkSurface>> surfaces; 1389// surfaces.setReserve(xTiles*yTiles); 1390 1391 SkImageInfo info = canvas->imageInfo().makeWH(fW, fH); 1392 for (int j = 0; j < yTiles; j++) { 1393 for (int i = 0; i < xTiles; i++) { 1394 // This lets our ultimate Sink determine the best kind of surface. 1395 // E.g., if it's a GpuSink, the surfaces and images are textures. 1396 auto s = canvas->makeSurface(info); 1397 if (!s) { 1398 s = SkSurface::MakeRaster(info); // Some canvases can't create surfaces. 1399 } 1400 surfaces.push_back(s); 1401 SkCanvas* c = s->getCanvas(); 1402 c->translate(SkIntToScalar(-i * fW), 1403 SkIntToScalar(-j * fH)); // Line up the canvas with this tile. 1404 mpd.add(c, pic.get()); 1405 } 1406 } 1407 mpd.draw(); 1408 for (int j = 0; j < yTiles; j++) { 1409 for (int i = 0; i < xTiles; i++) { 1410 sk_sp<SkImage> image(surfaces[i+xTiles*j]->makeImageSnapshot()); 1411 canvas->drawImage(image, SkIntToScalar(i*fW), SkIntToScalar(j*fH)); 1412 } 1413 } 1414 return ""; 1415 }); 1416} 1417 1418/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1419 1420Error ViaPicture::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 1421 auto size = src.size(); 1422 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error { 1423 SkPictureRecorder recorder; 1424 sk_sp<SkPicture> pic; 1425 Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()), 1426 SkIntToScalar(size.height()))); 1427 if (!err.isEmpty()) { 1428 return err; 1429 } 1430 pic = recorder.finishRecordingAsPicture(); 1431 canvas->drawPicture(pic); 1432 return check_against_reference(bitmap, src, fSink); 1433 }); 1434} 1435 1436/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1437 1438// Draw the Src into two pictures, then draw the second picture into the wrapped Sink. 1439// This tests that any shortcuts we may take while recording that second picture are legal. 1440Error ViaSecondPicture::draw( 1441 const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 1442 auto size = src.size(); 1443 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error { 1444 SkPictureRecorder recorder; 1445 sk_sp<SkPicture> pic; 1446 for (int i = 0; i < 2; i++) { 1447 Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()), 1448 SkIntToScalar(size.height()))); 1449 if (!err.isEmpty()) { 1450 return err; 1451 } 1452 pic = recorder.finishRecordingAsPicture(); 1453 } 1454 canvas->drawPicture(pic); 1455 return check_against_reference(bitmap, src, fSink); 1456 }); 1457} 1458 1459/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1460 1461// Draw the Src twice. This can help exercise caching. 1462Error ViaTwice::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 1463 return draw_to_canvas(fSink, bitmap, stream, log, src.size(), [&](SkCanvas* canvas) -> Error { 1464 for (int i = 0; i < 2; i++) { 1465 SkAutoCanvasRestore acr(canvas, true/*save now*/); 1466 canvas->clear(SK_ColorTRANSPARENT); 1467 Error err = src.draw(canvas); 1468 if (err.isEmpty()) { 1469 return err; 1470 } 1471 } 1472 return check_against_reference(bitmap, src, fSink); 1473 }); 1474} 1475 1476/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1477 1478// This is like SkRecords::Draw, in that it plays back SkRecords ops into a Canvas. 1479// Unlike SkRecords::Draw, it builds a single-op sub-picture out of each Draw-type op. 1480// This is an only-slightly-exaggerated simluation of Blink's Slimming Paint pictures. 1481struct DrawsAsSingletonPictures { 1482 SkCanvas* fCanvas; 1483 const SkDrawableList& fDrawables; 1484 SkRect fBounds; 1485 1486 template <typename T> 1487 void draw(const T& op, SkCanvas* canvas) { 1488 // We must pass SkMatrix::I() as our initial matrix. 1489 // By default SkRecords::Draw() uses the canvas' matrix as its initial matrix, 1490 // which would have the funky effect of applying transforms over and over. 1491 SkRecords::Draw d(canvas, nullptr, fDrawables.begin(), fDrawables.count(), &SkMatrix::I()); 1492 d(op); 1493 } 1494 1495 // Draws get their own picture. 1496 template <typename T> 1497 SK_WHEN(T::kTags & SkRecords::kDraw_Tag, void) operator()(const T& op) { 1498 SkPictureRecorder rec; 1499 this->draw(op, rec.beginRecording(fBounds)); 1500 sk_sp<SkPicture> pic(rec.finishRecordingAsPicture()); 1501 fCanvas->drawPicture(pic); 1502 } 1503 1504 // We'll just issue non-draws directly. 1505 template <typename T> 1506 skstd::enable_if_t<!(T::kTags & SkRecords::kDraw_Tag), void> operator()(const T& op) { 1507 this->draw(op, fCanvas); 1508 } 1509}; 1510 1511// Record Src into a picture, then record it into a macro picture with a sub-picture for each draw. 1512// Then play back that macro picture into our wrapped sink. 1513Error ViaSingletonPictures::draw( 1514 const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 1515 auto size = src.size(); 1516 return draw_to_canvas(fSink, bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error { 1517 // Use low-level (Skia-private) recording APIs so we can read the SkRecord. 1518 SkRecord skr; 1519 SkRecorder recorder(&skr, size.width(), size.height()); 1520 Error err = src.draw(&recorder); 1521 if (!err.isEmpty()) { 1522 return err; 1523 } 1524 1525 // Record our macro-picture, with each draw op as its own sub-picture. 1526 SkPictureRecorder macroRec; 1527 SkCanvas* macroCanvas = macroRec.beginRecording(SkIntToScalar(size.width()), 1528 SkIntToScalar(size.height())); 1529 1530 SkAutoTDelete<SkDrawableList> drawables(recorder.detachDrawableList()); 1531 const SkDrawableList empty; 1532 1533 DrawsAsSingletonPictures drawsAsSingletonPictures = { 1534 macroCanvas, 1535 drawables ? *drawables : empty, 1536 SkRect::MakeWH((SkScalar)size.width(), (SkScalar)size.height()), 1537 }; 1538 for (int i = 0; i < skr.count(); i++) { 1539 skr.visit(i, drawsAsSingletonPictures); 1540 } 1541 sk_sp<SkPicture> macroPic(macroRec.finishRecordingAsPicture()); 1542 1543 canvas->drawPicture(macroPic); 1544 return check_against_reference(bitmap, src, fSink); 1545 }); 1546} 1547 1548} // namespace DM 1549