diff options
author | James Almer <jamrial@gmail.com> | 2015-02-01 15:01:36 -0300 |
---|---|---|
committer | James Almer <jamrial@gmail.com> | 2015-02-01 20:22:35 -0300 |
commit | fa3eccb4f9f3ecc9e2bb3c5924c2aa343b808076 (patch) | |
tree | 3cb8dd1f22abc025929deedb3cd90c672d68ad53 /libavcodec | |
parent | a1684311b3de0766932c42b1ffdd59823d786bc2 (diff) | |
download | ffmpeg-fa3eccb4f9f3ecc9e2bb3c5924c2aa343b808076.tar.gz |
x86/hevc: add ff_hevc_sao_band_filter_{8,10,12}_{sse2,avx,avx2}
Original x86 intrinsics code and initial 8bit yasm port by Pierre-Edouard Lepere.
10/12bit yasm ports, refactoring and optimizations by James Almer
Benchmarks of BQTerrace_1920x1080_60_qp22.bin with an Intel Core i5-4200U
width 32
40338 decicycles in sao_band_filter_0_8, 2048 runs, 0 skips
8056 decicycles in ff_hevc_sao_band_filter_8_32_sse2, 2048 runs, 0 skips
7458 decicycles in ff_hevc_sao_band_filter_8_32_avx, 2048 runs, 0 skips
4504 decicycles in ff_hevc_sao_band_filter_8_32_avx2, 2048 runs, 0 skips
width 64
136046 decicycles in sao_band_filter_0_8, 16384 runs, 0 skips
28576 decicycles in ff_hevc_sao_band_filter_8_32_sse2, 16384 runs, 0 skips
26707 decicycles in ff_hevc_sao_band_filter_8_32_avx, 16384 runs, 0 skips
14387 decicycles in ff_hevc_sao_band_filter_8_32_avx2, 16384 runs, 0 skips
Reviewed-by: Christophe Gisquet <christophe.gisquet@gmail.com>
Signed-off-by: James Almer <jamrial@gmail.com>
Diffstat (limited to 'libavcodec')
-rw-r--r-- | libavcodec/hevc_filter.c | 8 | ||||
-rw-r--r-- | libavcodec/hevcdsp.c | 6 | ||||
-rw-r--r-- | libavcodec/hevcdsp.h | 4 | ||||
-rw-r--r-- | libavcodec/x86/Makefile | 3 | ||||
-rw-r--r-- | libavcodec/x86/hevc_sao.asm | 238 | ||||
-rw-r--r-- | libavcodec/x86/hevcdsp_init.c | 49 |
6 files changed, 301 insertions, 7 deletions
diff --git a/libavcodec/hevc_filter.c b/libavcodec/hevc_filter.c index fb1aa373df..9354c14300 100644 --- a/libavcodec/hevc_filter.c +++ b/libavcodec/hevc_filter.c @@ -187,6 +187,7 @@ static void restore_tqb_pixels(HEVCContext *s, int x0, int y0, int width, int he static void sao_filter_CTB(HEVCContext *s, int x, int y) { + static const uint8_t band_tab[8] = { 0, 1, 2, 2, 3, 3, 4, 4 }; int c_idx; int edges[4]; // 0 left 1 top 2 right 3 bottom int x_ctb = x >> s->sps->log2_ctb_size; @@ -252,15 +253,16 @@ static void sao_filter_CTB(HEVCContext *s, int x, int y) int ctb_size_v = (1 << (s->sps->log2_ctb_size)) >> s->sps->vshift[c_idx]; int width = FFMIN(ctb_size_h, (s->sps->width >> s->sps->hshift[c_idx]) - x0); int height = FFMIN(ctb_size_v, (s->sps->height >> s->sps->vshift[c_idx]) - y0); + int tab = band_tab[(FFALIGN(width, 8) >> 3) - 1]; uint8_t *src = &s->frame->data[c_idx][y0 * stride_src + (x0 << s->sps->pixel_shift)]; uint8_t *dst = &s->sao_frame->data[c_idx][y0 * stride_dst + (x0 << s->sps->pixel_shift)]; switch (sao->type_idx[c_idx]) { case SAO_BAND: copy_CTB(dst, src, width << s->sps->pixel_shift, height, stride_dst, stride_src); - s->hevcdsp.sao_band_filter(src, dst, stride_src, stride_dst, - sao->offset_val[c_idx], sao->band_position[c_idx], - width, height); + s->hevcdsp.sao_band_filter[tab](src, dst, stride_src, stride_dst, + sao->offset_val[c_idx], sao->band_position[c_idx], + width, height); restore_tqb_pixels(s, x, y, width, height, c_idx); sao->type_idx[c_idx] = SAO_APPLIED; break; diff --git a/libavcodec/hevcdsp.c b/libavcodec/hevcdsp.c index 3eae5419dd..8acad1b86c 100644 --- a/libavcodec/hevcdsp.c +++ b/libavcodec/hevcdsp.c @@ -212,7 +212,11 @@ void ff_hevc_dsp_init(HEVCDSPContext *hevcdsp, int bit_depth) hevcdsp->idct_dc[2] = FUNC(idct_16x16_dc, depth); \ hevcdsp->idct_dc[3] = FUNC(idct_32x32_dc, depth); \ \ - hevcdsp->sao_band_filter = FUNC(sao_band_filter_0, depth); \ + hevcdsp->sao_band_filter[0] = \ + hevcdsp->sao_band_filter[1] = \ + hevcdsp->sao_band_filter[2] = \ + hevcdsp->sao_band_filter[3] = \ + hevcdsp->sao_band_filter[4] = FUNC(sao_band_filter_0, depth); \ hevcdsp->sao_edge_filter[0] = FUNC(sao_edge_filter_0, depth); \ hevcdsp->sao_edge_filter[1] = FUNC(sao_edge_filter_1, depth); \ \ diff --git a/libavcodec/hevcdsp.h b/libavcodec/hevcdsp.h index a798fb1dc4..6fb161b462 100644 --- a/libavcodec/hevcdsp.h +++ b/libavcodec/hevcdsp.h @@ -58,8 +58,8 @@ typedef struct HEVCDSPContext { void (*idct_dc[4])(int16_t *coeffs); - void (*sao_band_filter)(uint8_t *_dst, uint8_t *_src, ptrdiff_t _stride_dst, ptrdiff_t _stride_src, - int16_t *sao_offset_val, int sao_left_class, int width, int height); + void (*sao_band_filter[5])(uint8_t *_dst, uint8_t *_src, ptrdiff_t _stride_dst, ptrdiff_t _stride_src, + int16_t *sao_offset_val, int sao_left_class, int width, int height); void (*sao_edge_filter[2])(uint8_t *_dst, uint8_t *_src, ptrdiff_t _stride_dst, ptrdiff_t _stride_src, struct SAOParams *sao, int *borders, int _width, diff --git a/libavcodec/x86/Makefile b/libavcodec/x86/Makefile index 7c8e7aae63..00dacda97a 100644 --- a/libavcodec/x86/Makefile +++ b/libavcodec/x86/Makefile @@ -134,7 +134,8 @@ YASM-OBJS-$(CONFIG_DCA_DECODER) += x86/dcadsp.o YASM-OBJS-$(CONFIG_HEVC_DECODER) += x86/hevc_mc.o \ x86/hevc_deblock.o \ x86/hevc_idct.o \ - x86/hevc_res_add.o + x86/hevc_res_add.o \ + x86/hevc_sao.o YASM-OBJS-$(CONFIG_MLP_DECODER) += x86/mlpdsp.o YASM-OBJS-$(CONFIG_PNG_DECODER) += x86/pngdsp.o YASM-OBJS-$(CONFIG_PRORES_DECODER) += x86/proresdsp.o diff --git a/libavcodec/x86/hevc_sao.asm b/libavcodec/x86/hevc_sao.asm new file mode 100644 index 0000000000..7f36fd0a8b --- /dev/null +++ b/libavcodec/x86/hevc_sao.asm @@ -0,0 +1,238 @@ +;****************************************************************************** +;* SIMD optimized SAO functions for HEVC decoding +;* +;* Copyright (c) 2013 Pierre-Edouard LEPERE +;* Copyright (c) 2014 James Almer +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%include "libavutil/x86/x86util.asm" + +%if ARCH_X86_64 +SECTION_RODATA 32 + +pw_mask10: times 16 dw 0x03FF +pw_mask12: times 16 dw 0x0FFF + +SECTION_TEXT + +%macro HEVC_SAO_BAND_FILTER_INIT 1 + and leftq, 31 + movd xm0, leftd + add leftq, 1 + and leftq, 31 + movd xm1, leftd + add leftq, 1 + and leftq, 31 + movd xm2, leftd + add leftq, 1 + and leftq, 31 + movd xm3, leftd + + SPLATW m0, xm0 + SPLATW m1, xm1 + SPLATW m2, xm2 + SPLATW m3, xm3 +%if mmsize > 16 + SPLATW m4, [offsetq + 2] + SPLATW m5, [offsetq + 4] + SPLATW m6, [offsetq + 6] + SPLATW m7, [offsetq + 8] +%else + movq m7, [offsetq + 2] + SPLATW m4, m7, 0 + SPLATW m5, m7, 1 + SPLATW m6, m7, 2 + SPLATW m7, m7, 3 +%endif + +%if %1 > 8 + mova m13, [pw_mask %+ %1] +%endif + pxor m14, m14 + +DEFINE_ARGS dst, src, dststride, srcstride, offset, height + mov heightd, r7m +%endmacro + +%macro HEVC_SAO_BAND_FILTER_COMPUTE 3 + psraw %2, %3, %1-5 + pcmpeqw m10, %2, m0 + pcmpeqw m11, %2, m1 + pcmpeqw m12, %2, m2 + pcmpeqw %2, m3 + pand m10, m4 + pand m11, m5 + pand m12, m6 + pand %2, m7 + por m10, m11 + por m12, %2 + por m10, m12 + paddw %3, m10 +%endmacro + +;void ff_hevc_sao_band_filter_<width>_8_<opt>(uint8_t *_dst, uint8_t *_src, ptrdiff_t _stride_dst, ptrdiff_t _stride_src, +; int16_t *sao_offset_val, int sao_left_class, int width, int height); +%macro HEVC_SAO_BAND_FILTER_8 2 +cglobal hevc_sao_band_filter_%1_8, 6, 6, 15, dst, src, dststride, srcstride, offset, left + HEVC_SAO_BAND_FILTER_INIT 8 + +align 16 +.loop +%if %1 == 8 + movq m8, [srcq] + punpcklbw m8, m14 + HEVC_SAO_BAND_FILTER_COMPUTE 8, m9, m8 + packuswb m8, m14 + movq [dstq], m8 +%endif ; %1 == 8 + +%assign i 0 +%rep %2 + movu m13, [srcq + i] + punpcklbw m8, m13, m14 + HEVC_SAO_BAND_FILTER_COMPUTE 8, m9, m8 + punpckhbw m13, m14 + HEVC_SAO_BAND_FILTER_COMPUTE 8, m9, m13 + packuswb m8, m13 + movu [dstq + i], m8 +%assign i i+mmsize +%endrep + +%if %1 == 48 +INIT_XMM cpuname + + movu m13, [srcq + i] + punpcklbw m8, m13, m14 + HEVC_SAO_BAND_FILTER_COMPUTE 8, m9, m8 + punpckhbw m13, m14 + HEVC_SAO_BAND_FILTER_COMPUTE 8, m9, m13 + packuswb m8, m13 + movu [dstq + i], m8 +%assign i i+16 +%endif ; %1 == 48 + + add dstq, dststrideq ; dst += dststride + add srcq, srcstrideq ; src += srcstride + dec heightd ; cmp height + jnz .loop ; height loop + REP_RET +%endmacro + +;void ff_hevc_sao_band_filter_<width>_<depth>_<opt>(uint8_t *_dst, uint8_t *_src, ptrdiff_t _stride_dst, ptrdiff_t _stride_src, +; int16_t *sao_offset_val, int sao_left_class, int width, int height); +%macro HEVC_SAO_BAND_FILTER_16 3 +cglobal hevc_sao_band_filter_%2_%1, 6, 6, 15, dst, src, dststride, srcstride, offset, left + HEVC_SAO_BAND_FILTER_INIT %1 + +align 16 +.loop +%if %2 == 8 + movu m8, [srcq] + HEVC_SAO_BAND_FILTER_COMPUTE %1, m9, m8 + CLIPW m8, m14, m13 + movu [dstq], m8 +%endif + +%assign i 0 +%rep %3 + movu m8, [srcq + i] + HEVC_SAO_BAND_FILTER_COMPUTE %1, m9, m8 + CLIPW m8, m14, m13 + movu [dstq + i], m8 + + movu m9, [srcq + i + mmsize] + HEVC_SAO_BAND_FILTER_COMPUTE %1, m8, m9 + CLIPW m9, m14, m13 + movu [dstq + i + mmsize], m9 +%assign i i+mmsize*2 +%endrep + +%if %2 == 48 +INIT_XMM cpuname + movu m8, [srcq + i] + HEVC_SAO_BAND_FILTER_COMPUTE %1, m9, m8 + CLIPW m8, m14, m13 + movu [dstq + i], m8 + + movu m9, [srcq + i + mmsize] + HEVC_SAO_BAND_FILTER_COMPUTE %1, m8, m9 + CLIPW m9, m14, m13 + movu [dstq + i + mmsize], m9 +%assign i i+32 +%endif ; %1 == 48 + + add dstq, dststrideq + add srcq, srcstrideq + dec heightd + jg .loop + REP_RET +%endmacro + +%macro HEVC_SAO_BAND_FILTER_FUNCS 0 +HEVC_SAO_BAND_FILTER_8 8, 0 +HEVC_SAO_BAND_FILTER_8 16, 1 +HEVC_SAO_BAND_FILTER_8 32, 2 +HEVC_SAO_BAND_FILTER_8 48, 2 +HEVC_SAO_BAND_FILTER_8 64, 4 + +HEVC_SAO_BAND_FILTER_16 10, 8, 0 +HEVC_SAO_BAND_FILTER_16 10, 16, 1 +HEVC_SAO_BAND_FILTER_16 10, 32, 2 +HEVC_SAO_BAND_FILTER_16 10, 48, 2 +HEVC_SAO_BAND_FILTER_16 10, 64, 4 + +HEVC_SAO_BAND_FILTER_16 12, 8, 0 +HEVC_SAO_BAND_FILTER_16 12, 16, 1 +HEVC_SAO_BAND_FILTER_16 12, 32, 2 +HEVC_SAO_BAND_FILTER_16 12, 48, 2 +HEVC_SAO_BAND_FILTER_16 12, 64, 4 +%endmacro + +INIT_XMM sse2 +HEVC_SAO_BAND_FILTER_FUNCS +INIT_XMM avx +HEVC_SAO_BAND_FILTER_FUNCS + +INIT_XMM avx2 +HEVC_SAO_BAND_FILTER_8 8, 0 +HEVC_SAO_BAND_FILTER_8 16, 1 +INIT_YMM avx2 +HEVC_SAO_BAND_FILTER_8 32, 1 +HEVC_SAO_BAND_FILTER_8 48, 1 +INIT_YMM avx2 +HEVC_SAO_BAND_FILTER_8 64, 2 + +INIT_XMM avx2 +HEVC_SAO_BAND_FILTER_16 10, 8, 0 +HEVC_SAO_BAND_FILTER_16 10, 16, 1 +INIT_YMM avx2 +HEVC_SAO_BAND_FILTER_16 10, 32, 1 +HEVC_SAO_BAND_FILTER_16 10, 48, 1 +INIT_YMM avx2 +HEVC_SAO_BAND_FILTER_16 10, 64, 2 + +INIT_XMM avx2 +HEVC_SAO_BAND_FILTER_16 12, 8, 0 +HEVC_SAO_BAND_FILTER_16 12, 16, 1 +INIT_YMM avx2 +HEVC_SAO_BAND_FILTER_16 12, 32, 1 +HEVC_SAO_BAND_FILTER_16 12, 48, 1 +INIT_YMM avx2 +HEVC_SAO_BAND_FILTER_16 12, 64, 2 +%endif diff --git a/libavcodec/x86/hevcdsp_init.c b/libavcodec/x86/hevcdsp_init.c index eaa97e1434..5a01ff63cd 100644 --- a/libavcodec/x86/hevcdsp_init.c +++ b/libavcodec/x86/hevcdsp_init.c @@ -478,6 +478,27 @@ mc_bi_w_funcs(qpel_v, 12, sse4); mc_bi_w_funcs(qpel_hv, 12, sse4); #endif //ARCH_X86_64 && HAVE_SSE4_EXTERNAL +#define SAO_BAND_FILTER_FUNCS(bitd, opt) \ +void ff_hevc_sao_band_filter_8_##bitd##_##opt(uint8_t *_dst, uint8_t *_src, ptrdiff_t _stride_dst, ptrdiff_t _stride_src, \ + int16_t *sao_offset_val, int sao_left_class, int width, int height); \ +void ff_hevc_sao_band_filter_16_##bitd##_##opt(uint8_t *_dst, uint8_t *_src, ptrdiff_t _stride_dst, ptrdiff_t _stride_src, \ + int16_t *sao_offset_val, int sao_left_class, int width, int height); \ +void ff_hevc_sao_band_filter_32_##bitd##_##opt(uint8_t *_dst, uint8_t *_src, ptrdiff_t _stride_dst, ptrdiff_t _stride_src, \ + int16_t *sao_offset_val, int sao_left_class, int width, int height); \ +void ff_hevc_sao_band_filter_48_##bitd##_##opt(uint8_t *_dst, uint8_t *_src, ptrdiff_t _stride_dst, ptrdiff_t _stride_src, \ + int16_t *sao_offset_val, int sao_left_class, int width, int height); \ +void ff_hevc_sao_band_filter_64_##bitd##_##opt(uint8_t *_dst, uint8_t *_src, ptrdiff_t _stride_dst, ptrdiff_t _stride_src, \ + int16_t *sao_offset_val, int sao_left_class, int width, int height) + +SAO_BAND_FILTER_FUNCS(8, sse2); +SAO_BAND_FILTER_FUNCS(10, sse2); +SAO_BAND_FILTER_FUNCS(12, sse2); +SAO_BAND_FILTER_FUNCS(8, avx); +SAO_BAND_FILTER_FUNCS(10, avx); +SAO_BAND_FILTER_FUNCS(12, avx); +SAO_BAND_FILTER_FUNCS(8, avx2); +SAO_BAND_FILTER_FUNCS(10, avx2); +SAO_BAND_FILTER_FUNCS(12, avx2); #define EPEL_LINKS(pointer, my, mx, fname, bitd, opt ) \ PEL_LINK(pointer, 1, my , mx , fname##4 , bitd, opt ); \ @@ -499,6 +520,13 @@ mc_bi_w_funcs(qpel_hv, 12, sse4); PEL_LINK(pointer, 8, my , mx , fname##48, bitd, opt ); \ PEL_LINK(pointer, 9, my , mx , fname##64, bitd, opt ) +#define SAO_BAND_INIT(bitd, opt) do { \ + c->sao_band_filter[0] = ff_hevc_sao_band_filter_8_##bitd##_##opt; \ + c->sao_band_filter[1] = ff_hevc_sao_band_filter_16_##bitd##_##opt; \ + c->sao_band_filter[2] = ff_hevc_sao_band_filter_32_##bitd##_##opt; \ + c->sao_band_filter[3] = ff_hevc_sao_band_filter_48_##bitd##_##opt; \ + c->sao_band_filter[4] = ff_hevc_sao_band_filter_64_##bitd##_##opt; \ +} while (0) void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth) { @@ -516,6 +544,8 @@ void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth) if (ARCH_X86_64) { c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_8_sse2; c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_8_sse2; + + SAO_BAND_INIT(8, sse2); } c->idct_dc[1] = ff_hevc_idct8x8_dc_8_sse2; c->idct_dc[2] = ff_hevc_idct16x16_dc_8_sse2; @@ -547,6 +577,8 @@ void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth) if (ARCH_X86_64) { c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_8_avx; c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_8_avx; + + SAO_BAND_INIT(8, avx); } c->transform_add[1] = ff_hevc_transform_add8_8_avx; c->transform_add[2] = ff_hevc_transform_add16_8_avx; @@ -555,6 +587,9 @@ void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth) if (EXTERNAL_AVX2(cpu_flags)) { c->idct_dc[2] = ff_hevc_idct16x16_dc_8_avx2; c->idct_dc[3] = ff_hevc_idct32x32_dc_8_avx2; + if (ARCH_X86_64) { + SAO_BAND_INIT(8, avx2); + } c->transform_add[3] = ff_hevc_transform_add32_8_avx2; } @@ -570,6 +605,8 @@ void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth) if (ARCH_X86_64) { c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_10_sse2; c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_10_sse2; + + SAO_BAND_INIT(10, sse2); } c->idct_dc[1] = ff_hevc_idct8x8_dc_10_sse2; @@ -601,12 +638,17 @@ void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth) if (ARCH_X86_64) { c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_10_avx; c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_10_avx; + + SAO_BAND_INIT(10, avx); } } if (EXTERNAL_AVX2(cpu_flags)) { c->idct_dc[2] = ff_hevc_idct16x16_dc_10_avx2; c->idct_dc[3] = ff_hevc_idct32x32_dc_10_avx2; + if (ARCH_X86_64) { + SAO_BAND_INIT(10, avx2); + } c->transform_add[2] = ff_hevc_transform_add16_10_avx2; c->transform_add[3] = ff_hevc_transform_add32_10_avx2; @@ -623,6 +665,8 @@ void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth) if (ARCH_X86_64) { c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_12_sse2; c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_12_sse2; + + SAO_BAND_INIT(12, sse2); } c->idct_dc[1] = ff_hevc_idct8x8_dc_12_sse2; @@ -650,11 +694,16 @@ void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth) if (ARCH_X86_64) { c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_12_avx; c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_12_avx; + + SAO_BAND_INIT(12, avx); } } if (EXTERNAL_AVX2(cpu_flags)) { c->idct_dc[2] = ff_hevc_idct16x16_dc_12_avx2; c->idct_dc[3] = ff_hevc_idct32x32_dc_12_avx2; + if (ARCH_X86_64) { + SAO_BAND_INIT(12, avx2); + } } } } |