Loading libs/hwui/GradientCache.cpp +4 −0 Original line number Diff line number Diff line Loading @@ -205,6 +205,10 @@ void GradientCache::mixFloats(const FloatColor& start, const FloatColor& end, *d++ = a * (start.g * oppAmount + end.g * amount); *d++ = a * (start.b * oppAmount + end.b * amount); #else // What we're doing to the alpha channel here is technically incorrect // but reproduces Android's old behavior when the alpha was pre-multiplied // with gamma-encoded colors a = EOCF_sRGB(a); *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); Loading libs/hwui/ProgramCache.cpp +34 −17 Original line number Diff line number Diff line Loading @@ -164,24 +164,39 @@ const char* gFS_Uniforms_HasRoundRectClip = // Dithering must be done in the quantization space // When we are writing to an sRGB framebuffer, we must do the following: // EOCF(OECF(color) + dither) // We approximate the transfer functions with gamma 2.0 to avoid branches and pow() // The dithering pattern is generated with a triangle noise generator in the range [-0.0,1.0] // TODO: Handle linear fp16 render targets const char* gFS_Gradient_Functions = "\nfloat triangleNoise(const highp vec2 n) {\n" " highp vec2 p = fract(n * vec2(5.3987, 5.4421));\n" " p += dot(p.yx, p.xy + vec2(21.5351, 14.3137));\n" " highp float xy = p.x * p.y;\n" " return fract(xy * 95.4307) + fract(xy * 75.04961) - 1.0;\n" "}\n"; const char* gFS_Gradient_Functions = R"__SHADER__( float triangleNoise(const highp vec2 n) { highp vec2 p = fract(n * vec2(5.3987, 5.4421)); p += dot(p.yx, p.xy + vec2(21.5351, 14.3137)); highp float xy = p.x * p.y; return fract(xy * 95.4307) + fract(xy * 75.04961) - 1.0; } float OECF_sRGB(const float linear) { // IEC 61966-2-1:1999 return linear <= 0.0031308 ? linear * 12.92 : (pow(linear, 1.0 / 2.4) * 1.055) - 0.055; } vec3 OECF_sRGB(const vec3 linear) { return vec3(OECF_sRGB(linear.r), OECF_sRGB(linear.g), OECF_sRGB(linear.b)); } float EOCF_sRGB(float srgb) { // IEC 61966-2-1:1999 return srgb <= 0.04045 ? srgb / 12.92 : pow((srgb + 0.055) / 1.055, 2.4); } )__SHADER__"; const char* gFS_Gradient_Preamble[2] = { // Linear framebuffer "\nvec4 dither(const vec4 color) {\n" " return vec4(color.rgb + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0), color.a);\n" "}\n" "\nvec4 gammaMix(const vec4 a, const vec4 b, float v) {\n" " vec4 c = pow(mix(a, b, v), vec4(vec3(1.0 / 2.2), 1.0));\n" " return vec4(c.rgb * c.a, c.a);\n" " vec4 c = mix(a, b, v);\n" " c.a = EOCF_sRGB(c.a);\n" // This is technically incorrect but preserves compatibility " return vec4(OECF_sRGB(c.rgb) * c.a, c.a);\n" "}\n", // sRGB framebuffer "\nvec4 dither(const vec4 color) {\n" Loading @@ -200,13 +215,15 @@ const char* gFS_Gradient_Preamble[2] = { // The gamma coefficient is chosen to thicken or thin the text accordingly // The dot product used to compute the luminance could be approximated with // a simple max(color.r, color.g, color.b) const char* gFS_Gamma_Preamble = "\n#define GAMMA (%.2f)\n" "#define GAMMA_INV (%.2f)\n" "\nfloat gamma(float a, const vec3 color) {\n" " float luminance = dot(color, vec3(0.2126, 0.7152, 0.0722));\n" " return pow(a, luminance < 0.5 ? GAMMA_INV : GAMMA);\n" "}\n"; const char* gFS_Gamma_Preamble = R"__SHADER__( #define GAMMA (%.2f) #define GAMMA_INV (%.2f) float gamma(float a, const vec3 color) { float luminance = dot(color, vec3(0.2126, 0.7152, 0.0722)); return pow(a, luminance < 0.5 ? GAMMA_INV : GAMMA); } )__SHADER__"; const char* gFS_Main = "\nvoid main(void) {\n" Loading libs/hwui/Texture.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -44,7 +44,7 @@ static int bytesPerPixel(GLint glFormat) { case GL_RGBA16F: return 8; default: LOG_ALWAYS_FATAL("UNKNOWN FORMAT %d", glFormat); LOG_ALWAYS_FATAL("UNKNOWN FORMAT 0x%x", glFormat); } } Loading Loading
libs/hwui/GradientCache.cpp +4 −0 Original line number Diff line number Diff line Loading @@ -205,6 +205,10 @@ void GradientCache::mixFloats(const FloatColor& start, const FloatColor& end, *d++ = a * (start.g * oppAmount + end.g * amount); *d++ = a * (start.b * oppAmount + end.b * amount); #else // What we're doing to the alpha channel here is technically incorrect // but reproduces Android's old behavior when the alpha was pre-multiplied // with gamma-encoded colors a = EOCF_sRGB(a); *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); Loading
libs/hwui/ProgramCache.cpp +34 −17 Original line number Diff line number Diff line Loading @@ -164,24 +164,39 @@ const char* gFS_Uniforms_HasRoundRectClip = // Dithering must be done in the quantization space // When we are writing to an sRGB framebuffer, we must do the following: // EOCF(OECF(color) + dither) // We approximate the transfer functions with gamma 2.0 to avoid branches and pow() // The dithering pattern is generated with a triangle noise generator in the range [-0.0,1.0] // TODO: Handle linear fp16 render targets const char* gFS_Gradient_Functions = "\nfloat triangleNoise(const highp vec2 n) {\n" " highp vec2 p = fract(n * vec2(5.3987, 5.4421));\n" " p += dot(p.yx, p.xy + vec2(21.5351, 14.3137));\n" " highp float xy = p.x * p.y;\n" " return fract(xy * 95.4307) + fract(xy * 75.04961) - 1.0;\n" "}\n"; const char* gFS_Gradient_Functions = R"__SHADER__( float triangleNoise(const highp vec2 n) { highp vec2 p = fract(n * vec2(5.3987, 5.4421)); p += dot(p.yx, p.xy + vec2(21.5351, 14.3137)); highp float xy = p.x * p.y; return fract(xy * 95.4307) + fract(xy * 75.04961) - 1.0; } float OECF_sRGB(const float linear) { // IEC 61966-2-1:1999 return linear <= 0.0031308 ? linear * 12.92 : (pow(linear, 1.0 / 2.4) * 1.055) - 0.055; } vec3 OECF_sRGB(const vec3 linear) { return vec3(OECF_sRGB(linear.r), OECF_sRGB(linear.g), OECF_sRGB(linear.b)); } float EOCF_sRGB(float srgb) { // IEC 61966-2-1:1999 return srgb <= 0.04045 ? srgb / 12.92 : pow((srgb + 0.055) / 1.055, 2.4); } )__SHADER__"; const char* gFS_Gradient_Preamble[2] = { // Linear framebuffer "\nvec4 dither(const vec4 color) {\n" " return vec4(color.rgb + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0), color.a);\n" "}\n" "\nvec4 gammaMix(const vec4 a, const vec4 b, float v) {\n" " vec4 c = pow(mix(a, b, v), vec4(vec3(1.0 / 2.2), 1.0));\n" " return vec4(c.rgb * c.a, c.a);\n" " vec4 c = mix(a, b, v);\n" " c.a = EOCF_sRGB(c.a);\n" // This is technically incorrect but preserves compatibility " return vec4(OECF_sRGB(c.rgb) * c.a, c.a);\n" "}\n", // sRGB framebuffer "\nvec4 dither(const vec4 color) {\n" Loading @@ -200,13 +215,15 @@ const char* gFS_Gradient_Preamble[2] = { // The gamma coefficient is chosen to thicken or thin the text accordingly // The dot product used to compute the luminance could be approximated with // a simple max(color.r, color.g, color.b) const char* gFS_Gamma_Preamble = "\n#define GAMMA (%.2f)\n" "#define GAMMA_INV (%.2f)\n" "\nfloat gamma(float a, const vec3 color) {\n" " float luminance = dot(color, vec3(0.2126, 0.7152, 0.0722));\n" " return pow(a, luminance < 0.5 ? GAMMA_INV : GAMMA);\n" "}\n"; const char* gFS_Gamma_Preamble = R"__SHADER__( #define GAMMA (%.2f) #define GAMMA_INV (%.2f) float gamma(float a, const vec3 color) { float luminance = dot(color, vec3(0.2126, 0.7152, 0.0722)); return pow(a, luminance < 0.5 ? GAMMA_INV : GAMMA); } )__SHADER__"; const char* gFS_Main = "\nvoid main(void) {\n" Loading
libs/hwui/Texture.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -44,7 +44,7 @@ static int bytesPerPixel(GLint glFormat) { case GL_RGBA16F: return 8; default: LOG_ALWAYS_FATAL("UNKNOWN FORMAT %d", glFormat); LOG_ALWAYS_FATAL("UNKNOWN FORMAT 0x%x", glFormat); } } Loading