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
This commit is contained in:
lsalzman 2016-10-11 14:29:12 -07:00 committed by Commit bot
parent 0f61faa7b7
commit a2415accf1
3 changed files with 120 additions and 70 deletions

View File

@ -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;
}

View File

@ -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())) {

View File

@ -135,8 +135,14 @@ static void fill_dst_bmp_with_init_data(SkBitmap* bitmap) {
intptr_t pixels = reinterpret_cast<intptr_t>(bitmap->getPixels());
for (int y = 0; y < h; ++y) {
for (int x = 0; x < w; ++x) {
SkPMColor* pixel = reinterpret_cast<SkPMColor*>(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<uint8_t*>(pixels + y * bitmap->rowBytes() + x);
*alpha = SkGetPackedA32(initColor);
} else {
SkPMColor* pixel = reinterpret_cast<SkPMColor*>(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<SkSurface>
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<SkSurface>
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);
}
}
}