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 <mtklein@chromium.org>
Commit-Queue: Matt Sarett <msarett@google.com>
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 @@
SkColorSpace::Equals(dstInfo.colorSpace(), srcInfo.colorSpace());
}
+enum AlphaVerb {
+ kNothing_AlphaVerb,
+ kPremul_AlphaVerb,
+ kUnpremul_AlphaVerb,
+};
+
+template <bool kSwapRB>
+static void wrap_unpremultiply(uint32_t* dst, const void* src, int count) {
+ SkUnpremultiplyRow<kSwapRB>(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<true> : wrap_unpremultiply<false>;
+ break;
+ }
+
+ for (int y = 0; y < dstInfo.height(); y++) {
+ proc((uint32_t*) dstPixels, srcPixels, dstInfo.width());
+ dstPixels = SkTAddOffset<void>(dstPixels, dstRB);
+ srcPixels = SkTAddOffset<const void>(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 @@
return true;
}
-enum AlphaVerb {
- kNothing_AlphaVerb,
- kPremul_AlphaVerb,
- kUnpremul_AlphaVerb,
-};
-
-template <bool doSwapRB, AlphaVerb doAlpha> 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 <bool doSwapRB, AlphaVerb doAlpha>
-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<doSwapRB, doAlpha>(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<true, kNothing_AlphaVerb>;
- break;
- case kPremul_AlphaVerb:
- if (doSwapRB) {
- proc = convert32_row<true, kPremul_AlphaVerb>;
- } else {
- proc = convert32_row<false, kPremul_AlphaVerb>;
- }
- break;
- case kUnpremul_AlphaVerb:
- if (doSwapRB) {
- proc = convert32_row<true, kUnpremul_AlphaVerb>;
- } else {
- proc = convert32_row<false, kUnpremul_AlphaVerb>;
- }
- break;
- }
-
- uint32_t* dstP = static_cast<uint32_t*>(dst->fPixels);
- const uint32_t* srcP = static_cast<const uint32_t*>(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 @@
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 @@
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 <bool kSwapRB>
+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 @@
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<void>(outPixels, outRowBytes);
+ inPixels = SkTAddOffset<const void>(inPixels, inRowBytes);
+ }
- return srcPI.convertPixelsTo(&dstPI, width, height);
+ return true;
}
bool GrContext::writeSurfacePixels(GrSurface* surface, SkColorSpace* dstColorSpace,
@@ -522,21 +522,17 @@
// 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<false>((uint32_t*) buffer, (const uint32_t*) buffer, width);
+ buffer = SkTAddOffset<void>(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 @@
}
}
-template <bool kIsRGBA>
-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<true>(dst, src, width);
+ SkUnpremultiplyRow<false>((uint32_t*) dst, (const uint32_t*) src, width);
}
/**
@@ -175,7 +142,7 @@
*/
static inline void transform_scanline_bgrA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
int width, int, const SkPMColor*) {
- transform_scanline_unpremultiply<false>(dst, src, width);
+ SkUnpremultiplyRow<true>((uint32_t*) dst, (const uint32_t*) src, width);
}
template <bool kIsRGBA>