DMSrcSink.cpp revision 7fcfb621998648ba018e3b89e2cab3135bd46a1f
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 "SkAutoMalloc.h" 12#include "SkBase64.h" 13#include "SkCodec.h" 14#include "SkCodecImageGenerator.h" 15#include "SkColorSpace.h" 16#include "SkColorSpaceXform.h" 17#include "SkColorSpaceXformCanvas.h" 18#include "SkColorSpace_XYZ.h" 19#include "SkCommonFlags.h" 20#include "SkCommonFlagsGpu.h" 21#include "SkData.h" 22#include "SkDebugCanvas.h" 23#include "SkDeferredDisplayListRecorder.h" 24#include "SkDocument.h" 25#include "SkExecutor.h" 26#include "SkImageGenerator.h" 27#include "SkImageGeneratorCG.h" 28#include "SkImageGeneratorWIC.h" 29#include "SkImageInfoPriv.h" 30#include "SkLiteDL.h" 31#include "SkLiteRecorder.h" 32#include "SkMallocPixelRef.h" 33#include "SkMultiPictureDocumentPriv.h" 34#include "SkMultiPictureDraw.h" 35#include "SkNullCanvas.h" 36#include "SkOSFile.h" 37#include "SkOSPath.h" 38#include "SkOpts.h" 39#include "SkPictureCommon.h" 40#include "SkPictureData.h" 41#include "SkPictureRecorder.h" 42#include "SkPipe.h" 43#include "SkPngEncoder.h" 44#include "SkRandom.h" 45#include "SkRecordDraw.h" 46#include "SkRecorder.h" 47#include "SkSurfaceCharacterization.h" 48#include "SkSVGCanvas.h" 49#include "SkStream.h" 50#include "SkSwizzler.h" 51#include "SkTaskGroup.h" 52#include "SkTLogic.h" 53#include <cmath> 54#include <functional> 55#include "../src/jumper/SkJumper.h" 56 57#if defined(SK_BUILD_FOR_WIN) 58 #include "SkAutoCoInitialize.h" 59 #include "SkHRESULT.h" 60 #include "SkTScopedComPtr.h" 61 #include <XpsObjectModel.h> 62#endif 63 64#if !defined(SK_BUILD_FOR_GOOGLE3) 65 #include "Skottie.h" 66#endif 67 68#if defined(SK_XML) 69 #include "SkSVGDOM.h" 70 #include "SkXMLWriter.h" 71#endif 72 73DEFINE_bool(multiPage, false, "For document-type backends, render the source" 74 " into multiple pages"); 75DEFINE_bool(RAW_threading, true, "Allow RAW decodes to run on multiple threads?"); 76 77using sk_gpu_test::GrContextFactory; 78 79namespace DM { 80 81GMSrc::GMSrc(skiagm::GMRegistry::Factory factory) : fFactory(factory) {} 82 83Error GMSrc::draw(SkCanvas* canvas) const { 84 std::unique_ptr<skiagm::GM> gm(fFactory(nullptr)); 85 gm->draw(canvas); 86 return ""; 87} 88 89SkISize GMSrc::size() const { 90 std::unique_ptr<skiagm::GM> gm(fFactory(nullptr)); 91 return gm->getISize(); 92} 93 94Name GMSrc::name() const { 95 std::unique_ptr<skiagm::GM> gm(fFactory(nullptr)); 96 return gm->getName(); 97} 98 99void GMSrc::modifyGrContextOptions(GrContextOptions* options) const { 100 std::unique_ptr<skiagm::GM> gm(fFactory(nullptr)); 101 gm->modifyGrContextOptions(options); 102} 103 104/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 105 106BRDSrc::BRDSrc(Path path, Mode mode, CodecSrc::DstColorType dstColorType, uint32_t sampleSize) 107 : fPath(path) 108 , fMode(mode) 109 , fDstColorType(dstColorType) 110 , fSampleSize(sampleSize) 111{} 112 113bool BRDSrc::veto(SinkFlags flags) const { 114 // No need to test to non-raster or indirect backends. 115 return flags.type != SinkFlags::kRaster 116 || flags.approach != SinkFlags::kDirect; 117} 118 119static SkBitmapRegionDecoder* create_brd(Path path) { 120 sk_sp<SkData> encoded(SkData::MakeFromFileName(path.c_str())); 121 if (!encoded) { 122 return nullptr; 123 } 124 return SkBitmapRegionDecoder::Create(encoded, SkBitmapRegionDecoder::kAndroidCodec_Strategy); 125} 126 127static inline void alpha8_to_gray8(SkBitmap* bitmap) { 128 // Android requires kGray8 bitmaps to be tagged as kAlpha8. Here we convert 129 // them back to kGray8 so our test framework can draw them correctly. 130 if (kAlpha_8_SkColorType == bitmap->info().colorType()) { 131 SkImageInfo newInfo = bitmap->info().makeColorType(kGray_8_SkColorType) 132 .makeAlphaType(kOpaque_SkAlphaType); 133 *const_cast<SkImageInfo*>(&bitmap->info()) = newInfo; 134 } 135} 136 137Error BRDSrc::draw(SkCanvas* canvas) const { 138 if (canvas->imageInfo().colorSpace() && 139 kRGBA_F16_SkColorType != canvas->imageInfo().colorType()) { 140 // SkAndroidCodec uses legacy premultiplication and blending. Therefore, we only 141 // run these tests on legacy canvases. 142 // We allow an exception for F16, since Android uses F16. 143 return Error::Nonfatal("Skip testing to color correct canvas."); 144 } 145 146 SkColorType colorType = canvas->imageInfo().colorType(); 147 if (kRGB_565_SkColorType == colorType && 148 CodecSrc::kGetFromCanvas_DstColorType != fDstColorType) { 149 return Error::Nonfatal("Testing non-565 to 565 is uninteresting."); 150 } 151 switch (fDstColorType) { 152 case CodecSrc::kGetFromCanvas_DstColorType: 153 break; 154 case CodecSrc::kGrayscale_Always_DstColorType: 155 colorType = kGray_8_SkColorType; 156 break; 157 default: 158 SkASSERT(false); 159 break; 160 } 161 162 std::unique_ptr<SkBitmapRegionDecoder> brd(create_brd(fPath)); 163 if (nullptr == brd.get()) { 164 return Error::Nonfatal(SkStringPrintf("Could not create brd for %s.", fPath.c_str())); 165 } 166 167 if (kRGB_565_SkColorType == colorType) { 168 auto recommendedCT = brd->computeOutputColorType(colorType); 169 if (recommendedCT != colorType) { 170 return Error::Nonfatal("Skip decoding non-opaque to 565."); 171 } 172 } 173 174 const uint32_t width = brd->width(); 175 const uint32_t height = brd->height(); 176 // Visually inspecting very small output images is not necessary. 177 if ((width / fSampleSize <= 10 || height / fSampleSize <= 10) && 1 != fSampleSize) { 178 return Error::Nonfatal("Scaling very small images is uninteresting."); 179 } 180 switch (fMode) { 181 case kFullImage_Mode: { 182 SkBitmap bitmap; 183 if (!brd->decodeRegion(&bitmap, nullptr, SkIRect::MakeXYWH(0, 0, width, height), 184 fSampleSize, colorType, false, SkColorSpace::MakeSRGB())) { 185 return "Cannot decode (full) region."; 186 } 187 alpha8_to_gray8(&bitmap); 188 189 canvas->drawBitmap(bitmap, 0, 0); 190 return ""; 191 } 192 case kDivisor_Mode: { 193 const uint32_t divisor = 2; 194 if (width < divisor || height < divisor) { 195 return Error::Nonfatal("Divisor is larger than image dimension."); 196 } 197 198 // Use a border to test subsets that extend outside the image. 199 // We will not allow the border to be larger than the image dimensions. Allowing 200 // these large borders causes off by one errors that indicate a problem with the 201 // test suite, not a problem with the implementation. 202 const uint32_t maxBorder = SkTMin(width, height) / (fSampleSize * divisor); 203 const uint32_t scaledBorder = SkTMin(5u, maxBorder); 204 const uint32_t unscaledBorder = scaledBorder * fSampleSize; 205 206 // We may need to clear the canvas to avoid uninitialized memory. 207 // Assume we are scaling a 780x780 image with sampleSize = 8. 208 // The output image should be 97x97. 209 // Each subset will be 390x390. 210 // Each scaled subset be 48x48. 211 // Four scaled subsets will only fill a 96x96 image. 212 // The bottom row and last column will not be touched. 213 // This is an unfortunate result of our rounding rules when scaling. 214 // Maybe we need to consider testing scaled subsets without trying to 215 // combine them to match the full scaled image? Or maybe this is the 216 // best we can do? 217 canvas->clear(0); 218 219 for (uint32_t x = 0; x < divisor; x++) { 220 for (uint32_t y = 0; y < divisor; y++) { 221 // Calculate the subset dimensions 222 uint32_t subsetWidth = width / divisor; 223 uint32_t subsetHeight = height / divisor; 224 const int left = x * subsetWidth; 225 const int top = y * subsetHeight; 226 227 // Increase the size of the last subset in each row or column, when the 228 // divisor does not divide evenly into the image dimensions 229 subsetWidth += (x + 1 == divisor) ? (width % divisor) : 0; 230 subsetHeight += (y + 1 == divisor) ? (height % divisor) : 0; 231 232 // Increase the size of the subset in order to have a border on each side 233 const int decodeLeft = left - unscaledBorder; 234 const int decodeTop = top - unscaledBorder; 235 const uint32_t decodeWidth = subsetWidth + unscaledBorder * 2; 236 const uint32_t decodeHeight = subsetHeight + unscaledBorder * 2; 237 SkBitmap bitmap; 238 if (!brd->decodeRegion(&bitmap, nullptr, SkIRect::MakeXYWH(decodeLeft, 239 decodeTop, decodeWidth, decodeHeight), fSampleSize, colorType, false, 240 SkColorSpace::MakeSRGB())) { 241 return "Cannot decode region."; 242 } 243 244 alpha8_to_gray8(&bitmap); 245 canvas->drawBitmapRect(bitmap, 246 SkRect::MakeXYWH((SkScalar) scaledBorder, (SkScalar) scaledBorder, 247 (SkScalar) (subsetWidth / fSampleSize), 248 (SkScalar) (subsetHeight / fSampleSize)), 249 SkRect::MakeXYWH((SkScalar) (left / fSampleSize), 250 (SkScalar) (top / fSampleSize), 251 (SkScalar) (subsetWidth / fSampleSize), 252 (SkScalar) (subsetHeight / fSampleSize)), 253 nullptr); 254 } 255 } 256 return ""; 257 } 258 default: 259 SkASSERT(false); 260 return "Error: Should not be reached."; 261 } 262} 263 264SkISize BRDSrc::size() const { 265 std::unique_ptr<SkBitmapRegionDecoder> brd(create_brd(fPath)); 266 if (brd) { 267 return {SkTMax(1, brd->width() / (int)fSampleSize), 268 SkTMax(1, brd->height() / (int)fSampleSize)}; 269 } 270 return {0, 0}; 271} 272 273static SkString get_scaled_name(const Path& path, float scale) { 274 return SkStringPrintf("%s_%.3f", SkOSPath::Basename(path.c_str()).c_str(), scale); 275} 276 277Name BRDSrc::name() const { 278 // We will replicate the names used by CodecSrc so that images can 279 // be compared in Gold. 280 if (1 == fSampleSize) { 281 return SkOSPath::Basename(fPath.c_str()); 282 } 283 return get_scaled_name(fPath, 1.0f / (float) fSampleSize); 284} 285 286/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 287 288static bool serial_from_path_name(const SkString& path) { 289 if (!FLAGS_RAW_threading) { 290 static const char* const exts[] = { 291 "arw", "cr2", "dng", "nef", "nrw", "orf", "raf", "rw2", "pef", "srw", 292 "ARW", "CR2", "DNG", "NEF", "NRW", "ORF", "RAF", "RW2", "PEF", "SRW", 293 }; 294 const char* actualExt = strrchr(path.c_str(), '.'); 295 if (actualExt) { 296 actualExt++; 297 for (auto* ext : exts) { 298 if (0 == strcmp(ext, actualExt)) { 299 return true; 300 } 301 } 302 } 303 } 304 return false; 305} 306 307CodecSrc::CodecSrc(Path path, Mode mode, DstColorType dstColorType, SkAlphaType dstAlphaType, 308 float scale) 309 : fPath(path) 310 , fMode(mode) 311 , fDstColorType(dstColorType) 312 , fDstAlphaType(dstAlphaType) 313 , fScale(scale) 314 , fRunSerially(serial_from_path_name(path)) 315{} 316 317bool CodecSrc::veto(SinkFlags flags) const { 318 // Test to direct raster backends (8888 and 565). 319 return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDirect; 320} 321 322// Allows us to test decodes to non-native 8888. 323static void swap_rb_if_necessary(SkBitmap& bitmap, CodecSrc::DstColorType dstColorType) { 324 if (CodecSrc::kNonNative8888_Always_DstColorType != dstColorType) { 325 return; 326 } 327 328 for (int y = 0; y < bitmap.height(); y++) { 329 uint32_t* row = (uint32_t*) bitmap.getAddr(0, y); 330 SkOpts::RGBA_to_BGRA(row, row, bitmap.width()); 331 } 332} 333 334// FIXME: Currently we cannot draw unpremultiplied sources. skbug.com/3338 and skbug.com/3339. 335// This allows us to still test unpremultiplied decodes. 336static void premultiply_if_necessary(SkBitmap& bitmap) { 337 if (kUnpremul_SkAlphaType != bitmap.alphaType()) { 338 return; 339 } 340 341 switch (bitmap.colorType()) { 342 case kRGBA_F16_SkColorType: { 343 SkJumper_MemoryCtx ctx = { bitmap.getAddr(0,0), bitmap.rowBytesAsPixels() }; 344 SkRasterPipeline_<256> p; 345 p.append(SkRasterPipeline::load_f16, &ctx); 346 p.append(SkRasterPipeline::premul); 347 p.append(SkRasterPipeline::store_f16, &ctx); 348 p.run(0,0, bitmap.width(), bitmap.height()); 349 } 350 break; 351 case kN32_SkColorType: 352 for (int y = 0; y < bitmap.height(); y++) { 353 uint32_t* row = (uint32_t*) bitmap.getAddr(0, y); 354 SkOpts::RGBA_to_rgbA(row, row, bitmap.width()); 355 } 356 break; 357 default: 358 // No need to premultiply kGray or k565 outputs. 359 break; 360 } 361 362 // In the kIndex_8 case, the canvas won't even try to draw unless we mark the 363 // bitmap as kPremul. 364 bitmap.setAlphaType(kPremul_SkAlphaType); 365} 366 367static bool get_decode_info(SkImageInfo* decodeInfo, SkColorType canvasColorType, 368 CodecSrc::DstColorType dstColorType, SkAlphaType dstAlphaType) { 369 switch (dstColorType) { 370 case CodecSrc::kGrayscale_Always_DstColorType: 371 if (kRGB_565_SkColorType == canvasColorType) { 372 return false; 373 } 374 *decodeInfo = decodeInfo->makeColorType(kGray_8_SkColorType); 375 break; 376 case CodecSrc::kNonNative8888_Always_DstColorType: 377 if (kRGB_565_SkColorType == canvasColorType 378 || kRGBA_F16_SkColorType == canvasColorType) { 379 return false; 380 } 381#ifdef SK_PMCOLOR_IS_RGBA 382 *decodeInfo = decodeInfo->makeColorType(kBGRA_8888_SkColorType); 383#else 384 *decodeInfo = decodeInfo->makeColorType(kRGBA_8888_SkColorType); 385#endif 386 break; 387 default: 388 if (kRGB_565_SkColorType == canvasColorType && 389 kOpaque_SkAlphaType != decodeInfo->alphaType()) { 390 return false; 391 } 392 393 if (kRGBA_F16_SkColorType == canvasColorType) { 394 sk_sp<SkColorSpace> linearSpace = decodeInfo->colorSpace()->makeLinearGamma(); 395 *decodeInfo = decodeInfo->makeColorSpace(std::move(linearSpace)); 396 } 397 398 *decodeInfo = decodeInfo->makeColorType(canvasColorType); 399 break; 400 } 401 402 *decodeInfo = decodeInfo->makeAlphaType(dstAlphaType); 403 return true; 404} 405 406static void draw_to_canvas(SkCanvas* canvas, const SkImageInfo& info, void* pixels, size_t rowBytes, 407 CodecSrc::DstColorType dstColorType, 408 SkScalar left = 0, SkScalar top = 0) { 409 SkBitmap bitmap; 410 bitmap.installPixels(info, pixels, rowBytes); 411 premultiply_if_necessary(bitmap); 412 swap_rb_if_necessary(bitmap, dstColorType); 413 canvas->drawBitmap(bitmap, left, top); 414} 415 416// For codec srcs, we want the "draw" step to be a memcpy. Any interesting color space or 417// color format conversions should be performed by the codec. Sometimes the output of the 418// decode will be in an interesting color space. On our srgb and f16 backends, we need to 419// "pretend" that the color space is standard sRGB to avoid triggering color conversion 420// at draw time. 421static void set_bitmap_color_space(SkImageInfo* info) { 422 if (kRGBA_F16_SkColorType == info->colorType()) { 423 *info = info->makeColorSpace(SkColorSpace::MakeSRGBLinear()); 424 } else { 425 *info = info->makeColorSpace(SkColorSpace::MakeSRGB()); 426 } 427} 428 429Error CodecSrc::draw(SkCanvas* canvas) const { 430 sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str())); 431 if (!encoded) { 432 return SkStringPrintf("Couldn't read %s.", fPath.c_str()); 433 } 434 435 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(encoded)); 436 if (nullptr == codec.get()) { 437 return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str()); 438 } 439 440 SkImageInfo decodeInfo = codec->getInfo(); 441 if (!get_decode_info(&decodeInfo, canvas->imageInfo().colorType(), fDstColorType, 442 fDstAlphaType)) { 443 return Error::Nonfatal("Skipping uninteresting test."); 444 } 445 446 // Try to scale the image if it is desired 447 SkISize size = codec->getScaledDimensions(fScale); 448 if (size == decodeInfo.dimensions() && 1.0f != fScale) { 449 return Error::Nonfatal("Test without scaling is uninteresting."); 450 } 451 452 // Visually inspecting very small output images is not necessary. We will 453 // cover these cases in unit testing. 454 if ((size.width() <= 10 || size.height() <= 10) && 1.0f != fScale) { 455 return Error::Nonfatal("Scaling very small images is uninteresting."); 456 } 457 decodeInfo = decodeInfo.makeWH(size.width(), size.height()); 458 459 const int bpp = decodeInfo.bytesPerPixel(); 460 const size_t rowBytes = size.width() * bpp; 461 const size_t safeSize = decodeInfo.computeByteSize(rowBytes); 462 SkAutoMalloc pixels(safeSize); 463 464 SkCodec::Options options; 465 options.fPremulBehavior = canvas->imageInfo().colorSpace() ? 466 SkTransferFunctionBehavior::kRespect : SkTransferFunctionBehavior::kIgnore; 467 if (kCodecZeroInit_Mode == fMode) { 468 memset(pixels.get(), 0, size.height() * rowBytes); 469 options.fZeroInitialized = SkCodec::kYes_ZeroInitialized; 470 } 471 472 SkImageInfo bitmapInfo = decodeInfo; 473 set_bitmap_color_space(&bitmapInfo); 474 if (kRGBA_8888_SkColorType == decodeInfo.colorType() || 475 kBGRA_8888_SkColorType == decodeInfo.colorType()) { 476 bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType); 477 } 478 479 switch (fMode) { 480 case kAnimated_Mode: { 481 std::vector<SkCodec::FrameInfo> frameInfos = codec->getFrameInfo(); 482 if (frameInfos.size() <= 1) { 483 return SkStringPrintf("%s is not an animated image.", fPath.c_str()); 484 } 485 486 // As in CodecSrc::size(), compute a roughly square grid to draw the frames 487 // into. "factor" is the number of frames to draw on one row. There will be 488 // up to "factor" rows as well. 489 const float root = sqrt((float) frameInfos.size()); 490 const int factor = sk_float_ceil2int(root); 491 492 // Used to cache a frame that future frames will depend on. 493 SkAutoMalloc priorFramePixels; 494 int cachedFrame = SkCodec::kNone; 495 for (int i = 0; static_cast<size_t>(i) < frameInfos.size(); i++) { 496 options.fFrameIndex = i; 497 // Check for a prior frame 498 const int reqFrame = frameInfos[i].fRequiredFrame; 499 if (reqFrame != SkCodec::kNone && reqFrame == cachedFrame 500 && priorFramePixels.get()) { 501 // Copy into pixels 502 memcpy(pixels.get(), priorFramePixels.get(), safeSize); 503 options.fPriorFrame = reqFrame; 504 } else { 505 options.fPriorFrame = SkCodec::kNone; 506 } 507 SkCodec::Result result = codec->getPixels(decodeInfo, pixels.get(), 508 rowBytes, &options); 509 if (SkCodec::kInvalidInput == result && i > 0) { 510 // Some of our test images have truncated later frames. Treat that 511 // the same as incomplete. 512 result = SkCodec::kIncompleteInput; 513 } 514 switch (result) { 515 case SkCodec::kSuccess: 516 case SkCodec::kErrorInInput: 517 case SkCodec::kIncompleteInput: { 518 // If the next frame depends on this one, store it in priorFrame. 519 // It is possible that we may discard a frame that future frames depend on, 520 // but the codec will simply redecode the discarded frame. 521 // Do this before calling draw_to_canvas, which premultiplies in place. If 522 // we're decoding to unpremul, we want to pass the unmodified frame to the 523 // codec for decoding the next frame. 524 if (static_cast<size_t>(i+1) < frameInfos.size() 525 && frameInfos[i+1].fRequiredFrame == i) { 526 memcpy(priorFramePixels.reset(safeSize), pixels.get(), safeSize); 527 cachedFrame = i; 528 } 529 530 SkAutoCanvasRestore acr(canvas, true); 531 const int xTranslate = (i % factor) * decodeInfo.width(); 532 const int yTranslate = (i / factor) * decodeInfo.height(); 533 canvas->translate(SkIntToScalar(xTranslate), SkIntToScalar(yTranslate)); 534 draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, fDstColorType); 535 if (result != SkCodec::kSuccess) { 536 return ""; 537 } 538 break; 539 } 540 case SkCodec::kInvalidConversion: 541 if (i > 0 && (decodeInfo.colorType() == kRGB_565_SkColorType)) { 542 return Error::Nonfatal(SkStringPrintf( 543 "Cannot decode frame %i to 565 (%s).", i, fPath.c_str())); 544 } 545 // Fall through. 546 default: 547 return SkStringPrintf("Couldn't getPixels for frame %i in %s.", 548 i, fPath.c_str()); 549 } 550 } 551 break; 552 } 553 case kCodecZeroInit_Mode: 554 case kCodec_Mode: { 555 switch (codec->getPixels(decodeInfo, pixels.get(), rowBytes, &options)) { 556 case SkCodec::kSuccess: 557 // We consider these to be valid, since we should still decode what is 558 // available. 559 case SkCodec::kErrorInInput: 560 case SkCodec::kIncompleteInput: 561 break; 562 default: 563 // Everything else is considered a failure. 564 return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str()); 565 } 566 567 draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, fDstColorType); 568 break; 569 } 570 case kScanline_Mode: { 571 void* dst = pixels.get(); 572 uint32_t height = decodeInfo.height(); 573 const bool useIncremental = [this]() { 574 auto exts = { "png", "PNG", "gif", "GIF" }; 575 for (auto ext : exts) { 576 if (fPath.endsWith(ext)) { 577 return true; 578 } 579 } 580 return false; 581 }(); 582 // ico may use the old scanline method or the new one, depending on whether it 583 // internally holds a bmp or a png. 584 const bool ico = fPath.endsWith("ico"); 585 bool useOldScanlineMethod = !useIncremental && !ico; 586 if (useIncremental || ico) { 587 if (SkCodec::kSuccess == codec->startIncrementalDecode(decodeInfo, dst, 588 rowBytes, &options)) { 589 int rowsDecoded; 590 auto result = codec->incrementalDecode(&rowsDecoded); 591 if (SkCodec::kIncompleteInput == result || SkCodec::kErrorInInput == result) { 592 codec->fillIncompleteImage(decodeInfo, dst, rowBytes, 593 SkCodec::kNo_ZeroInitialized, height, 594 rowsDecoded); 595 } 596 } else { 597 if (useIncremental) { 598 // Error: These should support incremental decode. 599 return "Could not start incremental decode"; 600 } 601 // Otherwise, this is an ICO. Since incremental failed, it must contain a BMP, 602 // which should work via startScanlineDecode 603 useOldScanlineMethod = true; 604 } 605 } 606 607 if (useOldScanlineMethod) { 608 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo)) { 609 return "Could not start scanline decoder"; 610 } 611 612 switch (codec->getScanlineOrder()) { 613 case SkCodec::kTopDown_SkScanlineOrder: 614 case SkCodec::kBottomUp_SkScanlineOrder: 615 // We do not need to check the return value. On an incomplete 616 // image, memory will be filled with a default value. 617 codec->getScanlines(dst, height, rowBytes); 618 break; 619 } 620 } 621 622 draw_to_canvas(canvas, bitmapInfo, dst, rowBytes, fDstColorType); 623 break; 624 } 625 case kStripe_Mode: { 626 const int height = decodeInfo.height(); 627 // This value is chosen arbitrarily. We exercise more cases by choosing a value that 628 // does not align with image blocks. 629 const int stripeHeight = 37; 630 const int numStripes = (height + stripeHeight - 1) / stripeHeight; 631 void* dst = pixels.get(); 632 633 // Decode odd stripes 634 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, &options)) { 635 return "Could not start scanline decoder"; 636 } 637 638 // This mode was designed to test the new skip scanlines API in libjpeg-turbo. 639 // Jpegs have kTopDown_SkScanlineOrder, and at this time, it is not interesting 640 // to run this test for image types that do not have this scanline ordering. 641 // We only run this on Jpeg, which is always kTopDown. 642 SkASSERT(SkCodec::kTopDown_SkScanlineOrder == codec->getScanlineOrder()); 643 644 for (int i = 0; i < numStripes; i += 2) { 645 // Skip a stripe 646 const int linesToSkip = SkTMin(stripeHeight, height - i * stripeHeight); 647 codec->skipScanlines(linesToSkip); 648 649 // Read a stripe 650 const int startY = (i + 1) * stripeHeight; 651 const int linesToRead = SkTMin(stripeHeight, height - startY); 652 if (linesToRead > 0) { 653 codec->getScanlines(SkTAddOffset<void>(dst, rowBytes * startY), linesToRead, 654 rowBytes); 655 } 656 } 657 658 // Decode even stripes 659 const SkCodec::Result startResult = codec->startScanlineDecode(decodeInfo); 660 if (SkCodec::kSuccess != startResult) { 661 return "Failed to restart scanline decoder with same parameters."; 662 } 663 for (int i = 0; i < numStripes; i += 2) { 664 // Read a stripe 665 const int startY = i * stripeHeight; 666 const int linesToRead = SkTMin(stripeHeight, height - startY); 667 codec->getScanlines(SkTAddOffset<void>(dst, rowBytes * startY), linesToRead, 668 rowBytes); 669 670 // Skip a stripe 671 const int linesToSkip = SkTMin(stripeHeight, height - (i + 1) * stripeHeight); 672 if (linesToSkip > 0) { 673 codec->skipScanlines(linesToSkip); 674 } 675 } 676 677 draw_to_canvas(canvas, bitmapInfo, dst, rowBytes, fDstColorType); 678 break; 679 } 680 case kCroppedScanline_Mode: { 681 const int width = decodeInfo.width(); 682 const int height = decodeInfo.height(); 683 // This value is chosen because, as we move across the image, it will sometimes 684 // align with the jpeg block sizes and it will sometimes not. This allows us 685 // to test interestingly different code paths in the implementation. 686 const int tileSize = 36; 687 SkIRect subset; 688 for (int x = 0; x < width; x += tileSize) { 689 subset = SkIRect::MakeXYWH(x, 0, SkTMin(tileSize, width - x), height); 690 options.fSubset = ⊂ 691 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, &options)) { 692 return "Could not start scanline decoder."; 693 } 694 695 codec->getScanlines(SkTAddOffset<void>(pixels.get(), x * bpp), height, rowBytes); 696 } 697 698 draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, fDstColorType); 699 break; 700 } 701 case kSubset_Mode: { 702 // Arbitrarily choose a divisor. 703 int divisor = 2; 704 // Total width/height of the image. 705 const int W = codec->getInfo().width(); 706 const int H = codec->getInfo().height(); 707 if (divisor > W || divisor > H) { 708 return Error::Nonfatal(SkStringPrintf("Cannot codec subset: divisor %d is too big " 709 "for %s with dimensions (%d x %d)", divisor, 710 fPath.c_str(), W, H)); 711 } 712 // subset dimensions 713 // SkWebpCodec, the only one that supports subsets, requires even top/left boundaries. 714 const int w = SkAlign2(W / divisor); 715 const int h = SkAlign2(H / divisor); 716 SkIRect subset; 717 options.fSubset = ⊂ 718 SkBitmap subsetBm; 719 // We will reuse pixel memory from bitmap. 720 void* dst = pixels.get(); 721 // Keep track of left and top (for drawing subsetBm into canvas). We could use 722 // fScale * x and fScale * y, but we want integers such that the next subset will start 723 // where the last one ended. So we'll add decodeInfo.width() and height(). 724 int left = 0; 725 for (int x = 0; x < W; x += w) { 726 int top = 0; 727 for (int y = 0; y < H; y+= h) { 728 // Do not make the subset go off the edge of the image. 729 const int preScaleW = SkTMin(w, W - x); 730 const int preScaleH = SkTMin(h, H - y); 731 subset.setXYWH(x, y, preScaleW, preScaleH); 732 // And scale 733 // FIXME: Should we have a version of getScaledDimensions that takes a subset 734 // into account? 735 const int scaledW = SkTMax(1, SkScalarRoundToInt(preScaleW * fScale)); 736 const int scaledH = SkTMax(1, SkScalarRoundToInt(preScaleH * fScale)); 737 decodeInfo = decodeInfo.makeWH(scaledW, scaledH); 738 SkImageInfo subsetBitmapInfo = bitmapInfo.makeWH(scaledW, scaledH); 739 size_t subsetRowBytes = subsetBitmapInfo.minRowBytes(); 740 const SkCodec::Result result = codec->getPixels(decodeInfo, dst, subsetRowBytes, 741 &options); 742 switch (result) { 743 case SkCodec::kSuccess: 744 case SkCodec::kErrorInInput: 745 case SkCodec::kIncompleteInput: 746 break; 747 default: 748 return SkStringPrintf("subset codec failed to decode (%d, %d, %d, %d) " 749 "from %s with dimensions (%d x %d)\t error %d", 750 x, y, decodeInfo.width(), decodeInfo.height(), 751 fPath.c_str(), W, H, result); 752 } 753 draw_to_canvas(canvas, subsetBitmapInfo, dst, subsetRowBytes, fDstColorType, 754 SkIntToScalar(left), SkIntToScalar(top)); 755 756 // translate by the scaled height. 757 top += decodeInfo.height(); 758 } 759 // translate by the scaled width. 760 left += decodeInfo.width(); 761 } 762 return ""; 763 } 764 default: 765 SkASSERT(false); 766 return "Invalid fMode"; 767 } 768 return ""; 769} 770 771SkISize CodecSrc::size() const { 772 sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str())); 773 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(encoded)); 774 if (nullptr == codec) { 775 return {0, 0}; 776 } 777 778 auto imageSize = codec->getScaledDimensions(fScale); 779 if (fMode == kAnimated_Mode) { 780 // We'll draw one of each frame, so make it big enough to hold them all 781 // in a grid. The grid will be roughly square, with "factor" frames per 782 // row and up to "factor" rows. 783 const size_t count = codec->getFrameInfo().size(); 784 const float root = sqrt((float) count); 785 const int factor = sk_float_ceil2int(root); 786 imageSize.fWidth = imageSize.fWidth * factor; 787 imageSize.fHeight = imageSize.fHeight * sk_float_ceil2int((float) count / (float) factor); 788 } 789 return imageSize; 790} 791 792Name CodecSrc::name() const { 793 if (1.0f == fScale) { 794 Name name = SkOSPath::Basename(fPath.c_str()); 795 if (fMode == kAnimated_Mode) { 796 name.append("_animated"); 797 } 798 return name; 799 } 800 SkASSERT(fMode != kAnimated_Mode); 801 return get_scaled_name(fPath, fScale); 802} 803 804/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 805 806AndroidCodecSrc::AndroidCodecSrc(Path path, CodecSrc::DstColorType dstColorType, 807 SkAlphaType dstAlphaType, int sampleSize) 808 : fPath(path) 809 , fDstColorType(dstColorType) 810 , fDstAlphaType(dstAlphaType) 811 , fSampleSize(sampleSize) 812 , fRunSerially(serial_from_path_name(path)) 813{} 814 815bool AndroidCodecSrc::veto(SinkFlags flags) const { 816 // No need to test decoding to non-raster or indirect backend. 817 return flags.type != SinkFlags::kRaster 818 || flags.approach != SinkFlags::kDirect; 819} 820 821Error AndroidCodecSrc::draw(SkCanvas* canvas) const { 822 if (canvas->imageInfo().colorSpace() && 823 kRGBA_F16_SkColorType != canvas->imageInfo().colorType()) { 824 // SkAndroidCodec uses legacy premultiplication and blending. Therefore, we only 825 // run these tests on legacy canvases. 826 // We allow an exception for F16, since Android uses F16. 827 return Error::Nonfatal("Skip testing to color correct canvas."); 828 } 829 830 sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str())); 831 if (!encoded) { 832 return SkStringPrintf("Couldn't read %s.", fPath.c_str()); 833 } 834 std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::MakeFromData(encoded)); 835 if (nullptr == codec) { 836 return SkStringPrintf("Couldn't create android codec for %s.", fPath.c_str()); 837 } 838 839 SkImageInfo decodeInfo = codec->getInfo(); 840 if (!get_decode_info(&decodeInfo, canvas->imageInfo().colorType(), fDstColorType, 841 fDstAlphaType)) { 842 return Error::Nonfatal("Skipping uninteresting test."); 843 } 844 845 // Scale the image if it is desired. 846 SkISize size = codec->getSampledDimensions(fSampleSize); 847 848 // Visually inspecting very small output images is not necessary. We will 849 // cover these cases in unit testing. 850 if ((size.width() <= 10 || size.height() <= 10) && 1 != fSampleSize) { 851 return Error::Nonfatal("Scaling very small images is uninteresting."); 852 } 853 decodeInfo = decodeInfo.makeWH(size.width(), size.height()); 854 855 int bpp = decodeInfo.bytesPerPixel(); 856 size_t rowBytes = size.width() * bpp; 857 SkAutoMalloc pixels(size.height() * rowBytes); 858 859 SkBitmap bitmap; 860 SkImageInfo bitmapInfo = decodeInfo; 861 set_bitmap_color_space(&bitmapInfo); 862 if (kRGBA_8888_SkColorType == decodeInfo.colorType() || 863 kBGRA_8888_SkColorType == decodeInfo.colorType()) { 864 bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType); 865 } 866 867 // Create options for the codec. 868 SkAndroidCodec::AndroidOptions options; 869 options.fSampleSize = fSampleSize; 870 871 switch (codec->getAndroidPixels(decodeInfo, pixels.get(), rowBytes, &options)) { 872 case SkCodec::kSuccess: 873 case SkCodec::kErrorInInput: 874 case SkCodec::kIncompleteInput: 875 break; 876 default: 877 return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str()); 878 } 879 draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, fDstColorType); 880 return ""; 881} 882 883SkISize AndroidCodecSrc::size() const { 884 sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str())); 885 std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::MakeFromData(encoded)); 886 if (nullptr == codec) { 887 return {0, 0}; 888 } 889 return codec->getSampledDimensions(fSampleSize); 890} 891 892Name AndroidCodecSrc::name() const { 893 // We will replicate the names used by CodecSrc so that images can 894 // be compared in Gold. 895 if (1 == fSampleSize) { 896 return SkOSPath::Basename(fPath.c_str()); 897 } 898 return get_scaled_name(fPath, 1.0f / (float) fSampleSize); 899} 900 901/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 902 903ImageGenSrc::ImageGenSrc(Path path, Mode mode, SkAlphaType alphaType, bool isGpu) 904 : fPath(path) 905 , fMode(mode) 906 , fDstAlphaType(alphaType) 907 , fIsGpu(isGpu) 908 , fRunSerially(serial_from_path_name(path)) 909{} 910 911bool ImageGenSrc::veto(SinkFlags flags) const { 912 if (fIsGpu) { 913 // MSAA runs tend to run out of memory and tests the same code paths as regular gpu configs. 914 return flags.type != SinkFlags::kGPU || flags.approach != SinkFlags::kDirect || 915 flags.multisampled == SinkFlags::kMultisampled; 916 } 917 918 return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDirect; 919} 920 921Error ImageGenSrc::draw(SkCanvas* canvas) const { 922 if (kRGB_565_SkColorType == canvas->imageInfo().colorType()) { 923 return Error::Nonfatal("Uninteresting to test image generator to 565."); 924 } 925 926 sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str())); 927 if (!encoded) { 928 return SkStringPrintf("Couldn't read %s.", fPath.c_str()); 929 } 930 931#if defined(SK_BUILD_FOR_WIN) 932 // Initialize COM in order to test with WIC. 933 SkAutoCoInitialize com; 934 if (!com.succeeded()) { 935 return "Could not initialize COM."; 936 } 937#endif 938 939 std::unique_ptr<SkImageGenerator> gen(nullptr); 940 switch (fMode) { 941 case kCodec_Mode: 942 gen = SkCodecImageGenerator::MakeFromEncodedCodec(encoded); 943 if (!gen) { 944 return "Could not create codec image generator."; 945 } 946 break; 947 case kPlatform_Mode: { 948#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) 949 gen = SkImageGeneratorCG::MakeFromEncodedCG(encoded); 950#elif defined(SK_BUILD_FOR_WIN) 951 gen.reset(SkImageGeneratorWIC::NewFromEncodedWIC(encoded.get())); 952#endif 953 954 if (!gen) { 955 return "Could not create platform image generator."; 956 } 957 break; 958 } 959 default: 960 SkASSERT(false); 961 return "Invalid image generator mode"; 962 } 963 964 // Test deferred decoding path on GPU 965 if (fIsGpu) { 966 sk_sp<SkImage> image(SkImage::MakeFromGenerator(std::move(gen), nullptr)); 967 if (!image) { 968 return "Could not create image from codec image generator."; 969 } 970 canvas->drawImage(image, 0, 0); 971 return ""; 972 } 973 974 // Test various color and alpha types on CPU 975 SkImageInfo decodeInfo = gen->getInfo().makeAlphaType(fDstAlphaType); 976 977 SkImageGenerator::Options options; 978 options.fBehavior = canvas->imageInfo().colorSpace() ? 979 SkTransferFunctionBehavior::kRespect : SkTransferFunctionBehavior::kIgnore; 980 981 int bpp = decodeInfo.bytesPerPixel(); 982 size_t rowBytes = decodeInfo.width() * bpp; 983 SkAutoMalloc pixels(decodeInfo.height() * rowBytes); 984 if (!gen->getPixels(decodeInfo, pixels.get(), rowBytes, &options)) { 985 SkString err = 986 SkStringPrintf("Image generator could not getPixels() for %s\n", fPath.c_str()); 987 988#if defined(SK_BUILD_FOR_WIN) 989 if (kPlatform_Mode == fMode) { 990 // Do not issue a fatal error for WIC flakiness. 991 return Error::Nonfatal(err); 992 } 993#endif 994 995 return err; 996 } 997 998 set_bitmap_color_space(&decodeInfo); 999 draw_to_canvas(canvas, decodeInfo, pixels.get(), rowBytes, 1000 CodecSrc::kGetFromCanvas_DstColorType); 1001 return ""; 1002} 1003 1004SkISize ImageGenSrc::size() const { 1005 sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str())); 1006 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(encoded)); 1007 if (nullptr == codec) { 1008 return {0, 0}; 1009 } 1010 return codec->getInfo().dimensions(); 1011} 1012 1013Name ImageGenSrc::name() const { 1014 return SkOSPath::Basename(fPath.c_str()); 1015} 1016 1017/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1018 1019ColorCodecSrc::ColorCodecSrc(Path path, Mode mode, SkColorType colorType) 1020 : fPath(path) 1021 , fMode(mode) 1022 , fColorType(colorType) 1023{} 1024 1025bool ColorCodecSrc::veto(SinkFlags flags) const { 1026 // Test to direct raster backends (8888 and 565). 1027 return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDirect; 1028} 1029 1030void clamp_if_necessary(const SkBitmap& bitmap, SkColorType dstCT) { 1031 if (kRGBA_F16_SkColorType != bitmap.colorType() || kRGBA_F16_SkColorType == dstCT) { 1032 // No need to clamp if the dst is F16. We will clamp when we encode to PNG. 1033 return; 1034 } 1035 1036 SkJumper_MemoryCtx ptr = { bitmap.getAddr(0,0), bitmap.rowBytesAsPixels() }; 1037 1038 SkRasterPipeline_<256> p; 1039 p.append(SkRasterPipeline::load_f16, &ptr); 1040 p.append(SkRasterPipeline::clamp_0); 1041 if (kPremul_SkAlphaType == bitmap.alphaType()) { 1042 p.append(SkRasterPipeline::clamp_a); 1043 } else { 1044 p.append(SkRasterPipeline::clamp_1); 1045 } 1046 p.append(SkRasterPipeline::store_f16, &ptr); 1047 1048 p.run(0,0, bitmap.width(), bitmap.height()); 1049} 1050 1051Error ColorCodecSrc::draw(SkCanvas* canvas) const { 1052 if (kRGB_565_SkColorType == canvas->imageInfo().colorType()) { 1053 return Error::Nonfatal("No need to test color correction to 565 backend."); 1054 } 1055 1056 bool runInLegacyMode = kBaseline_Mode == fMode; 1057 if (runInLegacyMode && canvas->imageInfo().colorSpace()) { 1058 return Error::Nonfatal("Skipping tests that are only interesting in legacy mode."); 1059 } else if (!runInLegacyMode && !canvas->imageInfo().colorSpace()) { 1060 return Error::Nonfatal("Skipping tests that are only interesting in srgb mode."); 1061 } 1062 1063 sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str())); 1064 if (!encoded) { 1065 return SkStringPrintf("Couldn't read %s.", fPath.c_str()); 1066 } 1067 1068 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(encoded)); 1069 if (nullptr == codec) { 1070 return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str()); 1071 } 1072 1073 // Load the dst ICC profile. This particular dst is fairly similar to Adobe RGB. 1074 sk_sp<SkData> dstData = GetResourceAsData("icc_profiles/HP_ZR30w.icc"); 1075 if (!dstData) { 1076 return "Cannot read monitor profile. Is the resource path set correctly?"; 1077 } 1078 1079 sk_sp<SkColorSpace> dstSpace = nullptr; 1080 if (kDst_sRGB_Mode == fMode) { 1081 dstSpace = SkColorSpace::MakeSRGB(); 1082 } else if (kDst_HPZR30w_Mode == fMode) { 1083 dstSpace = SkColorSpace::MakeICC(dstData->data(), dstData->size()); 1084 } 1085 1086 SkImageInfo decodeInfo = codec->getInfo().makeColorType(fColorType).makeColorSpace(dstSpace); 1087 if (kUnpremul_SkAlphaType == decodeInfo.alphaType()) { 1088 decodeInfo = decodeInfo.makeAlphaType(kPremul_SkAlphaType); 1089 } 1090 if (kRGBA_F16_SkColorType == fColorType) { 1091 decodeInfo = decodeInfo.makeColorSpace(decodeInfo.colorSpace()->makeLinearGamma()); 1092 } 1093 1094 SkImageInfo bitmapInfo = decodeInfo; 1095 set_bitmap_color_space(&bitmapInfo); 1096 if (kRGBA_8888_SkColorType == decodeInfo.colorType() || 1097 kBGRA_8888_SkColorType == decodeInfo.colorType()) 1098 { 1099 bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType); 1100 } 1101 1102 SkBitmap bitmap; 1103 if (!bitmap.tryAllocPixels(bitmapInfo)) { 1104 return SkStringPrintf("Image(%s) is too large (%d x %d)", fPath.c_str(), 1105 bitmapInfo.width(), bitmapInfo.height()); 1106 } 1107 1108 size_t rowBytes = bitmap.rowBytes(); 1109 SkCodec::Result r = codec->getPixels(decodeInfo, bitmap.getPixels(), rowBytes); 1110 switch (r) { 1111 case SkCodec::kSuccess: 1112 case SkCodec::kErrorInInput: 1113 case SkCodec::kIncompleteInput: 1114 break; 1115 default: 1116 return SkStringPrintf("Couldn't getPixels %s. Error code %d", fPath.c_str(), r); 1117 } 1118 1119 switch (fMode) { 1120 case kBaseline_Mode: 1121 case kDst_sRGB_Mode: 1122 case kDst_HPZR30w_Mode: 1123 // We do not support drawing unclamped F16. 1124 clamp_if_necessary(bitmap, canvas->imageInfo().colorType()); 1125 canvas->drawBitmap(bitmap, 0, 0); 1126 break; 1127 default: 1128 SkASSERT(false); 1129 return "Invalid fMode"; 1130 } 1131 return ""; 1132} 1133 1134SkISize ColorCodecSrc::size() const { 1135 sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str())); 1136 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(encoded)); 1137 if (nullptr == codec) { 1138 return {0, 0}; 1139 } 1140 return {codec->getInfo().width(), codec->getInfo().height()}; 1141} 1142 1143Name ColorCodecSrc::name() const { 1144 return SkOSPath::Basename(fPath.c_str()); 1145} 1146 1147/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1148 1149static const SkRect kSKPViewport = {0, 0, 1000, 1000}; 1150 1151SKPSrc::SKPSrc(Path path) : fPath(path) { } 1152 1153static sk_sp<SkPicture> read_skp(const char* path) { 1154 std::unique_ptr<SkStream> stream = SkStream::MakeFromFile(path); 1155 if (!stream) { 1156 return nullptr; 1157 } 1158 sk_sp<SkPicture> pic(SkPicture::MakeFromStream(stream.get())); 1159 if (!pic) { 1160 return nullptr; 1161 } 1162 stream = nullptr; // Might as well drop this when we're done with it. 1163 1164 return pic; 1165} 1166 1167Error SKPSrc::draw(SkCanvas* canvas) const { 1168 sk_sp<SkPicture> pic = read_skp(fPath.c_str()); 1169 if (!pic) { 1170 return SkStringPrintf("Couldn't read %s.", fPath.c_str()); 1171 } 1172 1173 canvas->clipRect(kSKPViewport); 1174 canvas->drawPicture(pic); 1175 return ""; 1176} 1177 1178static SkRect get_cull_rect_for_skp(const char* path) { 1179 std::unique_ptr<SkStream> stream = SkStream::MakeFromFile(path); 1180 if (!stream) { 1181 return SkRect::MakeEmpty(); 1182 } 1183 SkPictInfo info; 1184 if (!SkPicture_StreamIsSKP(stream.get(), &info)) { 1185 return SkRect::MakeEmpty(); 1186 } 1187 1188 return info.fCullRect; 1189} 1190 1191SkISize SKPSrc::size() const { 1192 SkRect viewport = get_cull_rect_for_skp(fPath.c_str()); 1193 if (!viewport.intersect(kSKPViewport)) { 1194 return {0, 0}; 1195 } 1196 return viewport.roundOut().size(); 1197} 1198 1199Name SKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); } 1200 1201/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1202 1203static const int kNumDDLXTiles = 4; 1204static const int kNumDDLYTiles = 4; 1205static const int kDDLTileSize = 1024; 1206static const SkRect kDDLSKPViewport = { 0, 0, 1207 kNumDDLXTiles * kDDLTileSize, 1208 kNumDDLYTiles * kDDLTileSize }; 1209 1210DDLSKPSrc::DDLSKPSrc(Path path) : fPath(path) { } 1211 1212Error DDLSKPSrc::draw(SkCanvas* canvas) const { 1213 class TileData { 1214 public: 1215 // Note: we could just pass in surface characterization 1216 TileData(sk_sp<SkSurface> surf, const SkIRect& clip) 1217 : fSurface(std::move(surf)) 1218 , fClip(clip) { 1219 SkAssertResult(fSurface->characterize(&fCharacterization)); 1220 } 1221 1222 // This method operates in parallel 1223 void preprocess(SkPicture* pic) { 1224 SkDeferredDisplayListRecorder recorder(fCharacterization); 1225 1226 SkCanvas* subCanvas = recorder.getCanvas(); 1227 1228 subCanvas->clipRect(SkRect::MakeWH(fClip.width(), fClip.height())); 1229 subCanvas->translate(-fClip.fLeft, -fClip.fTop); 1230 1231 // Note: in this use case we only render a picture to the deferred canvas 1232 // but, more generally, clients will use arbitrary draw calls. 1233 subCanvas->drawPicture(pic); 1234 1235 fDisplayList = recorder.detach(); 1236 } 1237 1238 // This method operates serially 1239 void draw() { 1240 fSurface->draw(fDisplayList.get()); 1241 } 1242 1243 // This method also operates serially 1244 void compose(SkCanvas* dst) { 1245 sk_sp<SkImage> img = fSurface->makeImageSnapshot(); 1246 dst->save(); 1247 dst->clipRect(SkRect::Make(fClip)); 1248 dst->drawImage(std::move(img), fClip.fLeft, fClip.fTop); 1249 dst->restore(); 1250 } 1251 1252 private: 1253 sk_sp<SkSurface> fSurface; 1254 SkIRect fClip; // in the device space of the destination canvas 1255 std::unique_ptr<SkDeferredDisplayList> fDisplayList; 1256 SkSurfaceCharacterization fCharacterization; 1257 }; 1258 1259 SkTArray<TileData> tileData; 1260 tileData.reserve(16); 1261 1262 sk_sp<SkPicture> pic = read_skp(fPath.c_str()); 1263 if (!pic) { 1264 return SkStringPrintf("Couldn't read %s.", fPath.c_str()); 1265 } 1266 1267 const SkRect cullRect = pic->cullRect(); 1268 1269 // All the destination tiles are the same size 1270 const SkImageInfo tileII = SkImageInfo::MakeN32Premul(kDDLTileSize, kDDLTileSize); 1271 1272 // First, create the destination tiles 1273 for (int y = 0; y < kNumDDLYTiles; ++y) { 1274 for (int x = 0; x < kNumDDLXTiles; ++x) { 1275 SkRect clip = SkRect::MakeXYWH(x * kDDLTileSize, y * kDDLTileSize, 1276 kDDLTileSize, kDDLTileSize); 1277 1278 if (!clip.intersect(cullRect)) { 1279 continue; 1280 } 1281 1282 tileData.push_back(TileData(canvas->makeSurface(tileII), clip.roundOut())); 1283 } 1284 } 1285 1286 // Second, run the cpu pre-processing in threads 1287 SkTaskGroup().batch(tileData.count(), [&](int i) { 1288 tileData[i].preprocess(pic.get()); 1289 }); 1290 1291 // Third, synchronously render the display lists into the dest tiles 1292 // TODO: it would be cool to not wait until all the tiles are drawn to begin 1293 // drawing to the GPU 1294 for (int i = 0; i < tileData.count(); ++i) { 1295 tileData[i].draw(); 1296 } 1297 1298 // Finally, compose the drawn tiles into the result 1299 // Note: the separation between the tiles and the final composition better 1300 // matches Chrome but costs us a copy 1301 for (int i = 0; i < tileData.count(); ++i) { 1302 tileData[i].compose(canvas); 1303 } 1304 1305 return ""; 1306} 1307 1308SkISize DDLSKPSrc::size() const { 1309 SkRect viewport = get_cull_rect_for_skp(fPath.c_str()); 1310 if (!viewport.intersect(kDDLSKPViewport)) { 1311 return {0, 0}; 1312 } 1313 return viewport.roundOut().size(); 1314} 1315 1316Name DDLSKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); } 1317 1318/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1319 1320#if !defined(SK_BUILD_FOR_GOOGLE3) 1321SkottieSrc::SkottieSrc(Path path) 1322 : fName(SkOSPath::Basename(path.c_str())) { 1323 1324 fAnimation = skottie::Animation::MakeFromFile(path.c_str()); 1325 if (!fAnimation) { 1326 return; 1327 } 1328 1329 // Fit kTileCount x kTileCount frames to a 1000x1000 film strip. 1330 static constexpr SkScalar kTargetSize = 1000; 1331 const auto scale = kTargetSize / (kTileCount * std::max(fAnimation->size().width(), 1332 fAnimation->size().height())); 1333 fTileSize = SkSize::Make(scale * fAnimation->size().width(), 1334 scale * fAnimation->size().height()).toCeil(); 1335 1336} 1337 1338Error SkottieSrc::draw(SkCanvas* canvas) const { 1339 if (!fAnimation) { 1340 return SkStringPrintf("Unable to parse file: %s", fName.c_str()); 1341 } 1342 1343 canvas->drawColor(SK_ColorWHITE); 1344 1345 SkPaint paint, clockPaint; 1346 paint.setColor(0xffa0a0a0); 1347 paint.setStyle(SkPaint::kStroke_Style); 1348 paint.setStrokeWidth(1); 1349 paint.setAntiAlias(true); 1350 1351 clockPaint.setTextSize(12); 1352 clockPaint.setAntiAlias(true); 1353 1354 const auto ip = fAnimation->inPoint() * 1000 / fAnimation->frameRate(), 1355 op = fAnimation->outPoint() * 1000 / fAnimation->frameRate(), 1356 fr = (op - ip) / (kTileCount * kTileCount - 1); 1357 1358 // Shuffled order to exercise non-linear frame progression. 1359 static constexpr int frames[] = { 4, 0, 3, 1, 2 }; 1360 static_assert(SK_ARRAY_COUNT(frames) == kTileCount, ""); 1361 1362 const auto canvas_size = this->size(); 1363 for (int i = 0; i < kTileCount; ++i) { 1364 const SkScalar y = frames[i] * (fTileSize.height() + 1); 1365 1366 for (int j = 0; j < kTileCount; ++j) { 1367 const SkScalar x = frames[j] * (fTileSize.width() + 1); 1368 SkRect dest = SkRect::MakeXYWH(x, y, fTileSize.width(), fTileSize.height()); 1369 1370 const auto t = fr * (frames[i] * kTileCount + frames[j]); 1371 { 1372 SkAutoCanvasRestore acr(canvas, true); 1373 canvas->clipRect(dest, true); 1374 canvas->concat(SkMatrix::MakeRectToRect(SkRect::MakeSize(fAnimation->size()), 1375 dest, 1376 SkMatrix::kFill_ScaleToFit)); 1377 1378 fAnimation->animationTick(t); 1379 fAnimation->render(canvas); 1380 } 1381 1382 canvas->drawLine(x + fTileSize.width() + .5f, 0, 1383 x + fTileSize.width() + .5f, canvas_size.height(), paint); 1384 const auto label = SkStringPrintf("%.3f", t); 1385 canvas->drawText(label.c_str(), label.size(), dest.x(), 1386 dest.bottom(), clockPaint); 1387 } 1388 1389 canvas->drawLine(0 , y + fTileSize.height() + .5f, 1390 canvas_size.width(), y + fTileSize.height() + .5f, paint); 1391 } 1392 1393 return ""; 1394} 1395 1396SkISize SkottieSrc::size() const { 1397 // Padding for grid. 1398 return SkISize::Make(kTileCount * (fTileSize.width() + 1), 1399 kTileCount * (fTileSize.height() + 1)); 1400} 1401 1402Name SkottieSrc::name() const { return fName; } 1403 1404bool SkottieSrc::veto(SinkFlags flags) const { 1405 // No need to test to non-(raster||gpu||vector) or indirect backends. 1406 bool type_ok = flags.type == SinkFlags::kRaster 1407 || flags.type == SinkFlags::kGPU 1408 || flags.type == SinkFlags::kVector; 1409 1410 return !type_ok || flags.approach != SinkFlags::kDirect; 1411} 1412#endif 1413 1414/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1415#if defined(SK_XML) 1416// Used when the image doesn't have an intrinsic size. 1417static const SkSize kDefaultSVGSize = {1000, 1000}; 1418 1419// Used to force-scale tiny fixed-size images. 1420static const SkSize kMinimumSVGSize = {128, 128}; 1421 1422SVGSrc::SVGSrc(Path path) 1423 : fName(SkOSPath::Basename(path.c_str())) 1424 , fScale(1) { 1425 1426 SkFILEStream stream(path.c_str()); 1427 if (!stream.isValid()) { 1428 return; 1429 } 1430 fDom = SkSVGDOM::MakeFromStream(stream); 1431 if (!fDom) { 1432 return; 1433 } 1434 1435 const SkSize& sz = fDom->containerSize(); 1436 if (sz.isEmpty()) { 1437 // no intrinsic size 1438 fDom->setContainerSize(kDefaultSVGSize); 1439 } else { 1440 fScale = SkTMax(1.f, SkTMax(kMinimumSVGSize.width() / sz.width(), 1441 kMinimumSVGSize.height() / sz.height())); 1442 } 1443} 1444 1445Error SVGSrc::draw(SkCanvas* canvas) const { 1446 if (!fDom) { 1447 return SkStringPrintf("Unable to parse file: %s", fName.c_str()); 1448 } 1449 1450 SkAutoCanvasRestore acr(canvas, true); 1451 canvas->scale(fScale, fScale); 1452 fDom->render(canvas); 1453 1454 return ""; 1455} 1456 1457SkISize SVGSrc::size() const { 1458 if (!fDom) { 1459 return {0, 0}; 1460 } 1461 1462 return SkSize{fDom->containerSize().width() * fScale, fDom->containerSize().height() * fScale} 1463 .toRound(); 1464} 1465 1466Name SVGSrc::name() const { return fName; } 1467 1468bool SVGSrc::veto(SinkFlags flags) const { 1469 // No need to test to non-(raster||gpu||vector) or indirect backends. 1470 bool type_ok = flags.type == SinkFlags::kRaster 1471 || flags.type == SinkFlags::kGPU 1472 || flags.type == SinkFlags::kVector; 1473 1474 return !type_ok || flags.approach != SinkFlags::kDirect; 1475} 1476 1477#endif // defined(SK_XML) 1478/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1479 1480MSKPSrc::MSKPSrc(Path path) : fPath(path) { 1481 std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(fPath.c_str()); 1482 int count = SkMultiPictureDocumentReadPageCount(stream.get()); 1483 if (count > 0) { 1484 fPages.reset(count); 1485 (void)SkMultiPictureDocumentReadPageSizes(stream.get(), &fPages[0], fPages.count()); 1486 } 1487} 1488 1489int MSKPSrc::pageCount() const { return fPages.count(); } 1490 1491SkISize MSKPSrc::size() const { return this->size(0); } 1492SkISize MSKPSrc::size(int i) const { 1493 return i >= 0 && i < fPages.count() ? fPages[i].fSize.toCeil() : SkISize{0, 0}; 1494} 1495 1496Error MSKPSrc::draw(SkCanvas* c) const { return this->draw(0, c); } 1497Error MSKPSrc::draw(int i, SkCanvas* canvas) const { 1498 if (this->pageCount() == 0) { 1499 return SkStringPrintf("Unable to parse MultiPictureDocument file: %s", fPath.c_str()); 1500 } 1501 if (i >= fPages.count() || i < 0) { 1502 return SkStringPrintf("MultiPictureDocument page number out of range: %d", i); 1503 } 1504 SkPicture* page = fPages[i].fPicture.get(); 1505 if (!page) { 1506 std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(fPath.c_str()); 1507 if (!stream) { 1508 return SkStringPrintf("Unable to open file: %s", fPath.c_str()); 1509 } 1510 if (!SkMultiPictureDocumentRead(stream.get(), &fPages[0], fPages.count())) { 1511 return SkStringPrintf("SkMultiPictureDocument reader failed on page %d: %s", i, 1512 fPath.c_str()); 1513 } 1514 page = fPages[i].fPicture.get(); 1515 } 1516 canvas->drawPicture(page); 1517 return ""; 1518} 1519 1520Name MSKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); } 1521 1522/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1523 1524Error NullSink::draw(const Src& src, SkBitmap*, SkWStream*, SkString*) const { 1525 return src.draw(SkMakeNullCanvas().get()); 1526} 1527 1528/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1529 1530static bool encode_png_base64(const SkBitmap& bitmap, SkString* dst) { 1531 SkPixmap pm; 1532 if (!bitmap.peekPixels(&pm)) { 1533 dst->set("peekPixels failed"); 1534 return false; 1535 } 1536 1537 // We're going to embed this PNG in a data URI, so make it as small as possible 1538 SkPngEncoder::Options options; 1539 options.fFilterFlags = SkPngEncoder::FilterFlag::kAll; 1540 options.fZLibLevel = 9; 1541 options.fUnpremulBehavior = pm.colorSpace() ? SkTransferFunctionBehavior::kRespect 1542 : SkTransferFunctionBehavior::kIgnore; 1543 1544 SkDynamicMemoryWStream wStream; 1545 if (!SkPngEncoder::Encode(&wStream, pm, options)) { 1546 dst->set("SkPngEncoder::Encode failed"); 1547 return false; 1548 } 1549 1550 sk_sp<SkData> pngData = wStream.detachAsData(); 1551 size_t len = SkBase64::Encode(pngData->data(), pngData->size(), nullptr); 1552 1553 // The PNG can be almost arbitrarily large. We don't want to fill our logs with enormous URLs. 1554 // Infra says these can be pretty big, as long as we're only outputting them on failure. 1555 static const size_t kMaxBase64Length = 1024 * 1024; 1556 if (len > kMaxBase64Length) { 1557 dst->printf("Encoded image too large (%u bytes)", static_cast<uint32_t>(len)); 1558 return false; 1559 } 1560 1561 dst->resize(len); 1562 SkBase64::Encode(pngData->data(), pngData->size(), dst->writable_str()); 1563 return true; 1564} 1565 1566static Error compare_bitmaps(const SkBitmap& reference, const SkBitmap& bitmap) { 1567 // The dimensions are a property of the Src only, and so should be identical. 1568 SkASSERT(reference.computeByteSize() == bitmap.computeByteSize()); 1569 if (reference.computeByteSize() != bitmap.computeByteSize()) { 1570 return "Dimensions don't match reference"; 1571 } 1572 // All SkBitmaps in DM are tight, so this comparison is easy. 1573 if (0 != memcmp(reference.getPixels(), bitmap.getPixels(), reference.computeByteSize())) { 1574 SkString encoded; 1575 SkString errString("Pixels don't match reference"); 1576 if (encode_png_base64(reference, &encoded)) { 1577 errString.append("\nExpected: data:image/png;base64,"); 1578 errString.append(encoded); 1579 } else { 1580 errString.append("\nExpected image failed to encode: "); 1581 errString.append(encoded); 1582 } 1583 if (encode_png_base64(bitmap, &encoded)) { 1584 errString.append("\nActual: data:image/png;base64,"); 1585 errString.append(encoded); 1586 } else { 1587 errString.append("\nActual image failed to encode: "); 1588 errString.append(encoded); 1589 } 1590 return errString; 1591 } 1592 return ""; 1593} 1594 1595/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1596 1597DEFINE_bool(gpuStats, false, "Append GPU stats to the log for each GPU task?"); 1598 1599GPUSink::GPUSink(GrContextFactory::ContextType ct, 1600 GrContextFactory::ContextOverrides overrides, 1601 int samples, 1602 bool diText, 1603 SkColorType colorType, 1604 SkAlphaType alphaType, 1605 sk_sp<SkColorSpace> colorSpace, 1606 bool threaded, 1607 const GrContextOptions& grCtxOptions) 1608 : fContextType(ct) 1609 , fContextOverrides(overrides) 1610 , fSampleCount(samples) 1611 , fUseDIText(diText) 1612 , fColorType(colorType) 1613 , fAlphaType(alphaType) 1614 , fColorSpace(std::move(colorSpace)) 1615 , fThreaded(threaded) 1616 , fBaseContextOptions(grCtxOptions) {} 1617 1618DEFINE_bool(drawOpClip, false, "Clip each GrDrawOp to its device bounds for testing."); 1619 1620Error GPUSink::draw(const Src& src, SkBitmap* dst, SkWStream* dstStream, SkString* log) const { 1621 return this->onDraw(src, dst, dstStream, log, fBaseContextOptions); 1622} 1623 1624Error GPUSink::onDraw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log, 1625 const GrContextOptions& baseOptions) const { 1626 GrContextOptions grOptions = baseOptions; 1627 1628 src.modifyGrContextOptions(&grOptions); 1629 1630 GrContextFactory factory(grOptions); 1631 const SkISize size = src.size(); 1632 SkImageInfo info = 1633 SkImageInfo::Make(size.width(), size.height(), fColorType, fAlphaType, fColorSpace); 1634#if SK_SUPPORT_GPU 1635 GrContext* context = factory.getContextInfo(fContextType, fContextOverrides).grContext(); 1636 const int maxDimension = context->caps()->maxTextureSize(); 1637 if (maxDimension < SkTMax(size.width(), size.height())) { 1638 return Error::Nonfatal("Src too large to create a texture.\n"); 1639 } 1640#endif 1641 1642 auto surface( 1643 NewGpuSurface(&factory, fContextType, fContextOverrides, info, fSampleCount, fUseDIText)); 1644 if (!surface) { 1645 return "Could not create a surface."; 1646 } 1647 if (FLAGS_preAbandonGpuContext) { 1648 factory.abandonContexts(); 1649 } 1650 SkCanvas* canvas = surface->getCanvas(); 1651 Error err = src.draw(canvas); 1652 if (!err.isEmpty()) { 1653 return err; 1654 } 1655 canvas->flush(); 1656 if (FLAGS_gpuStats) { 1657 canvas->getGrContext()->dumpCacheStats(log); 1658 canvas->getGrContext()->dumpGpuStats(log); 1659 } 1660 if (info.colorType() == kRGB_565_SkColorType || info.colorType() == kARGB_4444_SkColorType) { 1661 // We don't currently support readbacks into these formats on the GPU backend. Convert to 1662 // 32 bit. 1663 info = SkImageInfo::Make(size.width(), size.height(), kRGBA_8888_SkColorType, 1664 kPremul_SkAlphaType, fColorSpace); 1665 } 1666 dst->allocPixels(info); 1667 canvas->readPixels(*dst, 0, 0); 1668 if (FLAGS_abandonGpuContext) { 1669 factory.abandonContexts(); 1670 } else if (FLAGS_releaseAndAbandonGpuContext) { 1671 factory.releaseResourcesAndAbandonContexts(); 1672 } 1673 return ""; 1674} 1675 1676/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1677 1678GPUThreadTestingSink::GPUThreadTestingSink(GrContextFactory::ContextType ct, 1679 GrContextFactory::ContextOverrides overrides, 1680 int samples, 1681 bool diText, 1682 SkColorType colorType, 1683 SkAlphaType alphaType, 1684 sk_sp<SkColorSpace> colorSpace, 1685 bool threaded, 1686 const GrContextOptions& grCtxOptions) 1687 : INHERITED(ct, overrides, samples, diText, colorType, alphaType, std::move(colorSpace), 1688 threaded, grCtxOptions) 1689#if SK_SUPPORT_GPU 1690 , fExecutor(SkExecutor::MakeFIFOThreadPool(FLAGS_gpuThreads)) { 1691#else 1692 , fExecutor(nullptr) { 1693#endif 1694 SkASSERT(fExecutor); 1695} 1696 1697Error GPUThreadTestingSink::draw(const Src& src, SkBitmap* dst, SkWStream* wStream, 1698 SkString* log) const { 1699 // Draw twice, once with worker threads, and once without. Verify that we get the same result. 1700 // Also, force us to only use the software path renderer, so we really stress-test the threaded 1701 // version of that code. 1702 GrContextOptions contextOptions = this->baseContextOptions(); 1703 contextOptions.fGpuPathRenderers = GpuPathRenderers::kNone; 1704 1705 contextOptions.fExecutor = fExecutor.get(); 1706 Error err = this->onDraw(src, dst, wStream, log, contextOptions); 1707 if (!err.isEmpty() || !dst) { 1708 return err; 1709 } 1710 1711 SkBitmap reference; 1712 SkString refLog; 1713 SkDynamicMemoryWStream refStream; 1714 contextOptions.fExecutor = nullptr; 1715 Error refErr = this->onDraw(src, &reference, &refStream, &refLog, contextOptions); 1716 if (!refErr.isEmpty()) { 1717 return refErr; 1718 } 1719 1720 return compare_bitmaps(reference, *dst); 1721} 1722 1723/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1724 1725static Error draw_skdocument(const Src& src, SkDocument* doc, SkWStream* dst) { 1726 if (src.size().isEmpty()) { 1727 return "Source has empty dimensions"; 1728 } 1729 SkASSERT(doc); 1730 int pageCount = src.pageCount(); 1731 for (int i = 0; i < pageCount; ++i) { 1732 int width = src.size(i).width(), height = src.size(i).height(); 1733 SkCanvas* canvas = 1734 doc->beginPage(SkIntToScalar(width), SkIntToScalar(height)); 1735 if (!canvas) { 1736 return "SkDocument::beginPage(w,h) returned nullptr"; 1737 } 1738 Error err = src.draw(i, canvas); 1739 if (!err.isEmpty()) { 1740 return err; 1741 } 1742 doc->endPage(); 1743 } 1744 doc->close(); 1745 dst->flush(); 1746 return ""; 1747} 1748 1749Error PDFSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const { 1750 SkDocument::PDFMetadata metadata; 1751 metadata.fTitle = src.name(); 1752 metadata.fSubject = "rendering correctness test"; 1753 metadata.fCreator = "Skia/DM"; 1754 metadata.fRasterDPI = fRasterDpi; 1755 metadata.fPDFA = fPDFA; 1756 sk_sp<SkDocument> doc = SkDocument::MakePDF(dst, metadata); 1757 if (!doc) { 1758 return "SkDocument::MakePDF() returned nullptr"; 1759 } 1760 return draw_skdocument(src, doc.get(), dst); 1761} 1762 1763/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1764 1765XPSSink::XPSSink() {} 1766 1767#ifdef SK_BUILD_FOR_WIN 1768static SkTScopedComPtr<IXpsOMObjectFactory> make_xps_factory() { 1769 IXpsOMObjectFactory* factory; 1770 HRN(CoCreateInstance(CLSID_XpsOMObjectFactory, 1771 nullptr, 1772 CLSCTX_INPROC_SERVER, 1773 IID_PPV_ARGS(&factory))); 1774 return SkTScopedComPtr<IXpsOMObjectFactory>(factory); 1775} 1776 1777Error XPSSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const { 1778 SkAutoCoInitialize com; 1779 if (!com.succeeded()) { 1780 return "Could not initialize COM."; 1781 } 1782 SkTScopedComPtr<IXpsOMObjectFactory> factory = make_xps_factory(); 1783 if (!factory) { 1784 return "Failed to create XPS Factory."; 1785 } 1786 sk_sp<SkDocument> doc(SkDocument::MakeXPS(dst, factory.get())); 1787 if (!doc) { 1788 return "SkDocument::MakeXPS() returned nullptr"; 1789 } 1790 return draw_skdocument(src, doc.get(), dst); 1791} 1792#else 1793Error XPSSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const { 1794 return "XPS not supported on this platform."; 1795} 1796#endif 1797 1798/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1799 1800PipeSink::PipeSink() {} 1801 1802Error PipeSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const { 1803 return src.draw(SkPipeSerializer().beginWrite(SkRect::Make(src.size()), dst)); 1804} 1805 1806/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1807 1808SKPSink::SKPSink() {} 1809 1810Error SKPSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const { 1811 SkSize size; 1812 size = src.size(); 1813 SkPictureRecorder recorder; 1814 Error err = src.draw(recorder.beginRecording(size.width(), size.height())); 1815 if (!err.isEmpty()) { 1816 return err; 1817 } 1818 recorder.finishRecordingAsPicture()->serialize(dst); 1819 return ""; 1820} 1821 1822/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1823 1824Error DebugSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const { 1825 SkDebugCanvas debugCanvas(src.size().width(), src.size().height()); 1826 Error err = src.draw(&debugCanvas); 1827 if (!err.isEmpty()) { 1828 return err; 1829 } 1830 std::unique_ptr<SkCanvas> nullCanvas = SkMakeNullCanvas(); 1831 UrlDataManager dataManager(SkString("data")); 1832 Json::Value json = debugCanvas.toJSON( 1833 dataManager, debugCanvas.getSize(), nullCanvas.get()); 1834 std::string value = Json::StyledWriter().write(json); 1835 return dst->write(value.c_str(), value.size()) ? "" : "SkWStream Error"; 1836} 1837 1838/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1839 1840SVGSink::SVGSink() {} 1841 1842Error SVGSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const { 1843#if defined(SK_XML) 1844 std::unique_ptr<SkXMLWriter> xmlWriter(new SkXMLStreamWriter(dst)); 1845 return src.draw(SkSVGCanvas::Make(SkRect::MakeWH(SkIntToScalar(src.size().width()), 1846 SkIntToScalar(src.size().height())), 1847 xmlWriter.get()).get()); 1848#else 1849 return Error("SVG sink is disabled."); 1850#endif // SK_XML 1851} 1852 1853/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1854 1855RasterSink::RasterSink(SkColorType colorType, sk_sp<SkColorSpace> colorSpace) 1856 : fColorType(colorType) 1857 , fColorSpace(std::move(colorSpace)) {} 1858 1859Error RasterSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString*) const { 1860 const SkISize size = src.size(); 1861 // If there's an appropriate alpha type for this color type, use it, otherwise use premul. 1862 SkAlphaType alphaType = kPremul_SkAlphaType; 1863 (void)SkColorTypeValidateAlphaType(fColorType, alphaType, &alphaType); 1864 1865 dst->allocPixelsFlags(SkImageInfo::Make(size.width(), size.height(), 1866 fColorType, alphaType, fColorSpace), 1867 SkBitmap::kZeroPixels_AllocFlag); 1868 SkCanvas canvas(*dst); 1869 return src.draw(&canvas); 1870} 1871 1872/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1873 1874// Handy for front-patching a Src. Do whatever up-front work you need, then call draw_to_canvas(), 1875// passing the Sink draw() arguments, a size, and a function draws into an SkCanvas. 1876// Several examples below. 1877 1878template <typename Fn> 1879static Error draw_to_canvas(Sink* sink, SkBitmap* bitmap, SkWStream* stream, SkString* log, 1880 SkISize size, const Fn& draw) { 1881 class ProxySrc : public Src { 1882 public: 1883 ProxySrc(SkISize size, const Fn& draw) : fSize(size), fDraw(draw) {} 1884 Error draw(SkCanvas* canvas) const override { return fDraw(canvas); } 1885 Name name() const override { return "ProxySrc"; } 1886 SkISize size() const override { return fSize; } 1887 private: 1888 SkISize fSize; 1889 const Fn& fDraw; 1890 }; 1891 return sink->draw(ProxySrc(size, draw), bitmap, stream, log); 1892} 1893 1894/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1895 1896DEFINE_bool(check, true, "If true, have most Via- modes fail if they affect the output."); 1897 1898// Is *bitmap identical to what you get drawing src into sink? 1899static Error check_against_reference(const SkBitmap* bitmap, const Src& src, Sink* sink) { 1900 // We can only check raster outputs. 1901 // (Non-raster outputs like .pdf, .skp, .svg may differ but still draw identically.) 1902 if (FLAGS_check && bitmap) { 1903 SkBitmap reference; 1904 SkString log; 1905 SkDynamicMemoryWStream wStream; 1906 Error err = sink->draw(src, &reference, &wStream, &log); 1907 // If we can draw into this Sink via some pipeline, we should be able to draw directly. 1908 SkASSERT(err.isEmpty()); 1909 if (!err.isEmpty()) { 1910 return err; 1911 } 1912 return compare_bitmaps(reference, *bitmap); 1913 } 1914 return ""; 1915} 1916 1917/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1918 1919static SkISize auto_compute_translate(SkMatrix* matrix, int srcW, int srcH) { 1920 SkRect bounds = SkRect::MakeIWH(srcW, srcH); 1921 matrix->mapRect(&bounds); 1922 matrix->postTranslate(-bounds.x(), -bounds.y()); 1923 return {SkScalarRoundToInt(bounds.width()), SkScalarRoundToInt(bounds.height())}; 1924} 1925 1926ViaMatrix::ViaMatrix(SkMatrix matrix, Sink* sink) : Via(sink), fMatrix(matrix) {} 1927 1928Error ViaMatrix::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 1929 SkMatrix matrix = fMatrix; 1930 SkISize size = auto_compute_translate(&matrix, src.size().width(), src.size().height()); 1931 return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) { 1932 canvas->concat(matrix); 1933 return src.draw(canvas); 1934 }); 1935} 1936 1937// Undoes any flip or 90 degree rotate without changing the scale of the bitmap. 1938// This should be pixel-preserving. 1939ViaUpright::ViaUpright(SkMatrix matrix, Sink* sink) : Via(sink), fMatrix(matrix) {} 1940 1941Error ViaUpright::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 1942 Error err = fSink->draw(src, bitmap, stream, log); 1943 if (!err.isEmpty()) { 1944 return err; 1945 } 1946 1947 SkMatrix inverse; 1948 if (!fMatrix.rectStaysRect() || !fMatrix.invert(&inverse)) { 1949 return "Cannot upright --matrix."; 1950 } 1951 SkMatrix upright = SkMatrix::I(); 1952 upright.setScaleX(SkScalarSignAsScalar(inverse.getScaleX())); 1953 upright.setScaleY(SkScalarSignAsScalar(inverse.getScaleY())); 1954 upright.setSkewX(SkScalarSignAsScalar(inverse.getSkewX())); 1955 upright.setSkewY(SkScalarSignAsScalar(inverse.getSkewY())); 1956 1957 SkBitmap uprighted; 1958 SkISize size = auto_compute_translate(&upright, bitmap->width(), bitmap->height()); 1959 uprighted.allocPixels(bitmap->info().makeWH(size.width(), size.height())); 1960 1961 SkCanvas canvas(uprighted); 1962 canvas.concat(upright); 1963 SkPaint paint; 1964 paint.setBlendMode(SkBlendMode::kSrc); 1965 canvas.drawBitmap(*bitmap, 0, 0, &paint); 1966 1967 *bitmap = uprighted; 1968 return ""; 1969} 1970 1971/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1972 1973Error ViaSerialization::draw( 1974 const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 1975 // Record our Src into a picture. 1976 auto size = src.size(); 1977 SkPictureRecorder recorder; 1978 Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()), 1979 SkIntToScalar(size.height()))); 1980 if (!err.isEmpty()) { 1981 return err; 1982 } 1983 sk_sp<SkPicture> pic(recorder.finishRecordingAsPicture()); 1984 1985 // Serialize it and then deserialize it. 1986 sk_sp<SkPicture> deserialized(SkPicture::MakeFromData(pic->serialize().get())); 1987 1988 return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) { 1989 canvas->drawPicture(deserialized); 1990 return check_against_reference(bitmap, src, fSink.get()); 1991 }); 1992} 1993 1994/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 1995 1996ViaTiles::ViaTiles(int w, int h, SkBBHFactory* factory, Sink* sink) 1997 : Via(sink) 1998 , fW(w) 1999 , fH(h) 2000 , fFactory(factory) {} 2001 2002Error ViaTiles::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 2003 auto size = src.size(); 2004 SkPictureRecorder recorder; 2005 Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()), 2006 SkIntToScalar(size.height()), 2007 fFactory.get())); 2008 if (!err.isEmpty()) { 2009 return err; 2010 } 2011 sk_sp<SkPicture> pic(recorder.finishRecordingAsPicture()); 2012 2013 return draw_to_canvas(fSink.get(), bitmap, stream, log, src.size(), [&](SkCanvas* canvas) { 2014 const int xTiles = (size.width() + fW - 1) / fW, 2015 yTiles = (size.height() + fH - 1) / fH; 2016 SkMultiPictureDraw mpd(xTiles*yTiles); 2017 SkTArray<sk_sp<SkSurface>> surfaces; 2018// surfaces.setReserve(xTiles*yTiles); 2019 2020 SkImageInfo info = canvas->imageInfo().makeWH(fW, fH); 2021 for (int j = 0; j < yTiles; j++) { 2022 for (int i = 0; i < xTiles; i++) { 2023 // This lets our ultimate Sink determine the best kind of surface. 2024 // E.g., if it's a GpuSink, the surfaces and images are textures. 2025 auto s = canvas->makeSurface(info); 2026 if (!s) { 2027 s = SkSurface::MakeRaster(info); // Some canvases can't create surfaces. 2028 } 2029 surfaces.push_back(s); 2030 SkCanvas* c = s->getCanvas(); 2031 c->translate(SkIntToScalar(-i * fW), 2032 SkIntToScalar(-j * fH)); // Line up the canvas with this tile. 2033 mpd.add(c, pic.get()); 2034 } 2035 } 2036 mpd.draw(); 2037 for (int j = 0; j < yTiles; j++) { 2038 for (int i = 0; i < xTiles; i++) { 2039 sk_sp<SkImage> image(surfaces[i+xTiles*j]->makeImageSnapshot()); 2040 canvas->drawImage(image, SkIntToScalar(i*fW), SkIntToScalar(j*fH)); 2041 } 2042 } 2043 return ""; 2044 }); 2045} 2046 2047/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 2048 2049Error ViaPicture::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 2050 auto size = src.size(); 2051 return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error { 2052 SkPictureRecorder recorder; 2053 sk_sp<SkPicture> pic; 2054 Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()), 2055 SkIntToScalar(size.height()))); 2056 if (!err.isEmpty()) { 2057 return err; 2058 } 2059 pic = recorder.finishRecordingAsPicture(); 2060 canvas->drawPicture(pic); 2061 return check_against_reference(bitmap, src, fSink.get()); 2062 }); 2063} 2064 2065/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 2066 2067Error ViaPipe::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 2068 auto size = src.size(); 2069 return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error { 2070 SkDynamicMemoryWStream tmpStream; 2071 Error err = src.draw(SkPipeSerializer().beginWrite(SkRect::Make(size), &tmpStream)); 2072 if (!err.isEmpty()) { 2073 return err; 2074 } 2075 sk_sp<SkData> data = tmpStream.detachAsData(); 2076 SkPipeDeserializer().playback(data->data(), data->size(), canvas); 2077 return check_against_reference(bitmap, src, fSink.get()); 2078 }); 2079} 2080 2081/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 2082 2083#ifdef TEST_VIA_SVG 2084#include "SkXMLWriter.h" 2085#include "SkSVGCanvas.h" 2086#include "SkSVGDOM.h" 2087 2088Error ViaSVG::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 2089 auto size = src.size(); 2090 return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error { 2091 SkDynamicMemoryWStream wstream; 2092 SkXMLStreamWriter writer(&wstream); 2093 Error err = src.draw(SkSVGCanvas::Make(SkRect::Make(size), &writer).get()); 2094 if (!err.isEmpty()) { 2095 return err; 2096 } 2097 std::unique_ptr<SkStream> rstream(wstream.detachAsStream()); 2098 auto dom = SkSVGDOM::MakeFromStream(*rstream); 2099 if (dom) { 2100 dom->setContainerSize(SkSize::Make(size)); 2101 dom->render(canvas); 2102 } 2103 return ""; 2104 }); 2105} 2106#endif 2107 2108/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 2109 2110Error ViaLite::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 2111 auto size = src.size(); 2112 SkIRect bounds = {0,0, size.width(), size.height()}; 2113 return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error { 2114 SkLiteDL dl; 2115 SkLiteRecorder rec; 2116 rec.reset(&dl, bounds); 2117 2118 Error err = src.draw(&rec); 2119 if (!err.isEmpty()) { 2120 return err; 2121 } 2122 dl.draw(canvas); 2123 return check_against_reference(bitmap, src, fSink.get()); 2124 }); 2125} 2126 2127/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 2128 2129ViaCSXform::ViaCSXform(Sink* sink, sk_sp<SkColorSpace> cs, bool colorSpin) 2130 : Via(sink) 2131 , fCS(std::move(cs)) 2132 , fColorSpin(colorSpin) {} 2133 2134Error ViaCSXform::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { 2135 return draw_to_canvas(fSink.get(), bitmap, stream, log, src.size(), 2136 [&](SkCanvas* canvas) -> Error { 2137 { 2138 SkAutoCanvasRestore acr(canvas, true); 2139 auto proxy = SkCreateColorSpaceXformCanvas(canvas, fCS); 2140 Error err = src.draw(proxy.get()); 2141 if (!err.isEmpty()) { 2142 return err; 2143 } 2144 } 2145 2146 // Undo the color spin, so we can look at the pixels in Gold. 2147 if (fColorSpin) { 2148 SkBitmap pixels; 2149 pixels.allocPixels(canvas->imageInfo()); 2150 canvas->readPixels(pixels, 0, 0); 2151 2152 SkPaint rotateColors; 2153 SkScalar matrix[20] = { 0, 0, 1, 0, 0, // B -> R 2154 1, 0, 0, 0, 0, // R -> G 2155 0, 1, 0, 0, 0, // G -> B 2156 0, 0, 0, 1, 0 }; 2157 rotateColors.setBlendMode(SkBlendMode::kSrc); 2158 rotateColors.setColorFilter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix)); 2159 canvas->drawBitmap(pixels, 0, 0, &rotateColors); 2160 } 2161 2162 return ""; 2163 }); 2164} 2165 2166} // namespace DM 2167