Average vertically before horizontally; horizontal averaging is more worksome. Doing the vertical averaging first reduces the number of horizontal averages by half. Use pmaddubsw and pavgw to do the horizontal averaging for a slight performance improvement. Minor tweaks. Improve the SSSE3 dyadic downsample routines and drop the SSE4 routines. The non-temporal loads used in the SSE4 routines do nothing for cache- backed memory AFAIK. Adjust tests because averaging vertically first gives slightly different output. ~2.39x speedup for the widthx32 routine on Haswell when not memory-bound. ~2.20x speedup for the widthx16 routine on Haswell when not memory-bound. Note that the widthx16 routine can be unrolled for further speedup.
Showing the changes to test/processing/ProcessUT_DownSample.cpp (1 of 7 files). Show all
Unified · Split
| @@ -30,6 +30,27 @@ void DyadicBilinearDownsampler_ref (uint8_t* pDst, const int32_t kiDstStride, · 29 unmodified lines | |||
| 30 | } | 30 | } |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | void DyadicBilinearDownsampler2_ref (uint8_t* pDst, const int32_t kiDstStride, | ||
| 34 | const uint8_t* pSrc, const int32_t kiSrcStride, | ||
| 35 | const int32_t kiSrcWidth, const int32_t kiSrcHeight) { | ||
| 36 | uint8_t* pDstLine = pDst; | ||
| 37 | const uint8_t* pSrcLine1 = pSrc; | ||
| 38 | const uint8_t* pSrcLine2 = pSrc + kiSrcStride; | ||
| 39 | const int32_t kiDstWidth = kiSrcWidth >> 1; | ||
| 40 | const int32_t kiDstHeight = kiSrcHeight >> 1; | ||
| 41 | |||
| 42 | for (int32_t j = 0; j < kiDstHeight; j++) { | ||
| 43 | for (int32_t i = 0; i < kiDstWidth; i++) { | ||
| 44 | const int32_t kiTempCol1 = (pSrcLine1[2 * i + 0] + pSrcLine2[2 * i + 0] + 1) >> 1; | ||
| 45 | const int32_t kiTempCol2 = (pSrcLine1[2 * i + 1] + pSrcLine2[2 * i + 1] + 1) >> 1; | ||
| 46 | pDstLine[i] = (uint8_t) ((kiTempCol1 + kiTempCol2 + 1) >> 1); | ||
| 47 | } | ||
| 48 | pDstLine += kiDstStride; | ||
| 49 | pSrcLine1 += 2 * kiSrcStride; | ||
| 50 | pSrcLine2 += 2 * kiSrcStride; | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 33 | void GeneralBilinearFastDownsampler_ref (uint8_t* pDst, const int32_t kiDstStride, const int32_t kiDstWidth, | 54 | void GeneralBilinearFastDownsampler_ref (uint8_t* pDst, const int32_t kiDstStride, const int32_t kiDstWidth, |
| 34 | const int32_t kiDstHeight, | 55 | const int32_t kiDstHeight, |
| 35 | uint8_t* pSrc, const int32_t kiSrcStride, const int32_t kiSrcWidth, const int32_t kiSrcHeight) { | 56 | uint8_t* pSrc, const int32_t kiSrcStride, const int32_t kiSrcWidth, const int32_t kiSrcHeight) { |
| @@ -162,7 +183,7 @@ void GeneralBilinearAccurateDownsampler_ref (uint8_t* pDst, const int32_t kiDstS · 126 unmodified lines | |||
| 162 | } | 183 | } |
| 163 | } | 184 | } |
| 164 | 185 | ||
| 165 | #define GENERATE_DyadicBilinearDownsampler_UT(func, ASM, CPUFLAGS) \ | 186 | #define GENERATE_DyadicBilinearDownsampler_UT_with_ref(func, ASM, CPUFLAGS, ref_func) \ |
| 166 | TEST (DownSampleTest, func) { \ | 187 | TEST (DownSampleTest, func) { \ |
| 167 | if (ASM) {\ | 188 | if (ASM) {\ |
| 168 | int32_t iCpuCores = 0; \ | 189 | int32_t iCpuCores = 0; \ |
| @@ -190,7 +211,7 @@ TEST (DownSampleTest, func) { \ · 21 unmodified lines | |||
| 190 | dst_c[j] = dst_a[j] = rand() % 256; \ | 211 | dst_c[j] = dst_a[j] = rand() % 256; \ |
| 191 | src_c[j] = src_a[j] = rand() % 256; \ | 212 | src_c[j] = src_a[j] = rand() % 256; \ |
| 192 | } \ | 213 | } \ |
| 193 | DyadicBilinearDownsampler_ref (dst_c, dst_stride_c, src_c, src_stride_c, src_width_c, src_height_c); \ | 214 | ref_func (dst_c, dst_stride_c, src_c, src_stride_c, src_width_c, src_height_c); \ |
| 194 | func (dst_a, dst_stride_a, src_a, src_stride_a, src_width_a, src_height_a); \ | 215 | func (dst_a, dst_stride_a, src_a, src_stride_a, src_width_a, src_height_a); \ |
| 195 | for (int j = 0; j < (src_height_c >> 1); j++) { \ | 216 | for (int j = 0; j < (src_height_c >> 1); j++) { \ |
| 196 | for (int m = 0; m < (src_width_c >> 1); m++) { \ | 217 | for (int m = 0; m < (src_width_c >> 1); m++) { \ |
| @@ -199,6 +220,11 @@ TEST (DownSampleTest, func) { \ · 2 unmodified lines | |||
| 199 | } \ | 220 | } \ |
| 200 | } | 221 | } |
| 201 | 222 | ||
| 223 | #define GENERATE_DyadicBilinearDownsampler_UT(func, ASM, CPUFLAGS) \ | ||
| 224 | GENERATE_DyadicBilinearDownsampler_UT_with_ref(func, ASM, CPUFLAGS, DyadicBilinearDownsampler_ref) | ||
| 225 | #define GENERATE_DyadicBilinearDownsampler2_UT(func, ASM, CPUFLAGS) \ | ||
| 226 | GENERATE_DyadicBilinearDownsampler_UT_with_ref(func, ASM, CPUFLAGS, DyadicBilinearDownsampler2_ref) | ||
| 227 | |||
| 202 | #define GENERATE_DyadicBilinearOneThirdDownsampler_UT(func, ASM, CPUFLAGS) \ | 228 | #define GENERATE_DyadicBilinearOneThirdDownsampler_UT(func, ASM, CPUFLAGS) \ |
| 203 | TEST (DownSampleTest, func) { \ | 229 | TEST (DownSampleTest, func) { \ |
| 204 | if (ASM) {\ | 230 | if (ASM) {\ |
| @@ -328,11 +354,8 @@ GENERATE_DyadicBilinearDownsampler_UT (DyadicBilinearDownsamplerWidthx32_sse, 1, · 123 unmodified lines | |||
| 328 | GENERATE_DyadicBilinearDownsampler_UT (DyadicBilinearDownsamplerWidthx16_sse, 1, WELS_CPU_SSE) | 354 | GENERATE_DyadicBilinearDownsampler_UT (DyadicBilinearDownsamplerWidthx16_sse, 1, WELS_CPU_SSE) |
| 329 | GENERATE_DyadicBilinearDownsampler_UT (DyadicBilinearDownsamplerWidthx8_sse, 1, WELS_CPU_SSE) | 355 | GENERATE_DyadicBilinearDownsampler_UT (DyadicBilinearDownsamplerWidthx8_sse, 1, WELS_CPU_SSE) |
| 330 | 356 | ||
| 331 | GENERATE_DyadicBilinearDownsampler_UT (DyadicBilinearDownsamplerWidthx32_ssse3, 1, WELS_CPU_SSSE3) | 357 | GENERATE_DyadicBilinearDownsampler2_UT (DyadicBilinearDownsamplerWidthx32_ssse3, 1, WELS_CPU_SSSE3) |
| 332 | GENERATE_DyadicBilinearDownsampler_UT (DyadicBilinearDownsamplerWidthx16_ssse3, 1, WELS_CPU_SSSE3) | 358 | GENERATE_DyadicBilinearDownsampler2_UT (DyadicBilinearDownsamplerWidthx16_ssse3, 1, WELS_CPU_SSSE3) |
| 333 | |||
| 334 | GENERATE_DyadicBilinearDownsampler_UT (DyadicBilinearDownsamplerWidthx32_sse4, 1, WELS_CPU_SSE41) | ||
| 335 | GENERATE_DyadicBilinearDownsampler_UT (DyadicBilinearDownsamplerWidthx16_sse4, 1, WELS_CPU_SSE41) | ||
| 336 | 359 | ||
| 337 | GENERATE_DyadicBilinearOneThirdDownsampler_UT (DyadicBilinearOneThirdDownsampler_ssse3, 1, WELS_CPU_SSSE3) | 360 | GENERATE_DyadicBilinearOneThirdDownsampler_UT (DyadicBilinearOneThirdDownsampler_ssse3, 1, WELS_CPU_SSSE3) |
| 338 | GENERATE_DyadicBilinearOneThirdDownsampler_UT (DyadicBilinearOneThirdDownsampler_sse4, 1, WELS_CPU_SSE41) | 361 | GENERATE_DyadicBilinearOneThirdDownsampler_UT (DyadicBilinearOneThirdDownsampler_sse4, 1, WELS_CPU_SSE41) |