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