xref: /aosp_15_r20/external/skia/src/core/SkYUVMath.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2019 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "src/core/SkYUVMath.h"
9 
10 #include "include/core/SkImageInfo.h"
11 #include "include/core/SkM44.h"
12 #include "include/private/base/SkAssert.h"
13 #include "include/private/base/SkDebug.h"
14 
15 #include <cstring>
16 
17 // in SkColorMatrix order (row-major)
18 // Created by running SkColorMatrix_DumpYUVMatrixTables()
19 const float JPEG_full_rgb_to_yuv[] = {
20       0.299000f,  0.587000f,  0.114000f,  0.000000f,  0.000000f,
21      -0.168736f, -0.331264f,  0.500000f,  0.000000f,  0.501961f,
22       0.500000f, -0.418688f, -0.081312f,  0.000000f,  0.501961f,
23       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
24 };
25 const float JPEG_full_yuv_to_rgb[] = {
26       1.000000f, -0.000000f,  1.402000f,  0.000000f, -0.703749f,
27       1.000000f, -0.344136f, -0.714136f,  0.000000f,  0.531211f,
28       1.000000f,  1.772000f,  0.000000f,  0.000000f, -0.889475f,
29       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
30 };
31 const float Rec601_limited_rgb_to_yuv[] = {
32       0.256788f,  0.504129f,  0.097906f,  0.000000f,  0.062745f,
33      -0.148223f, -0.290993f,  0.439216f,  0.000000f,  0.501961f,
34       0.439216f, -0.367788f, -0.071427f,  0.000000f,  0.501961f,
35       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
36 };
37 const float Rec601_limited_yuv_to_rgb[] = {
38       1.164384f, -0.000000f,  1.596027f,  0.000000f, -0.874202f,
39       1.164384f, -0.391762f, -0.812968f,  0.000000f,  0.531668f,
40       1.164384f,  2.017232f,  0.000000f,  0.000000f, -1.085631f,
41       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
42 };
43 const float Rec709_full_rgb_to_yuv[] = {
44       0.212600f,  0.715200f,  0.072200f,  0.000000f,  0.000000f,
45      -0.114572f, -0.385428f,  0.500000f,  0.000000f,  0.501961f,
46       0.500000f, -0.454153f, -0.045847f,  0.000000f,  0.501961f,
47       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
48 };
49 const float Rec709_full_yuv_to_rgb[] = {
50       1.000000f, -0.000000f,  1.574800f,  0.000000f, -0.790488f,
51       1.000000f, -0.187324f, -0.468124f,  0.000000f,  0.329010f,
52       1.000000f,  1.855600f, -0.000000f,  0.000000f, -0.931439f,
53       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
54 };
55 const float Rec709_limited_rgb_to_yuv[] = {
56       0.182586f,  0.614231f,  0.062007f,  0.000000f,  0.062745f,
57      -0.100644f, -0.338572f,  0.439216f,  0.000000f,  0.501961f,
58       0.439216f, -0.398942f, -0.040274f,  0.000000f,  0.501961f,
59       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
60 };
61 const float Rec709_limited_yuv_to_rgb[] = {
62       1.164384f, -0.000000f,  1.792741f,  0.000000f, -0.972945f,
63       1.164384f, -0.213249f, -0.532909f,  0.000000f,  0.301483f,
64       1.164384f,  2.112402f, -0.000000f,  0.000000f, -1.133402f,
65       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
66 };
67 const float BT2020_8bit_full_rgb_to_yuv[] = {
68       0.262700f,  0.678000f,  0.059300f,  0.000000f,  0.000000f,
69      -0.139630f, -0.360370f,  0.500000f,  0.000000f,  0.501961f,
70       0.500000f, -0.459786f, -0.040214f,  0.000000f,  0.501961f,
71       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
72 };
73 const float BT2020_8bit_full_yuv_to_rgb[] = {
74       1.000000f, -0.000000f,  1.474600f,  0.000000f, -0.740191f,
75       1.000000f, -0.164553f, -0.571353f,  0.000000f,  0.369396f,
76       1.000000f,  1.881400f, -0.000000f,  0.000000f, -0.944389f,
77       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
78 };
79 const float BT2020_8bit_limited_rgb_to_yuv[] = {
80       0.225613f,  0.582282f,  0.050928f,  0.000000f,  0.062745f,
81      -0.122655f, -0.316560f,  0.439216f,  0.000000f,  0.501961f,
82       0.439216f, -0.403890f, -0.035326f,  0.000000f,  0.501961f,
83       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
84 };
85 const float BT2020_8bit_limited_yuv_to_rgb[] = {
86       1.164384f, -0.000000f,  1.678674f,  0.000000f, -0.915688f,
87       1.164384f, -0.187326f, -0.650424f,  0.000000f,  0.347458f,
88       1.164384f,  2.141772f, -0.000000f,  0.000000f, -1.148145f,
89       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
90 };
91 const float BT2020_10bit_full_rgb_to_yuv[] = {
92       0.262700f,  0.678000f,  0.059300f,  0.000000f,  0.000000f,
93      -0.139630f, -0.360370f,  0.500000f,  0.000000f,  0.500489f,
94       0.500000f, -0.459786f, -0.040214f,  0.000000f,  0.500489f,
95       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
96 };
97 const float BT2020_10bit_full_yuv_to_rgb[] = {
98       1.000000f, -0.000000f,  1.474600f,  0.000000f, -0.738021f,
99       1.000000f, -0.164553f, -0.571353f,  0.000000f,  0.368313f,
100       1.000000f,  1.881400f, -0.000000f,  0.000000f, -0.941620f,
101       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
102 };
103 const float BT2020_10bit_limited_rgb_to_yuv[] = {
104       0.224951f,  0.580575f,  0.050779f,  0.000000f,  0.062561f,
105      -0.122296f, -0.315632f,  0.437928f,  0.000000f,  0.500489f,
106       0.437928f, -0.402706f, -0.035222f,  0.000000f,  0.500489f,
107       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
108 };
109 const float BT2020_10bit_limited_yuv_to_rgb[] = {
110       1.167808f, -0.000000f,  1.683611f,  0.000000f, -0.915688f,
111       1.167808f, -0.187877f, -0.652337f,  0.000000f,  0.347458f,
112       1.167808f,  2.148072f, -0.000000f,  0.000000f, -1.148145f,
113       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
114 };
115 const float BT2020_12bit_full_rgb_to_yuv[] = {
116       0.262700f,  0.678000f,  0.059300f,  0.000000f,  0.000000f,
117      -0.139630f, -0.360370f,  0.500000f,  0.000000f,  0.500122f,
118       0.500000f, -0.459786f, -0.040214f,  0.000000f,  0.500122f,
119       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
120 };
121 const float BT2020_12bit_full_yuv_to_rgb[] = {
122       1.000000f, -0.000000f,  1.474600f,  0.000000f, -0.737480f,
123       1.000000f, -0.164553f, -0.571353f,  0.000000f,  0.368043f,
124       1.000000f,  1.881400f, -0.000000f,  0.000000f, -0.940930f,
125       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
126 };
127 const float BT2020_12bit_limited_rgb_to_yuv[] = {
128       0.224787f,  0.580149f,  0.050742f,  0.000000f,  0.062515f,
129      -0.122206f, -0.315401f,  0.437607f,  0.000000f,  0.500122f,
130       0.437607f, -0.402411f, -0.035196f,  0.000000f,  0.500122f,
131       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
132 };
133 const float BT2020_12bit_limited_yuv_to_rgb[] = {
134       1.168664f, -0.000000f,  1.684846f,  0.000000f, -0.915688f,
135       1.168664f, -0.188015f, -0.652816f,  0.000000f,  0.347458f,
136       1.168664f,  2.149647f, -0.000000f,  0.000000f, -1.148145f,
137       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
138 };
139 const float BT2020_16bit_full_rgb_to_yuv[] = {
140       0.262700f,  0.678000f,  0.059300f,  0.000000f,  0.000000f,
141      -0.139630f, -0.360370f,  0.500000f,  0.000000f,  0.500008f,
142       0.500000f, -0.459786f, -0.040214f,  0.000000f,  0.500008f,
143       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
144 };
145 const float BT2020_16bit_full_yuv_to_rgb[] = {
146       1.000000f, -0.000000f,  1.474600f,  0.000000f, -0.737311f,
147       1.000000f, -0.164553f, -0.571353f,  0.000000f,  0.367959f,
148       1.000000f,  1.881400f, -0.000000f,  0.000000f, -0.940714f,
149       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
150 };
151 const float BT2020_16bit_limited_rgb_to_yuv[] = {
152       0.224735f,  0.580017f,  0.050730f,  0.000000f,  0.062501f,
153      -0.122178f, -0.315329f,  0.437507f,  0.000000f,  0.500008f,
154       0.437507f, -0.402319f, -0.035188f,  0.000000f,  0.500008f,
155       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
156 };
157 const float BT2020_16bit_limited_yuv_to_rgb[] = {
158       1.168932f,  0.000000f,  1.685231f,  0.000000f, -0.915688f,
159       1.168932f, -0.188058f, -0.652965f,  0.000000f,  0.347458f,
160       1.168932f,  2.150139f, -0.000000f,  0.000000f, -1.148145f,
161       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
162 };
163 const float FCC_full_rgb_to_yuv[] = {
164       0.300000f,  0.590000f,  0.110000f,  0.000000f,  0.000000f,
165      -0.168539f, -0.331461f,  0.500000f,  0.000000f,  0.501961f,
166       0.500000f, -0.421429f, -0.078571f,  0.000000f,  0.501961f,
167       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
168 };
169 const float FCC_full_yuv_to_rgb[] = {
170       1.000000f,  0.000000f,  1.400000f,  0.000000f, -0.702745f,
171       1.000000f, -0.331864f, -0.711864f,  0.000000f,  0.523911f,
172       1.000000f,  1.780000f,  0.000000f,  0.000000f, -0.893490f,
173       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
174 };
175 const float FCC_limited_rgb_to_yuv[] = {
176       0.257647f,  0.506706f,  0.094471f,  0.000000f,  0.062745f,
177      -0.148050f, -0.291165f,  0.439216f,  0.000000f,  0.501961f,
178       0.439216f, -0.370196f, -0.069020f,  0.000000f,  0.501961f,
179       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
180 };
181 const float FCC_limited_yuv_to_rgb[] = {
182       1.164384f, -0.000000f,  1.593750f,  0.000000f, -0.873059f,
183       1.164384f, -0.377792f, -0.810381f,  0.000000f,  0.523357f,
184       1.164384f,  2.026339f,  0.000000f,  0.000000f, -1.090202f,
185       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
186 };
187 const float SMPTE240_full_rgb_to_yuv[] = {
188       0.212000f,  0.701000f,  0.087000f,  0.000000f,  0.000000f,
189      -0.116101f, -0.383899f,  0.500000f,  0.000000f,  0.501961f,
190       0.500000f, -0.444797f, -0.055203f,  0.000000f,  0.501961f,
191       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
192 };
193 const float SMPTE240_full_yuv_to_rgb[] = {
194       1.000000f,  0.000000f,  1.576000f,  0.000000f, -0.791090f,
195       1.000000f, -0.226622f, -0.476622f,  0.000000f,  0.353001f,
196       1.000000f,  1.826000f,  0.000000f,  0.000000f, -0.916580f,
197       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
198 };
199 const float SMPTE240_limited_rgb_to_yuv[] = {
200       0.182071f,  0.602035f,  0.074718f,  0.000000f,  0.062745f,
201      -0.101987f, -0.337229f,  0.439216f,  0.000000f,  0.501961f,
202       0.439216f, -0.390724f, -0.048492f,  0.000000f,  0.501961f,
203       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
204 };
205 const float SMPTE240_limited_yuv_to_rgb[] = {
206       1.164384f, -0.000000f,  1.794107f,  0.000000f, -0.973631f,
207       1.164384f, -0.257985f, -0.542583f,  0.000000f,  0.328794f,
208       1.164384f,  2.078705f,  0.000000f,  0.000000f, -1.116488f,
209       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
210 };
211 const float YDZDX_full_rgb_to_yuv[] = {
212       0.000000f,  1.000000f,  0.000000f,  0.000000f,  0.000000f,
213       0.000000f, -0.500000f,  0.493283f,  0.000000f,  0.501961f,
214       0.500000f, -0.495951f,  0.000000f,  0.000000f,  0.501961f,
215       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
216 };
217 const float YDZDX_full_yuv_to_rgb[] = {
218       0.991902f, -0.000000f,  2.000000f,  0.000000f, -1.003922f,
219       1.000000f,  0.000000f,  0.000000f,  0.000000f,  0.000000f,
220       1.013617f,  2.027234f,  0.000000f,  0.000000f, -1.017592f,
221       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
222 };
223 const float YDZDX_limited_rgb_to_yuv[] = {
224       0.000000f,  0.858824f,  0.000000f,  0.000000f,  0.062745f,
225       0.000000f, -0.439216f,  0.433315f,  0.000000f,  0.501961f,
226       0.439216f, -0.435659f,  0.000000f,  0.000000f,  0.501961f,
227       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
228 };
229 const float YDZDX_limited_yuv_to_rgb[] = {
230       1.154954f, -0.000000f,  2.276786f,  0.000000f, -1.215325f,
231       1.164384f,  0.000000f,  0.000000f,  0.000000f, -0.073059f,
232       1.180239f,  2.307788f,  0.000000f,  0.000000f, -1.232474f,
233       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
234 };
235 const float GBR_full_rgb_to_yuv[] = {
236       0.000000f,  1.000000f,  0.000000f,  0.000000f,  0.000000f,
237       0.000000f,  0.000000f,  1.000000f,  0.000000f,  0.000000f,
238       1.000000f,  0.000000f,  0.000000f,  0.000000f,  0.000000f,
239       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
240 };
241 const float GBR_full_yuv_to_rgb[] = {
242       0.000000f,  0.000000f,  1.000000f,  0.000000f,  0.000000f,
243       1.000000f,  0.000000f,  0.000000f,  0.000000f,  0.000000f,
244       0.000000f,  1.000000f,  0.000000f,  0.000000f, -0.000000f,
245       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
246 };
247 const float GBR_limited_rgb_to_yuv[] = {
248       0.000000f,  0.858824f,  0.000000f,  0.000000f,  0.062745f,
249       0.000000f,  0.000000f,  0.858824f,  0.000000f,  0.062745f,
250       0.858824f,  0.000000f,  0.000000f,  0.000000f,  0.062745f,
251       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
252 };
253 const float GBR_limited_yuv_to_rgb[] = {
254       0.000000f,  0.000000f,  1.164384f,  0.000000f, -0.073059f,
255       1.164384f,  0.000000f,  0.000000f,  0.000000f, -0.073059f,
256       0.000000f,  1.164384f,  0.000000f,  0.000000f, -0.073059f,
257       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
258 };
259 const float YCgCo_8bit_full_rgb_to_yuv[] = {
260       0.250000f,  0.500000f,  0.250000f,  0.000000f,  0.000000f,
261      -0.250000f,  0.500000f, -0.250000f,  0.000000f,  0.501961f,
262       0.500000f,  0.000000f, -0.500000f,  0.000000f,  0.501961f,
263       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
264 };
265 const float YCgCo_8bit_full_yuv_to_rgb[] = {
266       1.000000f, -1.000000f,  1.000000f,  0.000000f,  0.000000f,
267       1.000000f,  1.000000f,  0.000000f,  0.000000f, -0.501961f,
268       1.000000f, -1.000000f, -1.000000f,  0.000000f,  1.003922f,
269       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
270 };
271 const float YCgCo_8bit_limited_rgb_to_yuv[] = {
272       0.214706f,  0.429412f,  0.214706f,  0.000000f,  0.062745f,
273      -0.214706f,  0.429412f, -0.214706f,  0.000000f,  0.501961f,
274       0.429412f,  0.000000f, -0.429412f,  0.000000f,  0.501961f,
275       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
276 };
277 const float YCgCo_8bit_limited_yuv_to_rgb[] = {
278       1.164384f, -1.164384f,  1.164384f,  0.000000f, -0.073059f,
279       1.164384f,  1.164384f,  0.000000f,  0.000000f, -0.657534f,
280       1.164384f, -1.164384f, -1.164384f,  0.000000f,  1.095891f,
281       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
282 };
283 const float YCgCo_10bit_full_rgb_to_yuv[] = {
284       0.250000f,  0.500000f,  0.250000f,  0.000000f,  0.000000f,
285      -0.250000f,  0.500000f, -0.250000f,  0.000000f,  0.500489f,
286       0.500000f,  0.000000f, -0.500000f,  0.000000f,  0.500489f,
287       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
288 };
289 const float YCgCo_10bit_full_yuv_to_rgb[] = {
290       1.000000f, -1.000000f,  1.000000f,  0.000000f,  0.000000f,
291       1.000000f,  1.000000f,  0.000000f,  0.000000f, -0.500489f,
292       1.000000f, -1.000000f, -1.000000f,  0.000000f,  1.000978f,
293       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
294 };
295 const float YCgCo_10bit_limited_rgb_to_yuv[] = {
296       0.214076f,  0.428153f,  0.214076f,  0.000000f,  0.062561f,
297      -0.214076f,  0.428153f, -0.214076f,  0.000000f,  0.500489f,
298       0.428153f,  0.000000f, -0.428153f,  0.000000f,  0.500489f,
299       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
300 };
301 const float YCgCo_10bit_limited_yuv_to_rgb[] = {
302       1.167808f, -1.167808f,  1.167808f,  0.000000f, -0.073059f,
303       1.167808f,  1.167808f,  0.000000f,  0.000000f, -0.657534f,
304       1.167808f, -1.167808f, -1.167808f,  0.000000f,  1.095890f,
305       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
306 };
307 const float YCgCo_12bit_full_rgb_to_yuv[] = {
308       0.250000f,  0.500000f,  0.250000f,  0.000000f,  0.000000f,
309      -0.250000f,  0.500000f, -0.250000f,  0.000000f,  0.500122f,
310       0.500000f,  0.000000f, -0.500000f,  0.000000f,  0.500122f,
311       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
312 };
313 const float YCgCo_12bit_full_yuv_to_rgb[] = {
314       1.000000f, -1.000000f,  1.000000f,  0.000000f,  0.000000f,
315       1.000000f,  1.000000f,  0.000000f,  0.000000f, -0.500122f,
316       1.000000f, -1.000000f, -1.000000f,  0.000000f,  1.000244f,
317       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
318 };
319 const float YCgCo_12bit_limited_rgb_to_yuv[] = {
320       0.213919f,  0.427839f,  0.213919f,  0.000000f,  0.062515f,
321      -0.213919f,  0.427839f, -0.213919f,  0.000000f,  0.500122f,
322       0.427839f,  0.000000f, -0.427839f,  0.000000f,  0.500122f,
323       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
324 };
325 const float YCgCo_12bit_limited_yuv_to_rgb[] = {
326       1.168664f, -1.168664f,  1.168664f,  0.000000f, -0.073059f,
327       1.168664f,  1.168664f,  0.000000f,  0.000000f, -0.657534f,
328       1.168664f, -1.168664f, -1.168664f,  0.000000f,  1.095891f,
329       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
330 };
331 const float YCgCo_16bit_full_rgb_to_yuv[] = {
332       0.250000f,  0.500000f,  0.250000f,  0.000000f,  0.000000f,
333      -0.250000f,  0.500000f, -0.250000f,  0.000000f,  0.500008f,
334       0.500000f,  0.000000f, -0.500000f,  0.000000f,  0.500008f,
335       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
336 };
337 const float YCgCo_16bit_full_yuv_to_rgb[] = {
338       1.000000f, -1.000000f,  1.000000f,  0.000000f,  0.000000f,
339       1.000000f,  1.000000f,  0.000000f,  0.000000f, -0.500008f,
340       1.000000f, -1.000000f, -1.000000f,  0.000000f,  1.000015f,
341       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
342 };
343 const float YCgCo_16bit_limited_rgb_to_yuv[] = {
344       0.213870f,  0.427741f,  0.213870f,  0.000000f,  0.062501f,
345      -0.213870f,  0.427741f, -0.213870f,  0.000000f,  0.500008f,
346       0.427741f,  0.000000f, -0.427741f,  0.000000f,  0.500008f,
347       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
348 };
349 const float YCgCo_16bit_limited_yuv_to_rgb[] = {
350       1.168932f, -1.168932f,  1.168932f,  0.000000f, -0.073059f,
351       1.168932f,  1.168932f,  0.000000f,  0.000000f, -0.657534f,
352       1.168932f, -1.168932f, -1.168932f,  0.000000f,  1.095890f,
353       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
354 };
355 
356 static_assert(kJPEG_Full_SkYUVColorSpace            == 0, "");
357 static_assert(kRec601_Limited_SkYUVColorSpace       == 1, "");
358 static_assert(kRec709_Full_SkYUVColorSpace          == 2, "");
359 static_assert(kRec709_Limited_SkYUVColorSpace       == 3, "");
360 static_assert(kBT2020_8bit_Full_SkYUVColorSpace     == 4, "");
361 static_assert(kBT2020_8bit_Limited_SkYUVColorSpace  == 5, "");
362 static_assert(kBT2020_10bit_Full_SkYUVColorSpace    == 6, "");
363 static_assert(kBT2020_10bit_Limited_SkYUVColorSpace == 7, "");
364 static_assert(kBT2020_12bit_Full_SkYUVColorSpace    == 8, "");
365 static_assert(kBT2020_12bit_Limited_SkYUVColorSpace == 9, "");
366 static_assert(kBT2020_16bit_Full_SkYUVColorSpace    == 10, "");
367 static_assert(kBT2020_16bit_Limited_SkYUVColorSpace == 11, "");
368 static_assert(kFCC_Full_SkYUVColorSpace             == 12, "");
369 static_assert(kFCC_Limited_SkYUVColorSpace          == 13, "");
370 static_assert(kSMPTE240_Full_SkYUVColorSpace        == 14, "");
371 static_assert(kSMPTE240_Limited_SkYUVColorSpace     == 15, "");
372 static_assert(kYDZDX_Full_SkYUVColorSpace           == 16, "");
373 static_assert(kYDZDX_Limited_SkYUVColorSpace        == 17, "");
374 static_assert(kGBR_Full_SkYUVColorSpace             == 18, "");
375 static_assert(kGBR_Limited_SkYUVColorSpace          == 19, "");
376 static_assert(kYCgCo_8bit_Full_SkYUVColorSpace      == 20, "");
377 static_assert(kYCgCo_8bit_Limited_SkYUVColorSpace   == 21, "");
378 static_assert(kYCgCo_10bit_Full_SkYUVColorSpace     == 22, "");
379 static_assert(kYCgCo_10bit_Limited_SkYUVColorSpace  == 23, "");
380 static_assert(kYCgCo_12bit_Full_SkYUVColorSpace     == 24, "");
381 static_assert(kYCgCo_12bit_Limited_SkYUVColorSpace  == 25, "");
382 static_assert(kYCgCo_16bit_Full_SkYUVColorSpace     == 26, "");
383 static_assert(kYCgCo_16bit_Limited_SkYUVColorSpace  == 27, "");
384 
385 const float* yuv_to_rgb_array[] = {
386     JPEG_full_yuv_to_rgb,
387     Rec601_limited_yuv_to_rgb,
388     Rec709_full_yuv_to_rgb,
389     Rec709_limited_yuv_to_rgb,
390     BT2020_8bit_full_yuv_to_rgb,
391     BT2020_8bit_limited_yuv_to_rgb,
392     BT2020_10bit_full_yuv_to_rgb,
393     BT2020_10bit_limited_yuv_to_rgb,
394     BT2020_12bit_full_yuv_to_rgb,
395     BT2020_12bit_limited_yuv_to_rgb,
396     BT2020_16bit_full_yuv_to_rgb,
397     BT2020_16bit_limited_yuv_to_rgb,
398     FCC_full_yuv_to_rgb,
399     FCC_limited_yuv_to_rgb,
400     SMPTE240_full_yuv_to_rgb,
401     SMPTE240_limited_yuv_to_rgb,
402     YDZDX_full_yuv_to_rgb,
403     YDZDX_limited_yuv_to_rgb,
404     GBR_full_yuv_to_rgb,
405     GBR_limited_yuv_to_rgb,
406     YCgCo_8bit_full_yuv_to_rgb,
407     YCgCo_8bit_limited_yuv_to_rgb,
408     YCgCo_10bit_full_yuv_to_rgb,
409     YCgCo_10bit_limited_yuv_to_rgb,
410     YCgCo_12bit_full_yuv_to_rgb,
411     YCgCo_12bit_limited_yuv_to_rgb,
412     YCgCo_16bit_full_yuv_to_rgb,
413     YCgCo_16bit_limited_yuv_to_rgb,
414 };
415 
416 const float* rgb_to_yuv_array[] = {
417     JPEG_full_rgb_to_yuv,
418     Rec601_limited_rgb_to_yuv,
419     Rec709_full_rgb_to_yuv,
420     Rec709_limited_rgb_to_yuv,
421     BT2020_8bit_full_rgb_to_yuv,
422     BT2020_8bit_limited_rgb_to_yuv,
423     BT2020_10bit_full_rgb_to_yuv,
424     BT2020_10bit_limited_rgb_to_yuv,
425     BT2020_12bit_full_rgb_to_yuv,
426     BT2020_12bit_limited_rgb_to_yuv,
427     BT2020_16bit_full_rgb_to_yuv,
428     BT2020_16bit_limited_rgb_to_yuv,
429     FCC_full_rgb_to_yuv,
430     FCC_limited_rgb_to_yuv,
431     SMPTE240_full_rgb_to_yuv,
432     SMPTE240_limited_rgb_to_yuv,
433     YDZDX_full_rgb_to_yuv,
434     YDZDX_limited_rgb_to_yuv,
435     GBR_full_rgb_to_yuv,
436     GBR_limited_rgb_to_yuv,
437     YCgCo_8bit_full_rgb_to_yuv,
438     YCgCo_8bit_limited_rgb_to_yuv,
439     YCgCo_10bit_full_rgb_to_yuv,
440     YCgCo_10bit_limited_rgb_to_yuv,
441     YCgCo_12bit_full_rgb_to_yuv,
442     YCgCo_12bit_limited_rgb_to_yuv,
443     YCgCo_16bit_full_rgb_to_yuv,
444     YCgCo_16bit_limited_rgb_to_yuv,
445 };
446 
447 constexpr size_t kSizeOfColorMatrix = 20 * sizeof(float);
448 
SkColorMatrix_RGB2YUV(SkYUVColorSpace cs,float m[20])449 void SkColorMatrix_RGB2YUV(SkYUVColorSpace cs, float m[20]) {
450     if ((unsigned)cs < (unsigned)kIdentity_SkYUVColorSpace) {
451         memcpy(m, rgb_to_yuv_array[(unsigned)cs], kSizeOfColorMatrix);
452     } else {
453         memset(m, 0, kSizeOfColorMatrix);
454         m[0] = m[6] = m[12] = m[18] = 1;
455     }
456 }
457 
SkColorMatrix_YUV2RGB(SkYUVColorSpace cs,float m[20])458 void SkColorMatrix_YUV2RGB(SkYUVColorSpace cs, float m[20]) {
459     if ((unsigned)cs < (unsigned)kIdentity_SkYUVColorSpace) {
460         memcpy(m, yuv_to_rgb_array[(unsigned)cs], kSizeOfColorMatrix);
461     } else {
462         memset(m, 0, kSizeOfColorMatrix);
463         m[0] = m[6] = m[12] = m[18] = 1;
464     }
465 }
466 
467 ///////////////////////////////////////////////////////////////////////////////////////////////////
468 
469 // we just drop the alpha rol/col from the colormatrix
470 // output is |        tr |
471 //           |  3x3   tg |
472 //           |        tb |
473 //           | 0 0 0  1  |
colormatrix_to_matrix44(const float src[20],SkM44 * dst)474 static void colormatrix_to_matrix44(const float src[20], SkM44* dst) {
475     *dst = SkM44(src[ 0], src[ 1], src[ 2], src[ 4],
476                  src[ 5], src[ 6], src[ 7], src[ 9],
477                  src[10], src[11], src[12], src[14],
478                        0,       0,       0,       1);
479 }
480 
481 // input: ignore the bottom row
482 // output: inject identity row/column for alpha
matrix44_to_colormatrix(const SkM44 & src,float dst[20])483 static void matrix44_to_colormatrix(const SkM44& src, float dst[20]) {
484     dst[0] = src.rc(0,0);
485     dst[1] = src.rc(0,1);
486     dst[2] = src.rc(0,2);
487     dst[3] = 0;
488     dst[4] = src.rc(0,3);    // tx
489 
490     dst[5] = src.rc(1,0);
491     dst[6] = src.rc(1,1);
492     dst[7] = src.rc(1,2);
493     dst[8] = 0;
494     dst[9] = src.rc(1,3);    // ty
495 
496     dst[10] = src.rc(2,0);
497     dst[11] = src.rc(2,1);
498     dst[12] = src.rc(2,2);
499     dst[13] = 0;
500     dst[14] = src.rc(2,3);   // tz
501 
502     dst[15] = dst[16] = dst[17] = dst[19] = 0;
503     dst[18] = 1;
504 }
505 
scale3(float m[],float s)506 static void scale3(float m[], float s) {
507     for (int i = 0; i < 3; ++i) {
508         m[i] *= s;
509     }
510 }
511 
512 namespace {
513 enum Range { kFull, kLimited };
514 struct YUVCoeff {
515     float   Kr, Kb;
516     int     bits;
517     Range   range;
518 };
519 
520 const YUVCoeff gCoeff[] = {
521     { 0.2990f, 0.1140f,  8, kFull    }, // kJPEG_Full_SkYUVColorSpace
522     { 0.2990f, 0.1140f,  8, kLimited }, // kRec601_Limited_SkYUVColorSpace
523     { 0.2126f, 0.0722f,  8, kFull    }, // kRec709_Full_SkYUVColorSpace
524     { 0.2126f, 0.0722f,  8, kLimited }, // kRec709_Limited_SkYUVColorSpace
525     { 0.2627f, 0.0593f,  8, kFull    }, // kBT2020_8bit_Full_SkYUVColorSpace
526     { 0.2627f, 0.0593f,  8, kLimited }, // kBT2020_8bit_Limited_SkYUVColorSpace
527     { 0.2627f, 0.0593f, 10, kFull    }, // kBT2020_10bit_Full_SkYUVColorSpace
528     { 0.2627f, 0.0593f, 10, kLimited }, // kBT2020_10bit_Limited_SkYUVColorSpace
529     { 0.2627f, 0.0593f, 12, kFull    }, // kBT2020_12bit_Full_SkYUVColorSpace
530     { 0.2627f, 0.0593f, 12, kLimited }, // kBT2020_12bit_Limited_SkYUVColorSpace
531     { 0.2627f, 0.0593f, 16, kFull    }, // kBT2020_16bit_Full_SkYUVColorSpace
532     { 0.2627f, 0.0593f, 16, kLimited }, // kBT2020_16bit_Limited_SkYUVColorSpace
533     { 0.3000f, 0.1100f,  8, kFull    }, // kFCC_Full_SkYUVColorSpace
534     { 0.3000f, 0.1100f,  8, kLimited }, // kFCC_Limited_SkYUVColorSpace
535     { 0.2120f, 0.0870f,  8, kFull    }, // kSMPTE240_Full_SkYUVColorSpace
536     { 0.2120f, 0.0870f,  8, kLimited }, // kSMPTE240_Limited_SkYUVColorSpace
537 };
538 }  // namespace
539 
make_rgb_to_yuv_matrix_ycbcr(float mx[20],const YUVCoeff & c)540 static void make_rgb_to_yuv_matrix_ycbcr(float mx[20], const YUVCoeff& c) {
541     SkASSERT(c.bits >= 8);
542     const float Kr = c.Kr;
543     const float Kb = c.Kb;
544     const float Kg = 1.0f - Kr - Kb;
545     const float Cr = 0.5f / (1.0f - Kb);
546     const float Cb = 0.5f / (1.0f - Kr);
547 
548     const int shift = c.bits - 8;
549 
550     const float denom = static_cast<float>((1 << c.bits) - 1);
551     float scaleY  = 1.0f,
552           addY    = 0.0f,
553           scaleUV = 1.0f,
554           addUV   = (128 << shift) / denom;
555 
556     if (c.range == kLimited) {
557         scaleY  = (219 << shift) / denom;
558         addY    = ( 16 << shift) / denom;
559         scaleUV = (224 << shift) / denom;
560     }
561 
562     float m[20] = {
563           Kr,  Kg,   Kb,  0,  addY,
564          -Kr, -Kg, 1-Kb,  0, addUV,
565         1-Kr, -Kg,  -Kb,  0, addUV,
566            0,   0,    0,  1,     0,
567     };
568     memcpy(mx, m, sizeof(m));
569     scale3(mx +  0,      scaleY );
570     scale3(mx +  5, Cr * scaleUV);
571     scale3(mx + 10, Cb * scaleUV);
572 }
573 
make_rgb_to_yuv_matrix_ydzdx(float mx[20],Range range)574 static void make_rgb_to_yuv_matrix_ydzdx(float mx[20], Range range) {
575     const int bits = 8;
576     const float denom = static_cast<float>((1 << bits) - 1);
577     float scaleY  = 1.0f,
578           addY    = 0.0f,
579           scaleUV = 1.0f,
580           addUV   = 128 / denom;
581 
582     if (range == kLimited) {
583         scaleY  = 219 / denom;
584         addY    =  16 / denom;
585         scaleUV = 224 / denom;
586     }
587 
588     // YDZDX applies range correction to YUV values similar to YCbCr.
589     float m[20] = {
590           0.0f,              1.0f,             0.0f, 0.0f,  addY,  // Y
591           0.0f,             -0.5f, 0.986566f / 2.0f, 0.0f, addUV,  // DX or DZ
592           0.5f, -0.991902f / 2.0f,             0.0f, 0.0f, addUV,  // DZ or DX
593           0.0f,              0.0f,             0.0f, 1.0f,  0.0f,
594     };
595     memcpy(mx, m, sizeof(m));
596     scale3(mx +  0, scaleY );
597     scale3(mx +  5, scaleUV);
598     scale3(mx + 10, scaleUV);
599 }
600 
make_rgb_to_yuv_matrix_gbr(float mx[20],Range range)601 static void make_rgb_to_yuv_matrix_gbr(float mx[20], Range range) {
602     const int bits = 8;
603     const float denom = static_cast<float>((1 << bits) - 1);
604     float scaleY   = 1.0f,
605           addY     = 0.0f;
606 
607     if (range == kLimited) {
608         scaleY  = 219 / denom;
609         addY    =  16 / denom;
610     }
611 
612     // GBR applies range correction to RGB values similar to YCgCo.
613     float m[20] = {
614           0.0f, 1.0f, 0.0f, 0.0f,  addY, // G
615           0.0f, 0.0f, 1.0f, 0.0f,  addY, // B
616           1.0f, 0.0f, 0.0f, 0.0f,  addY, // R
617           0.0f, 0.0f, 0.0f, 1.0f,  0.0f,
618     };
619     memcpy(mx, m, sizeof(m));
620     scale3(mx +  0, scaleY);
621     scale3(mx +  5, scaleY);
622     scale3(mx + 10, scaleY);
623 }
624 
make_rgb_to_yuv_matrix_ycgco(float mx[20],int bits,Range range)625 static void make_rgb_to_yuv_matrix_ycgco(float mx[20], int bits, Range range) {
626     SkASSERT(bits >= 8);
627     const int shift = bits - 8;
628     const float denom = static_cast<float>((1 << bits) - 1);
629     float scaleY   = 1.0f,
630           addY     = 0.0f,
631           chroma05 = static_cast<float>(1 << (bits - 1)) / denom;
632 
633     if (range == kLimited) {
634         scaleY  = (219 << shift) / denom;
635         addY    = ( 16 << shift) / denom;
636     }
637 
638     float m[20] = {
639           0.25f,  0.5f,   0.25f,  0.0f,  addY,
640          -0.25f,  0.5f,  -0.25f,  0.0f,  chroma05,
641            0.5f,  0.0f,  -0.5f,   0.0f,  chroma05,
642            0.0f,  0.0f,   0.0f,   1.0f,  0.0f,
643     };
644     memcpy(mx, m, sizeof(m));
645     scale3(mx +  0, scaleY);
646     scale3(mx +  5, scaleY);
647     scale3(mx + 10, scaleY);
648 }
649 
make_rgb_to_yuv_matrix(float mx[20],SkYUVColorSpace cs)650 static void make_rgb_to_yuv_matrix(float mx[20], SkYUVColorSpace cs) {
651     switch (cs) {
652         case kJPEG_Full_SkYUVColorSpace:
653         case kRec601_Limited_SkYUVColorSpace:
654         case kRec709_Full_SkYUVColorSpace:
655         case kRec709_Limited_SkYUVColorSpace:
656         case kBT2020_8bit_Full_SkYUVColorSpace:
657         case kBT2020_8bit_Limited_SkYUVColorSpace:
658         case kBT2020_10bit_Full_SkYUVColorSpace:
659         case kBT2020_10bit_Limited_SkYUVColorSpace:
660         case kBT2020_12bit_Full_SkYUVColorSpace:
661         case kBT2020_12bit_Limited_SkYUVColorSpace:
662         case kBT2020_16bit_Full_SkYUVColorSpace:
663         case kBT2020_16bit_Limited_SkYUVColorSpace:
664         case kFCC_Full_SkYUVColorSpace:
665         case kFCC_Limited_SkYUVColorSpace:
666         case kSMPTE240_Full_SkYUVColorSpace:
667         case kSMPTE240_Limited_SkYUVColorSpace:
668         case kIdentity_SkYUVColorSpace:
669             return make_rgb_to_yuv_matrix_ycbcr(mx, gCoeff[(unsigned)cs]);
670         case kYDZDX_Full_SkYUVColorSpace:
671             return make_rgb_to_yuv_matrix_ydzdx(mx, Range::kFull);
672         case kYDZDX_Limited_SkYUVColorSpace:
673             return make_rgb_to_yuv_matrix_ydzdx(mx, Range::kLimited);
674         case kGBR_Full_SkYUVColorSpace:
675             return make_rgb_to_yuv_matrix_gbr(mx, Range::kFull);
676         case kGBR_Limited_SkYUVColorSpace:
677             return make_rgb_to_yuv_matrix_gbr(mx, Range::kLimited);
678         case kYCgCo_8bit_Full_SkYUVColorSpace:
679             return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/8, Range::kFull);
680         case kYCgCo_8bit_Limited_SkYUVColorSpace:
681             return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/8, Range::kLimited);
682         case kYCgCo_10bit_Full_SkYUVColorSpace:
683             return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/10, Range::kFull);
684         case kYCgCo_10bit_Limited_SkYUVColorSpace:
685             return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/10, Range::kLimited);
686         case kYCgCo_12bit_Full_SkYUVColorSpace:
687             return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/12, Range::kFull);
688         case kYCgCo_12bit_Limited_SkYUVColorSpace:
689             return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/12, Range::kLimited);
690         case kYCgCo_16bit_Full_SkYUVColorSpace:
691             return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/16, Range::kFull);
692         case kYCgCo_16bit_Limited_SkYUVColorSpace:
693             return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/16, Range::kLimited);
694     }
695 }
696 
dump(const float m[20],SkYUVColorSpace cs,bool rgb2yuv)697 static void dump(const float m[20], SkYUVColorSpace cs, bool rgb2yuv) {
698     const char* names[] = {
699         "JPEG_full",
700         "Rec601_limited",
701         "Rec709_full",
702         "Rec709_limited",
703         "BT2020_8bit_full",
704         "BT2020_8bit_limited",
705         "BT2020_10bit_full",
706         "BT2020_10bit_limited",
707         "BT2020_12bit_full",
708         "BT2020_12bit_limited",
709         "BT2020_16bit_full",
710         "BT2020_16bit_limited",
711         "FCC_full",
712         "FCC_limited",
713         "SMPTE240_full",
714         "SMPTE240_limited",
715         "YDZDX_full",
716         "YDZDX_limited",
717         "GBR_full",
718         "GBR_limited",
719         "YCgCo_8bit_full",
720         "YCgCo_8bit_limited",
721         "YCgCo_10bit_full",
722         "YCgCo_10bit_limited",
723         "YCgCo_12bit_full",
724         "YCgCo_12bit_limited",
725         "YCgCo_16bit_full",
726         "YCgCo_16bit_limited",
727     };
728     const char* dirnames[] = {
729         "yuv_to_rgb", "rgb_to_yuv",
730     };
731     SkDebugf("const float %s_%s[] = {\n", names[cs], dirnames[rgb2yuv]);
732     for (int i = 0; i < 4; ++i) {
733         SkDebugf("    ");
734         for (int j = 0; j < 5; ++j) {
735             SkDebugf(" %9.6ff,", m[i * 5 + j]);
736         }
737         SkDebugf("\n");
738     }
739     SkDebugf("};\n");
740 }
741 
742 // Used to create the prebuilt tables for each colorspace.
743 // Don't remove this function, in case we want to recompute those tables in the future.
SkColorMatrix_DumpYUVMatrixTables()744 void SkColorMatrix_DumpYUVMatrixTables() {
745     for (int i = 0; i < kLastEnum_SkYUVColorSpace; ++i) {
746         SkYUVColorSpace cs = static_cast<SkYUVColorSpace>(i);
747         float m[20];
748         make_rgb_to_yuv_matrix(m, cs);
749         dump(m, cs, true);
750         SkM44 m44, im44;
751         colormatrix_to_matrix44(m, &m44);
752         float im[20];
753 #ifdef SK_DEBUG
754         // be sure our coversion between matrix44 and colormatrix is perfect
755         matrix44_to_colormatrix(m44, im);
756         SkASSERT(memcmp(m, im, sizeof(im)) == 0);
757 #endif
758         SkAssertResult(m44.invert(&im44));
759         matrix44_to_colormatrix(im44, im);
760         dump(im, cs, false);
761     }
762 }
763