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/android/SkBitmapRegionDecoder.h" 13 #include "include/core/SkBBHFactory.h" 14 #include "include/core/SkBitmap.h" 15 #include "include/core/SkCanvas.h" 16 #include "include/core/SkData.h" 17 #include "include/core/SkPicture.h" 18 #include "src/utils/SkMultiPictureDocument.h" 19 #include "tools/flags/CommonFlagsConfig.h" 20 #include "tools/gpu/MemoryCache.h" 21 22 #include <functional> 23 24 //#define TEST_VIA_SVG 25 26 namespace skiagm { 27 namespace verifiers { 28 class VerifierList; 29 } 30 } 31 32 namespace DM { 33 34 // This is just convenience. It lets you use either return "foo" or return SkStringPrintf(...). 35 struct ImplicitString : public SkString { 36 template <typename T> ImplicitStringImplicitString37 ImplicitString(const T& s) : SkString(s) {} ImplicitStringImplicitString38 ImplicitString() : SkString("") {} 39 }; 40 typedef ImplicitString Name; 41 typedef ImplicitString Path; 42 43 class Result { 44 public: 45 enum class Status : int { Ok, Fatal, Skip }; Result(Status status,const SkString & s)46 Result(Status status, const SkString& s) : fMsg(s), fStatus(status) {} Result(Status status,const char * s)47 Result(Status status, const char* s) : fMsg(s), fStatus(status) {} Result(Status status,const char * s,Args...args)48 template <typename... Args> Result (Status status, const char* s, Args... args) 49 : fMsg(SkStringPrintf(s, args...)), fStatus(status) {} 50 51 Result(const Result&) = default; 52 Result& operator=(const Result&) = default; 53 Ok()54 static Result Ok() { return Result(Status::Ok, nullptr); } 55 Fatal(const SkString & s)56 static Result Fatal(const SkString& s) { return Result(Status::Fatal, s); } Fatal(const char * s)57 static Result Fatal(const char* s) { return Result(Status::Fatal, s); } Fatal(const char * s,Args...args)58 template <typename... Args> static Result Fatal(const char* s, Args... args) { 59 return Result(Status::Fatal, s, args...); 60 } 61 Skip(const SkString & s)62 static Result Skip(const SkString& s) { return Result(Status::Skip, s); } Skip(const char * s)63 static Result Skip(const char* s) { return Result(Status::Skip, s); } Skip(const char * s,Args...args)64 template <typename... Args> static Result Skip(const char* s, Args... args) { 65 return Result(Status::Skip, s, args...); 66 } 67 isOk()68 bool isOk() { return fStatus == Status::Ok; } isFatal()69 bool isFatal() { return fStatus == Status::Fatal; } isSkip()70 bool isSkip() { return fStatus == Status::Skip; } 71 c_str()72 const char* c_str() const { return fMsg.c_str(); } status()73 Status status() const { return fStatus; } 74 75 private: 76 SkString fMsg; 77 Status fStatus; 78 }; 79 80 struct SinkFlags { 81 enum Type { kNull, kGPU, kVector, kRaster } type; 82 enum Approach { kDirect, kIndirect } approach; 83 enum Multisampled { kNotMultisampled, kMultisampled } multisampled; 84 SinkFlags(Type t, Approach a, Multisampled ms = kNotMultisampled) typeSinkFlags85 : type(t), approach(a), multisampled(ms) {} 86 }; 87 88 struct Src { ~SrcSrc89 virtual ~Src() {} 90 virtual Result SK_WARN_UNUSED_RESULT draw(SkCanvas*) const = 0; 91 virtual SkISize size() const = 0; 92 virtual Name name() const = 0; modifyGrContextOptionsSrc93 virtual void modifyGrContextOptions(GrContextOptions* options) const {} vetoSrc94 virtual bool veto(SinkFlags) const { return false; } 95 pageCountSrc96 virtual int pageCount() const { return 1; } drawSrc97 virtual Result SK_WARN_UNUSED_RESULT draw(int, SkCanvas* canvas) const { 98 return this->draw(canvas); 99 } sizeSrc100 virtual SkISize size(int) const { return this->size(); } 101 // Force Tasks using this Src to run on the main thread? serialSrc102 virtual bool serial() const { return false; } 103 104 /** Return a list of verifiers for the src, or null if no verifiers should be run .*/ getVerifiersSrc105 virtual std::unique_ptr<skiagm::verifiers::VerifierList> getVerifiers() const { 106 return nullptr; 107 } 108 }; 109 110 struct Sink { ~SinkSink111 virtual ~Sink() {} 112 // You may write to either the bitmap or stream. If you write to log, we'll print that out. 113 virtual Result SK_WARN_UNUSED_RESULT draw(const Src&, SkBitmap*, SkWStream*, SkString* log) 114 const = 0; 115 116 // Force Tasks using this Sink to run on the main thread? serialSink117 virtual bool serial() const { return false; } 118 119 // File extension for the content draw() outputs, e.g. "png", "pdf". 120 virtual const char* fileExtension() const = 0; 121 122 virtual SinkFlags flags() const = 0; 123 124 /** Returns the color type and space used by the sink. */ colorInfoSink125 virtual SkColorInfo colorInfo() const { return SkColorInfo(); } 126 }; 127 128 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 129 130 class GMSrc : public Src { 131 public: 132 explicit GMSrc(skiagm::GMFactory); 133 134 Result draw(SkCanvas*) const override; 135 SkISize size() const override; 136 Name name() const override; 137 void modifyGrContextOptions(GrContextOptions* options) const override; 138 139 std::unique_ptr<skiagm::verifiers::VerifierList> getVerifiers() const override; 140 141 private: 142 skiagm::GMFactory fFactory; 143 }; 144 145 class CodecSrc : public Src { 146 public: 147 enum Mode { 148 kCodec_Mode, 149 // We choose to test only one mode with zero initialized memory. 150 // This will exercise all of the interesting cases in SkSwizzler 151 // without doubling the size of our test suite. 152 kCodecZeroInit_Mode, 153 kScanline_Mode, 154 kStripe_Mode, // Tests the skipping of scanlines 155 kCroppedScanline_Mode, // Tests (jpeg) cropped scanline optimization 156 kSubset_Mode, // For codecs that support subsets directly. 157 kAnimated_Mode, // For codecs that support animation. 158 }; 159 enum DstColorType { 160 kGetFromCanvas_DstColorType, 161 kGrayscale_Always_DstColorType, 162 kNonNative8888_Always_DstColorType, 163 }; 164 CodecSrc(Path, Mode, DstColorType, SkAlphaType, float); 165 166 Result draw(SkCanvas*) const override; 167 SkISize size() const override; 168 Name name() const override; veto(SinkFlags)169 bool veto(SinkFlags) const override; 170 bool serial() const override { return fRunSerially; } 171 private: 172 Path fPath; 173 Mode fMode; 174 DstColorType fDstColorType; 175 SkAlphaType fDstAlphaType; 176 float fScale; 177 bool fRunSerially; 178 }; 179 180 class AndroidCodecSrc : public Src { 181 public: 182 AndroidCodecSrc(Path, CodecSrc::DstColorType, SkAlphaType, int sampleSize); 183 184 Result draw(SkCanvas*) const override; 185 SkISize size() const override; 186 Name name() const override; veto(SinkFlags)187 bool veto(SinkFlags) const override; 188 bool serial() const override { return fRunSerially; } 189 private: 190 Path fPath; 191 CodecSrc::DstColorType fDstColorType; 192 SkAlphaType fDstAlphaType; 193 int fSampleSize; 194 bool fRunSerially; 195 }; 196 197 // Allows for testing of various implementations of Android's BitmapRegionDecoder 198 class BRDSrc : public Src { 199 public: 200 enum Mode { 201 // Decode the entire image as one region. 202 kFullImage_Mode, 203 // Splits the image into multiple regions using a divisor and decodes the regions 204 // separately. Also, this test adds a border of a few pixels to each of the regions 205 // that it is decoding. This tests the behavior when a client asks for a region that 206 // does not fully fit in the image. 207 kDivisor_Mode, 208 }; 209 210 BRDSrc(Path, Mode, CodecSrc::DstColorType, uint32_t); 211 212 Result draw(SkCanvas*) const override; 213 SkISize size() const override; 214 Name name() const override; 215 bool veto(SinkFlags) const override; 216 private: 217 Path fPath; 218 Mode fMode; 219 CodecSrc::DstColorType fDstColorType; 220 uint32_t fSampleSize; 221 }; 222 223 class ImageGenSrc : public Src { 224 public: 225 enum Mode { 226 kCodec_Mode, // Use CodecImageGenerator 227 kPlatform_Mode, // Uses CG or WIC 228 }; 229 ImageGenSrc(Path, Mode, SkAlphaType, bool); 230 231 Result draw(SkCanvas*) const override; 232 SkISize size() const override; 233 Name name() const override; veto(SinkFlags)234 bool veto(SinkFlags) const override; 235 bool serial() const override { return fRunSerially; } 236 private: 237 Path fPath; 238 Mode fMode; 239 SkAlphaType fDstAlphaType; 240 bool fIsGpu; 241 bool fRunSerially; 242 }; 243 244 class ColorCodecSrc : public Src { 245 public: 246 ColorCodecSrc(Path, bool decode_to_dst); 247 248 Result draw(SkCanvas*) const override; 249 SkISize size() const override; 250 Name name() const override; 251 bool veto(SinkFlags) const override; 252 private: 253 Path fPath; 254 bool fDecodeToDst; 255 }; 256 257 class SKPSrc : public Src { 258 public: 259 explicit SKPSrc(Path path); 260 261 Result draw(SkCanvas*) const override; 262 SkISize size() const override; 263 Name name() const override; 264 private: 265 Path fPath; 266 }; 267 268 // This class extracts all the paths from an SKP and then removes unwanted paths according to the 269 // provided l/r trail. It then just draws the remaining paths. (Non-path draws are thrown out.) It 270 // is useful for finding a reduced repo case for path drawing bugs. 271 class BisectSrc : public SKPSrc { 272 public: 273 explicit BisectSrc(Path path, const char* trail); 274 275 Result draw(SkCanvas*) const override; 276 277 private: 278 SkString fTrail; 279 280 typedef SKPSrc INHERITED; 281 }; 282 283 284 #if defined(SK_ENABLE_SKOTTIE) 285 class SkottieSrc final : public Src { 286 public: 287 explicit SkottieSrc(Path path); 288 289 Result draw(SkCanvas*) const override; 290 SkISize size() const override; 291 Name name() const override; 292 bool veto(SinkFlags) const override; 293 294 private: 295 // Generates a kTileCount x kTileCount filmstrip with evenly distributed frames. 296 static constexpr int kTileCount = 5; 297 298 // Fit kTileCount x kTileCount frames to a 1000x1000 film strip. 299 static constexpr SkScalar kTargetSize = 1000; 300 static constexpr SkScalar kTileSize = kTargetSize / kTileCount; 301 302 Path fPath; 303 }; 304 #endif 305 306 #if defined(SK_XML) 307 } // namespace DM 308 309 class SkSVGDOM; 310 311 namespace DM { 312 313 class SVGSrc : public Src { 314 public: 315 explicit SVGSrc(Path path); 316 317 Result draw(SkCanvas*) const override; 318 SkISize size() const override; 319 Name name() const override; 320 bool veto(SinkFlags) const override; 321 322 private: 323 Name fName; 324 sk_sp<SkSVGDOM> fDom; 325 SkScalar fScale; 326 327 typedef Src INHERITED; 328 }; 329 #endif // SK_XML 330 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 331 332 class MSKPSrc : public Src { 333 public: 334 explicit MSKPSrc(Path path); 335 336 int pageCount() const override; 337 Result draw(SkCanvas* c) const override; 338 Result draw(int, SkCanvas*) const override; 339 SkISize size() const override; 340 SkISize size(int) const override; 341 Name name() const override; 342 343 private: 344 Path fPath; 345 mutable SkTArray<SkDocumentPage> fPages; 346 }; 347 348 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 349 350 class NullSink : public Sink { 351 public: NullSink()352 NullSink() {} 353 354 Result draw(const Src& src, SkBitmap*, SkWStream*, SkString*) const override; fileExtension()355 const char* fileExtension() const override { return ""; } flags()356 SinkFlags flags() const override { return SinkFlags{ SinkFlags::kNull, SinkFlags::kDirect }; } 357 }; 358 359 class GPUSink : public Sink { 360 public: 361 GPUSink(const SkCommandLineConfigGpu*, const GrContextOptions&); 362 363 Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; 364 Result onDraw(const Src&, SkBitmap*, SkWStream*, SkString*, 365 const GrContextOptions& baseOptions, 366 std::function<void(GrContext*)> initContext = nullptr) const; 367 contextType()368 sk_gpu_test::GrContextFactory::ContextType contextType() const { return fContextType; } contextOverrides()369 const sk_gpu_test::GrContextFactory::ContextOverrides& contextOverrides() const { 370 return fContextOverrides; 371 } surfType()372 SkCommandLineConfigGpu::SurfType surfType() const { return fSurfType; } useDIText()373 bool useDIText() const { return fUseDIText; } serial()374 bool serial() const override { return true; } fileExtension()375 const char* fileExtension() const override { return "png"; } flags()376 SinkFlags flags() const override { 377 SinkFlags::Multisampled ms = fSampleCount > 1 ? SinkFlags::kMultisampled 378 : SinkFlags::kNotMultisampled; 379 return SinkFlags{ SinkFlags::kGPU, SinkFlags::kDirect, ms }; 380 } baseContextOptions()381 const GrContextOptions& baseContextOptions() const { return fBaseContextOptions; } colorInfo()382 SkColorInfo colorInfo() const override { 383 return SkColorInfo(fColorType, fAlphaType, fColorSpace); 384 } 385 386 protected: 387 sk_sp<SkSurface> createDstSurface(GrContext*, SkISize size, GrBackendTexture*, 388 GrBackendRenderTarget*) const; 389 bool readBack(SkSurface*, SkBitmap* dst) const; 390 391 private: 392 sk_gpu_test::GrContextFactory::ContextType fContextType; 393 sk_gpu_test::GrContextFactory::ContextOverrides fContextOverrides; 394 SkCommandLineConfigGpu::SurfType fSurfType; 395 int fSampleCount; 396 bool fUseDIText; 397 SkColorType fColorType; 398 SkAlphaType fAlphaType; 399 sk_sp<SkColorSpace> fColorSpace; 400 GrContextOptions fBaseContextOptions; 401 sk_gpu_test::MemoryCache fMemoryCache; 402 }; 403 404 class GPUThreadTestingSink : public GPUSink { 405 public: 406 GPUThreadTestingSink(const SkCommandLineConfigGpu*, const GrContextOptions&); 407 408 Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; 409 fileExtension()410 const char* fileExtension() const override { 411 // Suppress writing out results from this config - we just want to do our matching test 412 return nullptr; 413 } 414 415 private: 416 std::unique_ptr<SkExecutor> fExecutor; 417 418 typedef GPUSink INHERITED; 419 }; 420 421 class GPUPersistentCacheTestingSink : public GPUSink { 422 public: 423 GPUPersistentCacheTestingSink(const SkCommandLineConfigGpu*, const GrContextOptions&); 424 425 Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; 426 fileExtension()427 const char* fileExtension() const override { 428 // Suppress writing out results from this config - we just want to do our matching test 429 return nullptr; 430 } 431 432 private: 433 int fCacheType; 434 435 typedef GPUSink INHERITED; 436 }; 437 438 class GPUPrecompileTestingSink : public GPUSink { 439 public: 440 GPUPrecompileTestingSink(const SkCommandLineConfigGpu*, const GrContextOptions&); 441 442 Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; 443 fileExtension()444 const char* fileExtension() const override { 445 // Suppress writing out results from this config - we just want to do our matching test 446 return nullptr; 447 } 448 449 private: 450 typedef GPUSink INHERITED; 451 }; 452 453 // This sink attempts to better simulate the Chrome DDL use-case. It: 454 // creates the DDLs on separate recording threads 455 // performs all the GPU work on a separate GPU thread 456 // In the future this should be expanded to: 457 // upload on a utility thread w/ access to a shared context 458 // compile the programs on the utility thread 459 // perform fine grained scheduling of gpu tasks based on their image and program prerequisites 460 // create a single "compositing" DDL that is replayed last 461 class GPUDDLSink : public GPUSink { 462 public: 463 GPUDDLSink(const SkCommandLineConfigGpu*, const GrContextOptions&); 464 465 Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; 466 467 private: 468 Result ddlDraw(const Src&, 469 sk_sp<SkSurface> dstSurface, 470 SkTaskGroup* recordingTaskGroup, 471 SkTaskGroup* gpuTaskGroup, 472 GrContext* gpuCtx) const; 473 474 std::unique_ptr<SkExecutor> fRecordingThreadPool; 475 std::unique_ptr<SkExecutor> fGPUThread; 476 477 typedef GPUSink INHERITED; 478 }; 479 480 class PDFSink : public Sink { 481 public: PDFSink(bool pdfa,SkScalar rasterDpi)482 PDFSink(bool pdfa, SkScalar rasterDpi) : fPDFA(pdfa), fRasterDpi(rasterDpi) {} 483 Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; fileExtension()484 const char* fileExtension() const override { return "pdf"; } flags()485 SinkFlags flags() const override { return SinkFlags{ SinkFlags::kVector, SinkFlags::kDirect }; } 486 bool fPDFA; 487 SkScalar fRasterDpi; 488 }; 489 490 class XPSSink : public Sink { 491 public: 492 XPSSink(); 493 494 Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; fileExtension()495 const char* fileExtension() const override { return "xps"; } flags()496 SinkFlags flags() const override { return SinkFlags{ SinkFlags::kVector, SinkFlags::kDirect }; } 497 }; 498 499 class RasterSink : public Sink { 500 public: 501 explicit RasterSink(SkColorType, sk_sp<SkColorSpace> = nullptr); 502 503 Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; fileExtension()504 const char* fileExtension() const override { return "png"; } flags()505 SinkFlags flags() const override { return SinkFlags{ SinkFlags::kRaster, SinkFlags::kDirect }; } 506 507 private: 508 SkColorType fColorType; 509 sk_sp<SkColorSpace> fColorSpace; 510 }; 511 512 class ThreadedSink : public RasterSink { 513 public: 514 explicit ThreadedSink(SkColorType, sk_sp<SkColorSpace> = nullptr); 515 Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; 516 }; 517 518 class SKPSink : public Sink { 519 public: 520 SKPSink(); 521 522 Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; fileExtension()523 const char* fileExtension() const override { return "skp"; } flags()524 SinkFlags flags() const override { return SinkFlags{ SinkFlags::kVector, SinkFlags::kDirect }; } 525 }; 526 527 class DebugSink : public Sink { 528 public: 529 Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; fileExtension()530 const char* fileExtension() const override { return "json"; } flags()531 SinkFlags flags() const override { return SinkFlags{ SinkFlags::kVector, SinkFlags::kDirect }; } 532 }; 533 534 class SVGSink : public Sink { 535 public: 536 SVGSink(int pageIndex = 0); 537 538 Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; fileExtension()539 const char* fileExtension() const override { return "svg"; } flags()540 SinkFlags flags() const override { return SinkFlags{ SinkFlags::kVector, SinkFlags::kDirect }; } 541 542 private: 543 int fPageIndex; 544 }; 545 546 547 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 548 549 class Via : public Sink { 550 public: Via(Sink * sink)551 explicit Via(Sink* sink) : fSink(sink) {} fileExtension()552 const char* fileExtension() const override { return fSink->fileExtension(); } serial()553 bool serial() const override { return fSink->serial(); } flags()554 SinkFlags flags() const override { 555 SinkFlags flags = fSink->flags(); 556 flags.approach = SinkFlags::kIndirect; 557 return flags; 558 } 559 protected: 560 std::unique_ptr<Sink> fSink; 561 }; 562 563 class ViaMatrix : public Via { 564 public: 565 ViaMatrix(SkMatrix, Sink*); 566 Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; 567 private: 568 const SkMatrix fMatrix; 569 }; 570 571 class ViaUpright : public Via { 572 public: 573 ViaUpright(SkMatrix, Sink*); 574 Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; 575 private: 576 const SkMatrix fMatrix; 577 }; 578 579 class ViaSerialization : public Via { 580 public: ViaSerialization(Sink * sink)581 explicit ViaSerialization(Sink* sink) : Via(sink) {} 582 Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; 583 }; 584 585 class ViaPicture : public Via { 586 public: ViaPicture(Sink * sink)587 explicit ViaPicture(Sink* sink) : Via(sink) {} 588 Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; 589 }; 590 591 class ViaDDL : public Via { 592 public: 593 ViaDDL(int numReplays, int numDivisions, Sink* sink); 594 Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; 595 private: 596 const int fNumReplays; 597 const int fNumDivisions; 598 }; 599 600 class ViaSVG : public Via { 601 public: ViaSVG(Sink * sink)602 explicit ViaSVG(Sink* sink) : Via(sink) {} 603 Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; 604 }; 605 606 } // namespace DM 607 608 #endif//DMSrcSink_DEFINED 609