diff options
author | Romain Guy <romainguy@google.com> | 2016-12-12 18:21:32 -0800 |
---|---|---|
committer | Romain Guy <romainguy@google.com> | 2016-12-12 18:50:07 -0800 |
commit | a0ed6f03f6f06eb41cbcc15c0a99b4a78fd91bef (patch) | |
tree | f6eeb56420b457fe9955f21548ca12e6cf7ec68e /libs/hwui/GradientCache.cpp | |
parent | 84cac20dfdff35932901e978e6b6d3da843a2fa7 (diff) |
Pre-multiply gradient colors the right way
Alpha pre-multiplication must be done after applying the
opto-electronic transfer function when linear blending is
disabled. The correct way would be to pre-multiply before
gamma encoding but this leads to improper blending which
cannot be corrected without using sRGB frame buffers and
texture sampling.
Bug: 33010587
Test: cts-tradefed run singleCommand cts-dev --module CtsUiRenderingTestCases --test android.uirendering.cts.testclasses.GradientTests
Change-Id: I5f04bda4cb9f63674537aef5931621c14d601884
Diffstat (limited to 'libs/hwui/GradientCache.cpp')
-rw-r--r-- | libs/hwui/GradientCache.cpp | 37 |
1 files changed, 21 insertions, 16 deletions
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp index 0972ac1cafc2..1dad58fd64b9 100644 --- a/libs/hwui/GradientCache.cpp +++ b/libs/hwui/GradientCache.cpp @@ -188,26 +188,28 @@ size_t GradientCache::sourceBytesPerPixel() const { void GradientCache::mixBytes(const FloatColor& start, const FloatColor& end, float amount, uint8_t*& dst) const { float oppAmount = 1.0f - amount; - *dst++ = uint8_t(OECF_sRGB(start.r * oppAmount + end.r * amount) * 255.0f); - *dst++ = uint8_t(OECF_sRGB(start.g * oppAmount + end.g * amount) * 255.0f); - *dst++ = uint8_t(OECF_sRGB(start.b * oppAmount + end.b * amount) * 255.0f); - *dst++ = uint8_t( (start.a * oppAmount + end.a * amount) * 255.0f); + float a = start.a * oppAmount + end.a * amount; + *dst++ = uint8_t(a * OECF_sRGB((start.r * oppAmount + end.r * amount)) * 255.0f); + *dst++ = uint8_t(a * OECF_sRGB((start.g * oppAmount + end.g * amount)) * 255.0f); + *dst++ = uint8_t(a * OECF_sRGB((start.b * oppAmount + end.b * amount)) * 255.0f); + *dst++ = uint8_t(a * 255.0f); } void GradientCache::mixFloats(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; float* d = (float*) dst; #ifdef ANDROID_ENABLE_LINEAR_BLENDING - *d++ = start.r * oppAmount + end.r * amount; - *d++ = start.g * oppAmount + end.g * amount; - *d++ = start.b * oppAmount + end.b * amount; + *d++ = a * (start.r * oppAmount + end.r * amount); + *d++ = a * (start.g * oppAmount + end.g * amount); + *d++ = a * (start.b * oppAmount + end.b * amount); #else - *d++ = OECF_sRGB(start.r * oppAmount + end.r * amount); - *d++ = OECF_sRGB(start.g * oppAmount + end.g * amount); - *d++ = OECF_sRGB(start.b * oppAmount + end.b * amount); + *d++ = a * OECF_sRGB(start.r * oppAmount + end.r * amount); + *d++ = a * OECF_sRGB(start.g * oppAmount + end.g * amount); + *d++ = a * OECF_sRGB(start.b * oppAmount + end.b * amount); #endif - *d++ = start.a * oppAmount + end.a * amount; + *d++ = a; dst += 4 * sizeof(float); } @@ -217,16 +219,19 @@ void GradientCache::generateTexture(uint32_t* colors, float* positions, uint8_t pixels[rowBytes * height]; static ChannelMixer gMixers[] = { - &android::uirenderer::GradientCache::mixBytes, // colors are stored gamma-encoded - &android::uirenderer::GradientCache::mixFloats, // colors are stored in linear + // colors are stored gamma-encoded + &android::uirenderer::GradientCache::mixBytes, + // colors are stored in linear (linear blending on) + // or gamma-encoded (linear blending off) + &android::uirenderer::GradientCache::mixFloats, }; ChannelMixer mix = gMixers[mUseFloatTexture]; FloatColor start; - start.setSRGB(colors[0]); + start.setUnPreMultipliedSRGB(colors[0]); FloatColor end; - end.setSRGB(colors[1]); + end.setUnPreMultipliedSRGB(colors[1]); int currentPos = 1; float startPos = positions[0]; @@ -241,7 +246,7 @@ void GradientCache::generateTexture(uint32_t* colors, float* positions, currentPos++; - end.setSRGB(colors[currentPos]); + end.setUnPreMultipliedSRGB(colors[currentPos]); distance = positions[currentPos] - startPos; } |