[FFmpeg-devel] [PATCH v3 3/4] avcodec/mips: Optimize function ff_h264_loop_filter_strength_msa.

Shiyou Yin yinshiyou-hf at loongson.cn
Tue Oct 20 06:45:43 EEST 2020


From: gxw <guxiwei-hf at loongson.cn>

Speed of decoding H264: 5.45x ==> 5.53x

Signed-off-by: Shiyou Yin <yinshiyou-hf at loongson.cn>
---
 libavcodec/mips/Makefile            |   3 +-
 libavcodec/mips/h264_deblock_msa.c  | 153 ++++++++++++++++++++++++++++++++++++
 libavcodec/mips/h264dsp_init_mips.c |   2 +
 libavcodec/mips/h264dsp_mips.h      |   4 +
 4 files changed, 161 insertions(+), 1 deletion(-)
 create mode 100644 libavcodec/mips/h264_deblock_msa.c

diff --git a/libavcodec/mips/Makefile b/libavcodec/mips/Makefile
index 2be4d9b..81a73a4 100644
--- a/libavcodec/mips/Makefile
+++ b/libavcodec/mips/Makefile
@@ -57,7 +57,8 @@ MSA-OBJS-$(CONFIG_VP8_DECODER)            += mips/vp8_mc_msa.o             \
                                              mips/vp8_lpf_msa.o
 MSA-OBJS-$(CONFIG_VP3DSP)                 += mips/vp3dsp_idct_msa.o
 MSA-OBJS-$(CONFIG_H264DSP)                += mips/h264dsp_msa.o            \
-                                             mips/h264idct_msa.o
+                                             mips/h264idct_msa.o           \
+                                             mips/h264_deblock_msa.o
 MSA-OBJS-$(CONFIG_H264QPEL)               += mips/h264qpel_msa.o
 MSA-OBJS-$(CONFIG_H264CHROMA)             += mips/h264chroma_msa.o
 MSA-OBJS-$(CONFIG_H264PRED)               += mips/h264pred_msa.o
diff --git a/libavcodec/mips/h264_deblock_msa.c b/libavcodec/mips/h264_deblock_msa.c
new file mode 100644
index 0000000..4fed55c
--- /dev/null
+++ b/libavcodec/mips/h264_deblock_msa.c
@@ -0,0 +1,153 @@
+/*
+ * MIPS SIMD optimized H.264 deblocking code
+ *
+ * Copyright (c) 2020 Loongson Technology Corporation Limited
+ *                    Gu Xiwei <guxiwei-hf at loongson.cn>
+ *
+ * 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 "libavcodec/bit_depth_template.c"
+#include "h264dsp_mips.h"
+#include "libavutil/mips/generic_macros_msa.h"
+#include "libavcodec/mips/h264dsp_mips.h"
+
+#define h264_loop_filter_strength_iteration_msa(edges, step, mask_mv, dir, \
+                                                d_idx, mask_dir)           \
+do {                                                                       \
+    int b_idx = 0; \
+    int step_x4 = step << 2; \
+    int d_idx_12 = d_idx + 12; \
+    int d_idx_52 = d_idx + 52; \
+    int d_idx_x4 = d_idx << 2; \
+    int d_idx_x4_48 = d_idx_x4 + 48; \
+    int dir_x32  = dir * 32; \
+    uint8_t *ref_t = (uint8_t*)ref; \
+    uint8_t *mv_t  = (uint8_t*)mv; \
+    uint8_t *nnz_t = (uint8_t*)nnz; \
+    uint8_t *bS_t  = (uint8_t*)bS; \
+    mask_mv <<= 3; \
+    for (; b_idx < edges; b_idx += step) { \
+        out &= mask_dir; \
+        if (!(mask_mv & b_idx)) { \
+            if (bidir) { \
+                ref_2 = LD_SB(ref_t + d_idx_12); \
+                ref_3 = LD_SB(ref_t + d_idx_52); \
+                ref_0 = LD_SB(ref_t + 12); \
+                ref_1 = LD_SB(ref_t + 52); \
+                ref_2 = (v16i8)__msa_ilvr_w((v4i32)ref_3, (v4i32)ref_2); \
+                ref_0 = (v16i8)__msa_ilvr_w((v4i32)ref_0, (v4i32)ref_0); \
+                ref_1 = (v16i8)__msa_ilvr_w((v4i32)ref_1, (v4i32)ref_1); \
+                ref_3 = (v16i8)__msa_shf_h((v8i16)ref_2, 0x4e); \
+                ref_0 -= ref_2; \
+                ref_1 -= ref_3; \
+                ref_0 = (v16i8)__msa_or_v((v16u8)ref_0, (v16u8)ref_1); \
+\
+                tmp_2 = LD_SH(mv_t + d_idx_x4_48);   \
+                tmp_3 = LD_SH(mv_t + 48); \
+                tmp_4 = LD_SH(mv_t + 208); \
+                tmp_5 = tmp_2 - tmp_3; \
+                tmp_6 = tmp_2 - tmp_4; \
+                SAT_SH2_SH(tmp_5, tmp_6, 7); \
+                tmp_0 = __msa_pckev_b((v16i8)tmp_6, (v16i8)tmp_5); \
+                tmp_0 += cnst_1; \
+                tmp_0 = (v16i8)__msa_subs_u_b((v16u8)tmp_0, (v16u8)cnst_0);\
+                tmp_0 = (v16i8)__msa_sat_s_h((v8i16)tmp_0, 7); \
+                tmp_0 = __msa_pckev_b(tmp_0, tmp_0); \
+                out   = (v16i8)__msa_or_v((v16u8)ref_0, (v16u8)tmp_0); \
+\
+                tmp_2 = LD_SH(mv_t + 208 + d_idx_x4); \
+                tmp_5 = tmp_2 - tmp_3; \
+                tmp_6 = tmp_2 - tmp_4; \
+                SAT_SH2_SH(tmp_5, tmp_6, 7); \
+                tmp_1 = __msa_pckev_b((v16i8)tmp_6, (v16i8)tmp_5); \
+                tmp_1 += cnst_1; \
+                tmp_1 = (v16i8)__msa_subs_u_b((v16u8)tmp_1, (v16u8)cnst_0); \
+                tmp_1 = (v16i8)__msa_sat_s_h((v8i16)tmp_1, 7); \
+                tmp_1 = __msa_pckev_b(tmp_1, tmp_1); \
+\
+                tmp_1 = (v16i8)__msa_shf_h((v8i16)tmp_1, 0x4e); \
+                out   = (v16i8)__msa_or_v((v16u8)out, (v16u8)tmp_1); \
+                tmp_0 = (v16i8)__msa_shf_h((v8i16)out, 0x4e); \
+                out   = (v16i8)__msa_min_u_b((v16u8)out, (v16u8)tmp_0); \
+            } else { \
+                ref_0 = LD_SB(ref_t + d_idx_12); \
+                ref_3 = LD_SB(ref_t + 12); \
+                tmp_2 = LD_SH(mv_t + d_idx_x4_48); \
+                tmp_3 = LD_SH(mv_t + 48); \
+                tmp_4 = tmp_3 - tmp_2; \
+                tmp_1 = (v16i8)__msa_sat_s_h(tmp_4, 7); \
+                tmp_1 = __msa_pckev_b(tmp_1, tmp_1); \
+                tmp_1 += cnst_1; \
+                out   = (v16i8)__msa_subs_u_b((v16u8)tmp_1, (v16u8)cnst_0); \
+                out   = (v16i8)__msa_sat_s_h((v8i16)out, 7); \
+                out   = __msa_pckev_b(out, out); \
+                ref_0 = ref_3 - ref_0; \
+                out   = (v16i8)__msa_or_v((v16u8)out, (v16u8)ref_0); \
+            } \
+        } \
+        tmp_0 = LD_SB(nnz_t + 12); \
+        tmp_1 = LD_SB(nnz_t + d_idx_12); \
+        tmp_0 = (v16i8)__msa_or_v((v16u8)tmp_0, (v16u8)tmp_1); \
+        tmp_0 = (v16i8)__msa_min_u_b((v16u8)tmp_0, (v16u8)cnst_2); \
+        out   = (v16i8)__msa_min_u_b((v16u8)out, (v16u8)cnst_2); \
+        tmp_0 = (v16i8)((v8i16)tmp_0 << 1); \
+        tmp_0 = (v16i8)__msa_max_u_b((v16u8)out, (v16u8)tmp_0); \
+        tmp_0 = __msa_ilvr_b(zero, tmp_0); \
+        ST_D1(tmp_0, 0, bS_t + dir_x32); \
+        ref_t += step; \
+        mv_t  += step_x4; \
+        nnz_t += step; \
+        bS_t  += step; \
+    } \
+} while(0)
+
+void ff_h264_loop_filter_strength_msa(int16_t bS[2][4][4], uint8_t nnz[40],
+                                      int8_t ref[2][40], int16_t mv[2][40][2],
+                                      int bidir, int edges, int step,
+                                      int mask_mv0, int mask_mv1, int field)
+{
+    v16i8 out;
+    v16i8 ref_0, ref_1, ref_2, ref_3;
+    v16i8 tmp_0, tmp_1;
+    v8i16 tmp_2, tmp_3, tmp_4, tmp_5, tmp_6;
+    v16i8 cnst_0, cnst_1, cnst_2;
+    v16i8 zero = { 0 };
+    v16i8 one  = __msa_fill_b(0xff);
+    if (field) {
+        cnst_0 = (v16i8)__msa_fill_h(0x206);
+        cnst_1 = (v16i8)__msa_fill_h(0x103);
+        cnst_2 = (v16i8)__msa_fill_h(0x101);
+    } else {
+        cnst_0 = __msa_fill_b(0x6);
+        cnst_1 = __msa_fill_b(0x3);
+        cnst_2 = __msa_fill_b(0x1);
+    }
+    step  <<= 3;
+    edges <<= 3;
+
+    h264_loop_filter_strength_iteration_msa(edges, step, mask_mv1, 1, -8, zero);
+    h264_loop_filter_strength_iteration_msa(32, 8, mask_mv0, 0, -1, one);
+
+    LD_SB2((int8_t*)bS, 16, tmp_0, tmp_1);
+    tmp_2 = (v8i16)__msa_ilvl_d((v2i64)tmp_0, (v2i64)tmp_0);
+    tmp_3 = (v8i16)__msa_ilvl_d((v2i64)tmp_1, (v2i64)tmp_1);
+    TRANSPOSE4x4_SH_SH(tmp_0, tmp_2, tmp_1, tmp_3, tmp_2, tmp_3, tmp_4, tmp_5);
+    tmp_0 = (v16i8)__msa_ilvr_d((v2i64)tmp_3, (v2i64)tmp_2);
+    tmp_1 = (v16i8)__msa_ilvr_d((v2i64)tmp_5, (v2i64)tmp_4);
+    ST_SB2(tmp_0, tmp_1, (int8_t*)bS, 16);
+}
diff --git a/libavcodec/mips/h264dsp_init_mips.c b/libavcodec/mips/h264dsp_init_mips.c
index 9cd05e0..f822c38 100644
--- a/libavcodec/mips/h264dsp_init_mips.c
+++ b/libavcodec/mips/h264dsp_init_mips.c
@@ -78,6 +78,8 @@ av_cold void ff_h264dsp_init_mips(H264DSPContext *c, const int bit_depth,
     }
 
     if (have_msa(cpu_flags)) {
+        if (chroma_format_idc <= 1)
+            c->h264_loop_filter_strength = ff_h264_loop_filter_strength_msa;
         if (bit_depth == 8) {
             c->h264_v_loop_filter_luma = ff_h264_v_lpf_luma_inter_msa;
             c->h264_h_loop_filter_luma = ff_h264_h_lpf_luma_inter_msa;
diff --git a/libavcodec/mips/h264dsp_mips.h b/libavcodec/mips/h264dsp_mips.h
index 35e16c4..5847ef3 100644
--- a/libavcodec/mips/h264dsp_mips.h
+++ b/libavcodec/mips/h264dsp_mips.h
@@ -319,6 +319,10 @@ void ff_vp8_pred8x8_129_dc_8_msa(uint8_t *src, ptrdiff_t stride);
 void ff_vp8_pred16x16_127_dc_8_msa(uint8_t *src, ptrdiff_t stride);
 void ff_vp8_pred16x16_129_dc_8_msa(uint8_t *src, ptrdiff_t stride);
 
+void ff_h264_loop_filter_strength_msa(int16_t bS[2][4][4], uint8_t nnz[40],
+        int8_t ref[2][40], int16_t mv[2][40][2], int bidir, int edges,
+        int step, int mask_mv0, int mask_mv1, int field);
+
 void ff_h264_add_pixels4_8_mmi(uint8_t *_dst, int16_t *_src, int stride);
 void ff_h264_idct_add_8_mmi(uint8_t *dst, int16_t *block, int stride);
 void ff_h264_idct8_add_8_mmi(uint8_t *dst, int16_t *block, int stride);
-- 
2.1.0



More information about the ffmpeg-devel mailing list