1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "Color.h"
18 
19 #include <utils/Log.h>
20 #include <ui/ColorSpace.h>
21 
22 #ifdef __ANDROID__ // Layoutlib does not support hardware buffers or native windows
23 #include <android/hardware_buffer.h>
24 #include <android/native_window.h>
25 #endif
26 
27 #include <algorithm>
28 #include <cmath>
29 
30 namespace android {
31 namespace uirenderer {
32 
33 #ifdef __ANDROID__ // Layoutlib does not support hardware buffers or native windows
createImageInfo(int32_t width,int32_t height,int32_t format,sk_sp<SkColorSpace> colorSpace)34 static inline SkImageInfo createImageInfo(int32_t width, int32_t height, int32_t format,
35                                           sk_sp<SkColorSpace> colorSpace) {
36     SkColorType colorType = kUnknown_SkColorType;
37     SkAlphaType alphaType = kOpaque_SkAlphaType;
38     switch (format) {
39         case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
40             colorType = kN32_SkColorType;
41             alphaType = kPremul_SkAlphaType;
42             break;
43         case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
44             colorType = kN32_SkColorType;
45             alphaType = kOpaque_SkAlphaType;
46             break;
47         case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
48             colorType = kRGB_565_SkColorType;
49             alphaType = kOpaque_SkAlphaType;
50             break;
51         case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
52             colorType = kRGBA_1010102_SkColorType;
53             alphaType = kPremul_SkAlphaType;
54             break;
55         case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
56             colorType = kRGBA_F16_SkColorType;
57             alphaType = kPremul_SkAlphaType;
58             break;
59         default:
60             ALOGV("Unsupported format: %d, return unknown by default", format);
61             break;
62     }
63     return SkImageInfo::Make(width, height, colorType, alphaType, colorSpace);
64 }
65 
ANativeWindowToImageInfo(const ANativeWindow_Buffer & buffer,sk_sp<SkColorSpace> colorSpace)66 SkImageInfo ANativeWindowToImageInfo(const ANativeWindow_Buffer& buffer,
67                                      sk_sp<SkColorSpace> colorSpace) {
68     return createImageInfo(buffer.width, buffer.height, buffer.format, colorSpace);
69 }
70 
BufferDescriptionToImageInfo(const AHardwareBuffer_Desc & bufferDesc,sk_sp<SkColorSpace> colorSpace)71 SkImageInfo BufferDescriptionToImageInfo(const AHardwareBuffer_Desc& bufferDesc,
72                                          sk_sp<SkColorSpace> colorSpace) {
73     return createImageInfo(bufferDesc.width, bufferDesc.height, bufferDesc.format, colorSpace);
74 }
75 #endif
76 
ColorTypeToPixelFormat(SkColorType colorType)77 android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType) {
78     switch (colorType) {
79         case kRGBA_8888_SkColorType:
80             return PIXEL_FORMAT_RGBA_8888;
81         case kRGBA_F16_SkColorType:
82             return PIXEL_FORMAT_RGBA_FP16;
83         case kRGB_565_SkColorType:
84             return PIXEL_FORMAT_RGB_565;
85         case kRGB_888x_SkColorType:
86             return PIXEL_FORMAT_RGBX_8888;
87         case kRGBA_1010102_SkColorType:
88             return PIXEL_FORMAT_RGBA_1010102;
89         case kARGB_4444_SkColorType:
90             return PIXEL_FORMAT_RGBA_4444;
91         default:
92             ALOGV("Unsupported colorType: %d, return RGBA_8888 by default", (int)colorType);
93             return PIXEL_FORMAT_RGBA_8888;
94     }
95 }
96 
PixelFormatToColorType(android::PixelFormat format)97 SkColorType PixelFormatToColorType(android::PixelFormat format) {
98     switch (format) {
99         case PIXEL_FORMAT_RGBX_8888:    return kRGB_888x_SkColorType;
100         case PIXEL_FORMAT_RGBA_8888:    return kRGBA_8888_SkColorType;
101         case PIXEL_FORMAT_RGBA_FP16:    return kRGBA_F16_SkColorType;
102         case PIXEL_FORMAT_RGB_565:      return kRGB_565_SkColorType;
103         case PIXEL_FORMAT_RGBA_1010102: return kRGBA_1010102_SkColorType;
104         case PIXEL_FORMAT_RGBA_4444:    return kARGB_4444_SkColorType;
105         default:
106             ALOGV("Unsupported PixelFormat: %d, return kUnknown_SkColorType by default", format);
107             return kUnknown_SkColorType;
108     }
109 }
110 
111 namespace {
112 static constexpr skcms_TransferFunction k2Dot6 = {2.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
113 
114 // Skia's SkNamedGamut::kDCIP3 is based on a white point of D65. This gamut
115 // matches the white point used by ColorSpace.Named.DCIP3.
116 static constexpr skcms_Matrix3x3 kDCIP3 = {{
117         {0.486143, 0.323835, 0.154234},
118         {0.226676, 0.710327, 0.0629966},
119         {0.000800549, 0.0432385, 0.78275},
120 }};
121 
nearlyEqual(float a,float b)122 static bool nearlyEqual(float a, float b) {
123     // By trial and error, this is close enough to match for the ADataSpaces we
124     // compare for.
125     return ::fabs(a - b) < .002f;
126 }
127 
nearlyEqual(const skcms_TransferFunction & x,const skcms_TransferFunction & y)128 static bool nearlyEqual(const skcms_TransferFunction& x, const skcms_TransferFunction& y) {
129     return nearlyEqual(x.g, y.g)
130         && nearlyEqual(x.a, y.a)
131         && nearlyEqual(x.b, y.b)
132         && nearlyEqual(x.c, y.c)
133         && nearlyEqual(x.d, y.d)
134         && nearlyEqual(x.e, y.e)
135         && nearlyEqual(x.f, y.f);
136 }
137 
nearlyEqual(const skcms_Matrix3x3 & x,const skcms_Matrix3x3 & y)138 static bool nearlyEqual(const skcms_Matrix3x3& x, const skcms_Matrix3x3& y) {
139     for (int i = 0; i < 3; i++) {
140         for (int j = 0; j < 3; j++) {
141             if (!nearlyEqual(x.vals[i][j], y.vals[i][j])) return false;
142         }
143     }
144     return true;
145 }
146 
147 } // anonymous namespace
148 
ColorSpaceToADataSpace(SkColorSpace * colorSpace,SkColorType colorType)149 android_dataspace ColorSpaceToADataSpace(SkColorSpace* colorSpace, SkColorType colorType) {
150     if (!colorSpace) {
151         return HAL_DATASPACE_UNKNOWN;
152     }
153 
154     if (colorSpace->isSRGB()) {
155         if (colorType == kRGBA_F16_SkColorType) {
156             return HAL_DATASPACE_V0_SCRGB;
157         }
158         return HAL_DATASPACE_V0_SRGB;
159     }
160 
161     skcms_TransferFunction fn;
162     LOG_ALWAYS_FATAL_IF(!colorSpace->isNumericalTransferFn(&fn));
163 
164     skcms_Matrix3x3 gamut;
165     LOG_ALWAYS_FATAL_IF(!colorSpace->toXYZD50(&gamut));
166 
167     if (nearlyEqual(gamut, SkNamedGamut::kSRGB)) {
168         if (nearlyEqual(fn, SkNamedTransferFn::kLinear)) {
169             // Skia doesn't differentiate amongst the RANGES. In Java, we associate
170             // LINEAR_EXTENDED_SRGB with F16, and LINEAR_SRGB with other Configs.
171             // Make the same association here.
172             if (colorType == kRGBA_F16_SkColorType) {
173                 return HAL_DATASPACE_V0_SCRGB_LINEAR;
174             }
175             return HAL_DATASPACE_V0_SRGB_LINEAR;
176         }
177 
178         if (nearlyEqual(fn, SkNamedTransferFn::kRec2020)) {
179             return HAL_DATASPACE_V0_BT709;
180         }
181     }
182 
183     if (nearlyEqual(fn, SkNamedTransferFn::kSRGB) && nearlyEqual(gamut, SkNamedGamut::kDCIP3)) {
184         return HAL_DATASPACE_DISPLAY_P3;
185     }
186 
187     if (nearlyEqual(fn, SkNamedTransferFn::k2Dot2) && nearlyEqual(gamut, SkNamedGamut::kAdobeRGB)) {
188         return HAL_DATASPACE_ADOBE_RGB;
189     }
190 
191     if (nearlyEqual(fn, SkNamedTransferFn::kRec2020) &&
192         nearlyEqual(gamut, SkNamedGamut::kRec2020)) {
193         return HAL_DATASPACE_BT2020;
194     }
195 
196     if (nearlyEqual(fn, k2Dot6) && nearlyEqual(gamut, kDCIP3)) {
197         return HAL_DATASPACE_DCI_P3;
198     }
199 
200     return HAL_DATASPACE_UNKNOWN;
201 }
202 
DataSpaceToColorSpace(android_dataspace dataspace)203 sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace) {
204     if (dataspace == HAL_DATASPACE_UNKNOWN) {
205         return SkColorSpace::MakeSRGB();
206     }
207     if (dataspace == HAL_DATASPACE_DCI_P3) {
208         // This cannot be handled by the switch statements below because it
209         // needs to use the locally-defined kDCIP3 gamut, rather than the one in
210         // Skia (SkNamedGamut), which is used for other data spaces with
211         // HAL_DATASPACE_STANDARD_DCI_P3 (e.g. HAL_DATASPACE_DISPLAY_P3).
212         return SkColorSpace::MakeRGB(k2Dot6, kDCIP3);
213     }
214 
215     skcms_Matrix3x3 gamut;
216     switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
217         case HAL_DATASPACE_STANDARD_BT709:
218             gamut = SkNamedGamut::kSRGB;
219             break;
220         case HAL_DATASPACE_STANDARD_BT2020:
221             gamut = SkNamedGamut::kRec2020;
222             break;
223         case HAL_DATASPACE_STANDARD_DCI_P3:
224             gamut = SkNamedGamut::kDCIP3;
225             break;
226         case HAL_DATASPACE_STANDARD_ADOBE_RGB:
227             gamut = SkNamedGamut::kAdobeRGB;
228             break;
229         case HAL_DATASPACE_STANDARD_UNSPECIFIED:
230             return nullptr;
231         case HAL_DATASPACE_STANDARD_BT601_625:
232         case HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED:
233         case HAL_DATASPACE_STANDARD_BT601_525:
234         case HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED:
235         case HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE:
236         case HAL_DATASPACE_STANDARD_BT470M:
237         case HAL_DATASPACE_STANDARD_FILM:
238         default:
239             ALOGV("Unsupported Gamut: %d", dataspace);
240             return nullptr;
241     }
242 
243     switch (dataspace & HAL_DATASPACE_TRANSFER_MASK) {
244         case HAL_DATASPACE_TRANSFER_LINEAR:
245             return SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear, gamut);
246         case HAL_DATASPACE_TRANSFER_SRGB:
247             return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, gamut);
248         case HAL_DATASPACE_TRANSFER_GAMMA2_2:
249             return SkColorSpace::MakeRGB({2.2f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut);
250         case HAL_DATASPACE_TRANSFER_GAMMA2_6:
251             return SkColorSpace::MakeRGB(k2Dot6, gamut);
252         case HAL_DATASPACE_TRANSFER_GAMMA2_8:
253             return SkColorSpace::MakeRGB({2.8f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut);
254         case HAL_DATASPACE_TRANSFER_ST2084:
255             return SkColorSpace::MakeRGB(SkNamedTransferFn::kPQ, gamut);
256         case HAL_DATASPACE_TRANSFER_SMPTE_170M:
257             return SkColorSpace::MakeRGB(SkNamedTransferFn::kRec2020, gamut);
258         case HAL_DATASPACE_TRANSFER_UNSPECIFIED:
259             return nullptr;
260         case HAL_DATASPACE_TRANSFER_HLG:
261         default:
262             ALOGV("Unsupported Gamma: %d", dataspace);
263             return nullptr;
264     }
265 }
266 
267 template<typename T>
clamp(T x,T min,T max)268 static constexpr T clamp(T x, T min, T max) {
269     return x < min ? min : x > max ? max : x;
270 }
271 
272 //static const float2 ILLUMINANT_D50_XY = {0.34567f, 0.35850f};
273 static const float3 ILLUMINANT_D50_XYZ = {0.964212f, 1.0f, 0.825188f};
274 static const mat3 BRADFORD = mat3{
275         float3{ 0.8951f, -0.7502f,  0.0389f},
276         float3{ 0.2664f,  1.7135f, -0.0685f},
277         float3{-0.1614f,  0.0367f,  1.0296f}
278 };
279 
adaptation(const mat3 & matrix,const float3 & srcWhitePoint,const float3 & dstWhitePoint)280 static mat3 adaptation(const mat3& matrix, const float3& srcWhitePoint, const float3& dstWhitePoint) {
281     float3 srcLMS = matrix * srcWhitePoint;
282     float3 dstLMS = matrix * dstWhitePoint;
283     return inverse(matrix) * mat3{dstLMS / srcLMS} * matrix;
284 }
285 
286 namespace LabColorSpace {
287 
288 static constexpr float A = 216.0f / 24389.0f;
289 static constexpr float B = 841.0f / 108.0f;
290 static constexpr float C = 4.0f / 29.0f;
291 static constexpr float D = 6.0f / 29.0f;
292 
toXyz(const Lab & lab)293 float3 toXyz(const Lab& lab) {
294     float3 v { lab.L, lab.a, lab.b };
295     v[0] = clamp(v[0], 0.0f, 100.0f);
296     v[1] = clamp(v[1], -128.0f, 128.0f);
297     v[2] = clamp(v[2], -128.0f, 128.0f);
298 
299     float fy = (v[0] + 16.0f) / 116.0f;
300     float fx = fy + (v[1] * 0.002f);
301     float fz = fy - (v[2] * 0.005f);
302     float X = fx > D ? fx * fx * fx : (1.0f / B) * (fx - C);
303     float Y = fy > D ? fy * fy * fy : (1.0f / B) * (fy - C);
304     float Z = fz > D ? fz * fz * fz : (1.0f / B) * (fz - C);
305 
306     v[0] = X * ILLUMINANT_D50_XYZ[0];
307     v[1] = Y * ILLUMINANT_D50_XYZ[1];
308     v[2] = Z * ILLUMINANT_D50_XYZ[2];
309 
310     return v;
311 }
312 
fromXyz(const float3 & v)313 Lab fromXyz(const float3& v) {
314     float X = v[0] / ILLUMINANT_D50_XYZ[0];
315     float Y = v[1] / ILLUMINANT_D50_XYZ[1];
316     float Z = v[2] / ILLUMINANT_D50_XYZ[2];
317 
318     float fx = X > A ? pow(X, 1.0f / 3.0f) : B * X + C;
319     float fy = Y > A ? pow(Y, 1.0f / 3.0f) : B * Y + C;
320     float fz = Z > A ? pow(Z, 1.0f / 3.0f) : B * Z + C;
321 
322     float L = 116.0f * fy - 16.0f;
323     float a = 500.0f * (fx - fy);
324     float b = 200.0f * (fy - fz);
325 
326     return Lab {
327             clamp(L, 0.0f, 100.0f),
328             clamp(a, -128.0f, 128.0f),
329             clamp(b, -128.0f, 128.0f)
330     };
331 }
332 
333 };
334 
sRGBToLab(SkColor color)335 Lab sRGBToLab(SkColor color) {
336     auto colorSpace = ColorSpace::sRGB();
337     float3 rgb;
338     rgb.r = SkColorGetR(color) / 255.0f;
339     rgb.g = SkColorGetG(color) / 255.0f;
340     rgb.b = SkColorGetB(color) / 255.0f;
341     float3 xyz = colorSpace.rgbToXYZ(rgb);
342     float3 srcXYZ = ColorSpace::XYZ(float3{colorSpace.getWhitePoint(), 1});
343     xyz = adaptation(BRADFORD, srcXYZ, ILLUMINANT_D50_XYZ) * xyz;
344     return LabColorSpace::fromXyz(xyz);
345 }
346 
LabToSRGB(const Lab & lab,SkAlpha alpha)347 SkColor LabToSRGB(const Lab& lab, SkAlpha alpha) {
348     auto colorSpace = ColorSpace::sRGB();
349     float3 xyz = LabColorSpace::toXyz(lab);
350     float3 dstXYZ = ColorSpace::XYZ(float3{colorSpace.getWhitePoint(), 1});
351     xyz = adaptation(BRADFORD, ILLUMINANT_D50_XYZ, dstXYZ) * xyz;
352     float3 rgb = colorSpace.xyzToRGB(xyz);
353     return SkColorSetARGB(alpha,
354             static_cast<uint8_t>(rgb.r * 255),
355             static_cast<uint8_t>(rgb.g * 255),
356             static_cast<uint8_t>(rgb.b * 255));
357 }
358 
359 }  // namespace uirenderer
360 }  // namespace android
361