• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "dm/DMSrcSink.h"
9 #include "include/codec/SkAndroidCodec.h"
10 #include "include/codec/SkCodec.h"
11 #include "include/codec/SkPixmapUtils.h"
12 #include "include/core/SkColorSpace.h"
13 #include "include/core/SkData.h"
14 #include "include/core/SkDocument.h"
15 #include "include/core/SkExecutor.h"
16 #include "include/core/SkImageGenerator.h"
17 #include "include/core/SkMallocPixelRef.h"
18 #include "include/core/SkPictureRecorder.h"
19 #include "include/core/SkSerialProcs.h"
20 #include "include/core/SkStream.h"
21 #include "include/core/SkString.h"
22 #include "include/core/SkSurface.h"
23 #include "include/core/SkSurfaceProps.h"
24 #include "include/docs/SkMultiPictureDocument.h"
25 #include "include/docs/SkPDFDocument.h"
26 #include "include/encode/SkPngEncoder.h"
27 #include "include/gpu/GrBackendSurface.h"
28 #include "include/gpu/GrDirectContext.h"
29 #include "include/gpu/ganesh/SkImageGanesh.h"
30 #include "include/gpu/ganesh/SkSurfaceGanesh.h"
31 #include "include/ports/SkImageGeneratorCG.h"
32 #include "include/ports/SkImageGeneratorNDK.h"
33 #include "include/ports/SkImageGeneratorWIC.h"
34 #include "include/private/base/SkTLogic.h"
35 #include "include/private/chromium/GrDeferredDisplayList.h"
36 #include "include/private/chromium/GrSurfaceCharacterization.h"
37 #include "include/utils/SkNullCanvas.h"
38 #include "include/utils/SkPaintFilterCanvas.h"
39 #include "modules/skcms/skcms.h"
40 #include "modules/skottie/utils/SkottieUtils.h"
41 #include "modules/skshaper/utils/FactoryHelpers.h"
42 #include "src/base/SkAutoMalloc.h"
43 #include "src/base/SkRandom.h"
44 #include "src/base/SkTLazy.h"
45 #include "src/codec/SkCodecImageGenerator.h"
46 #include "src/core/SkAutoPixmapStorage.h"
47 #include "src/core/SkImageInfoPriv.h"
48 #include "src/core/SkOSFile.h"
49 #include "src/core/SkPictureData.h"
50 #include "src/core/SkPicturePriv.h"
51 #include "src/core/SkRecordDraw.h"
52 #include "src/core/SkRecorder.h"
53 #include "src/core/SkSwizzlePriv.h"
54 #include "src/core/SkTaskGroup.h"
55 #include "src/gpu/ganesh/GrDirectContextPriv.h"
56 #include "src/gpu/ganesh/GrGpu.h"
57 #include "src/gpu/ganesh/image/GrImageUtils.h"
58 #include "src/image/SkImage_Base.h"
59 #include "src/utils/SkJSONWriter.h"
60 #include "src/utils/SkMultiPictureDocumentPriv.h"
61 #include "src/utils/SkOSPath.h"
62 #include "src/utils/SkTestCanvas.h"
63 #include "tools/DDLPromiseImageHelper.h"
64 #include "tools/DDLTileHelper.h"
65 #include "tools/EncodeUtils.h"
66 #include "tools/GpuToolUtils.h"
67 #include "tools/Resources.h"
68 #include "tools/RuntimeBlendUtils.h"
69 #include "tools/ToolUtils.h"
70 #include "tools/UrlDataManager.h"
71 #include "tools/debugger/DebugCanvas.h"
72 #include "tools/fonts/FontToolUtils.h"
73 #include "tools/gpu/BackendSurfaceFactory.h"
74 #include "tools/gpu/MemoryCache.h"
75 
76 #if defined(SK_BUILD_FOR_WIN)
77 #include "include/docs/SkXPSDocument.h"
78 #include "src/utils/win/SkAutoCoInitialize.h"
79 #include "src/utils/win/SkHRESULT.h"
80 #include "src/utils/win/SkTScopedComPtr.h"
81 
82 #include <XpsObjectModel.h>
83 #endif
84 
85 #if defined(SK_ENABLE_SKOTTIE)
86 #include "modules/skottie/include/Skottie.h"
87 #include "modules/skresources/include/SkResources.h"
88 #endif
89 
90 #if defined(SK_ENABLE_SVG)
91 #include "include/svg/SkSVGCanvas.h"
92 #include "modules/svg/include/SkSVGDOM.h"
93 #include "modules/svg/include/SkSVGNode.h"
94 #include "src/xml/SkXMLWriter.h"
95 #endif
96 
97 #if defined(SK_GRAPHITE)
98 #include "include/gpu/graphite/Context.h"
99 #include "include/gpu/graphite/ContextOptions.h"
100 #include "include/gpu/graphite/Recorder.h"
101 #include "include/gpu/graphite/Recording.h"
102 #include "include/gpu/graphite/Surface.h"
103 #include "include/private/gpu/graphite/ContextOptionsPriv.h"
104 // TODO: Remove this src include once we figure out public readPixels call for Graphite.
105 #include "src/gpu/graphite/Surface_Graphite.h"
106 #include "tools/graphite/ContextFactory.h"
107 #include "tools/graphite/GraphiteTestContext.h"
108 
109 #if defined(SK_ENABLE_PRECOMPILE)
110 #include "src/gpu/graphite/Caps.h"
111 #include "src/gpu/graphite/ContextPriv.h"
112 #include "src/gpu/graphite/GraphicsPipeline.h"
113 #include "src/gpu/graphite/GraphicsPipelineDesc.h"
114 #include "src/gpu/graphite/PublicPrecompile.h"
115 #include "src/gpu/graphite/RecorderPriv.h"
116 #include "src/gpu/graphite/RenderPassDesc.h"
117 #include "src/gpu/graphite/RendererProvider.h"
118 #include "tools/graphite/UniqueKeyUtils.h"
119 #endif // SK_ENABLE_PRECOMPILE
120 
121 #endif // SK_GRAPHITE
122 
123 
124 #if defined(SK_ENABLE_ANDROID_UTILS)
125     #include "client_utils/android/BitmapRegionDecoder.h"
126 #endif
127 #include "tests/TestUtils.h"
128 
129 #include <cmath>
130 #include <functional>
131 
132 using namespace skia_private;
133 
134 static DEFINE_bool(RAW_threading, true, "Allow RAW decodes to run on multiple threads?");
135 static DEFINE_int(mskpFrame, 0, "Which MSKP frame to draw?");
136 
137 DECLARE_int(gpuThreads);
138 
139 using sk_gpu_test::GrContextFactory;
140 using sk_gpu_test::ContextInfo;
141 
142 namespace DM {
143 
GMSrc(skiagm::GMFactory factory)144 GMSrc::GMSrc(skiagm::GMFactory factory) : fFactory(factory) {}
145 
draw(SkCanvas * canvas,GraphiteTestContext * testContext) const146 Result GMSrc::draw(SkCanvas* canvas, GraphiteTestContext* testContext) const {
147     std::unique_ptr<skiagm::GM> gm(fFactory());
148     if (gm->isBazelOnly()) {
149         // We skip Bazel-only GMs because they might overlap with existing DM functionality. See
150         // comments in the skiagm::GM::isBazelOnly function declaration for context.
151         return Result(Result::Status::Skip, SkString("Bazel-only GM"));
152     }
153     SkString msg;
154 
155     skiagm::DrawResult gpuSetupResult = gm->gpuSetup(canvas, &msg, testContext);
156     switch (gpuSetupResult) {
157         case skiagm::DrawResult::kOk  : break;
158         case skiagm::DrawResult::kFail: return Result(Result::Status::Fatal, msg);
159         case skiagm::DrawResult::kSkip: return Result(Result::Status::Skip,  msg);
160         default: SK_ABORT("");
161     }
162 
163     skiagm::DrawResult drawResult = gm->draw(canvas, &msg);
164     switch (drawResult) {
165         case skiagm::DrawResult::kOk  : return Result(Result::Status::Ok,    msg);
166         case skiagm::DrawResult::kFail: return Result(Result::Status::Fatal, msg);
167         case skiagm::DrawResult::kSkip: return Result(Result::Status::Skip,  msg);
168         default: SK_ABORT("");
169     }
170 
171     // Note: we don't call "gpuTeardown" here because, when testing DDL recording, we want
172     // the gpu-backed images to live past the lifetime of the GM.
173 }
174 
size() const175 SkISize GMSrc::size() const {
176     std::unique_ptr<skiagm::GM> gm(fFactory());
177     return gm->getISize();
178 }
179 
name() const180 Name GMSrc::name() const {
181     std::unique_ptr<skiagm::GM> gm(fFactory());
182     return gm->getName();
183 }
184 
modifyGrContextOptions(GrContextOptions * options) const185 void GMSrc::modifyGrContextOptions(GrContextOptions* options) const {
186     std::unique_ptr<skiagm::GM> gm(fFactory());
187     gm->modifyGrContextOptions(options);
188 }
189 
190 #if defined(SK_GRAPHITE)
modifyGraphiteContextOptions(skgpu::graphite::ContextOptions * options) const191 void GMSrc::modifyGraphiteContextOptions(skgpu::graphite::ContextOptions* options) const {
192     std::unique_ptr<skiagm::GM> gm(fFactory());
193     gm->modifyGraphiteContextOptions(options);
194 }
195 #endif
196 
197 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
198 
get_scaled_name(const Path & path,float scale)199 static SkString get_scaled_name(const Path& path, float scale) {
200     return SkStringPrintf("%s_%.3f", SkOSPath::Basename(path.c_str()).c_str(), scale);
201 }
202 
203 #ifdef SK_ENABLE_ANDROID_UTILS
BRDSrc(Path path,Mode mode,CodecSrc::DstColorType dstColorType,uint32_t sampleSize)204 BRDSrc::BRDSrc(Path path, Mode mode, CodecSrc::DstColorType dstColorType, uint32_t sampleSize)
205     : fPath(path)
206     , fMode(mode)
207     , fDstColorType(dstColorType)
208     , fSampleSize(sampleSize)
209 {}
210 
veto(SinkFlags flags) const211 bool BRDSrc::veto(SinkFlags flags) const {
212     // No need to test to non-raster or indirect backends.
213     return flags.type != SinkFlags::kRaster
214         || flags.approach != SinkFlags::kDirect;
215 }
216 
create_brd(Path path)217 static std::unique_ptr<android::skia::BitmapRegionDecoder> create_brd(Path path) {
218     sk_sp<SkData> encoded(SkData::MakeFromFileName(path.c_str()));
219     return android::skia::BitmapRegionDecoder::Make(encoded);
220 }
221 
alpha8_to_gray8(SkBitmap * bitmap)222 static inline void alpha8_to_gray8(SkBitmap* bitmap) {
223     // Android requires kGray8 bitmaps to be tagged as kAlpha8.  Here we convert
224     // them back to kGray8 so our test framework can draw them correctly.
225     if (kAlpha_8_SkColorType == bitmap->info().colorType()) {
226         SkImageInfo newInfo = bitmap->info().makeColorType(kGray_8_SkColorType)
227                                             .makeAlphaType(kOpaque_SkAlphaType);
228         *const_cast<SkImageInfo*>(&bitmap->info()) = newInfo;
229     }
230 }
231 
draw(SkCanvas * canvas,GraphiteTestContext *) const232 Result BRDSrc::draw(SkCanvas* canvas, GraphiteTestContext*) const {
233     SkColorType colorType = canvas->imageInfo().colorType();
234     if (kRGB_565_SkColorType == colorType &&
235         CodecSrc::kGetFromCanvas_DstColorType != fDstColorType)
236     {
237         return Result::Skip("Testing non-565 to 565 is uninteresting.");
238     }
239     switch (fDstColorType) {
240         case CodecSrc::kGetFromCanvas_DstColorType:
241             break;
242         case CodecSrc::kGrayscale_Always_DstColorType:
243             colorType = kGray_8_SkColorType;
244             break;
245         default:
246             SkASSERT(false);
247             break;
248     }
249 
250     auto brd = create_brd(fPath);
251     if (nullptr == brd) {
252         return Result::Skip("Could not create brd for %s.", fPath.c_str());
253     }
254 
255     auto recommendedCT = brd->computeOutputColorType(colorType);
256     if (kRGB_565_SkColorType == colorType && recommendedCT != colorType) {
257         return Result::Skip("Skip decoding non-opaque to 565.");
258     }
259     colorType = recommendedCT;
260 
261     auto colorSpace = brd->computeOutputColorSpace(colorType, nullptr);
262 
263     const uint32_t width = brd->width();
264     const uint32_t height = brd->height();
265     // Visually inspecting very small output images is not necessary.
266     if ((width / fSampleSize <= 10 || height / fSampleSize <= 10) && 1 != fSampleSize) {
267         return Result::Skip("Scaling very small images is uninteresting.");
268     }
269     switch (fMode) {
270         case kFullImage_Mode: {
271             SkBitmap bitmap;
272             if (!brd->decodeRegion(&bitmap, nullptr, SkIRect::MakeXYWH(0, 0, width, height),
273                     fSampleSize, colorType, false, colorSpace)) {
274                 return Result::Fatal("Cannot decode (full) region.");
275             }
276             alpha8_to_gray8(&bitmap);
277 
278             canvas->drawImage(bitmap.asImage(), 0, 0);
279             return Result::Ok();
280         }
281         case kDivisor_Mode: {
282             const uint32_t divisor = 2;
283             if (width < divisor || height < divisor) {
284                 return Result::Skip("Divisor is larger than image dimension.");
285             }
286 
287             // Use a border to test subsets that extend outside the image.
288             // We will not allow the border to be larger than the image dimensions.  Allowing
289             // these large borders causes off by one errors that indicate a problem with the
290             // test suite, not a problem with the implementation.
291             const uint32_t maxBorder = std::min(width, height) / (fSampleSize * divisor);
292             const uint32_t scaledBorder = std::min(5u, maxBorder);
293             const uint32_t unscaledBorder = scaledBorder * fSampleSize;
294 
295             // We may need to clear the canvas to avoid uninitialized memory.
296             // Assume we are scaling a 780x780 image with sampleSize = 8.
297             // The output image should be 97x97.
298             // Each subset will be 390x390.
299             // Each scaled subset be 48x48.
300             // Four scaled subsets will only fill a 96x96 image.
301             // The bottom row and last column will not be touched.
302             // This is an unfortunate result of our rounding rules when scaling.
303             // Maybe we need to consider testing scaled subsets without trying to
304             // combine them to match the full scaled image?  Or maybe this is the
305             // best we can do?
306             canvas->clear(0);
307 
308             for (uint32_t x = 0; x < divisor; x++) {
309                 for (uint32_t y = 0; y < divisor; y++) {
310                     // Calculate the subset dimensions
311                     uint32_t subsetWidth = width / divisor;
312                     uint32_t subsetHeight = height / divisor;
313                     const int left = x * subsetWidth;
314                     const int top = y * subsetHeight;
315 
316                     // Increase the size of the last subset in each row or column, when the
317                     // divisor does not divide evenly into the image dimensions
318                     subsetWidth += (x + 1 == divisor) ? (width % divisor) : 0;
319                     subsetHeight += (y + 1 == divisor) ? (height % divisor) : 0;
320 
321                     // Increase the size of the subset in order to have a border on each side
322                     const int decodeLeft = left - unscaledBorder;
323                     const int decodeTop = top - unscaledBorder;
324                     const uint32_t decodeWidth = subsetWidth + unscaledBorder * 2;
325                     const uint32_t decodeHeight = subsetHeight + unscaledBorder * 2;
326                     SkBitmap bitmap;
327                     if (!brd->decodeRegion(&bitmap, nullptr, SkIRect::MakeXYWH(decodeLeft,
328                             decodeTop, decodeWidth, decodeHeight), fSampleSize, colorType, false,
329                             colorSpace)) {
330                         return Result::Fatal("Cannot decode region.");
331                     }
332 
333                     alpha8_to_gray8(&bitmap);
334                     canvas->drawImageRect(bitmap.asImage().get(),
335                             SkRect::MakeXYWH((SkScalar) scaledBorder, (SkScalar) scaledBorder,
336                                     (SkScalar) (subsetWidth / fSampleSize),
337                                     (SkScalar) (subsetHeight / fSampleSize)),
338                             SkRect::MakeXYWH((SkScalar) (left / fSampleSize),
339                                     (SkScalar) (top / fSampleSize),
340                                     (SkScalar) (subsetWidth / fSampleSize),
341                                     (SkScalar) (subsetHeight / fSampleSize)),
342                             SkSamplingOptions(), nullptr,
343                             SkCanvas::kStrict_SrcRectConstraint);
344                 }
345             }
346             return Result::Ok();
347         }
348         default:
349             SkASSERT(false);
350             return Result::Fatal("Error: Should not be reached.");
351     }
352 }
353 
size() const354 SkISize BRDSrc::size() const {
355     auto brd = create_brd(fPath);
356     if (brd) {
357         return {std::max(1, brd->width() / (int)fSampleSize),
358                 std::max(1, brd->height() / (int)fSampleSize)};
359     }
360     return {0, 0};
361 }
362 
name() const363 Name BRDSrc::name() const {
364     // We will replicate the names used by CodecSrc so that images can
365     // be compared in Gold.
366     if (1 == fSampleSize) {
367         return SkOSPath::Basename(fPath.c_str());
368     }
369     return get_scaled_name(fPath, 1.0f / (float) fSampleSize);
370 }
371 
372 #endif // SK_ENABLE_ANDROID_UTILS
373 
374 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
375 
serial_from_path_name(const SkString & path)376 static bool serial_from_path_name(const SkString& path) {
377     if (!FLAGS_RAW_threading) {
378         static const char* const exts[] = {
379             "arw", "cr2", "dng", "nef", "nrw", "orf", "raf", "rw2", "pef", "srw",
380             "ARW", "CR2", "DNG", "NEF", "NRW", "ORF", "RAF", "RW2", "PEF", "SRW",
381         };
382         const char* actualExt = strrchr(path.c_str(), '.');
383         if (actualExt) {
384             actualExt++;
385             for (auto* ext : exts) {
386                 if (0 == strcmp(ext, actualExt)) {
387                     return true;
388                 }
389             }
390         }
391     }
392     return false;
393 }
394 
CodecSrc(Path path,Mode mode,DstColorType dstColorType,SkAlphaType dstAlphaType,float scale)395 CodecSrc::CodecSrc(Path path, Mode mode, DstColorType dstColorType, SkAlphaType dstAlphaType,
396                    float scale)
397     : fPath(path)
398     , fMode(mode)
399     , fDstColorType(dstColorType)
400     , fDstAlphaType(dstAlphaType)
401     , fScale(scale)
402     , fRunSerially(serial_from_path_name(path))
403 {}
404 
veto(SinkFlags flags) const405 bool CodecSrc::veto(SinkFlags flags) const {
406     // Test to direct raster backends (8888 and 565).
407     return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDirect;
408 }
409 
410 // Allows us to test decodes to non-native 8888.
swap_rb_if_necessary(SkBitmap & bitmap,CodecSrc::DstColorType dstColorType)411 static void swap_rb_if_necessary(SkBitmap& bitmap, CodecSrc::DstColorType dstColorType) {
412     if (CodecSrc::kNonNative8888_Always_DstColorType != dstColorType) {
413         return;
414     }
415 
416     for (int y = 0; y < bitmap.height(); y++) {
417         uint32_t* row = (uint32_t*) bitmap.getAddr(0, y);
418         SkOpts::RGBA_to_BGRA(row, row, bitmap.width());
419     }
420 }
421 
get_decode_info(SkImageInfo * decodeInfo,SkColorType canvasColorType,CodecSrc::DstColorType dstColorType,SkAlphaType dstAlphaType)422 static bool get_decode_info(SkImageInfo* decodeInfo, SkColorType canvasColorType,
423                             CodecSrc::DstColorType dstColorType, SkAlphaType dstAlphaType) {
424     switch (dstColorType) {
425         case CodecSrc::kGrayscale_Always_DstColorType:
426             if (kRGB_565_SkColorType == canvasColorType) {
427                 return false;
428             }
429             *decodeInfo = decodeInfo->makeColorType(kGray_8_SkColorType);
430             break;
431         case CodecSrc::kNonNative8888_Always_DstColorType:
432             if (kRGB_565_SkColorType == canvasColorType
433                     || kRGBA_F16_SkColorType == canvasColorType) {
434                 return false;
435             }
436 #ifdef SK_PMCOLOR_IS_RGBA
437             *decodeInfo = decodeInfo->makeColorType(kBGRA_8888_SkColorType);
438 #else
439             *decodeInfo = decodeInfo->makeColorType(kRGBA_8888_SkColorType);
440 #endif
441             break;
442         default:
443             if (kRGB_565_SkColorType == canvasColorType &&
444                     kOpaque_SkAlphaType != decodeInfo->alphaType()) {
445                 return false;
446             }
447 
448             *decodeInfo = decodeInfo->makeColorType(canvasColorType);
449             break;
450     }
451 
452     *decodeInfo = decodeInfo->makeAlphaType(dstAlphaType);
453     return true;
454 }
455 
draw_to_canvas(SkCanvas * canvas,const SkImageInfo & info,void * pixels,size_t rowBytes,CodecSrc::DstColorType dstColorType,SkScalar left=0,SkScalar top=0)456 static void draw_to_canvas(SkCanvas* canvas, const SkImageInfo& info, void* pixels, size_t rowBytes,
457                            CodecSrc::DstColorType dstColorType,
458                            SkScalar left = 0, SkScalar top = 0) {
459     SkBitmap bitmap;
460     bitmap.installPixels(info, pixels, rowBytes);
461     swap_rb_if_necessary(bitmap, dstColorType);
462     canvas->drawImage(bitmap.asImage(), left, top);
463 }
464 
465 // For codec srcs, we want the "draw" step to be a memcpy.  Any interesting color space or
466 // color format conversions should be performed by the codec.  Sometimes the output of the
467 // decode will be in an interesting color space.  On our srgb and f16 backends, we need to
468 // "pretend" that the color space is standard sRGB to avoid triggering color conversion
469 // at draw time.
set_bitmap_color_space(SkImageInfo * info)470 static void set_bitmap_color_space(SkImageInfo* info) {
471     *info = info->makeColorSpace(SkColorSpace::MakeSRGB());
472 }
473 
draw(SkCanvas * canvas,GraphiteTestContext *) const474 Result CodecSrc::draw(SkCanvas* canvas, GraphiteTestContext*) const {
475     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
476     if (!encoded) {
477         return Result::Fatal("Couldn't read %s.", fPath.c_str());
478     }
479 
480     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(encoded));
481     if (nullptr == codec) {
482         return Result::Fatal("Couldn't create codec for %s.", fPath.c_str());
483     }
484 
485     SkImageInfo decodeInfo = codec->getInfo();
486     if (!get_decode_info(&decodeInfo, canvas->imageInfo().colorType(), fDstColorType,
487                          fDstAlphaType)) {
488         return Result::Skip("Skipping uninteresting test.");
489     }
490 
491     // Try to scale the image if it is desired
492     SkISize size = codec->getScaledDimensions(fScale);
493 
494     std::unique_ptr<SkAndroidCodec> androidCodec;
495     if (1.0f != fScale && fMode == kAnimated_Mode) {
496         androidCodec = SkAndroidCodec::MakeFromData(encoded);
497         size = androidCodec->getSampledDimensions(1 / fScale);
498     }
499 
500     if (size == decodeInfo.dimensions() && 1.0f != fScale) {
501         return Result::Skip("Test without scaling is uninteresting.");
502     }
503 
504     // Visually inspecting very small output images is not necessary.  We will
505     // cover these cases in unit testing.
506     if ((size.width() <= 10 || size.height() <= 10) && 1.0f != fScale) {
507         return Result::Skip("Scaling very small images is uninteresting.");
508     }
509     decodeInfo = decodeInfo.makeDimensions(size);
510 
511     const int bpp = decodeInfo.bytesPerPixel();
512     const size_t rowBytes = size.width() * bpp;
513     const size_t safeSize = decodeInfo.computeByteSize(rowBytes);
514     SkAutoMalloc pixels(safeSize);
515 
516     SkCodec::Options options;
517     if (kCodecZeroInit_Mode == fMode) {
518         memset(pixels.get(), 0, size.height() * rowBytes);
519         options.fZeroInitialized = SkCodec::kYes_ZeroInitialized;
520     }
521 
522     SkImageInfo bitmapInfo = decodeInfo;
523     set_bitmap_color_space(&bitmapInfo);
524     if (kRGBA_8888_SkColorType == decodeInfo.colorType() ||
525             kBGRA_8888_SkColorType == decodeInfo.colorType()) {
526         bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType);
527     }
528 
529     switch (fMode) {
530         case kAnimated_Mode: {
531             SkAndroidCodec::AndroidOptions androidOptions;
532             if (fScale != 1.0f) {
533                 SkASSERT(androidCodec);
534                 androidOptions.fSampleSize = 1 / fScale;
535                 auto dims = androidCodec->getSampledDimensions(androidOptions.fSampleSize);
536                 decodeInfo = decodeInfo.makeDimensions(dims);
537             }
538 
539             std::vector<SkCodec::FrameInfo> frameInfos = androidCodec
540                     ? androidCodec->codec()->getFrameInfo() : codec->getFrameInfo();
541             if (frameInfos.size() <= 1) {
542                 return Result::Fatal("%s is not an animated image.", fPath.c_str());
543             }
544 
545             // As in CodecSrc::size(), compute a roughly square grid to draw the frames
546             // into. "factor" is the number of frames to draw on one row. There will be
547             // up to "factor" rows as well.
548             const float root = sqrt((float) frameInfos.size());
549             const int factor = sk_float_ceil2int(root);
550 
551             // Used to cache a frame that future frames will depend on.
552             SkAutoMalloc priorFramePixels;
553             int cachedFrame = SkCodec::kNoFrame;
554             for (int i = 0; static_cast<size_t>(i) < frameInfos.size(); i++) {
555                 androidOptions.fFrameIndex = i;
556                 // Check for a prior frame
557                 const int reqFrame = frameInfos[i].fRequiredFrame;
558                 if (reqFrame != SkCodec::kNoFrame && reqFrame == cachedFrame
559                         && priorFramePixels.get()) {
560                     // Copy into pixels
561                     memcpy(pixels.get(), priorFramePixels.get(), safeSize);
562                     androidOptions.fPriorFrame = reqFrame;
563                 } else {
564                     androidOptions.fPriorFrame = SkCodec::kNoFrame;
565                 }
566                 SkCodec::Result result = androidCodec
567                         ? androidCodec->getAndroidPixels(decodeInfo, pixels.get(), rowBytes,
568                                                          &androidOptions)
569                         : codec->getPixels(decodeInfo, pixels.get(), rowBytes, &androidOptions);
570                 if (SkCodec::kInvalidInput == result && i > 0) {
571                     // Some of our test images have truncated later frames. Treat that
572                     // the same as incomplete.
573                     result = SkCodec::kIncompleteInput;
574                 }
575                 switch (result) {
576                     case SkCodec::kSuccess:
577                     case SkCodec::kErrorInInput:
578                     case SkCodec::kIncompleteInput: {
579                         // If the next frame depends on this one, store it in priorFrame.
580                         // It is possible that we may discard a frame that future frames depend on,
581                         // but the codec will simply redecode the discarded frame.
582                         // Do this before calling draw_to_canvas, which premultiplies in place. If
583                         // we're decoding to unpremul, we want to pass the unmodified frame to the
584                         // codec for decoding the next frame.
585                         if (static_cast<size_t>(i+1) < frameInfos.size()
586                                 && frameInfos[i+1].fRequiredFrame == i) {
587                             memcpy(priorFramePixels.reset(safeSize), pixels.get(), safeSize);
588                             cachedFrame = i;
589                         }
590 
591                         SkAutoCanvasRestore acr(canvas, true);
592                         const int xTranslate = (i % factor) * decodeInfo.width();
593                         const int yTranslate = (i / factor) * decodeInfo.height();
594                         canvas->translate(SkIntToScalar(xTranslate), SkIntToScalar(yTranslate));
595                         draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, fDstColorType);
596                         if (result != SkCodec::kSuccess) {
597                             return Result::Ok();
598                         }
599                         break;
600                     }
601                     case SkCodec::kInvalidConversion:
602                         if (i > 0 && (decodeInfo.colorType() == kRGB_565_SkColorType)) {
603                             return Result::Skip(
604                                 "Cannot decode frame %i to 565 (%s).", i, fPath.c_str());
605                         }
606                         [[fallthrough]];
607                     default:
608                         return Result::Fatal(
609                             "Couldn't getPixels for frame %i in %s.", i, fPath.c_str());
610                 }
611             }
612             break;
613         }
614         case kCodecZeroInit_Mode:
615         case kCodec_Mode: {
616             switch (codec->getPixels(decodeInfo, pixels.get(), rowBytes, &options)) {
617                 case SkCodec::kSuccess:
618                     // We consider these to be valid, since we should still decode what is
619                     // available.
620                 case SkCodec::kErrorInInput:
621                 case SkCodec::kIncompleteInput:
622                     break;
623                 default:
624                     // Everything else is considered a failure.
625                     return Result::Fatal("Couldn't getPixels %s.", fPath.c_str());
626             }
627 
628             draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, fDstColorType);
629             break;
630         }
631         case kScanline_Mode: {
632             void* dst = pixels.get();
633             uint32_t height = decodeInfo.height();
634             const bool useIncremental = [this]() {
635                 auto exts = { "png", "PNG", "gif", "GIF" };
636                 for (auto ext : exts) {
637                     if (fPath.endsWith(ext)) {
638                         return true;
639                     }
640                 }
641                 return false;
642             }();
643             // ico may use the old scanline method or the new one, depending on whether it
644             // internally holds a bmp or a png.
645             const bool ico = fPath.endsWith("ico");
646             bool useOldScanlineMethod = !useIncremental && !ico;
647             if (useIncremental || ico) {
648                 if (SkCodec::kSuccess == codec->startIncrementalDecode(decodeInfo, dst,
649                         rowBytes, &options)) {
650                     int rowsDecoded;
651                     auto result = codec->incrementalDecode(&rowsDecoded);
652                     if (SkCodec::kIncompleteInput == result || SkCodec::kErrorInInput == result) {
653                         codec->fillIncompleteImage(decodeInfo, dst, rowBytes,
654                                                    SkCodec::kNo_ZeroInitialized, height,
655                                                    rowsDecoded);
656                     }
657                 } else {
658                     if (useIncremental) {
659                         // Error: These should support incremental decode.
660                         return Result::Fatal("Could not start incremental decode");
661                     }
662                     // Otherwise, this is an ICO. Since incremental failed, it must contain a BMP,
663                     // which should work via startScanlineDecode
664                     useOldScanlineMethod = true;
665                 }
666             }
667 
668             if (useOldScanlineMethod) {
669                 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo)) {
670                     return Result::Fatal("Could not start scanline decoder");
671                 }
672 
673                 // We do not need to check the return value.  On an incomplete
674                 // image, memory will be filled with a default value.
675                 codec->getScanlines(dst, height, rowBytes);
676             }
677 
678             draw_to_canvas(canvas, bitmapInfo, dst, rowBytes, fDstColorType);
679             break;
680         }
681         case kStripe_Mode: {
682             const int height = decodeInfo.height();
683             // This value is chosen arbitrarily.  We exercise more cases by choosing a value that
684             // does not align with image blocks.
685             const int stripeHeight = 37;
686             const int numStripes = (height + stripeHeight - 1) / stripeHeight;
687             void* dst = pixels.get();
688 
689             // Decode odd stripes
690             if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, &options)) {
691                 return Result::Fatal("Could not start scanline decoder");
692             }
693 
694             // This mode was designed to test the new skip scanlines API in libjpeg-turbo.
695             // Jpegs have kTopDown_SkScanlineOrder, and at this time, it is not interesting
696             // to run this test for image types that do not have this scanline ordering.
697             // We only run this on Jpeg, which is always kTopDown.
698             SkASSERT(SkCodec::kTopDown_SkScanlineOrder == codec->getScanlineOrder());
699 
700             for (int i = 0; i < numStripes; i += 2) {
701                 // Skip a stripe
702                 const int linesToSkip = std::min(stripeHeight, height - i * stripeHeight);
703                 codec->skipScanlines(linesToSkip);
704 
705                 // Read a stripe
706                 const int startY = (i + 1) * stripeHeight;
707                 const int linesToRead = std::min(stripeHeight, height - startY);
708                 if (linesToRead > 0) {
709                     codec->getScanlines(SkTAddOffset<void>(dst, rowBytes * startY), linesToRead,
710                                         rowBytes);
711                 }
712             }
713 
714             // Decode even stripes
715             const SkCodec::Result startResult = codec->startScanlineDecode(decodeInfo);
716             if (SkCodec::kSuccess != startResult) {
717                 return Result::Fatal("Failed to restart scanline decoder with same parameters.");
718             }
719             for (int i = 0; i < numStripes; i += 2) {
720                 // Read a stripe
721                 const int startY = i * stripeHeight;
722                 const int linesToRead = std::min(stripeHeight, height - startY);
723                 codec->getScanlines(SkTAddOffset<void>(dst, rowBytes * startY), linesToRead,
724                                     rowBytes);
725 
726                 // Skip a stripe
727                 const int linesToSkip = std::min(stripeHeight, height - (i + 1) * stripeHeight);
728                 if (linesToSkip > 0) {
729                     codec->skipScanlines(linesToSkip);
730                 }
731             }
732 
733             draw_to_canvas(canvas, bitmapInfo, dst, rowBytes, fDstColorType);
734             break;
735         }
736         case kCroppedScanline_Mode: {
737             const int width = decodeInfo.width();
738             const int height = decodeInfo.height();
739             // This value is chosen because, as we move across the image, it will sometimes
740             // align with the jpeg block sizes and it will sometimes not.  This allows us
741             // to test interestingly different code paths in the implementation.
742             const int tileSize = 36;
743             SkIRect subset;
744             for (int x = 0; x < width; x += tileSize) {
745                 subset = SkIRect::MakeXYWH(x, 0, std::min(tileSize, width - x), height);
746                 options.fSubset = &subset;
747                 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, &options)) {
748                     return Result::Fatal("Could not start scanline decoder.");
749                 }
750 
751                 codec->getScanlines(SkTAddOffset<void>(pixels.get(), x * bpp), height, rowBytes);
752             }
753 
754             draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, fDstColorType);
755             break;
756         }
757         case kSubset_Mode: {
758             // Arbitrarily choose a divisor.
759             int divisor = 2;
760             // Total width/height of the image.
761             const int W = codec->getInfo().width();
762             const int H = codec->getInfo().height();
763             if (divisor > W || divisor > H) {
764                 return Result::Skip("Cannot codec subset: divisor %d is too big "
765                                     "for %s with dimensions (%d x %d)", divisor,
766                                     fPath.c_str(), W, H);
767             }
768             // subset dimensions
769             // SkWebpCodec, the only one that supports subsets, requires even top/left boundaries.
770             const int w = SkAlign2(W / divisor);
771             const int h = SkAlign2(H / divisor);
772             SkIRect subset;
773             options.fSubset = &subset;
774             SkBitmap subsetBm;
775             // We will reuse pixel memory from bitmap.
776             void* dst = pixels.get();
777             // Keep track of left and top (for drawing subsetBm into canvas). We could use
778             // fScale * x and fScale * y, but we want integers such that the next subset will start
779             // where the last one ended. So we'll add decodeInfo.width() and height().
780             int left = 0;
781             for (int x = 0; x < W; x += w) {
782                 int top = 0;
783                 for (int y = 0; y < H; y+= h) {
784                     // Do not make the subset go off the edge of the image.
785                     const int preScaleW = std::min(w, W - x);
786                     const int preScaleH = std::min(h, H - y);
787                     subset.setXYWH(x, y, preScaleW, preScaleH);
788                     // And scale
789                     // FIXME: Should we have a version of getScaledDimensions that takes a subset
790                     // into account?
791                     const int scaledW = std::max(1, SkScalarRoundToInt(preScaleW * fScale));
792                     const int scaledH = std::max(1, SkScalarRoundToInt(preScaleH * fScale));
793                     decodeInfo = decodeInfo.makeWH(scaledW, scaledH);
794                     SkImageInfo subsetBitmapInfo = bitmapInfo.makeWH(scaledW, scaledH);
795                     size_t subsetRowBytes = subsetBitmapInfo.minRowBytes();
796                     const SkCodec::Result result = codec->getPixels(decodeInfo, dst, subsetRowBytes,
797                             &options);
798                     switch (result) {
799                         case SkCodec::kSuccess:
800                         case SkCodec::kErrorInInput:
801                         case SkCodec::kIncompleteInput:
802                             break;
803                         default:
804                             return Result::Fatal("subset codec failed to decode (%d, %d, %d, %d) "
805                                                  "from %s with dimensions (%d x %d)\t error %d",
806                                                  x, y, decodeInfo.width(), decodeInfo.height(),
807                                                  fPath.c_str(), W, H, result);
808                     }
809                     draw_to_canvas(canvas, subsetBitmapInfo, dst, subsetRowBytes, fDstColorType,
810                                    SkIntToScalar(left), SkIntToScalar(top));
811 
812                     // translate by the scaled height.
813                     top += decodeInfo.height();
814                 }
815                 // translate by the scaled width.
816                 left += decodeInfo.width();
817             }
818             return Result::Ok();
819         }
820         default:
821             SkASSERT(false);
822             return Result::Fatal("Invalid fMode");
823     }
824     return Result::Ok();
825 }
826 
size() const827 SkISize CodecSrc::size() const {
828     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
829     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(encoded));
830     if (nullptr == codec) {
831         return {0, 0};
832     }
833 
834     if (fMode != kAnimated_Mode) {
835         return codec->getScaledDimensions(fScale);
836     }
837 
838     // We'll draw one of each frame, so make it big enough to hold them all
839     // in a grid. The grid will be roughly square, with "factor" frames per
840     // row and up to "factor" rows.
841     const size_t count = codec->getFrameInfo().size();
842     const float root = sqrt((float) count);
843     const int factor = sk_float_ceil2int(root);
844 
845     auto androidCodec = SkAndroidCodec::MakeFromCodec(std::move(codec));
846     auto imageSize = androidCodec->getSampledDimensions(1 / fScale);
847     imageSize.fWidth  = imageSize.fWidth  * factor;
848     imageSize.fHeight = imageSize.fHeight * sk_float_ceil2int((float) count / (float) factor);
849     return imageSize;
850 }
851 
name() const852 Name CodecSrc::name() const {
853     Name name = SkOSPath::Basename(fPath.c_str());
854     if (fMode == kAnimated_Mode) {
855         name.append("_animated");
856     }
857     if (1.0f == fScale) {
858         return name;
859     }
860     return get_scaled_name(name.c_str(), fScale);
861 }
862 
863 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
864 
AndroidCodecSrc(Path path,CodecSrc::DstColorType dstColorType,SkAlphaType dstAlphaType,int sampleSize)865 AndroidCodecSrc::AndroidCodecSrc(Path path, CodecSrc::DstColorType dstColorType,
866         SkAlphaType dstAlphaType, int sampleSize)
867     : fPath(path)
868     , fDstColorType(dstColorType)
869     , fDstAlphaType(dstAlphaType)
870     , fSampleSize(sampleSize)
871     , fRunSerially(serial_from_path_name(path))
872 {}
873 
veto(SinkFlags flags) const874 bool AndroidCodecSrc::veto(SinkFlags flags) const {
875     // No need to test decoding to non-raster or indirect backend.
876     return flags.type != SinkFlags::kRaster
877         || flags.approach != SinkFlags::kDirect;
878 }
879 
draw(SkCanvas * canvas,GraphiteTestContext *) const880 Result AndroidCodecSrc::draw(SkCanvas* canvas, GraphiteTestContext*) const {
881     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
882     if (!encoded) {
883         return Result::Fatal("Couldn't read %s.", fPath.c_str());
884     }
885     std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::MakeFromData(encoded));
886     if (nullptr == codec) {
887         return Result::Fatal("Couldn't create android codec for %s.", fPath.c_str());
888     }
889 
890     SkImageInfo decodeInfo = codec->getInfo();
891     if (!get_decode_info(&decodeInfo, canvas->imageInfo().colorType(), fDstColorType,
892                          fDstAlphaType)) {
893         return Result::Skip("Skipping uninteresting test.");
894     }
895 
896     // Scale the image if it is desired.
897     SkISize size = codec->getSampledDimensions(fSampleSize);
898 
899     // Visually inspecting very small output images is not necessary.  We will
900     // cover these cases in unit testing.
901     if ((size.width() <= 10 || size.height() <= 10) && 1 != fSampleSize) {
902         return Result::Skip("Scaling very small images is uninteresting.");
903     }
904     decodeInfo = decodeInfo.makeDimensions(size);
905 
906     int bpp = decodeInfo.bytesPerPixel();
907     size_t rowBytes = size.width() * bpp;
908     SkAutoMalloc pixels(size.height() * rowBytes);
909 
910     SkBitmap bitmap;
911     SkImageInfo bitmapInfo = decodeInfo;
912     set_bitmap_color_space(&bitmapInfo);
913     if (kRGBA_8888_SkColorType == decodeInfo.colorType() ||
914             kBGRA_8888_SkColorType == decodeInfo.colorType()) {
915         bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType);
916     }
917 
918     // Create options for the codec.
919     SkAndroidCodec::AndroidOptions options;
920     options.fSampleSize = fSampleSize;
921 
922     switch (codec->getAndroidPixels(decodeInfo, pixels.get(), rowBytes, &options)) {
923         case SkCodec::kSuccess:
924         case SkCodec::kErrorInInput:
925         case SkCodec::kIncompleteInput:
926             break;
927         default:
928             return Result::Fatal("Couldn't getPixels %s.", fPath.c_str());
929     }
930     draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, fDstColorType);
931     return Result::Ok();
932 }
933 
size() const934 SkISize AndroidCodecSrc::size() const {
935     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
936     std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::MakeFromData(encoded));
937     if (nullptr == codec) {
938         return {0, 0};
939     }
940     return codec->getSampledDimensions(fSampleSize);
941 }
942 
name() const943 Name AndroidCodecSrc::name() const {
944     // We will replicate the names used by CodecSrc so that images can
945     // be compared in Gold.
946     if (1 == fSampleSize) {
947         return SkOSPath::Basename(fPath.c_str());
948     }
949     return get_scaled_name(fPath, 1.0f / (float) fSampleSize);
950 }
951 
952 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
953 
ImageGenSrc(Path path,Mode mode,SkAlphaType alphaType,bool isGpu)954 ImageGenSrc::ImageGenSrc(Path path, Mode mode, SkAlphaType alphaType, bool isGpu)
955     : fPath(path)
956     , fMode(mode)
957     , fDstAlphaType(alphaType)
958     , fIsGpu(isGpu)
959     , fRunSerially(serial_from_path_name(path))
960 {}
961 
veto(SinkFlags flags) const962 bool ImageGenSrc::veto(SinkFlags flags) const {
963     if (fIsGpu) {
964         // MSAA runs tend to run out of memory and tests the same code paths as regular gpu configs.
965         return flags.type != SinkFlags::kGPU || flags.approach != SinkFlags::kDirect ||
966                flags.multisampled == SinkFlags::kMultisampled;
967     }
968 
969     return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDirect;
970 }
971 
draw(SkCanvas * canvas,GraphiteTestContext *) const972 Result ImageGenSrc::draw(SkCanvas* canvas, GraphiteTestContext*) const {
973     if (kRGB_565_SkColorType == canvas->imageInfo().colorType()) {
974         return Result::Skip("Uninteresting to test image generator to 565.");
975     }
976 
977     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
978     if (!encoded) {
979         return Result::Fatal("Couldn't read %s.", fPath.c_str());
980     }
981 
982 #if defined(SK_BUILD_FOR_WIN)
983     // Initialize COM in order to test with WIC.
984     SkAutoCoInitialize com;
985     if (!com.succeeded()) {
986         return Result::Fatal("Could not initialize COM.");
987     }
988 #endif
989 
990     std::unique_ptr<SkImageGenerator> gen(nullptr);
991     switch (fMode) {
992         case kCodec_Mode:
993             gen = SkCodecImageGenerator::MakeFromEncodedCodec(encoded);
994             if (!gen) {
995                 return Result::Fatal("Could not create codec image generator.");
996             }
997             break;
998         case kPlatform_Mode: {
999 #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
1000             gen = SkImageGeneratorCG::MakeFromEncodedCG(encoded);
1001 #elif defined(SK_BUILD_FOR_WIN)
1002             gen = SkImageGeneratorWIC::MakeFromEncodedWIC(encoded);
1003 #elif defined(SK_ENABLE_NDK_IMAGES)
1004             gen = SkImageGeneratorNDK::MakeFromEncodedNDK(encoded);
1005 #endif
1006             if (!gen) {
1007                 return Result::Fatal("Could not create platform image generator.");
1008             }
1009             break;
1010         }
1011         default:
1012             SkASSERT(false);
1013             return Result::Fatal("Invalid image generator mode");
1014     }
1015 
1016     // Test deferred decoding path on GPU
1017     if (fIsGpu) {
1018         sk_sp<SkImage> image(SkImages::DeferredFromGenerator(std::move(gen)));
1019         if (!image) {
1020             return Result::Fatal("Could not create image from codec image generator.");
1021         }
1022         canvas->drawImage(image, 0, 0);
1023         return Result::Ok();
1024     }
1025 
1026     // Test various color and alpha types on CPU
1027     SkImageInfo decodeInfo = gen->getInfo().makeAlphaType(fDstAlphaType);
1028 
1029     int bpp = decodeInfo.bytesPerPixel();
1030     size_t rowBytes = decodeInfo.width() * bpp;
1031     SkAutoMalloc pixels(decodeInfo.height() * rowBytes);
1032     if (!gen->getPixels(decodeInfo, pixels.get(), rowBytes)) {
1033         Result::Status status = Result::Status::Fatal;
1034 #if defined(SK_BUILD_FOR_WIN)
1035         if (kPlatform_Mode == fMode) {
1036             // Do not issue a fatal error for WIC flakiness.
1037             status = Result::Status::Skip;
1038         }
1039 #endif
1040         return Result(
1041                 status,
1042                 SkStringPrintf("Image generator could not getPixels() for %s\n", fPath.c_str()));
1043     }
1044 
1045     set_bitmap_color_space(&decodeInfo);
1046     draw_to_canvas(canvas, decodeInfo, pixels.get(), rowBytes,
1047                    CodecSrc::kGetFromCanvas_DstColorType);
1048     return Result::Ok();
1049 }
1050 
size() const1051 SkISize ImageGenSrc::size() const {
1052     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
1053     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(encoded));
1054     if (nullptr == codec) {
1055         return {0, 0};
1056     }
1057     return codec->getInfo().dimensions();
1058 }
1059 
name() const1060 Name ImageGenSrc::name() const {
1061     return SkOSPath::Basename(fPath.c_str());
1062 }
1063 
1064 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1065 
ColorCodecSrc(Path path,bool decode_to_dst)1066 ColorCodecSrc::ColorCodecSrc(Path path, bool decode_to_dst) : fPath(path)
1067                                                             , fDecodeToDst(decode_to_dst) {}
1068 
veto(SinkFlags flags) const1069 bool ColorCodecSrc::veto(SinkFlags flags) const {
1070     // Test to direct raster backends (8888 and 565).
1071     return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDirect;
1072 }
1073 
draw(SkCanvas * canvas,GraphiteTestContext *) const1074 Result ColorCodecSrc::draw(SkCanvas* canvas, GraphiteTestContext*) const {
1075     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
1076     if (!encoded) {
1077         return Result::Fatal("Couldn't read %s.", fPath.c_str());
1078     }
1079 
1080     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(encoded));
1081     if (nullptr == codec) {
1082         return Result::Fatal("Couldn't create codec for %s.", fPath.c_str());
1083     }
1084 
1085     SkImageInfo info = codec->getInfo();
1086     if (SkEncodedOriginSwapsWidthHeight(codec->getOrigin())) {
1087         info = SkPixmapUtils::SwapWidthHeight(info);
1088     }
1089     if (fDecodeToDst) {
1090         SkImageInfo canvasInfo = canvas->imageInfo();
1091         if (!canvasInfo.colorSpace()) {
1092             // This will skip color conversion, and the resulting images will
1093             // look different from images they are compared against in Gold, but
1094             // that doesn't mean they are wrong. We have a test verifying that
1095             // passing a null SkColorSpace skips conversion, so skip this
1096             // misleading test.
1097             return Result::Skip("Skipping decoding without color transform.");
1098         }
1099         info = canvasInfo.makeDimensions(info.dimensions());
1100     }
1101 
1102     auto [image, result] = codec->getImage(info);
1103     switch (result) {
1104         case SkCodec::kSuccess:
1105         case SkCodec::kErrorInInput:
1106         case SkCodec::kIncompleteInput:
1107             canvas->drawImage(image, 0,0);
1108             return Result::Ok();
1109         case SkCodec::kInvalidConversion:
1110             // TODO(mtklein): why are there formats we can't decode to?
1111             return Result::Skip("SkCodec can't decode to this format.");
1112         default:
1113             return Result::Fatal("Couldn't getPixels %s. Error code %d", fPath.c_str(), result);
1114     }
1115 }
1116 
size() const1117 SkISize ColorCodecSrc::size() const {
1118     sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
1119     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(encoded));
1120     if (nullptr == codec) {
1121         return {0, 0};
1122     }
1123     return {codec->getInfo().width(), codec->getInfo().height()};
1124 }
1125 
name() const1126 Name ColorCodecSrc::name() const {
1127     return SkOSPath::Basename(fPath.c_str());
1128 }
1129 
1130 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1131 
1132 static DEFINE_int(skpViewportSize, 1000,
1133                   "Width & height of the viewport used to crop skp rendering.");
1134 
SKPSrc(Path path)1135 SKPSrc::SKPSrc(Path path) : fPath(path) { }
1136 
draw(SkCanvas * canvas,GraphiteTestContext *) const1137 Result SKPSrc::draw(SkCanvas* canvas, GraphiteTestContext*) const {
1138     struct DeserializationContext {
1139         GrDirectContext*           fDirectContext = nullptr;
1140 #if defined(SK_GRAPHITE)
1141         skgpu::graphite::Recorder* fRecorder = nullptr;
1142 #endif
1143     } ctx {
1144         GrAsDirectContext(canvas->recordingContext()),
1145 #if defined(SK_GRAPHITE)
1146         canvas->recorder()
1147 #endif
1148     };
1149 
1150     SkDeserialProcs procs;
1151     procs.fImageProc = [](const void* data, size_t size, void* ctx) -> sk_sp<SkImage> {
1152         sk_sp<SkData> tmpData = SkData::MakeWithoutCopy(data, size);
1153         sk_sp<SkImage> image = SkImages::DeferredFromEncodedData(std::move(tmpData));
1154         image = image->makeRasterImage(); // force decoding
1155 
1156         if (image) {
1157             DeserializationContext* context = reinterpret_cast<DeserializationContext*>(ctx);
1158 
1159             if (context->fDirectContext) {
1160                 return SkImages::TextureFromImage(context->fDirectContext, image);
1161             }
1162         }
1163         return image;
1164     };
1165     procs.fImageCtx = &ctx;
1166 
1167     // SKPs may have typefaces encoded in them (e.g. with FreeType). We can try falling back
1168     // to the Test FontMgr (possibly a native one) if we have do not have FreeType built-in.
1169     procs.fTypefaceProc = [](const void* data, size_t size, void*) -> sk_sp<SkTypeface> {
1170         SkStream** stream = reinterpret_cast<SkStream**>(const_cast<void*>(data));
1171         return SkTypeface::MakeDeserialize(*stream, ToolUtils::TestFontMgr());
1172     };
1173 
1174 
1175     std::unique_ptr<SkStream> stream = SkStream::MakeFromFile(fPath.c_str());
1176     if (!stream) {
1177         return Result::Fatal("Couldn't read %s.", fPath.c_str());
1178     }
1179     sk_sp<SkPicture> pic(SkPicture::MakeFromStream(stream.get(), &procs));
1180     if (!pic) {
1181         return Result::Fatal("Couldn't parse file %s.", fPath.c_str());
1182     }
1183     stream = nullptr;  // Might as well drop this when we're done with it.
1184     canvas->clipRect(SkRect::MakeWH(FLAGS_skpViewportSize, FLAGS_skpViewportSize));
1185     canvas->drawPicture(pic);
1186     return Result::Ok();
1187 }
1188 
get_cull_rect_for_skp(const char * path)1189 static SkRect get_cull_rect_for_skp(const char* path) {
1190     std::unique_ptr<SkStream> stream = SkStream::MakeFromFile(path);
1191     if (!stream) {
1192         return SkRect::MakeEmpty();
1193     }
1194     SkPictInfo info;
1195     if (!SkPicture_StreamIsSKP(stream.get(), &info)) {
1196         return SkRect::MakeEmpty();
1197     }
1198 
1199     return info.fCullRect;
1200 }
1201 
size() const1202 SkISize SKPSrc::size() const {
1203     SkRect viewport = get_cull_rect_for_skp(fPath.c_str());
1204     if (!viewport.intersect((SkRect::MakeWH(FLAGS_skpViewportSize, FLAGS_skpViewportSize)))) {
1205         return {0, 0};
1206     }
1207     return viewport.roundOut().size();
1208 }
1209 
name() const1210 Name SKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); }
1211 
1212 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1213 
BisectSrc(Path path,const char * trail)1214 BisectSrc::BisectSrc(Path path, const char* trail) : INHERITED(path), fTrail(trail) {}
1215 
draw(SkCanvas * canvas,GraphiteTestContext * testContext) const1216 Result BisectSrc::draw(SkCanvas* canvas, GraphiteTestContext* testContext) const {
1217     struct FoundPath {
1218         SkPath fPath;
1219         SkPaint fPaint;
1220         SkMatrix fViewMatrix;
1221     };
1222 
1223     // This subclass of SkCanvas just extracts all the SkPaths (drawn via drawPath) from an SKP.
1224     class PathFindingCanvas : public SkCanvas {
1225     public:
1226         PathFindingCanvas(int width, int height) : SkCanvas(width, height, nullptr) {}
1227         const TArray<FoundPath>& foundPaths() const { return fFoundPaths; }
1228 
1229     private:
1230         void onDrawPath(const SkPath& path, const SkPaint& paint) override {
1231             fFoundPaths.push_back() = {path, paint, this->getTotalMatrix()};
1232         }
1233 
1234         TArray<FoundPath> fFoundPaths;
1235     };
1236 
1237     PathFindingCanvas pathFinder(canvas->getBaseLayerSize().width(),
1238                                  canvas->getBaseLayerSize().height());
1239     Result result = this->INHERITED::draw(&pathFinder, testContext);
1240     if (!result.isOk()) {
1241         return result;
1242     }
1243 
1244     int start = 0, end = pathFinder.foundPaths().size();
1245     for (const char* ch = fTrail.c_str(); *ch; ++ch) {
1246         int midpt = (start + end) / 2;
1247         if ('l' == *ch) {
1248             start = midpt;
1249         } else if ('r' == *ch) {
1250             end = midpt;
1251         }
1252     }
1253 
1254     for (int i = start; i < end; ++i) {
1255         const FoundPath& path = pathFinder.foundPaths()[i];
1256         SkAutoCanvasRestore acr(canvas, true);
1257         canvas->concat(path.fViewMatrix);
1258         canvas->drawPath(path.fPath, path.fPaint);
1259     }
1260 
1261     return Result::Ok();
1262 }
1263 
1264 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1265 
1266 #if defined(SK_ENABLE_SKOTTIE)
1267 static DEFINE_bool(useLottieGlyphPaths, false,
1268                    "Prioritize embedded glyph paths over native fonts.");
1269 
SkottieSrc(Path path)1270 SkottieSrc::SkottieSrc(Path path) : fPath(std::move(path)) {}
1271 
draw(SkCanvas * canvas,GraphiteTestContext *) const1272 Result SkottieSrc::draw(SkCanvas* canvas, GraphiteTestContext*) const {
1273     auto predecode = skresources::ImageDecodeStrategy::kPreDecode;
1274     // DM should have already registered the codecs necessary for DataURIResourceProviderProxy
1275     // to decode images.
1276     auto resource_provider = skresources::DataURIResourceProviderProxy::Make(
1277             skresources::FileResourceProvider::Make(SkOSPath::Dirname(fPath.c_str()), predecode),
1278             predecode,
1279             ToolUtils::TestFontMgr());
1280 
1281     static constexpr char kInterceptPrefix[] = "__";
1282     auto precomp_interceptor =
1283             sk_make_sp<skottie_utils::ExternalAnimationPrecompInterceptor>(resource_provider,
1284                                                                            kInterceptPrefix);
1285     uint32_t flags = 0;
1286     if (FLAGS_useLottieGlyphPaths) {
1287         flags |= skottie::Animation::Builder::kPreferEmbeddedFonts;
1288     }
1289 
1290     auto animation = skottie::Animation::Builder(flags)
1291         .setFontManager(ToolUtils::TestFontMgr())
1292         .setResourceProvider(std::move(resource_provider))
1293         .setPrecompInterceptor(std::move(precomp_interceptor))
1294         .setTextShapingFactory(SkShapers::BestAvailable())
1295         .makeFromFile(fPath.c_str());
1296     if (!animation) {
1297         return Result::Fatal("Unable to parse file: %s", fPath.c_str());
1298     }
1299 
1300     canvas->drawColor(SK_ColorWHITE);
1301 
1302     const auto t_rate = 1.0f / (kTileCount * kTileCount - 1);
1303 
1304     // Draw the frames in a shuffled order to exercise non-linear
1305     // frame progression. The film strip will still be in order left-to-right,
1306     // top-down, just not drawn in that order.
1307     static constexpr int frameOrder[] = { 4, 0, 3, 1, 2 };
1308     static_assert(std::size(frameOrder) == kTileCount, "");
1309 
1310     for (int i = 0; i < kTileCount; ++i) {
1311         const SkScalar y = frameOrder[i] * kTileSize;
1312 
1313         for (int j = 0; j < kTileCount; ++j) {
1314             const SkScalar x = frameOrder[j] * kTileSize;
1315             SkRect dest = SkRect::MakeXYWH(x, y, kTileSize, kTileSize);
1316 
1317             const auto t = t_rate * (frameOrder[i] * kTileCount + frameOrder[j]);
1318             {
1319                 SkAutoCanvasRestore acr(canvas, true);
1320                 canvas->clipRect(dest, true);
1321                 canvas->concat(SkMatrix::RectToRect(SkRect::MakeSize(animation->size()), dest,
1322                                                     SkMatrix::kCenter_ScaleToFit));
1323                 animation->seek(t);
1324                 animation->render(canvas);
1325             }
1326         }
1327     }
1328 
1329     return Result::Ok();
1330 }
1331 
size() const1332 SkISize SkottieSrc::size() const {
1333     return SkISize::Make(kTargetSize, kTargetSize);
1334 }
1335 
name() const1336 Name SkottieSrc::name() const { return SkOSPath::Basename(fPath.c_str()); }
1337 
veto(SinkFlags flags) const1338 bool SkottieSrc::veto(SinkFlags flags) const {
1339     // No need to test to non-(raster||gpu||vector) or indirect backends.
1340     bool type_ok = flags.type == SinkFlags::kRaster
1341                 || flags.type == SinkFlags::kGPU
1342                 || flags.type == SinkFlags::kVector;
1343 
1344     return !type_ok || flags.approach != SinkFlags::kDirect;
1345 }
1346 #endif
1347 
1348 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1349 #if defined(SK_ENABLE_SVG)
1350 // Used when the image doesn't have an intrinsic size.
1351 static const SkSize kDefaultSVGSize = {1000, 1000};
1352 
1353 // Used to force-scale tiny fixed-size images.
1354 static const SkSize kMinimumSVGSize = {128, 128};
1355 
SVGSrc(Path path)1356 SVGSrc::SVGSrc(Path path)
1357     : fName(SkOSPath::Basename(path.c_str()))
1358     , fScale(1) {
1359 
1360     auto stream = SkStream::MakeFromFile(path.c_str());
1361     if (!stream) {
1362         return;
1363     }
1364 
1365     // DM should have already registered the codecs necessary for DataURIResourceProviderProxy
1366     // to decode images.
1367     auto predecode = skresources::ImageDecodeStrategy::kPreDecode;
1368     auto rp = skresources::DataURIResourceProviderProxy::Make(
1369             skresources::FileResourceProvider::Make(SkOSPath::Dirname(path.c_str()), predecode),
1370             predecode,
1371             ToolUtils::TestFontMgr());
1372 
1373     fDom = SkSVGDOM::Builder()
1374                    .setResourceProvider(std::move(rp))
1375                    .setFontManager(ToolUtils::TestFontMgr())
1376                    .setTextShapingFactory(SkShapers::BestAvailable())
1377                    .make(*stream);
1378     if (!fDom) {
1379         return;
1380     }
1381 
1382     const SkSize& sz = fDom->containerSize();
1383     if (sz.isEmpty()) {
1384         // no intrinsic size
1385         fDom->setContainerSize(kDefaultSVGSize);
1386     } else {
1387         fScale = std::max(1.f, std::max(kMinimumSVGSize.width()  / sz.width(),
1388                                         kMinimumSVGSize.height() / sz.height()));
1389     }
1390 }
1391 
draw(SkCanvas * canvas,GraphiteTestContext *) const1392 Result SVGSrc::draw(SkCanvas* canvas, GraphiteTestContext*) const {
1393     if (!fDom) {
1394         return Result::Fatal("Unable to parse file: %s", fName.c_str());
1395     }
1396 
1397     SkAutoCanvasRestore acr(canvas, true);
1398     canvas->scale(fScale, fScale);
1399     canvas->drawColor(SK_ColorWHITE);
1400     fDom->render(canvas);
1401 
1402     return Result::Ok();
1403 }
1404 
size() const1405 SkISize SVGSrc::size() const {
1406     if (!fDom) {
1407         return {0, 0};
1408     }
1409 
1410     return SkSize{fDom->containerSize().width() * fScale, fDom->containerSize().height() * fScale}
1411             .toRound();
1412 }
1413 
name() const1414 Name SVGSrc::name() const { return fName; }
1415 
veto(SinkFlags flags) const1416 bool SVGSrc::veto(SinkFlags flags) const {
1417     // No need to test to non-(raster||gpu||vector) or indirect backends.
1418     bool type_ok = flags.type == SinkFlags::kRaster
1419                 || flags.type == SinkFlags::kGPU
1420                 || flags.type == SinkFlags::kVector;
1421 
1422     return !type_ok || flags.approach != SinkFlags::kDirect;
1423 }
1424 
1425 #endif // defined(SK_ENABLE_SVG)
1426 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1427 
MSKPSrc(Path path)1428 MSKPSrc::MSKPSrc(Path path) : fPath(path) {
1429     std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(fPath.c_str());
1430     int count = SkMultiPictureDocument::ReadPageCount(stream.get());
1431     if (count > 0) {
1432         fPages.reset(count);
1433         SkASSERT_RELEASE(SkMultiPictureDocument::ReadPageSizes(stream.get(), &fPages[0],
1434                                                                fPages.size()));
1435     }
1436 }
1437 
pageCount() const1438 int MSKPSrc::pageCount() const { return fPages.size(); }
1439 
size() const1440 SkISize MSKPSrc::size() const { return this->size(FLAGS_mskpFrame); }
size(int i) const1441 SkISize MSKPSrc::size(int i) const {
1442     return i >= 0 && i < fPages.size() ? fPages[i].fSize.toCeil() : SkISize{0, 0};
1443 }
1444 
draw(SkCanvas * c,GraphiteTestContext * testContext) const1445 Result MSKPSrc::draw(SkCanvas* c, GraphiteTestContext* testContext) const {
1446     return this->draw(FLAGS_mskpFrame, c, testContext);
1447 }
draw(int i,SkCanvas * canvas,GraphiteTestContext *) const1448 Result MSKPSrc::draw(int i, SkCanvas* canvas, GraphiteTestContext*) const {
1449     if (this->pageCount() == 0) {
1450         return Result::Fatal("Unable to parse MultiPictureDocument file: %s", fPath.c_str());
1451     }
1452     if (i >= fPages.size() || i < 0) {
1453         return Result::Fatal("MultiPictureDocument page number out of range: %d", i);
1454     }
1455     SkPicture* page = fPages[i].fPicture.get();
1456     if (!page) {
1457         std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(fPath.c_str());
1458         if (!stream) {
1459             return Result::Fatal("Unable to open file: %s", fPath.c_str());
1460         }
1461         if (!SkMultiPictureDocument::Read(stream.get(), &fPages[0], fPages.size())) {
1462             return Result::Fatal("SkMultiPictureDocument reader failed on page %d: %s", i,
1463                                  fPath.c_str());
1464         }
1465         page = fPages[i].fPicture.get();
1466     }
1467     canvas->drawPicture(page);
1468     return Result::Ok();
1469 }
1470 
name() const1471 Name MSKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); }
1472 
1473 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1474 
draw(const Src & src,SkBitmap *,SkWStream *,SkString *) const1475 Result NullSink::draw(const Src& src, SkBitmap*, SkWStream*, SkString*) const {
1476     return src.draw(SkMakeNullCanvas().get(), /*GraphiteTestContext=*/nullptr);
1477 }
1478 
1479 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1480 
compare_bitmaps(const SkBitmap & reference,const SkBitmap & bitmap)1481 static Result compare_bitmaps(const SkBitmap& reference, const SkBitmap& bitmap) {
1482     // The dimensions are a property of the Src only, and so should be identical.
1483     SkASSERT(reference.computeByteSize() == bitmap.computeByteSize());
1484     if (reference.computeByteSize() != bitmap.computeByteSize()) {
1485         return Result::Fatal("Dimensions don't match reference");
1486     }
1487     // All SkBitmaps in DM are tight, so this comparison is easy.
1488     if (0 != memcmp(reference.getPixels(), bitmap.getPixels(), reference.computeByteSize())) {
1489         SkString encoded;
1490         SkString errString("Pixels don't match reference");
1491         if (ToolUtils::BitmapToBase64DataURI(reference, &encoded)) {
1492             errString.append("\nExpected: ");
1493             errString.append(encoded);
1494         } else {
1495             errString.append("\nExpected image failed to encode: ");
1496             errString.append(encoded);
1497         }
1498         if (ToolUtils::BitmapToBase64DataURI(bitmap, &encoded)) {
1499             errString.append("\nActual: ");
1500             errString.append(encoded);
1501         } else {
1502             errString.append("\nActual image failed to encode: ");
1503             errString.append(encoded);
1504         }
1505         return Result(Result::Status::Fatal, errString);
1506     }
1507     return Result::Ok();
1508 }
1509 
1510 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1511 
1512 static DEFINE_bool(gpuStats, false, "Append GPU stats to the log for each GPU task?");
1513 static DEFINE_bool(preAbandonGpuContext, false,
1514                    "Test abandoning the GrContext before running the test.");
1515 static DEFINE_bool(abandonGpuContext, false,
1516                    "Test abandoning the GrContext after running each test.");
1517 static DEFINE_bool(releaseAndAbandonGpuContext, false,
1518                    "Test releasing all gpu resources and abandoning the GrContext "
1519                    "after running each test");
1520 static DEFINE_bool(drawOpClip, false, "Clip each GrDrawOp to its device bounds for testing.");
1521 static DEFINE_bool(programBinaryCache, true, "Use in-memory program binary cache");
1522 
GPUSink(const SkCommandLineConfigGpu * config,const GrContextOptions & grCtxOptions)1523 GPUSink::GPUSink(const SkCommandLineConfigGpu* config,
1524                  const GrContextOptions& grCtxOptions)
1525         : fContextType(config->getContextType())
1526         , fContextOverrides(config->getContextOverrides())
1527         , fSurfType(config->getSurfType())
1528         , fSampleCount(config->getSamples())
1529         , fSurfaceFlags(config->getSurfaceFlags())
1530         , fColorType(config->getColorType())
1531         , fAlphaType(config->getAlphaType())
1532         , fBaseContextOptions(grCtxOptions) {
1533     if (FLAGS_programBinaryCache) {
1534         fBaseContextOptions.fPersistentCache = &fMemoryCache;
1535     }
1536 }
1537 
draw(const Src & src,SkBitmap * dst,SkWStream * dstStream,SkString * log) const1538 Result GPUSink::draw(const Src& src, SkBitmap* dst, SkWStream* dstStream, SkString* log) const {
1539     return this->onDraw(src, dst, dstStream, log, fBaseContextOptions);
1540 }
1541 
createDstSurface(GrDirectContext * context,SkISize size) const1542 sk_sp<SkSurface> GPUSink::createDstSurface(GrDirectContext* context, SkISize size) const {
1543     sk_sp<SkSurface> surface;
1544 
1545     SkImageInfo info = SkImageInfo::Make(size, this->colorInfo());
1546     SkSurfaceProps props(fSurfaceFlags, kRGB_H_SkPixelGeometry);
1547 
1548     switch (fSurfType) {
1549         case SkCommandLineConfigGpu::SurfType::kDefault:
1550             surface = SkSurfaces::RenderTarget(
1551                     context, skgpu::Budgeted::kNo, info, fSampleCount, &props);
1552             break;
1553         case SkCommandLineConfigGpu::SurfType::kBackendTexture:
1554             surface = sk_gpu_test::MakeBackendTextureSurface(context,
1555                                                              info,
1556                                                              kTopLeft_GrSurfaceOrigin,
1557                                                              fSampleCount,
1558                                                              skgpu::Mipmapped::kNo,
1559                                                              GrProtected::kNo,
1560                                                              &props);
1561             break;
1562         case SkCommandLineConfigGpu::SurfType::kBackendRenderTarget:
1563             surface = sk_gpu_test::MakeBackendRenderTargetSurface(context,
1564                                                                   info,
1565                                                                   kBottomLeft_GrSurfaceOrigin,
1566                                                                   fSampleCount,
1567                                                                   GrProtected::kNo,
1568                                                                   &props);
1569             break;
1570     }
1571 
1572     return surface;
1573 }
1574 
readBack(SkSurface * surface,SkBitmap * dst) const1575 bool GPUSink::readBack(SkSurface* surface, SkBitmap* dst) const {
1576     SkCanvas* canvas = surface->getCanvas();
1577     SkISize size = surface->imageInfo().dimensions();
1578 
1579     SkImageInfo info = SkImageInfo::Make(size, this->colorInfo());
1580     dst->allocPixels(info);
1581     return canvas->readPixels(*dst, 0, 0);
1582 }
1583 
onDraw(const Src & src,SkBitmap * dst,SkWStream *,SkString * log,const GrContextOptions & baseOptions,std::function<void (GrDirectContext *)> initContext,std::function<SkCanvas * (SkCanvas *)> wrapCanvas) const1584 Result GPUSink::onDraw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log,
1585                        const GrContextOptions& baseOptions,
1586                        std::function<void(GrDirectContext*)> initContext,
1587                        std::function<SkCanvas*(SkCanvas*)> wrapCanvas) const {
1588     GrContextOptions grOptions = baseOptions;
1589 
1590     // We don't expect the src to mess with the persistent cache or the executor.
1591     SkDEBUGCODE(auto cache = grOptions.fPersistentCache);
1592     SkDEBUGCODE(auto exec = grOptions.fExecutor);
1593     src.modifyGrContextOptions(&grOptions);
1594     SkASSERT(cache == grOptions.fPersistentCache);
1595     SkASSERT(exec == grOptions.fExecutor);
1596 
1597     GrContextFactory factory(grOptions);
1598     auto direct = factory.getContextInfo(fContextType, fContextOverrides).directContext();
1599     if (initContext) {
1600         initContext(direct);
1601     }
1602 
1603     const int maxDimension = direct->priv().caps()->maxTextureSize();
1604     if (maxDimension < std::max(src.size().width(), src.size().height())) {
1605         return Result::Skip("Src too large to create a texture.\n");
1606     }
1607 
1608     sk_sp<SkSurface> surface = this->createDstSurface(direct, src.size());
1609     if (!surface) {
1610         return Result::Fatal("Could not create a surface.");
1611     }
1612     if (FLAGS_preAbandonGpuContext) {
1613         factory.abandonContexts();
1614     }
1615 
1616     auto canvas = surface->getCanvas();
1617     if (wrapCanvas != nullptr) {
1618         canvas = wrapCanvas(canvas);
1619     }
1620 
1621     Result result = src.draw(canvas, /*GraphiteTestContext=*/nullptr);
1622     if (!result.isOk()) {
1623         return result;
1624     }
1625     direct->flushAndSubmit(surface.get(), GrSyncCpu::kNo);
1626     if (FLAGS_gpuStats) {
1627         direct->priv().dumpCacheStats(log);
1628         direct->priv().dumpGpuStats(log);
1629         direct->priv().dumpContextStats(log);
1630     }
1631 
1632     this->readBack(surface.get(), dst);
1633 
1634     if (FLAGS_abandonGpuContext) {
1635         factory.abandonContexts();
1636     } else if (FLAGS_releaseAndAbandonGpuContext) {
1637         factory.releaseResourcesAndAbandonContexts();
1638     }
1639 
1640     if (grOptions.fPersistentCache) {
1641         direct->storeVkPipelineCacheData();
1642     }
1643     return Result::Ok();
1644 }
1645 
1646 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
GPUSlugSink(const SkCommandLineConfigGpu * config,const GrContextOptions & options)1647 GPUSlugSink::GPUSlugSink(const SkCommandLineConfigGpu* config, const GrContextOptions& options)
1648         : GPUSink(config, options) {}
1649 
draw(const Src & src,SkBitmap * dst,SkWStream * write,SkString * log) const1650 Result GPUSlugSink::draw(const Src& src, SkBitmap* dst, SkWStream* write, SkString* log) const {
1651     GrContextOptions grOptions = this->baseContextOptions();
1652     // Force padded atlas entries for slug drawing.
1653     grOptions.fSupportBilerpFromGlyphAtlas |= true;
1654 
1655     SkTLazy<SkTestCanvas<SkSlugTestKey>> testCanvas;
1656 
1657     return onDraw(src, dst, write, log, grOptions, nullptr,
1658         [&](SkCanvas* canvas){
1659             testCanvas.init(canvas);
1660             return testCanvas.get();
1661         });
1662 }
1663 
1664 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
GPUSerializeSlugSink(const SkCommandLineConfigGpu * config,const GrContextOptions & options)1665 GPUSerializeSlugSink::GPUSerializeSlugSink(
1666         const SkCommandLineConfigGpu* config, const GrContextOptions& options)
1667     : GPUSink(config, options) {}
1668 
draw(const Src & src,SkBitmap * dst,SkWStream * write,SkString * log) const1669 Result GPUSerializeSlugSink::draw(
1670         const Src& src, SkBitmap* dst, SkWStream* write, SkString* log) const {
1671     GrContextOptions grOptions = this->baseContextOptions();
1672     // Force padded atlas entries for slug drawing.
1673     grOptions.fSupportBilerpFromGlyphAtlas |= true;
1674 
1675     SkTLazy<SkTestCanvas<SkSerializeSlugTestKey>> testCanvas;
1676 
1677     return onDraw(src, dst, write, log, grOptions, nullptr,
1678                   [&](SkCanvas* canvas){
1679                       testCanvas.init(canvas);
1680                       return testCanvas.get();
1681                   });
1682 }
1683 
1684 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
GPURemoteSlugSink(const SkCommandLineConfigGpu * config,const GrContextOptions & options)1685 GPURemoteSlugSink::GPURemoteSlugSink(
1686         const SkCommandLineConfigGpu* config, const GrContextOptions& options)
1687         : GPUSink(config, options) {}
1688 
draw(const Src & src,SkBitmap * dst,SkWStream * write,SkString * log) const1689 Result GPURemoteSlugSink::draw(
1690         const Src& src, SkBitmap* dst, SkWStream* write, SkString* log) const {
1691     GrContextOptions grOptions = this->baseContextOptions();
1692     // Force padded atlas entries for slug drawing.
1693     grOptions.fSupportBilerpFromGlyphAtlas |= true;
1694 
1695     SkTLazy<SkTestCanvas<SkRemoteSlugTestKey>> testCanvas;
1696 
1697     return onDraw(src, dst, write, log, grOptions, nullptr,
1698                   [&](SkCanvas* canvas) {
1699                       testCanvas.init(canvas);
1700                       return testCanvas.get();
1701                   });
1702 }
1703 
1704 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
GPUPersistentCacheTestingSink(const SkCommandLineConfigGpu * config,const GrContextOptions & grCtxOptions)1705 GPUPersistentCacheTestingSink::GPUPersistentCacheTestingSink(const SkCommandLineConfigGpu* config,
1706                                                              const GrContextOptions& grCtxOptions)
1707     : INHERITED(config, grCtxOptions)
1708     , fCacheType(config->getTestPersistentCache()) {}
1709 
draw(const Src & src,SkBitmap * dst,SkWStream * wStream,SkString * log) const1710 Result GPUPersistentCacheTestingSink::draw(const Src& src, SkBitmap* dst, SkWStream* wStream,
1711                                            SkString* log) const {
1712     // Draw twice, once with a cold cache, and again with a warm cache. Verify that we get the same
1713     // result.
1714     sk_gpu_test::MemoryCache memoryCache;
1715     GrContextOptions contextOptions = this->baseContextOptions();
1716     contextOptions.fPersistentCache = &memoryCache;
1717     if (fCacheType == 2) {
1718         contextOptions.fShaderCacheStrategy = GrContextOptions::ShaderCacheStrategy::kBackendSource;
1719     }
1720 
1721     Result result = this->onDraw(src, dst, wStream, log, contextOptions);
1722     if (!result.isOk() || !dst) {
1723         return result;
1724     }
1725 
1726     SkBitmap reference;
1727     SkString refLog;
1728     SkDynamicMemoryWStream refStream;
1729     memoryCache.resetCacheStats();
1730     Result refResult = this->onDraw(src, &reference, &refStream, &refLog, contextOptions);
1731     if (!refResult.isOk()) {
1732         return refResult;
1733     }
1734     SkASSERT(!memoryCache.numCacheMisses());
1735     SkASSERT(!memoryCache.numCacheStores());
1736 
1737     return compare_bitmaps(reference, *dst);
1738 }
1739 
1740 
1741 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
1742 
GPUPrecompileTestingSink(const SkCommandLineConfigGpu * config,const GrContextOptions & grCtxOptions)1743 GPUPrecompileTestingSink::GPUPrecompileTestingSink(const SkCommandLineConfigGpu* config,
1744                                                    const GrContextOptions& grCtxOptions)
1745     : INHERITED(config, grCtxOptions) {}
1746 
draw(const Src & src,SkBitmap * dst,SkWStream * wStream,SkString * log) const1747 Result GPUPrecompileTestingSink::draw(const Src& src, SkBitmap* dst, SkWStream* wStream,
1748                                       SkString* log) const {
1749     // Three step process:
1750     // 1) Draw once with an SkSL cache, and store off the shader blobs.
1751     // 2) For the second context, pre-compile the shaders to warm the cache.
1752     // 3) Draw with the second context, ensuring that we get the same result, and no cache misses.
1753     sk_gpu_test::MemoryCache memoryCache;
1754     GrContextOptions contextOptions = this->baseContextOptions();
1755     contextOptions.fPersistentCache = &memoryCache;
1756     contextOptions.fShaderCacheStrategy = GrContextOptions::ShaderCacheStrategy::kSkSL;
1757 
1758     Result result = this->onDraw(src, dst, wStream, log, contextOptions);
1759     if (!result.isOk() || !dst) {
1760         return result;
1761     }
1762 
1763     auto precompileShaders = [&memoryCache](GrDirectContext* dContext) {
1764         memoryCache.foreach([dContext](sk_sp<const SkData> key,
1765                                        sk_sp<SkData> data,
1766                                        const SkString& /*description*/,
1767                                        int /*count*/) {
1768             SkAssertResult(dContext->precompileShader(*key, *data));
1769         });
1770     };
1771 
1772     sk_gpu_test::MemoryCache replayCache;
1773     GrContextOptions replayOptions = this->baseContextOptions();
1774     // Ensure that the runtime cache is large enough to hold all of the shaders we pre-compile
1775     replayOptions.fRuntimeProgramCacheSize = memoryCache.numCacheMisses();
1776     replayOptions.fPersistentCache = &replayCache;
1777 
1778     SkBitmap reference;
1779     SkString refLog;
1780     SkDynamicMemoryWStream refStream;
1781     Result refResult = this->onDraw(src, &reference, &refStream, &refLog, replayOptions,
1782                                     precompileShaders);
1783     if (!refResult.isOk()) {
1784         return refResult;
1785     }
1786     SkASSERT(!replayCache.numCacheMisses());
1787 
1788     return compare_bitmaps(reference, *dst);
1789 }
1790 
1791 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
GPUDDLSink(const SkCommandLineConfigGpu * config,const GrContextOptions & ctxOptions)1792 GPUDDLSink::GPUDDLSink(const SkCommandLineConfigGpu* config, const GrContextOptions& ctxOptions)
1793         : INHERITED(config, ctxOptions)
1794         , fRecordingExecutor(SkExecutor::MakeLIFOThreadPool(1))
1795         , fGPUExecutor(SkExecutor::MakeFIFOThreadPool(1, false)) {
1796 }
1797 
ddlDraw(const Src & src,sk_sp<SkSurface> dstSurface,SkTaskGroup * recordingTaskGroup,SkTaskGroup * gpuTaskGroup,sk_gpu_test::TestContext * gpuTestCtx,GrDirectContext * dContext) const1798 Result GPUDDLSink::ddlDraw(const Src& src,
1799                            sk_sp<SkSurface> dstSurface,
1800                            SkTaskGroup* recordingTaskGroup,
1801                            SkTaskGroup* gpuTaskGroup,
1802                            sk_gpu_test::TestContext* gpuTestCtx,
1803                            GrDirectContext* dContext) const {
1804 
1805     // We have to do this here bc characterization can hit the SkGpuDevice's thread guard (i.e.,
1806     // leaving it until the DDLTileHelper ctor will result in multiple threads trying to use the
1807     // same context (this thread and the gpuThread - which will be uploading textures)).
1808     GrSurfaceCharacterization dstCharacterization;
1809     SkAssertResult(dstSurface->characterize(&dstCharacterization));
1810 
1811     auto size = src.size();
1812     SkPictureRecorder recorder;
1813     Result result = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
1814                                                      SkIntToScalar(size.height())),
1815                              /*GraphiteTestContext=*/nullptr);
1816     if (!result.isOk()) {
1817         return result;
1818     }
1819     sk_sp<SkPicture> inputPicture(recorder.finishRecordingAsPicture());
1820 
1821     // this is our ultimate final drawing area/rect
1822     SkIRect viewport = SkIRect::MakeWH(size.fWidth, size.fHeight);
1823 
1824     auto supportedYUVADataTypes = skgpu::ganesh::SupportedTextureFormats(*dContext);
1825     DDLPromiseImageHelper promiseImageHelper(supportedYUVADataTypes);
1826     sk_sp<SkPicture> newSKP = promiseImageHelper.recreateSKP(dContext, inputPicture.get());
1827     if (!newSKP) {
1828         return Result::Fatal("GPUDDLSink: Couldn't recreate the SKP");
1829     }
1830 
1831     // 'gpuTestCtx/gpuThreadCtx' is being shifted to the gpuThread. Leave the main (this)
1832     // thread w/o a context.
1833     gpuTestCtx->makeNotCurrent();
1834 
1835     // Job one for the GPU thread is to make 'gpuTestCtx' current!
1836     gpuTaskGroup->add([gpuTestCtx] { gpuTestCtx->makeCurrent(); });
1837 
1838     // TODO: move the image upload to the utility thread
1839     promiseImageHelper.uploadAllToGPU(gpuTaskGroup, dContext);
1840 
1841     // Care must be taken when using 'gpuThreadCtx' bc it moves between the gpu-thread and this
1842     // one. About all it can be consistently used for is GrCaps access and 'defaultBackendFormat'
1843     // calls.
1844     constexpr int kNumDivisions = 3;
1845     DDLTileHelper tiles(dContext, dstCharacterization, viewport,
1846                         kNumDivisions, kNumDivisions,
1847                         /* addRandomPaddingToDst */ false);
1848 
1849     tiles.createBackendTextures(gpuTaskGroup, dContext);
1850 
1851     tiles.kickOffThreadedWork(recordingTaskGroup, gpuTaskGroup, dContext, newSKP.get());
1852 
1853     // We have to wait for the recording threads to schedule all their work on the gpu thread
1854     // before we can schedule the composition draw and the flush. Note that the gpu thread
1855     // is not blocked at this point and this thread is borrowing recording work.
1856     recordingTaskGroup->wait();
1857 
1858     // Note: at this point the recording thread(s) are stalled out w/ nothing to do.
1859 
1860     if (FLAGS_preAbandonGpuContext) {
1861         dContext->abandonContext();
1862     }
1863 
1864     // The recording threads have already scheduled the drawing of each tile's DDL on the gpu
1865     // thread. The composition DDL must be scheduled last bc it relies on the result of all
1866     // the tiles' rendering. Additionally, bc we're aliasing the tiles' backend textures,
1867     // there is nothing in the DAG to automatically force the required order.
1868     gpuTaskGroup->add([dstSurface, ddl = tiles.composeDDL()]() {
1869                           skgpu::ganesh::DrawDDL(dstSurface, ddl);
1870                       });
1871 
1872     // This should be the only explicit flush for the entire DDL draw.
1873     gpuTaskGroup->add([dContext]() {
1874                                            // We need to ensure all the GPU work is finished so
1875                                            // the following 'deleteAllFromGPU' call will work
1876                                            // on Vulkan.
1877                                            // TODO: switch over to using the promiseImage callbacks
1878                                            // to free the backendTextures. This is complicated a
1879                                            // bit by which thread possesses the direct context.
1880                                            dContext->flush();
1881                                            dContext->submit(GrSyncCpu::kYes);
1882                                        });
1883 
1884     // The backend textures are created on the gpuThread by the 'uploadAllToGPU' call.
1885     // It is simpler to also delete them at this point on the gpuThread.
1886     promiseImageHelper.deleteAllFromGPU(gpuTaskGroup, dContext);
1887 
1888     tiles.deleteBackendTextures(gpuTaskGroup, dContext);
1889 
1890     // A flush has already been scheduled on the gpu thread along with the clean up of the backend
1891     // textures so it is safe to schedule making 'gpuTestCtx' not current on the gpuThread.
1892     gpuTaskGroup->add([gpuTestCtx] { gpuTestCtx->makeNotCurrent(); });
1893 
1894     // All the work is scheduled on the gpu thread, we just need to wait
1895     gpuTaskGroup->wait();
1896 
1897     return Result::Ok();
1898 }
1899 
draw(const Src & src,SkBitmap * dst,SkWStream *,SkString * log) const1900 Result GPUDDLSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log) const {
1901     GrContextOptions contextOptions = this->baseContextOptions();
1902     src.modifyGrContextOptions(&contextOptions);
1903     contextOptions.fPersistentCache = nullptr;
1904     contextOptions.fExecutor = nullptr;
1905 
1906     GrContextFactory factory(contextOptions);
1907 
1908     // This captures the context destined to be the main gpu context
1909     ContextInfo mainCtxInfo = factory.getContextInfo(this->contextType(), this->contextOverrides());
1910     sk_gpu_test::TestContext* mainTestCtx = mainCtxInfo.testContext();
1911     auto mainCtx = mainCtxInfo.directContext();
1912     if (!mainCtx) {
1913         return Result::Fatal("Could not create context.");
1914     }
1915 
1916     SkASSERT(mainCtx->priv().getGpu());
1917 
1918     // TODO: make use of 'otherCtx' for uploads & compilation
1919 #if 0
1920     // This captures the context destined to be the utility context. It is in a share group
1921     // with the main context
1922     ContextInfo otherCtxInfo = factory.getSharedContextInfo(mainCtx);
1923     sk_gpu_test::TestContext* otherTestCtx = otherCtxInfo.testContext();
1924     auto otherCtx = otherCtxInfo.directContext();
1925     if (!otherCtx) {
1926         return Result::Fatal("Cound not create shared context.");
1927     }
1928 
1929     SkASSERT(otherCtx->priv().getGpu());
1930 #endif
1931 
1932     SkTaskGroup recordingTaskGroup(*fRecordingExecutor);
1933     SkTaskGroup gpuTaskGroup(*fGPUExecutor);
1934 
1935     // Make sure 'mainCtx' is current
1936     mainTestCtx->makeCurrent();
1937 
1938     sk_sp<SkSurface> surface = this->createDstSurface(mainCtx, src.size());
1939     if (!surface) {
1940         return Result::Fatal("Could not create a surface.");
1941     }
1942 
1943     Result result = this->ddlDraw(src, surface, &recordingTaskGroup, &gpuTaskGroup,
1944                                   mainTestCtx, mainCtx);
1945     if (!result.isOk()) {
1946         return result;
1947     }
1948 
1949     // 'ddlDraw' will have made 'mainCtx' not current on the gpuThread
1950     mainTestCtx->makeCurrent();
1951 
1952     if (FLAGS_gpuStats) {
1953         mainCtx->priv().dumpCacheStats(log);
1954         mainCtx->priv().dumpGpuStats(log);
1955         mainCtx->priv().dumpContextStats(log);
1956 
1957 #if 0
1958         otherCtx->priv().dumpCacheStats(log);
1959         otherCtx->priv().dumpGpuStats(log);
1960         otherCtx->priv().dumpContextStats(log);
1961 #endif
1962     }
1963 
1964     if (!this->readBack(surface.get(), dst)) {
1965         return Result::Fatal("Could not readback from surface.");
1966     }
1967 
1968     return Result::Ok();
1969 }
1970 
1971 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
draw_skdocument(const Src & src,SkDocument * doc,SkWStream * dst)1972 static Result draw_skdocument(const Src& src, SkDocument* doc, SkWStream* dst) {
1973     if (src.size().isEmpty()) {
1974         return Result::Fatal("Source has empty dimensions");
1975     }
1976     SkASSERT(doc);
1977     int pageCount = src.pageCount();
1978     for (int i = 0; i < pageCount; ++i) {
1979         int width = src.size(i).width(), height = src.size(i).height();
1980         SkCanvas* canvas =
1981                 doc->beginPage(SkIntToScalar(width), SkIntToScalar(height));
1982         if (!canvas) {
1983             return Result::Fatal("SkDocument::beginPage(w,h) returned nullptr");
1984         }
1985         Result result = src.draw(i, canvas, /*GraphiteTestContext=*/nullptr);
1986         if (!result.isOk()) {
1987             return result;
1988         }
1989         doc->endPage();
1990     }
1991     doc->close();
1992     dst->flush();
1993     return Result::Ok();
1994 }
1995 
draw(const Src & src,SkBitmap *,SkWStream * dst,SkString *) const1996 Result PDFSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
1997     SkPDF::Metadata metadata;
1998     metadata.fTitle = src.name();
1999     metadata.fSubject = "rendering correctness test";
2000     metadata.fCreator = "Skia/DM";
2001     metadata.fProducer = "Skia/PDF HEAD"; // Set producer to avoid SK_MILESTONE churn.
2002     metadata.fRasterDPI = fRasterDpi;
2003     metadata.fPDFA = fPDFA;
2004 #if SK_PDF_TEST_EXECUTOR
2005     std::unique_ptr<SkExecutor> executor = SkExecutor::MakeFIFOThreadPool();
2006     metadata.fExecutor = executor.get();
2007 #endif
2008     auto doc = SkPDF::MakeDocument(dst, metadata);
2009     if (!doc) {
2010         return Result::Fatal("SkPDF::MakeDocument() returned nullptr");
2011     }
2012     return draw_skdocument(src, doc.get(), dst);
2013 }
2014 
2015 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
2016 
XPSSink()2017 XPSSink::XPSSink() {}
2018 
2019 #if defined(SK_SUPPORT_XPS)
make_xps_factory()2020 static SkTScopedComPtr<IXpsOMObjectFactory> make_xps_factory() {
2021     IXpsOMObjectFactory* factory;
2022     HRN(CoCreateInstance(CLSID_XpsOMObjectFactory,
2023                          nullptr,
2024                          CLSCTX_INPROC_SERVER,
2025                          IID_PPV_ARGS(&factory)));
2026     return SkTScopedComPtr<IXpsOMObjectFactory>(factory);
2027 }
2028 
draw(const Src & src,SkBitmap *,SkWStream * dst,SkString *) const2029 Result XPSSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
2030     SkAutoCoInitialize com;
2031     if (!com.succeeded()) {
2032         return Result::Fatal("Could not initialize COM.");
2033     }
2034     SkTScopedComPtr<IXpsOMObjectFactory> factory = make_xps_factory();
2035     if (!factory) {
2036         return Result::Fatal("Failed to create XPS Factory.");
2037     }
2038     auto doc = SkXPS::MakeDocument(dst, factory.get());
2039     if (!doc) {
2040         return Result::Fatal("SkXPS::MakeDocument() returned nullptr");
2041     }
2042     return draw_skdocument(src, doc.get(), dst);
2043 }
2044 #else
draw(const Src & src,SkBitmap *,SkWStream * dst,SkString *) const2045 Result XPSSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
2046     return Result::Fatal("XPS not supported on this platform.");
2047 }
2048 #endif
2049 
serial_procs_using_png()2050 static SkSerialProcs serial_procs_using_png() {
2051     static SkSerialProcs procs;
2052     procs.fImageProc = [](SkImage* img, void*) -> sk_sp<SkData> {
2053         return SkPngEncoder::Encode(as_IB(img)->directContext(), img, SkPngEncoder::Options{});
2054     };
2055     return procs;
2056 }
2057 
2058 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
2059 
SKPSink()2060 SKPSink::SKPSink() {}
2061 
draw(const Src & src,SkBitmap *,SkWStream * dst,SkString *) const2062 Result SKPSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
2063     auto size = SkSize::Make(src.size());
2064     SkPictureRecorder recorder;
2065     Result result = src.draw(recorder.beginRecording(size.width(), size.height()),
2066                              /*GraphiteTestContext=*/nullptr);
2067     if (!result.isOk()) {
2068         return result;
2069     }
2070     SkSerialProcs procs = serial_procs_using_png();
2071     recorder.finishRecordingAsPicture()->serialize(dst, &procs);
2072     return Result::Ok();
2073 }
2074 
2075 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
2076 
draw(const Src & src,SkBitmap *,SkWStream * dst,SkString *) const2077 Result DebugSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
2078     DebugCanvas debugCanvas(src.size().width(), src.size().height());
2079     Result result = src.draw(&debugCanvas, /*GraphiteTestContext=*/nullptr);
2080     if (!result.isOk()) {
2081         return result;
2082     }
2083     std::unique_ptr<SkCanvas> nullCanvas = SkMakeNullCanvas();
2084     UrlDataManager dataManager(SkString("data"));
2085     SkJSONWriter writer(dst, SkJSONWriter::Mode::kPretty);
2086     writer.beginObject(); // root
2087     debugCanvas.toJSON(writer, dataManager, nullCanvas.get());
2088     writer.endObject(); // root
2089     writer.flush();
2090     return Result::Ok();
2091 }
2092 
2093 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
2094 
SVGSink(int pageIndex)2095 SVGSink::SVGSink(int pageIndex) : fPageIndex(pageIndex) {}
2096 
draw(const Src & src,SkBitmap *,SkWStream * dst,SkString *) const2097 Result SVGSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
2098 #if defined(SK_ENABLE_SVG)
2099     if (src.pageCount() > 1) {
2100         int pageCount = src.pageCount();
2101         if (fPageIndex > pageCount - 1) {
2102             return Result::Fatal("Page index %d too high for document with only %d pages.",
2103                                  fPageIndex, pageCount);
2104         }
2105     }
2106     return src.draw(fPageIndex,
2107                     SkSVGCanvas::Make(SkRect::MakeWH(SkIntToScalar(src.size().width()),
2108                                                      SkIntToScalar(src.size().height())),
2109                                       dst)
2110                             .get(),
2111                     /*GraphiteTestContext=*/nullptr);
2112 #else
2113     (void)fPageIndex;
2114     return Result::Fatal("SVG sink is disabled.");
2115 #endif // SK_ENABLE_SVG
2116 }
2117 
2118 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
2119 
RasterSink(SkColorType colorType)2120 RasterSink::RasterSink(SkColorType colorType)
2121     : fColorType(colorType) {}
2122 
draw(const Src & src,SkBitmap * dst,SkWStream *,SkString *) const2123 Result RasterSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString*) const {
2124     const SkISize size = src.size();
2125     if (size.isEmpty()) {
2126         return Result(Result::Status::Skip,
2127                       SkStringPrintf("Skipping empty source: %s", src.name().c_str()));
2128     }
2129 
2130     dst->allocPixelsFlags(SkImageInfo::Make(size, this->colorInfo()),
2131                           SkBitmap::kZeroPixels_AllocFlag);
2132 
2133     SkSurfaceProps props(/*flags=*/0, kRGB_H_SkPixelGeometry);
2134     auto surface = SkSurfaces::WrapPixels(dst->pixmap(), &props);
2135     return src.draw(surface->getCanvas(), /*GraphiteTestContext=*/nullptr);
2136 }
2137 
2138 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
2139 
2140 #if defined(SK_GRAPHITE)
2141 
GraphiteSink(const SkCommandLineConfigGraphite * config)2142 GraphiteSink::GraphiteSink(const SkCommandLineConfigGraphite* config)
2143         : fOptions(config->getOptions())
2144         , fContextType(config->getContextType())
2145         , fSurfaceType(config->getSurfaceType())
2146         , fColorType(config->getColorType())
2147         , fAlphaType(config->getAlphaType()) {}
2148 
draw(const Src & src,SkBitmap * dst,SkWStream * dstStream,SkString * log) const2149 Result GraphiteSink::draw(const Src& src,
2150                           SkBitmap* dst,
2151                           SkWStream* dstStream,
2152                           SkString* log) const {
2153     skiatest::graphite::TestOptions options = fOptions;
2154     // If we've copied context options from an external source we can't trust that the
2155     // priv pointer is still in scope, so assume it should be NULL and set our own up.
2156     SkASSERT(!options.fContextOptions.fOptionsPriv);
2157     skgpu::graphite::ContextOptionsPriv optionsPriv;
2158     options.fContextOptions.fOptionsPriv = &optionsPriv;
2159 
2160     src.modifyGraphiteContextOptions(&options.fContextOptions);
2161 
2162     skiatest::graphite::ContextFactory factory(options);
2163     skiatest::graphite::ContextInfo ctxInfo = factory.getContextInfo(fContextType);
2164     skgpu::graphite::Context* context = ctxInfo.fContext;
2165     if (!context) {
2166         return Result::Fatal("Could not create a context.");
2167     }
2168 
2169     std::unique_ptr<skgpu::graphite::Recorder> recorder =
2170                                 context->makeRecorder(ToolUtils::CreateTestingRecorderOptions());
2171     if (!recorder) {
2172         return Result::Fatal("Could not create a recorder.");
2173     }
2174 
2175     {
2176         sk_sp<SkSurface> surface = this->makeSurface(recorder.get(), src.size());
2177         if (!surface) {
2178             return Result::Fatal("Could not create a surface.");
2179         }
2180         dst->allocPixels(surface->imageInfo());
2181         Result result = src.draw(surface->getCanvas(), ctxInfo.fTestContext);
2182         if (!result.isOk()) {
2183             return result;
2184         }
2185 
2186         SkPixmap pm;
2187         if (!dst->peekPixels(&pm) ||
2188             !surface->readPixels(pm, 0, 0)) {
2189             return Result::Fatal("Could not readback from surface.");
2190         }
2191     }
2192 
2193     std::unique_ptr<skgpu::graphite::Recording> recording = recorder->snap();
2194     if (!recording) {
2195         return Result::Fatal("Could not create a recording.");
2196     }
2197 
2198     skgpu::graphite::InsertRecordingInfo info;
2199     info.fRecording = recording.get();
2200     if (!context->insertRecording(info)) {
2201         return Result::Fatal("Context::insertRecording failed.");
2202     }
2203     ctxInfo.fTestContext->syncedSubmit(context);
2204 
2205     return Result::Ok();
2206 }
2207 
makeSurface(skgpu::graphite::Recorder * recorder,SkISize dimensions) const2208 sk_sp<SkSurface> GraphiteSink::makeSurface(skgpu::graphite::Recorder* recorder,
2209                                            SkISize dimensions) const {
2210     SkSurfaceProps props(0, kRGB_H_SkPixelGeometry);
2211     auto ii = SkImageInfo::Make(dimensions, this->colorInfo());
2212     switch (fSurfaceType) {
2213         case SurfaceType::kDefault:
2214             return SkSurfaces::RenderTarget(recorder, ii, skgpu::Mipmapped::kNo, &props);
2215 
2216         case SurfaceType::kWrapTextureView:
2217             return sk_gpu_test::MakeBackendTextureViewSurface(recorder,
2218                                                               ii,
2219                                                               skgpu::Mipmapped::kNo,
2220                                                               skgpu::Protected::kNo,
2221                                                               &props);
2222     }
2223     SkUNREACHABLE;
2224 }
2225 
2226 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
2227 
2228 #if defined(SK_ENABLE_PRECOMPILE)
2229 
GraphitePrecompileTestingSink(const SkCommandLineConfigGraphite * config)2230 GraphitePrecompileTestingSink::GraphitePrecompileTestingSink(
2231         const SkCommandLineConfigGraphite* config) : GraphiteSink(config) {}
2232 
~GraphitePrecompileTestingSink()2233 GraphitePrecompileTestingSink::~GraphitePrecompileTestingSink() {}
2234 
drawSrc(const Src & src,skgpu::graphite::Context * context,skiatest::graphite::GraphiteTestContext * testContext) const2235 Result GraphitePrecompileTestingSink::drawSrc(
2236         const Src& src,
2237         skgpu::graphite::Context* context,
2238         skiatest::graphite::GraphiteTestContext* testContext) const {
2239     if (!fRecorder) {
2240         fRecorder = context->makeRecorder(ToolUtils::CreateTestingRecorderOptions());
2241         if (!fRecorder) {
2242             return Result::Fatal("Could not create a recorder.");
2243         }
2244     }
2245 
2246     sk_sp<SkSurface> surface = this->makeSurface(fRecorder.get(), src.size());
2247     if (!surface) {
2248         return Result::Fatal("Could not create a surface.");
2249     }
2250     Result result = src.draw(surface->getCanvas(), testContext);
2251     if (!result.isOk()) {
2252         return result;
2253     }
2254 
2255     std::unique_ptr<skgpu::graphite::Recording> recording = fRecorder->snap();
2256     if (!recording) {
2257         return Result::Fatal("Could not create a recording.");
2258     }
2259 
2260     skgpu::graphite::InsertRecordingInfo info;
2261     info.fRecording = recording.get();
2262     if (!context->insertRecording(info)) {
2263         return Result::Fatal("Context::insertRecording failed.");
2264     }
2265     if (!context->submit(skgpu::graphite::SyncToCpu::kYes)) {
2266         return Result::Fatal("Context::submit failed.");
2267     }
2268 
2269     return Result::Ok();
2270 }
2271 
resetAndRecreatePipelines(skgpu::graphite::Context * context) const2272 Result GraphitePrecompileTestingSink::resetAndRecreatePipelines(
2273         skgpu::graphite::Context* context) const {
2274     using namespace skgpu::graphite;
2275 
2276     SkASSERT(fRecorder);
2277 
2278     RuntimeEffectDictionary* rteDict = fRecorder->priv().runtimeEffectDictionary();
2279 
2280     std::vector<skgpu::UniqueKey> origKeys;
2281 
2282     UniqueKeyUtils::FetchUniqueKeys(context->priv().globalCache(), &origKeys);
2283 
2284     SkDEBUGCODE(int numBeforeReset = context->priv().globalCache()->numGraphicsPipelines();)
2285     SkASSERT(numBeforeReset == (int) origKeys.size());
2286 
2287     context->priv().globalCache()->resetGraphicsPipelines();
2288 
2289     SkASSERT(context->priv().globalCache()->numGraphicsPipelines() == 0);
2290 
2291     for (const skgpu::UniqueKey& k : origKeys) {
2292         // TODO: add a separate path that decomposes the keys into PaintOptions
2293         //  and uses them to Precompile
2294         GraphicsPipelineDesc pipelineDesc;
2295         RenderPassDesc renderPassDesc;
2296 
2297         if (!UniqueKeyUtils::ExtractKeyDescs(context, k, &pipelineDesc, &renderPassDesc)) {
2298             continue;
2299         }
2300 
2301         Precompile(context, rteDict, pipelineDesc, renderPassDesc);
2302     }
2303 
2304     SkDEBUGCODE(int postRecreate = context->priv().globalCache()->numGraphicsPipelines();)
2305 
2306     SkASSERT(numBeforeReset == postRecreate);
2307 
2308     {
2309         std::vector<skgpu::UniqueKey> recreatedKeys;
2310 
2311         UniqueKeyUtils::FetchUniqueKeys(context->priv().globalCache(), &recreatedKeys);
2312 
2313         for (const skgpu::UniqueKey& origKey : origKeys) {
2314             if(std::find(recreatedKeys.begin(), recreatedKeys.end(), origKey) ==
2315                          recreatedKeys.end()) {
2316                 sk_sp<GraphicsPipeline> pipeline =
2317                         context->priv().globalCache()->findGraphicsPipeline(origKey);
2318                 SkASSERT(!pipeline);
2319 
2320 #ifdef SK_DEBUG
2321                 const RendererProvider* rendererProvider = context->priv().rendererProvider();
2322                 const ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary();
2323 
2324                 {
2325                     GraphicsPipelineDesc originalPipelineDesc;
2326                     RenderPassDesc originalRenderPassDesc;
2327                     UniqueKeyUtils::ExtractKeyDescs(context, origKey,
2328                                                     &originalPipelineDesc,
2329                                                     &originalRenderPassDesc);
2330 
2331                     SkDebugf("------- Missing key from rebuilt keys:\n");
2332                     origKey.dump("original key:");
2333                     UniqueKeyUtils::DumpDescs(rendererProvider, dict,
2334                                               originalPipelineDesc,
2335                                               originalRenderPassDesc);
2336                 }
2337 
2338                 SkDebugf("Have %d recreated keys -----------------\n", (int) recreatedKeys.size());
2339                 int count = 0;
2340                 for (const skgpu::UniqueKey& recreatedKey : recreatedKeys) {
2341 
2342                     GraphicsPipelineDesc recreatedPipelineDesc;
2343                     RenderPassDesc recreatedRenderPassDesc;
2344                     UniqueKeyUtils::ExtractKeyDescs(context, recreatedKey,
2345                                                     &recreatedPipelineDesc,
2346                                                     &recreatedRenderPassDesc);
2347 
2348                     SkDebugf("%d ----\n", count++);
2349                     recreatedKey.dump("recreated key:");
2350                     UniqueKeyUtils::DumpDescs(rendererProvider, dict,
2351                                               recreatedPipelineDesc,
2352                                               recreatedRenderPassDesc);
2353                 }
2354 #endif
2355 
2356                 SK_ABORT("missing");
2357             }
2358         }
2359     }
2360 
2361     return Result::Ok();
2362 }
2363 
draw(const Src & src,SkBitmap * dst,SkWStream * dstStream,SkString * log) const2364 Result GraphitePrecompileTestingSink::draw(const Src& src,
2365                                            SkBitmap* dst,
2366                                            SkWStream* dstStream,
2367                                            SkString* log) const {
2368     skiatest::graphite::TestOptions options = fOptions;
2369     // If we've copied context options from an external source we can't trust that the
2370     // priv pointer is still in scope, so assume it should be NULL and set our own up.
2371     SkASSERT(!options.fContextOptions.fOptionsPriv);
2372     skgpu::graphite::ContextOptionsPriv optionsPriv;
2373     options.fContextOptions.fOptionsPriv = &optionsPriv;
2374 
2375     src.modifyGraphiteContextOptions(&options.fContextOptions);
2376 
2377     skiatest::graphite::ContextFactory factory(options);
2378     skiatest::graphite::ContextInfo ctxInfo = factory.getContextInfo(fContextType);
2379     skgpu::graphite::Context* context = ctxInfo.fContext;
2380     if (!context) {
2381         return Result::Fatal("Could not create a context.");
2382     }
2383 
2384     // First, clear out any miscellaneous Pipelines that might be cluttering up the global cache.
2385     context->priv().globalCache()->resetGraphicsPipelines();
2386 
2387     // Draw the Src for the first time, populating the global pipeline cache.
2388     Result result = this->drawSrc(src, context, ctxInfo.fTestContext);
2389     if (!result.isOk()) {
2390         fRecorder.reset();
2391         return result;
2392     }
2393 
2394     // Call resetAndRecreatePipelines to clear out all the Pipelines in the global cache and then
2395     // regenerate them using the Precompilation system.
2396     result = this->resetAndRecreatePipelines(context);
2397     if (!result.isOk()) {
2398         fRecorder.reset();
2399         return result;
2400     }
2401 
2402     // Draw the Src for the second time. This shouldn't create any new Pipelines since the ones
2403     // generated via Precompilation should be sufficient.
2404     result = this->drawSrc(src, context, ctxInfo.fTestContext);
2405     if (!result.isOk()) {
2406         fRecorder.reset();
2407         return result;
2408     }
2409 
2410     fRecorder.reset();
2411 
2412     // TODO: verify that no additional pipelines were created during the second 'drawSrc' call
2413     return Result::Ok();
2414 }
2415 #endif // SK_ENABLE_PRECOMPILE
2416 
2417 #endif // SK_GRAPHITE
2418 
2419 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
2420 
2421 // Handy for front-patching a Src.  Do whatever up-front work you need, then call draw_to_canvas(),
2422 // passing the Sink draw() arguments, a size, and a function draws into an SkCanvas.
2423 // Several examples below.
2424 
2425 using DrawToCanvasFn = std::function<DM::Result(SkCanvas*, Src::GraphiteTestContext*)>;
2426 
draw_to_canvas(Sink * sink,SkBitmap * bitmap,SkWStream * stream,SkString * log,SkISize size,const DrawToCanvasFn & draw)2427 static Result draw_to_canvas(Sink* sink, SkBitmap* bitmap, SkWStream* stream,
2428                              SkString* log, SkISize size, const DrawToCanvasFn& draw) {
2429     class ProxySrc : public Src {
2430     public:
2431         ProxySrc(SkISize size, const DrawToCanvasFn& draw) : fSize(size), fDraw(draw) {}
2432         Result draw(SkCanvas* canvas, GraphiteTestContext* testContext) const override {
2433             return fDraw(canvas, testContext);
2434         }
2435         Name    name() const override { return "ProxySrc"; }
2436         SkISize size() const override { return fSize; }
2437     private:
2438         SkISize               fSize;
2439         const DrawToCanvasFn& fDraw;
2440     };
2441     return sink->draw(ProxySrc(size, draw), bitmap, stream, log);
2442 }
2443 
2444 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
2445 
2446 static DEFINE_bool(check, true, "If true, have most Via- modes fail if they affect the output.");
2447 
2448 // Is *bitmap identical to what you get drawing src into sink?
check_against_reference(const SkBitmap * bitmap,const Src & src,Sink * sink)2449 static Result check_against_reference(const SkBitmap* bitmap, const Src& src, Sink* sink) {
2450     // We can only check raster outputs.
2451     // (Non-raster outputs like .pdf, .skp, .svg may differ but still draw identically.)
2452     if (FLAGS_check && bitmap) {
2453         SkBitmap reference;
2454         SkString log;
2455         SkDynamicMemoryWStream wStream;
2456         Result result = sink->draw(src, &reference, &wStream, &log);
2457         // If we can draw into this Sink via some pipeline, we should be able to draw directly.
2458         SkASSERT(result.isOk());
2459         if (!result.isOk()) {
2460             return result;
2461         }
2462         return compare_bitmaps(reference, *bitmap);
2463     }
2464     return Result::Ok();
2465 }
2466 
2467 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
2468 
auto_compute_translate(SkMatrix * matrix,int srcW,int srcH)2469 static SkISize auto_compute_translate(SkMatrix* matrix, int srcW, int srcH) {
2470     SkRect bounds = SkRect::MakeIWH(srcW, srcH);
2471     matrix->mapRect(&bounds);
2472     matrix->postTranslate(-bounds.x(), -bounds.y());
2473     return {SkScalarRoundToInt(bounds.width()), SkScalarRoundToInt(bounds.height())};
2474 }
2475 
ViaMatrix(SkMatrix matrix,Sink * sink)2476 ViaMatrix::ViaMatrix(SkMatrix matrix, Sink* sink) : Via(sink), fMatrix(matrix) {}
2477 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const2478 Result ViaMatrix::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
2479     SkMatrix matrix = fMatrix;
2480     SkISize size = auto_compute_translate(&matrix, src.size().width(), src.size().height());
2481     return draw_to_canvas(fSink.get(), bitmap, stream, log, size,
2482                           [&](SkCanvas* canvas,
2483                               Src::GraphiteTestContext* testContext) {
2484                               canvas->concat(matrix);
2485                               return src.draw(canvas, testContext);
2486                           });
2487 }
2488 
2489 // Undoes any flip or 90 degree rotate without changing the scale of the bitmap.
2490 // This should be pixel-preserving.
ViaUpright(SkMatrix matrix,Sink * sink)2491 ViaUpright::ViaUpright(SkMatrix matrix, Sink* sink) : Via(sink), fMatrix(matrix) {}
2492 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const2493 Result ViaUpright::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
2494     Result result = fSink->draw(src, bitmap, stream, log);
2495     if (!result.isOk()) {
2496         return result;
2497     }
2498 
2499     SkMatrix inverse;
2500     if (!fMatrix.rectStaysRect() || !fMatrix.invert(&inverse)) {
2501         return Result::Fatal("Cannot upright --matrix.");
2502     }
2503     SkMatrix upright = SkMatrix::I();
2504     upright.setScaleX(SkScalarSignAsScalar(inverse.getScaleX()));
2505     upright.setScaleY(SkScalarSignAsScalar(inverse.getScaleY()));
2506     upright.setSkewX(SkScalarSignAsScalar(inverse.getSkewX()));
2507     upright.setSkewY(SkScalarSignAsScalar(inverse.getSkewY()));
2508 
2509     SkBitmap uprighted;
2510     SkISize size = auto_compute_translate(&upright, bitmap->width(), bitmap->height());
2511     uprighted.allocPixels(bitmap->info().makeDimensions(size));
2512 
2513     SkCanvas canvas(uprighted);
2514     canvas.concat(upright);
2515     SkPaint paint;
2516     paint.setBlendMode(SkBlendMode::kSrc);
2517     canvas.drawImage(bitmap->asImage(), 0, 0, SkSamplingOptions(), &paint);
2518 
2519     *bitmap = uprighted;
2520     return Result::Ok();
2521 }
2522 
2523 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
2524 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const2525 Result ViaSerialization::draw(
2526         const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
2527     // Record our Src into a picture.
2528     auto size = src.size();
2529     SkPictureRecorder recorder;
2530     Result result = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
2531                                                      SkIntToScalar(size.height())),
2532                              /*GraphiteTestContext=*/nullptr);
2533     if (!result.isOk()) {
2534         return result;
2535     }
2536     sk_sp<SkPicture> pic(recorder.finishRecordingAsPicture());
2537 
2538     SkSerialProcs procs = serial_procs_using_png();
2539     // Serialize it and then deserialize it.
2540     sk_sp<SkPicture> deserialized = SkPicture::MakeFromData(pic->serialize(&procs).get());
2541 
2542     result = draw_to_canvas(fSink.get(), bitmap, stream, log, size,
2543                             [&](SkCanvas* canvas, Src::GraphiteTestContext*) {
2544                                 canvas->drawPicture(deserialized);
2545                                 return Result::Ok();
2546                             });
2547     if (!result.isOk()) {
2548         return result;
2549     }
2550 
2551     return check_against_reference(bitmap, src, fSink.get());
2552 }
2553 
2554 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
2555 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const2556 Result ViaPicture::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
2557     auto size = src.size();
2558     Result result = draw_to_canvas(fSink.get(), bitmap, stream, log, size,
2559                                    [&](SkCanvas* canvas, Src::GraphiteTestContext* testContext) {
2560         SkPictureRecorder recorder;
2561         sk_sp<SkPicture> pic;
2562         Result result = src.draw(recorder.beginRecording(SkIntToScalar(size.width()),
2563                                                          SkIntToScalar(size.height())),
2564                                  testContext);
2565         if (!result.isOk()) {
2566             return result;
2567         }
2568         pic = recorder.finishRecordingAsPicture();
2569         canvas->drawPicture(pic);
2570         return result;
2571     });
2572     if (!result.isOk()) {
2573         return result;
2574     }
2575 
2576     return check_against_reference(bitmap, src, fSink.get());
2577 }
2578 
2579 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
2580 
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const2581 Result ViaRuntimeBlend::draw(const Src& src,
2582                              SkBitmap* bitmap,
2583                              SkWStream* stream,
2584                              SkString* log) const {
2585     class RuntimeBlendFilterCanvas : public SkPaintFilterCanvas {
2586     public:
2587         RuntimeBlendFilterCanvas(SkCanvas* canvas) : INHERITED(canvas) { }
2588 
2589     protected:
2590         bool onFilter(SkPaint& paint) const override {
2591             if (std::optional<SkBlendMode> mode = paint.asBlendMode()) {
2592                 paint.setBlender(GetRuntimeBlendForBlendMode(*mode));
2593             }
2594             return true;
2595         }
2596 
2597     private:
2598         using INHERITED = SkPaintFilterCanvas;
2599     };
2600 
2601     return draw_to_canvas(fSink.get(), bitmap, stream, log, src.size(),
2602                           [&](SkCanvas* canvas, Src::GraphiteTestContext* testContext) {
2603         RuntimeBlendFilterCanvas runtimeBlendCanvas{canvas};
2604         return src.draw(&runtimeBlendCanvas, testContext);
2605     });
2606 }
2607 
2608 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
2609 
2610 #ifdef TEST_VIA_SVG
draw(const Src & src,SkBitmap * bitmap,SkWStream * stream,SkString * log) const2611 Result ViaSVG::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const {
2612     auto size = src.size();
2613     return draw_to_canvas(fSink.get(), bitmap, stream, log, size,
2614                           [&](SkCanvas* canvas, Src::GraphiteTestContext* testContext) -> Result {
2615         SkDynamicMemoryWStream wstream;
2616         SkXMLStreamWriter writer(&wstream);
2617         Result result = src.draw(SkSVGCanvas::Make(SkRect::Make(size), &writer).get(),
2618                                  testContext);
2619         if (!result.isOk()) {
2620             return result;
2621         }
2622 
2623         auto shapingFactory = SkShapers::BestAvailable();
2624         auto fontMgr = ToolUtils::TestFontMgr();
2625         // When rendering our SVGs we want to be sure we are using shaping.
2626         // If we fail to make a shaper, then it can mean something like skunicode is misconfigured.
2627         SkASSERT(shapingFactory->makeShaper(fontMgr));
2628 
2629         std::unique_ptr<SkStream> rstream(wstream.detachAsStream());
2630         sk_sp<SkSVGDOM> dom = SkSVGDOM::Builder()
2631                                       .setFontManager(std::move(fontMgr))
2632                                       .setTextShapingFactory(std::move(shapingFactory))
2633                                       .make(*rstream);
2634         if (dom) {
2635             dom->setContainerSize(SkSize::Make(size));
2636             dom->render(canvas);
2637         }
2638         return Result::Ok();
2639     });
2640 }
2641 #endif
2642 
2643 }  // namespace DM
2644