• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2020 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/SkBitmap.h"
10 #include "include/core/SkBlendMode.h"
11 #include "include/core/SkCanvas.h"
12 #include "include/core/SkColor.h"
13 #include "include/core/SkColorSpace.h"
14 #include "include/core/SkColorType.h"
15 #include "include/core/SkImage.h"
16 #include "include/core/SkImageInfo.h"
17 #include "include/core/SkMatrix.h"
18 #include "include/core/SkPaint.h"
19 #include "include/core/SkPixmap.h"
20 #include "include/core/SkPoint.h"
21 #include "include/core/SkRect.h"
22 #include "include/core/SkRefCnt.h"
23 #include "include/core/SkSamplingOptions.h"
24 #include "include/core/SkScalar.h"
25 #include "include/core/SkString.h"
26 #include "include/core/SkSurface.h"
27 #include "include/core/SkTileMode.h"
28 #include "include/core/SkTypes.h"
29 #include "include/effects/SkGradientShader.h"
30 #include "include/gpu/GpuTypes.h"
31 #include "include/gpu/GrBackendSurface.h"
32 #include "include/gpu/GrDirectContext.h"
33 #include "include/gpu/GrRecordingContext.h"
34 #include "include/gpu/GrTypes.h"
35 #include "include/private/base/SkTArray.h"
36 #include "include/private/gpu/ganesh/GrTypesPriv.h"
37 #include "src/core/SkAutoPixmapStorage.h"
38 #include "src/core/SkConvertPixels.h"
39 #include "src/core/SkImageInfoPriv.h"
40 #include "src/gpu/SkBackingFit.h"
41 #include "src/gpu/ganesh/GrCaps.h"
42 #include "src/gpu/ganesh/GrDataUtils.h"
43 #include "src/gpu/ganesh/GrDirectContextPriv.h"
44 #include "src/gpu/ganesh/GrFragmentProcessor.h"
45 #include "src/gpu/ganesh/GrImageInfo.h"
46 #include "src/gpu/ganesh/GrPixmap.h"
47 #include "src/gpu/ganesh/GrSamplerState.h"
48 #include "src/gpu/ganesh/GrSurfaceProxy.h"
49 #include "src/gpu/ganesh/SurfaceContext.h"
50 #include "src/gpu/ganesh/SurfaceFillContext.h"
51 #include "src/gpu/ganesh/effects/GrTextureEffect.h"
52 #include "tests/CtsEnforcement.h"
53 #include "tests/Test.h"
54 #include "tests/TestUtils.h"
55 #include "tools/ToolUtils.h"
56 #include "tools/gpu/BackendSurfaceFactory.h"
57 #include "tools/gpu/BackendTextureImageFactory.h"
58 
59 #include <algorithm>
60 #include <array>
61 #include <cstring>
62 #include <functional>
63 #include <initializer_list>
64 #include <memory>
65 #include <utility>
66 #include <vector>
67 
68 struct GrContextOptions;
69 
min_rgb_channel_bits(SkColorType ct)70 static constexpr int min_rgb_channel_bits(SkColorType ct) {
71     switch (ct) {
72         case kUnknown_SkColorType:            return 0;
73         case kAlpha_8_SkColorType:            return 0;
74         case kA16_unorm_SkColorType:          return 0;
75         case kA16_float_SkColorType:          return 0;
76         case kRGB_565_SkColorType:            return 5;
77         case kARGB_4444_SkColorType:          return 4;
78         case kR8G8_unorm_SkColorType:         return 8;
79         case kR16G16_unorm_SkColorType:       return 16;
80         case kR16G16_float_SkColorType:       return 16;
81         case kRGBA_8888_SkColorType:          return 8;
82         case kSRGBA_8888_SkColorType:         return 8;
83         case kRGB_888x_SkColorType:           return 8;
84         case kBGRA_8888_SkColorType:          return 8;
85         case kRGBA_1010102_SkColorType:       return 10;
86         case kRGB_101010x_SkColorType:        return 10;
87         case kBGRA_1010102_SkColorType:       return 10;
88         case kBGR_101010x_SkColorType:        return 10;
89         case kBGR_101010x_XR_SkColorType:     return 10;
90         case kGray_8_SkColorType:             return 8;   // counting gray as "rgb"
91         case kRGBA_F16Norm_SkColorType:       return 10;  // just counting the mantissa
92         case kRGBA_F16_SkColorType:           return 10;  // just counting the mantissa
93         case kRGBA_F32_SkColorType:           return 23;  // just counting the mantissa
94         case kR16G16B16A16_unorm_SkColorType: return 16;
95         case kR8_unorm_SkColorType:           return 8;
96     }
97     SkUNREACHABLE;
98 }
99 
alpha_channel_bits(SkColorType ct)100 static constexpr int alpha_channel_bits(SkColorType ct) {
101     switch (ct) {
102         case kUnknown_SkColorType:            return 0;
103         case kAlpha_8_SkColorType:            return 8;
104         case kA16_unorm_SkColorType:          return 16;
105         case kA16_float_SkColorType:          return 16;
106         case kRGB_565_SkColorType:            return 0;
107         case kARGB_4444_SkColorType:          return 4;
108         case kR8G8_unorm_SkColorType:         return 0;
109         case kR16G16_unorm_SkColorType:       return 0;
110         case kR16G16_float_SkColorType:       return 0;
111         case kRGBA_8888_SkColorType:          return 8;
112         case kSRGBA_8888_SkColorType:         return 8;
113         case kRGB_888x_SkColorType:           return 0;
114         case kBGRA_8888_SkColorType:          return 8;
115         case kRGBA_1010102_SkColorType:       return 2;
116         case kRGB_101010x_SkColorType:        return 0;
117         case kBGRA_1010102_SkColorType:       return 2;
118         case kBGR_101010x_SkColorType:        return 0;
119         case kBGR_101010x_XR_SkColorType:     return 0;
120         case kGray_8_SkColorType:             return 0;
121         case kRGBA_F16Norm_SkColorType:       return 10;  // just counting the mantissa
122         case kRGBA_F16_SkColorType:           return 10;  // just counting the mantissa
123         case kRGBA_F32_SkColorType:           return 23;  // just counting the mantissa
124         case kR16G16B16A16_unorm_SkColorType: return 16;
125         case kR8_unorm_SkColorType:           return 0;
126     }
127     SkUNREACHABLE;
128 }
129 
make_long_rect_array(int w,int h)130 std::vector<SkIRect> make_long_rect_array(int w, int h) {
131     return {
132             // entire thing
133             SkIRect::MakeWH(w, h),
134             // larger on all sides
135             SkIRect::MakeLTRB(-10, -10, w + 10, h + 10),
136             // fully contained
137             SkIRect::MakeLTRB(w/4, h/4, 3*w/4, 3*h/4),
138             // outside top left
139             SkIRect::MakeLTRB(-10, -10, -1, -1),
140             // touching top left corner
141             SkIRect::MakeLTRB(-10, -10, 0, 0),
142             // overlapping top left corner
143             SkIRect::MakeLTRB(-10, -10, w/4, h/4),
144             // overlapping top left and top right corners
145             SkIRect::MakeLTRB(-10, -10, w + 10, h/4),
146             // touching entire top edge
147             SkIRect::MakeLTRB(-10, -10, w + 10, 0),
148             // overlapping top right corner
149             SkIRect::MakeLTRB(3*w/4, -10, w + 10, h/4),
150             // contained in x, overlapping top edge
151             SkIRect::MakeLTRB(w/4, -10, 3*w/4, h/4),
152             // outside top right corner
153             SkIRect::MakeLTRB(w + 1, -10, w + 10, -1),
154             // touching top right corner
155             SkIRect::MakeLTRB(w, -10, w + 10, 0),
156             // overlapping top left and bottom left corners
157             SkIRect::MakeLTRB(-10, -10, w/4, h + 10),
158             // touching entire left edge
159             SkIRect::MakeLTRB(-10, -10, 0, h + 10),
160             // overlapping bottom left corner
161             SkIRect::MakeLTRB(-10, 3*h/4, w/4, h + 10),
162             // contained in y, overlapping left edge
163             SkIRect::MakeLTRB(-10, h/4, w/4, 3*h/4),
164             // outside bottom left corner
165             SkIRect::MakeLTRB(-10, h + 1, -1, h + 10),
166             // touching bottom left corner
167             SkIRect::MakeLTRB(-10, h, 0, h + 10),
168             // overlapping bottom left and bottom right corners
169             SkIRect::MakeLTRB(-10, 3*h/4, w + 10, h + 10),
170             // touching entire left edge
171             SkIRect::MakeLTRB(0, h, w, h + 10),
172             // overlapping bottom right corner
173             SkIRect::MakeLTRB(3*w/4, 3*h/4, w + 10, h + 10),
174             // overlapping top right and bottom right corners
175             SkIRect::MakeLTRB(3*w/4, -10, w + 10, h + 10),
176     };
177 }
178 
make_short_rect_array(int w,int h)179 std::vector<SkIRect> make_short_rect_array(int w, int h) {
180     return {
181             // entire thing
182             SkIRect::MakeWH(w, h),
183             // fully contained
184             SkIRect::MakeLTRB(w/4, h/4, 3*w/4, 3*h/4),
185             // overlapping top right corner
186             SkIRect::MakeLTRB(3*w/4, -10, w + 10, h/4),
187     };
188 }
189 
190 namespace {
191 
192 struct GpuReadPixelTestRules {
193     // Test unpremul sources? We could omit this and detect that creating the source of the read
194     // failed but having it lets us skip generating reference color data.
195     bool fAllowUnpremulSrc = true;
196     // Are reads that are overlapping but not contained by the src bounds expected to succeed?
197     bool fUncontainedRectSucceeds = true;
198 };
199 
200 // Makes a src populated with the pixmap. The src should get its image info (or equivalent) from
201 // the pixmap.
202 template <typename T> using GpuSrcFactory = T(SkPixmap&);
203 
204 enum class Result {
205     kFail,
206     kSuccess,
207     kExcusedFailure,
208 };
209 
210 // Does a read from the T into the pixmap.
211 template <typename T>
212 using GpuReadSrcFn = Result(const T&, const SkIPoint& offset, const SkPixmap&);
213 
214 // Makes a dst for testing writes.
215 template <typename T> using GpuDstFactory = T(const SkImageInfo& ii);
216 
217 // Does a write from the pixmap to the T.
218 template <typename T>
219 using GpuWriteDstFn = Result(const T&, const SkIPoint& offset, const SkPixmap&);
220 
221 // To test the results of the write we do a read. This reads the entire src T. It should do a non-
222 // converting read (i.e. the image info of the returned pixmap matches that of the T).
223 template <typename T>
224 using GpuReadDstFn = SkAutoPixmapStorage(const T&);
225 
226 }  // anonymous namespace
227 
make_pixmap_have_valid_alpha_type(SkPixmap pm)228 SkPixmap make_pixmap_have_valid_alpha_type(SkPixmap pm) {
229     if (pm.alphaType() == kUnknown_SkAlphaType) {
230         return {pm.info().makeAlphaType(kUnpremul_SkAlphaType), pm.addr(), pm.rowBytes()};
231     }
232     return pm;
233 }
234 
make_ref_data(const SkImageInfo & info,bool forceOpaque)235 static SkAutoPixmapStorage make_ref_data(const SkImageInfo& info, bool forceOpaque) {
236     SkAutoPixmapStorage result;
237     result.alloc(info);
238     auto surface = SkSurface::MakeRasterDirect(make_pixmap_have_valid_alpha_type(result));
239     if (!surface) {
240         return result;
241     }
242 
243     SkPoint pts1[] = {{0, 0}, {float(info.width()), float(info.height())}};
244     static constexpr SkColor kColors1[] = {SK_ColorGREEN, SK_ColorRED};
245     SkPaint paint;
246     paint.setShader(SkGradientShader::MakeLinear(pts1, kColors1, nullptr, 2, SkTileMode::kClamp));
247     surface->getCanvas()->drawPaint(paint);
248 
249     SkPoint pts2[] = {{float(info.width()), 0}, {0, float(info.height())}};
250     static constexpr SkColor kColors2[] = {SK_ColorBLUE, SK_ColorBLACK};
251     paint.setShader(SkGradientShader::MakeLinear(pts2, kColors2, nullptr, 2, SkTileMode::kClamp));
252     paint.setBlendMode(SkBlendMode::kPlus);
253     surface->getCanvas()->drawPaint(paint);
254 
255     // If not opaque add some fractional alpha.
256     if (info.alphaType() != kOpaque_SkAlphaType && !forceOpaque) {
257         static constexpr SkColor kColors3[] = {SK_ColorWHITE,
258                                                SK_ColorWHITE,
259                                                0x60FFFFFF,
260                                                SK_ColorWHITE,
261                                                SK_ColorWHITE};
262         static constexpr SkScalar kPos3[] = {0.f, 0.15f, 0.5f, 0.85f, 1.f};
263         paint.setShader(SkGradientShader::MakeRadial({info.width()/2.f, info.height()/2.f},
264                                                      (info.width() + info.height())/10.f,
265                                                      kColors3, kPos3, 5, SkTileMode::kMirror));
266         paint.setBlendMode(SkBlendMode::kDstIn);
267         surface->getCanvas()->drawPaint(paint);
268     }
269     return result;
270 }
271 
272 template <typename T>
gpu_read_pixels_test_driver(skiatest::Reporter * reporter,const GpuReadPixelTestRules & rules,const std::function<GpuSrcFactory<T>> & srcFactory,const std::function<GpuReadSrcFn<T>> & read,SkString label)273 static void gpu_read_pixels_test_driver(skiatest::Reporter* reporter,
274                                         const GpuReadPixelTestRules& rules,
275                                         const std::function<GpuSrcFactory<T>>& srcFactory,
276                                         const std::function<GpuReadSrcFn<T>>& read,
277                                         SkString label) {
278     if (!label.isEmpty()) {
279         // Add space for printing.
280         label.append(" ");
281     }
282     // Separate this out just to give it some line width to breathe. Note 'srcPixels' should have
283     // the same image info as src. We will do a converting readPixels() on it to get the data
284     // to compare with the results of 'read'.
285     auto runTest = [&](const T& src,
286                        const SkPixmap& srcPixels,
287                        const SkImageInfo& readInfo,
288                        SkIPoint offset) {
289         const bool csConversion =
290                 !SkColorSpace::Equals(readInfo.colorSpace(), srcPixels.info().colorSpace());
291         const auto readCT = readInfo.colorType();
292         const auto readAT = readInfo.alphaType();
293         const auto srcCT = srcPixels.info().colorType();
294         const auto srcAT = srcPixels.info().alphaType();
295         const auto rect = SkIRect::MakeWH(readInfo.width(), readInfo.height()).makeOffset(offset);
296         const auto surfBounds = SkIRect::MakeWH(srcPixels.width(), srcPixels.height());
297         const size_t readBpp = SkColorTypeBytesPerPixel(readCT);
298 
299         // Make the row bytes in the dst be loose for extra stress.
300         const size_t dstRB = readBpp * readInfo.width() + 10 * readBpp;
301         // This will make the last row tight.
302         const size_t dstSize = readInfo.computeByteSize(dstRB);
303         std::unique_ptr<char[]> dstData(new char[dstSize]);
304         SkPixmap dstPixels(readInfo, dstData.get(), dstRB);
305         // Initialize with an arbitrary value for each byte. Later we will check that only the
306         // correct part of the destination gets overwritten by 'read'.
307         static constexpr auto kInitialByte = static_cast<char>(0x1B);
308         std::fill_n(static_cast<char*>(dstPixels.writable_addr()),
309                     dstPixels.computeByteSize(),
310                     kInitialByte);
311 
312         const Result result = read(src, offset, dstPixels);
313 
314         if (!SkIRect::Intersects(rect, surfBounds)) {
315             REPORTER_ASSERT(reporter, result != Result::kSuccess);
316         } else if (readCT == kUnknown_SkColorType) {
317             REPORTER_ASSERT(reporter, result != Result::kSuccess);
318         } else if ((readAT == kUnknown_SkAlphaType) != (srcAT == kUnknown_SkAlphaType)) {
319             REPORTER_ASSERT(reporter, result != Result::kSuccess);
320         } else if (!rules.fUncontainedRectSucceeds && !surfBounds.contains(rect)) {
321             REPORTER_ASSERT(reporter, result != Result::kSuccess);
322         } else if (result == Result::kFail) {
323             // TODO: Support RGB/BGR 101010x, BGRA 1010102 on the GPU.
324             if (SkColorTypeToGrColorType(readCT) != GrColorType::kUnknown) {
325                 ERRORF(reporter,
326                        "Read failed. %sSrc CT: %s, Src AT: %s Read CT: %s, Read AT: %s, "
327                        "Rect [%d, %d, %d, %d], CS conversion: %d\n",
328                        label.c_str(),
329                        ToolUtils::colortype_name(srcCT), ToolUtils::alphatype_name(srcAT),
330                        ToolUtils::colortype_name(readCT), ToolUtils::alphatype_name(readAT),
331                        rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, csConversion);
332             }
333             return result;
334         }
335 
336         bool guardOk = true;
337         auto guardCheck = [](char x) { return x == kInitialByte; };
338 
339         // Considering the rect we tried to read and the surface bounds figure  out which pixels in
340         // both src and dst space should actually have been read and written.
341         SkIRect srcReadRect;
342         if (result == Result::kSuccess && srcReadRect.intersect(surfBounds, rect)) {
343             SkIRect dstWriteRect = srcReadRect.makeOffset(-rect.fLeft, -rect.fTop);
344 
345             const bool lumConversion =
346                     !(SkColorTypeChannelFlags(srcCT) & kGray_SkColorChannelFlag) &&
347                     (SkColorTypeChannelFlags(readCT) & kGray_SkColorChannelFlag);
348             // A CS or luminance conversion allows a 3 value difference and otherwise a 2 value
349             // difference. Note that sometimes read back on GPU can be lossy even when there no
350             // conversion at all because GPU->CPU read may go to a lower bit depth format and then
351             // be promoted back to the original type. For example, GL ES cannot read to 1010102, so
352             // we go through 8888.
353             float numer = (lumConversion || csConversion) ? 3.f : 2.f;
354             // Allow some extra tolerance if unpremuling.
355             if (srcAT == kPremul_SkAlphaType && readAT == kUnpremul_SkAlphaType) {
356                 numer += 1;
357             }
358             int rgbBits = std::min({min_rgb_channel_bits(readCT), min_rgb_channel_bits(srcCT), 8});
359             float tol = numer / (1 << rgbBits);
360             float alphaTol = 0;
361             if (readAT != kOpaque_SkAlphaType && srcAT != kOpaque_SkAlphaType) {
362                 // Alpha can also get squashed down to 8 bits going through an intermediate
363                 // color format.
364                 const int alphaBits = std::min({alpha_channel_bits(readCT),
365                                                 alpha_channel_bits(srcCT),
366                                                 8});
367                 alphaTol = 2.f / (1 << alphaBits);
368             }
369 
370             const float tols[4] = {tol, tol, tol, alphaTol};
371             auto error = std::function<ComparePixmapsErrorReporter>([&](int x, int y,
372                                                                         const float diffs[4]) {
373                 SkASSERT(x >= 0 && y >= 0);
374                 ERRORF(reporter,
375                        "%sSrc CT: %s, Src AT: %s, Read CT: %s, Read AT: %s, Rect [%d, %d, %d, %d]"
376                        ", CS conversion: %d\n"
377                        "Error at %d, %d. Diff in floats: (%f, %f, %f, %f)",
378                        label.c_str(),
379                        ToolUtils::colortype_name(srcCT), ToolUtils::alphatype_name(srcAT),
380                        ToolUtils::colortype_name(readCT), ToolUtils::alphatype_name(readAT),
381                        rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, csConversion, x, y,
382                        diffs[0], diffs[1], diffs[2], diffs[3]);
383             });
384             SkAutoPixmapStorage ref;
385             SkImageInfo refInfo = readInfo.makeDimensions(dstWriteRect.size());
386             ref.alloc(refInfo);
387             if (readAT == kUnknown_SkAlphaType) {
388                 // Do a spoofed read where src and dst alpha type are both kUnpremul. This will
389                 // allow SkPixmap readPixels to succeed and won't do any alpha type conversion.
390                 SkPixmap unpremulRef(refInfo.makeAlphaType(kUnpremul_SkAlphaType),
391                                      ref.addr(),
392                                      ref.rowBytes());
393                 SkPixmap unpremulSRc(srcPixels.info().makeAlphaType(kUnpremul_SkAlphaType),
394                                      srcPixels.addr(),
395                                      srcPixels.rowBytes());
396 
397                 unpremulSRc.readPixels(unpremulRef, srcReadRect.x(), srcReadRect.y());
398             } else {
399                 srcPixels.readPixels(ref, srcReadRect.x(), srcReadRect.y());
400             }
401             // This is the part of dstPixels that should have been updated.
402             SkPixmap actual;
403             SkAssertResult(dstPixels.extractSubset(&actual, dstWriteRect));
404             ComparePixels(ref, actual, tols, error);
405 
406             const auto* v = dstData.get();
407             const auto* end = dstData.get() + dstSize;
408             guardOk = std::all_of(v, v + dstWriteRect.top() * dstPixels.rowBytes(), guardCheck);
409             v += dstWriteRect.top() * dstPixels.rowBytes();
410             for (int y = dstWriteRect.top(); y < dstWriteRect.bottom(); ++y) {
411                 guardOk |= std::all_of(v, v + dstWriteRect.left() * readBpp, guardCheck);
412                 auto pad = v + dstWriteRect.right() * readBpp;
413                 auto rowEnd = std::min(end, v + dstPixels.rowBytes());
414                 // min protects against reading past the end of the tight last row.
415                 guardOk |= std::all_of(pad, rowEnd, guardCheck);
416                 v = rowEnd;
417             }
418             guardOk |= std::all_of(v, end, guardCheck);
419         } else {
420             guardOk = std::all_of(dstData.get(), dstData.get() + dstSize, guardCheck);
421         }
422         if (!guardOk) {
423             ERRORF(reporter,
424                    "Result pixels modified result outside read rect [%d, %d, %d, %d]. "
425                    "%sSrc CT: %s, Read CT: %s, CS conversion: %d",
426                    rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, label.c_str(),
427                    ToolUtils::colortype_name(srcCT), ToolUtils::colortype_name(readCT),
428                    csConversion);
429         }
430         return result;
431     };
432 
433     static constexpr int kW = 16;
434     static constexpr int kH = 16;
435 
436     const std::vector<SkIRect> longRectArray = make_long_rect_array(kW, kH);
437     const std::vector<SkIRect> shortRectArray = make_short_rect_array(kW, kH);
438 
439     // We ensure we use the long array once per src and read color type and otherwise use the
440     // short array to improve test run time.
441     // Also, some color types have no alpha values and thus Opaque Premul and Unpremul are
442     // equivalent. Just ensure each redundant AT is tested once with each CT (src and read).
443     // Similarly, alpha-only color types behave the same for all alpha types so just test premul
444     // after one iter.
445     // We consider a src or read CT thoroughly tested once it has run through the long rect array
446     // and full complement of alpha types with one successful read in the loop.
447     std::array<bool, kLastEnum_SkColorType + 1> srcCTTestedThoroughly  = {},
448                                                 readCTTestedThoroughly = {};
449     for (int sat = 0; sat < kLastEnum_SkAlphaType; ++sat) {
450         const auto srcAT = static_cast<SkAlphaType>(sat);
451         if (srcAT == kUnpremul_SkAlphaType && !rules.fAllowUnpremulSrc) {
452             continue;
453         }
454         for (int sct = 0; sct <= kLastEnum_SkColorType; ++sct) {
455             const auto srcCT = static_cast<SkColorType>(sct);
456             // We always make our ref data as F32
457             auto refInfo = SkImageInfo::Make(kW, kH,
458                                              kRGBA_F32_SkColorType,
459                                              srcAT,
460                                              SkColorSpace::MakeSRGB());
461             // 1010102 formats have an issue where it's easy to make a resulting
462             // color where r, g, or b is greater than a. CPU/GPU differ in whether the stored color
463             // channels are clipped to the alpha value. CPU clips but GPU does not.
464             // Note that we only currently use srcCT for the 1010102 workaround. If we remove this
465             // we can also put the ref data setup above the srcCT loop.
466             bool forceOpaque = srcAT == kPremul_SkAlphaType &&
467                     (srcCT == kRGBA_1010102_SkColorType || srcCT == kBGRA_1010102_SkColorType);
468 
469             SkAutoPixmapStorage srcPixels = make_ref_data(refInfo, forceOpaque);
470             auto src = srcFactory(srcPixels);
471             if (!src) {
472                 continue;
473             }
474             if (SkColorTypeIsAlwaysOpaque(srcCT) && srcCTTestedThoroughly[srcCT] &&
475                 (kPremul_SkAlphaType == srcAT || kUnpremul_SkAlphaType == srcAT)) {
476                 continue;
477             }
478             if (SkColorTypeIsAlphaOnly(srcCT) && srcCTTestedThoroughly[srcCT] &&
479                 (kUnpremul_SkAlphaType == srcAT ||
480                  kOpaque_SkAlphaType   == srcAT ||
481                  kUnknown_SkAlphaType  == srcAT)) {
482                 continue;
483             }
484             for (int rct = 0; rct <= kLastEnum_SkColorType; ++rct) {
485                 const auto readCT = static_cast<SkColorType>(rct);
486                 for (const sk_sp<SkColorSpace>& readCS :
487                      {SkColorSpace::MakeSRGB(), SkColorSpace::MakeSRGBLinear()}) {
488                     for (int at = 0; at <= kLastEnum_SkAlphaType; ++at) {
489                         const auto readAT = static_cast<SkAlphaType>(at);
490                         if (srcAT != kOpaque_SkAlphaType && readAT == kOpaque_SkAlphaType) {
491                             // This doesn't make sense.
492                             continue;
493                         }
494                         if (SkColorTypeIsAlwaysOpaque(readCT) && readCTTestedThoroughly[readCT] &&
495                             (kPremul_SkAlphaType == readAT || kUnpremul_SkAlphaType == readAT)) {
496                             continue;
497                         }
498                         if (SkColorTypeIsAlphaOnly(readCT) && readCTTestedThoroughly[readCT] &&
499                             (kUnpremul_SkAlphaType == readAT ||
500                              kOpaque_SkAlphaType   == readAT ||
501                              kUnknown_SkAlphaType  == readAT)) {
502                             continue;
503                         }
504                         const auto& rects =
505                                 srcCTTestedThoroughly[sct] && readCTTestedThoroughly[rct]
506                                         ? shortRectArray
507                                         : longRectArray;
508                         for (const auto& rect : rects) {
509                             const auto readInfo = SkImageInfo::Make(rect.width(), rect.height(),
510                                                                     readCT, readAT, readCS);
511                             const SkIPoint offset = rect.topLeft();
512                             Result r = runTest(src, srcPixels, readInfo, offset);
513                             if (r == Result::kSuccess) {
514                                 srcCTTestedThoroughly[sct] = true;
515                                 readCTTestedThoroughly[rct] = true;
516                             }
517                         }
518                     }
519                 }
520             }
521         }
522     }
523 }
524 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceContextReadPixels,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)525 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceContextReadPixels,
526                                        reporter,
527                                        ctxInfo,
528                                        CtsEnforcement::kApiLevel_T) {
529     using Surface = std::unique_ptr<skgpu::v1::SurfaceContext>;
530     GrDirectContext* direct = ctxInfo.directContext();
531     auto reader = std::function<GpuReadSrcFn<Surface>>(
532             [direct](const Surface& surface, const SkIPoint& offset, const SkPixmap& pixels) {
533                 if (surface->readPixels(direct, pixels, offset)) {
534                     return Result::kSuccess;
535                 } else {
536                     // Reading from a non-renderable format is not guaranteed to work on GL.
537                     // We'd have to be able to force a copy or draw draw to a renderable format.
538                     const auto& caps = *direct->priv().caps();
539                     if (direct->backend() == GrBackendApi::kOpenGL &&
540                         !caps.isFormatRenderable(surface->asSurfaceProxy()->backendFormat(), 1)) {
541                         return Result::kExcusedFailure;
542                     }
543                     return Result::kFail;
544                 }
545             });
546     GpuReadPixelTestRules rules;
547     rules.fAllowUnpremulSrc = true;
548     rules.fUncontainedRectSucceeds = true;
549 
550     for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) {
551         for (GrSurfaceOrigin origin : {kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin}) {
552             auto factory = std::function<GpuSrcFactory<Surface>>(
553                     [direct, origin, renderable](const SkPixmap& src) {
554                         auto sc = CreateSurfaceContext(
555                                 direct, src.info(), SkBackingFit::kExact, origin, renderable);
556                         if (sc) {
557                             sc->writePixels(direct, src, {0, 0});
558                         }
559                         return sc;
560                     });
561             auto label = SkStringPrintf("Renderable: %d, Origin: %d", (int)renderable, origin);
562             gpu_read_pixels_test_driver(reporter, rules, factory, reader, label);
563         }
564     }
565 }
566 
DEF_GANESH_TEST_FOR_ALL_CONTEXTS(ReadPixels_InvalidRowBytes_Gpu,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)567 DEF_GANESH_TEST_FOR_ALL_CONTEXTS(ReadPixels_InvalidRowBytes_Gpu,
568                                  reporter,
569                                  ctxInfo,
570                                  CtsEnforcement::kApiLevel_T) {
571     auto srcII = SkImageInfo::Make({10, 10}, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
572     auto surf = SkSurface::MakeRenderTarget(ctxInfo.directContext(), skgpu::Budgeted::kYes, srcII);
573     for (int ct = 0; ct < kLastEnum_SkColorType + 1; ++ct) {
574         auto colorType = static_cast<SkColorType>(ct);
575         size_t bpp = SkColorTypeBytesPerPixel(colorType);
576         if (bpp <= 1) {
577             continue;
578         }
579         auto dstII = srcII.makeColorType(colorType);
580         size_t badRowBytes = (surf->width() + 1)*bpp - 1;
581         auto storage = std::make_unique<char[]>(badRowBytes*surf->height());
582         REPORTER_ASSERT(reporter, !surf->readPixels(dstII, storage.get(), badRowBytes, 0, 0));
583     }
584 }
585 
DEF_GANESH_TEST_FOR_ALL_CONTEXTS(WritePixels_InvalidRowBytes_Gpu,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)586 DEF_GANESH_TEST_FOR_ALL_CONTEXTS(WritePixels_InvalidRowBytes_Gpu,
587                                  reporter,
588                                  ctxInfo,
589                                  CtsEnforcement::kApiLevel_T) {
590     auto dstII = SkImageInfo::Make({10, 10}, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
591     auto surf = SkSurface::MakeRenderTarget(ctxInfo.directContext(), skgpu::Budgeted::kYes, dstII);
592     for (int ct = 0; ct < kLastEnum_SkColorType + 1; ++ct) {
593         auto colorType = static_cast<SkColorType>(ct);
594         size_t bpp = SkColorTypeBytesPerPixel(colorType);
595         if (bpp <= 1) {
596             continue;
597         }
598         auto srcII = dstII.makeColorType(colorType);
599         size_t badRowBytes = (surf->width() + 1)*bpp - 1;
600         auto storage = std::make_unique<char[]>(badRowBytes*surf->height());
601         memset(storage.get(), 0, badRowBytes * surf->height());
602         // SkSurface::writePixels doesn't report bool, SkCanvas's does.
603         REPORTER_ASSERT(reporter,
604                         !surf->getCanvas()->writePixels(srcII, storage.get(), badRowBytes, 0, 0));
605     }
606 }
607 
608 namespace {
609 struct AsyncContext {
610     bool fCalled = false;
611     std::unique_ptr<const SkImage::AsyncReadResult> fResult;
612 };
613 }  // anonymous namespace
614 
615 // Making this a lambda in the test functions caused:
616 //   "error: cannot compile this forwarded non-trivially copyable parameter yet"
617 // on x86/Win/Clang bot, referring to 'result'.
async_callback(void * c,std::unique_ptr<const SkImage::AsyncReadResult> result)618 static void async_callback(void* c, std::unique_ptr<const SkImage::AsyncReadResult> result) {
619     auto context = static_cast<AsyncContext*>(c);
620     context->fResult = std::move(result);
621     context->fCalled = true;
622 }
623 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceAsyncReadPixels,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)624 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceAsyncReadPixels,
625                                        reporter,
626                                        ctxInfo,
627                                        CtsEnforcement::kApiLevel_T) {
628     using Surface = sk_sp<SkSurface>;
629     auto reader = std::function<GpuReadSrcFn<Surface>>(
630             [](const Surface& surface, const SkIPoint& offset, const SkPixmap& pixels) {
631                 auto direct = surface->recordingContext()->asDirectContext();
632                 SkASSERT(direct);
633 
634                 AsyncContext context;
635                 auto rect = SkIRect::MakeSize(pixels.dimensions()).makeOffset(offset);
636 
637                 // Rescale quality and linearity don't matter since we're doing a non-scaling
638                 // readback.
639                 surface->asyncRescaleAndReadPixels(pixels.info(), rect,
640                                                    SkImage::RescaleGamma::kSrc,
641                                                    SkImage::RescaleMode::kNearest,
642                                                    async_callback, &context);
643                 direct->submit();
644                 while (!context.fCalled) {
645                     direct->checkAsyncWorkCompletion();
646                 }
647                 if (!context.fResult) {
648                     return Result::kFail;
649                 }
650                 SkRectMemcpy(pixels.writable_addr(), pixels.rowBytes(), context.fResult->data(0),
651                              context.fResult->rowBytes(0), pixels.info().minRowBytes(),
652                              pixels.height());
653                 return Result::kSuccess;
654             });
655     GpuReadPixelTestRules rules;
656     rules.fAllowUnpremulSrc = false;
657     rules.fUncontainedRectSucceeds = false;
658 
659     for (GrSurfaceOrigin origin : {kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin}) {
660         auto factory = std::function<GpuSrcFactory<Surface>>(
661                 [context = ctxInfo.directContext(), origin](const SkPixmap& src) {
662                     auto surf = SkSurface::MakeRenderTarget(context,
663                                                             skgpu::Budgeted::kYes,
664                                                             src.info(),
665                                                             1,
666                                                             origin,
667                                                             nullptr);
668                     if (surf) {
669                         surf->writePixels(src, 0, 0);
670                     }
671                     return surf;
672                 });
673         auto label = SkStringPrintf("Origin: %d", origin);
674         gpu_read_pixels_test_driver(reporter, rules, factory, reader, label);
675         auto backendRTFactory = std::function<GpuSrcFactory<Surface>>(
676                 [context = ctxInfo.directContext(), origin](const SkPixmap& src) {
677                     // Dawn backend implementation of backend render targets doesn't support
678                     // reading.
679                     if (context->backend() == GrBackendApi::kDawn) {
680                         return Surface();
681                     }
682                     auto surf = sk_gpu_test::MakeBackendRenderTargetSurface(context,
683                                                                             src.info(),
684                                                                             origin,
685                                                                             1);
686                     if (surf) {
687                         surf->writePixels(src, 0, 0);
688                     }
689                     return surf;
690                 });
691         label = SkStringPrintf("BERT Origin: %d", origin);
692         gpu_read_pixels_test_driver(reporter, rules, backendRTFactory, reader, label);
693     }
694 }
695 
696 // Manually parameterized by GrRenderable and GrSurfaceOrigin to reduce per-test run time.
image_async_read_pixels(GrRenderable renderable,GrSurfaceOrigin origin,skiatest::Reporter * reporter,const sk_gpu_test::ContextInfo & ctxInfo)697 static void image_async_read_pixels(GrRenderable renderable,
698                                     GrSurfaceOrigin origin,
699                                     skiatest::Reporter* reporter,
700                                     const sk_gpu_test::ContextInfo& ctxInfo) {
701     using Image = sk_sp<SkImage>;
702     auto context = ctxInfo.directContext();
703     auto reader = std::function<GpuReadSrcFn<Image>>([context](const Image& image,
704                                                                const SkIPoint& offset,
705                                                                const SkPixmap& pixels) {
706         AsyncContext asyncContext;
707         auto rect = SkIRect::MakeSize(pixels.dimensions()).makeOffset(offset);
708         // The GPU implementation is based on rendering and will fail for non-renderable color
709         // types.
710         auto ct = SkColorTypeToGrColorType(image->colorType());
711         auto format = context->priv().caps()->getDefaultBackendFormat(ct, GrRenderable::kYes);
712         if (!context->priv().caps()->isFormatAsColorTypeRenderable(ct, format)) {
713             return Result::kExcusedFailure;
714         }
715 
716         // Rescale quality and linearity don't matter since we're doing a non-scaling readback.
717         image->asyncRescaleAndReadPixels(pixels.info(), rect,
718                                          SkImage::RescaleGamma::kSrc,
719                                          SkImage::RescaleMode::kNearest,
720                                          async_callback, &asyncContext);
721         context->submit();
722         while (!asyncContext.fCalled) {
723             context->checkAsyncWorkCompletion();
724         }
725         if (!asyncContext.fResult) {
726             return Result::kFail;
727         }
728         SkRectMemcpy(pixels.writable_addr(), pixels.rowBytes(), asyncContext.fResult->data(0),
729                      asyncContext.fResult->rowBytes(0), pixels.info().minRowBytes(),
730                      pixels.height());
731         return Result::kSuccess;
732     });
733 
734     GpuReadPixelTestRules rules;
735     rules.fAllowUnpremulSrc = true;
736     rules.fUncontainedRectSucceeds = false;
737 
738     auto factory = std::function<GpuSrcFactory<Image>>([&](const SkPixmap& src) {
739         return sk_gpu_test::MakeBackendTextureImage(ctxInfo.directContext(), src,
740                                                     renderable, origin);
741     });
742     auto label = SkStringPrintf("Renderable: %d, Origin: %d", (int)renderable, origin);
743     gpu_read_pixels_test_driver(reporter, rules, factory, reader, label);
744 }
745 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageAsyncReadPixels_NonRenderable_TopLeft,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)746 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageAsyncReadPixels_NonRenderable_TopLeft,
747                                        reporter,
748                                        ctxInfo,
749                                        CtsEnforcement::kApiLevel_T) {
750     image_async_read_pixels(GrRenderable::kNo, GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
751                             reporter, ctxInfo);
752 }
753 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageAsyncReadPixels_NonRenderable_BottomLeft,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)754 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageAsyncReadPixels_NonRenderable_BottomLeft,
755                                        reporter,
756                                        ctxInfo,
757                                        CtsEnforcement::kApiLevel_T) {
758     image_async_read_pixels(GrRenderable::kNo, GrSurfaceOrigin::kBottomLeft_GrSurfaceOrigin,
759                             reporter, ctxInfo);
760 }
761 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageAsyncReadPixels_Renderable_TopLeft,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)762 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageAsyncReadPixels_Renderable_TopLeft,
763                                        reporter,
764                                        ctxInfo,
765                                        CtsEnforcement::kApiLevel_T) {
766     image_async_read_pixels(GrRenderable::kYes, GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
767                             reporter, ctxInfo);
768 }
769 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageAsyncReadPixels_Renderable_BottomLeft,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)770 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageAsyncReadPixels_Renderable_BottomLeft,
771                                        reporter,
772                                        ctxInfo,
773                                        CtsEnforcement::kApiLevel_T) {
774     image_async_read_pixels(GrRenderable::kYes, GrSurfaceOrigin::kBottomLeft_GrSurfaceOrigin,
775                             reporter, ctxInfo);
776 }
777 
DEF_GANESH_TEST(AsyncReadPixelsContextShutdown,reporter,options,CtsEnforcement::kApiLevel_T)778 DEF_GANESH_TEST(AsyncReadPixelsContextShutdown, reporter, options, CtsEnforcement::kApiLevel_T) {
779     const auto ii = SkImageInfo::Make(10, 10, kRGBA_8888_SkColorType, kPremul_SkAlphaType,
780                                       SkColorSpace::MakeSRGB());
781     enum class ShutdownSequence {
782         kFreeResult_DestroyContext,
783         kDestroyContext_FreeResult,
784         kFreeResult_ReleaseAndAbandon_DestroyContext,
785         kFreeResult_Abandon_DestroyContext,
786         kReleaseAndAbandon_FreeResult_DestroyContext,
787         kAbandon_FreeResult_DestroyContext,
788         kReleaseAndAbandon_DestroyContext_FreeResult,
789         kAbandon_DestroyContext_FreeResult,
790     };
791     for (int t = 0; t < sk_gpu_test::GrContextFactory::kContextTypeCnt; ++t) {
792         auto type = static_cast<sk_gpu_test::GrContextFactory::ContextType>(t);
793         for (auto sequence : {ShutdownSequence::kFreeResult_DestroyContext,
794                               ShutdownSequence::kDestroyContext_FreeResult,
795                               ShutdownSequence::kFreeResult_ReleaseAndAbandon_DestroyContext,
796                               ShutdownSequence::kFreeResult_Abandon_DestroyContext,
797                               ShutdownSequence::kReleaseAndAbandon_FreeResult_DestroyContext,
798                               ShutdownSequence::kAbandon_FreeResult_DestroyContext,
799                               ShutdownSequence::kReleaseAndAbandon_DestroyContext_FreeResult,
800                               ShutdownSequence::kAbandon_DestroyContext_FreeResult}) {
801             // Vulkan and D3D context abandoning without resource release has issues outside of the
802             // scope of this test.
803             if ((type == sk_gpu_test::GrContextFactory::kVulkan_ContextType ||
804                  type == sk_gpu_test::GrContextFactory::kDirect3D_ContextType) &&
805                 (sequence == ShutdownSequence::kFreeResult_ReleaseAndAbandon_DestroyContext ||
806                  sequence == ShutdownSequence::kFreeResult_Abandon_DestroyContext ||
807                  sequence == ShutdownSequence::kReleaseAndAbandon_FreeResult_DestroyContext ||
808                  sequence == ShutdownSequence::kReleaseAndAbandon_DestroyContext_FreeResult ||
809                  sequence == ShutdownSequence::kAbandon_FreeResult_DestroyContext ||
810                  sequence == ShutdownSequence::kAbandon_DestroyContext_FreeResult)) {
811                 continue;
812             }
813             for (bool yuv : {false, true}) {
814                 sk_gpu_test::GrContextFactory factory(options);
815                 auto direct = factory.get(type);
816                 if (!direct) {
817                     continue;
818                 }
819                 // This test is only meaningful for contexts that support transfer buffers for
820                 // reads.
821                 if (!direct->priv().caps()->transferFromSurfaceToBufferSupport()) {
822                     continue;
823                 }
824                 auto surf = SkSurface::MakeRenderTarget(direct, skgpu::Budgeted::kYes, ii, 1,
825                                                         nullptr);
826                 if (!surf) {
827                     continue;
828                 }
829                 AsyncContext cbContext;
830                 if (yuv) {
831                     surf->asyncRescaleAndReadPixelsYUV420(
832                             kIdentity_SkYUVColorSpace, SkColorSpace::MakeSRGB(), ii.bounds(),
833                             ii.dimensions(), SkImage::RescaleGamma::kSrc,
834                             SkImage::RescaleMode::kNearest, &async_callback, &cbContext);
835                 } else {
836                     surf->asyncRescaleAndReadPixels(ii, ii.bounds(), SkImage::RescaleGamma::kSrc,
837                                                     SkImage::RescaleMode::kNearest, &async_callback,
838                                                     &cbContext);
839                 }
840                 direct->submit();
841                 while (!cbContext.fCalled) {
842                     direct->checkAsyncWorkCompletion();
843                 }
844                 if (!cbContext.fResult) {
845                     ERRORF(reporter, "Callback failed on %s. is YUV: %d",
846                            sk_gpu_test::GrContextFactory::ContextTypeName(type), yuv);
847                     continue;
848                 }
849                 // For vulkan we need to release all refs to the GrDirectContext before trying to
850                 // destroy the test context. The surface here is holding a ref.
851                 surf.reset();
852 
853                 // The real test is that we don't crash, get Vulkan validation errors, etc, during
854                 // this shutdown sequence.
855                 switch (sequence) {
856                     case ShutdownSequence::kFreeResult_DestroyContext:
857                     case ShutdownSequence::kFreeResult_ReleaseAndAbandon_DestroyContext:
858                     case ShutdownSequence::kFreeResult_Abandon_DestroyContext:
859                         break;
860                     case ShutdownSequence::kDestroyContext_FreeResult:
861                         factory.destroyContexts();
862                         break;
863                     case ShutdownSequence::kReleaseAndAbandon_FreeResult_DestroyContext:
864                         factory.releaseResourcesAndAbandonContexts();
865                         break;
866                     case ShutdownSequence::kAbandon_FreeResult_DestroyContext:
867                         factory.abandonContexts();
868                         break;
869                     case ShutdownSequence::kReleaseAndAbandon_DestroyContext_FreeResult:
870                         factory.releaseResourcesAndAbandonContexts();
871                         factory.destroyContexts();
872                         break;
873                     case ShutdownSequence::kAbandon_DestroyContext_FreeResult:
874                         factory.abandonContexts();
875                         factory.destroyContexts();
876                         break;
877                 }
878                 cbContext.fResult.reset();
879                 switch (sequence) {
880                     case ShutdownSequence::kFreeResult_ReleaseAndAbandon_DestroyContext:
881                         factory.releaseResourcesAndAbandonContexts();
882                         break;
883                     case ShutdownSequence::kFreeResult_Abandon_DestroyContext:
884                         factory.abandonContexts();
885                         break;
886                     case ShutdownSequence::kFreeResult_DestroyContext:
887                     case ShutdownSequence::kDestroyContext_FreeResult:
888                     case ShutdownSequence::kReleaseAndAbandon_FreeResult_DestroyContext:
889                     case ShutdownSequence::kAbandon_FreeResult_DestroyContext:
890                     case ShutdownSequence::kReleaseAndAbandon_DestroyContext_FreeResult:
891                     case ShutdownSequence::kAbandon_DestroyContext_FreeResult:
892                         break;
893                 }
894             }
895         }
896     }
897 }
898 
899 template <typename T>
gpu_write_pixels_test_driver(skiatest::Reporter * reporter,const std::function<GpuDstFactory<T>> & dstFactory,const std::function<GpuWriteDstFn<T>> & write,const std::function<GpuReadDstFn<T>> & read)900 static void gpu_write_pixels_test_driver(skiatest::Reporter* reporter,
901                                          const std::function<GpuDstFactory<T>>& dstFactory,
902                                          const std::function<GpuWriteDstFn<T>>& write,
903                                          const std::function<GpuReadDstFn<T>>& read) {
904     // Separate this out just to give it some line width to breathe.
905     auto runTest = [&](const T& dst,
906                        const SkImageInfo& dstInfo,
907                        const SkPixmap& srcPixels,
908                        SkIPoint offset) {
909         const bool csConversion =
910                 !SkColorSpace::Equals(dstInfo.colorSpace(), srcPixels.info().colorSpace());
911         const auto writeCT = srcPixels.colorType();
912         const auto writeAT = srcPixels.alphaType();
913         const auto dstCT = dstInfo.colorType();
914         const auto dstAT = dstInfo.alphaType();
915         const auto rect = SkIRect::MakePtSize(offset, srcPixels.dimensions());
916         const auto surfBounds = SkIRect::MakeSize(dstInfo.dimensions());
917 
918         // Do an initial read before the write.
919         SkAutoPixmapStorage firstReadPM = read(dst);
920         if (!firstReadPM.addr()) {
921             // Particularly with GLES 2 we can have formats that are unreadable with our current
922             // implementation of read pixels. If the format can't be attached to a FBO we don't have
923             // a code path that draws it to another readable color type/format combo and reads from
924             // that.
925             return Result::kExcusedFailure;
926         }
927 
928         const Result result = write(dst, offset, srcPixels);
929 
930         if (!SkIRect::Intersects(rect, surfBounds)) {
931             REPORTER_ASSERT(reporter, result != Result::kSuccess);
932         } else if (writeCT == kUnknown_SkColorType) {
933             REPORTER_ASSERT(reporter, result != Result::kSuccess);
934         } else if ((writeAT == kUnknown_SkAlphaType) != (dstAT == kUnknown_SkAlphaType)) {
935             REPORTER_ASSERT(reporter, result != Result::kSuccess);
936         } else if (result == Result::kExcusedFailure) {
937             return result;
938         } else if (result == Result::kFail) {
939             // TODO: Support RGB/BGR 101010x, BGRA 1010102 on the GPU.
940             if (SkColorTypeToGrColorType(writeCT) != GrColorType::kUnknown) {
941                 ERRORF(reporter,
942                        "Write failed. Write CT: %s, Write AT: %s Dst CT: %s, Dst AT: %s, "
943                        "Rect [%d, %d, %d, %d], CS conversion: %d\n",
944                        ToolUtils::colortype_name(writeCT), ToolUtils::alphatype_name(writeAT),
945                        ToolUtils::colortype_name(dstCT), ToolUtils::alphatype_name(dstAT),
946                        rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, csConversion);
947             }
948             return result;
949         }
950 
951         SkIRect checkRect;
952         if (result != Result::kSuccess || !checkRect.intersect(surfBounds, rect)) {
953             return result;
954         }
955 
956         // Do an initial read before the write. We'll use this to verify that areas outside the
957         // write are unaffected.
958         SkAutoPixmapStorage secondReadPM = read(dst);
959         if (!secondReadPM.addr()) {
960             // The first read succeeded so this one should, too.
961             ERRORF(reporter,
962                    "could not read from dst (CT: %s, AT: %s)\n",
963                    ToolUtils::colortype_name(dstCT),
964                    ToolUtils::alphatype_name(dstAT));
965             return Result::kFail;
966         }
967 
968         // Sometimes wider types go through 8bit unorm intermediates because of API
969         // restrictions.
970         int rgbBits = std::min({min_rgb_channel_bits(writeCT), min_rgb_channel_bits(dstCT), 8});
971         float tol = 2.f/(1 << rgbBits);
972         float alphaTol = 0;
973         if (writeAT != kOpaque_SkAlphaType && dstAT != kOpaque_SkAlphaType) {
974             // Alpha can also get squashed down to 8 bits going through an intermediate
975             // color format.
976             const int alphaBits = std::min({alpha_channel_bits(writeCT),
977                                             alpha_channel_bits(dstCT),
978                                             8});
979             alphaTol = 2.f/(1 << alphaBits);
980         }
981 
982         const float tols[4] = {tol, tol, tol, alphaTol};
983         auto error = std::function<ComparePixmapsErrorReporter>([&](int x,
984                                                                     int y,
985                                                                     const float diffs[4]) {
986             SkASSERT(x >= 0 && y >= 0);
987             ERRORF(reporter,
988                    "Write CT: %s, Write AT: %s, Dst CT: %s, Dst AT: %s, Rect [%d, %d, %d, %d]"
989                    ", CS conversion: %d\n"
990                    "Error at %d, %d. Diff in floats: (%f, %f, %f, %f)",
991                    ToolUtils::colortype_name(writeCT),
992                    ToolUtils::alphatype_name(writeAT),
993                    ToolUtils::colortype_name(dstCT),
994                    ToolUtils::alphatype_name(dstAT),
995                    rect.fLeft,
996                    rect.fTop,
997                    rect.fRight,
998                    rect.fBottom,
999                    csConversion,
1000                    x,
1001                    y,
1002                    diffs[0],
1003                    diffs[1],
1004                    diffs[2],
1005                    diffs[3]);
1006         });
1007 
1008         SkAutoPixmapStorage ref;
1009         ref.alloc(secondReadPM.info().makeDimensions(checkRect.size()));
1010         // Here we use the CPU backend to do the equivalent conversion as the write we're
1011         // testing, using kUnpremul instead of kUnknown since CPU requires a valid alpha type.
1012         SkAssertResult(make_pixmap_have_valid_alpha_type(srcPixels).readPixels(
1013                 make_pixmap_have_valid_alpha_type(ref),
1014                 std::max(0, -offset.fX),
1015                 std::max(0, -offset.fY)));
1016         // This is the part of secondReadPixels that should have been updated by the write.
1017         SkPixmap actual;
1018         SkAssertResult(secondReadPM.extractSubset(&actual, checkRect));
1019         ComparePixels(ref, actual, tols, error);
1020         // The area around written rect should be the same in the first and second read.
1021         SkIRect borders[]{
1022                 {               0,                 0, secondReadPM.width(), secondReadPM.height()},
1023                 {checkRect.fRight,                 0,      checkRect.fLeft, secondReadPM.height()},
1024                 { checkRect.fLeft,                 0,     checkRect.fRight,        checkRect.fTop},
1025                 { checkRect.fLeft, checkRect.fBottom,     checkRect.fRight, secondReadPM.height()}
1026         };
1027         for (const auto r : borders) {
1028             if (!r.isEmpty()) {
1029                 // Make a copy because MSVC for some reason doesn't correctly capture 'r'.
1030                 SkIPoint tl = r.topLeft();
1031                 auto guardError = std::function<ComparePixmapsErrorReporter>(
1032                         [&](int x, int y, const float diffs[4]) {
1033                             x += tl.x();
1034                             y += tl.y();
1035                             ERRORF(reporter,
1036                                    "Write CT: %s, Write AT: %s, Dst CT: %s, Dst AT: %s,"
1037                                    "Rect [%d, %d, %d, %d], CS conversion: %d\n"
1038                                    "Error in guard region %d, %d. Diff in floats: (%f, %f, %f, %f)",
1039                                    ToolUtils::colortype_name(writeCT),
1040                                    ToolUtils::alphatype_name(writeAT),
1041                                    ToolUtils::colortype_name(dstCT),
1042                                    ToolUtils::alphatype_name(dstAT),
1043                                    rect.fLeft,
1044                                    rect.fTop,
1045                                    rect.fRight,
1046                                    rect.fBottom,
1047                                    csConversion,
1048                                    x,
1049                                    y,
1050                                    diffs[0],
1051                                    diffs[1],
1052                                    diffs[2],
1053                                    diffs[3]);
1054                         });
1055                 SkPixmap a, b;
1056                 SkAssertResult(firstReadPM.extractSubset(&a, r));
1057                 SkAssertResult(firstReadPM.extractSubset(&b, r));
1058                 float zeroTols[4] = {};
1059                 ComparePixels(a, b, zeroTols, guardError);
1060             }
1061         }
1062         return result;
1063     };
1064 
1065     static constexpr int kW = 16;
1066     static constexpr int kH = 16;
1067 
1068     const std::vector<SkIRect> longRectArray = make_long_rect_array(kW, kH);
1069     const std::vector<SkIRect> shortRectArray = make_short_rect_array(kW, kH);
1070 
1071     // We ensure we use the long array once per src and read color type and otherwise use the
1072     // short array to improve test run time.
1073     // Also, some color types have no alpha values and thus Opaque Premul and Unpremul are
1074     // equivalent. Just ensure each redundant AT is tested once with each CT (dst and write).
1075     // Similarly, alpha-only color types behave the same for all alpha types so just test premul
1076     // after one iter.
1077     // We consider a dst or write CT thoroughly tested once it has run through the long rect array
1078     // and full complement of alpha types with one successful read in the loop.
1079     std::array<bool, kLastEnum_SkColorType + 1> dstCTTestedThoroughly   = {},
1080                                                 writeCTTestedThoroughly = {};
1081     for (int dat = 0; dat < kLastEnum_SkAlphaType; ++dat) {
1082         const auto dstAT = static_cast<SkAlphaType>(dat);
1083         for (int dct = 0; dct <= kLastEnum_SkColorType; ++dct) {
1084             const auto dstCT = static_cast<SkColorType>(dct);
1085             const auto dstInfo = SkImageInfo::Make(kW, kH, dstCT, dstAT, SkColorSpace::MakeSRGB());
1086             auto dst = dstFactory(dstInfo);
1087             if (!dst) {
1088                 continue;
1089             }
1090             if (SkColorTypeIsAlwaysOpaque(dstCT) && dstCTTestedThoroughly[dstCT] &&
1091                 (kPremul_SkAlphaType == dstAT || kUnpremul_SkAlphaType == dstAT)) {
1092                 continue;
1093             }
1094             if (SkColorTypeIsAlphaOnly(dstCT) && dstCTTestedThoroughly[dstCT] &&
1095                 (kUnpremul_SkAlphaType == dstAT ||
1096                  kOpaque_SkAlphaType   == dstAT ||
1097                  kUnknown_SkAlphaType  == dstAT)) {
1098                 continue;
1099             }
1100             for (int wct = 0; wct <= kLastEnum_SkColorType; ++wct) {
1101                 const auto writeCT = static_cast<SkColorType>(wct);
1102                 for (const sk_sp<SkColorSpace>& writeCS : {SkColorSpace::MakeSRGB(),
1103                                                            SkColorSpace::MakeSRGBLinear()}) {
1104                     for (int wat = 0; wat <= kLastEnum_SkAlphaType; ++wat) {
1105                         const auto writeAT = static_cast<SkAlphaType>(wat);
1106                         if (writeAT != kOpaque_SkAlphaType && dstAT == kOpaque_SkAlphaType) {
1107                             // This doesn't make sense.
1108                             continue;
1109                         }
1110                         if (SkColorTypeIsAlwaysOpaque(writeCT) &&
1111                             writeCTTestedThoroughly[writeCT] &&
1112                             (kPremul_SkAlphaType == writeAT || kUnpremul_SkAlphaType == writeAT)) {
1113                             continue;
1114                         }
1115                         if (SkColorTypeIsAlphaOnly(writeCT) && writeCTTestedThoroughly[writeCT] &&
1116                             (kUnpremul_SkAlphaType == writeAT ||
1117                              kOpaque_SkAlphaType   == writeAT ||
1118                              kUnknown_SkAlphaType  == writeAT)) {
1119                             continue;
1120                         }
1121                         const auto& rects =
1122                                 dstCTTestedThoroughly[dct] && writeCTTestedThoroughly[wct]
1123                                         ? shortRectArray
1124                                         : longRectArray;
1125                         for (const auto& rect : rects) {
1126                             auto writeInfo = SkImageInfo::Make(rect.size(),
1127                                                                writeCT,
1128                                                                writeAT,
1129                                                                writeCS);
1130                             // CPU and GPU handle 1010102 differently. CPU clamps RGB to A, GPU
1131                             // doesn't.
1132                             bool forceOpaque = writeCT == kRGBA_1010102_SkColorType ||
1133                                                writeCT == kBGRA_1010102_SkColorType;
1134                             SkAutoPixmapStorage writePixels = make_ref_data(writeInfo, forceOpaque);
1135                             const SkIPoint offset = rect.topLeft();
1136                             Result r = runTest(dst, dstInfo, writePixels, offset);
1137                             if (r == Result::kSuccess) {
1138                                 dstCTTestedThoroughly[dct] = true;
1139                                 writeCTTestedThoroughly[wct] = true;
1140                             }
1141                         }
1142                     }
1143                 }
1144             }
1145         }
1146     }
1147 }
1148 
1149 // Manually parameterized by GrRenderable and GrSurfaceOrigin to reduce per-test run time.
surface_context_write_pixels(GrRenderable renderable,GrSurfaceOrigin origin,skiatest::Reporter * reporter,const sk_gpu_test::ContextInfo & ctxInfo)1150 static void surface_context_write_pixels(GrRenderable renderable,
1151                                          GrSurfaceOrigin origin,
1152                                          skiatest::Reporter* reporter,
1153                                          const sk_gpu_test::ContextInfo& ctxInfo) {
1154     using Surface = std::unique_ptr<skgpu::v1::SurfaceContext>;
1155     GrDirectContext* direct = ctxInfo.directContext();
1156     auto writer = std::function<GpuWriteDstFn<Surface>>(
1157             [direct](const Surface& surface, const SkIPoint& offset, const SkPixmap& pixels) {
1158                 if (surface->writePixels(direct, pixels, offset)) {
1159                     return Result::kSuccess;
1160                 } else {
1161                     return Result::kFail;
1162                 }
1163             });
1164     auto reader = std::function<GpuReadDstFn<Surface>>([direct](const Surface& s) {
1165         SkAutoPixmapStorage result;
1166         auto grInfo = s->imageInfo();
1167         SkColorType ct = GrColorTypeToSkColorType(grInfo.colorType());
1168         SkASSERT(ct != kUnknown_SkColorType);
1169         auto skInfo = SkImageInfo::Make(grInfo.dimensions(), ct, grInfo.alphaType(),
1170                                         grInfo.refColorSpace());
1171         result.alloc(skInfo);
1172         if (!s->readPixels(direct, result, {0, 0})) {
1173             SkAutoPixmapStorage badResult;
1174             return badResult;
1175         }
1176         return result;
1177     });
1178 
1179     auto factory = std::function<GpuDstFactory<Surface>>(
1180             [direct, origin, renderable](const SkImageInfo& info) {
1181                 return CreateSurfaceContext(direct,
1182                                             info,
1183                                             SkBackingFit::kExact,
1184                                             origin,
1185                                             renderable);
1186             });
1187 
1188     gpu_write_pixels_test_driver(reporter, factory, writer, reader);
1189 }
1190 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceContextWritePixels_NonRenderable_TopLeft,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)1191 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceContextWritePixels_NonRenderable_TopLeft,
1192                                        reporter,
1193                                        ctxInfo,
1194                                        CtsEnforcement::kApiLevel_T) {
1195     surface_context_write_pixels(GrRenderable::kNo, GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
1196                                  reporter, ctxInfo);
1197 }
1198 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceContextWritePixels_NonRenderable_BottomLeft,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)1199 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceContextWritePixels_NonRenderable_BottomLeft,
1200                                        reporter,
1201                                        ctxInfo,
1202                                        CtsEnforcement::kApiLevel_T) {
1203     surface_context_write_pixels(GrRenderable::kNo, GrSurfaceOrigin::kBottomLeft_GrSurfaceOrigin,
1204                                  reporter, ctxInfo);
1205 }
1206 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceContextWritePixels_Renderable_TopLeft,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)1207 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceContextWritePixels_Renderable_TopLeft,
1208                                        reporter,
1209                                        ctxInfo,
1210                                        CtsEnforcement::kApiLevel_T) {
1211     surface_context_write_pixels(GrRenderable::kYes, GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
1212                                  reporter, ctxInfo);
1213 }
1214 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceContextWritePixels_Renderable_BottomLeft,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)1215 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceContextWritePixels_Renderable_BottomLeft,
1216                                        reporter,
1217                                        ctxInfo,
1218                                        CtsEnforcement::kApiLevel_T) {
1219     surface_context_write_pixels(GrRenderable::kYes, GrSurfaceOrigin::kBottomLeft_GrSurfaceOrigin,
1220                                  reporter, ctxInfo);
1221 }
1222 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceContextWritePixelsMipped,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)1223 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SurfaceContextWritePixelsMipped,
1224                                        reporter,
1225                                        ctxInfo,
1226                                        CtsEnforcement::kApiLevel_T) {
1227     auto direct = ctxInfo.directContext();
1228     if (!direct->priv().caps()->mipmapSupport()) {
1229         return;
1230     }
1231     static constexpr int kW = 25,
1232                          kH = 37;
1233     SkAutoPixmapStorage refP = make_ref_data(SkImageInfo::Make({kW, kH},
1234                                                                kRGBA_F32_SkColorType,
1235                                                                kPremul_SkAlphaType,
1236                                                                nullptr),
1237                                              false);
1238     SkAutoPixmapStorage refO = make_ref_data(SkImageInfo::Make({kW, kH},
1239                                                                kRGBA_F32_SkColorType,
1240                                                                kOpaque_SkAlphaType,
1241                                                                nullptr),
1242                                              true);
1243 
1244     for (int c = 0; c < kGrColorTypeCnt; ++c) {
1245         auto ct = static_cast<GrColorType>(c);
1246         // Below we use rendering to read the level pixels back.
1247         auto format = direct->priv().caps()->getDefaultBackendFormat(ct, GrRenderable::kYes);
1248         if (!format.isValid()) {
1249             continue;
1250         }
1251         SkAlphaType at = GrColorTypeHasAlpha(ct) ? kPremul_SkAlphaType : kOpaque_SkAlphaType;
1252         GrImageInfo info(ct, at, nullptr, kW, kH);
1253         SkTArray<GrCPixmap> levels;
1254         const auto& ref = at == kPremul_SkAlphaType ? refP : refO;
1255         for (int w = kW, h = kH; w || h; w/=2, h/=2) {
1256             auto level = GrPixmap::Allocate(info.makeWH(std::max(w, 1), std::max(h, 1)));
1257             SkPixmap src;
1258             SkAssertResult(ref.extractSubset(&src, SkIRect::MakeSize(level.dimensions())));
1259             SkAssertResult(GrConvertPixels(level, src));
1260             levels.push_back(level);
1261         }
1262 
1263         for (bool unowned : {false, true}) { // test a GrCPixmap that doesn't own its storage.
1264             for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) {
1265                 for (GrSurfaceOrigin origin : {kTopLeft_GrSurfaceOrigin,
1266                                                kBottomLeft_GrSurfaceOrigin}) {
1267                     auto sc = CreateSurfaceContext(direct,
1268                                                    info,
1269                                                    SkBackingFit::kExact,
1270                                                    origin,
1271                                                    renderable,
1272                                                    /*sample count*/ 1,
1273                                                    GrMipmapped::kYes);
1274                     if (!sc) {
1275                         continue;
1276                     }
1277                     // Keeps pixels in unowned case alive until after writePixels is called but no
1278                     // longer.
1279                     GrPixmap keepAlive;
1280                     GrCPixmap savedLevel = levels[1];
1281                     if (unowned) {
1282                         // Also test non-tight row bytes with the unowned pixmap, bump width by 1.
1283                         int w = levels[1].width() + 1;
1284                         int h = levels[1].height();
1285                         keepAlive = GrPixmap::Allocate(levels[1].info().makeWH(w, h));
1286                         SkPixmap src;
1287                         // These pixel values will be the same as the original level 1.
1288                         SkAssertResult(ref.extractSubset(&src, SkIRect::MakeWH(w, h)));
1289                         SkAssertResult(GrConvertPixels(keepAlive, src));
1290                         levels[1] = GrCPixmap(levels[1].info(),
1291                                               keepAlive.addr(),
1292                                               keepAlive.rowBytes());
1293                     }
1294                     // Going through intermediate textures is not supported for MIP levels (because
1295                     // we don't support rendering to non-base levels). So it's hard to have any hard
1296                     // rules about when we expect success.
1297                     if (!sc->writePixels(direct, levels.begin(), levels.size())) {
1298                         continue;
1299                     }
1300                     // Make sure the pixels from the unowned pixmap are released and then put the
1301                     // original level back in for the comparison after the read below.
1302                     keepAlive = {};
1303                     levels[1] = savedLevel;
1304 
1305                     // TODO: Update this when read pixels supports reading back levels to read
1306                     // directly rather than using minimizing draws.
1307                     auto dstSC = CreateSurfaceContext(direct,
1308                                                       info,
1309                                                       SkBackingFit::kExact,
1310                                                       kBottomLeft_GrSurfaceOrigin,
1311                                                       GrRenderable::kYes);
1312                     SkASSERT(dstSC);
1313                     GrSamplerState sampler(SkFilterMode::kNearest, SkMipmapMode::kNearest);
1314                     for (int i = 1; i <= 1; ++i) {
1315                         auto te = GrTextureEffect::Make(sc->readSurfaceView(),
1316                                                         info.alphaType(),
1317                                                         SkMatrix::I(),
1318                                                         sampler,
1319                                                         *direct->priv().caps());
1320                         dstSC->asFillContext()->fillRectToRectWithFP(
1321                                 SkIRect::MakeSize(sc->dimensions()),
1322                                 SkIRect::MakeSize(levels[i].dimensions()),
1323                                 std::move(te));
1324                         GrImageInfo readInfo =
1325                                 dstSC->imageInfo().makeDimensions(levels[i].dimensions());
1326                         GrPixmap read = GrPixmap::Allocate(readInfo);
1327                         if (!dstSC->readPixels(direct, read, {0, 0})) {
1328                             continue;
1329                         }
1330 
1331                         auto skCT = GrColorTypeToSkColorType(info.colorType());
1332                         int rgbBits = std::min(min_rgb_channel_bits(skCT), 8);
1333                         float rgbTol = (rgbBits == 0) ? 1.f : 2.f / ((1 << rgbBits) - 1);
1334                         int alphaBits = std::min(alpha_channel_bits(skCT), 8);
1335                         float alphaTol = (alphaBits == 0) ? 1.f : 2.f / ((1 << alphaBits) - 1);
1336                         float tol[] = {rgbTol, rgbTol, rgbTol, alphaTol};
1337 
1338                         GrCPixmap a = levels[i];
1339                         GrCPixmap b = read;
1340                         // The compare code will linearize when reading the srgb data. This will
1341                         // magnify differences at the high end. Rather than adjusting the tolerance
1342                         // to compensate we do the comparison without going through srgb->linear.
1343                         if (ct == GrColorType::kRGBA_8888_SRGB) {
1344                             a = GrCPixmap(a.info().makeColorType(GrColorType::kRGBA_8888),
1345                                           a.addr(),
1346                                           a.rowBytes());
1347                             b = GrCPixmap(b.info().makeColorType(GrColorType::kRGBA_8888),
1348                                           b.addr(),
1349                                           b.rowBytes());
1350                         }
1351 
1352                         auto error = std::function<ComparePixmapsErrorReporter>(
1353                                 [&](int x, int y, const float diffs[4]) {
1354                                     SkASSERT(x >= 0 && y >= 0);
1355                                     ERRORF(reporter,
1356                                            "CT: %s, Level %d, Unowned: %d. "
1357                                            "Error at %d, %d. Diff in floats:"
1358                                            "(%f, %f, %f, %f)",
1359                                            GrColorTypeToStr(info.colorType()), i, unowned, x, y,
1360                                            diffs[0], diffs[1], diffs[2], diffs[3]);
1361                                 });
1362                         ComparePixels(a, b, tol, error);
1363                     }
1364                 }
1365             }
1366         }
1367     }
1368 }
1369 
1370 // Tests a bug found in OOP-R canvas2d in Chrome. The GPU backend would incorrectly not bind
1371 // buffer 0 to GL_PIXEL_PACK_BUFFER before a glReadPixels() that was supposed to read into
1372 // client memory if a GrDirectContext::resetContext() occurred.
DEF_GANESH_TEST_FOR_GL_RENDERING_CONTEXTS(GLReadPixelsUnbindPBO,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)1373 DEF_GANESH_TEST_FOR_GL_RENDERING_CONTEXTS(GLReadPixelsUnbindPBO,
1374                                           reporter,
1375                                           ctxInfo,
1376                                           CtsEnforcement::kApiLevel_T) {
1377     // Start with a async read so that we bind to GL_PIXEL_PACK_BUFFER.
1378     auto info = SkImageInfo::Make(16, 16, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
1379     SkAutoPixmapStorage pmap = make_ref_data(info, /*forceOpaque=*/false);
1380     auto image = SkImage::MakeFromRaster(pmap, nullptr, nullptr);
1381     image = image->makeTextureImage(ctxInfo.directContext());
1382     if (!image) {
1383         ERRORF(reporter, "Couldn't make texture image.");
1384         return;
1385     }
1386 
1387     AsyncContext asyncContext;
1388     image->asyncRescaleAndReadPixels(info,
1389                                      SkIRect::MakeSize(info.dimensions()),
1390                                      SkImage::RescaleGamma::kSrc,
1391                                      SkImage::RescaleMode::kNearest,
1392                                      async_callback,
1393                                      &asyncContext);
1394 
1395     // This will force the async readback to finish.
1396     ctxInfo.directContext()->flushAndSubmit(true);
1397     if (!asyncContext.fCalled) {
1398         ERRORF(reporter, "async_callback not called.");
1399     }
1400     if (!asyncContext.fResult) {
1401         ERRORF(reporter, "async read failed.");
1402     }
1403 
1404     SkPixmap asyncResult(info, asyncContext.fResult->data(0), asyncContext.fResult->rowBytes(0));
1405 
1406     // Bug was that this would cause GrGLGpu to think no buffer was left bound to
1407     // GL_PIXEL_PACK_BUFFER even though async transfer did leave one bound. So the sync read
1408     // wouldn't bind buffer 0.
1409     ctxInfo.directContext()->resetContext();
1410 
1411     SkBitmap syncResult;
1412     syncResult.allocPixels(info);
1413     syncResult.eraseARGB(0xFF, 0xFF, 0xFF, 0xFF);
1414 
1415     image->readPixels(ctxInfo.directContext(), syncResult.pixmap(), 0, 0);
1416 
1417     float tol[4] = {};  // expect exactly same pixels, no conversions.
1418     auto error = std::function<ComparePixmapsErrorReporter>([&](int x, int y,
1419                                                                 const float diffs[4]) {
1420       SkASSERT(x >= 0 && y >= 0);
1421       ERRORF(reporter, "Expect sync and async read to be the same. "
1422              "Error at %d, %d. Diff in floats: (%f, %f, %f, %f)",
1423              x, y, diffs[0], diffs[1], diffs[2], diffs[3]);
1424     });
1425 
1426     ComparePixels(syncResult.pixmap(), asyncResult, tol, error);
1427 }
1428