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