1 /* 2 * Copyright 2011 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkCanvas.h" 9 #include "SkSurface.h" 10 #include "Test.h" 11 #include "sk_tool_utils.h" 12 13 #include "GrContext.h" 14 15 static uint32_t pack_unpremul_rgba(SkColor c) { 16 uint32_t packed; 17 uint8_t* byte = reinterpret_cast<uint8_t*>(&packed); 18 byte[0] = SkColorGetR(c); 19 byte[1] = SkColorGetG(c); 20 byte[2] = SkColorGetB(c); 21 byte[3] = SkColorGetA(c); 22 return packed; 23 } 24 25 static uint32_t pack_unpremul_bgra(SkColor c) { 26 uint32_t packed; 27 uint8_t* byte = reinterpret_cast<uint8_t*>(&packed); 28 byte[0] = SkColorGetB(c); 29 byte[1] = SkColorGetG(c); 30 byte[2] = SkColorGetR(c); 31 byte[3] = SkColorGetA(c); 32 return packed; 33 } 34 35 typedef uint32_t (*PackUnpremulProc)(SkColor); 36 37 const struct { 38 SkColorType fColorType; 39 PackUnpremulProc fPackProc; 40 } gUnpremul[] = { 41 { kRGBA_8888_SkColorType, pack_unpremul_rgba }, 42 { kBGRA_8888_SkColorType, pack_unpremul_bgra }, 43 }; 44 45 static void fill_surface(SkSurface* surf, SkColorType colorType, PackUnpremulProc proc) { 46 // Don't strictly need a bitmap, but its a handy way to allocate the pixels 47 SkBitmap bmp; 48 bmp.allocN32Pixels(256, 256); 49 50 for (int a = 0; a < 256; ++a) { 51 uint32_t* pixels = bmp.getAddr32(0, a); 52 for (int r = 0; r < 256; ++r) { 53 pixels[r] = proc(SkColorSetARGB(a, r, 0, 0)); 54 } 55 } 56 57 const SkImageInfo info = SkImageInfo::Make(bmp.width(), bmp.height(), 58 colorType, kUnpremul_SkAlphaType); 59 surf->writePixels({info, bmp.getPixels(), bmp.rowBytes()}, 0, 0); 60 } 61 62 static void test_premul_alpha_roundtrip(skiatest::Reporter* reporter, SkSurface* surf) { 63 for (size_t upmaIdx = 0; upmaIdx < SK_ARRAY_COUNT(gUnpremul); ++upmaIdx) { 64 fill_surface(surf, gUnpremul[upmaIdx].fColorType, gUnpremul[upmaIdx].fPackProc); 65 66 const SkImageInfo info = SkImageInfo::Make(256, 256, gUnpremul[upmaIdx].fColorType, 67 kUnpremul_SkAlphaType); 68 SkBitmap readBmp1; 69 readBmp1.allocPixels(info); 70 SkBitmap readBmp2; 71 readBmp2.allocPixels(info); 72 73 readBmp1.eraseColor(0); 74 readBmp2.eraseColor(0); 75 76 surf->readPixels(readBmp1, 0, 0); 77 sk_tool_utils::write_pixels(surf, readBmp1, 0, 0, gUnpremul[upmaIdx].fColorType, 78 kUnpremul_SkAlphaType); 79 surf->readPixels(readBmp2, 0, 0); 80 81 bool success = true; 82 for (int y = 0; y < 256 && success; ++y) { 83 const uint32_t* pixels1 = readBmp1.getAddr32(0, y); 84 const uint32_t* pixels2 = readBmp2.getAddr32(0, y); 85 for (int x = 0; x < 256 && success; ++x) { 86 // We see sporadic failures here. May help to see where it goes wrong. 87 if (pixels1[x] != pixels2[x]) { 88 SkDebugf("%x != %x, x = %d, y = %d\n", pixels1[x], pixels2[x], x, y); 89 } 90 REPORTER_ASSERT(reporter, success = pixels1[x] == pixels2[x]); 91 } 92 } 93 } 94 } 95 96 DEF_TEST(PremulAlphaRoundTrip, reporter) { 97 const SkImageInfo info = SkImageInfo::MakeN32Premul(256, 256); 98 99 sk_sp<SkSurface> surf(SkSurface::MakeRaster(info)); 100 101 test_premul_alpha_roundtrip(reporter, surf.get()); 102 } 103 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(PremulAlphaRoundTrip_Gpu, reporter, ctxInfo) { 104 const SkImageInfo info = SkImageInfo::MakeN32Premul(256, 256); 105 106 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(ctxInfo.grContext(), 107 SkBudgeted::kNo, 108 info)); 109 test_premul_alpha_roundtrip(reporter, surf.get()); 110 } 111