From c7b29089475772a51541323a93a15baad2a5feaa Mon Sep 17 00:00:00 2001 From: Matt Sarett Date: Thu, 9 Feb 2017 16:22:39 -0500 Subject: [PATCH] Refactor pixel conversion: premul and unpremul Just going for simpler and more code sharing. BUG=skia: Change-Id: I84c20cd4dbb6950f7b4d0bc659c4b3b5a2af201c Reviewed-on: https://skia-review.googlesource.com/8287 Reviewed-by: Mike Klein Commit-Queue: Matt Sarett --- src/core/SkConfig8888.cpp | 168 +++++++++++++--------------------------- src/core/SkConfig8888.h | 12 --- src/core/SkUnPreMultiplyPriv.h | 43 ++++++++++ src/gpu/GrContext.cpp | 42 +++++----- src/images/transform_scanline.h | 39 +--------- 5 files changed, 117 insertions(+), 187 deletions(-) create mode 100644 src/core/SkUnPreMultiplyPriv.h diff --git a/src/core/SkConfig8888.cpp b/src/core/SkConfig8888.cpp index cae2eef..59360e2 100644 --- a/src/core/SkConfig8888.cpp +++ b/src/core/SkConfig8888.cpp @@ -14,9 +14,10 @@ #include "SkDither.h" #include "SkImageInfoPriv.h" #include "SkMathPriv.h" +#include "SkOpts.h" #include "SkPM4fPriv.h" #include "SkRasterPipeline.h" -#include "SkUnPreMultiply.h" +#include "SkUnPreMultiplyPriv.h" // Fast Path 1: The memcpy() case. static inline bool can_memcpy(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo) { @@ -36,6 +37,53 @@ static inline bool can_memcpy(const SkImageInfo& dstInfo, const SkImageInfo& src SkColorSpace::Equals(dstInfo.colorSpace(), srcInfo.colorSpace()); } +enum AlphaVerb { + kNothing_AlphaVerb, + kPremul_AlphaVerb, + kUnpremul_AlphaVerb, +}; + +template +static void wrap_unpremultiply(uint32_t* dst, const void* src, int count) { + SkUnpremultiplyRow(dst, (const uint32_t*) src, count); +} + +// Fast Path 2: Simple swizzles and premuls. +void swizzle_and_multiply(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, + const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRB) { + void (*proc)(uint32_t* dst, const void* src, int count); + const bool swapRB = dstInfo.colorType() != srcInfo.colorType(); + AlphaVerb alphaVerb = kNothing_AlphaVerb; + if (kPremul_SkAlphaType == dstInfo.alphaType() && + kUnpremul_SkAlphaType == srcInfo.alphaType()) + { + alphaVerb = kPremul_AlphaVerb; + } else if (kUnpremul_SkAlphaType == dstInfo.alphaType() && + kPremul_SkAlphaType == srcInfo.alphaType()) { + alphaVerb = kUnpremul_AlphaVerb; + } + + switch (alphaVerb) { + case kNothing_AlphaVerb: + // If we do not need to swap or multiply, we should hit the memcpy case. + SkASSERT(swapRB); + proc = SkOpts::RGBA_to_BGRA; + break; + case kPremul_AlphaVerb: + proc = swapRB ? SkOpts::RGBA_to_bgrA : SkOpts::RGBA_to_rgbA; + break; + case kUnpremul_AlphaVerb: + proc = swapRB ? wrap_unpremultiply : wrap_unpremultiply; + break; + } + + for (int y = 0; y < dstInfo.height(); y++) { + proc((uint32_t*) dstPixels, srcPixels, dstInfo.width()); + dstPixels = SkTAddOffset(dstPixels, dstRB); + srcPixels = SkTAddOffset(srcPixels, srcRB); + } +} + // Default: Use the pipeline. static bool copy_pipeline_pixels(const SkImageInfo& dstInfo, void* dstRow, size_t dstRB, const SkImageInfo& srcInfo, const void* srcRow, size_t srcRB, @@ -114,107 +162,6 @@ static bool copy_pipeline_pixels(const SkImageInfo& dstInfo, void* dstRow, size_ return true; } -enum AlphaVerb { - kNothing_AlphaVerb, - kPremul_AlphaVerb, - kUnpremul_AlphaVerb, -}; - -template uint32_t convert32(uint32_t c) { - if (doSwapRB) { - c = SkSwizzle_RB(c); - } - - // Lucky for us, in both RGBA and BGRA, the alpha component is always in the same place, so - // we can perform premul or unpremul the same way without knowing the swizzles for RGB. - switch (doAlpha) { - case kNothing_AlphaVerb: - // no change - break; - case kPremul_AlphaVerb: - c = SkPreMultiplyARGB(SkGetPackedA32(c), SkGetPackedR32(c), - SkGetPackedG32(c), SkGetPackedB32(c)); - break; - case kUnpremul_AlphaVerb: - c = SkUnPreMultiply::UnPreMultiplyPreservingByteOrder(c); - break; - } - return c; -} - -template -void convert32_row(uint32_t* dst, const uint32_t* src, int count) { - // This has to be correct if src == dst (but not partial overlap) - for (int i = 0; i < count; ++i) { - dst[i] = convert32(src[i]); - } -} - -static bool is_32bit_colortype(SkColorType ct) { - return kRGBA_8888_SkColorType == ct || kBGRA_8888_SkColorType == ct; -} - -static AlphaVerb compute_AlphaVerb(SkAlphaType src, SkAlphaType dst) { - SkASSERT(kUnknown_SkAlphaType != src); - SkASSERT(kUnknown_SkAlphaType != dst); - - if (kOpaque_SkAlphaType == src || kOpaque_SkAlphaType == dst || src == dst) { - return kNothing_AlphaVerb; - } - if (kPremul_SkAlphaType == dst) { - SkASSERT(kUnpremul_SkAlphaType == src); - return kPremul_AlphaVerb; - } else { - SkASSERT(kPremul_SkAlphaType == src); - SkASSERT(kUnpremul_SkAlphaType == dst); - return kUnpremul_AlphaVerb; - } -} - -bool SkSrcPixelInfo::convertPixelsTo(SkDstPixelInfo* dst, int width, int height) const { - SkASSERT(width > 0 && height > 0); - - if (!is_32bit_colortype(fColorType) || !is_32bit_colortype(dst->fColorType)) { - return false; - } - - void (*proc)(uint32_t* dst, const uint32_t* src, int count); - AlphaVerb doAlpha = compute_AlphaVerb(fAlphaType, dst->fAlphaType); - bool doSwapRB = fColorType != dst->fColorType; - - switch (doAlpha) { - case kNothing_AlphaVerb: - SkASSERT(doSwapRB); - proc = convert32_row; - break; - case kPremul_AlphaVerb: - if (doSwapRB) { - proc = convert32_row; - } else { - proc = convert32_row; - } - break; - case kUnpremul_AlphaVerb: - if (doSwapRB) { - proc = convert32_row; - } else { - proc = convert32_row; - } - break; - } - - uint32_t* dstP = static_cast(dst->fPixels); - const uint32_t* srcP = static_cast(fPixels); - size_t srcInc = fRowBytes >> 2; - size_t dstInc = dst->fRowBytes >> 2; - for (int y = 0; y < height; ++y) { - proc(dstP, srcP, width); - dstP += dstInc; - srcP += srcInc; - } - return true; -} - 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; @@ -358,21 +305,10 @@ bool SkPixelInfo::CopyPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t const bool isColorAware = dstInfo.colorSpace(); SkASSERT(srcInfo.colorSpace() || !isColorAware); - // Handle fancy alpha swizzling if both are ARGB32 + // Fast Path 2: Simple swizzles and premuls. if (4 == srcInfo.bytesPerPixel() && 4 == dstInfo.bytesPerPixel() && !isColorAware) { - SkDstPixelInfo dstPI; - dstPI.fColorType = dstInfo.colorType(); - dstPI.fAlphaType = dstInfo.alphaType(); - dstPI.fPixels = dstPixels; - dstPI.fRowBytes = dstRB; - - SkSrcPixelInfo srcPI; - srcPI.fColorType = srcInfo.colorType(); - srcPI.fAlphaType = srcInfo.alphaType(); - srcPI.fPixels = srcPixels; - srcPI.fRowBytes = srcRB; - - return srcPI.convertPixelsTo(&dstPI, width, height); + swizzle_and_multiply(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB); + return true; } if (isColorAware && optimized_color_xform(dstInfo, srcInfo)) { diff --git a/src/core/SkConfig8888.h b/src/core/SkConfig8888.h index 3544cbe..9c1ff4a 100644 --- a/src/core/SkConfig8888.h +++ b/src/core/SkConfig8888.h @@ -23,18 +23,6 @@ struct SkPixelInfo { SkColorTable* srcCTable = nullptr); }; -struct SkDstPixelInfo : SkPixelInfo { - void* fPixels; -}; - -struct SkSrcPixelInfo : SkPixelInfo { - const void* fPixels; - - // Guaranteed to work even if src.fPixels and dst.fPixels are the same - // (but not if they overlap partially) - bool convertPixelsTo(SkDstPixelInfo* dst, int width, int height) const; -}; - static inline void SkRectMemcpy(void* dst, size_t dstRB, const void* src, size_t srcRB, size_t bytesPerRow, int rowCount) { SkASSERT(bytesPerRow <= dstRB); diff --git a/src/core/SkUnPreMultiplyPriv.h b/src/core/SkUnPreMultiplyPriv.h new file mode 100644 index 0000000..073e239 --- /dev/null +++ b/src/core/SkUnPreMultiplyPriv.h @@ -0,0 +1,43 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkUnPreMultiplyPriv_DEFINED +#define SkUnPreMultiplyPriv_DEFINED + +#include "SkColor.h" + +template +void SkUnpremultiplyRow(uint32_t* dst, const uint32_t* src, int count) { + const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable(); + + for (int i = 0; i < count; i++) { + uint32_t c = *src++; + uint8_t r, g, b, a; + if (kSwapRB) { + r = (c >> 16) & 0xFF; + g = (c >> 8) & 0xFF; + b = (c >> 0) & 0xFF; + a = (c >> 24) & 0xFF; + } else { + r = (c >> 0) & 0xFF; + g = (c >> 8) & 0xFF; + b = (c >> 16) & 0xFF; + a = (c >> 24) & 0xFF; + } + + if (0 != a && 255 != a) { + SkUnPreMultiply::Scale scale = table[a]; + r = SkUnPreMultiply::ApplyScale(scale, r); + g = SkUnPreMultiply::ApplyScale(scale, g); + b = SkUnPreMultiply::ApplyScale(scale, b); + } + + *dst++ = (r << 0) | (g << 8) | (b << 16) | (a << 24); + } +} + +#endif diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index b5586b4..4b67d54 100644 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -21,6 +21,7 @@ #include "SkConfig8888.h" #include "SkGrPriv.h" +#include "SkUnPreMultiplyPriv.h" #include "effects/GrConfigConversionEffect.h" #include "text/GrTextBlobCache.h" @@ -226,21 +227,20 @@ void GrContext::flush() { bool sw_convert_to_premul(GrPixelConfig srcConfig, int width, int height, size_t inRowBytes, const void* inPixels, size_t outRowBytes, void* outPixels) { - SkSrcPixelInfo srcPI; - if (!GrPixelConfigToColorType(srcConfig, &srcPI.fColorType)) { + SkColorType colorType; + if (!GrPixelConfigToColorType(srcConfig, &colorType) || + 4 != SkColorTypeBytesPerPixel(colorType)) + { return false; } - srcPI.fAlphaType = kUnpremul_SkAlphaType; - srcPI.fPixels = inPixels; - srcPI.fRowBytes = inRowBytes; - SkDstPixelInfo dstPI; - dstPI.fColorType = srcPI.fColorType; - dstPI.fAlphaType = kPremul_SkAlphaType; - dstPI.fPixels = outPixels; - dstPI.fRowBytes = outRowBytes; + for (int y = 0; y < height; y++) { + SkOpts::RGBA_to_rgbA((uint32_t*) outPixels, inPixels, width); + outPixels = SkTAddOffset(outPixels, outRowBytes); + inPixels = SkTAddOffset(inPixels, inRowBytes); + } - return srcPI.convertPixelsTo(&dstPI, width, height); + return true; } bool GrContext::writeSurfacePixels(GrSurface* surface, SkColorSpace* dstColorSpace, @@ -522,21 +522,17 @@ bool GrContext::readSurfacePixels(GrSurface* src, SkColorSpace* srcColorSpace, // Perform umpremul conversion if we weren't able to perform it as a draw. if (unpremul) { - SkDstPixelInfo dstPI; - if (!GrPixelConfigToColorType(dstConfig, &dstPI.fColorType)) { + SkColorType colorType; + if (!GrPixelConfigToColorType(dstConfig, &colorType) || + 4 != SkColorTypeBytesPerPixel(colorType)) + { return false; } - dstPI.fAlphaType = kUnpremul_SkAlphaType; - dstPI.fPixels = buffer; - dstPI.fRowBytes = rowBytes; - SkSrcPixelInfo srcPI; - srcPI.fColorType = dstPI.fColorType; - srcPI.fAlphaType = kPremul_SkAlphaType; - srcPI.fPixels = buffer; - srcPI.fRowBytes = rowBytes; - - return srcPI.convertPixelsTo(&dstPI, width, height); + for (int y = 0; y < height; y++) { + SkUnpremultiplyRow((uint32_t*) buffer, (const uint32_t*) buffer, width); + buffer = SkTAddOffset(buffer, rowBytes); + } } return true; } diff --git a/src/images/transform_scanline.h b/src/images/transform_scanline.h index 6bf3474..d855964 100644 --- a/src/images/transform_scanline.h +++ b/src/images/transform_scanline.h @@ -15,6 +15,7 @@ #include "SkPreConfig.h" #include "SkRasterPipeline.h" #include "SkUnPreMultiply.h" +#include "SkUnPreMultiplyPriv.h" /** * Function template for transforming scanlines. @@ -128,46 +129,12 @@ static inline void transform_scanline_444(char* SK_RESTRICT dst, const char* SK_ } } -template -static inline void transform_scanline_unpremultiply(char* SK_RESTRICT dst, - const char* SK_RESTRICT src, int width) { - const uint32_t* srcP = (const SkPMColor*)src; - const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable(); - - for (int i = 0; i < width; i++) { - uint32_t c = *srcP++; - unsigned r, g, b, a; - if (kIsRGBA) { - r = (c >> 0) & 0xFF; - g = (c >> 8) & 0xFF; - b = (c >> 16) & 0xFF; - a = (c >> 24) & 0xFF; - } else { - r = (c >> 16) & 0xFF; - g = (c >> 8) & 0xFF; - b = (c >> 0) & 0xFF; - a = (c >> 24) & 0xFF; - } - - if (0 != a && 255 != a) { - SkUnPreMultiply::Scale scale = table[a]; - r = SkUnPreMultiply::ApplyScale(scale, r); - g = SkUnPreMultiply::ApplyScale(scale, g); - b = SkUnPreMultiply::ApplyScale(scale, b); - } - *dst++ = r; - *dst++ = g; - *dst++ = b; - *dst++ = a; - } -} - /** * Transform from legacy kPremul, kRGBA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA. */ static inline void transform_scanline_rgbA(char* SK_RESTRICT dst, const char* SK_RESTRICT src, int width, int, const SkPMColor*) { - transform_scanline_unpremultiply(dst, src, width); + SkUnpremultiplyRow((uint32_t*) dst, (const uint32_t*) src, width); } /** @@ -175,7 +142,7 @@ static inline void transform_scanline_rgbA(char* SK_RESTRICT dst, const char* SK */ static inline void transform_scanline_bgrA(char* SK_RESTRICT dst, const char* SK_RESTRICT src, int width, int, const SkPMColor*) { - transform_scanline_unpremultiply(dst, src, width); + SkUnpremultiplyRow((uint32_t*) dst, (const uint32_t*) src, width); } template -- 2.7.4