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