• 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 "SkCanvas.h"
9 #include "SkColorData.h"
10 #include "SkImageInfoPriv.h"
11 #include "SkMathPriv.h"
12 #include "SkSurface.h"
13 #include "Test.h"
14 #include "sk_tool_utils.h"
15 
16 #include "GrBackendSurface.h"
17 #include "GrContext.h"
18 #include "GrContextPriv.h"
19 #include "GrGpu.h"
20 #include "GrProxyProvider.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:
146         case kRGB_888x_SkColorType:  // fallthrough
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 "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()->getGrContext());
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                 // sk_tool_utils::write_pixels(&canvas, bmp, rect.fLeft, rect.fTop, ct, at);
400                 surface->writePixels(bmp, rect.fLeft, rect.fTop);
401 
402                 uint32_t idAfter = surface->generationID();
403                 REPORTER_ASSERT(reporter, check_write(reporter, surface, surfaceInfo.alphaType(),
404                                                       bmp, rect.fLeft, rect.fTop));
405 
406                 // we should change the genID iff pixels were actually written.
407                 SkIRect canvasRect = SkIRect::MakeSize(canvas->getBaseLayerSize());
408                 SkIRect writeRect = SkIRect::MakeXYWH(rect.fLeft, rect.fTop,
409                                                       bmp.width(), bmp.height());
410                 bool expectSuccess = SkIRect::Intersects(canvasRect, writeRect) &&
411                                      write_should_succeed(surfaceInfo, bmp.info(), isGPU);
412                 REPORTER_ASSERT(reporter, expectSuccess == (idBefore != idAfter));
413             }
414         }
415     }
416 }
417 
DEF_TEST(WritePixels,reporter)418 DEF_TEST(WritePixels, reporter) {
419     const SkImageInfo info = SkImageInfo::MakeN32Premul(DEV_W, DEV_H);
420     for (auto& tightRowBytes : { true, false }) {
421         const size_t rowBytes = tightRowBytes ? info.minRowBytes() : 4 * DEV_W + 100;
422         const size_t size = info.computeByteSize(rowBytes);
423         void* pixels = sk_malloc_throw(size);
424         // if rowBytes isn't tight then set the padding to a known value
425         if (!tightRowBytes) {
426             memset(pixels, DEV_PAD, size);
427         }
428         auto surface(SkSurface::MakeRasterDirectReleaseProc(info, pixels, rowBytes,
429                                                             free_pixels, nullptr));
430         test_write_pixels(reporter, surface.get(), info);
431     }
432 }
433 
test_write_pixels(skiatest::Reporter * reporter,GrContext * context,int sampleCnt)434 static void test_write_pixels(skiatest::Reporter* reporter, GrContext* context, int sampleCnt) {
435     const SkImageInfo ii = SkImageInfo::MakeN32Premul(DEV_W, DEV_H);
436     for (auto& origin : { kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin }) {
437         sk_sp<SkSurface> surface(SkSurface::MakeRenderTarget(context,
438                                                              SkBudgeted::kNo, ii, sampleCnt,
439                                                              origin, nullptr));
440         if (surface) {
441             test_write_pixels(reporter, surface.get(), ii);
442         }
443     }
444 }
445 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WritePixels_Gpu,reporter,ctxInfo)446 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WritePixels_Gpu, reporter, ctxInfo) {
447     test_write_pixels(reporter, ctxInfo.grContext(), 1);
448 }
449 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WritePixelsMSAA_Gpu,reporter,ctxInfo)450 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WritePixelsMSAA_Gpu, reporter, ctxInfo) {
451     test_write_pixels(reporter, ctxInfo.grContext(), 1);
452 }
453 
test_write_pixels_non_texture(skiatest::Reporter * reporter,GrContext * context,int sampleCnt)454 static void test_write_pixels_non_texture(skiatest::Reporter* reporter, GrContext* context,
455                                           int sampleCnt) {
456     GrGpu* gpu = context->contextPriv().getGpu();
457 
458     for (auto& origin : { kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin }) {
459         GrBackendTexture backendTex = gpu->createTestingOnlyBackendTexture(
460                 nullptr, DEV_W, DEV_H, GrColorType::kRGBA_8888, true, GrMipMapped::kNo);
461         if (!backendTex.isValid()) {
462             continue;
463         }
464         SkColorType colorType = kN32_SkColorType;
465         sk_sp<SkSurface> surface(SkSurface::MakeFromBackendTextureAsRenderTarget(
466                 context, backendTex, origin, sampleCnt, colorType, nullptr, nullptr));
467         if (surface) {
468             auto ii = SkImageInfo::MakeN32Premul(DEV_W, DEV_H);
469             test_write_pixels(reporter, surface.get(), ii);
470         }
471         gpu->deleteTestingOnlyBackendTexture(backendTex);
472     }
473 }
474 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WritePixelsNonTexture_Gpu,reporter,ctxInfo)475 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WritePixelsNonTexture_Gpu, reporter, ctxInfo) {
476     test_write_pixels_non_texture(reporter, ctxInfo.grContext(), 1);
477 }
478 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WritePixelsNonTextureMSAA_Gpu,reporter,ctxInfo)479 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WritePixelsNonTextureMSAA_Gpu, reporter, ctxInfo) {
480     test_write_pixels_non_texture(reporter, ctxInfo.grContext(), 4);
481 }
482 
create_surf(GrContext * context,int width,int height)483 static sk_sp<SkSurface> create_surf(GrContext* context, int width, int height) {
484     const SkImageInfo ii = SkImageInfo::Make(width, height,
485                                              kRGBA_8888_SkColorType, kPremul_SkAlphaType);
486 
487     sk_sp<SkSurface> surf = SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, ii);
488     surf->flush();
489     return surf;
490 }
491 
upload(const sk_sp<SkSurface> & surf,SkColor color)492 static sk_sp<SkImage> upload(const sk_sp<SkSurface>& surf, SkColor color) {
493     const SkImageInfo smII = SkImageInfo::Make(16, 16, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
494     SkBitmap bm;
495     bm.allocPixels(smII);
496     bm.eraseColor(color);
497 
498     surf->writePixels(bm, 0, 0);
499 
500     return surf->makeImageSnapshot();
501 }
502 
503 // This is tests whether the first writePixels is completed before the
504 // second writePixels takes effect (i.e., that writePixels correctly flushes
505 // in between uses of the shared backing resource).
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WritePixelsPendingIO,reporter,ctxInfo)506 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WritePixelsPendingIO, reporter, ctxInfo) {
507     GrContext* context = ctxInfo.grContext();
508     GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
509 
510     static const int kFullSize = 62;
511     static const int kHalfSize = 31;
512 
513     static const uint32_t kLeftColor = 0xFF222222;
514     static const uint32_t kRightColor = 0xFFAAAAAA;
515 
516     const SkImageInfo fullII = SkImageInfo::Make(kFullSize, kFullSize,
517                                                  kRGBA_8888_SkColorType, kPremul_SkAlphaType);
518     const SkImageInfo halfII = SkImageInfo::Make(kHalfSize, kFullSize,
519                                                  kRGBA_8888_SkColorType, kPremul_SkAlphaType);
520 
521     sk_sp<SkSurface> dest = SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, fullII);
522 
523     {
524         // Seed the resource cached with a scratch texture that will be
525         // reused by writeSurfacePixels
526         GrSurfaceDesc desc;
527         desc.fFlags = kNone_GrSurfaceFlags;
528         desc.fWidth = 32;
529         desc.fHeight = 64;
530         desc.fConfig = kRGBA_8888_GrPixelConfig;
531 
532         const GrBackendFormat format =
533             context->contextPriv().caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType);
534 
535         sk_sp<GrTextureProxy> temp = proxyProvider->createProxy(
536                 format, desc, kTopLeft_GrSurfaceOrigin, SkBackingFit::kApprox, SkBudgeted::kYes);
537         temp->instantiate(context->contextPriv().resourceProvider());
538     }
539 
540     // Create the surfaces and flush them to ensure there is no lingering pendingIO
541     sk_sp<SkSurface> leftSurf = create_surf(context, kHalfSize, kFullSize);
542     sk_sp<SkSurface> rightSurf = create_surf(context, kHalfSize, kFullSize);
543 
544     sk_sp<SkImage> leftImg = upload(std::move(leftSurf), kLeftColor);
545     dest->getCanvas()->drawImage(std::move(leftImg), 0, 0);
546 
547     sk_sp<SkImage> rightImg = upload(std::move(rightSurf), kRightColor);
548     dest->getCanvas()->drawImage(std::move(rightImg), kHalfSize, 0);
549 
550     SkBitmap bm;
551     bm.allocPixels(fullII);
552     SkAssertResult(dest->readPixels(bm, 0, 0));
553 
554     bool isCorrect = true;
555     for (int y = 0; isCorrect && y < 16; ++y) {
556         const uint32_t* sl = bm.getAddr32(0, y);
557 
558         for (int x = 0; x < 16; ++x) {
559             if (kLeftColor != sl[x]) {
560                 isCorrect = false;
561                 break;
562             }
563         }
564         for (int x = kHalfSize; x < kHalfSize+16; ++x) {
565             if (kRightColor != sl[x]) {
566                 isCorrect = false;
567                 break;
568             }
569         }
570     }
571 
572     REPORTER_ASSERT(reporter, isCorrect);
573 }
574