PM/UPM conversion improvements

Snap input values to N / 255 before doing PM/UPM conversions, and add
a new round-to-nearest conversion pair. With the pre-snapping, that
pair is chosen by (almost?) every GPU we have. This now lets us round
trip perfectly on Mali GPUs (which were falling back to SW before).

Bug: skia:
Change-Id: I0cebf1382e1c829aedfef4ec1614d7fa980057b5
Reviewed-on: https://skia-review.googlesource.com/11520
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
This commit is contained in:
Brian Osman 2017-04-10 13:42:48 -04:00 committed by Skia Commit-Bot
parent 95ddf137b2
commit 9f903e4a58
2 changed files with 35 additions and 8 deletions

View File

@ -27,7 +27,11 @@ public:
// could optimize this case, but we aren't for now.
args.fInputColor = "vec4(1)";
}
fragBuilder->codeAppendf("vec4 color = %s;", args.fInputColor);
// Aggressively round to the nearest exact (N / 255) floating point value. This lets us
// find a round-trip preserving pair on some GPUs that do odd byte to float conversion.
fragBuilder->codeAppendf("vec4 color = floor(%s * 255.0 + 0.5) / 255.0;",
args.fInputColor);
switch (cce.pmConversion()) {
case GrConfigConversionEffect::kMulByAlpha_RoundUp_PMConversion:
@ -42,6 +46,11 @@ public:
fragBuilder->codeAppend(
"color.rgb = floor(color.rgb * color.a * 255.0 + 0.001) / 255.0;");
break;
case GrConfigConversionEffect::kMulByAlpha_RoundNearest_PMConversion:
fragBuilder->codeAppend(
"color.rgb = floor(color.rgb * color.a * 255.0 + 0.5) / 255.0;");
break;
case GrConfigConversionEffect::kDivByAlpha_RoundUp_PMConversion:
fragBuilder->codeAppend(
"color.rgb = color.a <= 0.0 ? vec3(0,0,0) : ceil(color.rgb / color.a * 255.0) / 255.0;");
@ -50,6 +59,11 @@ public:
fragBuilder->codeAppend(
"color.rgb = color.a <= 0.0 ? vec3(0,0,0) : floor(color.rgb / color.a * 255.0) / 255.0;");
break;
case GrConfigConversionEffect::kDivByAlpha_RoundNearest_PMConversion:
fragBuilder->codeAppend(
"color.rgb = color.a <= 0.0 ? vec3(0,0,0) : floor(color.rgb / color.a * 255.0 + 0.5) / 255.0;");
break;
default:
SkFAIL("Unknown conversion op.");
break;
@ -155,13 +169,15 @@ void GrConfigConversionEffect::TestForPreservingPMConversions(GrContext* context
}
static const PMConversion kConversionRules[][2] = {
{kDivByAlpha_RoundNearest_PMConversion, kMulByAlpha_RoundNearest_PMConversion},
{kDivByAlpha_RoundDown_PMConversion, kMulByAlpha_RoundUp_PMConversion},
{kDivByAlpha_RoundUp_PMConversion, kMulByAlpha_RoundDown_PMConversion},
};
bool failed = true;
uint32_t bestFailCount = 0xFFFFFFFF;
size_t bestRule = 0;
for (size_t i = 0; i < SK_ARRAY_COUNT(kConversionRules) && failed; ++i) {
for (size_t i = 0; i < SK_ARRAY_COUNT(kConversionRules) && bestFailCount; ++i) {
*pmToUPMRule = kConversionRules[i][0];
*upmToPMRule = kConversionRules[i][1];
@ -211,19 +227,27 @@ void GrConfigConversionEffect::TestForPreservingPMConversions(GrContext* context
continue;
}
failed = false;
for (int y = 0; y < kSize && !failed; ++y) {
uint32_t failCount = 0;
for (int y = 0; y < kSize; ++y) {
for (int x = 0; x <= y; ++x) {
if (firstRead[kSize * y + x] != secondRead[kSize * y + x]) {
failed = true;
break;
if (++failCount >= bestFailCount) {
break;
}
}
}
}
if (failCount < bestFailCount) {
bestFailCount = failCount;
bestRule = i;
}
}
if (failed) {
if (bestFailCount > 0) {
*pmToUPMRule = kPMConversionCnt;
*upmToPMRule = kPMConversionCnt;
} else {
*pmToUPMRule = kConversionRules[bestRule][0];
*upmToPMRule = kConversionRules[bestRule][1];
}
}

View File

@ -22,8 +22,11 @@ public:
enum PMConversion {
kMulByAlpha_RoundUp_PMConversion = 0,
kMulByAlpha_RoundDown_PMConversion,
kMulByAlpha_RoundNearest_PMConversion,
kDivByAlpha_RoundUp_PMConversion,
kDivByAlpha_RoundDown_PMConversion,
kDivByAlpha_RoundNearest_PMConversion,
kPMConversionCnt
};