• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 FCC_full_rgb_to_yuv[] = {
140       0.300000f,  0.590000f,  0.110000f,  0.000000f,  0.000000f,
141      -0.168539f, -0.331461f,  0.500000f,  0.000000f,  0.501961f,
142       0.500000f, -0.421429f, -0.078571f,  0.000000f,  0.501961f,
143       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
144 };
145 const float FCC_full_yuv_to_rgb[] = {
146       1.000000f,  0.000000f,  1.400000f,  0.000000f, -0.702745f,
147       1.000000f, -0.331864f, -0.711864f,  0.000000f,  0.523911f,
148       1.000000f,  1.780000f,  0.000000f,  0.000000f, -0.893490f,
149       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
150 };
151 const float FCC_limited_rgb_to_yuv[] = {
152       0.257647f,  0.506706f,  0.094471f,  0.000000f,  0.062745f,
153      -0.148050f, -0.291165f,  0.439216f,  0.000000f,  0.501961f,
154       0.439216f, -0.370196f, -0.069020f,  0.000000f,  0.501961f,
155       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
156 };
157 const float FCC_limited_yuv_to_rgb[] = {
158       1.164384f, -0.000000f,  1.593750f,  0.000000f, -0.873059f,
159       1.164384f, -0.377792f, -0.810381f,  0.000000f,  0.523357f,
160       1.164384f,  2.026339f,  0.000000f,  0.000000f, -1.090202f,
161       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
162 };
163 const float SMPTE240_full_rgb_to_yuv[] = {
164       0.212000f,  0.701000f,  0.087000f,  0.000000f,  0.000000f,
165      -0.116101f, -0.383899f,  0.500000f,  0.000000f,  0.501961f,
166       0.500000f, -0.444797f, -0.055203f,  0.000000f,  0.501961f,
167       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
168 };
169 const float SMPTE240_full_yuv_to_rgb[] = {
170       1.000000f,  0.000000f,  1.576000f,  0.000000f, -0.791090f,
171       1.000000f, -0.226622f, -0.476622f,  0.000000f,  0.353001f,
172       1.000000f,  1.826000f,  0.000000f,  0.000000f, -0.916580f,
173       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
174 };
175 const float SMPTE240_limited_rgb_to_yuv[] = {
176       0.182071f,  0.602035f,  0.074718f,  0.000000f,  0.062745f,
177      -0.101987f, -0.337229f,  0.439216f,  0.000000f,  0.501961f,
178       0.439216f, -0.390724f, -0.048492f,  0.000000f,  0.501961f,
179       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
180 };
181 const float SMPTE240_limited_yuv_to_rgb[] = {
182       1.164384f, -0.000000f,  1.794107f,  0.000000f, -0.973631f,
183       1.164384f, -0.257985f, -0.542583f,  0.000000f,  0.328794f,
184       1.164384f,  2.078705f,  0.000000f,  0.000000f, -1.116488f,
185       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
186 };
187 const float YDZDX_full_rgb_to_yuv[] = {
188       0.000000f,  1.000000f,  0.000000f,  0.000000f,  0.000000f,
189       0.000000f, -0.500000f,  0.493283f,  0.000000f,  0.501961f,
190       0.500000f, -0.495951f,  0.000000f,  0.000000f,  0.501961f,
191       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
192 };
193 const float YDZDX_full_yuv_to_rgb[] = {
194       0.991902f, -0.000000f,  2.000000f,  0.000000f, -1.003922f,
195       1.000000f,  0.000000f,  0.000000f,  0.000000f,  0.000000f,
196       1.013617f,  2.027234f,  0.000000f,  0.000000f, -1.017592f,
197       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
198 };
199 const float YDZDX_limited_rgb_to_yuv[] = {
200       0.000000f,  0.858824f,  0.000000f,  0.000000f,  0.062745f,
201       0.000000f, -0.439216f,  0.433315f,  0.000000f,  0.501961f,
202       0.439216f, -0.435659f,  0.000000f,  0.000000f,  0.501961f,
203       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
204 };
205 const float YDZDX_limited_yuv_to_rgb[] = {
206       1.154954f, -0.000000f,  2.276786f,  0.000000f, -1.215325f,
207       1.164384f,  0.000000f,  0.000000f,  0.000000f, -0.073059f,
208       1.180239f,  2.307788f,  0.000000f,  0.000000f, -1.232474f,
209       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
210 };
211 const float GBR_full_rgb_to_yuv[] = {
212       0.000000f,  1.000000f,  0.000000f,  0.000000f,  0.000000f,
213       0.000000f,  0.000000f,  1.000000f,  0.000000f,  0.000000f,
214       1.000000f,  0.000000f,  0.000000f,  0.000000f,  0.000000f,
215       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
216 };
217 const float GBR_full_yuv_to_rgb[] = {
218       0.000000f,  0.000000f,  1.000000f,  0.000000f,  0.000000f,
219       1.000000f,  0.000000f,  0.000000f,  0.000000f,  0.000000f,
220       0.000000f,  1.000000f,  0.000000f,  0.000000f, -0.000000f,
221       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
222 };
223 const float GBR_limited_rgb_to_yuv[] = {
224       0.000000f,  0.858824f,  0.000000f,  0.000000f,  0.062745f,
225       0.000000f,  0.000000f,  0.858824f,  0.000000f,  0.062745f,
226       0.858824f,  0.000000f,  0.000000f,  0.000000f,  0.062745f,
227       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
228 };
229 const float GBR_limited_yuv_to_rgb[] = {
230       0.000000f,  0.000000f,  1.164384f,  0.000000f, -0.073059f,
231       1.164384f,  0.000000f,  0.000000f,  0.000000f, -0.073059f,
232       0.000000f,  1.164384f,  0.000000f,  0.000000f, -0.073059f,
233       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
234 };
235 const float YCgCo_8bit_full_rgb_to_yuv[] = {
236       0.250000f,  0.500000f,  0.250000f,  0.000000f,  0.000000f,
237      -0.250000f,  0.500000f, -0.250000f,  0.000000f,  0.501961f,
238       0.500000f,  0.000000f, -0.500000f,  0.000000f,  0.501961f,
239       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
240 };
241 const float YCgCo_8bit_full_yuv_to_rgb[] = {
242       1.000000f, -1.000000f,  1.000000f,  0.000000f,  0.000000f,
243       1.000000f,  1.000000f,  0.000000f,  0.000000f, -0.501961f,
244       1.000000f, -1.000000f, -1.000000f,  0.000000f,  1.003922f,
245       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
246 };
247 const float YCgCo_8bit_limited_rgb_to_yuv[] = {
248       0.214706f,  0.429412f,  0.214706f,  0.000000f,  0.062745f,
249      -0.214706f,  0.429412f, -0.214706f,  0.000000f,  0.501961f,
250       0.429412f,  0.000000f, -0.429412f,  0.000000f,  0.501961f,
251       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
252 };
253 const float YCgCo_8bit_limited_yuv_to_rgb[] = {
254       1.164384f, -1.164384f,  1.164384f,  0.000000f, -0.073059f,
255       1.164384f,  1.164384f,  0.000000f,  0.000000f, -0.657534f,
256       1.164384f, -1.164384f, -1.164384f,  0.000000f,  1.095891f,
257       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
258 };
259 const float YCgCo_10bit_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.500489f,
262       0.500000f,  0.000000f, -0.500000f,  0.000000f,  0.500489f,
263       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
264 };
265 const float YCgCo_10bit_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.500489f,
268       1.000000f, -1.000000f, -1.000000f,  0.000000f,  1.000978f,
269       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
270 };
271 const float YCgCo_10bit_limited_rgb_to_yuv[] = {
272       0.214076f,  0.428153f,  0.214076f,  0.000000f,  0.062561f,
273      -0.214076f,  0.428153f, -0.214076f,  0.000000f,  0.500489f,
274       0.428153f,  0.000000f, -0.428153f,  0.000000f,  0.500489f,
275       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
276 };
277 const float YCgCo_10bit_limited_yuv_to_rgb[] = {
278       1.167808f, -1.167808f,  1.167808f,  0.000000f, -0.073059f,
279       1.167808f,  1.167808f,  0.000000f,  0.000000f, -0.657534f,
280       1.167808f, -1.167808f, -1.167808f,  0.000000f,  1.095890f,
281       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
282 };
283 const float YCgCo_12bit_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.500122f,
286       0.500000f,  0.000000f, -0.500000f,  0.000000f,  0.500122f,
287       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
288 };
289 const float YCgCo_12bit_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.500122f,
292       1.000000f, -1.000000f, -1.000000f,  0.000000f,  1.000244f,
293       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
294 };
295 const float YCgCo_12bit_limited_rgb_to_yuv[] = {
296       0.213919f,  0.427839f,  0.213919f,  0.000000f,  0.062515f,
297      -0.213919f,  0.427839f, -0.213919f,  0.000000f,  0.500122f,
298       0.427839f,  0.000000f, -0.427839f,  0.000000f,  0.500122f,
299       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
300 };
301 const float YCgCo_12bit_limited_yuv_to_rgb[] = {
302       1.168664f, -1.168664f,  1.168664f,  0.000000f, -0.073059f,
303       1.168664f,  1.168664f,  0.000000f,  0.000000f, -0.657534f,
304       1.168664f, -1.168664f, -1.168664f,  0.000000f,  1.095891f,
305       0.000000f,  0.000000f,  0.000000f,  1.000000f,  0.000000f,
306 };
307 
308 static_assert(kJPEG_Full_SkYUVColorSpace            == 0, "");
309 static_assert(kRec601_Limited_SkYUVColorSpace       == 1, "");
310 static_assert(kRec709_Full_SkYUVColorSpace          == 2, "");
311 static_assert(kRec709_Limited_SkYUVColorSpace       == 3, "");
312 static_assert(kBT2020_8bit_Full_SkYUVColorSpace     == 4, "");
313 static_assert(kBT2020_8bit_Limited_SkYUVColorSpace  == 5, "");
314 static_assert(kBT2020_10bit_Full_SkYUVColorSpace    == 6, "");
315 static_assert(kBT2020_10bit_Limited_SkYUVColorSpace == 7, "");
316 static_assert(kBT2020_12bit_Full_SkYUVColorSpace    == 8, "");
317 static_assert(kBT2020_12bit_Limited_SkYUVColorSpace == 9, "");
318 static_assert(kFCC_Full_SkYUVColorSpace             == 10, "");
319 static_assert(kFCC_Limited_SkYUVColorSpace          == 11, "");
320 static_assert(kSMPTE240_Full_SkYUVColorSpace        == 12, "");
321 static_assert(kSMPTE240_Limited_SkYUVColorSpace     == 13, "");
322 static_assert(kYDZDX_Full_SkYUVColorSpace           == 14, "");
323 static_assert(kYDZDX_Limited_SkYUVColorSpace        == 15, "");
324 static_assert(kGBR_Full_SkYUVColorSpace             == 16, "");
325 static_assert(kGBR_Limited_SkYUVColorSpace          == 17, "");
326 static_assert(kYCgCo_8bit_Full_SkYUVColorSpace      == 18, "");
327 static_assert(kYCgCo_8bit_Limited_SkYUVColorSpace   == 19, "");
328 static_assert(kYCgCo_10bit_Full_SkYUVColorSpace     == 20, "");
329 static_assert(kYCgCo_10bit_Limited_SkYUVColorSpace  == 21, "");
330 static_assert(kYCgCo_12bit_Full_SkYUVColorSpace     == 22, "");
331 static_assert(kYCgCo_12bit_Limited_SkYUVColorSpace  == 23, "");
332 
333 const float* yuv_to_rgb_array[] = {
334     JPEG_full_yuv_to_rgb,
335     Rec601_limited_yuv_to_rgb,
336     Rec709_full_yuv_to_rgb,
337     Rec709_limited_yuv_to_rgb,
338     BT2020_8bit_full_yuv_to_rgb,
339     BT2020_8bit_limited_yuv_to_rgb,
340     BT2020_10bit_full_yuv_to_rgb,
341     BT2020_10bit_limited_yuv_to_rgb,
342     BT2020_12bit_full_yuv_to_rgb,
343     BT2020_12bit_limited_yuv_to_rgb,
344     FCC_full_yuv_to_rgb,
345     FCC_limited_yuv_to_rgb,
346     SMPTE240_full_yuv_to_rgb,
347     SMPTE240_limited_yuv_to_rgb,
348     YDZDX_full_yuv_to_rgb,
349     YDZDX_limited_yuv_to_rgb,
350     GBR_full_yuv_to_rgb,
351     GBR_limited_yuv_to_rgb,
352     YCgCo_8bit_full_yuv_to_rgb,
353     YCgCo_8bit_limited_yuv_to_rgb,
354     YCgCo_10bit_full_yuv_to_rgb,
355     YCgCo_10bit_limited_yuv_to_rgb,
356     YCgCo_12bit_full_yuv_to_rgb,
357     YCgCo_12bit_limited_yuv_to_rgb,
358 };
359 
360 const float* rgb_to_yuv_array[] = {
361     JPEG_full_rgb_to_yuv,
362     Rec601_limited_rgb_to_yuv,
363     Rec709_full_rgb_to_yuv,
364     Rec709_limited_rgb_to_yuv,
365     BT2020_8bit_full_rgb_to_yuv,
366     BT2020_8bit_limited_rgb_to_yuv,
367     BT2020_10bit_full_rgb_to_yuv,
368     BT2020_10bit_limited_rgb_to_yuv,
369     BT2020_12bit_full_rgb_to_yuv,
370     BT2020_12bit_limited_rgb_to_yuv,
371     FCC_full_rgb_to_yuv,
372     FCC_limited_rgb_to_yuv,
373     SMPTE240_full_rgb_to_yuv,
374     SMPTE240_limited_rgb_to_yuv,
375     YDZDX_full_rgb_to_yuv,
376     YDZDX_limited_rgb_to_yuv,
377     GBR_full_rgb_to_yuv,
378     GBR_limited_rgb_to_yuv,
379     YCgCo_8bit_full_rgb_to_yuv,
380     YCgCo_8bit_limited_rgb_to_yuv,
381     YCgCo_10bit_full_rgb_to_yuv,
382     YCgCo_10bit_limited_rgb_to_yuv,
383     YCgCo_12bit_full_rgb_to_yuv,
384     YCgCo_12bit_limited_rgb_to_yuv,
385 };
386 
387 constexpr size_t kSizeOfColorMatrix = 20 * sizeof(float);
388 
SkColorMatrix_RGB2YUV(SkYUVColorSpace cs,float m[20])389 void SkColorMatrix_RGB2YUV(SkYUVColorSpace cs, float m[20]) {
390     if ((unsigned)cs < (unsigned)kIdentity_SkYUVColorSpace) {
391         memcpy(m, rgb_to_yuv_array[(unsigned)cs], kSizeOfColorMatrix);
392     } else {
393         memset(m, 0, kSizeOfColorMatrix);
394         m[0] = m[6] = m[12] = m[18] = 1;
395     }
396 }
397 
SkColorMatrix_YUV2RGB(SkYUVColorSpace cs,float m[20])398 void SkColorMatrix_YUV2RGB(SkYUVColorSpace cs, float m[20]) {
399     if ((unsigned)cs < (unsigned)kIdentity_SkYUVColorSpace) {
400         memcpy(m, yuv_to_rgb_array[(unsigned)cs], kSizeOfColorMatrix);
401     } else {
402         memset(m, 0, kSizeOfColorMatrix);
403         m[0] = m[6] = m[12] = m[18] = 1;
404     }
405 }
406 
407 ///////////////////////////////////////////////////////////////////////////////////////////////////
408 
409 // we just drop the alpha rol/col from the colormatrix
410 // output is |        tr |
411 //           |  3x3   tg |
412 //           |        tb |
413 //           | 0 0 0  1  |
colormatrix_to_matrix44(const float src[20],SkM44 * dst)414 static void colormatrix_to_matrix44(const float src[20], SkM44* dst) {
415     *dst = SkM44(src[ 0], src[ 1], src[ 2], src[ 4],
416                  src[ 5], src[ 6], src[ 7], src[ 9],
417                  src[10], src[11], src[12], src[14],
418                        0,       0,       0,       1);
419 }
420 
421 // input: ignore the bottom row
422 // output: inject identity row/column for alpha
matrix44_to_colormatrix(const SkM44 & src,float dst[20])423 static void matrix44_to_colormatrix(const SkM44& src, float dst[20]) {
424     dst[0] = src.rc(0,0);
425     dst[1] = src.rc(0,1);
426     dst[2] = src.rc(0,2);
427     dst[3] = 0;
428     dst[4] = src.rc(0,3);    // tx
429 
430     dst[5] = src.rc(1,0);
431     dst[6] = src.rc(1,1);
432     dst[7] = src.rc(1,2);
433     dst[8] = 0;
434     dst[9] = src.rc(1,3);    // ty
435 
436     dst[10] = src.rc(2,0);
437     dst[11] = src.rc(2,1);
438     dst[12] = src.rc(2,2);
439     dst[13] = 0;
440     dst[14] = src.rc(2,3);   // tz
441 
442     dst[15] = dst[16] = dst[17] = dst[19] = 0;
443     dst[18] = 1;
444 }
445 
scale3(float m[],float s)446 static void scale3(float m[], float s) {
447     for (int i = 0; i < 3; ++i) {
448         m[i] *= s;
449     }
450 }
451 
452 namespace {
453 enum Range { kFull, kLimited };
454 struct YUVCoeff {
455     float   Kr, Kb;
456     int     bits;
457     Range   range;
458 };
459 
460 const YUVCoeff gCoeff[] = {
461     { 0.2990f, 0.1140f,  8, kFull    }, // kJPEG_Full_SkYUVColorSpace
462     { 0.2990f, 0.1140f,  8, kLimited }, // kRec601_Limited_SkYUVColorSpace
463     { 0.2126f, 0.0722f,  8, kFull    }, // kRec709_Full_SkYUVColorSpace
464     { 0.2126f, 0.0722f,  8, kLimited }, // kRec709_Limited_SkYUVColorSpace
465     { 0.2627f, 0.0593f,  8, kFull    }, // kBT2020_8bit_Full_SkYUVColorSpace
466     { 0.2627f, 0.0593f,  8, kLimited }, // kBT2020_8bit_Limited_SkYUVColorSpace
467     { 0.2627f, 0.0593f, 10, kFull    }, // kBT2020_10bit_Full_SkYUVColorSpace
468     { 0.2627f, 0.0593f, 10, kLimited }, // kBT2020_10bit_Limited_SkYUVColorSpace
469     { 0.2627f, 0.0593f, 12, kFull    }, // kBT2020_12bit_Full_SkYUVColorSpace
470     { 0.2627f, 0.0593f, 12, kLimited }, // kBT2020_12bit_Limited_SkYUVColorSpace
471     { 0.3000f, 0.1100f,  8, kFull    }, // kFCC_Full_SkYUVColorSpace
472     { 0.3000f, 0.1100f,  8, kLimited }, // kFCC_Limited_SkYUVColorSpace
473     { 0.2120f, 0.0870f,  8, kFull    }, // kSMPTE240_Full_SkYUVColorSpace
474     { 0.2120f, 0.0870f,  8, kLimited }, // kSMPTE240_Limited_SkYUVColorSpace
475 };
476 }  // namespace
477 
make_rgb_to_yuv_matrix_ycbcr(float mx[20],const YUVCoeff & c)478 static void make_rgb_to_yuv_matrix_ycbcr(float mx[20], const YUVCoeff& c) {
479     SkASSERT(c.bits >= 8);
480     const float Kr = c.Kr;
481     const float Kb = c.Kb;
482     const float Kg = 1.0f - Kr - Kb;
483     const float Cr = 0.5f / (1.0f - Kb);
484     const float Cb = 0.5f / (1.0f - Kr);
485 
486     const int shift = c.bits - 8;
487 
488     const float denom = static_cast<float>((1 << c.bits) - 1);
489     float scaleY  = 1.0f,
490           addY    = 0.0f,
491           scaleUV = 1.0f,
492           addUV   = (128 << shift) / denom;
493 
494     if (c.range == kLimited) {
495         scaleY  = (219 << shift) / denom;
496         addY    = ( 16 << shift) / denom;
497         scaleUV = (224 << shift) / denom;
498     }
499 
500     float m[20] = {
501           Kr,  Kg,   Kb,  0,  addY,
502          -Kr, -Kg, 1-Kb,  0, addUV,
503         1-Kr, -Kg,  -Kb,  0, addUV,
504            0,   0,    0,  1,     0,
505     };
506     memcpy(mx, m, sizeof(m));
507     scale3(mx +  0,      scaleY );
508     scale3(mx +  5, Cr * scaleUV);
509     scale3(mx + 10, Cb * scaleUV);
510 }
511 
make_rgb_to_yuv_matrix_ydzdx(float mx[20],Range range)512 static void make_rgb_to_yuv_matrix_ydzdx(float mx[20], Range range) {
513     const int bits = 8;
514     const float denom = static_cast<float>((1 << bits) - 1);
515     float scaleY  = 1.0f,
516           addY    = 0.0f,
517           scaleUV = 1.0f,
518           addUV   = 128 / denom;
519 
520     if (range == kLimited) {
521         scaleY  = 219 / denom;
522         addY    =  16 / denom;
523         scaleUV = 224 / denom;
524     }
525 
526     // YDZDX applies range correction to YUV values similar to YCbCr.
527     float m[20] = {
528           0.0f,              1.0f,             0.0f, 0.0f,  addY,  // Y
529           0.0f,             -0.5f, 0.986566f / 2.0f, 0.0f, addUV,  // DX or DZ
530           0.5f, -0.991902f / 2.0f,             0.0f, 0.0f, addUV,  // DZ or DX
531           0.0f,              0.0f,             0.0f, 1.0f,  0.0f,
532     };
533     memcpy(mx, m, sizeof(m));
534     scale3(mx +  0, scaleY );
535     scale3(mx +  5, scaleUV);
536     scale3(mx + 10, scaleUV);
537 }
538 
make_rgb_to_yuv_matrix_gbr(float mx[20],Range range)539 static void make_rgb_to_yuv_matrix_gbr(float mx[20], Range range) {
540     const int bits = 8;
541     const float denom = static_cast<float>((1 << bits) - 1);
542     float scaleY   = 1.0f,
543           addY     = 0.0f;
544 
545     if (range == kLimited) {
546         scaleY  = 219 / denom;
547         addY    =  16 / denom;
548     }
549 
550     // GBR applies range correction to RGB values similar to YCgCo.
551     float m[20] = {
552           0.0f, 1.0f, 0.0f, 0.0f,  addY, // G
553           0.0f, 0.0f, 1.0f, 0.0f,  addY, // B
554           1.0f, 0.0f, 0.0f, 0.0f,  addY, // R
555           0.0f, 0.0f, 0.0f, 1.0f,  0.0f,
556     };
557     memcpy(mx, m, sizeof(m));
558     scale3(mx +  0, scaleY);
559     scale3(mx +  5, scaleY);
560     scale3(mx + 10, scaleY);
561 }
562 
make_rgb_to_yuv_matrix_ycgco(float mx[20],int bits,Range range)563 static void make_rgb_to_yuv_matrix_ycgco(float mx[20], int bits, Range range) {
564     SkASSERT(bits >= 8);
565     const int shift = bits - 8;
566     const float denom = static_cast<float>((1 << bits) - 1);
567     float scaleY   = 1.0f,
568           addY     = 0.0f,
569           chroma05 = static_cast<float>(1 << (bits - 1)) / denom;
570 
571     if (range == kLimited) {
572         scaleY  = (219 << shift) / denom;
573         addY    = ( 16 << shift) / denom;
574     }
575 
576     float m[20] = {
577           0.25f,  0.5f,   0.25f,  0.0f,  addY,
578          -0.25f,  0.5f,  -0.25f,  0.0f,  chroma05,
579            0.5f,  0.0f,  -0.5f,   0.0f,  chroma05,
580            0.0f,  0.0f,   0.0f,   1.0f,  0.0f,
581     };
582     memcpy(mx, m, sizeof(m));
583     scale3(mx +  0, scaleY);
584     scale3(mx +  5, scaleY);
585     scale3(mx + 10, scaleY);
586 }
587 
make_rgb_to_yuv_matrix(float mx[20],SkYUVColorSpace cs)588 static void make_rgb_to_yuv_matrix(float mx[20], SkYUVColorSpace cs) {
589     switch (cs) {
590         case kJPEG_Full_SkYUVColorSpace:
591         case kRec601_Limited_SkYUVColorSpace:
592         case kRec709_Full_SkYUVColorSpace:
593         case kRec709_Limited_SkYUVColorSpace:
594         case kBT2020_8bit_Full_SkYUVColorSpace:
595         case kBT2020_8bit_Limited_SkYUVColorSpace:
596         case kBT2020_10bit_Full_SkYUVColorSpace:
597         case kBT2020_10bit_Limited_SkYUVColorSpace:
598         case kBT2020_12bit_Full_SkYUVColorSpace:
599         case kBT2020_12bit_Limited_SkYUVColorSpace:
600         case kFCC_Full_SkYUVColorSpace:
601         case kFCC_Limited_SkYUVColorSpace:
602         case kSMPTE240_Full_SkYUVColorSpace:
603         case kSMPTE240_Limited_SkYUVColorSpace:
604         case kIdentity_SkYUVColorSpace:
605             return make_rgb_to_yuv_matrix_ycbcr(mx, gCoeff[(unsigned)cs]);
606         case kYDZDX_Full_SkYUVColorSpace:
607             return make_rgb_to_yuv_matrix_ydzdx(mx, Range::kFull);
608         case kYDZDX_Limited_SkYUVColorSpace:
609             return make_rgb_to_yuv_matrix_ydzdx(mx, Range::kLimited);
610         case kGBR_Full_SkYUVColorSpace:
611             return make_rgb_to_yuv_matrix_gbr(mx, Range::kFull);
612         case kGBR_Limited_SkYUVColorSpace:
613             return make_rgb_to_yuv_matrix_gbr(mx, Range::kLimited);
614         case kYCgCo_8bit_Full_SkYUVColorSpace:
615             return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/8, Range::kFull);
616         case kYCgCo_8bit_Limited_SkYUVColorSpace:
617             return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/8, Range::kLimited);
618         case kYCgCo_10bit_Full_SkYUVColorSpace:
619             return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/10, Range::kFull);
620         case kYCgCo_10bit_Limited_SkYUVColorSpace:
621             return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/10, Range::kLimited);
622         case kYCgCo_12bit_Full_SkYUVColorSpace:
623             return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/12, Range::kFull);
624         case kYCgCo_12bit_Limited_SkYUVColorSpace:
625             return make_rgb_to_yuv_matrix_ycgco(mx, /*bits=*/12, Range::kLimited);
626     }
627 }
628 
dump(const float m[20],SkYUVColorSpace cs,bool rgb2yuv)629 static void dump(const float m[20], SkYUVColorSpace cs, bool rgb2yuv) {
630     const char* names[] = {
631         "JPEG_full",
632         "Rec601_limited",
633         "Rec709_full",
634         "Rec709_limited",
635         "BT2020_8bit_full",
636         "BT2020_8bit_limited",
637         "BT2020_10bit_full",
638         "BT2020_10bit_limited",
639         "BT2020_12bit_full",
640         "BT2020_12bit_limited",
641         "FCC_full",
642         "FCC_limited",
643         "SMPTE240_full",
644         "SMPTE240_limited",
645         "YDZDX_full",
646         "YDZDX_limited",
647         "GBR_full",
648         "GBR_limited",
649         "YCgCo_8bit_full",
650         "YCgCo_8bit_limited",
651         "YCgCo_10bit_full",
652         "YCgCo_10bit_limited",
653         "YCgCo_12bit_full",
654         "YCgCo_12bit_limited",
655     };
656     const char* dirnames[] = {
657         "yuv_to_rgb", "rgb_to_yuv",
658     };
659     SkDebugf("const float %s_%s[] = {\n", names[cs], dirnames[rgb2yuv]);
660     for (int i = 0; i < 4; ++i) {
661         SkDebugf("    ");
662         for (int j = 0; j < 5; ++j) {
663             SkDebugf(" %9.6ff,", m[i * 5 + j]);
664         }
665         SkDebugf("\n");
666     }
667     SkDebugf("};\n");
668 }
669 
670 // Used to create the prebuilt tables for each colorspace.
671 // Don't remove this function, in case we want to recompute those tables in the future.
SkColorMatrix_DumpYUVMatrixTables()672 void SkColorMatrix_DumpYUVMatrixTables() {
673     for (int i = 0; i < kLastEnum_SkYUVColorSpace; ++i) {
674         SkYUVColorSpace cs = static_cast<SkYUVColorSpace>(i);
675         float m[20];
676         make_rgb_to_yuv_matrix(m, cs);
677         dump(m, cs, true);
678         SkM44 m44, im44;
679         colormatrix_to_matrix44(m, &m44);
680         float im[20];
681 #ifdef SK_DEBUG
682         // be sure our coversion between matrix44 and colormatrix is perfect
683         matrix44_to_colormatrix(m44, im);
684         SkASSERT(memcmp(m, im, sizeof(im)) == 0);
685 #endif
686         SkAssertResult(m44.invert(&im44));
687         matrix44_to_colormatrix(im44, im);
688         dump(im, cs, false);
689     }
690 }
691