| 1 | // Copyright 2014 Google Inc. All Rights Reserved. | 
|---|
| 2 | // | 
|---|
| 3 | // Use of this source code is governed by a BSD-style license | 
|---|
| 4 | // that can be found in the COPYING file in the root of the source | 
|---|
| 5 | // tree. An additional intellectual property rights grant can be found | 
|---|
| 6 | // in the file PATENTS. All contributing project authors may | 
|---|
| 7 | // be found in the AUTHORS file in the root of the source tree. | 
|---|
| 8 | // ----------------------------------------------------------------------------- | 
|---|
| 9 | // | 
|---|
| 10 | // YUV to RGB upsampling functions. | 
|---|
| 11 | // | 
|---|
| 12 | // Author(s): Branimir Vasic (branimir.vasic@imgtec.com) | 
|---|
| 13 | //            Djordje Pesut  (djordje.pesut@imgtec.com) | 
|---|
| 14 |  | 
|---|
| 15 | #include "./dsp.h" | 
|---|
| 16 |  | 
|---|
| 17 | #if defined(WEBP_USE_MIPS_DSP_R2) | 
|---|
| 18 |  | 
|---|
| 19 | #include <assert.h> | 
|---|
| 20 | #include "./yuv.h" | 
|---|
| 21 |  | 
|---|
| 22 | #if !defined(WEBP_YUV_USE_TABLE) | 
|---|
| 23 |  | 
|---|
| 24 | #define YUV_TO_RGB(Y, U, V, R, G, B) do {                                      \ | 
|---|
| 25 | const int t1 = MultHi(Y, 19077);                                           \ | 
|---|
| 26 | const int t2 = MultHi(V, 13320);                                           \ | 
|---|
| 27 | R = MultHi(V, 26149);                                                      \ | 
|---|
| 28 | G = MultHi(U, 6419);                                                       \ | 
|---|
| 29 | B = MultHi(U, 33050);                                                      \ | 
|---|
| 30 | R = t1 + R;                                                                \ | 
|---|
| 31 | G = t1 - G;                                                                \ | 
|---|
| 32 | B = t1 + B;                                                                \ | 
|---|
| 33 | R = R - 14234;                                                             \ | 
|---|
| 34 | G = G - t2 + 8708;                                                         \ | 
|---|
| 35 | B = B - 17685;                                                             \ | 
|---|
| 36 | __asm__ volatile (                                                         \ | 
|---|
| 37 | "shll_s.w         %[" #R "],      %[" #R "],        17         \n\t"     \ | 
|---|
| 38 | "shll_s.w         %[" #G "],      %[" #G "],        17         \n\t"     \ | 
|---|
| 39 | "shll_s.w         %[" #B "],      %[" #B "],        17         \n\t"     \ | 
|---|
| 40 | "precrqu_s.qb.ph  %[" #R "],      %[" #R "],        $zero      \n\t"     \ | 
|---|
| 41 | "precrqu_s.qb.ph  %[" #G "],      %[" #G "],        $zero      \n\t"     \ | 
|---|
| 42 | "precrqu_s.qb.ph  %[" #B "],      %[" #B "],        $zero      \n\t"     \ | 
|---|
| 43 | "srl              %[" #R "],      %[" #R "],        24         \n\t"     \ | 
|---|
| 44 | "srl              %[" #G "],      %[" #G "],        24         \n\t"     \ | 
|---|
| 45 | "srl              %[" #B "],      %[" #B "],        24         \n\t"     \ | 
|---|
| 46 | : [R]"+r"(R), [G]"+r"(G), [B]"+r"(B)                                     \ | 
|---|
| 47 | :                                                                        \ | 
|---|
| 48 | );                                                                         \ | 
|---|
| 49 | } while (0) | 
|---|
| 50 |  | 
|---|
| 51 | static WEBP_INLINE void YuvToRgb(int y, int u, int v, uint8_t* const rgb) { | 
|---|
| 52 | int r, g, b; | 
|---|
| 53 | YUV_TO_RGB(y, u, v, r, g, b); | 
|---|
| 54 | rgb[0] = r; | 
|---|
| 55 | rgb[1] = g; | 
|---|
| 56 | rgb[2] = b; | 
|---|
| 57 | } | 
|---|
| 58 | static WEBP_INLINE void YuvToBgr(int y, int u, int v, uint8_t* const bgr) { | 
|---|
| 59 | int r, g, b; | 
|---|
| 60 | YUV_TO_RGB(y, u, v, r, g, b); | 
|---|
| 61 | bgr[0] = b; | 
|---|
| 62 | bgr[1] = g; | 
|---|
| 63 | bgr[2] = r; | 
|---|
| 64 | } | 
|---|
| 65 | static WEBP_INLINE void YuvToRgb565(int y, int u, int v, uint8_t* const rgb) { | 
|---|
| 66 | int r, g, b; | 
|---|
| 67 | YUV_TO_RGB(y, u, v, r, g, b); | 
|---|
| 68 | { | 
|---|
| 69 | const int rg = (r & 0xf8) | (g >> 5); | 
|---|
| 70 | const int gb = ((g << 3) & 0xe0) | (b >> 3); | 
|---|
| 71 | #ifdef WEBP_SWAP_16BIT_CSP | 
|---|
| 72 | rgb[0] = gb; | 
|---|
| 73 | rgb[1] = rg; | 
|---|
| 74 | #else | 
|---|
| 75 | rgb[0] = rg; | 
|---|
| 76 | rgb[1] = gb; | 
|---|
| 77 | #endif | 
|---|
| 78 | } | 
|---|
| 79 | } | 
|---|
| 80 | static WEBP_INLINE void YuvToRgba4444(int y, int u, int v, | 
|---|
| 81 | uint8_t* const argb) { | 
|---|
| 82 | int r, g, b; | 
|---|
| 83 | YUV_TO_RGB(y, u, v, r, g, b); | 
|---|
| 84 | { | 
|---|
| 85 | const int rg = (r & 0xf0) | (g >> 4); | 
|---|
| 86 | const int ba = (b & 0xf0) | 0x0f;     // overwrite the lower 4 bits | 
|---|
| 87 | #ifdef WEBP_SWAP_16BIT_CSP | 
|---|
| 88 | argb[0] = ba; | 
|---|
| 89 | argb[1] = rg; | 
|---|
| 90 | #else | 
|---|
| 91 | argb[0] = rg; | 
|---|
| 92 | argb[1] = ba; | 
|---|
| 93 | #endif | 
|---|
| 94 | } | 
|---|
| 95 | } | 
|---|
| 96 | #endif  // WEBP_YUV_USE_TABLE | 
|---|
| 97 |  | 
|---|
| 98 | //----------------------------------------------------------------------------- | 
|---|
| 99 | // Alpha handling variants | 
|---|
| 100 |  | 
|---|
| 101 | static WEBP_INLINE void YuvToArgb(uint8_t y, uint8_t u, uint8_t v, | 
|---|
| 102 | uint8_t* const argb) { | 
|---|
| 103 | int r, g, b; | 
|---|
| 104 | YUV_TO_RGB(y, u, v, r, g, b); | 
|---|
| 105 | argb[0] = 0xff; | 
|---|
| 106 | argb[1] = r; | 
|---|
| 107 | argb[2] = g; | 
|---|
| 108 | argb[3] = b; | 
|---|
| 109 | } | 
|---|
| 110 | static WEBP_INLINE void YuvToBgra(uint8_t y, uint8_t u, uint8_t v, | 
|---|
| 111 | uint8_t* const bgra) { | 
|---|
| 112 | int r, g, b; | 
|---|
| 113 | YUV_TO_RGB(y, u, v, r, g, b); | 
|---|
| 114 | bgra[0] = b; | 
|---|
| 115 | bgra[1] = g; | 
|---|
| 116 | bgra[2] = r; | 
|---|
| 117 | bgra[3] = 0xff; | 
|---|
| 118 | } | 
|---|
| 119 | static WEBP_INLINE void YuvToRgba(uint8_t y, uint8_t u, uint8_t v, | 
|---|
| 120 | uint8_t* const rgba) { | 
|---|
| 121 | int r, g, b; | 
|---|
| 122 | YUV_TO_RGB(y, u, v, r, g, b); | 
|---|
| 123 | rgba[0] = r; | 
|---|
| 124 | rgba[1] = g; | 
|---|
| 125 | rgba[2] = b; | 
|---|
| 126 | rgba[3] = 0xff; | 
|---|
| 127 | } | 
|---|
| 128 |  | 
|---|
| 129 | //------------------------------------------------------------------------------ | 
|---|
| 130 | // Fancy upsampler | 
|---|
| 131 |  | 
|---|
| 132 | #ifdef FANCY_UPSAMPLING | 
|---|
| 133 |  | 
|---|
| 134 | // Given samples laid out in a square as: | 
|---|
| 135 | //  [a b] | 
|---|
| 136 | //  [c d] | 
|---|
| 137 | // we interpolate u/v as: | 
|---|
| 138 | //  ([9*a + 3*b + 3*c +   d    3*a + 9*b + 3*c +   d] + [8 8]) / 16 | 
|---|
| 139 | //  ([3*a +   b + 9*c + 3*d      a + 3*b + 3*c + 9*d]   [8 8]) / 16 | 
|---|
| 140 |  | 
|---|
| 141 | // We process u and v together stashed into 32bit (16bit each). | 
|---|
| 142 | #define LOAD_UV(u, v) ((u) | ((v) << 16)) | 
|---|
| 143 |  | 
|---|
| 144 | #define UPSAMPLE_FUNC(FUNC_NAME, FUNC, XSTEP)                                  \ | 
|---|
| 145 | static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y,           \ | 
|---|
| 146 | const uint8_t* top_u, const uint8_t* top_v,              \ | 
|---|
| 147 | const uint8_t* cur_u, const uint8_t* cur_v,              \ | 
|---|
| 148 | uint8_t* top_dst, uint8_t* bottom_dst, int len) {        \ | 
|---|
| 149 | int x;                                                                       \ | 
|---|
| 150 | const int last_pixel_pair = (len - 1) >> 1;                                  \ | 
|---|
| 151 | uint32_t tl_uv = LOAD_UV(top_u[0], top_v[0]);   /* top-left sample */        \ | 
|---|
| 152 | uint32_t l_uv  = LOAD_UV(cur_u[0], cur_v[0]);   /* left-sample */            \ | 
|---|
| 153 | assert(top_y != NULL);                                                       \ | 
|---|
| 154 | {                                                                            \ | 
|---|
| 155 | const uint32_t uv0 = (3 * tl_uv + l_uv + 0x00020002u) >> 2;                \ | 
|---|
| 156 | FUNC(top_y[0], uv0 & 0xff, (uv0 >> 16), top_dst);                          \ | 
|---|
| 157 | }                                                                            \ | 
|---|
| 158 | if (bottom_y != NULL) {                                                      \ | 
|---|
| 159 | const uint32_t uv0 = (3 * l_uv + tl_uv + 0x00020002u) >> 2;                \ | 
|---|
| 160 | FUNC(bottom_y[0], uv0 & 0xff, (uv0 >> 16), bottom_dst);                    \ | 
|---|
| 161 | }                                                                            \ | 
|---|
| 162 | for (x = 1; x <= last_pixel_pair; ++x) {                                     \ | 
|---|
| 163 | const uint32_t t_uv = LOAD_UV(top_u[x], top_v[x]);  /* top sample */       \ | 
|---|
| 164 | const uint32_t uv   = LOAD_UV(cur_u[x], cur_v[x]);  /* sample */           \ | 
|---|
| 165 | /* precompute invariant values associated with first and second diagonals*/\ | 
|---|
| 166 | const uint32_t avg = tl_uv + t_uv + l_uv + uv + 0x00080008u;               \ | 
|---|
| 167 | const uint32_t diag_12 = (avg + 2 * (t_uv + l_uv)) >> 3;                   \ | 
|---|
| 168 | const uint32_t diag_03 = (avg + 2 * (tl_uv + uv)) >> 3;                    \ | 
|---|
| 169 | {                                                                          \ | 
|---|
| 170 | const uint32_t uv0 = (diag_12 + tl_uv) >> 1;                             \ | 
|---|
| 171 | const uint32_t uv1 = (diag_03 + t_uv) >> 1;                              \ | 
|---|
| 172 | FUNC(top_y[2 * x - 1], uv0 & 0xff, (uv0 >> 16),                          \ | 
|---|
| 173 | top_dst + (2 * x - 1) * XSTEP);                                     \ | 
|---|
| 174 | FUNC(top_y[2 * x - 0], uv1 & 0xff, (uv1 >> 16),                          \ | 
|---|
| 175 | top_dst + (2 * x - 0) * XSTEP);                                     \ | 
|---|
| 176 | }                                                                          \ | 
|---|
| 177 | if (bottom_y != NULL) {                                                    \ | 
|---|
| 178 | const uint32_t uv0 = (diag_03 + l_uv) >> 1;                              \ | 
|---|
| 179 | const uint32_t uv1 = (diag_12 + uv) >> 1;                                \ | 
|---|
| 180 | FUNC(bottom_y[2 * x - 1], uv0 & 0xff, (uv0 >> 16),                       \ | 
|---|
| 181 | bottom_dst + (2 * x - 1) * XSTEP);                                  \ | 
|---|
| 182 | FUNC(bottom_y[2 * x + 0], uv1 & 0xff, (uv1 >> 16),                       \ | 
|---|
| 183 | bottom_dst + (2 * x + 0) * XSTEP);                                  \ | 
|---|
| 184 | }                                                                          \ | 
|---|
| 185 | tl_uv = t_uv;                                                              \ | 
|---|
| 186 | l_uv = uv;                                                                 \ | 
|---|
| 187 | }                                                                            \ | 
|---|
| 188 | if (!(len & 1)) {                                                            \ | 
|---|
| 189 | {                                                                          \ | 
|---|
| 190 | const uint32_t uv0 = (3 * tl_uv + l_uv + 0x00020002u) >> 2;              \ | 
|---|
| 191 | FUNC(top_y[len - 1], uv0 & 0xff, (uv0 >> 16),                            \ | 
|---|
| 192 | top_dst + (len - 1) * XSTEP);                                       \ | 
|---|
| 193 | }                                                                          \ | 
|---|
| 194 | if (bottom_y != NULL) {                                                    \ | 
|---|
| 195 | const uint32_t uv0 = (3 * l_uv + tl_uv + 0x00020002u) >> 2;              \ | 
|---|
| 196 | FUNC(bottom_y[len - 1], uv0 & 0xff, (uv0 >> 16),                         \ | 
|---|
| 197 | bottom_dst + (len - 1) * XSTEP);                                    \ | 
|---|
| 198 | }                                                                          \ | 
|---|
| 199 | }                                                                            \ | 
|---|
| 200 | } | 
|---|
| 201 |  | 
|---|
| 202 | // All variants implemented. | 
|---|
| 203 | UPSAMPLE_FUNC(UpsampleRgbLinePair,      YuvToRgb,      3) | 
|---|
| 204 | UPSAMPLE_FUNC(UpsampleBgrLinePair,      YuvToBgr,      3) | 
|---|
| 205 | UPSAMPLE_FUNC(UpsampleRgbaLinePair,     YuvToRgba,     4) | 
|---|
| 206 | UPSAMPLE_FUNC(UpsampleBgraLinePair,     YuvToBgra,     4) | 
|---|
| 207 | UPSAMPLE_FUNC(UpsampleArgbLinePair,     YuvToArgb,     4) | 
|---|
| 208 | UPSAMPLE_FUNC(UpsampleRgba4444LinePair, YuvToRgba4444, 2) | 
|---|
| 209 | UPSAMPLE_FUNC(UpsampleRgb565LinePair,   YuvToRgb565,   2) | 
|---|
| 210 |  | 
|---|
| 211 | #undef LOAD_UV | 
|---|
| 212 | #undef UPSAMPLE_FUNC | 
|---|
| 213 |  | 
|---|
| 214 | //------------------------------------------------------------------------------ | 
|---|
| 215 | // Entry point | 
|---|
| 216 |  | 
|---|
| 217 | extern void WebPInitUpsamplersMIPSdspR2(void); | 
|---|
| 218 |  | 
|---|
| 219 | WEBP_TSAN_IGNORE_FUNCTION void WebPInitUpsamplersMIPSdspR2(void) { | 
|---|
| 220 | WebPUpsamplers[MODE_RGB]       = UpsampleRgbLinePair; | 
|---|
| 221 | WebPUpsamplers[MODE_RGBA]      = UpsampleRgbaLinePair; | 
|---|
| 222 | WebPUpsamplers[MODE_BGR]       = UpsampleBgrLinePair; | 
|---|
| 223 | WebPUpsamplers[MODE_BGRA]      = UpsampleBgraLinePair; | 
|---|
| 224 | WebPUpsamplers[MODE_ARGB]      = UpsampleArgbLinePair; | 
|---|
| 225 | WebPUpsamplers[MODE_RGBA_4444] = UpsampleRgba4444LinePair; | 
|---|
| 226 | WebPUpsamplers[MODE_RGB_565]   = UpsampleRgb565LinePair; | 
|---|
| 227 | WebPUpsamplers[MODE_rgbA]      = UpsampleRgbaLinePair; | 
|---|
| 228 | WebPUpsamplers[MODE_bgrA]      = UpsampleBgraLinePair; | 
|---|
| 229 | WebPUpsamplers[MODE_Argb]      = UpsampleArgbLinePair; | 
|---|
| 230 | WebPUpsamplers[MODE_rgbA_4444] = UpsampleRgba4444LinePair; | 
|---|
| 231 | } | 
|---|
| 232 |  | 
|---|
| 233 | #endif  // FANCY_UPSAMPLING | 
|---|
| 234 |  | 
|---|
| 235 | //------------------------------------------------------------------------------ | 
|---|
| 236 | // YUV444 converter | 
|---|
| 237 |  | 
|---|
| 238 | #define YUV444_FUNC(FUNC_NAME, FUNC, XSTEP)                                    \ | 
|---|
| 239 | static void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v,    \ | 
|---|
| 240 | uint8_t* dst, int len) {                                 \ | 
|---|
| 241 | int i;                                                                       \ | 
|---|
| 242 | for (i = 0; i < len; ++i) FUNC(y[i], u[i], v[i], &dst[i * XSTEP]);           \ | 
|---|
| 243 | } | 
|---|
| 244 |  | 
|---|
| 245 | YUV444_FUNC(Yuv444ToRgb,      YuvToRgb,      3) | 
|---|
| 246 | YUV444_FUNC(Yuv444ToBgr,      YuvToBgr,      3) | 
|---|
| 247 | YUV444_FUNC(Yuv444ToRgba,     YuvToRgba,     4) | 
|---|
| 248 | YUV444_FUNC(Yuv444ToBgra,     YuvToBgra,     4) | 
|---|
| 249 | YUV444_FUNC(Yuv444ToArgb,     YuvToArgb,     4) | 
|---|
| 250 | YUV444_FUNC(Yuv444ToRgba4444, YuvToRgba4444, 2) | 
|---|
| 251 | YUV444_FUNC(Yuv444ToRgb565,   YuvToRgb565,   2) | 
|---|
| 252 |  | 
|---|
| 253 | #undef YUV444_FUNC | 
|---|
| 254 |  | 
|---|
| 255 | //------------------------------------------------------------------------------ | 
|---|
| 256 | // Entry point | 
|---|
| 257 |  | 
|---|
| 258 | extern void WebPInitYUV444ConvertersMIPSdspR2(void); | 
|---|
| 259 |  | 
|---|
| 260 | WEBP_TSAN_IGNORE_FUNCTION void WebPInitYUV444ConvertersMIPSdspR2(void) { | 
|---|
| 261 | WebPYUV444Converters[MODE_RGB]       = Yuv444ToRgb; | 
|---|
| 262 | WebPYUV444Converters[MODE_RGBA]      = Yuv444ToRgba; | 
|---|
| 263 | WebPYUV444Converters[MODE_BGR]       = Yuv444ToBgr; | 
|---|
| 264 | WebPYUV444Converters[MODE_BGRA]      = Yuv444ToBgra; | 
|---|
| 265 | WebPYUV444Converters[MODE_ARGB]      = Yuv444ToArgb; | 
|---|
| 266 | WebPYUV444Converters[MODE_RGBA_4444] = Yuv444ToRgba4444; | 
|---|
| 267 | WebPYUV444Converters[MODE_RGB_565]   = Yuv444ToRgb565; | 
|---|
| 268 | WebPYUV444Converters[MODE_rgbA]      = Yuv444ToRgba; | 
|---|
| 269 | WebPYUV444Converters[MODE_bgrA]      = Yuv444ToBgra; | 
|---|
| 270 | WebPYUV444Converters[MODE_Argb]      = Yuv444ToArgb; | 
|---|
| 271 | WebPYUV444Converters[MODE_rgbA_4444] = Yuv444ToRgba4444; | 
|---|
| 272 | } | 
|---|
| 273 |  | 
|---|
| 274 | #else  // !WEBP_USE_MIPS_DSP_R2 | 
|---|
| 275 |  | 
|---|
| 276 | WEBP_DSP_INIT_STUB(WebPInitYUV444ConvertersMIPSdspR2) | 
|---|
| 277 |  | 
|---|
| 278 | #endif  // WEBP_USE_MIPS_DSP_R2 | 
|---|
| 279 |  | 
|---|
| 280 | #if !(defined(FANCY_UPSAMPLING) && defined(WEBP_USE_MIPS_DSP_R2)) | 
|---|
| 281 | WEBP_DSP_INIT_STUB(WebPInitUpsamplersMIPSdspR2) | 
|---|
| 282 | #endif | 
|---|
| 283 |  | 
|---|