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