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