• 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 "include/core/SkBitmap.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkSurface.h"
11 #include "include/gpu/GrBackendSurface.h"
12 #include "include/gpu/GrDirectContext.h"
13 #include "include/private/SkColorData.h"
14 #include "include/private/SkImageInfoPriv.h"
15 #include "src/core/SkMathPriv.h"
16 #include "src/gpu/GrDirectContextPriv.h"
17 #include "src/gpu/GrGpu.h"
18 #include "src/gpu/GrProxyProvider.h"
19 #include "tests/Test.h"
20 #include "tools/gpu/BackendSurfaceFactory.h"
21 
22 #include <initializer_list>
23 
24 static const int DEV_W = 100, DEV_H = 100;
25 static const SkIRect DEV_RECT = SkIRect::MakeWH(DEV_W, DEV_H);
26 static const U8CPU DEV_PAD = 0xee;
27 
get_canvas_color(int x,int y)28 static SkPMColor get_canvas_color(int x, int y) {
29     SkASSERT(x >= 0 && x < DEV_W);
30     SkASSERT(y >= 0 && y < DEV_H);
31 
32     U8CPU r = x;
33     U8CPU g = y;
34     U8CPU b = 0xc;
35 
36     U8CPU a = 0x0;
37     switch ((x+y) % 5) {
38         case 0:
39             a = 0xff;
40             break;
41         case 1:
42             a = 0x80;
43             break;
44         case 2:
45             a = 0xCC;
46             break;
47         case 3:
48             a = 0x00;
49             break;
50         case 4:
51             a = 0x01;
52             break;
53     }
54     return SkPremultiplyARGBInline(a, r, g, b);
55 }
56 
57 // assumes any premu/.unpremul has been applied
pack_color_type(SkColorType ct,U8CPU a,U8CPU r,U8CPU g,U8CPU b)58 static uint32_t pack_color_type(SkColorType ct, U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
59     uint32_t r32;
60     uint8_t* result = reinterpret_cast<uint8_t*>(&r32);
61     switch (ct) {
62         case kBGRA_8888_SkColorType:
63             result[0] = b;
64             result[1] = g;
65             result[2] = r;
66             result[3] = a;
67             break;
68         case kRGBA_8888_SkColorType:  // fallthrough
69         case kRGB_888x_SkColorType:
70             result[0] = r;
71             result[1] = g;
72             result[2] = b;
73             result[3] = a;
74             break;
75         default:
76             SkASSERT(0);
77             return 0;
78     }
79     return r32;
80 }
81 
get_bitmap_color(int x,int y,int w,SkColorType ct,SkAlphaType at)82 static uint32_t get_bitmap_color(int x, int y, int w, SkColorType ct, SkAlphaType at) {
83     int n = y * w + x;
84     U8CPU b = n & 0xff;
85     U8CPU g = (n >> 8) & 0xff;
86     U8CPU r = (n >> 16) & 0xff;
87     U8CPU a = 0;
88     switch ((x+y) % 5) {
89         case 4:
90             a = 0xff;
91             break;
92         case 3:
93             a = 0x80;
94             break;
95         case 2:
96             a = 0xCC;
97             break;
98         case 1:
99             a = 0x01;
100             break;
101         case 0:
102             a = 0x00;
103             break;
104     }
105     if (kPremul_SkAlphaType == at) {
106         r = SkMulDiv255Ceiling(r, a);
107         g = SkMulDiv255Ceiling(g, a);
108         b = SkMulDiv255Ceiling(b, a);
109     }
110     return pack_color_type(ct, a, r, g , b);
111 }
112 
fill_surface(SkSurface * surface)113 static void fill_surface(SkSurface* surface) {
114     SkBitmap bmp;
115     bmp.allocN32Pixels(DEV_W, DEV_H);
116     for (int y = 0; y < DEV_H; ++y) {
117         for (int x = 0; x < DEV_W; ++x) {
118             *bmp.getAddr32(x, y) = get_canvas_color(x, y);
119         }
120     }
121     surface->writePixels(bmp, 0, 0);
122 }
123 
124 /**
125  *  Lucky for us, alpha is always in the same spot (SK_A32_SHIFT), for both RGBA and BGRA.
126  *  Thus this routine doesn't need to know the exact colortype
127  */
premul(uint32_t color)128 static uint32_t premul(uint32_t color) {
129     unsigned a = SkGetPackedA32(color);
130     // these next three are not necessarily r,g,b in that order, but they are r,g,b in some order.
131     unsigned c0 = SkGetPackedR32(color);
132     unsigned c1 = SkGetPackedG32(color);
133     unsigned c2 = SkGetPackedB32(color);
134     c0 = SkMulDiv255Ceiling(c0, a);
135     c1 = SkMulDiv255Ceiling(c1, a);
136     c2 = SkMulDiv255Ceiling(c2, a);
137     return SkPackARGB32NoCheck(a, c0, c1, c2);
138 }
139 
convert_to_PMColor(SkColorType ct,SkAlphaType at,uint32_t color)140 static SkPMColor convert_to_PMColor(SkColorType ct, SkAlphaType at, uint32_t color) {
141     if (kUnpremul_SkAlphaType == at) {
142         color = premul(color);
143     }
144     switch (ct) {
145         case kRGBA_8888_SkColorType: // fallthrough
146         case kRGB_888x_SkColorType:
147             color = SkSwizzle_RGBA_to_PMColor(color);
148             break;
149         case kBGRA_8888_SkColorType:
150             color = SkSwizzle_BGRA_to_PMColor(color);
151             break;
152         default:
153             SkASSERT(0);
154             break;
155     }
156     return color;
157 }
158 
check_pixel(SkPMColor a,SkPMColor b,bool didPremulConversion)159 static bool check_pixel(SkPMColor a, SkPMColor b, bool didPremulConversion) {
160     if (!didPremulConversion) {
161         return a == b;
162     }
163     int32_t aA = static_cast<int32_t>(SkGetPackedA32(a));
164     int32_t aR = static_cast<int32_t>(SkGetPackedR32(a));
165     int32_t aG = static_cast<int32_t>(SkGetPackedG32(a));
166     int32_t aB = SkGetPackedB32(a);
167 
168     int32_t bA = static_cast<int32_t>(SkGetPackedA32(b));
169     int32_t bR = static_cast<int32_t>(SkGetPackedR32(b));
170     int32_t bG = static_cast<int32_t>(SkGetPackedG32(b));
171     int32_t bB = static_cast<int32_t>(SkGetPackedB32(b));
172 
173     return aA == bA &&
174            SkAbs32(aR - bR) <= 1 &&
175            SkAbs32(aG - bG) <= 1 &&
176            SkAbs32(aB - bB) <= 1;
177 }
178 
write_should_succeed(const SkImageInfo & dstInfo,const SkImageInfo & srcInfo,bool isGPU)179 bool write_should_succeed(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo, bool isGPU) {
180     if (!SkImageInfoValidConversion(dstInfo, srcInfo)) {
181         return false;
182     }
183     if (!isGPU) {
184         return true;
185     }
186     // The GPU backend supports writing unpremul data to a premul dst but not vice versa.
187     if (srcInfo.alphaType() == kPremul_SkAlphaType &&
188         dstInfo.alphaType() == kUnpremul_SkAlphaType) {
189         return false;
190     }
191     if (!SkColorTypeIsAlwaysOpaque(srcInfo.colorType()) &&
192         SkColorTypeIsAlwaysOpaque(dstInfo.colorType())) {
193         return false;
194     }
195     // The source has no alpha value and the dst is only alpha
196     if (SkColorTypeIsAlwaysOpaque(srcInfo.colorType()) &&
197         SkColorTypeIsAlphaOnly(dstInfo.colorType())) {
198         return false;
199     }
200     return true;
201 }
202 
check_write(skiatest::Reporter * reporter,SkSurface * surf,SkAlphaType surfaceAlphaType,const SkBitmap & bitmap,int writeX,int writeY)203 static bool check_write(skiatest::Reporter* reporter, SkSurface* surf, SkAlphaType surfaceAlphaType,
204                         const SkBitmap& bitmap, int writeX, int writeY) {
205     size_t canvasRowBytes;
206     const uint32_t* canvasPixels;
207 
208     // Can't use canvas->peekPixels(), as we are trying to look at GPU pixels sometimes as well.
209     // At some point this will be unsupported, as we won't allow accessBitmap() to magically call
210     // readPixels for the client.
211     SkBitmap secretDevBitmap;
212     secretDevBitmap.allocN32Pixels(surf->width(), surf->height());
213     if (!surf->readPixels(secretDevBitmap, 0, 0)) {
214         return false;
215     }
216 
217     canvasRowBytes = secretDevBitmap.rowBytes();
218     canvasPixels = static_cast<const uint32_t*>(secretDevBitmap.getPixels());
219 
220     if (nullptr == canvasPixels) {
221         return false;
222     }
223 
224     if (surf->width() != DEV_W || surf->height() != DEV_H) {
225         return false;
226     }
227 
228     const SkImageInfo& bmInfo = bitmap.info();
229 
230     SkIRect writeRect = SkIRect::MakeXYWH(writeX, writeY, bitmap.width(), bitmap.height());
231     for (int cy = 0; cy < DEV_H; ++cy) {
232         for (int cx = 0; cx < DEV_W; ++cx) {
233             SkPMColor canvasPixel = canvasPixels[cx];
234             if (writeRect.contains(cx, cy)) {
235                 int bx = cx - writeX;
236                 int by = cy - writeY;
237                 uint32_t bmpColor8888 = get_bitmap_color(bx, by, bitmap.width(),
238                                                        bmInfo.colorType(), bmInfo.alphaType());
239                 bool mul = (kUnpremul_SkAlphaType == bmInfo.alphaType());
240                 SkPMColor bmpPMColor = convert_to_PMColor(bmInfo.colorType(), bmInfo.alphaType(),
241                                                           bmpColor8888);
242                 if (bmInfo.alphaType() == kOpaque_SkAlphaType ||
243                     surfaceAlphaType == kOpaque_SkAlphaType) {
244                     bmpPMColor |= 0xFF000000;
245                 }
246                 if (!check_pixel(bmpPMColor, canvasPixel, mul)) {
247                     ERRORF(reporter, "Expected canvas pixel at %d, %d to be 0x%08x, got 0x%08x. "
248                            "Write performed premul: %d", cx, cy, bmpPMColor, canvasPixel, mul);
249                     return false;
250                 }
251             } else {
252                 SkPMColor testColor = get_canvas_color(cx, cy);
253                 if (canvasPixel != testColor) {
254                     ERRORF(reporter, "Canvas pixel outside write rect at %d, %d changed."
255                            " Should be 0x%08x, got 0x%08x. ", cx, cy, testColor, canvasPixel);
256                     return false;
257                 }
258             }
259         }
260         if (cy != DEV_H -1) {
261             const char* pad = reinterpret_cast<const char*>(canvasPixels + DEV_W);
262             for (size_t px = 0; px < canvasRowBytes - 4 * DEV_W; ++px) {
263                 bool check;
264                 REPORTER_ASSERT(reporter, check = (pad[px] == static_cast<char>(DEV_PAD)));
265                 if (!check) {
266                     return false;
267                 }
268             }
269         }
270         canvasPixels += canvasRowBytes/4;
271     }
272 
273     return true;
274 }
275 
276 #include "include/core/SkMallocPixelRef.h"
277 
278 // This is a tricky pattern, because we have to setConfig+rowBytes AND specify
279 // a custom pixelRef (which also has to specify its rowBytes), so we have to be
280 // sure that the two rowBytes match (and the infos match).
281 //
alloc_row_bytes(SkBitmap * bm,const SkImageInfo & info,size_t rowBytes)282 static bool alloc_row_bytes(SkBitmap* bm, const SkImageInfo& info, size_t rowBytes) {
283     if (!bm->setInfo(info, rowBytes)) {
284         return false;
285     }
286     sk_sp<SkPixelRef> pr = SkMallocPixelRef::MakeAllocate(info, rowBytes);
287     bm->setPixelRef(std::move(pr), 0, 0);
288     return true;
289 }
290 
free_pixels(void * pixels,void * ctx)291 static void free_pixels(void* pixels, void* ctx) {
292     sk_free(pixels);
293 }
294 
setup_bitmap(SkBitmap * bm,SkColorType ct,SkAlphaType at,int w,int h,int tightRB)295 static bool setup_bitmap(SkBitmap* bm, SkColorType ct, SkAlphaType at, int w, int h, int tightRB) {
296     size_t rowBytes = tightRB ? 0 : 4 * w + 60;
297     SkImageInfo info = SkImageInfo::Make(w, h, ct, at);
298     if (!alloc_row_bytes(bm, info, rowBytes)) {
299         return false;
300     }
301     for (int y = 0; y < h; ++y) {
302         for (int x = 0; x < w; ++x) {
303             *bm->getAddr32(x, y) = get_bitmap_color(x, y, w, ct, at);
304         }
305     }
306     return true;
307 }
308 
call_writepixels(SkSurface * surface)309 static void call_writepixels(SkSurface* surface) {
310     const SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
311     SkPMColor pixel = 0;
312     surface->writePixels({info, &pixel, sizeof(SkPMColor)}, 0, 0);
313 }
314 
DEF_TEST(WritePixelsSurfaceGenID,reporter)315 DEF_TEST(WritePixelsSurfaceGenID, reporter) {
316     const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
317     auto surface(SkSurface::MakeRaster(info));
318     uint32_t genID1 = surface->generationID();
319     call_writepixels(surface.get());
320     uint32_t genID2 = surface->generationID();
321     REPORTER_ASSERT(reporter, genID1 != genID2);
322 }
323 
test_write_pixels(skiatest::Reporter * reporter,SkSurface * surface,const SkImageInfo & surfaceInfo)324 static void test_write_pixels(skiatest::Reporter* reporter, SkSurface* surface,
325                               const SkImageInfo& surfaceInfo) {
326     const SkIRect testRects[] = {
327         // entire thing
328         DEV_RECT,
329         // larger on all sides
330         SkIRect::MakeLTRB(-10, -10, DEV_W + 10, DEV_H + 10),
331         // fully contained
332         SkIRect::MakeLTRB(DEV_W / 4, DEV_H / 4, 3 * DEV_W / 4, 3 * DEV_H / 4),
333         // outside top left
334         SkIRect::MakeLTRB(-10, -10, -1, -1),
335         // touching top left corner
336         SkIRect::MakeLTRB(-10, -10, 0, 0),
337         // overlapping top left corner
338         SkIRect::MakeLTRB(-10, -10, DEV_W / 4, DEV_H / 4),
339         // overlapping top left and top right corners
340         SkIRect::MakeLTRB(-10, -10, DEV_W  + 10, DEV_H / 4),
341         // touching entire top edge
342         SkIRect::MakeLTRB(-10, -10, DEV_W  + 10, 0),
343         // overlapping top right corner
344         SkIRect::MakeLTRB(3 * DEV_W / 4, -10, DEV_W  + 10, DEV_H / 4),
345         // contained in x, overlapping top edge
346         SkIRect::MakeLTRB(DEV_W / 4, -10, 3 * DEV_W  / 4, DEV_H / 4),
347         // outside top right corner
348         SkIRect::MakeLTRB(DEV_W + 1, -10, DEV_W + 10, -1),
349         // touching top right corner
350         SkIRect::MakeLTRB(DEV_W, -10, DEV_W + 10, 0),
351         // overlapping top left and bottom left corners
352         SkIRect::MakeLTRB(-10, -10, DEV_W / 4, DEV_H + 10),
353         // touching entire left edge
354         SkIRect::MakeLTRB(-10, -10, 0, DEV_H + 10),
355         // overlapping bottom left corner
356         SkIRect::MakeLTRB(-10, 3 * DEV_H / 4, DEV_W / 4, DEV_H + 10),
357         // contained in y, overlapping left edge
358         SkIRect::MakeLTRB(-10, DEV_H / 4, DEV_W / 4, 3 * DEV_H / 4),
359         // outside bottom left corner
360         SkIRect::MakeLTRB(-10, DEV_H + 1, -1, DEV_H + 10),
361         // touching bottom left corner
362         SkIRect::MakeLTRB(-10, DEV_H, 0, DEV_H + 10),
363         // overlapping bottom left and bottom right corners
364         SkIRect::MakeLTRB(-10, 3 * DEV_H / 4, DEV_W + 10, DEV_H + 10),
365         // touching entire left edge
366         SkIRect::MakeLTRB(0, DEV_H, DEV_W, DEV_H + 10),
367         // overlapping bottom right corner
368         SkIRect::MakeLTRB(3 * DEV_W / 4, 3 * DEV_H / 4, DEV_W + 10, DEV_H + 10),
369         // overlapping top right and bottom right corners
370         SkIRect::MakeLTRB(3 * DEV_W / 4, -10, DEV_W + 10, DEV_H + 10),
371     };
372 
373     SkCanvas* canvas = surface->getCanvas();
374 
375     static const struct {
376         SkColorType fColorType;
377         SkAlphaType fAlphaType;
378     } gSrcConfigs[] = {
379             {kRGBA_8888_SkColorType, kPremul_SkAlphaType},
380             {kRGBA_8888_SkColorType, kUnpremul_SkAlphaType},
381             {kRGB_888x_SkColorType, kOpaque_SkAlphaType},
382             {kBGRA_8888_SkColorType, kPremul_SkAlphaType},
383             {kBGRA_8888_SkColorType, kUnpremul_SkAlphaType},
384     };
385     for (size_t r = 0; r < SK_ARRAY_COUNT(testRects); ++r) {
386         const SkIRect& rect = testRects[r];
387         for (int tightBmp = 0; tightBmp < 2; ++tightBmp) {
388             for (size_t c = 0; c < SK_ARRAY_COUNT(gSrcConfigs); ++c) {
389                 const SkColorType ct = gSrcConfigs[c].fColorType;
390                 const SkAlphaType at = gSrcConfigs[c].fAlphaType;
391 
392                 bool isGPU = SkToBool(surface->getCanvas()->recordingContext());
393                 fill_surface(surface);
394                 SkBitmap bmp;
395                 REPORTER_ASSERT(reporter, setup_bitmap(&bmp, ct, at, rect.width(),
396                                                        rect.height(), SkToBool(tightBmp)));
397                 uint32_t idBefore = surface->generationID();
398 
399                 surface->writePixels(bmp, rect.fLeft, rect.fTop);
400 
401                 uint32_t idAfter = surface->generationID();
402                 REPORTER_ASSERT(reporter, check_write(reporter, surface, surfaceInfo.alphaType(),
403                                                       bmp, rect.fLeft, rect.fTop));
404 
405                 // we should change the genID iff pixels were actually written.
406                 SkIRect canvasRect = SkIRect::MakeSize(canvas->getBaseLayerSize());
407                 SkIRect writeRect = SkIRect::MakeXYWH(rect.fLeft, rect.fTop,
408                                                       bmp.width(), bmp.height());
409                 bool expectSuccess = SkIRect::Intersects(canvasRect, writeRect) &&
410                                      write_should_succeed(surfaceInfo, bmp.info(), isGPU);
411                 REPORTER_ASSERT(reporter, expectSuccess == (idBefore != idAfter));
412             }
413         }
414     }
415 }
416 
DEF_TEST(WritePixels,reporter)417 DEF_TEST(WritePixels, reporter) {
418     const SkImageInfo info = SkImageInfo::MakeN32Premul(DEV_W, DEV_H);
419     for (auto& tightRowBytes : { true, false }) {
420         const size_t rowBytes = tightRowBytes ? info.minRowBytes() : 4 * DEV_W + 100;
421         const size_t size = info.computeByteSize(rowBytes);
422         void* pixels = sk_malloc_throw(size);
423         // if rowBytes isn't tight then set the padding to a known value
424         if (!tightRowBytes) {
425             memset(pixels, DEV_PAD, size);
426         }
427         auto surface(SkSurface::MakeRasterDirectReleaseProc(info, pixels, rowBytes,
428                                                             free_pixels, nullptr));
429         test_write_pixels(reporter, surface.get(), info);
430     }
431 }
432 
test_write_pixels(skiatest::Reporter * reporter,GrRecordingContext * rContext,int sampleCnt)433 static void test_write_pixels(skiatest::Reporter* reporter,
434                               GrRecordingContext* rContext,
435                               int sampleCnt) {
436     const SkImageInfo ii = SkImageInfo::MakeN32Premul(DEV_W, DEV_H);
437     for (auto& origin : { kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin }) {
438         sk_sp<SkSurface> surface(SkSurface::MakeRenderTarget(rContext,
439                                                              SkBudgeted::kNo, ii, sampleCnt,
440                                                              origin, nullptr));
441         if (surface) {
442             test_write_pixels(reporter, surface.get(), ii);
443         }
444     }
445 }
446 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WritePixels_Gpu,reporter,ctxInfo)447 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WritePixels_Gpu, reporter, ctxInfo) {
448     test_write_pixels(reporter, ctxInfo.directContext(), 1);
449 }
450 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WritePixelsMSAA_Gpu,reporter,ctxInfo)451 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WritePixelsMSAA_Gpu, reporter, ctxInfo) {
452     test_write_pixels(reporter, ctxInfo.directContext(), 1);
453 }
454 
test_write_pixels_non_texture(skiatest::Reporter * reporter,GrDirectContext * dContext,int sampleCnt)455 static void test_write_pixels_non_texture(skiatest::Reporter* reporter,
456                                           GrDirectContext* dContext,
457                                           int sampleCnt) {
458     // Dawn currently doesn't support writePixels to a texture-as-render-target.
459     // See http://skbug.com/10336.
460     if (GrBackendApi::kDawn == dContext->backend()) {
461         return;
462     }
463     for (auto& origin : { kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin }) {
464         SkColorType colorType = kN32_SkColorType;
465         auto surface = sk_gpu_test::MakeBackendRenderTargetSurface(dContext,
466                                                                    {DEV_W, DEV_H},
467                                                                    origin,
468                                                                    sampleCnt,
469                                                                    colorType);
470         if (surface) {
471             auto ii = SkImageInfo::MakeN32Premul(DEV_W, DEV_H);
472             test_write_pixels(reporter, surface.get(), ii);
473         }
474     }
475 }
476 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WritePixelsNonTexture_Gpu,reporter,ctxInfo)477 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WritePixelsNonTexture_Gpu, reporter, ctxInfo) {
478     test_write_pixels_non_texture(reporter, ctxInfo.directContext(), 1);
479 }
480 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WritePixelsNonTextureMSAA_Gpu,reporter,ctxInfo)481 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WritePixelsNonTextureMSAA_Gpu, reporter, ctxInfo) {
482     test_write_pixels_non_texture(reporter, ctxInfo.directContext(), 4);
483 }
484 
create_surf(GrRecordingContext * rContext,int width,int height)485 static sk_sp<SkSurface> create_surf(GrRecordingContext* rContext, int width, int height) {
486     const SkImageInfo ii = SkImageInfo::Make(width, height,
487                                              kRGBA_8888_SkColorType, kPremul_SkAlphaType);
488 
489     sk_sp<SkSurface> surf = SkSurface::MakeRenderTarget(rContext, SkBudgeted::kYes, ii);
490     surf->flushAndSubmit();
491     return surf;
492 }
493 
upload(const sk_sp<SkSurface> & surf,SkColor color)494 static sk_sp<SkImage> upload(const sk_sp<SkSurface>& surf, SkColor color) {
495     const SkImageInfo smII = SkImageInfo::Make(16, 16, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
496     SkBitmap bm;
497     bm.allocPixels(smII);
498     bm.eraseColor(color);
499 
500     surf->writePixels(bm, 0, 0);
501 
502     return surf->makeImageSnapshot();
503 }
504 
505 // This is tests whether the first writePixels is completed before the
506 // second writePixels takes effect (i.e., that writePixels correctly flushes
507 // in between uses of the shared backing resource).
508 // The unit test fails on Nexus 6P/Android M with driver 129.0 without the
509 // "DisallowTexSubImageForUnormConfigTexturesEverBoundToFBO" workaround enabled.
510 // skbug.com/11834
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WritePixelsPendingIO,reporter,ctxInfo)511 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WritePixelsPendingIO, reporter, ctxInfo) {
512     auto context = ctxInfo.directContext();
513     GrProxyProvider* proxyProvider = context->priv().proxyProvider();
514     const GrCaps* caps = context->priv().caps();
515 
516     static const int kFullSize = 62;
517     static const int kHalfSize = 31;
518 
519     static const uint32_t kLeftColor = 0xFF222222;
520     static const uint32_t kRightColor = 0xFFAAAAAA;
521 
522     const SkImageInfo fullII = SkImageInfo::Make(kFullSize, kFullSize,
523                                                  kRGBA_8888_SkColorType, kPremul_SkAlphaType);
524     const SkImageInfo halfII = SkImageInfo::Make(kHalfSize, kFullSize,
525                                                  kRGBA_8888_SkColorType, kPremul_SkAlphaType);
526 
527     sk_sp<SkSurface> dest = SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, fullII);
528 
529     {
530         // Seed the resource cached with a scratch texture that will be reused by writePixels
531         static constexpr SkISize kDims = {32, 64};
532 
533         const GrBackendFormat format = caps->getDefaultBackendFormat(GrColorType::kRGBA_8888,
534                                                                      GrRenderable::kNo);
535 
536         sk_sp<GrTextureProxy> temp = proxyProvider->createProxy(
537                 format, kDims, GrRenderable::kNo, 1, GrMipmapped::kNo, SkBackingFit::kApprox,
538                 SkBudgeted::kYes, GrProtected::kNo);
539         temp->instantiate(context->priv().resourceProvider());
540     }
541 
542     // Create the surfaces and flush them to ensure there is no lingering pendingIO
543     sk_sp<SkSurface> leftSurf = create_surf(context, kHalfSize, kFullSize);
544     sk_sp<SkSurface> rightSurf = create_surf(context, kHalfSize, kFullSize);
545 
546     sk_sp<SkImage> leftImg = upload(std::move(leftSurf), kLeftColor);
547     dest->getCanvas()->drawImage(std::move(leftImg), 0, 0);
548 
549     sk_sp<SkImage> rightImg = upload(std::move(rightSurf), kRightColor);
550     dest->getCanvas()->drawImage(std::move(rightImg), kHalfSize, 0);
551 
552     SkBitmap bm;
553     bm.allocPixels(fullII);
554     SkAssertResult(dest->readPixels(bm, 0, 0));
555 
556     bool isCorrect = true;
557     for (int y = 0; isCorrect && y < 16; ++y) {
558         const uint32_t* sl = bm.getAddr32(0, y);
559 
560         for (int x = 0; x < 16; ++x) {
561             if (kLeftColor != sl[x]) {
562                 isCorrect = false;
563                 break;
564             }
565         }
566         for (int x = kHalfSize; x < kHalfSize+16; ++x) {
567             if (kRightColor != sl[x]) {
568                 isCorrect = false;
569                 break;
570             }
571         }
572     }
573 
574     REPORTER_ASSERT(reporter, isCorrect);
575 }
576 
DEF_TEST(WritePixels_InvalidRowBytes,reporter)577 DEF_TEST(WritePixels_InvalidRowBytes, reporter) {
578     auto dstII = SkImageInfo::Make({10, 10}, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
579     auto surf = SkSurface::MakeRaster(dstII);
580     for (int ct = 0; ct < kLastEnum_SkColorType + 1; ++ct) {
581         auto colorType = static_cast<SkColorType>(ct);
582 
583         size_t bpp = SkColorTypeBytesPerPixel(colorType);
584         if (bpp <= 1) {
585             continue;
586         }
587         auto srcII = dstII.makeColorType(colorType);
588         size_t badRowBytes = (surf->width() + 1)*bpp - 1;
589         auto storage = std::make_unique<char[]>(badRowBytes*surf->height());
590         memset(storage.get(), 0, badRowBytes * surf->height());
591         // SkSurface::writePixels doesn't report bool, SkCanvas's does.
592         REPORTER_ASSERT(reporter,
593                         !surf->getCanvas()->writePixels(srcII, storage.get(), badRowBytes, 0, 0));
594     }
595 }
596