summaryrefslogtreecommitdiff
path: root/libs/hwui/GradientCache.cpp
diff options
context:
space:
mode:
authorRomain Guy <romainguy@google.com>2016-12-12 18:21:32 -0800
committerRomain Guy <romainguy@google.com>2016-12-12 18:50:07 -0800
commita0ed6f03f6f06eb41cbcc15c0a99b4a78fd91bef (patch)
treef6eeb56420b457fe9955f21548ca12e6cf7ec68e /libs/hwui/GradientCache.cpp
parent84cac20dfdff35932901e978e6b6d3da843a2fa7 (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.cpp37
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;
}