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 | 54 | void GeneralBilinearFastDownsampler_ref (uint8_t* pDst, const int32_t kiDstStride, const int32_t kiDstWidth, |
| 34 | 55 | const int32_t kiDstHeight, |
| 35 | 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 | 187 | TEST (DownSampleTest, func) { \ |
| 167 | 188 | if (ASM) {\ |
| 168 | 189 | int32_t iCpuCores = 0; \ |
| @@ -190,7 +211,7 @@ TEST (DownSampleTest, func) { \ · 21 unmodified lines | ||
| 190 | 211 | dst_c[j] = dst_a[j] = rand() % 256; \ |
| 191 | 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 | 215 | func (dst_a, dst_stride_a, src_a, src_stride_a, src_width_a, src_height_a); \ |
| 195 | 216 | for (int j = 0; j < (src_height_c >> 1); j++) { \ |
| 196 | 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 | 228 | #define GENERATE_DyadicBilinearOneThirdDownsampler_UT(func, ASM, CPUFLAGS) \ |
| 203 | 229 | TEST (DownSampleTest, func) { \ |
| 204 | 230 | if (ASM) {\ |
| @@ -328,11 +354,8 @@ GENERATE_DyadicBilinearDownsampler_UT (DyadicBilinearDownsamplerWidthx32_sse, 1, · 123 unmodified lines | ||
| 328 | 354 | GENERATE_DyadicBilinearDownsampler_UT (DyadicBilinearDownsamplerWidthx16_sse, 1, WELS_CPU_SSE) |
| 329 | 355 | GENERATE_DyadicBilinearDownsampler_UT (DyadicBilinearDownsamplerWidthx8_sse, 1, WELS_CPU_SSE) |
| 330 | 356 | |
| 331 | −GENERATE_DyadicBilinearDownsampler_UT (DyadicBilinearDownsamplerWidthx32_ssse3, 1, WELS_CPU_SSSE3) | |
| 332 | −GENERATE_DyadicBilinearDownsampler_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) | |
| 357 | +GENERATE_DyadicBilinearDownsampler2_UT (DyadicBilinearDownsamplerWidthx32_ssse3, 1, WELS_CPU_SSSE3) | |
| 358 | +GENERATE_DyadicBilinearDownsampler2_UT (DyadicBilinearDownsamplerWidthx16_ssse3, 1, WELS_CPU_SSSE3) | |
| 336 | 359 | |
| 337 | 360 | GENERATE_DyadicBilinearOneThirdDownsampler_UT (DyadicBilinearOneThirdDownsampler_ssse3, 1, WELS_CPU_SSSE3) |
| 338 | 361 | GENERATE_DyadicBilinearOneThirdDownsampler_UT (DyadicBilinearOneThirdDownsampler_sse4, 1, WELS_CPU_SSE41) |