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>
This commit is contained in:
parent
5881e82060
commit
c7b2908947
@ -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 <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 @@ static bool copy_pipeline_pixels(const SkImageInfo& dstInfo, void* dstRow, size_
|
||||
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 @@ 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)) {
|
||||
|
@ -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);
|
||||
|
43
src/core/SkUnPreMultiplyPriv.h
Normal file
43
src/core/SkUnPreMultiplyPriv.h
Normal file
@ -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
|
@ -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<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 @@ 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<false>((uint32_t*) buffer, (const uint32_t*) buffer, width);
|
||||
buffer = SkTAddOffset<void>(buffer, rowBytes);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -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 <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_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<false>(dst, src, width);
|
||||
SkUnpremultiplyRow<true>((uint32_t*) dst, (const uint32_t*) src, width);
|
||||
}
|
||||
|
||||
template <bool kIsRGBA>
|
||||
|
Loading…
Reference in New Issue
Block a user