FreeRDP
prim_colors.c
1 /* FreeRDP: A Remote Desktop Protocol Client
2  * Color conversion operations.
3  * vi:ts=4 sw=4:
4  *
5  * Copyright 2011 Stephen Erisman
6  * Copyright 2011 Norbert Federa <norbert.federa@thincast.com>
7  * Copyright 2011 Martin Fleisz <martin.fleisz@thincast.com>
8  * (c) Copyright 2012 Hewlett-Packard Development Company, L.P.
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License"); you may
11  * not use this file except in compliance with the License. You may obtain
12  * a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
16  * or implied. See the License for the specific language governing
17  * permissions and limitations under the License.
18  */
19 
20 #include <math.h>
21 
22 #include <freerdp/config.h>
23 #include <winpr/assert.h>
24 #include <winpr/cast.h>
25 
26 #include <freerdp/types.h>
27 #include <freerdp/primitives.h>
28 #include <freerdp/codec/color.h>
29 
30 #include "prim_internal.h"
31 #include "prim_colors.h"
32 
33 #ifndef MINMAX
34 #define MINMAX(_v_, _l_, _h_) ((_v_) < (_l_) ? (_l_) : ((_v_) > (_h_) ? (_h_) : (_v_)))
35 #endif /* !MINMAX */
36 /* ------------------------------------------------------------------------- */
37 
38 /* pregenerated table for ycbcr constants: [0,27]
39  *
40  * rounded integer values derived from the following formula:
41  *
42  * { (1.402525f * 2^divisor), (0.714401f * 2^divisor), (0.343730f * 2^divisor), (1.769905f *
43  * 2^divisor) }
44  */
45 
46 static const INT32 ycbcr_constants[][4] = { { 1, 1, 0, 2 },
47  { 3, 1, 1, 4 },
48  { 6, 3, 1, 7 },
49  { 11, 6, 3, 14 },
50  { 22, 11, 5, 28 },
51  { 45, 23, 11, 57 },
52  { 90, 46, 22, 113 },
53  { 180, 91, 44, 227 },
54  { 359, 183, 88, 453 },
55  { 718, 366, 176, 906 },
56  { 1436, 732, 352, 1812 },
57  { 2872, 1463, 704, 3625 },
58  { 5745, 2926, 1408, 7250 },
59  { 11489, 5852, 2816, 14499 },
60  { 22979, 11705, 5632, 28998 },
61  { 45958, 23409, 11263, 57996 },
62  { 91916, 46819, 22527, 115992 },
63  { 183832, 93638, 45053, 231985 },
64  { 367664, 187276, 90107, 463970 },
65  { 735327, 374552, 180214, 927940 },
66  { 1470654, 749104, 360427, 1855880 },
67  { 2941308, 1498207, 720854, 3711760 },
68  { 5882616, 2996415, 1441708, 7423520 },
69  { 11765232, 5992830, 2883416, 14847039 },
70  { 23530465, 11985660, 5766832, 29694078 },
71  { 47060930, 23971320, 11533665, 59388157 },
72  { 94121859, 47942640, 23067330, 118776314 },
73  { 188243719, 95885279, 46134660, 237552628 },
74  { 376487438, 191770558, 92269319, 475105256 },
75  { 752974876, 383541116, 184538639, 950210512 },
76  { 1505949752, 767082233, 369077277, 1900421023 } };
77 
78 static pstatus_t general_yCbCrToRGB_16s8u_P3AC4R_BGRX(const INT16* WINPR_RESTRICT pSrc[3],
79  UINT32 srcStep, BYTE* WINPR_RESTRICT pDst,
80  UINT32 dstStep, UINT32 DstFormat,
81  const prim_size_t* WINPR_RESTRICT roi)
82 {
83  BYTE* pRGB = pDst;
84  const INT16* pY = pSrc[0];
85  const INT16* pCb = pSrc[1];
86  const INT16* pCr = pSrc[2];
87  const size_t srcPad = (srcStep - (roi->width * 2)) / 2;
88  const size_t dstPad = (dstStep - (roi->width * 4));
89  const DWORD formatSize = FreeRDPGetBytesPerPixel(DstFormat);
90 
91  for (UINT32 y = 0; y < roi->height; y++)
92  {
93  for (UINT32 x = 0; x < roi->width; x++)
94  {
95  const INT32 divisor = 16;
96  const INT32 Y = (INT32)((UINT32)((*pY++) + 4096) << divisor);
97  const INT32 Cb = (*pCb++);
98  const INT32 Cr = (*pCr++);
99 
100  const INT32 CrR = WINPR_ASSERTING_INT_CAST(
101  int32_t, Cr* ycbcr_constants[divisor][0]); //(1.402525f * 2^divisor);
102  const INT32 CrG = WINPR_ASSERTING_INT_CAST(
103  int32_t, Cr* ycbcr_constants[divisor][1]); //(0.714401f * 2^divisor);
104  const INT32 CbG = WINPR_ASSERTING_INT_CAST(
105  int32_t, Cb* ycbcr_constants[divisor][2]); //(0.343730f * 2^divisor);
106  const INT32 CbB = WINPR_ASSERTING_INT_CAST(
107  int32_t, Cb* ycbcr_constants[divisor][3]); //(1.769905f * 2^divisor);
108  const INT16 R = WINPR_ASSERTING_INT_CAST(int16_t, ((CrR + Y) >> divisor) >> 5);
109  const INT16 G = WINPR_ASSERTING_INT_CAST(int16_t, ((Y - CbG - CrG) >> divisor) >> 5);
110  const INT16 B = WINPR_ASSERTING_INT_CAST(int16_t, ((CbB + Y) >> divisor) >> 5);
111  pRGB = writePixelBGRX(pRGB, formatSize, DstFormat, CLIP(R), CLIP(G), CLIP(B), 0);
112  }
113 
114  pY += srcPad;
115  pCb += srcPad;
116  pCr += srcPad;
117  pRGB += dstPad;
118  }
119 
120  return PRIMITIVES_SUCCESS;
121 }
122 
123 static pstatus_t general_yCbCrToRGB_16s8u_P3AC4R_general(const INT16* WINPR_RESTRICT pSrc[3],
124  UINT32 srcStep, BYTE* WINPR_RESTRICT pDst,
125  UINT32 dstStep, UINT32 DstFormat,
126  const prim_size_t* WINPR_RESTRICT roi)
127 {
128  BYTE* pRGB = pDst;
129  const INT16* pY = pSrc[0];
130  const INT16* pCb = pSrc[1];
131  const INT16* pCr = pSrc[2];
132  const size_t srcPad = (srcStep - (roi->width * 2)) / 2;
133  const size_t dstPad = (dstStep - (roi->width * 4));
134  const fkt_writePixel writePixel = getPixelWriteFunction(DstFormat, FALSE);
135  const DWORD formatSize = FreeRDPGetBytesPerPixel(DstFormat);
136 
137  for (UINT32 y = 0; y < roi->height; y++)
138  {
139  for (UINT32 x = 0; x < roi->width; x++)
140  {
141  const INT32 divisor = 16;
142  const INT32 Y = (INT32)((UINT32)((*pY++) + 4096) << divisor);
143  const INT32 Cb = (*pCb++);
144  const INT32 Cr = (*pCr++);
145  const INT32 CrR = Cr * ycbcr_constants[divisor][0];
146  const INT32 CrG = Cr * ycbcr_constants[divisor][1];
147  const INT32 CbG = Cb * ycbcr_constants[divisor][2];
148  const INT32 CbB = Cb * ycbcr_constants[divisor][3];
149  const INT32 R = (CrR + Y) >> (divisor + 5);
150  const INT32 G = (Y - CbG - CrG) >> (divisor + 5);
151  const INT32 B = (CbB + Y) >> (divisor + 5);
152  pRGB = writePixel(pRGB, formatSize, DstFormat, CLIP(R), CLIP(G), CLIP(B), 0);
153  }
154 
155  pY += srcPad;
156  pCb += srcPad;
157  pCr += srcPad;
158  pRGB += dstPad;
159  }
160 
161  return PRIMITIVES_SUCCESS;
162 }
163 
164 static pstatus_t general_yCbCrToRGB_16s8u_P3AC4R(const INT16* WINPR_RESTRICT pSrc[3],
165  UINT32 srcStep, BYTE* WINPR_RESTRICT pDst,
166  UINT32 dstStep, UINT32 DstFormat,
167  const prim_size_t* WINPR_RESTRICT roi)
168 {
169  switch (DstFormat)
170  {
171  case PIXEL_FORMAT_BGRA32:
172  case PIXEL_FORMAT_BGRX32:
173  return general_yCbCrToRGB_16s8u_P3AC4R_BGRX(pSrc, srcStep, pDst, dstStep, DstFormat,
174  roi);
175 
176  default:
177  return general_yCbCrToRGB_16s8u_P3AC4R_general(pSrc, srcStep, pDst, dstStep, DstFormat,
178  roi);
179  }
180 }
181 
182 /* ------------------------------------------------------------------------- */
183 
184 static pstatus_t
185 general_yCbCrToRGB_16s16s_P3P3(const INT16* WINPR_RESTRICT pSrc[3], INT32 srcStep,
186  INT16* WINPR_RESTRICT pDst[3], INT32 dstStep,
187  const prim_size_t* WINPR_RESTRICT roi) /* region of interest */
188 {
200  const INT16* yptr = pSrc[0];
201  const INT16* cbptr = pSrc[1];
202  const INT16* crptr = pSrc[2];
203  INT16* rptr = pDst[0];
204  INT16* gptr = pDst[1];
205  INT16* bptr = pDst[2];
206  UINT32 srcbump = (WINPR_ASSERTING_INT_CAST(uint32_t, srcStep) - (roi->width * sizeof(UINT16))) /
207  sizeof(UINT16);
208  UINT32 dstbump = (WINPR_ASSERTING_INT_CAST(uint32_t, dstStep) - (roi->width * sizeof(UINT16))) /
209  sizeof(UINT16);
210 
211  for (UINT32 y = 0; y < roi->height; y++)
212  {
213  for (UINT32 x = 0; x < roi->width; ++x)
214  {
215  /* INT32 is used intentionally because we calculate
216  * with shifted factors!
217  */
218  INT32 cy = (INT32)(*yptr++);
219  INT32 cb = (INT32)(*cbptr++);
220  INT32 cr = (INT32)(*crptr++);
221  INT64 r = 0;
222  INT64 g = 0;
223  INT64 b = 0;
224  /*
225  * This is the slow floating point version kept here for reference.
226  * y = y + 4096; // 128<<5=4096 so that we can scale the sum by>>5
227  * r = y + cr*1.403f;
228  * g = y - cb*0.344f - cr*0.714f;
229  * b = y + cb*1.770f;
230  * y_r_buf[i] = CLIP(r>>5);
231  * cb_g_buf[i] = CLIP(g>>5);
232  * cr_b_buf[i] = CLIP(b>>5);
233  */
234  /*
235  * We scale the factors by << 16 into 32-bit integers in order to
236  * avoid slower floating point multiplications. Since the final
237  * result needs to be scaled by >> 5 we will extract only the
238  * upper 11 bits (>> 21) from the final sum.
239  * Hence we also have to scale the other terms of the sum by << 16.
240  * R: 1.403 << 16 = 91947
241  * G: 0.344 << 16 = 22544, 0.714 << 16 = 46792
242  * B: 1.770 << 16 = 115998
243  */
244  cy = (INT32)((UINT32)(cy + 4096) << 16);
245 
246  r = 1LL * cy + 1LL * cr * ycbcr_constants[16][0];
247  g = 1LL * cy - 1LL * cb * ycbcr_constants[16][1] - 1LL * cr * ycbcr_constants[16][2];
248  b = 1LL * cy + 1LL * cb * ycbcr_constants[16][3];
249  *rptr++ = CLIP(r >> 21);
250  *gptr++ = CLIP(g >> 21);
251  *bptr++ = CLIP(b >> 21);
252  }
253 
254  yptr += srcbump;
255  cbptr += srcbump;
256  crptr += srcbump;
257  rptr += dstbump;
258  gptr += dstbump;
259  bptr += dstbump;
260  }
261 
262  return PRIMITIVES_SUCCESS;
263 }
264 
265 /* ------------------------------------------------------------------------- */
266 static pstatus_t
267 general_RGBToYCbCr_16s16s_P3P3(const INT16* WINPR_RESTRICT pSrc[3], INT32 srcStep,
268  INT16* WINPR_RESTRICT pDst[3], INT32 dstStep,
269  const prim_size_t* WINPR_RESTRICT roi) /* region of interest */
270 {
271  /* The encoded YCbCr coefficients are represented as 11.5 fixed-point
272  * numbers:
273  *
274  * 1 sign bit + 10 integer bits + 5 fractional bits
275  *
276  * However only 7 integer bits will be actually used since the value
277  * range is [-128.0, 127.0]. In other words, the encoded coefficients
278  * is scaled by << 5 when interpreted as INT16.
279  * It will be scaled down to original during the quantization phase.
280  */
281  const INT16* rptr = pSrc[0];
282  const INT16* gptr = pSrc[1];
283  const INT16* bptr = pSrc[2];
284  INT16* yptr = pDst[0];
285  INT16* cbptr = pDst[1];
286  INT16* crptr = pDst[2];
287  UINT32 srcbump = (WINPR_ASSERTING_INT_CAST(uint32_t, srcStep) - (roi->width * sizeof(UINT16))) /
288  sizeof(UINT16);
289  UINT32 dstbump = (WINPR_ASSERTING_INT_CAST(uint32_t, dstStep) - (roi->width * sizeof(UINT16))) /
290  sizeof(UINT16);
291 
292  for (UINT32 y = 0; y < roi->height; y++)
293  {
294  for (UINT32 x = 0; x < roi->width; ++x)
295  {
296  /* INT32 is used intentionally because we calculate with
297  * shifted factors!
298  */
299  INT32 r = (INT32)(*rptr++);
300  INT32 g = (INT32)(*gptr++);
301  INT32 b = (INT32)(*bptr++);
302  /* We scale the factors by << 15 into 32-bit integers in order
303  * to avoid slower floating point multiplications. Since the
304  * terms need to be scaled by << 5 we simply scale the final
305  * sum by >> 10
306  *
307  * Y: 0.299000 << 15 = 9798, 0.587000 << 15 = 19235,
308  * 0.114000 << 15 = 3735
309  * Cb: 0.168935 << 15 = 5535, 0.331665 << 15 = 10868,
310  * 0.500590 << 15 = 16403
311  * Cr: 0.499813 << 15 = 16377, 0.418531 << 15 = 13714,
312  * 0.081282 << 15 = 2663
313  */
314  INT32 cy = (r * 9798 + g * 19235 + b * 3735) >> 10;
315  INT32 cb = (r * -5535 + g * -10868 + b * 16403) >> 10;
316  INT32 cr = (r * 16377 + g * -13714 + b * -2663) >> 10;
317  *yptr++ = (INT16)MINMAX(cy - 4096, -4096, 4095);
318  *cbptr++ = (INT16)MINMAX(cb, -4096, 4095);
319  *crptr++ = (INT16)MINMAX(cr, -4096, 4095);
320  }
321 
322  yptr += srcbump;
323  cbptr += srcbump;
324  crptr += srcbump;
325  rptr += dstbump;
326  gptr += dstbump;
327  bptr += dstbump;
328  }
329 
330  return PRIMITIVES_SUCCESS;
331 }
332 
333 static INLINE void writeScanlineGeneric(BYTE* dst, DWORD formatSize, UINT32 DstFormat,
334  const INT16* r, const INT16* g, const INT16* b, DWORD width)
335 {
336  fkt_writePixel writePixel = getPixelWriteFunction(DstFormat, FALSE);
337 
338  for (UINT32 x = 0; x < width; x++)
339  {
340  const INT16 pr = *r++;
341  const INT16 pg = *g++;
342  const INT16 pb = *b++;
343 
344  dst =
345  writePixel(dst, formatSize, DstFormat, WINPR_ASSERTING_INT_CAST(UINT8, pr),
346  WINPR_ASSERTING_INT_CAST(UINT8, pg), WINPR_ASSERTING_INT_CAST(UINT8, pb), 0);
347  }
348 }
349 
350 static INLINE void writeScanlineRGB(BYTE* dst, DWORD formatSize, UINT32 DstFormat, const INT16* r,
351  const INT16* g, const INT16* b, DWORD width)
352 {
353  WINPR_UNUSED(formatSize);
354  WINPR_UNUSED(DstFormat);
355 
356  for (UINT32 x = 0; x < width; x++)
357  {
358  const BYTE R = CLIP(*r++);
359  const BYTE G = CLIP(*g++);
360  const BYTE B = CLIP(*b++);
361  *dst++ = R;
362  *dst++ = G;
363  *dst++ = B;
364  }
365 }
366 
367 static INLINE void writeScanlineBGR(BYTE* dst, DWORD formatSize, UINT32 DstFormat, const INT16* r,
368  const INT16* g, const INT16* b, DWORD width)
369 {
370  WINPR_UNUSED(formatSize);
371  WINPR_UNUSED(DstFormat);
372 
373  for (UINT32 x = 0; x < width; x++)
374  {
375  const BYTE R = CLIP(*r++);
376  const BYTE G = CLIP(*g++);
377  const BYTE B = CLIP(*b++);
378  *dst++ = B;
379  *dst++ = G;
380  *dst++ = R;
381  }
382 }
383 
384 static INLINE void writeScanlineBGRX(BYTE* dst, DWORD formatSize, UINT32 DstFormat, const INT16* r,
385  const INT16* g, const INT16* b, DWORD width)
386 {
387  WINPR_UNUSED(formatSize);
388  WINPR_UNUSED(DstFormat);
389 
390  for (UINT32 x = 0; x < width; x++)
391  {
392  const BYTE R = CLIP(*r++);
393  const BYTE G = CLIP(*g++);
394  const BYTE B = CLIP(*b++);
395  *dst++ = B;
396  *dst++ = G;
397  *dst++ = R;
398  *dst++ = 0xFF;
399  }
400 }
401 
402 static INLINE void writeScanlineRGBX(BYTE* dst, DWORD formatSize, UINT32 DstFormat, const INT16* r,
403  const INT16* g, const INT16* b, DWORD width)
404 {
405  WINPR_UNUSED(formatSize);
406  WINPR_UNUSED(DstFormat);
407 
408  for (UINT32 x = 0; x < width; x++)
409  {
410  const BYTE R = CLIP(*r++);
411  const BYTE G = CLIP(*g++);
412  const BYTE B = CLIP(*b++);
413  *dst++ = R;
414  *dst++ = G;
415  *dst++ = B;
416  *dst++ = 0xFF;
417  }
418 }
419 
420 static INLINE void writeScanlineXBGR(BYTE* dst, DWORD formatSize, UINT32 DstFormat, const INT16* r,
421  const INT16* g, const INT16* b, DWORD width)
422 {
423  WINPR_UNUSED(formatSize);
424  WINPR_UNUSED(DstFormat);
425 
426  for (UINT32 x = 0; x < width; x++)
427  {
428  const BYTE R = CLIP(*r++);
429  const BYTE G = CLIP(*g++);
430  const BYTE B = CLIP(*b++);
431  *dst++ = 0xFF;
432  *dst++ = B;
433  *dst++ = G;
434  *dst++ = R;
435  }
436 }
437 
438 static INLINE void writeScanlineXRGB(BYTE* dst, DWORD formatSize, UINT32 DstFormat, const INT16* r,
439  const INT16* g, const INT16* b, DWORD width)
440 {
441  WINPR_UNUSED(formatSize);
442  WINPR_UNUSED(DstFormat);
443 
444  for (UINT32 x = 0; x < width; x++)
445  {
446  const BYTE R = CLIP(*r++);
447  const BYTE G = CLIP(*g++);
448  const BYTE B = CLIP(*b++);
449  *dst++ = 0xFF;
450  *dst++ = R;
451  *dst++ = G;
452  *dst++ = B;
453  }
454 }
455 
456 typedef void (*fkt_writeScanline)(BYTE*, DWORD, UINT32, const INT16*, const INT16*, const INT16*,
457  DWORD);
458 
459 static INLINE fkt_writeScanline getScanlineWriteFunction(DWORD format)
460 {
461  switch (format)
462  {
463  case PIXEL_FORMAT_ARGB32:
464  case PIXEL_FORMAT_XRGB32:
465  return writeScanlineXRGB;
466 
467  case PIXEL_FORMAT_ABGR32:
468  case PIXEL_FORMAT_XBGR32:
469  return writeScanlineXBGR;
470 
471  case PIXEL_FORMAT_RGBA32:
472  case PIXEL_FORMAT_RGBX32:
473  return writeScanlineRGBX;
474 
475  case PIXEL_FORMAT_BGRA32:
476  case PIXEL_FORMAT_BGRX32:
477  return writeScanlineBGRX;
478 
479  case PIXEL_FORMAT_BGR24:
480  return writeScanlineBGR;
481 
482  case PIXEL_FORMAT_RGB24:
483  return writeScanlineRGB;
484 
485  default:
486  return writeScanlineGeneric;
487  }
488 }
489 
490 /* ------------------------------------------------------------------------- */
491 static pstatus_t general_RGBToRGB_16s8u_P3AC4R_general(
492  const INT16* WINPR_RESTRICT pSrc[3], /* 16-bit R,G, and B arrays */
493  UINT32 srcStep, /* bytes between rows in source data */
494  BYTE* WINPR_RESTRICT pDst, /* 32-bit interleaved ARGB (ABGR?) data */
495  UINT32 dstStep, /* bytes between rows in dest data */
496  UINT32 DstFormat, const prim_size_t* WINPR_RESTRICT roi) /* region of interest */
497 {
498  const INT16* r = pSrc[0];
499  const INT16* g = pSrc[1];
500  const INT16* b = pSrc[2];
501  const DWORD srcAdd = srcStep / sizeof(INT16);
502  fkt_writeScanline writeScanline = getScanlineWriteFunction(DstFormat);
503  const DWORD formatSize = FreeRDPGetBytesPerPixel(DstFormat);
504 
505  for (UINT32 y = 0; y < roi->height; ++y)
506  {
507  (*writeScanline)(pDst, formatSize, DstFormat, r, g, b, roi->width);
508  pDst += dstStep;
509  r += srcAdd;
510  g += srcAdd;
511  b += srcAdd;
512  }
513 
514  return PRIMITIVES_SUCCESS;
515 }
516 
517 static pstatus_t general_RGBToRGB_16s8u_P3AC4R_BGRX(
518  const INT16* WINPR_RESTRICT pSrc[3], /* 16-bit R,G, and B arrays */
519  UINT32 srcStep, /* bytes between rows in source data */
520  BYTE* WINPR_RESTRICT pDst, /* 32-bit interleaved ARGB (ABGR?) data */
521  UINT32 dstStep, /* bytes between rows in dest data */
522  UINT32 DstFormat, const prim_size_t* WINPR_RESTRICT roi) /* region of interest */
523 {
524  const INT16* r = pSrc[0];
525  const INT16* g = pSrc[1];
526  const INT16* b = pSrc[2];
527  const DWORD srcAdd = srcStep / sizeof(INT16);
528  const DWORD formatSize = FreeRDPGetBytesPerPixel(DstFormat);
529 
530  for (UINT32 y = 0; y < roi->height; ++y)
531  {
532  writeScanlineBGRX(pDst, formatSize, DstFormat, r, g, b, roi->width);
533  pDst += dstStep;
534  r += srcAdd;
535  g += srcAdd;
536  b += srcAdd;
537  }
538 
539  return PRIMITIVES_SUCCESS;
540 }
541 
542 static pstatus_t
543 general_RGBToRGB_16s8u_P3AC4R(const INT16* WINPR_RESTRICT pSrc[3], /* 16-bit R,G, and B arrays */
544  UINT32 srcStep, /* bytes between rows in source data */
545  BYTE* WINPR_RESTRICT pDst, /* 32-bit interleaved ARGB (ABGR?) data */
546  UINT32 dstStep, /* bytes between rows in dest data */
547  UINT32 DstFormat,
548  const prim_size_t* WINPR_RESTRICT roi) /* region of interest */
549 {
550  switch (DstFormat)
551  {
552  case PIXEL_FORMAT_BGRA32:
553  case PIXEL_FORMAT_BGRX32:
554  return general_RGBToRGB_16s8u_P3AC4R_BGRX(pSrc, srcStep, pDst, dstStep, DstFormat, roi);
555 
556  default:
557  return general_RGBToRGB_16s8u_P3AC4R_general(pSrc, srcStep, pDst, dstStep, DstFormat,
558  roi);
559  }
560 }
561 /* ------------------------------------------------------------------------- */
562 void primitives_init_colors(primitives_t* WINPR_RESTRICT prims)
563 {
564  prims->yCbCrToRGB_16s8u_P3AC4R = general_yCbCrToRGB_16s8u_P3AC4R;
565  prims->yCbCrToRGB_16s16s_P3P3 = general_yCbCrToRGB_16s16s_P3P3;
566  prims->RGBToYCbCr_16s16s_P3P3 = general_RGBToYCbCr_16s16s_P3P3;
567  prims->RGBToRGB_16s8u_P3AC4R = general_RGBToRGB_16s8u_P3AC4R;
568 }
569 
570 /* ------------------------------------------------------------------------- */
571 void primitives_init_colors_opt(primitives_t* WINPR_RESTRICT prims)
572 {
573  primitives_init_colors_sse2(prims);
574  primitives_init_colors_neon(prims);
575 }