From 669b15a93548b82135c73196665bcb7f03d87795 Mon Sep 17 00:00:00 2001 From: Derek Sollenberger Date: Fri, 31 Mar 2017 12:09:24 -0400 Subject: Fix HWUI/Skia Gradients to premultiply the colors prior to interpolation This is fixed in Skia by passing the appropriate flag when the shader is generated. The fix in HWUI is to reverse the premultiplication and interpolation steps. Test: bit CtsUiRenderingTestCases:.testclasses.ShaderTests Bug: 34323783 Change-Id: I3417141949f62fcc696b6d8213a4b446d7d0cbf8 --- core/jni/android/graphics/Shader.cpp | 22 +++++++++++++++------- libs/hwui/GradientCache.cpp | 24 ++++++++++++------------ libs/hwui/ProgramCache.cpp | 14 +++----------- libs/hwui/SkiaShader.cpp | 4 ++-- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp index a77ed626d0e8..1a353302d7d8 100644 --- a/core/jni/android/graphics/Shader.cpp +++ b/core/jni/android/graphics/Shader.cpp @@ -10,6 +10,14 @@ using namespace android::uirenderer; +/** + * By default Skia gradients will interpolate their colors in unpremul space + * and then premultiply each of the results. We must set this flag to preserve + * backwards compatiblity by premultiplying the colors of the gradient first, + * and then interpolating between them. + */ +static const uint32_t sGradientShaderFlags = SkGradientShader::kInterpolateColorsInPremul_Flag; + static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) { if (NULL == ptr) { doThrowIAE(env); @@ -89,7 +97,7 @@ static jlong LinearGradient_create1(JNIEnv* env, jobject o, jlong matrixPtr, SkShader* shader = SkGradientShader::MakeLinear(pts, reinterpret_cast(colorValues), pos, count, - static_cast(tileMode), /* flags */ 0, matrix).release(); + static_cast(tileMode), sGradientShaderFlags, matrix).release(); env->ReleaseIntArrayElements(colorArray, const_cast(colorValues), JNI_ABORT); ThrowIAE_IfNull(env, shader); @@ -109,7 +117,7 @@ static jlong LinearGradient_create2(JNIEnv* env, jobject o, jlong matrixPtr, colors[1] = color1; SkShader* s = SkGradientShader::MakeLinear(pts, colors, NULL, 2, - (SkShader::TileMode)tileMode, /* flags */ 0, matrix).release(); + static_cast(tileMode), sGradientShaderFlags, matrix).release(); ThrowIAE_IfNull(env, s); return reinterpret_cast(s); @@ -135,7 +143,7 @@ static jlong RadialGradient_create1(JNIEnv* env, jobject, jlong matrixPtr, jfloa SkShader* shader = SkGradientShader::MakeRadial(center, radius, reinterpret_cast(colorValues), pos, count, - static_cast(tileMode), /* flags */ 0, matrix).release(); + static_cast(tileMode), sGradientShaderFlags, matrix).release(); env->ReleaseIntArrayElements(colorArray, const_cast(colorValues), JNI_ABORT); @@ -154,7 +162,7 @@ static jlong RadialGradient_create2(JNIEnv* env, jobject, jlong matrixPtr, jfloa colors[1] = color1; SkShader* s = SkGradientShader::MakeRadial(center, radius, colors, NULL, 2, - (SkShader::TileMode)tileMode, /* flags */ 0, matrix).release(); + static_cast(tileMode), sGradientShaderFlags, matrix).release(); ThrowIAE_IfNull(env, s); return reinterpret_cast(s); } @@ -174,8 +182,8 @@ static jlong SweepGradient_create1(JNIEnv* env, jobject, jlong matrixPtr, jfloat #error Need to convert float array to SkScalar array before calling the following function. #endif - SkShader* shader = SkGradientShader::MakeSweep(x, y, - reinterpret_cast(colors), pos, count, /* flags */ 0, matrix).release(); + SkShader* shader = SkGradientShader::MakeSweep(x, y, reinterpret_cast(colors), + pos, count, sGradientShaderFlags, matrix).release(); env->ReleaseIntArrayElements(jcolors, const_cast(colors), JNI_ABORT); ThrowIAE_IfNull(env, shader); @@ -189,7 +197,7 @@ static jlong SweepGradient_create2(JNIEnv* env, jobject, jlong matrixPtr, jfloat colors[0] = color0; colors[1] = color1; SkShader* s = SkGradientShader::MakeSweep(x, y, colors, NULL, 2, - /* flags */ 0, matrix).release(); + sGradientShaderFlags, matrix).release(); ThrowIAE_IfNull(env, s); return reinterpret_cast(s); } diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp index dceb28518db3..d4d0c997be11 100644 --- a/libs/hwui/GradientCache.cpp +++ b/libs/hwui/GradientCache.cpp @@ -189,9 +189,9 @@ void GradientCache::mixBytes(const FloatColor& start, const FloatColor& end, float amount, uint8_t*& dst) const { float oppAmount = 1.0f - amount; float a = start.a * oppAmount + end.a * amount; - *dst++ = uint8_t(a * OECF(start.r * oppAmount + end.r * amount) * 255.0f); - *dst++ = uint8_t(a * OECF(start.g * oppAmount + end.g * amount) * 255.0f); - *dst++ = uint8_t(a * OECF(start.b * oppAmount + end.b * amount) * 255.0f); + *dst++ = uint8_t(OECF(start.r * oppAmount + end.r * amount) * 255.0f); + *dst++ = uint8_t(OECF(start.g * oppAmount + end.g * amount) * 255.0f); + *dst++ = uint8_t(OECF(start.b * oppAmount + end.b * amount) * 255.0f); *dst++ = uint8_t(a * 255.0f); } @@ -202,13 +202,13 @@ void GradientCache::mixFloats(const FloatColor& start, const FloatColor& end, float* d = (float*) dst; #ifdef ANDROID_ENABLE_LINEAR_BLENDING // We want to stay linear - *d++ = a * (start.r * oppAmount + end.r * amount); - *d++ = a * (start.g * oppAmount + end.g * amount); - *d++ = a * (start.b * oppAmount + end.b * amount); + *d++ = (start.r * oppAmount + end.r * amount); + *d++ = (start.g * oppAmount + end.g * amount); + *d++ = (start.b * oppAmount + end.b * amount); #else - *d++ = a * OECF(start.r * oppAmount + end.r * amount); - *d++ = a * OECF(start.g * oppAmount + end.g * amount); - *d++ = a * OECF(start.b * oppAmount + end.b * amount); + *d++ = OECF(start.r * oppAmount + end.r * amount); + *d++ = OECF(start.g * oppAmount + end.g * amount); + *d++ = OECF(start.b * oppAmount + end.b * amount); #endif *d++ = a; dst += 4 * sizeof(float); @@ -229,10 +229,10 @@ void GradientCache::generateTexture(uint32_t* colors, float* positions, ChannelMixer mix = gMixers[mUseFloatTexture]; FloatColor start; - start.setUnPreMultiplied(colors[0]); + start.set(colors[0]); FloatColor end; - end.setUnPreMultiplied(colors[1]); + end.set(colors[1]); int currentPos = 1; float startPos = positions[0]; @@ -247,7 +247,7 @@ void GradientCache::generateTexture(uint32_t* colors, float* positions, currentPos++; - end.setUnPreMultiplied(colors[currentPos]); + end.set(colors[currentPos]); distance = positions[currentPos] - startPos; } diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp index 1f78e09b5a58..d0f0949d5e78 100644 --- a/libs/hwui/ProgramCache.cpp +++ b/libs/hwui/ProgramCache.cpp @@ -295,10 +295,6 @@ const char* gFS_GradientPreamble[2] = { vec4 dither(const vec4 color) { return color + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0); } - vec4 gradientMix(const vec4 a, const vec4 b, float v) { - vec4 c = mix(a, b, v); - return vec4(c.rgb * c.a, c.a); - } )__SHADER__", // sRGB framebuffer R"__SHADER__( @@ -306,10 +302,6 @@ const char* gFS_GradientPreamble[2] = { vec3 dithered = sqrt(color.rgb) + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0); return vec4(dithered * dithered, color.a); } - vec4 gradientMixMix(const vec4 a, const vec4 b, float v) { - vec4 c = mix(a, b, v); - return vec4(c.rgb * c.a, c.a); - } )__SHADER__", }; @@ -364,19 +356,19 @@ const char* gFS_Main_FetchGradient[6] = { // Linear " vec4 gradientColor = texture2D(gradientSampler, linear);\n", - " vec4 gradientColor = gradientMix(startColor, endColor, clamp(linear, 0.0, 1.0));\n", + " vec4 gradientColor = mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n", // Circular " vec4 gradientColor = texture2D(gradientSampler, vec2(length(circular), 0.5));\n", - " vec4 gradientColor = gradientMix(startColor, endColor, clamp(length(circular), 0.0, 1.0));\n", + " vec4 gradientColor = mix(startColor, endColor, clamp(length(circular), 0.0, 1.0));\n", // Sweep " highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n" " vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n", " highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n" - " vec4 gradientColor = gradientMix(startColor, endColor, clamp(index - floor(index), 0.0, 1.0));\n" + " vec4 gradientColor = mix(startColor, endColor, clamp(index - floor(index), 0.0, 1.0));\n" }; const char* gFS_Main_FetchBitmap = " vec4 bitmapColor = colorConvert(texture2D(bitmapSampler, outBitmapTexCoords));\n"; diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp index 8a504d4431c4..5c5378bf22ad 100644 --- a/libs/hwui/SkiaShader.cpp +++ b/libs/hwui/SkiaShader.cpp @@ -173,8 +173,8 @@ bool tryStoreGradient(Caches& caches, const SkShader& shader, const Matrix4 mode outData->gradientSampler = 0; outData->gradientTexture = nullptr; - outData->startColor.setUnPreMultiplied(gradInfo.fColors[0]); - outData->endColor.setUnPreMultiplied(gradInfo.fColors[1]); + outData->startColor.set(gradInfo.fColors[0]); + outData->endColor.set(gradInfo.fColors[1]); } return true; -- cgit v1.2.3-59-g8ed1b