• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2011 Google Inc.
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 <initializer_list>
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkSurface.h"
11 #include "include/effects/SkGradientShader.h"
12 #include "include/gpu/GrContext.h"
13 #include "include/private/SkColorData.h"
14 #include "include/private/SkHalf.h"
15 #include "include/private/SkImageInfoPriv.h"
16 #include "include/utils/SkNWayCanvas.h"
17 #include "src/core/SkAutoPixmapStorage.h"
18 #include "src/core/SkConvertPixels.h"
19 #include "src/core/SkMathPriv.h"
20 #include "src/gpu/GrContextPriv.h"
21 #include "src/gpu/GrImageInfo.h"
22 #include "tests/Test.h"
23 #include "tests/TestUtils.h"
24 #include "tools/ToolUtils.h"
25 #include "tools/gpu/GrContextFactory.h"
26 #include "tools/gpu/ProxyUtils.h"
27 
28 static const int DEV_W = 100, DEV_H = 100;
29 static const SkIRect DEV_RECT = SkIRect::MakeWH(DEV_W, DEV_H);
30 static const SkRect DEV_RECT_S = SkRect::MakeWH(DEV_W * SK_Scalar1,
31                                                 DEV_H * SK_Scalar1);
32 
get_src_color(int x,int y)33 static SkPMColor get_src_color(int x, int y) {
34     SkASSERT(x >= 0 && x < DEV_W);
35     SkASSERT(y >= 0 && y < DEV_H);
36 
37     U8CPU r = x;
38     U8CPU g = y;
39     U8CPU b = 0xc;
40 
41     U8CPU a = 0xff;
42     switch ((x+y) % 5) {
43         case 0:
44             a = 0xff;
45             break;
46         case 1:
47             a = 0x80;
48             break;
49         case 2:
50             a = 0xCC;
51             break;
52         case 4:
53             a = 0x01;
54             break;
55         case 3:
56             a = 0x00;
57             break;
58     }
59     return SkPremultiplyARGBInline(a, r, g, b);
60 }
61 
get_dst_bmp_init_color(int x,int y,int w)62 static SkPMColor get_dst_bmp_init_color(int x, int y, int w) {
63     int n = y * w + x;
64 
65     U8CPU b = n & 0xff;
66     U8CPU g = (n >> 8) & 0xff;
67     U8CPU r = (n >> 16) & 0xff;
68     return SkPackARGB32(0xff, r, g , b);
69 }
70 
71 // TODO: Make this consider both ATs
convert_to_pmcolor(SkColorType ct,SkAlphaType at,const uint32_t * addr,bool * doUnpremul)72 static SkPMColor convert_to_pmcolor(SkColorType ct, SkAlphaType at, const uint32_t* addr,
73                                     bool* doUnpremul) {
74     *doUnpremul = (kUnpremul_SkAlphaType == at);
75 
76     const uint8_t* c = reinterpret_cast<const uint8_t*>(addr);
77     U8CPU a,r,g,b;
78     switch (ct) {
79         case kBGRA_8888_SkColorType:
80             b = static_cast<U8CPU>(c[0]);
81             g = static_cast<U8CPU>(c[1]);
82             r = static_cast<U8CPU>(c[2]);
83             a = static_cast<U8CPU>(c[3]);
84             break;
85         case kRGB_888x_SkColorType:  // fallthrough
86         case kRGBA_8888_SkColorType:
87             r = static_cast<U8CPU>(c[0]);
88             g = static_cast<U8CPU>(c[1]);
89             b = static_cast<U8CPU>(c[2]);
90             // We set this even when for kRGB_888x because our caller will validate that it is 0xff.
91             a = static_cast<U8CPU>(c[3]);
92             break;
93         default:
94             SkDEBUGFAIL("Unexpected colortype");
95             return 0;
96     }
97 
98     if (*doUnpremul) {
99         r = SkMulDiv255Ceiling(r, a);
100         g = SkMulDiv255Ceiling(g, a);
101         b = SkMulDiv255Ceiling(b, a);
102     }
103     return SkPackARGB32(a, r, g, b);
104 }
105 
make_src_bitmap()106 static SkBitmap make_src_bitmap() {
107     static SkBitmap bmp;
108     if (bmp.isNull()) {
109         bmp.allocN32Pixels(DEV_W, DEV_H);
110         intptr_t pixels = reinterpret_cast<intptr_t>(bmp.getPixels());
111         for (int y = 0; y < DEV_H; ++y) {
112             for (int x = 0; x < DEV_W; ++x) {
113                 SkPMColor* pixel = reinterpret_cast<SkPMColor*>(pixels + y * bmp.rowBytes() + x * bmp.bytesPerPixel());
114                 *pixel = get_src_color(x, y);
115             }
116         }
117     }
118     return bmp;
119 }
120 
fill_src_canvas(SkCanvas * canvas)121 static void fill_src_canvas(SkCanvas* canvas) {
122     canvas->save();
123     canvas->setMatrix(SkMatrix::I());
124     canvas->clipRect(DEV_RECT_S, kReplace_SkClipOp);
125     SkPaint paint;
126     paint.setBlendMode(SkBlendMode::kSrc);
127     canvas->drawBitmap(make_src_bitmap(), 0, 0, &paint);
128     canvas->restore();
129 }
130 
fill_dst_bmp_with_init_data(SkBitmap * bitmap)131 static void fill_dst_bmp_with_init_data(SkBitmap* bitmap) {
132     int w = bitmap->width();
133     int h = bitmap->height();
134     intptr_t pixels = reinterpret_cast<intptr_t>(bitmap->getPixels());
135     for (int y = 0; y < h; ++y) {
136         for (int x = 0; x < w; ++x) {
137             SkPMColor initColor = get_dst_bmp_init_color(x, y, w);
138             if (kAlpha_8_SkColorType == bitmap->colorType()) {
139                 uint8_t* alpha = reinterpret_cast<uint8_t*>(pixels + y * bitmap->rowBytes() + x);
140                 *alpha = SkGetPackedA32(initColor);
141             } else {
142                 SkPMColor* pixel = reinterpret_cast<SkPMColor*>(pixels + y * bitmap->rowBytes() + x * bitmap->bytesPerPixel());
143                 *pixel = initColor;
144             }
145         }
146     }
147 }
148 
check_read_pixel(SkPMColor a,SkPMColor b,bool didPremulConversion)149 static bool check_read_pixel(SkPMColor a, SkPMColor b, bool didPremulConversion) {
150     if (!didPremulConversion) {
151         return a == b;
152     }
153     int32_t aA = static_cast<int32_t>(SkGetPackedA32(a));
154     int32_t aR = static_cast<int32_t>(SkGetPackedR32(a));
155     int32_t aG = static_cast<int32_t>(SkGetPackedG32(a));
156     int32_t aB = SkGetPackedB32(a);
157 
158     int32_t bA = static_cast<int32_t>(SkGetPackedA32(b));
159     int32_t bR = static_cast<int32_t>(SkGetPackedR32(b));
160     int32_t bG = static_cast<int32_t>(SkGetPackedG32(b));
161     int32_t bB = static_cast<int32_t>(SkGetPackedB32(b));
162 
163     return aA == bA &&
164            SkAbs32(aR - bR) <= 1 &&
165            SkAbs32(aG - bG) <= 1 &&
166            SkAbs32(aB - bB) <= 1;
167 }
168 
169 // checks the bitmap contains correct pixels after the readPixels
170 // if the bitmap was prefilled with pixels it checks that these weren't
171 // overwritten in the area outside the readPixels.
check_read(skiatest::Reporter * reporter,const SkBitmap & bitmap,int x,int y,bool checkSurfacePixels,bool checkBitmapPixels,SkImageInfo surfaceInfo)172 static bool check_read(skiatest::Reporter* reporter, const SkBitmap& bitmap, int x, int y,
173                        bool checkSurfacePixels, bool checkBitmapPixels,
174                        SkImageInfo surfaceInfo) {
175     SkAlphaType bmpAT = bitmap.alphaType();
176     SkColorType bmpCT = bitmap.colorType();
177     SkASSERT(!bitmap.isNull());
178     SkASSERT(checkSurfacePixels || checkBitmapPixels);
179 
180     int bw = bitmap.width();
181     int bh = bitmap.height();
182 
183     SkIRect srcRect = SkIRect::MakeXYWH(x, y, bw, bh);
184     SkIRect clippedSrcRect = DEV_RECT;
185     if (!clippedSrcRect.intersect(srcRect)) {
186         clippedSrcRect.setEmpty();
187     }
188     if (kAlpha_8_SkColorType == bmpCT) {
189         for (int by = 0; by < bh; ++by) {
190             for (int bx = 0; bx < bw; ++bx) {
191                 int devx = bx + srcRect.fLeft;
192                 int devy = by + srcRect.fTop;
193                 const uint8_t* alpha = bitmap.getAddr8(bx, by);
194 
195                 if (clippedSrcRect.contains(devx, devy)) {
196                     if (checkSurfacePixels) {
197                         uint8_t surfaceAlpha = (surfaceInfo.alphaType() == kOpaque_SkAlphaType)
198                                                        ? 0xFF
199                                                        : SkGetPackedA32(get_src_color(devx, devy));
200                         if (surfaceAlpha != *alpha) {
201                             ERRORF(reporter,
202                                    "Expected readback alpha (%d, %d) value 0x%02x, got 0x%02x. ",
203                                    bx, by, surfaceAlpha, *alpha);
204                             return false;
205                         }
206                     }
207                 } else if (checkBitmapPixels) {
208                     uint32_t origDstAlpha = SkGetPackedA32(get_dst_bmp_init_color(bx, by, bw));
209                     if (origDstAlpha != *alpha) {
210                         ERRORF(reporter, "Expected clipped out area of readback to be unchanged. "
211                             "Expected 0x%02x, got 0x%02x", origDstAlpha, *alpha);
212                         return false;
213                     }
214                 }
215             }
216         }
217         return true;
218     }
219     for (int by = 0; by < bh; ++by) {
220         for (int bx = 0; bx < bw; ++bx) {
221             int devx = bx + srcRect.fLeft;
222             int devy = by + srcRect.fTop;
223 
224             const uint32_t* pixel = bitmap.getAddr32(bx, by);
225 
226             if (clippedSrcRect.contains(devx, devy)) {
227                 if (checkSurfacePixels) {
228                     SkPMColor surfacePMColor = get_src_color(devx, devy);
229                     if (SkColorTypeIsAlphaOnly(surfaceInfo.colorType())) {
230                         surfacePMColor &= 0xFF000000;
231                     }
232                     if (kOpaque_SkAlphaType == surfaceInfo.alphaType() || kOpaque_SkAlphaType == bmpAT) {
233                         surfacePMColor |= 0xFF000000;
234                     }
235                     bool didPremul;
236                     SkPMColor pmPixel = convert_to_pmcolor(bmpCT, bmpAT, pixel, &didPremul);
237                     if (!check_read_pixel(pmPixel, surfacePMColor, didPremul)) {
238                         ERRORF(reporter,
239                                "Expected readback pixel (%d, %d) value 0x%08x, got 0x%08x. "
240                                "Readback was unpremul: %d",
241                                bx, by, surfacePMColor, pmPixel, didPremul);
242                         return false;
243                     }
244                 }
245             } else if (checkBitmapPixels) {
246                 uint32_t origDstPixel = get_dst_bmp_init_color(bx, by, bw);
247                 if (origDstPixel != *pixel) {
248                     ERRORF(reporter, "Expected clipped out area of readback to be unchanged. "
249                            "Expected 0x%08x, got 0x%08x", origDstPixel, *pixel);
250                     return false;
251                 }
252             }
253         }
254     }
255     return true;
256 }
257 
258 enum class TightRowBytes : bool { kNo, kYes };
259 
init_bitmap(SkBitmap * bitmap,const SkIRect & rect,TightRowBytes tightRB,SkColorType ct,SkAlphaType at)260 static void init_bitmap(SkBitmap* bitmap, const SkIRect& rect, TightRowBytes tightRB,
261                         SkColorType ct, SkAlphaType at) {
262     SkImageInfo info = SkImageInfo::Make(rect.size(), ct, at);
263     size_t rowBytes = 0;
264     if (tightRB == TightRowBytes::kNo) {
265         rowBytes = SkAlign4((info.width() + 16) * info.bytesPerPixel());
266     }
267     bitmap->allocPixels(info, rowBytes);
268 }
269 
270 static const struct {
271     SkColorType fColorType;
272     SkAlphaType fAlphaType;
273 } gReadPixelsConfigs[] = {
274         {kRGBA_8888_SkColorType, kPremul_SkAlphaType},
275         {kRGBA_8888_SkColorType, kUnpremul_SkAlphaType},
276         {kRGB_888x_SkColorType, kOpaque_SkAlphaType},
277         {kBGRA_8888_SkColorType, kPremul_SkAlphaType},
278         {kBGRA_8888_SkColorType, kUnpremul_SkAlphaType},
279         {kAlpha_8_SkColorType, kPremul_SkAlphaType},
280 };
281 const SkIRect gReadPixelsTestRects[] = {
282     // entire thing
283     DEV_RECT,
284     // larger on all sides
285     SkIRect::MakeLTRB(-10, -10, DEV_W + 10, DEV_H + 10),
286     // fully contained
287     SkIRect::MakeLTRB(DEV_W / 4, DEV_H / 4, 3 * DEV_W / 4, 3 * DEV_H / 4),
288     // outside top left
289     SkIRect::MakeLTRB(-10, -10, -1, -1),
290     // touching top left corner
291     SkIRect::MakeLTRB(-10, -10, 0, 0),
292     // overlapping top left corner
293     SkIRect::MakeLTRB(-10, -10, DEV_W / 4, DEV_H / 4),
294     // overlapping top left and top right corners
295     SkIRect::MakeLTRB(-10, -10, DEV_W  + 10, DEV_H / 4),
296     // touching entire top edge
297     SkIRect::MakeLTRB(-10, -10, DEV_W  + 10, 0),
298     // overlapping top right corner
299     SkIRect::MakeLTRB(3 * DEV_W / 4, -10, DEV_W  + 10, DEV_H / 4),
300     // contained in x, overlapping top edge
301     SkIRect::MakeLTRB(DEV_W / 4, -10, 3 * DEV_W  / 4, DEV_H / 4),
302     // outside top right corner
303     SkIRect::MakeLTRB(DEV_W + 1, -10, DEV_W + 10, -1),
304     // touching top right corner
305     SkIRect::MakeLTRB(DEV_W, -10, DEV_W + 10, 0),
306     // overlapping top left and bottom left corners
307     SkIRect::MakeLTRB(-10, -10, DEV_W / 4, DEV_H + 10),
308     // touching entire left edge
309     SkIRect::MakeLTRB(-10, -10, 0, DEV_H + 10),
310     // overlapping bottom left corner
311     SkIRect::MakeLTRB(-10, 3 * DEV_H / 4, DEV_W / 4, DEV_H + 10),
312     // contained in y, overlapping left edge
313     SkIRect::MakeLTRB(-10, DEV_H / 4, DEV_W / 4, 3 * DEV_H / 4),
314     // outside bottom left corner
315     SkIRect::MakeLTRB(-10, DEV_H + 1, -1, DEV_H + 10),
316     // touching bottom left corner
317     SkIRect::MakeLTRB(-10, DEV_H, 0, DEV_H + 10),
318     // overlapping bottom left and bottom right corners
319     SkIRect::MakeLTRB(-10, 3 * DEV_H / 4, DEV_W + 10, DEV_H + 10),
320     // touching entire left edge
321     SkIRect::MakeLTRB(0, DEV_H, DEV_W, DEV_H + 10),
322     // overlapping bottom right corner
323     SkIRect::MakeLTRB(3 * DEV_W / 4, 3 * DEV_H / 4, DEV_W + 10, DEV_H + 10),
324     // overlapping top right and bottom right corners
325     SkIRect::MakeLTRB(3 * DEV_W / 4, -10, DEV_W + 10, DEV_H + 10),
326 };
327 
read_should_succeed(const SkIRect & srcRect,const SkImageInfo & dstInfo,const SkImageInfo & srcInfo)328 bool read_should_succeed(const SkIRect& srcRect, const SkImageInfo& dstInfo,
329                          const SkImageInfo& srcInfo) {
330     return SkIRect::Intersects(srcRect, DEV_RECT) && SkImageInfoValidConversion(dstInfo, srcInfo);
331 }
332 
test_readpixels(skiatest::Reporter * reporter,const sk_sp<SkSurface> & surface,const SkImageInfo & surfaceInfo)333 static void test_readpixels(skiatest::Reporter* reporter, const sk_sp<SkSurface>& surface,
334                             const SkImageInfo& surfaceInfo) {
335     SkCanvas* canvas = surface->getCanvas();
336     fill_src_canvas(canvas);
337     for (size_t rect = 0; rect < SK_ARRAY_COUNT(gReadPixelsTestRects); ++rect) {
338         const SkIRect& srcRect = gReadPixelsTestRects[rect];
339         for (auto tightRB : {TightRowBytes::kYes, TightRowBytes::kNo}) {
340             for (size_t c = 0; c < SK_ARRAY_COUNT(gReadPixelsConfigs); ++c) {
341                 SkBitmap bmp;
342                 init_bitmap(&bmp, srcRect, tightRB, gReadPixelsConfigs[c].fColorType,
343                             gReadPixelsConfigs[c].fAlphaType);
344 
345                 // if the bitmap has pixels allocated before the readPixels,
346                 // note that and fill them with pattern
347                 bool startsWithPixels = !bmp.isNull();
348                 if (startsWithPixels) {
349                     fill_dst_bmp_with_init_data(&bmp);
350                 }
351                 uint32_t idBefore = surface->generationID();
352                 bool success = surface->readPixels(bmp, srcRect.fLeft, srcRect.fTop);
353                 uint32_t idAfter = surface->generationID();
354 
355                 // we expect to succeed when the read isn't fully clipped out and the infos are
356                 // compatible.
357                 bool expectSuccess = read_should_succeed(srcRect, bmp.info(), surfaceInfo);
358                 // determine whether we expected the read to succeed.
359                 REPORTER_ASSERT(reporter, expectSuccess == success,
360                                 "Read succeed=%d unexpectedly, src ct/at: %d/%d, dst ct/at: %d/%d",
361                                 success, surfaceInfo.colorType(), surfaceInfo.alphaType(),
362                                 bmp.info().colorType(), bmp.info().alphaType());
363                 // read pixels should never change the gen id
364                 REPORTER_ASSERT(reporter, idBefore == idAfter);
365 
366                 if (success || startsWithPixels) {
367                     check_read(reporter, bmp, srcRect.fLeft, srcRect.fTop, success,
368                                startsWithPixels, surfaceInfo);
369                 } else {
370                     // if we had no pixels beforehand and the readPixels
371                     // failed then our bitmap should still not have pixels
372                     REPORTER_ASSERT(reporter, bmp.isNull());
373                 }
374             }
375         }
376     }
377 }
378 
DEF_TEST(ReadPixels,reporter)379 DEF_TEST(ReadPixels, reporter) {
380     const SkImageInfo info = SkImageInfo::MakeN32Premul(DEV_W, DEV_H);
381     auto surface(SkSurface::MakeRaster(info));
382     test_readpixels(reporter, surface, info);
383 }
384 
test_readpixels_texture(skiatest::Reporter * reporter,std::unique_ptr<GrSurfaceContext> sContext,const SkImageInfo & surfaceInfo)385 static void test_readpixels_texture(skiatest::Reporter* reporter,
386                                     std::unique_ptr<GrSurfaceContext> sContext,
387                                     const SkImageInfo& surfaceInfo) {
388     for (size_t rect = 0; rect < SK_ARRAY_COUNT(gReadPixelsTestRects); ++rect) {
389         const SkIRect& srcRect = gReadPixelsTestRects[rect];
390         for (auto tightRB : {TightRowBytes::kYes, TightRowBytes::kNo}) {
391             for (size_t c = 0; c < SK_ARRAY_COUNT(gReadPixelsConfigs); ++c) {
392                 SkBitmap bmp;
393                 init_bitmap(&bmp, srcRect, tightRB, gReadPixelsConfigs[c].fColorType,
394                             gReadPixelsConfigs[c].fAlphaType);
395 
396                 // if the bitmap has pixels allocated before the readPixels,
397                 // note that and fill them with pattern
398                 bool startsWithPixels = !bmp.isNull();
399                 // Try doing the read directly from a non-renderable texture
400                 if (startsWithPixels) {
401                     fill_dst_bmp_with_init_data(&bmp);
402                     bool success = sContext->readPixels(bmp.info(), bmp.getPixels(), bmp.rowBytes(),
403                                                         {srcRect.fLeft, srcRect.fTop});
404                     auto expectSuccess = read_should_succeed(srcRect, bmp.info(), surfaceInfo);
405                     REPORTER_ASSERT(
406                             reporter, expectSuccess == success,
407                             "Read succeed=%d unexpectedly, src ct/at: %d/%d, dst ct/at: %d/%d",
408                             success, surfaceInfo.colorType(), surfaceInfo.alphaType(),
409                             bmp.info().colorType(), bmp.info().alphaType());
410                     if (success) {
411                         check_read(reporter, bmp, srcRect.fLeft, srcRect.fTop, success, true,
412                                    surfaceInfo);
413                     }
414                 }
415             }
416         }
417     }
418 }
419 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ReadPixels_Texture,reporter,ctxInfo)420 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ReadPixels_Texture, reporter, ctxInfo) {
421     GrContext* context = ctxInfo.grContext();
422     SkBitmap bmp = make_src_bitmap();
423 
424     // On the GPU we will also try reading back from a non-renderable texture.
425     for (auto origin : {kBottomLeft_GrSurfaceOrigin, kTopLeft_GrSurfaceOrigin}) {
426         for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) {
427             sk_sp<GrTextureProxy> proxy = sk_gpu_test::MakeTextureProxyFromData(
428                     context, renderable, origin, bmp.info(), bmp.getPixels(), bmp.rowBytes());
429             GrColorType grColorType = SkColorTypeToGrColorType(bmp.colorType());
430             GrSwizzle swizzle = context->priv().caps()->getReadSwizzle(proxy->backendFormat(),
431                                                                        grColorType);
432             GrSurfaceProxyView view(std::move(proxy), origin, swizzle);
433             auto sContext = GrSurfaceContext::Make(context, std::move(view),
434                     grColorType, kPremul_SkAlphaType, nullptr);
435             auto info = SkImageInfo::Make(DEV_W, DEV_H, kN32_SkColorType, kPremul_SkAlphaType);
436             test_readpixels_texture(reporter, std::move(sContext), info);
437         }
438     }
439 }
440 
441 ///////////////////////////////////////////////////////////////////////////////////////////////////
442 
443 static const uint32_t kNumPixels = 5;
444 
445 // The five reference pixels are: red, green, blue, white, black.
446 // Five is an interesting number to test because we'll exercise a full 4-wide SIMD vector
447 // plus a tail pixel.
448 static const uint32_t rgba[kNumPixels] = {
449         0xFF0000FF, 0xFF00FF00, 0xFFFF0000, 0xFFFFFFFF, 0xFF000000
450 };
451 static const uint32_t bgra[kNumPixels] = {
452         0xFFFF0000, 0xFF00FF00, 0xFF0000FF, 0xFFFFFFFF, 0xFF000000
453 };
454 static const uint16_t rgb565[kNumPixels] = {
455         SK_R16_MASK_IN_PLACE, SK_G16_MASK_IN_PLACE, SK_B16_MASK_IN_PLACE, 0xFFFF, 0x0
456 };
457 
458 static const uint16_t rgba4444[kNumPixels] = { 0xF00F, 0x0F0F, 0x00FF, 0xFFFF, 0x000F };
459 
460 static const uint64_t kRed      = (uint64_t) SK_Half1 <<  0;
461 static const uint64_t kGreen    = (uint64_t) SK_Half1 << 16;
462 static const uint64_t kBlue     = (uint64_t) SK_Half1 << 32;
463 static const uint64_t kAlpha    = (uint64_t) SK_Half1 << 48;
464 static const uint64_t f16[kNumPixels] = {
465         kAlpha | kRed, kAlpha | kGreen, kAlpha | kBlue, kAlpha | kBlue | kGreen | kRed, kAlpha
466 };
467 
468 static const uint8_t alpha8[kNumPixels] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
469 static const uint8_t gray8[kNumPixels] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
470 
five_reference_pixels(SkColorType colorType)471 static const void* five_reference_pixels(SkColorType colorType) {
472     switch (colorType) {
473         case kUnknown_SkColorType:
474             return nullptr;
475         case kAlpha_8_SkColorType:
476             return alpha8;
477         case kRGB_565_SkColorType:
478             return rgb565;
479         case kARGB_4444_SkColorType:
480             return rgba4444;
481         case kRGBA_8888_SkColorType:
482             return rgba;
483         case kBGRA_8888_SkColorType:
484             return bgra;
485         case kGray_8_SkColorType:
486             return gray8;
487         case kRGBA_F16_SkColorType:
488             return f16;
489         default:
490             return nullptr;
491     }
492 
493     SkASSERT(false);
494     return nullptr;
495 }
496 
test_conversion(skiatest::Reporter * r,const SkImageInfo & dstInfo,const SkImageInfo & srcInfo)497 static void test_conversion(skiatest::Reporter* r, const SkImageInfo& dstInfo,
498                             const SkImageInfo& srcInfo) {
499     if (!SkImageInfoIsValid(srcInfo)) {
500         return;
501     }
502 
503     const void* srcPixels = five_reference_pixels(srcInfo.colorType());
504     SkPixmap srcPixmap(srcInfo, srcPixels, srcInfo.minRowBytes());
505     sk_sp<SkImage> src = SkImage::MakeFromRaster(srcPixmap, nullptr, nullptr);
506     REPORTER_ASSERT(r, src);
507 
508     // Enough space for 5 pixels when color type is F16, more than enough space in other cases.
509     uint64_t dstPixels[kNumPixels];
510     SkPixmap dstPixmap(dstInfo, dstPixels, dstInfo.minRowBytes());
511     bool success = src->readPixels(dstPixmap, 0, 0);
512     REPORTER_ASSERT(r, success == SkImageInfoValidConversion(dstInfo, srcInfo));
513 
514     if (success) {
515         if (kGray_8_SkColorType == srcInfo.colorType() &&
516             kGray_8_SkColorType != dstInfo.colorType()) {
517             // TODO: test (r,g,b) == (gray,gray,gray)?
518             return;
519         }
520 
521         if (kGray_8_SkColorType == dstInfo.colorType() &&
522             kGray_8_SkColorType != srcInfo.colorType()) {
523             // TODO: test gray = luminance?
524             return;
525         }
526 
527         if (kAlpha_8_SkColorType == srcInfo.colorType() &&
528             kAlpha_8_SkColorType != dstInfo.colorType()) {
529             // TODO: test output = black with this alpha?
530             return;
531         }
532 
533         REPORTER_ASSERT(r, 0 == memcmp(dstPixels, five_reference_pixels(dstInfo.colorType()),
534                                        kNumPixels * SkColorTypeBytesPerPixel(dstInfo.colorType())));
535     }
536 }
537 
DEF_TEST(ReadPixels_ValidConversion,reporter)538 DEF_TEST(ReadPixels_ValidConversion, reporter) {
539     const SkColorType kColorTypes[] = {
540             kUnknown_SkColorType,
541             kAlpha_8_SkColorType,
542             kRGB_565_SkColorType,
543             kARGB_4444_SkColorType,
544             kRGBA_8888_SkColorType,
545             kBGRA_8888_SkColorType,
546             kGray_8_SkColorType,
547             kRGBA_F16_SkColorType,
548     };
549 
550     const SkAlphaType kAlphaTypes[] = {
551             kUnknown_SkAlphaType,
552             kOpaque_SkAlphaType,
553             kPremul_SkAlphaType,
554             kUnpremul_SkAlphaType,
555     };
556 
557     const sk_sp<SkColorSpace> kColorSpaces[] = {
558             nullptr,
559             SkColorSpace::MakeSRGB(),
560     };
561 
562     for (SkColorType dstCT : kColorTypes) {
563         for (SkAlphaType dstAT: kAlphaTypes) {
564             for (sk_sp<SkColorSpace> dstCS : kColorSpaces) {
565                 for (SkColorType srcCT : kColorTypes) {
566                     for (SkAlphaType srcAT: kAlphaTypes) {
567                         for (sk_sp<SkColorSpace> srcCS : kColorSpaces) {
568                             test_conversion(reporter,
569                                             SkImageInfo::Make(kNumPixels, 1, dstCT, dstAT, dstCS),
570                                             SkImageInfo::Make(kNumPixels, 1, srcCT, srcAT, srcCS));
571                         }
572                     }
573                 }
574             }
575         }
576     }
577 }
578 
min_rgb_channel_bits(SkColorType ct)579 static constexpr int min_rgb_channel_bits(SkColorType ct) {
580     switch (ct) {
581         case kUnknown_SkColorType:            return 0;
582         case kAlpha_8_SkColorType:            return 0;
583         case kA16_unorm_SkColorType:          return 0;
584         case kA16_float_SkColorType:          return 0;
585         case kRGB_565_SkColorType:            return 5;
586         case kARGB_4444_SkColorType:          return 4;
587         case kR8G8_unorm_SkColorType:         return 8;
588         case kR16G16_unorm_SkColorType:       return 16;
589         case kR16G16_float_SkColorType:       return 16;
590         case kRGBA_8888_SkColorType:          return 8;
591         case kRGB_888x_SkColorType:           return 8;
592         case kBGRA_8888_SkColorType:          return 8;
593         case kRGBA_1010102_SkColorType:       return 10;
594         case kRGB_101010x_SkColorType:        return 10;
595         case kBGRA_1010102_SkColorType:       return 10;
596         case kBGR_101010x_SkColorType:        return 10;
597         case kGray_8_SkColorType:             return 8;   // counting gray as "rgb"
598         case kRGBA_F16Norm_SkColorType:       return 10;  // just counting the mantissa
599         case kRGBA_F16_SkColorType:           return 10;  // just counting the mantissa
600         case kRGBA_F32_SkColorType:           return 23;  // just counting the mantissa
601         case kR16G16B16A16_unorm_SkColorType: return 16;
602     }
603     SkUNREACHABLE;
604 }
605 
alpha_channel_bits(SkColorType ct)606 static constexpr int alpha_channel_bits(SkColorType ct) {
607     switch (ct) {
608         case kUnknown_SkColorType:            return 0;
609         case kAlpha_8_SkColorType:            return 8;
610         case kA16_unorm_SkColorType:          return 16;
611         case kA16_float_SkColorType:          return 16;
612         case kRGB_565_SkColorType:            return 0;
613         case kARGB_4444_SkColorType:          return 4;
614         case kR8G8_unorm_SkColorType:         return 0;
615         case kR16G16_unorm_SkColorType:       return 0;
616         case kR16G16_float_SkColorType:       return 0;
617         case kRGBA_8888_SkColorType:          return 8;
618         case kRGB_888x_SkColorType:           return 0;
619         case kBGRA_8888_SkColorType:          return 8;
620         case kRGBA_1010102_SkColorType:       return 2;
621         case kRGB_101010x_SkColorType:        return 0;
622         case kBGRA_1010102_SkColorType:       return 2;
623         case kBGR_101010x_SkColorType:        return 0;
624         case kGray_8_SkColorType:             return 0;
625         case kRGBA_F16Norm_SkColorType:       return 10;  // just counting the mantissa
626         case kRGBA_F16_SkColorType:           return 10;  // just counting the mantissa
627         case kRGBA_F32_SkColorType:           return 23;  // just counting the mantissa
628         case kR16G16B16A16_unorm_SkColorType: return 16;
629     }
630     SkUNREACHABLE;
631 }
632 
633 namespace {
634 
635 struct GpuReadPixelTestRules {
636     // Test unpremul sources? We could omit this and detect that creating the source of the read
637     // failed but having it lets us skip generating reference color data.
638     bool fAllowUnpremulSrc = true;
639     // Expect read function to succeed for kUnpremul?
640     bool fAllowUnpremulRead = true;
641     // Are reads that are overlapping but not contained by the src bounds expected to succeed?
642     bool fUncontainedRectSucceeds = true;
643 };
644 
645 // Makes a src populated with the pixmap. The src should get its image info (or equivalent) from
646 // the pixmap.
647 template <typename T> using GpuSrcFactory = T(SkPixmap&);
648 
649 // Does a read from the T into the pixmap.
650 template <typename T> using GpuReadSrcFn = bool(const T&, const SkIVector& offset, const SkPixmap&);
651 
652 }  // anonymous namespace
653 
654 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)655 static void gpu_read_pixels_test_driver(skiatest::Reporter* reporter,
656                                         const GpuReadPixelTestRules& rules,
657                                         const std::function<GpuSrcFactory<T>>& srcFactory,
658                                         const std::function<GpuReadSrcFn<T>>& read) {
659     // Separate this out just to give it some line width to breathe. Note 'srcPixels' should have
660     // the same image info as src. We will do a converting readPixels() on it to get the data
661     // to compare with the results of 'read'.
662     auto runTest = [&](const T& src, const SkPixmap& srcPixels, const SkImageInfo& readInfo,
663                        const SkIVector& offset) {
664         const bool csConversion =
665                 !SkColorSpace::Equals(readInfo.colorSpace(), srcPixels.info().colorSpace());
666         const auto readCT = readInfo.colorType();
667         const auto readAT = readInfo.alphaType();
668         const auto srcCT = srcPixels.info().colorType();
669         const auto srcAT = srcPixels.info().alphaType();
670         const auto rect = SkIRect::MakeWH(readInfo.width(), readInfo.height()).makeOffset(offset);
671         const auto surfBounds = SkIRect::MakeWH(srcPixels.width(), srcPixels.height());
672         const size_t readBpp = SkColorTypeBytesPerPixel(readCT);
673 
674         // Make the row bytes in the dst be loose for extra stress.
675         const size_t dstRB = readBpp * readInfo.width() + 10 * readBpp;
676         // This will make the last row tight.
677         const size_t dstSize = readInfo.computeByteSize(dstRB);
678         std::unique_ptr<char[]> dstData(new char[dstSize]);
679         SkPixmap dstPixels(readInfo, dstData.get(), dstRB);
680         // Initialize with an arbitrary value for each byte. Later we will check that only the
681         // correct part of the destination gets overwritten by 'read'.
682         static constexpr auto kInitialByte = static_cast<char>(0x1B);
683         std::fill_n(static_cast<char*>(dstPixels.writable_addr()),
684                     dstPixels.computeByteSize(),
685                     kInitialByte);
686 
687         const bool success = read(src, offset, dstPixels);
688 
689         if (!SkIRect::Intersects(rect, surfBounds)) {
690             REPORTER_ASSERT(reporter, !success);
691         } else if (readCT == kUnknown_SkColorType) {
692             REPORTER_ASSERT(reporter, !success);
693         } else if (readAT == kUnknown_SkAlphaType) {
694             REPORTER_ASSERT(reporter, !success);
695         } else if (!rules.fUncontainedRectSucceeds && !surfBounds.contains(rect)) {
696             REPORTER_ASSERT(reporter, !success);
697         } else if (!rules.fAllowUnpremulRead && readAT == kUnpremul_SkAlphaType) {
698             REPORTER_ASSERT(reporter, !success);
699         } else if (!success) {
700             // TODO: Support RGB/BGR 101010x, BGRA 1010102 on the GPU.
701             if (SkColorTypeToGrColorType(readCT) != GrColorType::kUnknown) {
702                 ERRORF(reporter,
703                        "Read failed. Src CT: %s, Src AT: %s Read CT: %s, Read AT: %s, "
704                        "Rect [%d, %d, %d, %d], CS conversion: %d\n",
705                        ToolUtils::colortype_name(srcCT), ToolUtils::alphatype_name(srcAT),
706                        ToolUtils::colortype_name(readCT), ToolUtils::alphatype_name(readAT),
707                        rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, csConversion);
708             }
709             return;
710         }
711 
712         bool guardOk = true;
713         auto guardCheck = [](char x) { return x == kInitialByte; };
714 
715         // Considering the rect we tried to read and the surface bounds figure  out which pixels in
716         // both src and dst space should actually have been read and written.
717         SkIRect srcReadRect;
718         if (success && srcReadRect.intersect(surfBounds, rect)) {
719             SkIRect dstWriteRect = srcReadRect.makeOffset(-rect.fLeft, -rect.fTop);
720 
721             const bool lumConversion =
722                     !(SkColorTypeComponentFlags(srcCT)  & kGray_SkColorTypeComponentFlag) &&
723                      (SkColorTypeComponentFlags(readCT) & kGray_SkColorTypeComponentFlag);
724             // A CS or luminance conversion allows a 3 value difference and otherwise a 2 value
725             // difference. Note that sometimes read back on GPU can be lossy even when there no
726             // conversion at allbecause GPU->CPU read may go to a lower bit depth format and then be
727             // promoted back to the original type. For example, GL ES cannot read to 1010102, so we
728             // go through 8888.
729             const float numer = (lumConversion || csConversion) ? 3.f : 2.f;
730             int rgbBits = std::min({min_rgb_channel_bits(readCT),
731                                     min_rgb_channel_bits(srcCT),
732                                     8});
733             float tol = numer / (1 << rgbBits);
734             float alphaTol = 0;
735             if (readAT != kOpaque_SkAlphaType && srcAT != kOpaque_SkAlphaType) {
736                 const int alphaBits = std::min(alpha_channel_bits(readCT),
737                                                alpha_channel_bits(srcCT));
738                 alphaTol = 2.f / (1 << alphaBits);
739             }
740 
741             const float tols[4] = {tol, tol, tol, alphaTol};
742             auto error = std::function<ComparePixmapsErrorReporter>([&](int x, int y,
743                                                                         const float diffs[4]) {
744                 SkASSERT(x >= 0 && y >= 0);
745                 ERRORF(reporter,
746                        "Src CT: %s, Src AT: %s, Read CT: %s, Read AT: %s, Rect [%d, %d, %d, %d]"
747                        ", CS conversion: %d\n"
748                        "Error at %d, %d. Diff in floats: (%f, %f, %f %f)",
749                        ToolUtils::colortype_name(srcCT), ToolUtils::alphatype_name(srcAT),
750                        ToolUtils::colortype_name(readCT), ToolUtils::alphatype_name(readAT),
751                        rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, csConversion, x, y,
752                        diffs[0], diffs[1], diffs[2], diffs[3]);
753             });
754             SkAutoPixmapStorage ref;
755             ref.alloc(readInfo.makeWH(dstWriteRect.width(), dstWriteRect.height()));
756             srcPixels.readPixels(ref, srcReadRect.x(), srcReadRect.y());
757             // This is the part of dstPixels that should have been updated.
758             SkPixmap actual;
759             SkAssertResult(dstPixels.extractSubset(&actual, dstWriteRect));
760             ComparePixels(ref, actual, tols, error);
761 
762             const auto* v = dstData.get();
763             const auto* end = dstData.get() + dstSize;
764             guardOk = std::all_of(v, v + dstWriteRect.top() * dstPixels.rowBytes(), guardCheck);
765             v += dstWriteRect.top() * dstPixels.rowBytes();
766             for (int y = dstWriteRect.top(); y < dstWriteRect.bottom(); ++y) {
767                 guardOk |= std::all_of(v, v + dstWriteRect.left() * readBpp, guardCheck);
768                 auto pad = v + dstWriteRect.right() * readBpp;
769                 auto rowEnd = std::min(end, v + dstPixels.rowBytes());
770                 // min protects against reading past the end of the tight last row.
771                 guardOk |= std::all_of(pad, rowEnd, guardCheck);
772                 v = rowEnd;
773             }
774             guardOk |= std::all_of(v, end, guardCheck);
775         } else {
776             guardOk = std::all_of(dstData.get(), dstData.get() + dstSize, guardCheck);
777         }
778         if (!guardOk) {
779             ERRORF(reporter,
780                    "Result pixels modified result outside read rect [%d, %d, %d, %d]. "
781                    "Src CT: %s, Read CT: %s, CS conversion: %d",
782                    rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
783                    ToolUtils::colortype_name(srcCT), ToolUtils::colortype_name(readCT),
784                    csConversion);
785         }
786     };
787 
788     static constexpr int kW = 16;
789     static constexpr int kH = 16;
790 
791     // Makes the reference data that is used to populate the src. Always F32 regardless of srcCT.
792     auto make_ref_f32_data = [](SkAlphaType srcAT, SkColorType srcCT) {
793         // Make src data in F32 with srcAT. We will convert it to each color type we test to
794         // initialize the src.
795         const auto refInfo =
796                 SkImageInfo::Make(kW, kH, kRGBA_F32_SkColorType, srcAT, SkColorSpace::MakeSRGB());
797         auto refSurf = SkSurface::MakeRaster(refInfo);
798         static constexpr SkPoint kPts1[] = {{0, 0}, {kW, kH}};
799         static constexpr SkColor kColors1[] = {SK_ColorGREEN, SK_ColorRED};
800         SkPaint paint;
801         paint.setShader(
802                 SkGradientShader::MakeLinear(kPts1, kColors1, nullptr, 2, SkTileMode::kClamp));
803         refSurf->getCanvas()->drawPaint(paint);
804         static constexpr SkPoint kPts2[] = {{kW, 0}, {0, kH}};
805         static constexpr SkColor kColors2[] = {SK_ColorBLUE, SK_ColorBLACK};
806         paint.setShader(
807                 SkGradientShader::MakeLinear(kPts2, kColors2, nullptr, 2, SkTileMode::kClamp));
808         paint.setBlendMode(SkBlendMode::kPlus);
809         refSurf->getCanvas()->drawPaint(paint);
810         // Keep everything opaque if the src alpha type is opaque. Also, there is an issue with
811         // 1010102 (the only color type where the number of alpha bits is non-zero and not the
812         // same as r, g, and b). Because of the different precisions the draw below can create
813         // data that isn't strictly premul (e.g. alpha is 1/3 but green is .4). SW will clamp
814         // r, g, b to a if the dst is premul and a different color type. GPU doesn't do this.
815         // We could but 1010102 premul is kind of dubious anyway. So for now just keep the data
816         // opaque.
817         if (srcAT != kOpaque_SkAlphaType &&
818             (srcAT == kPremul_SkAlphaType && srcCT != kRGBA_1010102_SkColorType
819                                           && srcCT != kBGRA_1010102_SkColorType)) {
820             static constexpr SkColor kColors3[] = {SK_ColorWHITE,
821                                                    SK_ColorWHITE,
822                                                    0x60FFFFFF,
823                                                    SK_ColorWHITE,
824                                                    SK_ColorWHITE};
825             static constexpr SkScalar kPos3[] = {0.f, 0.15f, 0.5f, 0.85f, 1.f};
826             paint.setShader(SkGradientShader::MakeRadial({kW / 2.f, kH / 2.f}, (kW + kH) / 10.f,
827                                                          kColors3, kPos3, 5, SkTileMode::kMirror));
828             paint.setBlendMode(SkBlendMode::kDstIn);
829             refSurf->getCanvas()->drawPaint(paint);
830         }
831 
832         const auto srcInfo = SkImageInfo::Make(kW, kH, srcCT, srcAT, SkColorSpace::MakeSRGB());
833         SkAutoPixmapStorage srcPixels;
834         srcPixels.alloc(srcInfo);
835         refSurf->readPixels(srcPixels, 0, 0);
836         return std::move(srcPixels);
837     };
838 
839     for (int sat = 0; sat < kLastEnum_SkAlphaType; ++sat) {
840         const auto srcAT = static_cast<SkAlphaType>(sat);
841         if (srcAT == kUnknown_SkAlphaType ||
842             (srcAT == kUnpremul_SkAlphaType && !rules.fAllowUnpremulSrc)) {
843             continue;
844         }
845         for (int sct = 0; sct <= kLastEnum_SkColorType; ++sct) {
846             const auto srcCT = static_cast<SkColorType>(sct);
847             // Note that we only currently use srcCT for a 1010102 workaround. If we remove this we
848             // can also but the ref data setup above the srcCT loop.
849             SkAutoPixmapStorage srcPixels = make_ref_f32_data(srcAT, srcCT);
850             auto src = srcFactory(srcPixels);
851             if (!src) {
852                 continue;
853             }
854             for (int rct = 0; rct <= kLastEnum_SkColorType; ++rct) {
855                 const auto readCT = static_cast<SkColorType>(rct);
856                 for (const sk_sp<SkColorSpace>& readCS :
857                      {SkColorSpace::MakeSRGB(), SkColorSpace::MakeSRGBLinear()}) {
858                     for (int at = 0; at <= kLastEnum_SkAlphaType; ++at) {
859                         const auto readAT = static_cast<SkAlphaType>(at);
860                         if (srcAT != kOpaque_SkAlphaType && readAT == kOpaque_SkAlphaType) {
861                             // This doesn't make sense.
862                             continue;
863                         }
864                         // Test full size, partial, empty, and too wide rects.
865                         for (const auto& rect : {
866                                      // entire thing
867                                      SkIRect::MakeWH(kW, kH),
868                                      // larger on all sides
869                                      SkIRect::MakeLTRB(-10, -10, kW + 10, kH + 10),
870                                      // fully contained
871                                      SkIRect::MakeLTRB(kW / 4, kH / 4, 3 * kW / 4, 3 * kH / 4),
872                                      // outside top left
873                                      SkIRect::MakeLTRB(-10, -10, -1, -1),
874                                      // touching top left corner
875                                      SkIRect::MakeLTRB(-10, -10, 0, 0),
876                                      // overlapping top left corner
877                                      SkIRect::MakeLTRB(-10, -10, kW / 4, kH / 4),
878                                      // overlapping top left and top right corners
879                                      SkIRect::MakeLTRB(-10, -10, kW + 10, kH / 4),
880                                      // touching entire top edge
881                                      SkIRect::MakeLTRB(-10, -10, kW + 10, 0),
882                                      // overlapping top right corner
883                                      SkIRect::MakeLTRB(3 * kW / 4, -10, kW + 10, kH / 4),
884                                      // contained in x, overlapping top edge
885                                      SkIRect::MakeLTRB(kW / 4, -10, 3 * kW / 4, kH / 4),
886                                      // outside top right corner
887                                      SkIRect::MakeLTRB(kW + 1, -10, kW + 10, -1),
888                                      // touching top right corner
889                                      SkIRect::MakeLTRB(kW, -10, kW + 10, 0),
890                                      // overlapping top left and bottom left corners
891                                      SkIRect::MakeLTRB(-10, -10, kW / 4, kH + 10),
892                                      // touching entire left edge
893                                      SkIRect::MakeLTRB(-10, -10, 0, kH + 10),
894                                      // overlapping bottom left corner
895                                      SkIRect::MakeLTRB(-10, 3 * kH / 4, kW / 4, kH + 10),
896                                      // contained in y, overlapping left edge
897                                      SkIRect::MakeLTRB(-10, kH / 4, kW / 4, 3 * kH / 4),
898                                      // outside bottom left corner
899                                      SkIRect::MakeLTRB(-10, kH + 1, -1, kH + 10),
900                                      // touching bottom left corner
901                                      SkIRect::MakeLTRB(-10, kH, 0, kH + 10),
902                                      // overlapping bottom left and bottom right corners
903                                      SkIRect::MakeLTRB(-10, 3 * kH / 4, kW + 10, kH + 10),
904                                      // touching entire left edge
905                                      SkIRect::MakeLTRB(0, kH, kW, kH + 10),
906                                      // overlapping bottom right corner
907                                      SkIRect::MakeLTRB(3 * kW / 4, 3 * kH / 4, kW + 10, kH + 10),
908                                      // overlapping top right and bottom right corners
909                                      SkIRect::MakeLTRB(3 * kW / 4, -10, kW + 10, kH + 10),
910                              }) {
911                             const auto readInfo = SkImageInfo::Make(rect.width(), rect.height(),
912                                                                     readCT, readAT, readCS);
913                             const SkIVector offset = rect.topLeft();
914                             runTest(src, srcPixels, readInfo, offset);
915                         }
916                     }
917                 }
918             }
919         }
920     }
921 }
922 
923 namespace {
924 struct AsyncContext {
925     bool fCalled = false;
926     std::unique_ptr<const SkSurface::AsyncReadResult> fResult;
927 };
928 }  // anonymous namespace
929 
930 // Making this a lambda in the test functions caused:
931 //   "error: cannot compile this forwarded non-trivially copyable parameter yet"
932 // on x86/Win/Clang bot, referring to 'result'.
async_callback(void * c,std::unique_ptr<const SkSurface::AsyncReadResult> result)933 static void async_callback(void* c, std::unique_ptr<const SkSurface::AsyncReadResult> result) {
934     auto context = static_cast<AsyncContext*>(c);
935     context->fResult = std::move(result);
936     context->fCalled = true;
937 };
938 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(AsyncReadPixels,reporter,ctxInfo)939 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(AsyncReadPixels, reporter, ctxInfo) {
940     using Surface = sk_sp<SkSurface>;
941     auto reader = std::function<GpuReadSrcFn<Surface>>([](const Surface& surface,
942                                                           const SkIVector& offset,
943                                                           const SkPixmap& pixels) {
944         AsyncContext context;
945         auto rect = SkIRect::MakeSize(pixels.dimensions()).makeOffset(offset);
946 
947         // Rescale quality and linearity don't matter since we're doing a non-scaling readback.
948         surface->asyncRescaleAndReadPixels(pixels.info(), rect, SkSurface::RescaleGamma::kSrc,
949                                            kNone_SkFilterQuality, async_callback, &context);
950         while (!context.fCalled) {
951             surface->getCanvas()->getGrContext()->checkAsyncWorkCompletion();
952         }
953         if (!context.fResult) {
954             return false;
955         }
956         SkRectMemcpy(pixels.writable_addr(), pixels.rowBytes(), context.fResult->data(0),
957                      context.fResult->rowBytes(0), pixels.info().minRowBytes(), pixels.height());
958         return true;
959     });
960     GpuReadPixelTestRules rules;
961     rules.fAllowUnpremulSrc = false;
962     rules.fAllowUnpremulRead = false;
963     rules.fUncontainedRectSucceeds = false;
964 
965     for (GrSurfaceOrigin origin : {kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin}) {
966         auto factory = std::function<GpuSrcFactory<Surface>>(
967                 [context = ctxInfo.grContext(), origin](const SkPixmap& src) {
968                     if (src.colorType() == kRGB_888x_SkColorType) {
969                         return Surface();
970                     }
971                     auto surf = SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, src.info(),
972                                                             0, origin, nullptr);
973                     if (surf) {
974                         surf->writePixels(src, 0, 0);
975                     }
976                     return surf;
977                 });
978         gpu_read_pixels_test_driver(reporter, rules, factory, reader);
979     }
980 }
981 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ReadPixels_Gpu,reporter,ctxInfo)982 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ReadPixels_Gpu, reporter, ctxInfo) {
983     using Surface = sk_sp<SkSurface>;
984     auto reader = std::function<GpuReadSrcFn<Surface>>(
985             [](const Surface& surface, const SkIVector& offset, const SkPixmap& pixels) {
986                 return surface->readPixels(pixels, offset.fX, offset.fY);
987             });
988     GpuReadPixelTestRules rules;
989     rules.fAllowUnpremulSrc = false;
990     rules.fAllowUnpremulRead = true;
991     rules.fUncontainedRectSucceeds = true;
992 
993     for (GrSurfaceOrigin origin : {kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin}) {
994         auto factory = std::function<GpuSrcFactory<Surface>>(
995                 [context = ctxInfo.grContext(), origin](const SkPixmap& src) {
996                     if (src.colorType() == kRGB_888x_SkColorType) {
997                         return Surface();
998                     }
999                     auto surf = SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, src.info(),
1000                                                             0, origin, nullptr);
1001                     if (surf) {
1002                         surf->writePixels(src, 0, 0);
1003                     }
1004                     return surf;
1005                 });
1006         gpu_read_pixels_test_driver(reporter, rules, factory, reader);
1007     }
1008 }
1009 
DEF_GPUTEST(AsyncReadPixelsContextShutdown,reporter,options)1010 DEF_GPUTEST(AsyncReadPixelsContextShutdown, reporter, options) {
1011     const auto ii = SkImageInfo::Make(10, 10, kRGBA_8888_SkColorType, kPremul_SkAlphaType,
1012                                       SkColorSpace::MakeSRGB());
1013     enum class ShutdownSequence {
1014         kFreeResult_DestroyContext,
1015         kDestroyContext_FreeResult,
1016         kFreeResult_ReleaseAndAbandon_DestroyContext,
1017         kFreeResult_Abandon_DestroyContext,
1018         kReleaseAndAbandon_FreeResult_DestroyContext,
1019         kAbandon_FreeResult_DestroyContext,
1020         kReleaseAndAbandon_DestroyContext_FreeResult,
1021         kAbandon_DestroyContext_FreeResult,
1022     };
1023     for (int t = 0; t < sk_gpu_test::GrContextFactory::kContextTypeCnt; ++t) {
1024         auto type = static_cast<sk_gpu_test::GrContextFactory::ContextType>(t);
1025         for (auto sequence : {ShutdownSequence::kFreeResult_DestroyContext,
1026                               ShutdownSequence::kDestroyContext_FreeResult,
1027                               ShutdownSequence::kFreeResult_ReleaseAndAbandon_DestroyContext,
1028                               ShutdownSequence::kFreeResult_Abandon_DestroyContext,
1029                               ShutdownSequence::kReleaseAndAbandon_FreeResult_DestroyContext,
1030                               ShutdownSequence::kAbandon_FreeResult_DestroyContext,
1031                               ShutdownSequence::kReleaseAndAbandon_DestroyContext_FreeResult,
1032                               ShutdownSequence::kAbandon_DestroyContext_FreeResult}) {
1033             // Vulkan context abandoning without resource release has issues outside of the scope of
1034             // this test.
1035             if (type == sk_gpu_test::GrContextFactory::kVulkan_ContextType &&
1036                 (sequence == ShutdownSequence::kAbandon_FreeResult_DestroyContext ||
1037                  sequence == ShutdownSequence::kAbandon_DestroyContext_FreeResult ||
1038                  sequence == ShutdownSequence::kFreeResult_Abandon_DestroyContext)) {
1039                 continue;
1040             }
1041             for (bool yuv : {false, true}) {
1042                 sk_gpu_test::GrContextFactory factory(options);
1043                 auto context = factory.get(type);
1044                 if (!context) {
1045                     continue;
1046                 }
1047                 // This test is only meaningful for contexts that support transfer buffers for
1048                 // reads.
1049                 if (!context->priv().caps()->transferFromSurfaceToBufferSupport()) {
1050                     continue;
1051                 }
1052                 auto surf = SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, ii, 1, nullptr);
1053                 if (!surf) {
1054                     continue;
1055                 }
1056                 AsyncContext cbContext;
1057                 if (yuv) {
1058                     surf->asyncRescaleAndReadPixelsYUV420(
1059                             kIdentity_SkYUVColorSpace, SkColorSpace::MakeSRGB(), ii.bounds(),
1060                             ii.dimensions(), SkSurface::RescaleGamma::kSrc, kNone_SkFilterQuality,
1061                             &async_callback, &cbContext);
1062                 } else {
1063                     surf->asyncRescaleAndReadPixels(ii, ii.bounds(), SkSurface::RescaleGamma::kSrc,
1064                                                     kNone_SkFilterQuality, &async_callback,
1065                                                     &cbContext);
1066                 }
1067                 while (!cbContext.fCalled) {
1068                     context->checkAsyncWorkCompletion();
1069                 }
1070                 if (!cbContext.fResult) {
1071                     ERRORF(reporter, "Callback failed on %s. is YUV: %d",
1072                            sk_gpu_test::GrContextFactory::ContextTypeName(type), yuv);
1073                     continue;
1074                 }
1075                 // The real test is that we don't crash, get Vulkan validation errors, etc, during
1076                 // this shutdown sequence.
1077                 switch (sequence) {
1078                     case ShutdownSequence::kFreeResult_DestroyContext:
1079                     case ShutdownSequence::kFreeResult_ReleaseAndAbandon_DestroyContext:
1080                     case ShutdownSequence::kFreeResult_Abandon_DestroyContext:
1081                         break;
1082                     case ShutdownSequence::kDestroyContext_FreeResult:
1083                         factory.destroyContexts();
1084                         break;
1085                     case ShutdownSequence::kReleaseAndAbandon_FreeResult_DestroyContext:
1086                         factory.releaseResourcesAndAbandonContexts();
1087                         break;
1088                     case ShutdownSequence::kAbandon_FreeResult_DestroyContext:
1089                         factory.abandonContexts();
1090                         break;
1091                     case ShutdownSequence::kReleaseAndAbandon_DestroyContext_FreeResult:
1092                         factory.releaseResourcesAndAbandonContexts();
1093                         factory.destroyContexts();
1094                         break;
1095                     case ShutdownSequence::kAbandon_DestroyContext_FreeResult:
1096                         factory.abandonContexts();
1097                         factory.destroyContexts();
1098                         break;
1099                 }
1100                 cbContext.fResult.reset();
1101                 switch (sequence) {
1102                     case ShutdownSequence::kFreeResult_ReleaseAndAbandon_DestroyContext:
1103                         factory.releaseResourcesAndAbandonContexts();
1104                         break;
1105                     case ShutdownSequence::kFreeResult_Abandon_DestroyContext:
1106                         factory.abandonContexts();
1107                         break;
1108                     case ShutdownSequence::kFreeResult_DestroyContext:
1109                     case ShutdownSequence::kDestroyContext_FreeResult:
1110                     case ShutdownSequence::kReleaseAndAbandon_FreeResult_DestroyContext:
1111                     case ShutdownSequence::kAbandon_FreeResult_DestroyContext:
1112                     case ShutdownSequence::kReleaseAndAbandon_DestroyContext_FreeResult:
1113                     case ShutdownSequence::kAbandon_DestroyContext_FreeResult:
1114                         break;
1115                 }
1116             }
1117         }
1118     }
1119 }
1120