xref: /aosp_15_r20/external/skia/gm/asyncrescaleandread.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2019 Google LLC
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "gm/gm.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkColor.h"
11 #include "include/core/SkPaint.h"
12 #include "include/core/SkRect.h"
13 #include "include/core/SkSurface.h"
14 #include "include/core/SkYUVAInfo.h"
15 #include "include/core/SkYUVAPixmaps.h"
16 #include "include/effects/SkGradientShader.h"
17 #include "include/gpu/ganesh/GrDirectContext.h"
18 #include "include/gpu/ganesh/GrRecordingContext.h"
19 #include "include/gpu/ganesh/SkImageGanesh.h"
20 #include "src/base/SkScopeExit.h"
21 #include "src/core/SkAutoPixmapStorage.h"
22 #include "tools/DecodeUtils.h"
23 #include "tools/Resources.h"
24 #include "tools/ToolUtils.h"
25 #include "tools/gpu/YUVUtils.h"
26 
27 #if defined(SK_GRAPHITE)
28 #include "include/gpu/graphite/Context.h"
29 #include "include/gpu/graphite/Image.h"
30 #include "src/gpu/graphite/RecorderPriv.h"
31 #include "tools/graphite/GraphiteTestContext.h"
32 #endif
33 
34 #include <variant>
35 
36 namespace {
37 /// We test reading from images and surfaces
38 enum class ReadSource {
39     kImage,
40     kSurface,
41 };
42 
43 // We test reading to RGBA, YUV, and YUVA
44 enum class Type {
45     kRGBA,
46     kYUV,
47     kYUVA
48 };
49 
50 template <ReadSource> struct SourceS;
51 template <> struct SourceS<ReadSource::kImage>   { using Type = SkImage;   };
52 template <> struct SourceS<ReadSource::kSurface> { using Type = SkSurface; };
53 
54 template <ReadSource RS> using Source = typename SourceS<RS>::Type;
55 
56 // Converts a source image to either an SkImage or SkSurface, backed by GPU if canvas is. Returns
57 // kSkip or kFail if the image cannot be converted.
58 template <ReadSource RS>
59 std::variant<sk_sp<Source<RS>>, skiagm::DrawResult> convert_image_to_source(SkCanvas* canvas,
60                                                                             sk_sp<SkImage> image,
61                                                                             SkString* errorMsg);
62 
63 template <>
convert_image_to_source(SkCanvas * canvas,sk_sp<SkImage> image,SkString * errorMsg)64 std::variant<sk_sp<SkImage>, skiagm::DrawResult> convert_image_to_source<ReadSource::kImage>(
65         SkCanvas* canvas,
66         sk_sp<SkImage> image,
67         SkString* errorMsg) {
68 #if defined(SK_GRAPHITE)
69     if (auto recorder = canvas->recorder()) {
70         image = SkImages::TextureFromImage(recorder, image);
71         if (image) {
72             return image;
73         }
74         *errorMsg = "Could not create Graphite image";
75         return skiagm::DrawResult::kFail;
76     }
77 #endif
78     auto dContext = GrAsDirectContext(canvas->recordingContext());
79     if (!dContext && canvas->recordingContext()) {
80         *errorMsg = "Not supported in DDL mode";
81         return skiagm::DrawResult::kSkip;
82     }
83     if (dContext) {
84         image = SkImages::TextureFromImage(dContext, image);
85         if (image) {
86             return image;
87         }
88         // When testing abandoned GrContext we expect surface creation to fail.
89         if (dContext && dContext->abandoned()) {
90             return skiagm::DrawResult::kSkip;
91         }
92         *errorMsg = "Could not create Ganesh image";
93         return skiagm::DrawResult::kFail;
94     }
95     return image;
96 }
97 
98 template <>
convert_image_to_source(SkCanvas * canvas,sk_sp<SkImage> image,SkString * errorMsg)99 std::variant<sk_sp<SkSurface>, skiagm::DrawResult> convert_image_to_source<ReadSource::kSurface>(
100         SkCanvas* canvas,
101         sk_sp<SkImage> image,
102         SkString* errorMsg) {
103     // Turn the image into a surface in order to call the read and rescale API
104     auto surfInfo = image->imageInfo().makeDimensions(image->dimensions());
105     auto surface = canvas->makeSurface(surfInfo);
106     if (!surface && surfInfo.colorType() == kBGRA_8888_SkColorType) {
107         surfInfo = surfInfo.makeColorType(kRGBA_8888_SkColorType);
108         surface = canvas->makeSurface(surfInfo);
109     }
110     if (!surface) {
111         *errorMsg = "Could not create surface for image.";
112         // When testing abandoned GrContext we expect surface creation to fail.
113         if (canvas->recordingContext() && canvas->recordingContext()->abandoned()) {
114             return skiagm::DrawResult::kSkip;
115         }
116         return skiagm::DrawResult::kFail;
117     }
118     SkPaint paint;
119     paint.setBlendMode(SkBlendMode::kSrc);
120     surface->getCanvas()->drawImage(image, 0, 0, SkSamplingOptions(), &paint);
121     return surface;
122 }
123 
124 class AsyncReadGMBase : public skiagm::GM {
125 public:
AsyncReadGMBase(const char * name)126     AsyncReadGMBase(const char* name) : fName(name) {}
127 
getName() const128     SkString getName() const override { return fName; }
129 
130 protected:
131     // Does a rescale and read using Graphite, Ganesh, or CPU and returns the result as a pixmap
132     // image.
133     template <ReadSource ReadSource>
readAndScaleRGBA(Source<ReadSource> * src,SkIRect srcRect,GrDirectContext * direct,skgpu::graphite::Recorder * recorder,const SkImageInfo & ii,SkImage::RescaleGamma rescaleGamma,SkImage::RescaleMode rescaleMode)134     sk_sp<SkImage> readAndScaleRGBA(Source<ReadSource>* src,
135                                     SkIRect srcRect,
136                                     GrDirectContext* direct,
137                                     skgpu::graphite::Recorder* recorder,
138                                     const SkImageInfo& ii,
139                                     SkImage::RescaleGamma rescaleGamma,
140                                     SkImage::RescaleMode rescaleMode) {
141         auto* asyncContext = new AsyncContext();
142         if (recorder) {
143 #if defined(SK_GRAPHITE)
144             skgpu::graphite::Context* graphiteContext = recorder->priv().context();
145             if (!graphiteContext) {
146                 return nullptr;
147             }
148             // We need to flush the existing drawing commands before we try to read
149             std::unique_ptr<skgpu::graphite::Recording> recording = recorder->snap();
150             if (!recording) {
151                 return nullptr;
152             }
153             skgpu::graphite::InsertRecordingInfo recordingInfo;
154             recordingInfo.fRecording = recording.get();
155             if (!graphiteContext->insertRecording(recordingInfo)) {
156                 return nullptr;
157             }
158 
159             graphiteContext->asyncRescaleAndReadPixels(src,
160                                                        ii,
161                                                        srcRect,
162                                                        rescaleGamma,
163                                                        rescaleMode,
164                                                        AsyncCallback,
165                                                        asyncContext);
166             graphiteContext->submit();
167             while (!asyncContext->fCalled) {
168                 graphiteContext->checkAsyncWorkCompletion();
169                 if (this->graphiteTestContext()) {
170                     this->graphiteTestContext()->tick();
171                 }
172             }
173 #endif
174         } else {
175             src->asyncRescaleAndReadPixels(ii,
176                                            srcRect,
177                                            rescaleGamma,
178                                            rescaleMode,
179                                            AsyncCallback,
180                                            asyncContext);
181             if (direct) {
182                 direct->submit();
183             }
184             while (!asyncContext->fCalled) {
185                 // Only GPU should actually be asynchronous.
186                 SkASSERT(direct);
187                 direct->checkAsyncWorkCompletion();
188             }
189         }
190         if (!asyncContext->fResult) {
191             return nullptr;
192         }
193         SkPixmap pixmap(ii, asyncContext->fResult->data(0), asyncContext->fResult->rowBytes(0));
194         auto releasePixels = [](const void*, void* c) { delete static_cast<AsyncContext*>(c); };
195         return SkImages::RasterFromPixmap(pixmap, releasePixels, asyncContext);
196     }
197 
198     // Does a YUV[A] rescale and read using Graphite or Ganesh (no CPU support) and returns the
199     // result as a YUVA planar texture image.
200     template <ReadSource ReadSource>
readAndScaleYUVA(Source<ReadSource> * src,SkIRect srcRect,SkISize resultSize,bool readAlpha,GrDirectContext * direct,skgpu::graphite::Recorder * recorder,SkYUVColorSpace yuvCS,SkImage::RescaleGamma rescaleGamma,SkImage::RescaleMode rescaleMode,SkScopeExit * cleanup)201     sk_sp<SkImage> readAndScaleYUVA(Source<ReadSource>* src,
202                                     SkIRect srcRect,
203                                     SkISize resultSize,
204                                     bool readAlpha,
205                                     GrDirectContext* direct,
206                                     skgpu::graphite::Recorder* recorder,
207                                     SkYUVColorSpace yuvCS,
208                                     SkImage::RescaleGamma rescaleGamma,
209                                     SkImage::RescaleMode rescaleMode,
210                                     SkScopeExit* cleanup) {
211         SkASSERT(!(resultSize.width() & 0b1) && !(resultSize.height() & 0b1));
212 
213         SkISize uvSize = {resultSize.width() / 2, resultSize.height() / 2};
214         SkImageInfo yaII = SkImageInfo::Make(resultSize, kGray_8_SkColorType, kPremul_SkAlphaType);
215         SkImageInfo uvII = SkImageInfo::Make(uvSize,     kGray_8_SkColorType, kPremul_SkAlphaType);
216 
217         AsyncContext asyncContext;
218         if (recorder) {
219 #if defined(SK_GRAPHITE)
220             skgpu::graphite::Context* graphiteContext = recorder->priv().context();
221             if (!graphiteContext) {
222                 return nullptr;
223             }
224             // We need to flush the existing drawing commands before we try to read
225             std::unique_ptr<skgpu::graphite::Recording> recording = recorder->snap();
226             if (!recording) {
227                 return nullptr;
228             }
229             skgpu::graphite::InsertRecordingInfo recordingInfo;
230             recordingInfo.fRecording = recording.get();
231             if (!graphiteContext->insertRecording(recordingInfo)) {
232                 return nullptr;
233             }
234 
235             if (readAlpha) {
236                 graphiteContext->asyncRescaleAndReadPixelsYUVA420(src,
237                                                                   yuvCS,
238                                                                   SkColorSpace::MakeSRGB(),
239                                                                   srcRect,
240                                                                   resultSize,
241                                                                   rescaleGamma,
242                                                                   rescaleMode,
243                                                                   AsyncCallback,
244                                                                   &asyncContext);
245             } else {
246                 graphiteContext->asyncRescaleAndReadPixelsYUV420(src,
247                                                                  yuvCS,
248                                                                  SkColorSpace::MakeSRGB(),
249                                                                  srcRect,
250                                                                  resultSize,
251                                                                  rescaleGamma,
252                                                                  rescaleMode,
253                                                                  AsyncCallback,
254                                                                  &asyncContext);
255             }
256             graphiteContext->submit();
257             while (!asyncContext.fCalled) {
258                 graphiteContext->checkAsyncWorkCompletion();
259                 if (this->graphiteTestContext()) {
260                     this->graphiteTestContext()->tick();
261                 }
262             }
263 #endif
264         } else {
265             if (readAlpha) {
266                 src->asyncRescaleAndReadPixelsYUVA420(yuvCS,
267                                                       SkColorSpace::MakeSRGB(),
268                                                       srcRect,
269                                                       resultSize,
270                                                       rescaleGamma,
271                                                       rescaleMode,
272                                                       AsyncCallback,
273                                                       &asyncContext);
274             } else {
275                 src->asyncRescaleAndReadPixelsYUV420(yuvCS,
276                                                      SkColorSpace::MakeSRGB(),
277                                                      srcRect,
278                                                      resultSize,
279                                                      rescaleGamma,
280                                                      rescaleMode,
281                                                      AsyncCallback,
282                                                      &asyncContext);
283             }
284             if (direct) {
285                 direct->submit();
286             }
287             while (!asyncContext.fCalled) {
288                 // Only GPU should actually be asynchronous.
289                 SkASSERT(direct);
290                 direct->checkAsyncWorkCompletion();
291             }
292         }
293         if (!asyncContext.fResult) {
294             return nullptr;
295         }
296         auto planeConfig = readAlpha ? SkYUVAInfo::PlaneConfig::kY_U_V_A :
297                                        SkYUVAInfo::PlaneConfig::kY_U_V;
298         SkYUVAInfo yuvaInfo(resultSize,
299                             planeConfig,
300                             SkYUVAInfo::Subsampling::k420,
301                             yuvCS);
302         SkPixmap yuvPMs[4] = {
303                 {yaII, asyncContext.fResult->data(0), asyncContext.fResult->rowBytes(0)},
304                 {uvII, asyncContext.fResult->data(1), asyncContext.fResult->rowBytes(1)},
305                 {uvII, asyncContext.fResult->data(2), asyncContext.fResult->rowBytes(2)},
306                 {},
307         };
308         if (readAlpha) {
309             yuvPMs[3] = {yaII, asyncContext.fResult->data(3), asyncContext.fResult->rowBytes(3)};
310         }
311         auto pixmaps = SkYUVAPixmaps::FromExternalPixmaps(yuvaInfo, yuvPMs);
312         SkASSERT(pixmaps.isValid());
313         auto lazyYUVImage = sk_gpu_test::LazyYUVImage::Make(pixmaps);
314         SkASSERT(lazyYUVImage);
315 #if defined(SK_GRAPHITE)
316         if (recorder) {
317             return lazyYUVImage->refImage(recorder, sk_gpu_test::LazyYUVImage::Type::kFromTextures);
318         } else
319 #endif
320         {
321             return lazyYUVImage->refImage(direct, sk_gpu_test::LazyYUVImage::Type::kFromTextures);
322         }
323     }
324 
325     // Draws a 3x2 grid of rescales. The columns are none, low, and high filter quality. The rows
326     // are rescale in src gamma and rescale in linear gamma.
327     template <ReadSource ReadSource>
drawRescaleGrid(SkCanvas * canvas,Source<ReadSource> * src,SkIRect srcRect,SkISize readSize,Type type,SkString * errorMsg,int pad=0)328     skiagm::DrawResult drawRescaleGrid(SkCanvas* canvas,
329                                        Source<ReadSource>* src,
330                                        SkIRect srcRect,
331                                        SkISize readSize,
332                                        Type type,
333                                        SkString* errorMsg,
334                                        int pad = 0) {
335         SkASSERT(canvas->imageInfo().colorType() != kUnknown_SkColorType);
336 
337         auto direct = GrAsDirectContext(canvas->recordingContext());
338         auto recorder = canvas->recorder();
339         SkASSERT(direct || !canvas->recordingContext());
340 
341         SkYUVColorSpace yuvColorSpace = kRec601_SkYUVColorSpace;
342         canvas->save();
343         for (auto gamma : {SkImage::RescaleGamma::kSrc, SkImage::RescaleGamma::kLinear}) {
344             canvas->save();
345             for (auto mode : {SkImage::RescaleMode::kNearest,
346                               SkImage::RescaleMode::kRepeatedLinear,
347                               SkImage::RescaleMode::kRepeatedCubic}) {
348                 SkScopeExit cleanup;
349                 sk_sp<SkImage> result;
350                 switch (type) {
351                     case Type::kRGBA: {
352                         const auto ii = canvas->imageInfo().makeDimensions(readSize);
353                         result = readAndScaleRGBA<ReadSource>(src,
354                                                               srcRect,
355                                                               direct,
356                                                               recorder,
357                                                               ii,
358                                                               gamma,
359                                                               mode);
360                         if (!result) {
361                             errorMsg->printf("async read call failed.");
362                             return skiagm::DrawResult::kFail;
363                         }
364                         break;
365                     }
366                     case Type::kYUV:
367                     case Type::kYUVA:
368                         result = readAndScaleYUVA<ReadSource>(src,
369                                                               srcRect,
370                                                               readSize,
371                                                               /*readAlpha=*/type == Type::kYUVA,
372                                                               direct,
373                                                               recorder,
374                                                               yuvColorSpace,
375                                                               gamma,
376                                                               mode,
377                                                               &cleanup);
378                         if (!result) {
379                             errorMsg->printf("YUV[A]420 async call failed. Allowed for now.");
380                             return skiagm::DrawResult::kSkip;
381                         }
382                         int nextCS = static_cast<int>(yuvColorSpace + 1) %
383                                      (kLastEnum_SkYUVColorSpace + 1);
384                         yuvColorSpace = static_cast<SkYUVColorSpace>(nextCS);
385                         break;
386                 }
387                 canvas->drawImage(result, 0, 0);
388                 canvas->translate(readSize.width() + pad, 0);
389             }
390             canvas->restore();
391             canvas->translate(0, readSize.height() + pad);
392         }
393         canvas->restore();
394         return skiagm::DrawResult::kOk;
395     }
396 
397 private:
398     struct AsyncContext {
399         bool fCalled = false;
400         std::unique_ptr<const SkImage::AsyncReadResult> fResult;
401     };
402 
403     // Making this a lambda in the test functions caused:
404     //   "error: cannot compile this forwarded non-trivially copyable parameter yet"
405     // on x86/Win/Clang bot, referring to 'result'.
AsyncCallback(void * c,std::unique_ptr<const SkImage::AsyncReadResult> result)406     static void AsyncCallback(void* c, std::unique_ptr<const SkImage::AsyncReadResult> result) {
407         auto context = static_cast<AsyncContext*>(c);
408         context->fResult = std::move(result);
409         context->fCalled = true;
410     }
411 
412     SkString fName;
413 };
414 
415 template <ReadSource ReadSource, Type Type>
416 class AsyncRescaleAndReadGridGM : public AsyncReadGMBase {
417 public:
AsyncRescaleAndReadGridGM(const char * name,const char * imageFile,SkIRect srcRect,SkISize readSize)418     AsyncRescaleAndReadGridGM(const char* name,
419                               const char* imageFile,
420                               SkIRect srcRect,
421                               SkISize readSize)
422             : AsyncReadGMBase(name)
423             , fImageFile(imageFile)
424             , fSrcRect(srcRect)
425             , fReadSize(readSize) {}
426 
onDraw(SkCanvas * canvas,SkString * errorMsg)427     DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
428         ToolUtils::draw_checkerboard(canvas, SK_ColorDKGRAY, SK_ColorLTGRAY, 25);
429         auto image = ToolUtils::GetResourceAsImage(fImageFile.c_str());
430         if (!image) {
431             errorMsg->printf("Could not load image file %s.", fImageFile.c_str());
432             return skiagm::DrawResult::kFail;
433         }
434         if (canvas->imageInfo().colorType() == kUnknown_SkColorType) {
435             *errorMsg = "Not supported on recording/vector backends.";
436             return skiagm::DrawResult::kSkip;
437         }
438 
439         auto sourceOrResult = convert_image_to_source<ReadSource>(canvas, image, errorMsg);
440         if (auto dr = std::get_if<skiagm::DrawResult>(&sourceOrResult)) {
441             return *dr;
442         }
443 
444         using Src = sk_sp<Source<ReadSource>>;
445         return drawRescaleGrid<ReadSource>(canvas,
446                                            std::get<Src>(sourceOrResult).get(),
447                                            fSrcRect,
448                                            fReadSize,
449                                            Type,
450                                            errorMsg);
451     }
452 
getISize()453     SkISize getISize() override { return {3 * fReadSize.width(), 2 * fReadSize.height()}; }
454 
455 private:
456     SkString fImageFile;
457     SkIRect fSrcRect;
458     SkISize fReadSize;
459 };
460 }  // anonymous namespace
461 
462 #define DEF_RESCALE_AND_READ_GRID_GM(IMAGE_FILE, TAG, SRC_RECT, W, H, SOURCE, TYPE) \
463     DEF_GM(return new (AsyncRescaleAndReadGridGM<SOURCE, TYPE>)(                    \
464                           "async_rescale_and_read_" #TAG, #IMAGE_FILE, SRC_RECT, SkISize{W, H});)
465 
466 DEF_RESCALE_AND_READ_GRID_GM(images/yellow_rose.webp,
467                              yuv420_rose,
468                              SkIRect::MakeXYWH(50, 5, 200, 150),
469                              410,
470                              376,
471                              ReadSource::kSurface,
472                              Type::kYUVA)
473 
474 DEF_RESCALE_AND_READ_GRID_GM(images/yellow_rose.webp,
475                              yuv420_rose_down,
476                              SkIRect::MakeXYWH(50, 5, 200, 150),
477                              106,
478                              60,
479                              ReadSource::kImage,
480                              Type::kYUV)
481 
482 DEF_RESCALE_AND_READ_GRID_GM(images/yellow_rose.webp,
483                              rose,
484                              SkIRect::MakeXYWH(100, 20, 100, 100),
485                              410,
486                              410,
487                              ReadSource::kSurface,
488                              Type::kRGBA)
489 
490 DEF_RESCALE_AND_READ_GRID_GM(images/dog.jpg,
491                              dog_down,
492                              SkIRect::MakeXYWH(0, 10, 180, 150),
493                              45,
494                              45,
495                              ReadSource::kSurface,
496                              Type::kRGBA)
497 
498 DEF_RESCALE_AND_READ_GRID_GM(images/dog.jpg,
499                              dog_up,
500                              SkIRect::MakeWH(180, 180),
501                              800,
502                              400,
503                              ReadSource::kImage,
504                              Type::kRGBA)
505 
506 DEF_RESCALE_AND_READ_GRID_GM(images/text.png,
507                              text_down,
508                              SkIRect::MakeWH(637, 105),
509                              (int)(0.7 * 637),
510                              (int)(0.7 * 105),
511                              ReadSource::kImage,
512                              Type::kRGBA)
513 
514 DEF_RESCALE_AND_READ_GRID_GM(images/text.png,
515                              text_up,
516                              SkIRect::MakeWH(637, 105),
517                              (int)(1.2 * 637),
518                              (int)(1.2 * 105),
519                              ReadSource::kSurface,
520                              Type::kRGBA)
521 
522 DEF_RESCALE_AND_READ_GRID_GM(images/text.png,
523                              text_up_large,
524                              SkIRect::MakeXYWH(300, 0, 300, 105),
525                              (int)(2.4 * 300),
526                              (int)(2.4 * 105),
527                              ReadSource::kImage,
528                              Type::kRGBA)
529 
530 namespace {
531 class AyncYUVNoScaleGM : public AsyncReadGMBase {
532 public:
AyncYUVNoScaleGM()533     AyncYUVNoScaleGM() : AsyncReadGMBase("async_yuv_no_scale") {}
onDraw(SkCanvas * canvas,SkString * errorMsg)534     DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
535         auto surface = canvas->getSurface();
536         if (!surface) {
537             *errorMsg = "Not supported on recording/vector backends.";
538             return skiagm::DrawResult::kSkip;
539         }
540 
541         auto dContext = GrAsDirectContext(surface->recordingContext());
542         if (!dContext && surface->recordingContext()) {
543             *errorMsg = "Not supported in DDL mode";
544             return skiagm::DrawResult::kSkip;
545         }
546 
547         auto image = ToolUtils::GetResourceAsImage("images/yellow_rose.webp");
548         if (!image) {
549             return skiagm::DrawResult::kFail;
550         }
551 
552         static constexpr SkIPoint kOffset = {15, 12};
553         SkISize evenSz = {image->width() & ~0b1, image->height() & ~0b1};
554         canvas->drawImage(image.get(), kOffset.fX, kOffset.fY);
555 
556         skgpu::graphite::Recorder* recorder = canvas->recorder();
557         SkScopeExit scopeExit;
558         auto yuvImage = readAndScaleYUVA<ReadSource::kSurface>(surface,
559                                                                SkIRect::MakePtSize(kOffset, evenSz),
560                                                                evenSz,
561                                                                /*readAlpha=*/false,
562                                                                dContext,
563                                                                recorder,
564                                                                kRec601_SkYUVColorSpace,
565                                                                SkImage::RescaleGamma::kSrc,
566                                                                SkImage::RescaleMode::kNearest,
567                                                                &scopeExit);
568 
569         canvas->clear(SK_ColorWHITE);
570         canvas->drawImage(yuvImage.get(), 0, 0);
571 
572         return skiagm::DrawResult::kOk;
573     }
getISize()574     SkISize getISize() override { return {400, 300}; }
575 };
576 }  // namespace
577 
578 DEF_GM(return new AyncYUVNoScaleGM();)
579 
580 namespace {
581 class AsyncRescaleAndReadNoBleedGM : public AsyncReadGMBase {
582 public:
AsyncRescaleAndReadNoBleedGM()583     AsyncRescaleAndReadNoBleedGM() : AsyncReadGMBase("async_rescale_and_read_no_bleed") {}
584 
getISize()585     SkISize getISize() override { return {60, 60}; }
586 
onDraw(SkCanvas * canvas,SkString * errorMsg)587     DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
588         if (canvas->imageInfo().colorType() == kUnknown_SkColorType) {
589             *errorMsg = "Not supported on recording/vector backends.";
590             return skiagm::DrawResult::kSkip;
591         }
592 
593         auto dContext = GrAsDirectContext(canvas->recordingContext());
594         if (!dContext && canvas->recordingContext()) {
595             *errorMsg = "Not supported in DDL mode";
596             return skiagm::DrawResult::kSkip;
597         }
598 
599         static constexpr int kBorder = 5;
600         static constexpr int kInner = 5;
601         const auto srcRect = SkIRect::MakeXYWH(kBorder, kBorder, kInner, kInner);
602         auto surfaceII = SkImageInfo::Make(kInner + 2 * kBorder,
603                                            kInner + 2 * kBorder,
604                                            kRGBA_8888_SkColorType,
605                                            kPremul_SkAlphaType,
606                                            SkColorSpace::MakeSRGB());
607         auto surface = canvas->makeSurface(surfaceII);
608         if (!surface) {
609             *errorMsg = "Could not create surface for image.";
610             // When testing abandoned GrContext we expect surface creation to fail.
611             if (canvas->recordingContext() && canvas->recordingContext()->abandoned()) {
612                 return skiagm::DrawResult::kSkip;
613             }
614             return skiagm::DrawResult::kFail;
615         }
616         surface->getCanvas()->clear(SK_ColorRED);
617         surface->getCanvas()->save();
618         surface->getCanvas()->clipRect(SkRect::Make(srcRect), SkClipOp::kIntersect, false);
619         surface->getCanvas()->clear(SK_ColorBLUE);
620         surface->getCanvas()->restore();
621         static constexpr int kPad = 2;
622         canvas->translate(kPad, kPad);
623         skiagm::DrawResult result;
624         SkISize downSize = {static_cast<int>(kInner / 2), static_cast<int>(kInner / 2)};
625         result = drawRescaleGrid<ReadSource::kSurface>(canvas,
626                                                        surface.get(),
627                                                        srcRect,
628                                                        downSize,
629                                                        Type::kRGBA,
630                                                        errorMsg,
631                                                        kPad);
632         if (result != skiagm::DrawResult::kOk) {
633             return result;
634         }
635         canvas->translate(0, 4 * downSize.height());
636         SkISize upSize = {static_cast<int>(kInner * 3.5), static_cast<int>(kInner * 4.6)};
637         result = drawRescaleGrid<ReadSource::kSurface>(canvas,
638                                                        surface.get(),
639                                                        srcRect,
640                                                        upSize,
641                                                        Type::kRGBA,
642                                                        errorMsg,
643                                                        kPad);
644         if (result != skiagm::DrawResult::kOk) {
645             return result;
646         }
647         return skiagm::DrawResult::kOk;
648     }
649 };
650 }  // namespace
651 
652 DEF_GM(return new AsyncRescaleAndReadNoBleedGM();)
653 
654 namespace {
655 class AsyncRescaleAndReadAlphaTypeGM : public AsyncReadGMBase {
656 public:
AsyncRescaleAndReadAlphaTypeGM()657     AsyncRescaleAndReadAlphaTypeGM() : AsyncReadGMBase("async_rescale_and_read_alpha_type") {}
658 
getISize()659     SkISize getISize() override { return {512, 512}; }
660 
onDraw(SkCanvas * canvas,SkString * errorMsg)661     DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
662         auto dContext = GrAsDirectContext(canvas->recordingContext());
663         if (!dContext && canvas->recordingContext()) {
664             *errorMsg = "Not supported in DDL mode";
665             return skiagm::DrawResult::kSkip;
666         }
667 
668         if (canvas->recorder()) {
669             *errorMsg = "Reading to unpremul not supported in Graphite.";
670             return skiagm::DrawResult::kSkip;
671         }
672 
673         auto upmII = SkImageInfo::Make(200, 200, kRGBA_8888_SkColorType, kUnpremul_SkAlphaType);
674 
675         auto pmII = upmII.makeAlphaType(kPremul_SkAlphaType);
676 
677         auto upmSurf = SkSurfaces::Raster(upmII);
678         auto pmSurf = SkSurfaces::Raster(pmII);
679 
680         SkColor4f colors[] = {
681                 {.3f, .3f, .3f, .3f},
682                 {1.f, .2f, .6f, .9f},
683                 {0.f, .1f, 1.f, .1f},
684                 {.7f, .8f, .2f, .7f},
685         };
686         auto shader = SkGradientShader::MakeRadial({100, 100},
687                                                    230,
688                                                    colors,
689                                                    nullptr,
690                                                    nullptr,
691                                                    std::size(colors),
692                                                    SkTileMode::kRepeat);
693         SkPaint paint;
694         paint.setShader(std::move(shader));
695 
696         upmSurf->getCanvas()->drawPaint(paint);
697         pmSurf ->getCanvas()->drawPaint(paint);
698 
699         auto pmImg  =  pmSurf->makeImageSnapshot();
700         auto upmImg = upmSurf->makeImageSnapshot();
701 
702         auto imageOrResult = convert_image_to_source<ReadSource::kImage>(canvas,
703                                                                          std::move(pmImg),
704                                                                          errorMsg);
705         if (const auto* dr = std::get_if<skiagm::DrawResult>(&imageOrResult)) {
706             return *dr;
707         }
708         pmImg = std::move(std::get<sk_sp<SkImage>>(imageOrResult));
709 
710         imageOrResult = convert_image_to_source<ReadSource::kImage>(canvas,
711                                                                     std::move(upmImg),
712                                                                     errorMsg);
713         if (const auto* dr = std::get_if<skiagm::DrawResult>(&imageOrResult)) {
714             return *dr;
715         }
716         upmImg = std::move(std::get<sk_sp<SkImage>>(imageOrResult));
717 
718         int size = 256;
719 
720         ToolUtils::draw_checkerboard(canvas, SK_ColorWHITE, SK_ColorBLACK, 32);
721 
722         for (const auto& img : {pmImg, upmImg}) {
723             canvas->save();
724             for (auto readAT : {kPremul_SkAlphaType, kUnpremul_SkAlphaType}) {
725                 auto readInfo = img->imageInfo().makeAlphaType(readAT).makeWH(size, size);
726                 auto result =
727                         readAndScaleRGBA<ReadSource::kImage>(img.get(),
728                                                              SkIRect::MakeSize(img->dimensions()),
729                                                              dContext,
730                                                              canvas->recorder(),
731                                                              readInfo,
732                                                              SkImage::RescaleGamma::kSrc,
733                                                              SkImage::RescaleMode::kRepeatedCubic);
734                 if (!result) {
735                     *errorMsg = "async readback failed";
736                     return skiagm::DrawResult::kFail;
737                 }
738                 canvas->drawImage(result, 0, 0);
739                 canvas->translate(size, 0);
740             }
741             canvas->restore();
742             canvas->translate(0, size);
743         }
744         return skiagm::DrawResult::kOk;
745     }
746 };
747 }  // namespace
748 
749 DEF_GM(return new AsyncRescaleAndReadAlphaTypeGM();)
750