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