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