|  | /* | 
|  | * Copyright 2011 Google Inc. | 
|  | * | 
|  | * Use of this source code is governed by a BSD-style license that can be | 
|  | * found in the LICENSE file. | 
|  | */ | 
|  |  | 
|  | #include "SkBitmapDevice.h" | 
|  | #include "SkCanvas.h" | 
|  | #include "SkConfig8888.h" | 
|  | #include "Test.h" | 
|  | #include "sk_tool_utils.h" | 
|  |  | 
|  | #if SK_SUPPORT_GPU | 
|  | #include "GrContextFactory.h" | 
|  | #include "SkGpuDevice.h" | 
|  | #endif | 
|  |  | 
|  | static uint32_t pack_unpremul_rgba(SkColor c) { | 
|  | uint32_t packed; | 
|  | uint8_t* byte = reinterpret_cast<uint8_t*>(&packed); | 
|  | byte[0] = SkColorGetR(c); | 
|  | byte[1] = SkColorGetG(c); | 
|  | byte[2] = SkColorGetB(c); | 
|  | byte[3] = SkColorGetA(c); | 
|  | return packed; | 
|  | } | 
|  |  | 
|  | static uint32_t pack_unpremul_bgra(SkColor c) { | 
|  | uint32_t packed; | 
|  | uint8_t* byte = reinterpret_cast<uint8_t*>(&packed); | 
|  | byte[0] = SkColorGetB(c); | 
|  | byte[1] = SkColorGetG(c); | 
|  | byte[2] = SkColorGetR(c); | 
|  | byte[3] = SkColorGetA(c); | 
|  | return packed; | 
|  | } | 
|  |  | 
|  | typedef uint32_t (*PackUnpremulProc)(SkColor); | 
|  |  | 
|  | const struct { | 
|  | SkColorType         fColorType; | 
|  | PackUnpremulProc    fPackProc; | 
|  | } gUnpremul[] = { | 
|  | { kRGBA_8888_SkColorType, pack_unpremul_rgba }, | 
|  | { kBGRA_8888_SkColorType, pack_unpremul_bgra }, | 
|  | }; | 
|  |  | 
|  | static void fillCanvas(SkCanvas* canvas, SkColorType colorType, PackUnpremulProc proc) { | 
|  | // Don't strictly need a bitmap, but its a handy way to allocate the pixels | 
|  | SkBitmap bmp; | 
|  | bmp.allocN32Pixels(256, 256); | 
|  |  | 
|  | for (int a = 0; a < 256; ++a) { | 
|  | uint32_t* pixels = bmp.getAddr32(0, a); | 
|  | for (int r = 0; r < 256; ++r) { | 
|  | pixels[r] = proc(SkColorSetARGB(a, r, 0, 0)); | 
|  | } | 
|  | } | 
|  |  | 
|  | SkImageInfo info = bmp.info(); | 
|  | info.fColorType = colorType; | 
|  | info.fAlphaType = kUnpremul_SkAlphaType; | 
|  | canvas->writePixels(info, bmp.getPixels(), bmp.rowBytes(), 0, 0); | 
|  | } | 
|  |  | 
|  | DEF_GPUTEST(PremulAlphaRoundTrip, reporter, factory) { | 
|  | const SkImageInfo info = SkImageInfo::MakeN32Premul(256, 256); | 
|  |  | 
|  | for (int dtype = 0; dtype < 2; ++dtype) { | 
|  |  | 
|  | int glCtxTypeCnt = 1; | 
|  | #if SK_SUPPORT_GPU | 
|  | if (0 != dtype)  { | 
|  | glCtxTypeCnt = GrContextFactory::kGLContextTypeCnt; | 
|  | } | 
|  | #endif | 
|  | for (int glCtxType = 0; glCtxType < glCtxTypeCnt; ++glCtxType) { | 
|  | SkAutoTUnref<SkBaseDevice> device; | 
|  | if (0 == dtype) { | 
|  | device.reset(SkBitmapDevice::Create(info)); | 
|  | } else { | 
|  | #if SK_SUPPORT_GPU | 
|  | GrContextFactory::GLContextType type = | 
|  | static_cast<GrContextFactory::GLContextType>(glCtxType); | 
|  | if (!GrContextFactory::IsRenderingGLContext(type)) { | 
|  | continue; | 
|  | } | 
|  | GrContext* context = factory->get(type); | 
|  | if (NULL == context) { | 
|  | continue; | 
|  | } | 
|  |  | 
|  | device.reset(SkGpuDevice::Create(context, info, 0)); | 
|  | #else | 
|  | continue; | 
|  | #endif | 
|  | } | 
|  | SkCanvas canvas(device); | 
|  |  | 
|  | for (size_t upmaIdx = 0; upmaIdx < SK_ARRAY_COUNT(gUnpremul); ++upmaIdx) { | 
|  | fillCanvas(&canvas, gUnpremul[upmaIdx].fColorType, gUnpremul[upmaIdx].fPackProc); | 
|  |  | 
|  | const SkImageInfo info = SkImageInfo::Make(256, 256, gUnpremul[upmaIdx].fColorType, | 
|  | kUnpremul_SkAlphaType); | 
|  | SkBitmap readBmp1; | 
|  | readBmp1.allocPixels(info); | 
|  | SkBitmap readBmp2; | 
|  | readBmp2.allocPixels(info); | 
|  |  | 
|  | readBmp1.eraseColor(0); | 
|  | readBmp2.eraseColor(0); | 
|  |  | 
|  | canvas.readPixels(&readBmp1, 0, 0); | 
|  | sk_tool_utils::write_pixels(&canvas, readBmp1, 0, 0, gUnpremul[upmaIdx].fColorType, | 
|  | kUnpremul_SkAlphaType); | 
|  | canvas.readPixels(&readBmp2, 0, 0); | 
|  |  | 
|  | bool success = true; | 
|  | for (int y = 0; y < 256 && success; ++y) { | 
|  | const uint32_t* pixels1 = readBmp1.getAddr32(0, y); | 
|  | const uint32_t* pixels2 = readBmp2.getAddr32(0, y); | 
|  | for (int x = 0; x < 256 && success; ++x) { | 
|  | // We see sporadic failures here. May help to see where it goes wrong. | 
|  | if (pixels1[x] != pixels2[x]) { | 
|  | SkDebugf("%x != %x, x = %d, y = %d\n", pixels1[x], pixels2[x], x, y); | 
|  | } | 
|  | REPORTER_ASSERT(reporter, success = pixels1[x] == pixels2[x]); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } |