implement SkConvertPixels color xform with steps

Opaque destinations like 565 prove the assert
I just added can't be quite so strong.

This kills off another nemesis, append_gamut_transform().

Change-Id: I5030ce094ae0f6a34d0301f6fe060b50342c7ef4
Reviewed-on: https://skia-review.googlesource.com/147106
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Mike Klein <mtklein@google.com>
This commit is contained in:
Mike Klein 2018-08-14 12:58:53 -04:00 committed by Skia Commit-Bot
parent 0edad3e46d
commit 6a2a197602
3 changed files with 15 additions and 86 deletions

View File

@ -12,8 +12,10 @@
SkColorSpaceXformSteps::SkColorSpaceXformSteps(SkColorSpace* src, SkAlphaType srcAT,
SkColorSpace* dst, SkAlphaType dstAT) {
// We can exploit that srcs are opaque, but it doesn't make sense to ask for opaque output.
SkASSERT(dstAT != kOpaque_SkAlphaType);
// It's mildly interesting to know the output is opaque, but mechanically that's just unpremul.
if (dstAT == kOpaque_SkAlphaType) {
dstAT = kUnpremul_SkAlphaType;
}
// Set all bools to false, all floats to 0.0f.
memset(this, 0, sizeof(*this));

View File

@ -173,8 +173,7 @@ static void convert_to_alpha8(uint8_t* dst, size_t dstRB, const SkImageInfo& src
// Default: Use the pipeline.
static void convert_with_pipeline(const SkImageInfo& dstInfo, void* dstRow, size_t dstRB,
const SkImageInfo& srcInfo, const void* srcRow, size_t srcRB,
bool isColorAware) {
const SkImageInfo& srcInfo, const void* srcRow, size_t srcRB) {
SkJumper_MemoryCtx src = { (void*)srcRow, (int)(srcRB / srcInfo.bytesPerPixel()) },
dst = { (void*)dstRow, (int)(dstRB / dstInfo.bytesPerPixel()) };
@ -218,53 +217,16 @@ static void convert_with_pipeline(const SkImageInfo& dstInfo, void* dstRow, size
break;
}
SkAlphaType premulState = srcInfo.alphaType();
if (kPremul_SkAlphaType == premulState) {
pipeline.append(SkRasterPipeline::unpremul);
premulState = kUnpremul_SkAlphaType;
}
// Interpret any untagged source as sRGB.
auto srcCS = srcInfo.colorSpace() ? srcInfo.colorSpace() : sk_srgb_singleton();
SkColorSpaceTransferFn srcFn;
if (isColorAware && srcInfo.gammaCloseToSRGB()) {
pipeline.append(SkRasterPipeline::from_srgb);
} else if (isColorAware && !srcInfo.colorSpace()->gammaIsLinear()) {
SkAssertResult(srcInfo.colorSpace()->isNumericalTransferFn(&srcFn));
if (is_just_gamma(srcFn)) {
pipeline.append(SkRasterPipeline::gamma, &srcFn.fG);
} else {
pipeline.append(SkRasterPipeline::parametric, &srcFn);
}
}
// An untagged destination implies no color space transform is needed,
// but SkColorSpaceXformSteps may still do premul/unpremul conversion.
auto dstCS = dstInfo.colorSpace() ? dstInfo.colorSpace() : srcCS;
SkSTArenaAlloc<12*sizeof(float)> alloc;
if (isColorAware) {
append_gamut_transform(&pipeline, &alloc,
srcInfo.colorSpace(), dstInfo.colorSpace(), premulState);
}
SkColorSpaceTransferFn dstFn;
if (isColorAware && dstInfo.gammaCloseToSRGB()) {
pipeline.append(SkRasterPipeline::to_srgb);
} else if (isColorAware && !dstInfo.colorSpace()->gammaIsLinear()) {
SkAssertResult(dstInfo.colorSpace()->isNumericalTransferFn(&dstFn));
dstFn = dstFn.invert();
if (is_just_gamma(dstFn)) {
pipeline.append(SkRasterPipeline::gamma, &dstFn.fG);
} else {
pipeline.append(SkRasterPipeline::parametric, &dstFn);
}
}
SkAlphaType dat = dstInfo.alphaType();
if (kUnpremul_SkAlphaType == premulState && kPremul_SkAlphaType == dat)
{
pipeline.append(SkRasterPipeline::premul);
premulState = kPremul_SkAlphaType;
}
// The final premul state must equal the dst alpha type. Note that if we are "converting"
// opaque to another alpha type, there's no need to worry about multiplication.
SkASSERT(premulState == dat || kOpaque_SkAlphaType == srcInfo.alphaType());
SkColorSpaceXformSteps steps{srcCS, srcInfo.alphaType(),
dstCS, dstInfo.alphaType()};
steps.apply(&pipeline);
// We'll dither if we're decreasing precision below 32-bit.
float dither_rate = 0.0f;
@ -338,12 +300,9 @@ void SkConvertPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
return;
}
const bool isColorAware = dstInfo.colorSpace();
SkASSERT(srcInfo.colorSpace() || !isColorAware);
// Fast Path 2: Simple swizzles and premuls.
if (swizzle_and_multiply_color_type(srcInfo.colorType()) &&
swizzle_and_multiply_color_type(dstInfo.colorType()) && !isColorAware) {
swizzle_and_multiply_color_type(dstInfo.colorType()) && !dstInfo.colorSpace()) {
swizzle_and_multiply(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB);
return;
}
@ -355,5 +314,5 @@ void SkConvertPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
}
// Default: Use the pipeline.
convert_with_pipeline(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB, isColorAware);
convert_with_pipeline(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB);
}

View File

@ -83,36 +83,4 @@ static inline uint32_t Sk4f_toS32(const Sk4f& px) {
return s32;
}
static inline void append_gamut_transform(SkRasterPipeline* p,
SkArenaAlloc* alloc,
SkColorSpace* src,
SkColorSpace* dst,
SkAlphaType srcAT) {
if (src == dst || !dst || !src) {
return;
}
const SkMatrix44 *fromSrc = src-> toXYZD50(),
*toDst = dst->fromXYZD50();
if (!fromSrc || !toDst) {
SkDEBUGFAIL("We can't handle non-XYZ color spaces in append_gamut_transform().");
return;
}
// Slightly more sophisticated version of if (src == dst)
if (src->toXYZD50Hash() == dst->toXYZD50Hash()) {
return;
}
// Convert from 4x4 to (column-major) 3x4.
SkMatrix44 m44(*toDst, *fromSrc);
float* ptr = alloc->makeArrayDefault<float>(12);
*ptr++ = m44.get(0,0); *ptr++ = m44.get(1,0); *ptr++ = m44.get(2,0);
*ptr++ = m44.get(0,1); *ptr++ = m44.get(1,1); *ptr++ = m44.get(2,1);
*ptr++ = m44.get(0,2); *ptr++ = m44.get(1,2); *ptr++ = m44.get(2,2);
*ptr++ = m44.get(0,3); *ptr++ = m44.get(1,3); *ptr++ = m44.get(2,3);
p->append(SkRasterPipeline::matrix_3x4, ptr-12);
}
#endif