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