From a2415accf1f184c4df6cffc2ccdd38f8d61031f6 Mon Sep 17 00:00:00 2001 From: lsalzman Date: Tue, 11 Oct 2016 14:29:12 -0700 Subject: implement A8 destination fast-path for SkPixelInfo::CopyPixels BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2407093002 Review-Url: https://codereview.chromium.org/2407093002 --- src/core/SkBitmap.cpp | 66 ++++++----------------------------------------- src/core/SkConfig8888.cpp | 63 ++++++++++++++++++++++++++++++++++++++++++++ tests/ReadPixelsTest.cpp | 61 ++++++++++++++++++++++++++++++++++--------- 3 files changed, 120 insertions(+), 70 deletions(-) diff --git a/src/core/SkBitmap.cpp b/src/core/SkBitmap.cpp index 26630860ac..c62f5f391b 100644 --- a/src/core/SkBitmap.cpp +++ b/src/core/SkBitmap.cpp @@ -8,6 +8,7 @@ #include "SkAtomics.h" #include "SkBitmap.h" #include "SkColorPriv.h" +#include "SkConfig8888.h" #include "SkData.h" #include "SkFilterQuality.h" #include "SkMallocPixelRef.h" @@ -906,72 +907,21 @@ bool SkBitmap::deepCopyTo(SkBitmap* dst) const { /////////////////////////////////////////////////////////////////////////////// -static void rect_memset(uint8_t* array, U8CPU value, SkISize size, size_t rowBytes) { - for (int y = 0; y < size.height(); ++y) { - memset(array, value, size.width()); - array += rowBytes; - } -} - -static void get_bitmap_alpha(const SkPixmap& pmap, uint8_t* SK_RESTRICT alpha, int alphaRowBytes) { - SkColorType colorType = pmap.colorType(); - int w = pmap.width(); - int h = pmap.height(); - size_t rb = pmap.rowBytes(); - - if (kAlpha_8_SkColorType == colorType && !pmap.isOpaque()) { - const uint8_t* s = pmap.addr8(0, 0); - while (--h >= 0) { - memcpy(alpha, s, w); - s += rb; - alpha += alphaRowBytes; - } - } else if (kN32_SkColorType == colorType && !pmap.isOpaque()) { - const SkPMColor* SK_RESTRICT s = pmap.addr32(0, 0); - while (--h >= 0) { - for (int x = 0; x < w; x++) { - alpha[x] = SkGetPackedA32(s[x]); - } - s = (const SkPMColor*)((const char*)s + rb); - alpha += alphaRowBytes; - } - } else if (kARGB_4444_SkColorType == colorType && !pmap.isOpaque()) { - const SkPMColor16* SK_RESTRICT s = pmap.addr16(0, 0); - while (--h >= 0) { - for (int x = 0; x < w; x++) { - alpha[x] = SkPacked4444ToA32(s[x]); - } - s = (const SkPMColor16*)((const char*)s + rb); - alpha += alphaRowBytes; - } - } else if (kIndex_8_SkColorType == colorType && !pmap.isOpaque()) { - const SkColorTable* ct = pmap.ctable(); - if (ct) { - const SkPMColor* SK_RESTRICT table = ct->readColors(); - const uint8_t* SK_RESTRICT s = pmap.addr8(0, 0); - while (--h >= 0) { - for (int x = 0; x < w; x++) { - alpha[x] = SkGetPackedA32(table[s[x]]); - } - s += rb; - alpha += alphaRowBytes; - } - } - } else { // src is opaque, so just fill alpha[] with 0xFF - rect_memset(alpha, 0xFF, pmap.info().dimensions(), alphaRowBytes); - } -} - static bool GetBitmapAlpha(const SkBitmap& src, uint8_t* SK_RESTRICT alpha, int alphaRowBytes) { SkASSERT(alpha != nullptr); SkASSERT(alphaRowBytes >= src.width()); SkAutoPixmapUnlock apl; if (!src.requestLock(&apl)) { - rect_memset(alpha, 0, src.info().dimensions(), alphaRowBytes); + for (int y = 0; y < src.height(); ++y) { + memset(alpha, 0, src.width()); + alpha += alphaRowBytes; + } return false; } - get_bitmap_alpha(apl.pixmap(), alpha, alphaRowBytes); + const SkPixmap& pmap = apl.pixmap(); + SkPixelInfo::CopyPixels(SkImageInfo::MakeA8(pmap.width(), pmap.height()), alpha, alphaRowBytes, + pmap.info(), pmap.addr(), pmap.rowBytes(), pmap.ctable()); return true; } diff --git a/src/core/SkConfig8888.cpp b/src/core/SkConfig8888.cpp index 31def9a92d..7c3f0214e3 100644 --- a/src/core/SkConfig8888.cpp +++ b/src/core/SkConfig8888.cpp @@ -167,6 +167,64 @@ static void copy_32_to_g8(void* dst, size_t dstRB, const void* src, size_t srcRB } } +static bool extract_alpha(void* dst, size_t dstRB, const void* src, size_t srcRB, + const SkImageInfo& srcInfo, SkColorTable* ctable) { + uint8_t* SK_RESTRICT dst8 = (uint8_t*)dst; + + const int w = srcInfo.width(); + const int h = srcInfo.height(); + if (srcInfo.isOpaque()) { + // src is opaque, so just fill alpha with 0xFF + for (int y = 0; y < h; ++y) { + memset(dst8, 0xFF, w); + dst8 += dstRB; + } + return true; + } + switch (srcInfo.colorType()) { + case kN32_SkColorType: { + const SkPMColor* SK_RESTRICT src32 = (const SkPMColor*)src; + for (int y = 0; y < h; ++y) { + for (int x = 0; x < w; ++x) { + dst8[x] = SkGetPackedA32(src32[x]); + } + dst8 += dstRB; + src32 = (const SkPMColor*)((const char*)src32 + srcRB); + } + break; + } + case kARGB_4444_SkColorType: { + const SkPMColor16* SK_RESTRICT src16 = (const SkPMColor16*)src; + for (int y = 0; y < h; ++y) { + for (int x = 0; x < w; ++x) { + dst8[x] = SkPacked4444ToA32(src16[x]); + } + dst8 += dstRB; + src16 = (const SkPMColor16*)((const char*)src16 + srcRB); + } + break; + } + case kIndex_8_SkColorType: { + if (nullptr == ctable) { + return false; + } + const SkPMColor* SK_RESTRICT table = ctable->readColors(); + const uint8_t* SK_RESTRICT src8 = (const uint8_t*)src; + for (int y = 0; y < h; ++y) { + for (int x = 0; x < w; ++x) { + dst8[x] = SkGetPackedA32(table[src8[x]]); + } + dst8 += dstRB; + src8 += srcRB; + } + break; + } + default: + return false; + } + return true; +} + bool SkPixelInfo::CopyPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRB, SkColorTable* ctable) { @@ -241,6 +299,11 @@ bool SkPixelInfo::CopyPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t return true; } + if (kAlpha_8_SkColorType == dstInfo.colorType() && + extract_alpha(dstPixels, dstRB, srcPixels, srcRB, srcInfo, ctable)) { + return true; + } + // Can no longer draw directly into 4444, but we can manually whack it for a few combinations if (kARGB_4444_SkColorType == dstInfo.colorType() && (kN32_SkColorType == srcInfo.colorType() || kIndex_8_SkColorType == srcInfo.colorType())) { diff --git a/tests/ReadPixelsTest.cpp b/tests/ReadPixelsTest.cpp index 008781ca06..5fa7dd19f4 100644 --- a/tests/ReadPixelsTest.cpp +++ b/tests/ReadPixelsTest.cpp @@ -135,8 +135,14 @@ static void fill_dst_bmp_with_init_data(SkBitmap* bitmap) { intptr_t pixels = reinterpret_cast(bitmap->getPixels()); for (int y = 0; y < h; ++y) { for (int x = 0; x < w; ++x) { - SkPMColor* pixel = reinterpret_cast(pixels + y * bitmap->rowBytes() + x * bitmap->bytesPerPixel()); - *pixel = get_dst_bmp_init_color(x, y, w); + SkPMColor initColor = get_dst_bmp_init_color(x, y, w); + if (kAlpha_8_SkColorType == bitmap->colorType()) { + uint8_t* alpha = reinterpret_cast(pixels + y * bitmap->rowBytes() + x); + *alpha = SkGetPackedA32(initColor); + } else { + SkPMColor* pixel = reinterpret_cast(pixels + y * bitmap->rowBytes() + x * bitmap->bytesPerPixel()); + *pixel = initColor; + } } } } @@ -168,14 +174,13 @@ static bool check_read(skiatest::Reporter* reporter, const SkBitmap& bitmap, int x, int y, bool checkCanvasPixels, - bool checkBitmapPixels) { - SkASSERT(4 == bitmap.bytesPerPixel()); + bool checkBitmapPixels, + SkColorType ct, + SkAlphaType at) { + SkASSERT(ct == bitmap.colorType() && at == bitmap.alphaType()); SkASSERT(!bitmap.isNull()); SkASSERT(checkCanvasPixels || checkBitmapPixels); - const SkColorType ct = bitmap.colorType(); - const SkAlphaType at = bitmap.alphaType(); - int bw = bitmap.width(); int bh = bitmap.height(); @@ -185,6 +190,34 @@ static bool check_read(skiatest::Reporter* reporter, clippedSrcRect.setEmpty(); } SkAutoLockPixels alp(bitmap); + if (kAlpha_8_SkColorType == ct) { + for (int by = 0; by < bh; ++by) { + for (int bx = 0; bx < bw; ++bx) { + int devx = bx + srcRect.fLeft; + int devy = by + srcRect.fTop; + const uint8_t* alpha = bitmap.getAddr8(bx, by); + + if (clippedSrcRect.contains(devx, devy)) { + if (checkCanvasPixels) { + uint8_t canvasAlpha = SkGetPackedA32(get_src_color(devx, devy)); + if (canvasAlpha != *alpha) { + ERRORF(reporter, "Expected readback alpha (%d, %d) value 0x%02x, got 0x%02x. ", + bx, by, canvasAlpha, *alpha); + return false; + } + } + } else if (checkBitmapPixels) { + uint32_t origDstAlpha = SkGetPackedA32(get_dst_bmp_init_color(bx, by, bw)); + if (origDstAlpha != *alpha) { + ERRORF(reporter, "Expected clipped out area of readback to be unchanged. " + "Expected 0x%02x, got 0x%02x", origDstAlpha, *alpha); + return false; + } + } + } + } + return true; + } for (int by = 0; by < bh; ++by) { for (int bx = 0; bx < bw; ++bx) { int devx = bx + srcRect.fLeft; @@ -249,10 +282,10 @@ static void init_bitmap(SkBitmap* bitmap, const SkIRect& rect, BitmapInit init, case kTight_BitmapInit: break; case kRowBytes_BitmapInit: - rowBytes = (info.width() + 16) * sizeof(SkPMColor); + rowBytes = SkAlign4((info.width() + 16) * info.bytesPerPixel()); break; case kRowBytesOdd_BitmapInit: - rowBytes = (info.width() * sizeof(SkPMColor)) + 3; + rowBytes = SkAlign4(info.width() * info.bytesPerPixel()) + 3; break; default: SkASSERT(0); @@ -274,6 +307,7 @@ static const struct { { kRGBA_8888_SkColorType, kUnpremul_SkAlphaType }, { kBGRA_8888_SkColorType, kPremul_SkAlphaType }, { kBGRA_8888_SkColorType, kUnpremul_SkAlphaType }, + { kAlpha_8_SkColorType, kPremul_SkAlphaType }, }; const SkIRect gReadPixelsTestRects[] = { // entire thing @@ -354,7 +388,8 @@ static void test_readpixels(skiatest::Reporter* reporter, const sk_sp if (success || startsWithPixels) { check_read(reporter, bmp, srcRect.fLeft, srcRect.fTop, - success, startsWithPixels); + success, startsWithPixels, + gReadPixelsConfigs[c].fColorType, gReadPixelsConfigs[c].fAlphaType); } else { // if we had no pixels beforehand and the readPixels // failed then our bitmap should still not have pixels @@ -371,7 +406,8 @@ static void test_readpixels(skiatest::Reporter* reporter, const sk_sp REPORTER_ASSERT(reporter, kN32_SkColorType == wkbmp.colorType()); REPORTER_ASSERT(reporter, kPremul_SkAlphaType == wkbmp.alphaType()); check_read(reporter, wkbmp, clippedRect.fLeft, - clippedRect.fTop, true, false); + clippedRect.fTop, true, false, + kN32_SkColorType, kPremul_SkAlphaType); } else { REPORTER_ASSERT(reporter, !success); } @@ -427,7 +463,8 @@ static void test_readpixels_texture(skiatest::Reporter* reporter, GrTexture* tex bmp.rowBytes(), flags); bmp.unlockPixels(); check_read(reporter, bmp, srcRect.fLeft, srcRect.fTop, - success, true); + success, true, + gReadPixelsConfigs[c].fColorType, gReadPixelsConfigs[c].fAlphaType); } } } -- cgit v1.2.3