• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 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 "include/core/SkAlphaType.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkColorSpace.h"
11 #include "include/core/SkColorType.h"
12 #include "include/core/SkPixmap.h"
13 #include "include/core/SkSurface.h"
14 #include "include/effects/SkGradientShader.h"
15 #include "include/gpu/GpuTypes.h"
16 #include "include/gpu/graphite/BackendTexture.h"
17 #include "include/gpu/graphite/Context.h"
18 #include "include/gpu/graphite/Image.h"
19 #include "include/gpu/graphite/Recorder.h"
20 #include "include/gpu/graphite/Recording.h"
21 #include "include/gpu/graphite/Surface.h"
22 #include "include/gpu/graphite/TextureInfo.h"
23 #include "src/base/SkRectMemcpy.h"
24 #include "src/core/SkAutoPixmapStorage.h"
25 #include "src/core/SkImageInfoPriv.h"
26 #include "src/gpu/graphite/Caps.h"
27 #include "src/gpu/graphite/ContextPriv.h"
28 #include "src/gpu/graphite/RecorderPriv.h"
29 #include "src/gpu/graphite/ResourceTypes.h"
30 #include "tests/Test.h"
31 #include "tests/TestUtils.h"
32 #include "tools/ToolUtils.h"
33 #include "tools/gpu/BackendTextureImageFactory.h"
34 #include "tools/gpu/ManagedBackendTexture.h"
35 #include "tools/graphite/GraphiteTestContext.h"
36 
37 using Mipmapped = skgpu::Mipmapped;
38 
min_rgb_channel_bits(SkColorType ct)39 static constexpr int min_rgb_channel_bits(SkColorType ct) {
40     switch (ct) {
41         case kUnknown_SkColorType:            return 0;
42         case kAlpha_8_SkColorType:            return 0;
43         case kA16_unorm_SkColorType:          return 0;
44         case kA16_float_SkColorType:          return 0;
45         case kRGB_565_SkColorType:            return 5;
46         case kARGB_4444_SkColorType:          return 4;
47         case kR8G8_unorm_SkColorType:         return 8;
48         case kR16G16_unorm_SkColorType:       return 16;
49         case kR16G16_float_SkColorType:       return 16;
50         case kRGBA_8888_SkColorType:          return 8;
51         case kSRGBA_8888_SkColorType:         return 8;
52         case kRGB_888x_SkColorType:           return 8;
53         case kBGRA_8888_SkColorType:          return 8;
54         case kRGBA_1010102_SkColorType:       return 10;
55         case kRGB_101010x_SkColorType:        return 10;
56         case kBGRA_1010102_SkColorType:       return 10;
57         case kBGR_101010x_SkColorType:        return 10;
58         case kBGR_101010x_XR_SkColorType:     return 10;
59         case kRGBA_10x6_SkColorType:          return 10;
60         case kBGRA_10101010_XR_SkColorType:   return 10;
61         case kGray_8_SkColorType:             return 8;   // counting gray as "rgb"
62         case kRGBA_F16Norm_SkColorType:       return 10;  // just counting the mantissa
63         case kRGBA_F16_SkColorType:           return 10;  // just counting the mantissa
64         case kRGBA_F32_SkColorType:           return 23;  // just counting the mantissa
65         case kR16G16B16A16_unorm_SkColorType: return 16;
66         case kR8_unorm_SkColorType:           return 8;
67     }
68     SkUNREACHABLE;
69 }
70 
alpha_channel_bits(SkColorType ct)71 static constexpr int alpha_channel_bits(SkColorType ct) {
72     switch (ct) {
73         case kUnknown_SkColorType:            return 0;
74         case kAlpha_8_SkColorType:            return 8;
75         case kA16_unorm_SkColorType:          return 16;
76         case kA16_float_SkColorType:          return 16;
77         case kRGB_565_SkColorType:            return 0;
78         case kARGB_4444_SkColorType:          return 4;
79         case kR8G8_unorm_SkColorType:         return 0;
80         case kR16G16_unorm_SkColorType:       return 0;
81         case kR16G16_float_SkColorType:       return 0;
82         case kRGBA_8888_SkColorType:          return 8;
83         case kSRGBA_8888_SkColorType:         return 8;
84         case kRGB_888x_SkColorType:           return 0;
85         case kBGRA_8888_SkColorType:          return 8;
86         case kRGBA_1010102_SkColorType:       return 2;
87         case kRGB_101010x_SkColorType:        return 0;
88         case kBGRA_1010102_SkColorType:       return 2;
89         case kBGR_101010x_SkColorType:        return 0;
90         case kBGR_101010x_XR_SkColorType:     return 0;
91         case kRGBA_10x6_SkColorType:          return 10;
92         case kBGRA_10101010_XR_SkColorType:   return 10;
93         case kGray_8_SkColorType:             return 0;
94         case kRGBA_F16Norm_SkColorType:       return 10;  // just counting the mantissa
95         case kRGBA_F16_SkColorType:           return 10;  // just counting the mantissa
96         case kRGBA_F32_SkColorType:           return 23;  // just counting the mantissa
97         case kR16G16B16A16_unorm_SkColorType: return 16;
98         case kR8_unorm_SkColorType:           return 0;
99     }
100     SkUNREACHABLE;
101 }
102 
103 namespace {
make_long_rect_array(int w,int h)104 std::vector<SkIRect> make_long_rect_array(int w, int h) {
105     return {
106             // entire thing
107             SkIRect::MakeWH(w, h),
108             // larger on all sides
109             SkIRect::MakeLTRB(-10, -10, w + 10, h + 10),
110             // fully contained
111             SkIRect::MakeLTRB(w/4, h/4, 3*w/4, 3*h/4),
112             // outside top left
113             SkIRect::MakeLTRB(-10, -10, -1, -1),
114             // touching top left corner
115             SkIRect::MakeLTRB(-10, -10, 0, 0),
116             // overlapping top left corner
117             SkIRect::MakeLTRB(-10, -10, w/4, h/4),
118             // overlapping top left and top right corners
119             SkIRect::MakeLTRB(-10, -10, w + 10, h/4),
120             // touching entire top edge
121             SkIRect::MakeLTRB(-10, -10, w + 10, 0),
122             // overlapping top right corner
123             SkIRect::MakeLTRB(3*w/4, -10, w + 10, h/4),
124             // contained in x, overlapping top edge
125             SkIRect::MakeLTRB(w/4, -10, 3*w/4, h/4),
126             // outside top right corner
127             SkIRect::MakeLTRB(w + 1, -10, w + 10, -1),
128             // touching top right corner
129             SkIRect::MakeLTRB(w, -10, w + 10, 0),
130             // overlapping top left and bottom left corners
131             SkIRect::MakeLTRB(-10, -10, w/4, h + 10),
132             // touching entire left edge
133             SkIRect::MakeLTRB(-10, -10, 0, h + 10),
134             // overlapping bottom left corner
135             SkIRect::MakeLTRB(-10, 3*h/4, w/4, h + 10),
136             // contained in y, overlapping left edge
137             SkIRect::MakeLTRB(-10, h/4, w/4, 3*h/4),
138             // outside bottom left corner
139             SkIRect::MakeLTRB(-10, h + 1, -1, h + 10),
140             // touching bottom left corner
141             SkIRect::MakeLTRB(-10, h, 0, h + 10),
142             // overlapping bottom left and bottom right corners
143             SkIRect::MakeLTRB(-10, 3*h/4, w + 10, h + 10),
144             // touching entire left edge
145             SkIRect::MakeLTRB(0, h, w, h + 10),
146             // overlapping bottom right corner
147             SkIRect::MakeLTRB(3*w/4, 3*h/4, w + 10, h + 10),
148             // overlapping top right and bottom right corners
149             SkIRect::MakeLTRB(3*w/4, -10, w + 10, h + 10),
150     };
151 }
152 
make_short_rect_array(int w,int h)153 std::vector<SkIRect> make_short_rect_array(int w, int h) {
154     return {
155             // entire thing
156             SkIRect::MakeWH(w, h),
157             // fully contained
158             SkIRect::MakeLTRB(w/4, h/4, 3*w/4, 3*h/4),
159             // overlapping top right corner
160             SkIRect::MakeLTRB(3*w/4, -10, w + 10, h/4),
161     };
162 }
163 
164 struct GraphiteReadPixelTestRules {
165     // Test unpremul sources? We could omit this and detect that creating the source of the read
166     // failed but having it lets us skip generating reference color data.
167     bool fAllowUnpremulSrc = true;
168     // Are reads that are overlapping but not contained by the src bounds expected to succeed?
169     bool fUncontainedRectSucceeds = true;
170 };
171 
172 // Makes a src populated with the pixmap. The src should get its image info (or equivalent) from
173 // the pixmap.
174 template <typename T> using GraphiteSrcFactory = T(skgpu::graphite::Recorder*, SkPixmap&);
175 
176 enum class Result {
177     kFail,
178     kSuccess,
179     kExcusedFailure,
180 };
181 
182 // Does a read from the T into the pixmap.
183 template <typename T>
184 using GraphiteReadSrcFn = Result(const T&, const SkIPoint& offset, const SkPixmap&);
185 
make_ref_data(const SkImageInfo & info,bool forceOpaque)186 static SkAutoPixmapStorage make_ref_data(const SkImageInfo& info, bool forceOpaque) {
187     SkAutoPixmapStorage result;
188     if (info.alphaType() == kUnknown_SkAlphaType) {
189         result.alloc(info.makeAlphaType(kUnpremul_SkAlphaType));
190     } else {
191         result.alloc(info);
192     }
193     auto surface = SkSurfaces::WrapPixels(result);
194     if (!surface) {
195         return result;
196     }
197 
198     SkPoint pts1[] = {{0, 0}, {float(info.width()), float(info.height())}};
199     static constexpr SkColor kColors1[] = {SK_ColorGREEN, SK_ColorRED};
200     SkPaint paint;
201     paint.setShader(SkGradientShader::MakeLinear(pts1, kColors1, nullptr, 2, SkTileMode::kClamp));
202     surface->getCanvas()->drawPaint(paint);
203 
204     SkPoint pts2[] = {{float(info.width()), 0}, {0, float(info.height())}};
205     static constexpr SkColor kColors2[] = {SK_ColorBLUE, SK_ColorBLACK};
206     paint.setShader(SkGradientShader::MakeLinear(pts2, kColors2, nullptr, 2, SkTileMode::kClamp));
207     paint.setBlendMode(SkBlendMode::kPlus);
208     surface->getCanvas()->drawPaint(paint);
209 
210     // If not opaque add some fractional alpha.
211     if (info.alphaType() != kOpaque_SkAlphaType && !forceOpaque) {
212         static constexpr SkColor kColors3[] = {SK_ColorWHITE,
213                                                SK_ColorWHITE,
214                                                0x60FFFFFF,
215                                                SK_ColorWHITE,
216                                                SK_ColorWHITE};
217         static constexpr SkScalar kPos3[] = {0.f, 0.15f, 0.5f, 0.85f, 1.f};
218         paint.setShader(SkGradientShader::MakeRadial({info.width()/2.f, info.height()/2.f},
219                                                      (info.width() + info.height())/10.f,
220                                                      kColors3, kPos3, 5, SkTileMode::kMirror));
221         paint.setBlendMode(SkBlendMode::kDstIn);
222         surface->getCanvas()->drawPaint(paint);
223     }
224     return result;
225 };
226 }  // anonymous namespace
227 
228 template <typename T>
graphite_read_pixels_test_driver(skiatest::Reporter * reporter,skgpu::graphite::Context * context,const GraphiteReadPixelTestRules & rules,const std::function<GraphiteSrcFactory<T>> & srcFactory,const std::function<GraphiteReadSrcFn<T>> & read,SkString label)229 static void graphite_read_pixels_test_driver(skiatest::Reporter* reporter,
230                                              skgpu::graphite::Context* context,
231                                              const GraphiteReadPixelTestRules& rules,
232                                              const std::function<GraphiteSrcFactory<T>>& srcFactory,
233                                              const std::function<GraphiteReadSrcFn<T>>& read,
234                                              SkString label) {
235     if (!label.isEmpty()) {
236         // Add space for printing.
237         label.append(" ");
238     }
239     // Separate this out just to give it some line width to breathe. Note 'srcPixels' should have
240     // the same image info as src. We will do a converting readPixels() on it to get the data
241     // to compare with the results of 'read'.
242     auto runTest = [&](const T& src,
243                        const SkPixmap& srcPixels,
244                        const SkImageInfo& readInfo,
245                        SkIPoint offset) {
246         const bool csConversion =
247                 !SkColorSpace::Equals(readInfo.colorSpace(), srcPixels.info().colorSpace());
248         const auto readCT = readInfo.colorType();
249         const auto readAT = readInfo.alphaType();
250         const auto srcCT = srcPixels.info().colorType();
251         const auto srcAT = srcPixels.info().alphaType();
252         const auto rect = SkIRect::MakeWH(readInfo.width(), readInfo.height()).makeOffset(offset);
253         const auto surfBounds = SkIRect::MakeWH(srcPixels.width(), srcPixels.height());
254         const size_t readBpp = SkColorTypeBytesPerPixel(readCT);
255 
256         // Make the row bytes in the dst be loose for extra stress.
257         const size_t dstRB = readBpp * readInfo.width() + 10 * readBpp;
258         // This will make the last row tight.
259         const size_t dstSize = readInfo.computeByteSize(dstRB);
260         std::unique_ptr<char[]> dstData(new char[dstSize]);
261         SkPixmap dstPixels(readInfo, dstData.get(), dstRB);
262         // Initialize with an arbitrary value for each byte. Later we will check that only the
263         // correct part of the destination gets overwritten by 'read'.
264         static constexpr auto kInitialByte = static_cast<char>(0x1B);
265         std::fill_n(static_cast<char*>(dstPixels.writable_addr()),
266                     dstPixels.computeByteSize(),
267                     kInitialByte);
268 
269         const Result result = read(src, offset, dstPixels);
270 
271         if (!SkIRect::Intersects(rect, surfBounds)) {
272             REPORTER_ASSERT(reporter, result != Result::kSuccess);
273         } else if (readCT == kUnknown_SkColorType) {
274             REPORTER_ASSERT(reporter, result != Result::kSuccess);
275         } else if (readAT == kUnknown_SkAlphaType) {
276             REPORTER_ASSERT(reporter, result != Result::kSuccess);
277         } else if (!rules.fUncontainedRectSucceeds && !surfBounds.contains(rect)) {
278             REPORTER_ASSERT(reporter, result != Result::kSuccess);
279         } else if (result == Result::kFail) {
280             // TODO: Support RGB/BGR 101010x, BGRA 1010102 on the GPU.
281             ERRORF(reporter,
282                    "Read failed. %sSrc CT: %s, Src AT: %s Read CT: %s, Read AT: %s, "
283                    "Rect [%d, %d, %d, %d], CS conversion: %d\n",
284                    label.c_str(),
285                    ToolUtils::colortype_name(srcCT), ToolUtils::alphatype_name(srcAT),
286                    ToolUtils::colortype_name(readCT), ToolUtils::alphatype_name(readAT),
287                    rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, csConversion);
288             return result;
289         }
290 
291         bool guardOk = true;
292         auto guardCheck = [](char x) { return x == kInitialByte; };
293 
294         // Considering the rect we tried to read and the surface bounds figure  out which pixels in
295         // both src and dst space should actually have been read and written.
296         SkIRect srcReadRect;
297         if (result == Result::kSuccess && srcReadRect.intersect(surfBounds, rect)) {
298             SkIRect dstWriteRect = srcReadRect.makeOffset(-rect.fLeft, -rect.fTop);
299 
300             const bool lumConversion =
301                     !(SkColorTypeChannelFlags(srcCT) & kGray_SkColorChannelFlag) &&
302                     (SkColorTypeChannelFlags(readCT) & kGray_SkColorChannelFlag);
303             // A CS or luminance conversion allows a 3 value difference and otherwise a 2 value
304             // difference. Note that sometimes read back on GPU can be lossy even when there no
305             // conversion at all because GPU->CPU read may go to a lower bit depth format and then
306             // be promoted back to the original type. For example, GL ES cannot read to 1010102, so
307             // we go through 8888.
308             float numer = (lumConversion || csConversion) ? 3.f : 2.f;
309             // Allow some extra tolerance if unpremuling.
310             if (srcAT == kPremul_SkAlphaType && readAT == kUnpremul_SkAlphaType) {
311                 numer += 1;
312             }
313             int rgbBits = std::min({min_rgb_channel_bits(readCT), min_rgb_channel_bits(srcCT), 8});
314             float tol = numer / (1 << rgbBits);
315             float alphaTol = 0;
316             if (readAT != kOpaque_SkAlphaType && srcAT != kOpaque_SkAlphaType) {
317                 // Alpha can also get squashed down to 8 bits going through an intermediate
318                 // color format.
319                 const int alphaBits = std::min({alpha_channel_bits(readCT),
320                                                 alpha_channel_bits(srcCT),
321                                                 8});
322                 alphaTol = 2.f / (1 << alphaBits);
323             }
324 
325             const float tols[4] = {tol, tol, tol, alphaTol};
326             auto error = std::function<ComparePixmapsErrorReporter>([&](int x, int y,
327                                                                         const float diffs[4]) {
328                 SkASSERT(x >= 0 && y >= 0);
329                 ERRORF(reporter,
330                        "%sSrc CT: %s, Src AT: %s, Read CT: %s, Read AT: %s, Rect [%d, %d, %d, %d]"
331                        ", CS conversion: %d\n"
332                        "Error at %d, %d. Diff in floats: (%f, %f, %f, %f)",
333                        label.c_str(),
334                        ToolUtils::colortype_name(srcCT), ToolUtils::alphatype_name(srcAT),
335                        ToolUtils::colortype_name(readCT), ToolUtils::alphatype_name(readAT),
336                        rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, csConversion, x, y,
337                        diffs[0], diffs[1], diffs[2], diffs[3]);
338             });
339             SkAutoPixmapStorage ref;
340             SkImageInfo refInfo = readInfo.makeDimensions(dstWriteRect.size());
341             ref.alloc(refInfo);
342             if (readAT == kUnknown_SkAlphaType) {
343                 // Do a spoofed read where src and dst alpha type are both kUnpremul. This will
344                 // allow SkPixmap readPixels to succeed and won't do any alpha type conversion.
345                 SkPixmap unpremulRef(refInfo.makeAlphaType(kUnpremul_SkAlphaType),
346                                      ref.addr(),
347                                      ref.rowBytes());
348                 SkPixmap unpremulSrc(srcPixels.info().makeAlphaType(kUnpremul_SkAlphaType),
349                                      srcPixels.addr(),
350                                      srcPixels.rowBytes());
351 
352                 unpremulSrc.readPixels(unpremulRef, srcReadRect.x(), srcReadRect.y());
353             } else {
354                 srcPixels.readPixels(ref, srcReadRect.x(), srcReadRect.y());
355             }
356             // This is the part of dstPixels that should have been updated.
357             SkPixmap actual;
358             SkAssertResult(dstPixels.extractSubset(&actual, dstWriteRect));
359             ComparePixels(ref, actual, tols, error);
360 
361             const auto* v = dstData.get();
362             const auto* end = dstData.get() + dstSize;
363             guardOk = std::all_of(v, v + dstWriteRect.top() * dstPixels.rowBytes(), guardCheck);
364             v += dstWriteRect.top() * dstPixels.rowBytes();
365             for (int y = dstWriteRect.top(); y < dstWriteRect.bottom(); ++y) {
366                 guardOk |= std::all_of(v, v + dstWriteRect.left() * readBpp, guardCheck);
367                 auto pad = v + dstWriteRect.right() * readBpp;
368                 auto rowEnd = std::min(end, v + dstPixels.rowBytes());
369                 // min protects against reading past the end of the tight last row.
370                 guardOk |= std::all_of(pad, rowEnd, guardCheck);
371                 v = rowEnd;
372             }
373             guardOk |= std::all_of(v, end, guardCheck);
374         } else {
375             guardOk = std::all_of(dstData.get(), dstData.get() + dstSize, guardCheck);
376         }
377         if (!guardOk) {
378             ERRORF(reporter,
379                    "Result pixels modified result outside read rect [%d, %d, %d, %d]. "
380                    "%sSrc CT: %s, Read CT: %s, CS conversion: %d",
381                    rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, label.c_str(),
382                    ToolUtils::colortype_name(srcCT), ToolUtils::colortype_name(readCT),
383                    csConversion);
384         }
385         return result;
386     };
387 
388     static constexpr int kW = 16;
389     static constexpr int kH = 16;
390 
391     const std::vector<SkIRect> longRectArray = make_long_rect_array(kW, kH);
392     const std::vector<SkIRect> shortRectArray = make_short_rect_array(kW, kH);
393 
394     // We ensure we use the long array once per src and read color type and otherwise use the
395     // short array to improve test run time.
396     // Also, some color types have no alpha values and thus Opaque Premul and Unpremul are
397     // equivalent. Just ensure each redundant AT is tested once with each CT (src and read).
398     // Similarly, alpha-only color types behave the same for all alpha types so just test premul
399     // after one iter.
400     // We consider a src or read CT thoroughly tested once it has run through the long rect array
401     // and full complement of alpha types with one successful read in the loop.
402     std::array<bool, kLastEnum_SkColorType + 1> srcCTTestedThoroughly  = {},
403                                                 readCTTestedThoroughly = {};
404     for (int sat = 0; sat <= kLastEnum_SkAlphaType; ++sat) {
405         const auto srcAT = static_cast<SkAlphaType>(sat);
406         if (srcAT == kUnpremul_SkAlphaType && !rules.fAllowUnpremulSrc) {
407             continue;
408         }
409         for (int sct = 0; sct <= kLastEnum_SkColorType; ++sct) {
410             const auto srcCT = static_cast<SkColorType>(sct);
411             // We always make our ref data as F32
412             auto refInfo = SkImageInfo::Make(kW, kH,
413                                              kRGBA_F32_SkColorType,
414                                              srcAT,
415                                              SkColorSpace::MakeSRGB());
416             // 1010102 formats have an issue where it's easy to make a resulting
417             // color where r, g, or b is greater than a. CPU/GPU differ in whether the stored color
418             // channels are clipped to the alpha value. CPU clips but GPU does not.
419             // Note that we only currently use srcCT for the 1010102 workaround. If we remove this
420             // we can also put the ref data setup above the srcCT loop.
421             bool forceOpaque = srcAT == kPremul_SkAlphaType &&
422                     (srcCT == kRGBA_1010102_SkColorType || srcCT == kBGRA_1010102_SkColorType);
423 
424             SkAutoPixmapStorage refPixels = make_ref_data(refInfo, forceOpaque);
425             // Convert the ref data to our desired src color type.
426             const auto srcInfo = SkImageInfo::Make(kW, kH, srcCT, srcAT, SkColorSpace::MakeSRGB());
427             SkAutoPixmapStorage srcPixels;
428             srcPixels.alloc(srcInfo);
429             {
430                 SkPixmap readPixmap = srcPixels;
431                 // Spoof the alpha type to kUnpremul so the read will succeed without doing any
432                 // conversion (because we made our surface also use kUnpremul).
433                 if (srcAT == kUnknown_SkAlphaType) {
434                     readPixmap.reset(srcPixels.info().makeAlphaType(kUnpremul_SkAlphaType),
435                                      srcPixels.addr(),
436                                      srcPixels.rowBytes());
437                 }
438                 refPixels.readPixels(readPixmap, 0, 0);
439             }
440 
441             std::unique_ptr<skgpu::graphite::Recorder> recorder = context->makeRecorder();
442 
443             auto src = srcFactory(recorder.get(), srcPixels);
444             if (!src) {
445                 continue;
446             }
447             if (SkColorTypeIsAlwaysOpaque(srcCT) && srcCTTestedThoroughly[srcCT] &&
448                 (kPremul_SkAlphaType == srcAT || kUnpremul_SkAlphaType == srcAT)) {
449                 continue;
450             }
451             if (SkColorTypeIsAlphaOnly(srcCT) && srcCTTestedThoroughly[srcCT] &&
452                 (kUnpremul_SkAlphaType == srcAT ||
453                  kOpaque_SkAlphaType   == srcAT ||
454                  kUnknown_SkAlphaType  == srcAT)) {
455                 continue;
456             }
457             for (int rct = 0; rct <= kLastEnum_SkColorType; ++rct) {
458                 const auto readCT = static_cast<SkColorType>(rct);
459                 // ComparePixels will end up converting these types to kUnknown
460                 // because there's no corresponding GrColorType, and hence it will fail
461                 if (readCT == kRGB_101010x_SkColorType ||
462                     readCT == kBGR_101010x_XR_SkColorType ||
463                     readCT == kBGRA_10101010_XR_SkColorType ||
464                     readCT == kBGR_101010x_SkColorType) {
465                     continue;
466                 }
467                 for (const sk_sp<SkColorSpace>& readCS :
468                      {SkColorSpace::MakeSRGB(), SkColorSpace::MakeSRGBLinear()}) {
469                     for (int at = 0; at <= kLastEnum_SkAlphaType; ++at) {
470                         const auto readAT = static_cast<SkAlphaType>(at);
471                         if (srcAT != kOpaque_SkAlphaType && readAT == kOpaque_SkAlphaType) {
472                             // This doesn't make sense.
473                             continue;
474                         }
475                         if (SkColorTypeIsAlwaysOpaque(readCT) && readCTTestedThoroughly[readCT] &&
476                             (kPremul_SkAlphaType == readAT || kUnpremul_SkAlphaType == readAT)) {
477                             continue;
478                         }
479                         if (SkColorTypeIsAlphaOnly(readCT) && readCTTestedThoroughly[readCT] &&
480                             (kUnpremul_SkAlphaType == readAT ||
481                              kOpaque_SkAlphaType   == readAT ||
482                              kUnknown_SkAlphaType  == readAT)) {
483                             continue;
484                         }
485                         const auto& rects =
486                                 srcCTTestedThoroughly[sct] && readCTTestedThoroughly[rct]
487                                         ? shortRectArray
488                                         : longRectArray;
489                         for (const auto& rect : rects) {
490                             const auto readInfo = SkImageInfo::Make(rect.width(), rect.height(),
491                                                                     readCT, readAT, readCS);
492                             const SkIPoint offset = rect.topLeft();
493                             Result r = runTest(src, srcPixels, readInfo, offset);
494                             if (r == Result::kSuccess) {
495                                 srcCTTestedThoroughly[sct] = true;
496                                 readCTTestedThoroughly[rct] = true;
497                             }
498                         }
499                     }
500                 }
501             }
502         }
503     }
504 }
505 
506 namespace {
507 struct AsyncContext {
508     bool fCalled = false;
509     std::unique_ptr<const SkImage::AsyncReadResult> fResult;
510 };
511 }  // anonymous namespace
512 
513 // Making this a lambda in the test functions caused:
514 //   "error: cannot compile this forwarded non-trivially copyable parameter yet"
515 // on x86/Win/Clang bot, referring to 'result'.
async_callback(void * c,std::unique_ptr<const SkImage::AsyncReadResult> result)516 static void async_callback(void* c, std::unique_ptr<const SkImage::AsyncReadResult> result) {
517     auto context = static_cast<AsyncContext*>(c);
518     context->fResult = std::move(result);
519     context->fCalled = true;
520 };
521 
DEF_CONDITIONAL_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(ImageAsyncReadPixelsGraphite,reporter,context,testContext,true,CtsEnforcement::kNextRelease)522 DEF_CONDITIONAL_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(ImageAsyncReadPixelsGraphite,
523                                                      reporter,
524                                                      context,
525                                                      testContext,
526                                                      true,
527                                                      CtsEnforcement::kNextRelease) {
528     using Image = sk_sp<SkImage>;
529     using Renderable = skgpu::Renderable;
530     using TextureInfo = skgpu::graphite::TextureInfo;
531 
532     auto reader = std::function<GraphiteReadSrcFn<Image>>([context, testContext](
533                                                                   const Image& image,
534                                                                   const SkIPoint& offset,
535                                                                   const SkPixmap& pixels) {
536         AsyncContext asyncContext;
537         auto rect = SkIRect::MakeSize(pixels.dimensions()).makeOffset(offset);
538         // The GPU implementation is based on rendering and will fail for non-renderable color
539         // types.
540         TextureInfo texInfo = context->priv().caps()->getDefaultSampledTextureInfo(
541                 image->colorType(),
542                 Mipmapped::kNo,
543                 skgpu::Protected::kNo,
544                 Renderable::kYes);
545         if (!context->priv().caps()->isRenderable(texInfo)) {
546             return Result::kExcusedFailure;
547         }
548 
549         context->asyncRescaleAndReadPixels(image.get(),
550                                            pixels.info(),
551                                            rect,
552                                            SkImage::RescaleGamma::kSrc,
553                                            SkImage::RescaleMode::kRepeatedLinear,
554                                            async_callback,
555                                            &asyncContext);
556         if (!asyncContext.fCalled) {
557             context->submit();
558         }
559         while (!asyncContext.fCalled) {
560             testContext->tick();
561             context->checkAsyncWorkCompletion();
562         }
563         if (!asyncContext.fResult) {
564             return Result::kFail;
565         }
566         SkRectMemcpy(pixels.writable_addr(), pixels.rowBytes(), asyncContext.fResult->data(0),
567                      asyncContext.fResult->rowBytes(0), pixels.info().minRowBytes(),
568                      pixels.height());
569         return Result::kSuccess;
570     });
571 
572     GraphiteReadPixelTestRules rules;
573     rules.fAllowUnpremulSrc = true;
574     rules.fUncontainedRectSucceeds = false;
575 
576     for (auto renderable : {Renderable::kNo, Renderable::kYes}) {
577         auto factory = std::function<GraphiteSrcFactory<Image>>([&](
578                 skgpu::graphite::Recorder* recorder,
579                 const SkPixmap& src) {
580             Image image = sk_gpu_test::MakeBackendTextureImage(recorder,
581                                                                src,
582                                                                Mipmapped::kNo,
583                                                                renderable,
584                                                                skgpu::Origin::kTopLeft,
585                                                                skgpu::Protected::kNo);
586 
587             std::unique_ptr<skgpu::graphite::Recording> recording = recorder->snap();
588             skgpu::graphite::InsertRecordingInfo recordingInfo;
589             recordingInfo.fRecording = recording.get();
590             context->insertRecording(recordingInfo);
591 
592             return image;
593         });
594         auto label = SkStringPrintf("Renderable: %d", (int)renderable);
595         graphite_read_pixels_test_driver(reporter, context, rules, factory, reader, label);
596     }
597 
598     // It's possible that we've created an Image using the factory, but then don't try to do
599     // readPixels on it, leaving a hanging command buffer. So we submit here to clean up.
600     context->submit();
601 }
602 
DEF_CONDITIONAL_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(SurfaceAsyncReadPixelsGraphite,reporter,context,testContext,true,CtsEnforcement::kNextRelease)603 DEF_CONDITIONAL_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(SurfaceAsyncReadPixelsGraphite,
604                                                      reporter,
605                                                      context,
606                                                      testContext,
607                                                      true,
608                                                      CtsEnforcement::kNextRelease) {
609     using Surface = sk_sp<SkSurface>;
610 
611     auto reader = std::function<GraphiteReadSrcFn<Surface>>([context, testContext](
612                                                                     const Surface& surface,
613                                                                     const SkIPoint& offset,
614                                                                     const SkPixmap& pixels) {
615         AsyncContext asyncContext;
616         auto rect = SkIRect::MakeSize(pixels.dimensions()).makeOffset(offset);
617 
618         context->asyncRescaleAndReadPixels(surface.get(),
619                                            pixels.info(),
620                                            rect,
621                                            SkImage::RescaleGamma::kSrc,
622                                            SkImage::RescaleMode::kRepeatedLinear,
623                                            async_callback,
624                                            &asyncContext);
625         if (!asyncContext.fCalled) {
626             context->submit();
627         }
628         while (!asyncContext.fCalled) {
629             testContext->tick();
630             context->checkAsyncWorkCompletion();
631         }
632         if (!asyncContext.fResult) {
633             return Result::kFail;
634         }
635         SkRectMemcpy(pixels.writable_addr(), pixels.rowBytes(), asyncContext.fResult->data(0),
636                      asyncContext.fResult->rowBytes(0), pixels.info().minRowBytes(),
637                      pixels.height());
638         return Result::kSuccess;
639     });
640 
641     GraphiteReadPixelTestRules rules;
642     rules.fAllowUnpremulSrc = true;
643     rules.fUncontainedRectSucceeds = false;
644 
645     auto factory = std::function<GraphiteSrcFactory<Surface>>(
646             [&](skgpu::graphite::Recorder* recorder, const SkPixmap& src) {
647                 Surface surface = SkSurfaces::RenderTarget(recorder,
648                                                            src.info(),
649                                                            Mipmapped::kNo,
650                                                            /*surfaceProps=*/nullptr);
651                 if (surface) {
652                     surface->writePixels(src, 0, 0);
653 
654                     std::unique_ptr<skgpu::graphite::Recording> recording = recorder->snap();
655                     skgpu::graphite::InsertRecordingInfo recordingInfo;
656                     recordingInfo.fRecording = recording.get();
657                     context->insertRecording(recordingInfo);
658                 }
659 
660                 return surface;
661             });
662     graphite_read_pixels_test_driver(reporter, context, rules, factory, reader, {});
663 
664     // It's possible that we've created an Image using the factory, but then don't try to do
665     // readPixels on it, leaving a hanging command buffer. So we submit here to clean up.
666     context->submit();
667 }
668