upsampling.c (15863B)
1 // Copyright 2011 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: somnath@google.com (Somnath Banerjee) 13 14 #include <assert.h> 15 #include <stddef.h> 16 17 #include "src/dsp/cpu.h" 18 #include "src/webp/types.h" 19 #include "src/dsp/dsp.h" 20 #include "src/dsp/yuv.h" 21 #include "src/webp/decode.h" 22 23 //------------------------------------------------------------------------------ 24 // Fancy upsampler 25 26 #ifdef FANCY_UPSAMPLING 27 28 // Fancy upsampling functions to convert YUV to RGB 29 WebPUpsampleLinePairFunc WebPUpsamplers[MODE_LAST]; 30 31 // Given samples laid out in a square as: 32 // [a b] 33 // [c d] 34 // we interpolate u/v as: 35 // ([9*a + 3*b + 3*c + d 3*a + 9*b + 3*c + d] + [8 8]) / 16 36 // ([3*a + b + 9*c + 3*d a + 3*b + 3*c + 9*d] [8 8]) / 16 37 38 // We process u and v together stashed into 32bit (16bit each). 39 #define LOAD_UV(u, v) ((u) | ((v) << 16)) 40 41 #define UPSAMPLE_FUNC(FUNC_NAME, FUNC, XSTEP) \ 42 static void FUNC_NAME(const uint8_t* WEBP_RESTRICT top_y, \ 43 const uint8_t* WEBP_RESTRICT bottom_y, \ 44 const uint8_t* WEBP_RESTRICT top_u, \ 45 const uint8_t* WEBP_RESTRICT top_v, \ 46 const uint8_t* WEBP_RESTRICT cur_u, \ 47 const uint8_t* WEBP_RESTRICT cur_v, \ 48 uint8_t* WEBP_RESTRICT top_dst, \ 49 uint8_t* WEBP_RESTRICT bottom_dst, int len) { \ 50 int x; \ 51 const int last_pixel_pair = (len - 1) >> 1; \ 52 uint32_t tl_uv = LOAD_UV(top_u[0], top_v[0]); /* top-left sample */ \ 53 uint32_t l_uv = LOAD_UV(cur_u[0], cur_v[0]); /* left-sample */ \ 54 assert(top_y != NULL); \ 55 { \ 56 const uint32_t uv0 = (3 * tl_uv + l_uv + 0x00020002u) >> 2; \ 57 FUNC(top_y[0], uv0 & 0xff, (uv0 >> 16), top_dst); \ 58 } \ 59 if (bottom_y != NULL) { \ 60 const uint32_t uv0 = (3 * l_uv + tl_uv + 0x00020002u) >> 2; \ 61 FUNC(bottom_y[0], uv0 & 0xff, (uv0 >> 16), bottom_dst); \ 62 } \ 63 for (x = 1; x <= last_pixel_pair; ++x) { \ 64 const uint32_t t_uv = LOAD_UV(top_u[x], top_v[x]); /* top sample */ \ 65 const uint32_t uv = LOAD_UV(cur_u[x], cur_v[x]); /* sample */ \ 66 /* precompute invariant values associated with first and second diagonals*/\ 67 const uint32_t avg = tl_uv + t_uv + l_uv + uv + 0x00080008u; \ 68 const uint32_t diag_12 = (avg + 2 * (t_uv + l_uv)) >> 3; \ 69 const uint32_t diag_03 = (avg + 2 * (tl_uv + uv)) >> 3; \ 70 { \ 71 const uint32_t uv0 = (diag_12 + tl_uv) >> 1; \ 72 const uint32_t uv1 = (diag_03 + t_uv) >> 1; \ 73 FUNC(top_y[2 * x - 1], uv0 & 0xff, (uv0 >> 16), \ 74 top_dst + (2 * x - 1) * (XSTEP)); \ 75 FUNC(top_y[2 * x - 0], uv1 & 0xff, (uv1 >> 16), \ 76 top_dst + (2 * x - 0) * (XSTEP)); \ 77 } \ 78 if (bottom_y != NULL) { \ 79 const uint32_t uv0 = (diag_03 + l_uv) >> 1; \ 80 const uint32_t uv1 = (diag_12 + uv) >> 1; \ 81 FUNC(bottom_y[2 * x - 1], uv0 & 0xff, (uv0 >> 16), \ 82 bottom_dst + (2 * x - 1) * (XSTEP)); \ 83 FUNC(bottom_y[2 * x + 0], uv1 & 0xff, (uv1 >> 16), \ 84 bottom_dst + (2 * x + 0) * (XSTEP)); \ 85 } \ 86 tl_uv = t_uv; \ 87 l_uv = uv; \ 88 } \ 89 if (!(len & 1)) { \ 90 { \ 91 const uint32_t uv0 = (3 * tl_uv + l_uv + 0x00020002u) >> 2; \ 92 FUNC(top_y[len - 1], uv0 & 0xff, (uv0 >> 16), \ 93 top_dst + (len - 1) * (XSTEP)); \ 94 } \ 95 if (bottom_y != NULL) { \ 96 const uint32_t uv0 = (3 * l_uv + tl_uv + 0x00020002u) >> 2; \ 97 FUNC(bottom_y[len - 1], uv0 & 0xff, (uv0 >> 16), \ 98 bottom_dst + (len - 1) * (XSTEP)); \ 99 } \ 100 } \ 101 } 102 103 // All variants implemented. 104 #if !WEBP_NEON_OMIT_C_CODE 105 UPSAMPLE_FUNC(UpsampleRgbaLinePair_C, VP8YuvToRgba, 4) 106 UPSAMPLE_FUNC(UpsampleBgraLinePair_C, VP8YuvToBgra, 4) 107 #if !defined(WEBP_REDUCE_CSP) 108 UPSAMPLE_FUNC(UpsampleArgbLinePair_C, VP8YuvToArgb, 4) 109 UPSAMPLE_FUNC(UpsampleRgbLinePair_C, VP8YuvToRgb, 3) 110 UPSAMPLE_FUNC(UpsampleBgrLinePair_C, VP8YuvToBgr, 3) 111 UPSAMPLE_FUNC(UpsampleRgba4444LinePair_C, VP8YuvToRgba4444, 2) 112 UPSAMPLE_FUNC(UpsampleRgb565LinePair_C, VP8YuvToRgb565, 2) 113 #else 114 static void EmptyUpsampleFunc(const uint8_t* top_y, const uint8_t* bottom_y, 115 const uint8_t* top_u, const uint8_t* top_v, 116 const uint8_t* cur_u, const uint8_t* cur_v, 117 uint8_t* top_dst, uint8_t* bottom_dst, int len) { 118 (void)top_y; 119 (void)bottom_y; 120 (void)top_u; 121 (void)top_v; 122 (void)cur_u; 123 (void)cur_v; 124 (void)top_dst; 125 (void)bottom_dst; 126 (void)len; 127 assert(0); // COLORSPACE SUPPORT NOT COMPILED 128 } 129 #define UpsampleArgbLinePair_C EmptyUpsampleFunc 130 #define UpsampleRgbLinePair_C EmptyUpsampleFunc 131 #define UpsampleBgrLinePair_C EmptyUpsampleFunc 132 #define UpsampleRgba4444LinePair_C EmptyUpsampleFunc 133 #define UpsampleRgb565LinePair_C EmptyUpsampleFunc 134 #endif // WEBP_REDUCE_CSP 135 136 #endif 137 138 #undef LOAD_UV 139 #undef UPSAMPLE_FUNC 140 141 #endif // FANCY_UPSAMPLING 142 143 //------------------------------------------------------------------------------ 144 145 #if !defined(FANCY_UPSAMPLING) 146 #define DUAL_SAMPLE_FUNC(FUNC_NAME, FUNC) \ 147 static void FUNC_NAME(const uint8_t* WEBP_RESTRICT top_y, \ 148 const uint8_t* WEBP_RESTRICT bot_y, \ 149 const uint8_t* WEBP_RESTRICT top_u, \ 150 const uint8_t* WEBP_RESTRICT top_v, \ 151 const uint8_t* WEBP_RESTRICT bot_u, \ 152 const uint8_t* WEBP_RESTRICT bot_v, \ 153 uint8_t* WEBP_RESTRICT top_dst, \ 154 uint8_t* WEBP_RESTRICT bot_dst, int len) { \ 155 const int half_len = len >> 1; \ 156 int x; \ 157 assert(top_dst != NULL); \ 158 { \ 159 for (x = 0; x < half_len; ++x) { \ 160 FUNC(top_y[2 * x + 0], top_u[x], top_v[x], top_dst + 8 * x + 0); \ 161 FUNC(top_y[2 * x + 1], top_u[x], top_v[x], top_dst + 8 * x + 4); \ 162 } \ 163 if (len & 1) FUNC(top_y[2 * x + 0], top_u[x], top_v[x], top_dst + 8 * x); \ 164 } \ 165 if (bot_dst != NULL) { \ 166 for (x = 0; x < half_len; ++x) { \ 167 FUNC(bot_y[2 * x + 0], bot_u[x], bot_v[x], bot_dst + 8 * x + 0); \ 168 FUNC(bot_y[2 * x + 1], bot_u[x], bot_v[x], bot_dst + 8 * x + 4); \ 169 } \ 170 if (len & 1) FUNC(bot_y[2 * x + 0], bot_u[x], bot_v[x], bot_dst + 8 * x); \ 171 } \ 172 } 173 174 DUAL_SAMPLE_FUNC(DualLineSamplerBGRA, VP8YuvToBgra) 175 DUAL_SAMPLE_FUNC(DualLineSamplerARGB, VP8YuvToArgb) 176 #undef DUAL_SAMPLE_FUNC 177 178 #endif // !FANCY_UPSAMPLING 179 180 WebPUpsampleLinePairFunc WebPGetLinePairConverter(int alpha_is_last) { 181 WebPInitUpsamplers(); 182 #ifdef FANCY_UPSAMPLING 183 return WebPUpsamplers[alpha_is_last ? MODE_BGRA : MODE_ARGB]; 184 #else 185 return (alpha_is_last ? DualLineSamplerBGRA : DualLineSamplerARGB); 186 #endif 187 } 188 189 //------------------------------------------------------------------------------ 190 // YUV444 converter 191 192 #define YUV444_FUNC(FUNC_NAME, FUNC, XSTEP) \ 193 extern void FUNC_NAME(const uint8_t* WEBP_RESTRICT y, \ 194 const uint8_t* WEBP_RESTRICT u, \ 195 const uint8_t* WEBP_RESTRICT v, \ 196 uint8_t* WEBP_RESTRICT dst, int len); \ 197 void FUNC_NAME(const uint8_t* WEBP_RESTRICT y, \ 198 const uint8_t* WEBP_RESTRICT u, \ 199 const uint8_t* WEBP_RESTRICT v, \ 200 uint8_t* WEBP_RESTRICT dst, int len) { \ 201 int i; \ 202 for (i = 0; i < len; ++i) FUNC(y[i], u[i], v[i], &dst[i * (XSTEP)]); \ 203 } 204 205 YUV444_FUNC(WebPYuv444ToRgba_C, VP8YuvToRgba, 4) 206 YUV444_FUNC(WebPYuv444ToBgra_C, VP8YuvToBgra, 4) 207 #if !defined(WEBP_REDUCE_CSP) 208 YUV444_FUNC(WebPYuv444ToRgb_C, VP8YuvToRgb, 3) 209 YUV444_FUNC(WebPYuv444ToBgr_C, VP8YuvToBgr, 3) 210 YUV444_FUNC(WebPYuv444ToArgb_C, VP8YuvToArgb, 4) 211 YUV444_FUNC(WebPYuv444ToRgba4444_C, VP8YuvToRgba4444, 2) 212 YUV444_FUNC(WebPYuv444ToRgb565_C, VP8YuvToRgb565, 2) 213 #else 214 static void EmptyYuv444Func(const uint8_t* y, 215 const uint8_t* u, const uint8_t* v, 216 uint8_t* dst, int len) { 217 (void)y; 218 (void)u; 219 (void)v; 220 (void)dst; 221 (void)len; 222 } 223 #define WebPYuv444ToRgb_C EmptyYuv444Func 224 #define WebPYuv444ToBgr_C EmptyYuv444Func 225 #define WebPYuv444ToArgb_C EmptyYuv444Func 226 #define WebPYuv444ToRgba4444_C EmptyYuv444Func 227 #define WebPYuv444ToRgb565_C EmptyYuv444Func 228 #endif // WEBP_REDUCE_CSP 229 230 #undef YUV444_FUNC 231 232 WebPYUV444Converter WebPYUV444Converters[MODE_LAST]; 233 234 extern VP8CPUInfo VP8GetCPUInfo; 235 extern void WebPInitYUV444ConvertersMIPSdspR2(void); 236 extern void WebPInitYUV444ConvertersSSE2(void); 237 extern void WebPInitYUV444ConvertersSSE41(void); 238 239 WEBP_DSP_INIT_FUNC(WebPInitYUV444Converters) { 240 WebPYUV444Converters[MODE_RGBA] = WebPYuv444ToRgba_C; 241 WebPYUV444Converters[MODE_BGRA] = WebPYuv444ToBgra_C; 242 WebPYUV444Converters[MODE_RGB] = WebPYuv444ToRgb_C; 243 WebPYUV444Converters[MODE_BGR] = WebPYuv444ToBgr_C; 244 WebPYUV444Converters[MODE_ARGB] = WebPYuv444ToArgb_C; 245 WebPYUV444Converters[MODE_RGBA_4444] = WebPYuv444ToRgba4444_C; 246 WebPYUV444Converters[MODE_RGB_565] = WebPYuv444ToRgb565_C; 247 WebPYUV444Converters[MODE_rgbA] = WebPYuv444ToRgba_C; 248 WebPYUV444Converters[MODE_bgrA] = WebPYuv444ToBgra_C; 249 WebPYUV444Converters[MODE_Argb] = WebPYuv444ToArgb_C; 250 WebPYUV444Converters[MODE_rgbA_4444] = WebPYuv444ToRgba4444_C; 251 252 if (VP8GetCPUInfo != NULL) { 253 #if defined(WEBP_HAVE_SSE2) 254 if (VP8GetCPUInfo(kSSE2)) { 255 WebPInitYUV444ConvertersSSE2(); 256 } 257 #endif 258 #if defined(WEBP_HAVE_SSE41) 259 if (VP8GetCPUInfo(kSSE4_1)) { 260 WebPInitYUV444ConvertersSSE41(); 261 } 262 #endif 263 #if defined(WEBP_USE_MIPS_DSP_R2) 264 if (VP8GetCPUInfo(kMIPSdspR2)) { 265 WebPInitYUV444ConvertersMIPSdspR2(); 266 } 267 #endif 268 } 269 } 270 271 //------------------------------------------------------------------------------ 272 // Main calls 273 274 extern void WebPInitUpsamplersSSE2(void); 275 extern void WebPInitUpsamplersSSE41(void); 276 extern void WebPInitUpsamplersNEON(void); 277 extern void WebPInitUpsamplersMIPSdspR2(void); 278 extern void WebPInitUpsamplersMSA(void); 279 280 WEBP_DSP_INIT_FUNC(WebPInitUpsamplers) { 281 #ifdef FANCY_UPSAMPLING 282 #if !WEBP_NEON_OMIT_C_CODE 283 WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair_C; 284 WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair_C; 285 WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair_C; 286 WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair_C; 287 WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair_C; 288 WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair_C; 289 WebPUpsamplers[MODE_ARGB] = UpsampleArgbLinePair_C; 290 WebPUpsamplers[MODE_RGBA_4444] = UpsampleRgba4444LinePair_C; 291 WebPUpsamplers[MODE_RGB_565] = UpsampleRgb565LinePair_C; 292 WebPUpsamplers[MODE_Argb] = UpsampleArgbLinePair_C; 293 WebPUpsamplers[MODE_rgbA_4444] = UpsampleRgba4444LinePair_C; 294 #endif 295 296 // If defined, use CPUInfo() to overwrite some pointers with faster versions. 297 if (VP8GetCPUInfo != NULL) { 298 #if defined(WEBP_HAVE_SSE2) 299 if (VP8GetCPUInfo(kSSE2)) { 300 WebPInitUpsamplersSSE2(); 301 } 302 #endif 303 #if defined(WEBP_HAVE_SSE41) 304 if (VP8GetCPUInfo(kSSE4_1)) { 305 WebPInitUpsamplersSSE41(); 306 } 307 #endif 308 #if defined(WEBP_USE_MIPS_DSP_R2) 309 if (VP8GetCPUInfo(kMIPSdspR2)) { 310 WebPInitUpsamplersMIPSdspR2(); 311 } 312 #endif 313 #if defined(WEBP_USE_MSA) 314 if (VP8GetCPUInfo(kMSA)) { 315 WebPInitUpsamplersMSA(); 316 } 317 #endif 318 } 319 320 #if defined(WEBP_HAVE_NEON) 321 if (WEBP_NEON_OMIT_C_CODE || 322 (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) { 323 WebPInitUpsamplersNEON(); 324 } 325 #endif 326 327 assert(WebPUpsamplers[MODE_RGBA] != NULL); 328 assert(WebPUpsamplers[MODE_BGRA] != NULL); 329 assert(WebPUpsamplers[MODE_rgbA] != NULL); 330 assert(WebPUpsamplers[MODE_bgrA] != NULL); 331 #if !defined(WEBP_REDUCE_CSP) || !WEBP_NEON_OMIT_C_CODE 332 assert(WebPUpsamplers[MODE_RGB] != NULL); 333 assert(WebPUpsamplers[MODE_BGR] != NULL); 334 assert(WebPUpsamplers[MODE_ARGB] != NULL); 335 assert(WebPUpsamplers[MODE_RGBA_4444] != NULL); 336 assert(WebPUpsamplers[MODE_RGB_565] != NULL); 337 assert(WebPUpsamplers[MODE_Argb] != NULL); 338 assert(WebPUpsamplers[MODE_rgbA_4444] != NULL); 339 #endif 340 341 #endif // FANCY_UPSAMPLING 342 } 343 344 //------------------------------------------------------------------------------