• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef DMSrcSink_DEFINED
9 #define DMSrcSink_DEFINED
10 
11 #include "gm/gm.h"
12 #include "include/core/SkBitmap.h"
13 #include "include/core/SkCanvas.h"
14 #include "include/core/SkPicture.h"
15 #include "include/docs/SkMultiPictureDocument.h"
16 #include "include/gpu/graphite/PrecompileContext.h"
17 #include "tools/flags/CommonFlagsConfig.h"
18 #include "tools/gpu/MemoryCache.h"
19 
20 #include <functional>
21 
22 #if !defined (SK_DISABLE_LEGACY_TESTS)
23     #include "include/gpu/graphite/ContextOptions.h"
24     #include "tools/graphite/TestOptions.h"
25 #endif
26 
27 //#define TEST_VIA_SVG
28 
29 namespace skgpu {
30 class UniqueKey;
31 }
32 namespace skiagm::verifiers {
33 class VerifierList;
34 }
35 namespace skiatools::graphite {
36     class PipelineCallBackHandler;
37 }
38 namespace DM {
39 
40 // This is just convenience.  It lets you use either return "foo" or return SkStringPrintf(...).
41 struct ImplicitString : public SkString {
42     template <typename T>
ImplicitStringImplicitString43     ImplicitString(const T& s) : SkString(s) {}
ImplicitStringImplicitString44     ImplicitString() : SkString("") {}
45 };
46 typedef ImplicitString Name;
47 typedef ImplicitString Path;
48 
49 class Result {
50 public:
51     enum class Status : int { Ok, Fatal, Skip };
52 
Result(Status status,SkString msg)53     Result(Status status, SkString msg) : fMsg(std::move(msg)), fStatus(status) {}
54 
55     Result(const Result&)            = default;
56     Result& operator=(const Result&) = default;
57 
Ok()58     static Result Ok() { return Result{Status::Ok, {}}; }
59 
Fatal(const char * fmt,...)60     static Result Fatal(const char* fmt, ...) SK_PRINTF_LIKE(1, 2) {
61         SkString msg;
62         va_list args;
63         va_start(args, fmt);
64         msg.printVAList(fmt, args);
65         va_end(args);
66 
67         return Result{Status::Fatal, std::move(msg)};
68     }
69 
Skip(const char * fmt,...)70     static Result Skip(const char* fmt, ...) SK_PRINTF_LIKE(1, 2) {
71         SkString msg;
72         va_list args;
73         va_start(args, fmt);
74         msg.printVAList(fmt, args);
75         va_end(args);
76 
77         return Result{Status::Skip, std::move(msg)};
78     }
79 
isOk()80     bool isOk() { return fStatus == Status::Ok; }
isFatal()81     bool isFatal() { return fStatus == Status::Fatal; }
isSkip()82     bool isSkip() { return fStatus == Status::Skip; }
83 
c_str()84     const char* c_str() const { return fMsg.c_str(); }
status()85     Status status() const { return fStatus; }
86 
87 private:
88     SkString fMsg;
89     Status   fStatus;
90 };
91 
92 struct SinkFlags {
93     enum Type { kNull, kGPU, kVector, kRaster } type;
94     enum Approach { kDirect, kIndirect } approach;
95     enum Multisampled { kNotMultisampled, kMultisampled } multisampled;
96     SinkFlags(Type t, Approach a, Multisampled ms = kNotMultisampled)
typeSinkFlags97             : type(t), approach(a), multisampled(ms) {}
98 };
99 
100 struct Src {
101     using GraphiteTestContext = skiatest::graphite::GraphiteTestContext;
102 
~SrcSrc103     virtual ~Src() {}
104     [[nodiscard]] virtual Result draw(SkCanvas* canvas, GraphiteTestContext*) const = 0;
105     virtual SkISize size() const = 0;
106     virtual Name name() const = 0;
modifyGrContextOptionsSrc107     virtual void modifyGrContextOptions(GrContextOptions*) const  {}
modifyGraphiteContextOptionsSrc108     virtual void modifyGraphiteContextOptions(skgpu::graphite::ContextOptions*) const {}
vetoSrc109     virtual bool veto(SinkFlags) const { return false; }
110 
pageCountSrc111     virtual int pageCount() const { return 1; }
drawSrc112     [[nodiscard]] virtual Result draw([[maybe_unused]] int page,
113                                       SkCanvas* canvas,
114                                       GraphiteTestContext* graphiteTestContext) const {
115         return this->draw(canvas, graphiteTestContext);
116     }
sizeSrc117     virtual SkISize size([[maybe_unused]] int page) const { return this->size(); }
118     // Force Tasks using this Src to run on the main thread?
serialSrc119     virtual bool serial() const { return false; }
120 };
121 
122 struct Sink {
~SinkSink123     virtual ~Sink() {}
124     // You may write to either the bitmap or stream.  If you write to log, we'll print that out.
125     [[nodiscard]] virtual Result draw(const Src&, SkBitmap*, SkWStream*, SkString* log) const = 0;
126 
127     // Override the color space of this Sink, after creation
setColorSpaceSink128     virtual void setColorSpace(sk_sp<SkColorSpace>) {}
129 
130     // Force Tasks using this Sink to run on the main thread?
serialSink131     virtual bool serial() const { return false; }
132 
133     // File extension for the content draw() outputs, e.g. "png", "pdf".
134     virtual const char* fileExtension() const  = 0;
135 
136     virtual SinkFlags flags() const = 0;
137 
138     /** Returns the color type and space used by the sink. */
colorInfoSink139     virtual SkColorInfo colorInfo() const { return SkColorInfo(); }
140 };
141 
142 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
143 
144 class GMSrc : public Src {
145 public:
146     explicit GMSrc(skiagm::GMFactory);
147 
148     Result draw(SkCanvas*, GraphiteTestContext*) const override;
149     SkISize size() const override;
150     Name name() const override;
151     void modifyGrContextOptions(GrContextOptions* options) const override;
152 #if defined(SK_GRAPHITE)
153     void modifyGraphiteContextOptions(skgpu::graphite::ContextOptions*) const override;
154 #endif
155 
156 private:
157     skiagm::GMFactory fFactory;
158 };
159 
160 class CodecSrc : public Src {
161 public:
162     enum Mode {
163         kCodec_Mode,
164         // We choose to test only one mode with zero initialized memory.
165         // This will exercise all of the interesting cases in SkSwizzler
166         // without doubling the size of our test suite.
167         kCodecZeroInit_Mode,
168         kScanline_Mode,
169         kStripe_Mode, // Tests the skipping of scanlines
170         kCroppedScanline_Mode, // Tests (jpeg) cropped scanline optimization
171         kSubset_Mode, // For codecs that support subsets directly.
172         kAnimated_Mode, // For codecs that support animation.
173     };
174     enum DstColorType {
175         kGetFromCanvas_DstColorType,
176         kGrayscale_Always_DstColorType,
177         kNonNative8888_Always_DstColorType,
178     };
179     CodecSrc(Path, Mode, DstColorType, SkAlphaType, float);
180 
181     Result draw(SkCanvas*, GraphiteTestContext*) const override;
182     SkISize size() const override;
183     Name name() const override;
veto(SinkFlags)184     bool veto(SinkFlags) const override;
185     bool serial() const override { return fRunSerially; }
186 private:
187     Path                    fPath;
188     Mode                    fMode;
189     DstColorType            fDstColorType;
190     SkAlphaType             fDstAlphaType;
191     float                   fScale;
192     bool                    fRunSerially;
193 };
194 
195 class AndroidCodecSrc : public Src {
196 public:
197     AndroidCodecSrc(Path, CodecSrc::DstColorType, SkAlphaType, int sampleSize);
198 
199     Result draw(SkCanvas*, GraphiteTestContext*) const override;
200     SkISize size() const override;
201     Name name() const override;
veto(SinkFlags)202     bool veto(SinkFlags) const override;
203     bool serial() const override { return fRunSerially; }
204 private:
205     Path                    fPath;
206     CodecSrc::DstColorType  fDstColorType;
207     SkAlphaType             fDstAlphaType;
208     int                     fSampleSize;
209     bool                    fRunSerially;
210 };
211 
212 #ifdef SK_ENABLE_ANDROID_UTILS
213 // Allows for testing of various implementations of Android's BitmapRegionDecoder
214 class BRDSrc : public Src {
215 public:
216     enum Mode {
217         // Decode the entire image as one region.
218         kFullImage_Mode,
219         // Splits the image into multiple regions using a divisor and decodes the regions
220         // separately.  Also, this test adds a border of a few pixels to each of the regions
221         // that it is decoding.  This tests the behavior when a client asks for a region that
222         // does not fully fit in the image.
223         kDivisor_Mode,
224     };
225 
226     BRDSrc(Path, Mode, CodecSrc::DstColorType, uint32_t);
227 
228     Result draw(SkCanvas*, GraphiteTestContext*) const override;
229     SkISize size() const override;
230     Name name() const override;
231     bool veto(SinkFlags) const override;
232 private:
233     Path                                     fPath;
234     Mode                                     fMode;
235     CodecSrc::DstColorType                   fDstColorType;
236     uint32_t                                 fSampleSize;
237 };
238 #endif
239 
240 class ImageGenSrc : public Src {
241 public:
242     enum Mode {
243         kCodec_Mode,    // Use CodecImageGenerator
244         kPlatform_Mode, // Uses CG or WIC
245     };
246     ImageGenSrc(Path, Mode, SkAlphaType, bool);
247 
248     Result draw(SkCanvas*, GraphiteTestContext*) const override;
249     SkISize size() const override;
250     Name name() const override;
veto(SinkFlags)251     bool veto(SinkFlags) const override;
252     bool serial() const override { return fRunSerially; }
253 private:
254     Path        fPath;
255     Mode        fMode;
256     SkAlphaType fDstAlphaType;
257     bool        fIsGpu;
258     bool        fRunSerially;
259 };
260 
261 class ColorCodecSrc : public Src {
262 public:
263     ColorCodecSrc(Path, bool decode_to_dst);
264 
265     Result draw(SkCanvas*, GraphiteTestContext*) const override;
266     SkISize size() const override;
267     Name name() const override;
268     bool veto(SinkFlags) const override;
269 private:
270     Path fPath;
271     bool fDecodeToDst;
272 };
273 
274 class SKPSrc : public Src {
275 public:
276     explicit SKPSrc(Path path);
277 
278     Result draw(SkCanvas*, GraphiteTestContext*) const override;
279     SkISize size() const override;
280     Name name() const override;
281 private:
282     Path fPath;
283 };
284 
285 // This class extracts all the paths from an SKP and then removes unwanted paths according to the
286 // provided l/r trail. It then just draws the remaining paths. (Non-path draws are thrown out.) It
287 // is useful for finding a reduced repo case for path drawing bugs.
288 class BisectSrc : public SKPSrc {
289 public:
290     explicit BisectSrc(Path path, const char* trail);
291 
292     Result draw(SkCanvas*, GraphiteTestContext*) const override;
293 
294 private:
295     SkString fTrail;
296 
297     using INHERITED = SKPSrc;
298 };
299 
300 #if defined(SK_ENABLE_SKOTTIE)
301 class SkottieSrc final : public Src {
302 public:
303     explicit SkottieSrc(Path path);
304 
305     Result draw(SkCanvas*, GraphiteTestContext*) const override;
306     SkISize size() const override;
307     Name name() const override;
308     bool veto(SinkFlags) const override;
309 
310 private:
311     // Generates a kTileCount x kTileCount filmstrip with evenly distributed frames.
312     inline static constexpr int      kTileCount = 5;
313 
314     // Fit kTileCount x kTileCount frames to a 1000x1000 film strip.
315     inline static constexpr SkScalar kTargetSize = 1000;
316     inline static constexpr SkScalar kTileSize = kTargetSize / kTileCount;
317 
318     Path                      fPath;
319 };
320 #endif
321 
322 #if defined(SK_ENABLE_SVG)
323 } // namespace DM
324 
325 class SkSVGDOM;
326 
327 namespace DM {
328 
329 class SVGSrc : public Src {
330 public:
331     explicit SVGSrc(Path path);
332 
333     Result draw(SkCanvas*, GraphiteTestContext*) const override;
334     SkISize size() const override;
335     Name name() const override;
336     bool veto(SinkFlags) const override;
337 
338 private:
339     Name            fName;
340     sk_sp<SkSVGDOM> fDom;
341     SkScalar        fScale;
342 
343     using INHERITED = Src;
344 };
345 #endif // SK_ENABLE_SVG
346 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
347 
348 class MSKPSrc : public Src {
349 public:
350     explicit MSKPSrc(Path path);
351 
352     int pageCount() const override;
353     Result draw(SkCanvas* c, GraphiteTestContext*) const override;
354     Result draw(int, SkCanvas*, GraphiteTestContext*) const override;
355     SkISize size() const override;
356     SkISize size(int) const override;
357     Name name() const override;
358 
359 private:
360     Path fPath;
361     mutable skia_private::TArray<SkDocumentPage> fPages;
362 };
363 
364 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
365 
366 class NullSink : public Sink {
367 public:
NullSink()368     NullSink() {}
369 
370     Result draw(const Src& src, SkBitmap*, SkWStream*, SkString*) const override;
fileExtension()371     const char* fileExtension() const override { return ""; }
flags()372     SinkFlags flags() const override { return SinkFlags{ SinkFlags::kNull, SinkFlags::kDirect }; }
373 };
374 
375 class GPUSink : public Sink {
376 public:
377     GPUSink(const SkCommandLineConfigGpu*, const GrContextOptions&);
378 
379     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
380     Result onDraw(const Src&, SkBitmap*, SkWStream*, SkString*,
381                   const GrContextOptions& baseOptions,
382                   std::function<void(GrDirectContext*)> initContext = nullptr,
383                   std::function<SkCanvas*(SkCanvas*)> wrapCanvas = nullptr) const;
384 
contextType()385     skgpu::ContextType contextType() const { return fContextType; }
contextOverrides()386     const sk_gpu_test::GrContextFactory::ContextOverrides& contextOverrides() const {
387         return fContextOverrides;
388     }
surfType()389     SkCommandLineConfigGpu::SurfType surfType() const { return fSurfType; }
serial()390     bool serial() const override { return true; }
fileExtension()391     const char* fileExtension() const override { return "png"; }
flags()392     SinkFlags flags() const override {
393         SinkFlags::Multisampled ms = fSampleCount > 1 ? SinkFlags::kMultisampled
394                                                       : SinkFlags::kNotMultisampled;
395         return SinkFlags{ SinkFlags::kGPU, SinkFlags::kDirect, ms };
396     }
baseContextOptions()397     const GrContextOptions& baseContextOptions() const { return fBaseContextOptions; }
setColorSpace(sk_sp<SkColorSpace> colorSpace)398     void setColorSpace(sk_sp<SkColorSpace> colorSpace) override { fColorSpace = colorSpace; }
colorInfo()399     SkColorInfo colorInfo() const override {
400         return SkColorInfo(fColorType, fAlphaType, fColorSpace);
401     }
402 
403 protected:
404     sk_sp<SkSurface> createDstSurface(GrDirectContext*, SkISize size) const;
405     bool readBack(SkSurface*, SkBitmap* dst) const;
406 
407 private:
408     skgpu::ContextType                                fContextType;
409     sk_gpu_test::GrContextFactory::ContextOverrides   fContextOverrides;
410     SkCommandLineConfigGpu::SurfType                  fSurfType;
411     int                                               fSampleCount;
412     uint32_t                                          fSurfaceFlags;
413     SkColorType                                       fColorType;
414     SkAlphaType                                       fAlphaType;
415     sk_sp<SkColorSpace>                               fColorSpace;
416     GrContextOptions                                  fBaseContextOptions;
417     sk_gpu_test::MemoryCache                          fMemoryCache;
418 };
419 
420 // Wrap a gpu canvas in one that routes all text draws through Slugs.
421 // Note that text blobs that have an RSXForm aren't converted.
422 class GPUSlugSink : public GPUSink {
423 public:
424     GPUSlugSink(const SkCommandLineConfigGpu*, const GrContextOptions&);
425 
426     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
427 };
428 
429 class GPUSerializeSlugSink : public GPUSink {
430 public:
431     GPUSerializeSlugSink(const SkCommandLineConfigGpu*, const GrContextOptions&);
432 
433     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
434 };
435 
436 class GPURemoteSlugSink : public GPUSink {
437 public:
438     GPURemoteSlugSink(const SkCommandLineConfigGpu*, const GrContextOptions&);
439 
440     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
441 };
442 
443 class GPUPersistentCacheTestingSink : public GPUSink {
444 public:
445     GPUPersistentCacheTestingSink(const SkCommandLineConfigGpu*, const GrContextOptions&);
446 
447     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
448 
fileExtension()449     const char* fileExtension() const override {
450         // Suppress writing out results from this config - we just want to do our matching test
451         return nullptr;
452     }
453 
454 private:
455     int fCacheType;
456 
457     using INHERITED = GPUSink;
458 };
459 
460 class GaneshPrecompileTestingSink : public GPUSink {
461 public:
462     GaneshPrecompileTestingSink(const SkCommandLineConfigGpu*, const GrContextOptions&);
463 
464     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
465 
fileExtension()466     const char* fileExtension() const override {
467         // Suppress writing out results from this config - we just want to do our matching test
468         return nullptr;
469     }
470 
471 private:
472     using INHERITED = GPUSink;
473 };
474 
475 // This sink attempts to better simulate the Chrome DDL use-case. It:
476 //    creates the DDLs on separate recording threads
477 //    performs all the GPU work on a separate GPU thread
478 // In the future this should be expanded to:
479 //    upload on a utility thread w/ access to a shared context
480 //    compile the programs on the utility thread
481 //    perform fine grained scheduling of gpu tasks based on their image and program prerequisites
482 //    create a single "compositing" DDL that is replayed last
483 class GPUDDLSink : public GPUSink {
484 public:
485     GPUDDLSink(const SkCommandLineConfigGpu*, const GrContextOptions&);
486 
487     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
488 
489 private:
490     Result ddlDraw(const Src&,
491                    sk_sp<SkSurface> dstSurface,
492                    SkTaskGroup* recordingTaskGroup,
493                    SkTaskGroup* gpuTaskGroup,
494                    sk_gpu_test::TestContext* gpuTestCtx,
495                    GrDirectContext* gpuThreadCtx) const;
496 
497     std::unique_ptr<SkExecutor> fRecordingExecutor;
498     std::unique_ptr<SkExecutor> fGPUExecutor;
499 
500     using INHERITED = GPUSink;
501 };
502 
503 class PDFSink : public Sink {
504 public:
PDFSink(bool pdfa,SkScalar rasterDpi)505     PDFSink(bool pdfa, SkScalar rasterDpi) : fPDFA(pdfa), fRasterDpi(rasterDpi) {}
506     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
fileExtension()507     const char* fileExtension() const override { return "pdf"; }
flags()508     SinkFlags flags() const override { return SinkFlags{ SinkFlags::kVector, SinkFlags::kDirect }; }
509 
510     bool fPDFA;
511     SkScalar fRasterDpi;
512 };
513 
514 class XPSSink : public Sink {
515 public:
516     XPSSink();
517 
518     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
fileExtension()519     const char* fileExtension() const override { return "xps"; }
flags()520     SinkFlags flags() const override { return SinkFlags{ SinkFlags::kVector, SinkFlags::kDirect }; }
521 };
522 
523 class RasterSink : public Sink {
524 public:
525     explicit RasterSink(SkColorType);
526 
527     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
fileExtension()528     const char* fileExtension() const override { return "png"; }
flags()529     SinkFlags flags() const override { return SinkFlags{ SinkFlags::kRaster, SinkFlags::kDirect }; }
setColorSpace(sk_sp<SkColorSpace> colorSpace)530     void setColorSpace(sk_sp<SkColorSpace> colorSpace) override { fColorSpace = colorSpace; }
531 
colorInfo()532     SkColorInfo colorInfo() const override {
533         // If there's an appropriate alpha type for this color type, use it, otherwise use premul.
534         SkAlphaType alphaType = kPremul_SkAlphaType;
535         (void)SkColorTypeValidateAlphaType(fColorType, alphaType, &alphaType);
536 
537         return SkColorInfo(fColorType, alphaType, fColorSpace);
538     }
539 
540 private:
541     SkColorType         fColorType;
542     sk_sp<SkColorSpace> fColorSpace;
543 };
544 
545 class SKPSink : public Sink {
546 public:
547     SKPSink();
548 
549     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
fileExtension()550     const char* fileExtension() const override { return "skp"; }
flags()551     SinkFlags flags() const override { return SinkFlags{ SinkFlags::kVector, SinkFlags::kDirect }; }
552 };
553 
554 class DebugSink : public Sink {
555 public:
556     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
fileExtension()557     const char* fileExtension() const override { return "json"; }
flags()558     SinkFlags flags() const override { return SinkFlags{ SinkFlags::kVector, SinkFlags::kDirect }; }
559 };
560 
561 class SVGSink : public Sink {
562 public:
563     SVGSink(int pageIndex = 0);
564 
565     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
fileExtension()566     const char* fileExtension() const override { return "svg"; }
flags()567     SinkFlags flags() const override { return SinkFlags{ SinkFlags::kVector, SinkFlags::kDirect }; }
568 
569 private:
570     int fPageIndex;
571 };
572 
573 #if defined(SK_GRAPHITE)
574 
575 class GraphiteSink : public Sink {
576 public:
577     GraphiteSink(const SkCommandLineConfigGraphite*, const skiatest::graphite::TestOptions&);
578 
579     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
serial()580     bool serial() const override { return true; }
fileExtension()581     const char* fileExtension() const override { return "png"; }
flags()582     SinkFlags flags() const override { return SinkFlags{SinkFlags::kGPU, SinkFlags::kDirect}; }
setColorSpace(sk_sp<SkColorSpace> colorSpace)583     void setColorSpace(sk_sp<SkColorSpace> colorSpace) override { fColorSpace = colorSpace; }
colorInfo()584     SkColorInfo colorInfo() const override {
585         return SkColorInfo(fColorType, fAlphaType, fColorSpace);
586     }
587 
588 protected:
589     sk_sp<SkSurface> makeSurface(skgpu::graphite::Recorder*, SkISize) const;
590 
591     skiatest::graphite::TestOptions fOptions;
592     skgpu::ContextType fContextType;
593     SkColorType fColorType;
594     SkAlphaType fAlphaType;
595     sk_sp<SkColorSpace> fColorSpace;
596 };
597 
598 #if defined(SK_ENABLE_PRECOMPILE)
599 // In general this sink:
600 //   renders a gm, skp or svg (in drawSrc)
601 //   collects all the UniqueKeys                  |
602 //   clears the pipeline cache                    | (in resetAndRecreatePipelines)
603 //   recreates the pipelines from the UniqueKeys  |
604 //   renders a second time (in drawSrc)
605 //   asserts that no new pipelines were created
606 class GraphitePrecompileTestingSink : public GraphiteSink {
607 public:
608     GraphitePrecompileTestingSink(const SkCommandLineConfigGraphite*,
609                                   const skiatest::graphite::TestOptions&);
610     ~GraphitePrecompileTestingSink() override;
611 
612     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
613 
fileExtension()614     const char* fileExtension() const override {
615         // Suppress writing out results from this config - we just want to check that
616         // the precompilation API is expressive enough and prepopulates the cache.
617         // If desired, this could be updated to save the result of the precompiled rendering.
618         // However; if all the keys match, as is expected, the images should always match.
619         return nullptr;
620     }
621 
622 private:
623 
624     Result drawSrc(const Src&,
625                    skgpu::graphite::Context*,
626                    skiatest::graphite::GraphiteTestContext*,
627                    skgpu::graphite::Recorder*) const;
628     Result resetAndRecreatePipelines(skiatools::graphite::PipelineCallBackHandler*,
629                                      skgpu::graphite::PrecompileContext*) const;
630 
631 #ifdef SK_DEBUG
632     static void LogMissingKey(skgpu::graphite::PrecompileContext*,
633                               const skgpu::UniqueKey& missingKey,
634                               const char* missingKeyName,
635                               const std::vector<skgpu::UniqueKey>& pool,
636                               const char* poolName);
637 #endif
638 
639     static void CompareKeys(skgpu::graphite::PrecompileContext*,
640                             const std::vector<skgpu::UniqueKey>& vA, const char* aName,
641                             const std::vector<skgpu::UniqueKey>& vB, const char* bName);
642 };
643 #endif // SK_ENABLE_PRECOMPILE
644 #endif // SK_GRAPHITE
645 
646 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
647 
648 class Via : public Sink {
649 public:
Via(Sink * sink)650     explicit Via(Sink* sink) : fSink(sink) {}
fileExtension()651     const char* fileExtension() const override { return fSink->fileExtension(); }
serial()652     bool               serial() const override { return fSink->serial(); }
flags()653     SinkFlags flags() const override {
654         SinkFlags flags = fSink->flags();
655         flags.approach = SinkFlags::kIndirect;
656         return flags;
657     }
setColorSpace(sk_sp<SkColorSpace> colorSpace)658     void setColorSpace(sk_sp<SkColorSpace> colorSpace) override {
659         fSink->setColorSpace(colorSpace);
660     }
661 protected:
662     std::unique_ptr<Sink> fSink;
663 };
664 
665 class ViaMatrix : public Via {
666 public:
667     ViaMatrix(SkMatrix, Sink*);
668     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
669 
670 private:
671     const SkMatrix fMatrix;
672 };
673 
674 class ViaUpright : public Via {
675 public:
676     ViaUpright(SkMatrix, Sink*);
677     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
678 
679 private:
680     const SkMatrix fMatrix;
681 };
682 
683 class ViaSerialization : public Via {
684 public:
ViaSerialization(Sink * sink)685     explicit ViaSerialization(Sink* sink) : Via(sink) {}
686     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
687 };
688 
689 class ViaPicture : public Via {
690 public:
ViaPicture(Sink * sink)691     explicit ViaPicture(Sink* sink) : Via(sink) {}
692     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
693 };
694 
695 class ViaRuntimeBlend : public Via {
696 public:
ViaRuntimeBlend(Sink * sink)697     explicit ViaRuntimeBlend(Sink* sink) : Via(sink) {}
698     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
699 };
700 
701 class ViaSVG : public Via {
702 public:
ViaSVG(Sink * sink)703     explicit ViaSVG(Sink* sink) : Via(sink) {}
704     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
705 };
706 
707 }  // namespace DM
708 
709 #endif//DMSrcSink_DEFINED
710