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