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