diff --git a/libavcodec/h264_cabac.c b/libavcodec/h264_cabac.c index 815149a501..d4ddcba9e7 100644 --- a/libavcodec/h264_cabac.c +++ b/libavcodec/h264_cabac.c @@ -44,6 +44,8 @@ #if ARCH_X86 #include "x86/h264_cabac.c" +#elif ARCH_LOONGARCH64 +#include "loongarch/h264_cabac.c" #endif /* Cabac pre state table */ diff --git a/libavcodec/h264pred.c b/libavcodec/h264pred.c index 5632a58fd7..718f2819ce 100644 --- a/libavcodec/h264pred.c +++ b/libavcodec/h264pred.c @@ -600,4 +600,6 @@ av_cold void ff_h264_pred_init(H264PredContext *h, int codec_id, ff_h264_pred_init_x86(h, codec_id, bit_depth, chroma_format_idc); if (ARCH_MIPS) ff_h264_pred_init_mips(h, codec_id, bit_depth, chroma_format_idc); + if (ARCH_LOONGARCH) + ff_h264_pred_init_loongarch(h, codec_id, bit_depth, chroma_format_idc); } diff --git a/libavcodec/h264pred.h b/libavcodec/h264pred.h index 2863dc9bd1..4583052dfe 100644 --- a/libavcodec/h264pred.h +++ b/libavcodec/h264pred.h @@ -122,5 +122,7 @@ void ff_h264_pred_init_x86(H264PredContext *h, int codec_id, const int bit_depth, const int chroma_format_idc); void ff_h264_pred_init_mips(H264PredContext *h, int codec_id, const int bit_depth, const int chroma_format_idc); +void ff_h264_pred_init_loongarch(H264PredContext *h, int codec_id, + const int bit_depth, const int chroma_format_idc); #endif /* AVCODEC_H264PRED_H */ diff --git a/libavcodec/loongarch/Makefile b/libavcodec/loongarch/Makefile index d82eef4fd0..583e3545eb 100644 --- a/libavcodec/loongarch/Makefile +++ b/libavcodec/loongarch/Makefile @@ -8,6 +8,7 @@ OBJS-$(CONFIG_HEVC_DECODER) += loongarch/hevcdsp_init_loongarch.o OBJS-$(CONFIG_VP8_DECODER) += loongarch/vp8dsp_init_loongarch.o OBJS-$(CONFIG_VP9_DECODER) += loongarch/vp9dsp_init_loongarch.o OBJS-$(CONFIG_VIDEODSP) += loongarch/videodsp_init.o +OBJS-$(CONFIG_H264PRED) += loongarch/h264_intrapred_init_loongarch.o LASX-OBJS-$(CONFIG_H264DSP) += loongarch/h264dsp_lasx.o \ loongarch/h264idct_lasx.o \ loongarch/h264_deblock_lasx.o @@ -17,6 +18,7 @@ LASX-OBJS-$(CONFIG_IDCTDSP) += loongarch/simple_idct_lasx.o \ loongarch/idctdsp_lasx.o LASX-OBJS-$(CONFIG_VC1_DECODER) += loongarch/vc1dsp_lasx.o LASX-OBJS-$(CONFIG_HPELDSP) += loongarch/hpeldsp_lasx.o +LASX-OBJS-$(CONFIG_H264PRED) += loongarch/h264_intrapred_lasx.o LSX-OBJS-$(CONFIG_HEVC_DECODER) += loongarch/hevcdsp_lsx.o LSX-OBJS-$(CONFIG_HEVC_DECODER) += loongarch/hevc_idct_lsx.o LSX-OBJS-$(CONFIG_HEVC_DECODER) += loongarch/hevc_mc_bi_lsx.o diff --git a/libavcodec/loongarch/cabac.h b/libavcodec/loongarch/cabac.h index c0e17e3462..ea937665b4 100644 --- a/libavcodec/loongarch/cabac.h +++ b/libavcodec/loongarch/cabac.h @@ -28,67 +28,105 @@ #include "libavcodec/cabac.h" #include "config.h" +#define GET_CABAC_LOONGARCH \ + "ld.bu %[bit], %[state], 0x0 \n\t" \ + "andi %[tmp0], %[c_range], 0xC0 \n\t" \ + "slli.d %[tmp0], %[tmp0], 0x01 \n\t" \ + "add.d %[tmp0], %[tmp0], %[tables] \n\t" \ + "add.d %[tmp0], %[tmp0], %[bit] \n\t" \ + /* tmp1: RangeLPS */ \ + "ld.bu %[tmp1], %[tmp0], %[lps_off] \n\t" \ + \ + "sub.d %[c_range], %[c_range], %[tmp1] \n\t" \ + "slli.d %[tmp0], %[c_range], 0x11 \n\t" \ + "bge %[tmp0], %[c_low], 1f \n\t" \ + "move %[c_range], %[tmp1] \n\t" \ + "nor %[bit], %[bit], %[bit] \n\t" \ + "sub.d %[c_low], %[c_low], %[tmp0] \n\t" \ + \ + "1: \n\t" \ + /* tmp1: *state */ \ + "add.d %[tmp0], %[tables], %[bit] \n\t" \ + "ld.bu %[tmp1], %[tmp0], %[mlps_off] \n\t" \ + /* tmp2: lps_mask */ \ + "add.d %[tmp0], %[tables], %[c_range] \n\t" \ + "ld.bu %[tmp2], %[tmp0], %[norm_off] \n\t" \ + \ + "andi %[bit], %[bit], 0x01 \n\t" \ + "st.b %[tmp1], %[state], 0x0 \n\t" \ + "sll.d %[c_range], %[c_range], %[tmp2] \n\t" \ + "sll.d %[c_low], %[c_low], %[tmp2] \n\t" \ + \ + "and %[tmp1], %[c_low], %[cabac_mask] \n\t" \ + "bnez %[tmp1], 1f \n\t" \ + "ld.hu %[tmp1], %[c_bytestream], 0x0 \n\t" \ + "ctz.d %[tmp0], %[c_low] \n\t" \ + "addi.d %[tmp2], %[tmp0], -16 \n\t" \ + "revb.2h %[tmp0], %[tmp1] \n\t" \ + "slli.d %[tmp0], %[tmp0], 0x01 \n\t" \ + "sub.d %[tmp0], %[tmp0], %[cabac_mask] \n\t" \ + "sll.d %[tmp0], %[tmp0], %[tmp2] \n\t" \ + "add.d %[c_low], %[c_low], %[tmp0] \n\t" \ + "addi.d %[c_bytestream], %[c_bytestream], 0x02 \n\t" \ + "1: \n\t" \ + +#define GET_CABAC_LOONGARCH_END \ + "ld.bu %[bit], %[state], 0x0 \n\t" \ + "andi %[tmp0], %[c_range], 0xC0 \n\t" \ + "slli.d %[tmp0], %[tmp0], 0x01 \n\t" \ + "add.d %[tmp0], %[tmp0], %[tables] \n\t" \ + "add.d %[tmp0], %[tmp0], %[bit] \n\t" \ + /* tmp1: RangeLPS */ \ + "ld.bu %[tmp1], %[tmp0], %[lps_off] \n\t" \ + \ + "sub.d %[c_range], %[c_range], %[tmp1] \n\t" \ + "slli.d %[tmp0], %[c_range], 0x11 \n\t" \ + "bge %[tmp0], %[c_low], 1f \n\t" \ + "move %[c_range], %[tmp1] \n\t" \ + "nor %[bit], %[bit], %[bit] \n\t" \ + "sub.d %[c_low], %[c_low], %[tmp0] \n\t" \ + \ + "1: \n\t" \ + /* tmp1: *state */ \ + "add.d %[tmp0], %[tables], %[bit] \n\t" \ + "ld.bu %[tmp1], %[tmp0], %[mlps_off] \n\t" \ + /* tmp2: lps_mask */ \ + "add.d %[tmp0], %[tables], %[c_range] \n\t" \ + "ld.bu %[tmp2], %[tmp0], %[norm_off] \n\t" \ + \ + "andi %[bit], %[bit], 0x01 \n\t" \ + "st.b %[tmp1], %[state], 0x0 \n\t" \ + "sll.d %[c_range], %[c_range], %[tmp2] \n\t" \ + "sll.d %[c_low], %[c_low], %[tmp2] \n\t" \ + \ + "and %[tmp1], %[c_low], %[cabac_mask] \n\t" \ + "bnez %[tmp1], 1f \n\t" \ + "ld.hu %[tmp1], %[c_bytestream], 0x0 \n\t" \ + "ctz.d %[tmp0], %[c_low] \n\t" \ + "addi.d %[tmp2], %[tmp0], -16 \n\t" \ + "revb.2h %[tmp0], %[tmp1] \n\t" \ + "slli.d %[tmp0], %[tmp0], 0x01 \n\t" \ + "sub.d %[tmp0], %[tmp0], %[cabac_mask] \n\t" \ + "sll.d %[tmp0], %[tmp0], %[tmp2] \n\t" \ + \ + "add.d %[c_low], %[c_low], %[tmp0] \n\t" \ + \ + "slt %[tmp0], %[c_bytestream], %[c_bytestream_end] \n\t" \ + "add.d %[c_bytestream], %[c_bytestream], %[tmp0] \n\t" \ + "add.d %[c_bytestream], %[c_bytestream], %[tmp0] \n\t" \ + "1: \n\t" \ + #define get_cabac_inline get_cabac_inline_loongarch static av_always_inline int get_cabac_inline_loongarch(CABACContext *c, uint8_t * const state){ int64_t tmp0, tmp1, tmp2, bit; __asm__ volatile ( - "ld.bu %[bit], %[state], 0x0 \n\t" - "andi %[tmp0], %[c_range], 0xC0 \n\t" - "slli.d %[tmp0], %[tmp0], 0x01 \n\t" - "add.d %[tmp0], %[tmp0], %[tables] \n\t" - "add.d %[tmp0], %[tmp0], %[bit] \n\t" - /* tmp1: RangeLPS */ - "ld.bu %[tmp1], %[tmp0], %[lps_off] \n\t" - - "sub.d %[c_range], %[c_range], %[tmp1] \n\t" - "slli.d %[tmp0], %[c_range], 0x11 \n\t" - "bge %[tmp0], %[c_low], 1f \n\t" - "move %[c_range], %[tmp1] \n\t" - "nor %[bit], %[bit], %[bit] \n\t" - "sub.d %[c_low], %[c_low], %[tmp0] \n\t" - - "1: \n\t" - /* tmp1: *state */ - "add.d %[tmp0], %[tables], %[bit] \n\t" - "ld.bu %[tmp1], %[tmp0], %[mlps_off] \n\t" - /* tmp2: lps_mask */ - "add.d %[tmp0], %[tables], %[c_range] \n\t" - "ld.bu %[tmp2], %[tmp0], %[norm_off] \n\t" - - "andi %[bit], %[bit], 0x01 \n\t" - "st.b %[tmp1], %[state], 0x0 \n\t" - "sll.d %[c_range], %[c_range], %[tmp2] \n\t" - "sll.d %[c_low], %[c_low], %[tmp2] \n\t" - - "and %[tmp1], %[c_low], %[cabac_mask] \n\t" - "bnez %[tmp1], 1f \n\t" - "ld.hu %[tmp1], %[c_bytestream], 0x0 \n\t" - "addi.d %[tmp0], %[c_low], -0X01 \n\t" - "xor %[tmp0], %[c_low], %[tmp0] \n\t" - "srai.d %[tmp0], %[tmp0], 0x0f \n\t" - "add.d %[tmp0], %[tmp0], %[tables] \n\t" - /* tmp2: ff_h264_norm_shift[x >> (CABAC_BITS - 1)] */ - "ld.bu %[tmp2], %[tmp0], %[norm_off] \n\t" - - "revb.2h %[tmp0], %[tmp1] \n\t" - "slli.d %[tmp0], %[tmp0], 0x01 \n\t" - "sub.d %[tmp0], %[tmp0], %[cabac_mask] \n\t" - - "li.d %[tmp1], 0x07 \n\t" - "sub.d %[tmp1], %[tmp1], %[tmp2] \n\t" - "sll.d %[tmp0], %[tmp0], %[tmp1] \n\t" - "add.d %[c_low], %[c_low], %[tmp0] \n\t" - #if UNCHECKED_BITSTREAM_READER - "addi.d %[c_bytestream], %[c_bytestream], 0x02 \n\t" + GET_CABAC_LOONGARCH #else - "slt %[tmp0], %[c_bytestream], %[c_bytestream_end] \n\t" - "add.d %[c_bytestream], %[c_bytestream], %[tmp0] \n\t" - "add.d %[c_bytestream], %[c_bytestream], %[tmp0] \n\t" + GET_CABAC_LOONGARCH_END #endif - "1: \n\t" : [bit]"=&r"(bit), [tmp0]"=&r"(tmp0), [tmp1]"=&r"(tmp1), [tmp2]"=&r"(tmp2), [c_range]"+&r"(c->range), [c_low]"+&r"(c->low), [c_bytestream]"+&r"(c->bytestream) diff --git a/libavcodec/loongarch/h264_cabac.c b/libavcodec/loongarch/h264_cabac.c new file mode 100644 index 0000000000..d3ea8a884c --- /dev/null +++ b/libavcodec/loongarch/h264_cabac.c @@ -0,0 +1,136 @@ +/* + * Loongson optimized cabac + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + * Contributed by Hao Chen + * + * 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/cabac.h" +#include "cabac.h" + +#define decode_significance decode_significance_loongarch +static int decode_significance_loongarch(CABACContext *c, int max_coeff, + uint8_t *significant_coeff_ctx_base, + int *index, int64_t last_off) +{ + void *end = significant_coeff_ctx_base + max_coeff - 1; + int64_t minusstart = -(int64_t)significant_coeff_ctx_base; + int64_t minusindex = 4 - (int64_t)index; + int64_t bit, tmp0, tmp1, tmp2, one = 1; + uint8_t *state = significant_coeff_ctx_base; + + __asm__ volatile( + "3:" +#if UNCHECKED_BITSTREAM_READER + GET_CABAC_LOONGARCH +#else + GET_CABAC_LOONGARCH_END +#endif + "blt %[bit], %[one], 4f \n\t" + "add.d %[state], %[state], %[last_off] \n\t" +#if UNCHECKED_BITSTREAM_READER + GET_CABAC_LOONGARCH +#else + GET_CABAC_LOONGARCH_END +#endif + "sub.d %[state], %[state], %[last_off] \n\t" + "add.d %[tmp0], %[state], %[minusstart] \n\t" + "st.w %[tmp0], %[index], 0 \n\t" + "bge %[bit], %[one], 5f \n\t" + "addi.d %[index], %[index], 4 \n\t" + "4: \n\t" + "addi.d %[state], %[state], 1 \n\t" + "blt %[state], %[end], 3b \n\t" + "add.d %[tmp0], %[state], %[minusstart] \n\t" + "st.w %[tmp0], %[index], 0 \n\t" + "5: \n\t" + "add.d %[tmp0], %[index], %[minusindex] \n\t" + "srli.d %[tmp0], %[tmp0], 2 \n\t" + : [bit]"=&r"(bit), [tmp0]"=&r"(tmp0), [tmp1]"=&r"(tmp1), [tmp2]"=&r"(tmp2), [c_range]"+&r"(c->range), + [c_low]"+&r"(c->low), [state]"+&r"(state), + [c_bytestream]"+&r"(c->bytestream), [index]"+&r"(index) + : [tables]"r"(ff_h264_cabac_tables), [end]"r"(end), [one]"r"(one), + [minusstart]"r"(minusstart), [minusindex]"r"(minusindex), [last_off]"r"(last_off), +#if !UNCHECKED_BITSTREAM_READER + [c_bytestream_end]"r"(c->bytestream_end), +#endif + [lps_off]"i"(H264_LPS_RANGE_OFFSET), + [mlps_off]"i"(H264_MLPS_STATE_OFFSET + 128), + [norm_off]"i"(H264_NORM_SHIFT_OFFSET), + [cabac_mask]"r"(CABAC_MASK) + : "memory" + ); + + return (int)tmp0; +} + +#define decode_significance_8x8 decode_significance_8x8_loongarch +static int decode_significance_8x8_loongarch(CABACContext *c, + uint8_t *significant_coeff_ctx_base, + int *index, uint8_t *last_coeff_ctx_base, const uint8_t *sig_off) +{ + int64_t minusindex = 4 - (int64_t)index; + int64_t bit, tmp0, tmp1, tmp2, one = 1, end = 63, last = 0; + uint8_t *state = 0; + int64_t flag_offset = H264_LAST_COEFF_FLAG_OFFSET_8x8_OFFSET; + + __asm__ volatile( + "3: \n\t" + "ldx.bu %[tmp0], %[sig_off], %[last] \n\t" + "add.d %[state], %[tmp0], %[significant_coeff_ctx_base] \n\t" +#if UNCHECKED_BITSTREAM_READER + GET_CABAC_LOONGARCH +#else + GET_CABAC_LOONGARCH_END +#endif + "blt %[bit], %[one], 4f \n\t" + "add.d %[tmp0], %[tables], %[flag_offset] \n\t" + "ldx.bu %[tmp1], %[tmp0], %[last] \n\t" + "add.d %[state], %[tmp1], %[last_coeff_ctx_base] \n\t" +#if UNCHECKED_BITSTREAM_READER + GET_CABAC_LOONGARCH +#else + GET_CABAC_LOONGARCH_END +#endif + "st.w %[last], %[index], 0 \n\t" + "bge %[bit], %[one], 5f \n\t" + "addi.d %[index], %[index], 4 \n\t" + "4: \n\t" + "addi.d %[last], %[last], 1 \n\t" + "blt %[last], %[end], 3b \n\t" + "st.w %[last], %[index], 0 \n\t" + "5: \n\t" + "add.d %[tmp0], %[index], %[minusindex] \n\t" + "srli.d %[tmp0], %[tmp0], 2 \n\t" + : [bit]"=&r"(bit), [tmp0]"=&r"(tmp0), [tmp1]"=&r"(tmp1), [tmp2]"=&r"(tmp2), [c_range]"+&r"(c->range), + [c_low]"+&r"(c->low), [state]"+&r"(state), [last]"+&r"(last), + [c_bytestream]"+&r"(c->bytestream), [index]"+&r"(index) + : [tables]"r"(ff_h264_cabac_tables), [end]"r"(end), [one]"r"(one), [minusindex]"r"(minusindex), + [last_coeff_ctx_base]"r"(last_coeff_ctx_base), [flag_offset]"r"(flag_offset), +#if !UNCHECKED_BITSTREAM_READER + [c_bytestream_end]"r"(c->bytestream_end), +#endif + [lps_off]"i"(H264_LPS_RANGE_OFFSET), [sig_off]"r"(sig_off), + [mlps_off]"i"(H264_MLPS_STATE_OFFSET + 128), + [norm_off]"i"(H264_NORM_SHIFT_OFFSET), + [cabac_mask]"r"(CABAC_MASK), [significant_coeff_ctx_base]"r"(significant_coeff_ctx_base) + ); + + return (int)tmp0; +} diff --git a/libavcodec/loongarch/h264_intrapred_init_loongarch.c b/libavcodec/loongarch/h264_intrapred_init_loongarch.c new file mode 100644 index 0000000000..12620bd842 --- /dev/null +++ b/libavcodec/loongarch/h264_intrapred_init_loongarch.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + * Contributed by Hao Chen + * + * 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/loongarch/cpu.h" +#include "libavcodec/h264pred.h" +#include "h264_intrapred_lasx.h" + +av_cold void ff_h264_pred_init_loongarch(H264PredContext *h, int codec_id, + const int bit_depth, + const int chroma_format_idc) +{ + int cpu_flags = av_get_cpu_flags(); + + if (bit_depth == 8) { + if (have_lasx(cpu_flags)) { + if (chroma_format_idc <= 1) { + } + if (codec_id == AV_CODEC_ID_VP7 || codec_id == AV_CODEC_ID_VP8) { + } else { + if (chroma_format_idc <= 1) { + } + if (codec_id == AV_CODEC_ID_SVQ3) { + h->pred16x16[PLANE_PRED8x8] = ff_h264_pred16x16_plane_svq3_8_lasx; + } else if (codec_id == AV_CODEC_ID_RV40) { + h->pred16x16[PLANE_PRED8x8] = ff_h264_pred16x16_plane_rv40_8_lasx; + } else { + h->pred16x16[PLANE_PRED8x8] = ff_h264_pred16x16_plane_h264_8_lasx; + } + } + } + } +} diff --git a/libavcodec/loongarch/h264_intrapred_lasx.c b/libavcodec/loongarch/h264_intrapred_lasx.c new file mode 100644 index 0000000000..c38cd611b8 --- /dev/null +++ b/libavcodec/loongarch/h264_intrapred_lasx.c @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + * Contributed by Hao Chen + * + * 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/loongarch/loongson_intrinsics.h" +#include "h264_intrapred_lasx.h" + +#define PRED16X16_PLANE \ + ptrdiff_t stride_1, stride_2, stride_3, stride_4, stride_5, stride_6; \ + ptrdiff_t stride_8, stride_15; \ + int32_t res0, res1, res2, res3, cnt; \ + uint8_t *src0, *src1; \ + __m256i reg0, reg1, reg2, reg3, reg4; \ + __m256i tmp0, tmp1, tmp2, tmp3; \ + __m256i shuff = {0x0B040A0509060807, 0x0F000E010D020C03, 0, 0}; \ + __m256i mult = {0x0004000300020001, 0x0008000700060005, 0, 0}; \ + __m256i int_mult1 = {0x0000000100000000, 0x0000000300000002, \ + 0x0000000500000004, 0x0000000700000006}; \ + \ + stride_1 = -stride; \ + stride_2 = stride << 1; \ + stride_3 = stride_2 + stride; \ + stride_4 = stride_2 << 1; \ + stride_5 = stride_4 + stride; \ + stride_6 = stride_3 << 1; \ + stride_8 = stride_4 << 1; \ + stride_15 = (stride_8 << 1) - stride; \ + src0 = src - 1; \ + src1 = src0 + stride_8; \ + \ + reg0 = __lasx_xvldx(src0, -stride); \ + reg1 = __lasx_xvldx(src, (8 - stride)); \ + reg0 = __lasx_xvilvl_d(reg1, reg0); \ + reg0 = __lasx_xvshuf_b(reg0, reg0, shuff); \ + reg0 = __lasx_xvhsubw_hu_bu(reg0, reg0); \ + reg0 = __lasx_xvmul_h(reg0, mult); \ + res1 = (src1[0] - src0[stride_6]) + \ + 2 * (src1[stride] - src0[stride_5]) + \ + 3 * (src1[stride_2] - src0[stride_4]) + \ + 4 * (src1[stride_3] - src0[stride_3]) + \ + 5 * (src1[stride_4] - src0[stride_2]) + \ + 6 * (src1[stride_5] - src0[stride]) + \ + 7 * (src1[stride_6] - src0[0]) + \ + 8 * (src0[stride_15] - src0[stride_1]); \ + reg0 = __lasx_xvhaddw_w_h(reg0, reg0); \ + reg0 = __lasx_xvhaddw_d_w(reg0, reg0); \ + reg0 = __lasx_xvhaddw_q_d(reg0, reg0); \ + res0 = __lasx_xvpickve2gr_w(reg0, 0); \ + +#define PRED16X16_PLANE_END \ + res2 = (src0[stride_15] + src[15 - stride] + 1) << 4; \ + res3 = 7 * (res0 + res1); \ + res2 -= res3; \ + reg0 = __lasx_xvreplgr2vr_w(res0); \ + reg1 = __lasx_xvreplgr2vr_w(res1); \ + reg2 = __lasx_xvreplgr2vr_w(res2); \ + reg3 = __lasx_xvmul_w(reg0, int_mult1); \ + reg4 = __lasx_xvslli_w(reg0, 3); \ + reg4 = __lasx_xvadd_w(reg4, reg3); \ + for (cnt = 8; cnt--;) { \ + tmp0 = __lasx_xvadd_w(reg2, reg3); \ + tmp1 = __lasx_xvadd_w(reg2, reg4); \ + tmp0 = __lasx_xvssrani_hu_w(tmp1, tmp0, 5); \ + tmp0 = __lasx_xvpermi_d(tmp0, 0xD8); \ + reg2 = __lasx_xvadd_w(reg2, reg1); \ + tmp2 = __lasx_xvadd_w(reg2, reg3); \ + tmp3 = __lasx_xvadd_w(reg2, reg4); \ + tmp1 = __lasx_xvssrani_hu_w(tmp3, tmp2, 5); \ + tmp1 = __lasx_xvpermi_d(tmp1, 0xD8); \ + tmp0 = __lasx_xvssrani_bu_h(tmp1, tmp0, 0); \ + reg2 = __lasx_xvadd_w(reg2, reg1); \ + __lasx_xvstelm_d(tmp0, src, 0, 0); \ + __lasx_xvstelm_d(tmp0, src, 8, 2); \ + src += stride; \ + __lasx_xvstelm_d(tmp0, src, 0, 1); \ + __lasx_xvstelm_d(tmp0, src, 8, 3); \ + src += stride; \ + } + + +void ff_h264_pred16x16_plane_h264_8_lasx(uint8_t *src, ptrdiff_t stride) +{ + PRED16X16_PLANE + res0 = (5 * res0 + 32) >> 6; + res1 = (5 * res1 + 32) >> 6; + PRED16X16_PLANE_END +} + +void ff_h264_pred16x16_plane_rv40_8_lasx(uint8_t *src, ptrdiff_t stride) +{ + PRED16X16_PLANE + res0 = (res0 + (res0 >> 2)) >> 4; + res1 = (res1 + (res1 >> 2)) >> 4; + PRED16X16_PLANE_END +} + +void ff_h264_pred16x16_plane_svq3_8_lasx(uint8_t *src, ptrdiff_t stride) +{ + PRED16X16_PLANE + cnt = (5 * (res0/4)) / 16; + res0 = (5 * (res1/4)) / 16; + res1 = cnt; + PRED16X16_PLANE_END +} diff --git a/libavcodec/loongarch/h264_intrapred_lasx.h b/libavcodec/loongarch/h264_intrapred_lasx.h new file mode 100644 index 0000000000..0c2653300c --- /dev/null +++ b/libavcodec/loongarch/h264_intrapred_lasx.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + * Contributed by Hao Chen + * + * 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 + */ + +#ifndef AVCODEC_LOONGARCH_H264_INTRAPRED_LASX_H +#define AVCODEC_LOONGARCH_H264_INTRAPRED_LASX_H + +#include "libavcodec/avcodec.h" + +void ff_h264_pred16x16_plane_h264_8_lasx(uint8_t *src, ptrdiff_t stride); +void ff_h264_pred16x16_plane_rv40_8_lasx(uint8_t *src, ptrdiff_t stride); +void ff_h264_pred16x16_plane_svq3_8_lasx(uint8_t *src, ptrdiff_t stride); + +#endif // #ifndef AVCODEC_LOONGARCH_H264_INTRAPRED_LASX_H diff --git a/libavcodec/loongarch/h264chroma_init_loongarch.c b/libavcodec/loongarch/h264chroma_init_loongarch.c index 5789b5f573..7f1aa4d848 100644 --- a/libavcodec/loongarch/h264chroma_init_loongarch.c +++ b/libavcodec/loongarch/h264chroma_init_loongarch.c @@ -30,6 +30,7 @@ av_cold void ff_h264chroma_init_loongarch(H264ChromaContext *c, int bit_depth) if (bit_depth <= 8) { c->put_h264_chroma_pixels_tab[0] = ff_put_h264_chroma_mc8_lasx; c->avg_h264_chroma_pixels_tab[0] = ff_avg_h264_chroma_mc8_lasx; + c->put_h264_chroma_pixels_tab[1] = ff_put_h264_chroma_mc4_lasx; } } } diff --git a/libavcodec/loongarch/h264chroma_lasx.c b/libavcodec/loongarch/h264chroma_lasx.c index 82cef77a95..824a78dfc8 100644 --- a/libavcodec/loongarch/h264chroma_lasx.c +++ b/libavcodec/loongarch/h264chroma_lasx.c @@ -26,9 +26,11 @@ #include "libavutil/avassert.h" #include "libavutil/loongarch/loongson_intrinsics.h" -static const uint8_t chroma_mask_arr[32] = { +static const uint8_t chroma_mask_arr[64] = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, + 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20, + 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; static av_always_inline void avc_chroma_hv_8x4_lasx(uint8_t *src, uint8_t *dst, @@ -38,6 +40,7 @@ static av_always_inline void avc_chroma_hv_8x4_lasx(uint8_t *src, uint8_t *dst, { ptrdiff_t stride_2x = stride << 1; ptrdiff_t stride_3x = stride_2x + stride; + ptrdiff_t stride_4x = stride_2x << 1; __m256i src0, src1, src2, src3, src4, out; __m256i res_hz0, res_hz1, res_hz2, res_vt0, res_vt1; __m256i mask; @@ -48,8 +51,7 @@ static av_always_inline void avc_chroma_hv_8x4_lasx(uint8_t *src, uint8_t *dst, __m256i coeff_vt_vec1 = __lasx_xvreplgr2vr_h(coef_ver1); DUP2_ARG2(__lasx_xvld, chroma_mask_arr, 0, src, 0, mask, src0); - src += stride; - DUP4_ARG2(__lasx_xvldx, src, 0, src, stride, src, stride_2x, src, stride_3x, + DUP4_ARG2(__lasx_xvldx, src, stride, src, stride_2x, src, stride_3x, src, stride_4x, src1, src2, src3, src4); DUP2_ARG3(__lasx_xvpermi_q, src2, src1, 0x20, src4, src3, 0x20, src1, src3); src0 = __lasx_xvshuf_b(src0, src0, mask); @@ -60,14 +62,9 @@ static av_always_inline void avc_chroma_hv_8x4_lasx(uint8_t *src, uint8_t *dst, res_vt1 = __lasx_xvmul_h(res_hz2, coeff_vt_vec0); res_hz0 = __lasx_xvpermi_q(res_hz1, res_hz0, 0x20); res_hz1 = __lasx_xvpermi_q(res_hz1, res_hz2, 0x3); - res_hz0 = __lasx_xvmul_h(res_hz0, coeff_vt_vec1); - res_hz1 = __lasx_xvmul_h(res_hz1, coeff_vt_vec1); - res_vt0 = __lasx_xvadd_h(res_vt0, res_hz0); - res_vt1 = __lasx_xvadd_h(res_vt1, res_hz1); - DUP2_ARG2(__lasx_xvsrari_h, res_vt0, 6, res_vt1, 6, res_vt0, res_vt1); - res_vt0 = __lasx_xvsat_hu(res_vt0, 7); - res_vt1 = __lasx_xvsat_hu(res_vt1, 7); - out = __lasx_xvpickev_b(res_vt1, res_vt0); + res_vt0 = __lasx_xvmadd_h(res_vt0, res_hz0, coeff_vt_vec1); + res_vt1 = __lasx_xvmadd_h(res_vt1, res_hz1, coeff_vt_vec1); + out = __lasx_xvssrarni_bu_h(res_vt1, res_vt0, 6); __lasx_xvstelm_d(out, dst, 0, 0); __lasx_xvstelm_d(out, dst + stride, 0, 2); __lasx_xvstelm_d(out, dst + stride_2x, 0, 1); @@ -94,11 +91,10 @@ static av_always_inline void avc_chroma_hv_8x8_lasx(uint8_t *src, uint8_t *dst, __m256i coeff_vt_vec1 = __lasx_xvreplgr2vr_h(coef_ver1); DUP2_ARG2(__lasx_xvld, chroma_mask_arr, 0, src, 0, mask, src0); - src += stride; - DUP4_ARG2(__lasx_xvldx, src, 0, src, stride, src, stride_2x, src, stride_3x, + DUP4_ARG2(__lasx_xvldx, src, stride, src, stride_2x, src, stride_3x, src, stride_4x, src1, src2, src3, src4); src += stride_4x; - DUP4_ARG2(__lasx_xvldx, src, 0, src, stride, src, stride_2x, src, stride_3x, + DUP4_ARG2(__lasx_xvldx, src, stride, src, stride_2x, src, stride_3x, src, stride_4x, src5, src6, src7, src8); DUP4_ARG3(__lasx_xvpermi_q, src2, src1, 0x20, src4, src3, 0x20, src6, src5, 0x20, src8, src7, 0x20, src1, src3, src5, src7); @@ -116,21 +112,10 @@ static av_always_inline void avc_chroma_hv_8x8_lasx(uint8_t *src, uint8_t *dst, res_hz1 = __lasx_xvpermi_q(res_hz1, res_hz2, 0x3); res_hz2 = __lasx_xvpermi_q(res_hz2, res_hz3, 0x3); res_hz3 = __lasx_xvpermi_q(res_hz3, res_hz4, 0x3); - res_hz0 = __lasx_xvmul_h(res_hz0, coeff_vt_vec1); - res_hz1 = __lasx_xvmul_h(res_hz1, coeff_vt_vec1); - res_hz2 = __lasx_xvmul_h(res_hz2, coeff_vt_vec1); - res_hz3 = __lasx_xvmul_h(res_hz3, coeff_vt_vec1); - res_vt0 = __lasx_xvadd_h(res_vt0, res_hz0); - res_vt1 = __lasx_xvadd_h(res_vt1, res_hz1); - res_vt2 = __lasx_xvadd_h(res_vt2, res_hz2); - res_vt3 = __lasx_xvadd_h(res_vt3, res_hz3); - DUP4_ARG2(__lasx_xvsrari_h, res_vt0, 6, res_vt1, 6, res_vt2, 6, res_vt3, 6, + DUP4_ARG3(__lasx_xvmadd_h, res_vt0, res_hz0, coeff_vt_vec1, res_vt1, res_hz1, coeff_vt_vec1, + res_vt2, res_hz2, coeff_vt_vec1, res_vt3, res_hz3, coeff_vt_vec1, res_vt0, res_vt1, res_vt2, res_vt3); - res_vt0 = __lasx_xvsat_hu(res_vt0, 7); - res_vt1 = __lasx_xvsat_hu(res_vt1, 7); - res_vt2 = __lasx_xvsat_hu(res_vt2, 7); - res_vt3 = __lasx_xvsat_hu(res_vt3, 7); - DUP2_ARG2(__lasx_xvpickev_b, res_vt1, res_vt0, res_vt3, res_vt2, out0, out1); + DUP2_ARG3(__lasx_xvssrarni_bu_h, res_vt1, res_vt0, 6, res_vt3, res_vt2, 6, out0, out1); __lasx_xvstelm_d(out0, dst, 0, 0); __lasx_xvstelm_d(out0, dst + stride, 0, 2); __lasx_xvstelm_d(out0, dst + stride_2x, 0, 1); @@ -154,18 +139,14 @@ static av_always_inline void avc_chroma_hz_8x4_lasx(uint8_t *src, uint8_t *dst, __m256i coeff_vec1 = __lasx_xvreplgr2vr_b(coeff1); __m256i coeff_vec = __lasx_xvilvl_b(coeff_vec0, coeff_vec1); - mask = __lasx_xvld(chroma_mask_arr, 0); - DUP4_ARG2(__lasx_xvldx, src, 0, src, stride, src, stride_2x, src, stride_3x, - src0, src1, src2, src3); + coeff_vec = __lasx_xvslli_b(coeff_vec, 3); + DUP2_ARG2(__lasx_xvld, chroma_mask_arr, 0, src, 0, mask, src0); + DUP2_ARG2(__lasx_xvldx, src, stride, src, stride_2x, src1, src2); + src3 = __lasx_xvldx(src, stride_3x); DUP2_ARG3(__lasx_xvpermi_q, src1, src0, 0x20, src3, src2, 0x20, src0, src2); DUP2_ARG3(__lasx_xvshuf_b, src0, src0, mask, src2, src2, mask, src0, src2); DUP2_ARG2(__lasx_xvdp2_h_bu, src0, coeff_vec, src2, coeff_vec, res0, res1); - res0 = __lasx_xvslli_h(res0, 3); - res1 = __lasx_xvslli_h(res1, 3); - DUP2_ARG2(__lasx_xvsrari_h, res0, 6, res1, 6, res0, res1); - res0 = __lasx_xvsat_hu(res0, 7); - res1 = __lasx_xvsat_hu(res1, 7); - out = __lasx_xvpickev_b(res1, res0); + out = __lasx_xvssrarni_bu_h(res1, res0, 6); __lasx_xvstelm_d(out, dst, 0, 0); __lasx_xvstelm_d(out, dst + stride, 0, 2); __lasx_xvstelm_d(out, dst + stride_2x, 0, 1); @@ -187,28 +168,20 @@ static av_always_inline void avc_chroma_hz_8x8_lasx(uint8_t *src, uint8_t *dst, __m256i coeff_vec1 = __lasx_xvreplgr2vr_b(coeff1); __m256i coeff_vec = __lasx_xvilvl_b(coeff_vec0, coeff_vec1); - mask = __lasx_xvld(chroma_mask_arr, 0); - DUP4_ARG2(__lasx_xvldx, src, 0, src, stride, src, stride_2x, src, stride_3x, - src0, src1, src2, src3); + coeff_vec = __lasx_xvslli_b(coeff_vec, 3); + DUP2_ARG2(__lasx_xvld, chroma_mask_arr, 0, src, 0, mask, src0); + DUP4_ARG2(__lasx_xvldx, src, stride, src, stride_2x, src, stride_3x, src, stride_4x, + src1, src2, src3, src4); src += stride_4x; - DUP4_ARG2(__lasx_xvldx, src, 0, src, stride, src, stride_2x, src, stride_3x, - src4, src5, src6, src7); + DUP2_ARG2(__lasx_xvldx, src, stride, src, stride_2x, src5, src6); + src7 = __lasx_xvldx(src, stride_3x); DUP4_ARG3(__lasx_xvpermi_q, src1, src0, 0x20, src3, src2, 0x20, src5, src4, 0x20, src7, src6, 0x20, src0, src2, src4, src6); DUP4_ARG3(__lasx_xvshuf_b, src0, src0, mask, src2, src2, mask, src4, src4, mask, src6, src6, mask, src0, src2, src4, src6); DUP4_ARG2(__lasx_xvdp2_h_bu, src0, coeff_vec, src2, coeff_vec, src4, coeff_vec, src6, coeff_vec, res0, res1, res2, res3); - res0 = __lasx_xvslli_h(res0, 3); - res1 = __lasx_xvslli_h(res1, 3); - res2 = __lasx_xvslli_h(res2, 3); - res3 = __lasx_xvslli_h(res3, 3); - DUP4_ARG2(__lasx_xvsrari_h, res0, 6, res1, 6, res2, 6, res3, 6, res0, res1, res2, res3); - res0 = __lasx_xvsat_hu(res0, 7); - res1 = __lasx_xvsat_hu(res1, 7); - res2 = __lasx_xvsat_hu(res2, 7); - res3 = __lasx_xvsat_hu(res3, 7); - DUP2_ARG2(__lasx_xvpickev_b, res1, res0, res3, res2, out0, out1); + DUP2_ARG3(__lasx_xvssrarni_bu_h, res1, res0, 6, res3, res2, 6, out0, out1); __lasx_xvstelm_d(out0, dst, 0, 0); __lasx_xvstelm_d(out0, dst + stride, 0, 2); __lasx_xvstelm_d(out0, dst + stride_2x, 0, 1); @@ -236,6 +209,7 @@ static av_always_inline void avc_chroma_hz_nonmult_lasx(uint8_t *src, __m256i coeff_vec = __lasx_xvilvl_b(coeff_vec0, coeff_vec1); mask = __lasx_xvld(chroma_mask_arr, 0); + coeff_vec = __lasx_xvslli_b(coeff_vec, 3); for (row = height >> 2; row--;) { DUP4_ARG2(__lasx_xvldx, src, 0, src, stride, src, stride_2x, src, stride_3x, @@ -244,12 +218,7 @@ static av_always_inline void avc_chroma_hz_nonmult_lasx(uint8_t *src, DUP2_ARG3(__lasx_xvpermi_q, src1, src0, 0x20, src3, src2, 0x20, src0, src2); DUP2_ARG3(__lasx_xvshuf_b, src0, src0, mask, src2, src2, mask, src0, src2); DUP2_ARG2(__lasx_xvdp2_h_bu, src0, coeff_vec, src2, coeff_vec, res0, res1); - res0 = __lasx_xvslli_h(res0, 3); - res1 = __lasx_xvslli_h(res1, 3); - DUP2_ARG2(__lasx_xvsrari_h, res0, 6, res1, 6, res0, res1); - res0 = __lasx_xvsat_hu(res0, 7); - res1 = __lasx_xvsat_hu(res1, 7); - out = __lasx_xvpickev_b(res1, res0); + out = __lasx_xvssrarni_bu_h(res1, res0, 6); __lasx_xvstelm_d(out, dst, 0, 0); __lasx_xvstelm_d(out, dst + stride, 0, 2); __lasx_xvstelm_d(out, dst + stride_2x, 0, 1); @@ -258,18 +227,15 @@ static av_always_inline void avc_chroma_hz_nonmult_lasx(uint8_t *src, } if ((height & 3)) { - for (row = (height & 3); row--;) { - src0 = __lasx_xvld(src, 0); - src += stride; - src0 = __lasx_xvshuf_b(src0, src0, mask); - res0 = __lasx_xvdp2_h_bu(src0, coeff_vec); - res0 = __lasx_xvslli_h(res0, 3); - res0 = __lasx_xvsrari_h(res0, 6); - res0 = __lasx_xvsat_hu(res0, 7); - out = __lasx_xvpickev_b(res0, res0); - __lasx_xvstelm_d(out, dst, 0, 0); - dst += stride; - } + src0 = __lasx_xvld(src, 0); + src1 = __lasx_xvldx(src, stride); + src1 = __lasx_xvpermi_q(src1, src0, 0x20); + src0 = __lasx_xvshuf_b(src1, src1, mask); + res0 = __lasx_xvdp2_h_bu(src0, coeff_vec); + out = __lasx_xvssrarni_bu_h(res0, res0, 6); + __lasx_xvstelm_d(out, dst, 0, 0); + dst += stride; + __lasx_xvstelm_d(out, dst, 0, 2); } } @@ -284,6 +250,7 @@ static av_always_inline void avc_chroma_vt_8x4_lasx(uint8_t *src, uint8_t *dst, __m256i coeff_vec1 = __lasx_xvreplgr2vr_b(coeff1); __m256i coeff_vec = __lasx_xvilvl_b(coeff_vec0, coeff_vec1); + coeff_vec = __lasx_xvslli_b(coeff_vec, 3); src0 = __lasx_xvld(src, 0); src += stride; DUP4_ARG2(__lasx_xvldx, src, 0, src, stride, src, stride_2x, src, stride_3x, @@ -292,12 +259,7 @@ static av_always_inline void avc_chroma_vt_8x4_lasx(uint8_t *src, uint8_t *dst, src4, src3, 0x20, src0, src1, src2, src3); DUP2_ARG2(__lasx_xvilvl_b, src1, src0, src3, src2, src0, src2); DUP2_ARG2(__lasx_xvdp2_h_bu, src0, coeff_vec, src2, coeff_vec, res0, res1); - res0 = __lasx_xvslli_h(res0, 3); - res1 = __lasx_xvslli_h(res1, 3); - DUP2_ARG2(__lasx_xvsrari_h, res0, 6, res1, 6, res0, res1); - res0 = __lasx_xvsat_hu(res0, 7); - res1 = __lasx_xvsat_hu(res1, 7); - out = __lasx_xvpickev_b(res1, res0); + out = __lasx_xvssrarni_bu_h(res1, res0, 6); __lasx_xvstelm_d(out, dst, 0, 0); __lasx_xvstelm_d(out, dst + stride, 0, 2); __lasx_xvstelm_d(out, dst + stride_2x, 0, 1); @@ -317,6 +279,7 @@ static av_always_inline void avc_chroma_vt_8x8_lasx(uint8_t *src, uint8_t *dst, __m256i coeff_vec1 = __lasx_xvreplgr2vr_b(coeff1); __m256i coeff_vec = __lasx_xvilvl_b(coeff_vec0, coeff_vec1); + coeff_vec = __lasx_xvslli_b(coeff_vec, 3); src0 = __lasx_xvld(src, 0); src += stride; DUP4_ARG2(__lasx_xvldx, src, 0, src, stride, src, stride_2x, src, stride_3x, @@ -332,16 +295,7 @@ static av_always_inline void avc_chroma_vt_8x8_lasx(uint8_t *src, uint8_t *dst, src0, src2, src4, src6); DUP4_ARG2(__lasx_xvdp2_h_bu, src0, coeff_vec, src2, coeff_vec, src4, coeff_vec, src6, coeff_vec, res0, res1, res2, res3); - res0 = __lasx_xvslli_h(res0, 3); - res1 = __lasx_xvslli_h(res1, 3); - res2 = __lasx_xvslli_h(res2, 3); - res3 = __lasx_xvslli_h(res3, 3); - DUP4_ARG2(__lasx_xvsrari_h, res0, 6, res1, 6, res2, 6, res3, 6, res0, res1, res2, res3); - res0 = __lasx_xvsat_hu(res0, 7); - res1 = __lasx_xvsat_hu(res1, 7); - res2 = __lasx_xvsat_hu(res2, 7); - res3 = __lasx_xvsat_hu(res3, 7); - DUP2_ARG2(__lasx_xvpickev_b, res1, res0, res3, res2, out0, out1); + DUP2_ARG3(__lasx_xvssrarni_bu_h, res1, res0, 6, res3, res2, 6, out0, out1); __lasx_xvstelm_d(out0, dst, 0, 0); __lasx_xvstelm_d(out0, dst + stride, 0, 2); __lasx_xvstelm_d(out0, dst + stride_2x, 0, 1); @@ -357,43 +311,37 @@ static av_always_inline void copy_width8x8_lasx(uint8_t *src, uint8_t *dst, ptrdiff_t stride) { uint64_t tmp[8]; + ptrdiff_t stride_2, stride_3, stride_4; __asm__ volatile ( - "ld.d %[tmp0], %[src], 0x0 \n\t" - "add.d %[src], %[src], %[stride] \n\t" - "ld.d %[tmp1], %[src], 0x0 \n\t" - "add.d %[src], %[src], %[stride] \n\t" - "ld.d %[tmp2], %[src], 0x0 \n\t" - "add.d %[src], %[src], %[stride] \n\t" - "ld.d %[tmp3], %[src], 0x0 \n\t" - "add.d %[src], %[src], %[stride] \n\t" - "ld.d %[tmp4], %[src], 0x0 \n\t" - "add.d %[src], %[src], %[stride] \n\t" - "ld.d %[tmp5], %[src], 0x0 \n\t" - "add.d %[src], %[src], %[stride] \n\t" - "ld.d %[tmp6], %[src], 0x0 \n\t" - "add.d %[src], %[src], %[stride] \n\t" - "ld.d %[tmp7], %[src], 0x0 \n\t" - - "st.d %[tmp0], %[dst], 0x0 \n\t" - "add.d %[dst], %[dst], %[stride] \n\t" - "st.d %[tmp1], %[dst], 0x0 \n\t" - "add.d %[dst], %[dst], %[stride] \n\t" - "st.d %[tmp2], %[dst], 0x0 \n\t" - "add.d %[dst], %[dst], %[stride] \n\t" - "st.d %[tmp3], %[dst], 0x0 \n\t" - "add.d %[dst], %[dst], %[stride] \n\t" - "st.d %[tmp4], %[dst], 0x0 \n\t" - "add.d %[dst], %[dst], %[stride] \n\t" - "st.d %[tmp5], %[dst], 0x0 \n\t" - "add.d %[dst], %[dst], %[stride] \n\t" - "st.d %[tmp6], %[dst], 0x0 \n\t" - "add.d %[dst], %[dst], %[stride] \n\t" - "st.d %[tmp7], %[dst], 0x0 \n\t" + "slli.d %[stride_2], %[stride], 1 \n\t" + "add.d %[stride_3], %[stride_2], %[stride] \n\t" + "slli.d %[stride_4], %[stride_2], 1 \n\t" + "ld.d %[tmp0], %[src], 0x0 \n\t" + "ldx.d %[tmp1], %[src], %[stride] \n\t" + "ldx.d %[tmp2], %[src], %[stride_2] \n\t" + "ldx.d %[tmp3], %[src], %[stride_3] \n\t" + "add.d %[src], %[src], %[stride_4] \n\t" + "ld.d %[tmp4], %[src], 0x0 \n\t" + "ldx.d %[tmp5], %[src], %[stride] \n\t" + "ldx.d %[tmp6], %[src], %[stride_2] \n\t" + "ldx.d %[tmp7], %[src], %[stride_3] \n\t" + + "st.d %[tmp0], %[dst], 0x0 \n\t" + "stx.d %[tmp1], %[dst], %[stride] \n\t" + "stx.d %[tmp2], %[dst], %[stride_2] \n\t" + "stx.d %[tmp3], %[dst], %[stride_3] \n\t" + "add.d %[dst], %[dst], %[stride_4] \n\t" + "st.d %[tmp4], %[dst], 0x0 \n\t" + "stx.d %[tmp5], %[dst], %[stride] \n\t" + "stx.d %[tmp6], %[dst], %[stride_2] \n\t" + "stx.d %[tmp7], %[dst], %[stride_3] \n\t" : [tmp0]"=&r"(tmp[0]), [tmp1]"=&r"(tmp[1]), [tmp2]"=&r"(tmp[2]), [tmp3]"=&r"(tmp[3]), [tmp4]"=&r"(tmp[4]), [tmp5]"=&r"(tmp[5]), [tmp6]"=&r"(tmp[6]), [tmp7]"=&r"(tmp[7]), - [dst]"+&r"(dst), [src]"+&r"(src) + [dst]"+&r"(dst), [src]"+&r"(src), + [stride_2]"=&r"(stride_2), [stride_3]"=&r"(stride_3), + [stride_4]"=&r"(stride_4) : [stride]"r"(stride) : "memory" ); @@ -403,26 +351,23 @@ static av_always_inline void copy_width8x4_lasx(uint8_t *src, uint8_t *dst, ptrdiff_t stride) { uint64_t tmp[4]; + ptrdiff_t stride_2, stride_3; __asm__ volatile ( - "ld.d %[tmp0], %[src], 0x0 \n\t" - "add.d %[src], %[src], %[stride] \n\t" - "ld.d %[tmp1], %[src], 0x0 \n\t" - "add.d %[src], %[src], %[stride] \n\t" - "ld.d %[tmp2], %[src], 0x0 \n\t" - "add.d %[src], %[src], %[stride] \n\t" - "ld.d %[tmp3], %[src], 0x0 \n\t" - - "st.d %[tmp0], %[dst], 0x0 \n\t" - "add.d %[dst], %[dst], %[stride] \n\t" - "st.d %[tmp1], %[dst], 0x0 \n\t" - "add.d %[dst], %[dst], %[stride] \n\t" - "st.d %[tmp2], %[dst], 0x0 \n\t" - "add.d %[dst], %[dst], %[stride] \n\t" - "st.d %[tmp3], %[dst], 0x0 \n\t" + "slli.d %[stride_2], %[stride], 1 \n\t" + "add.d %[stride_3], %[stride_2], %[stride] \n\t" + "ld.d %[tmp0], %[src], 0x0 \n\t" + "ldx.d %[tmp1], %[src], %[stride] \n\t" + "ldx.d %[tmp2], %[src], %[stride_2] \n\t" + "ldx.d %[tmp3], %[src], %[stride_3] \n\t" + + "st.d %[tmp0], %[dst], 0x0 \n\t" + "stx.d %[tmp1], %[dst], %[stride] \n\t" + "stx.d %[tmp2], %[dst], %[stride_2] \n\t" + "stx.d %[tmp3], %[dst], %[stride_3] \n\t" : [tmp0]"=&r"(tmp[0]), [tmp1]"=&r"(tmp[1]), [tmp2]"=&r"(tmp[2]), [tmp3]"=&r"(tmp[3]), - [dst]"+&r"(dst), [src]"+&r"(src) - : [stride]"r"(stride) + [stride_2]"=&r"(stride_2), [stride_3]"=&r"(stride_3) + : [stride]"r"(stride), [dst]"r"(dst), [src]"r"(src) : "memory" ); } @@ -441,6 +386,221 @@ static void avc_chroma_hv_8w_lasx(uint8_t *src, uint8_t *dst, ptrdiff_t stride, } } +static void avc_chroma_hv_4x2_lasx(uint8_t *src, uint8_t *dst, ptrdiff_t stride, + uint32_t coef_hor0, uint32_t coef_hor1, + uint32_t coef_ver0, uint32_t coef_ver1) +{ + ptrdiff_t stride_2 = stride << 1; + __m256i src0, src1, src2; + __m256i res_hz, res_vt; + __m256i mask; + __m256i coeff_hz_vec0 = __lasx_xvreplgr2vr_b(coef_hor0); + __m256i coeff_hz_vec1 = __lasx_xvreplgr2vr_b(coef_hor1); + __m256i coeff_hz_vec = __lasx_xvilvl_b(coeff_hz_vec0, coeff_hz_vec1); + __m256i coeff_vt_vec0 = __lasx_xvreplgr2vr_h(coef_ver0); + __m256i coeff_vt_vec1 = __lasx_xvreplgr2vr_h(coef_ver1); + __m256i coeff_vt_vec = __lasx_xvpermi_q(coeff_vt_vec1, coeff_vt_vec0, 0x02); + + DUP2_ARG2(__lasx_xvld, chroma_mask_arr, 32, src, 0, mask, src0); + DUP2_ARG2(__lasx_xvldx, src, stride, src, stride_2, src1, src2); + DUP2_ARG3(__lasx_xvshuf_b, src1, src0, mask, src2, src1, mask, src0, src1); + src0 = __lasx_xvpermi_q(src0, src1, 0x02); + res_hz = __lasx_xvdp2_h_bu(src0, coeff_hz_vec); + res_vt = __lasx_xvmul_h(res_hz, coeff_vt_vec); + res_hz = __lasx_xvpermi_q(res_hz, res_vt, 0x01); + res_vt = __lasx_xvadd_h(res_hz, res_vt); + res_vt = __lasx_xvssrarni_bu_h(res_vt, res_vt, 6); + __lasx_xvstelm_w(res_vt, dst, 0, 0); + __lasx_xvstelm_w(res_vt, dst + stride, 0, 1); +} + +static void avc_chroma_hv_4x4_lasx(uint8_t *src, uint8_t *dst, ptrdiff_t stride, + uint32_t coef_hor0, uint32_t coef_hor1, + uint32_t coef_ver0, uint32_t coef_ver1) +{ + ptrdiff_t stride_2 = stride << 1; + ptrdiff_t stride_3 = stride_2 + stride; + ptrdiff_t stride_4 = stride_2 << 1; + __m256i src0, src1, src2, src3, src4; + __m256i res_hz0, res_hz1, res_vt0, res_vt1; + __m256i mask; + __m256i coeff_hz_vec0 = __lasx_xvreplgr2vr_b(coef_hor0); + __m256i coeff_hz_vec1 = __lasx_xvreplgr2vr_b(coef_hor1); + __m256i coeff_hz_vec = __lasx_xvilvl_b(coeff_hz_vec0, coeff_hz_vec1); + __m256i coeff_vt_vec0 = __lasx_xvreplgr2vr_h(coef_ver0); + __m256i coeff_vt_vec1 = __lasx_xvreplgr2vr_h(coef_ver1); + + DUP2_ARG2(__lasx_xvld, chroma_mask_arr, 32, src, 0, mask, src0); + DUP4_ARG2(__lasx_xvldx, src, stride, src, stride_2, src, stride_3, + src, stride_4, src1, src2, src3, src4); + DUP4_ARG3(__lasx_xvshuf_b, src1, src0, mask, src2, src1, mask, src3, src2, mask, + src4, src3, mask, src0, src1, src2, src3); + DUP2_ARG3(__lasx_xvpermi_q, src0, src2, 0x02, src1, src3, 0x02, src0, src1); + DUP2_ARG2(__lasx_xvdp2_h_bu, src0, coeff_hz_vec, src1, coeff_hz_vec, res_hz0, res_hz1); + DUP2_ARG2(__lasx_xvmul_h, res_hz0, coeff_vt_vec1, res_hz1, coeff_vt_vec0, res_vt0, res_vt1); + res_hz0 = __lasx_xvadd_h(res_vt0, res_vt1); + res_hz0 = __lasx_xvssrarni_bu_h(res_hz0, res_hz0, 6); + __lasx_xvstelm_w(res_hz0, dst, 0, 0); + __lasx_xvstelm_w(res_hz0, dst + stride, 0, 1); + __lasx_xvstelm_w(res_hz0, dst + stride_2, 0, 4); + __lasx_xvstelm_w(res_hz0, dst + stride_3, 0, 5); +} + +static void avc_chroma_hv_4x8_lasx(uint8_t *src, uint8_t * dst, ptrdiff_t stride, + uint32_t coef_hor0, uint32_t coef_hor1, + uint32_t coef_ver0, uint32_t coef_ver1) +{ + ptrdiff_t stride_2 = stride << 1; + ptrdiff_t stride_3 = stride_2 + stride; + ptrdiff_t stride_4 = stride_2 << 1; + __m256i src0, src1, src2, src3, src4, src5, src6, src7, src8; + __m256i res_hz0, res_hz1, res_hz2, res_hz3; + __m256i res_vt0, res_vt1, res_vt2, res_vt3; + __m256i mask; + __m256i coeff_hz_vec0 = __lasx_xvreplgr2vr_b(coef_hor0); + __m256i coeff_hz_vec1 = __lasx_xvreplgr2vr_b(coef_hor1); + __m256i coeff_hz_vec = __lasx_xvilvl_b(coeff_hz_vec0, coeff_hz_vec1); + __m256i coeff_vt_vec0 = __lasx_xvreplgr2vr_h(coef_ver0); + __m256i coeff_vt_vec1 = __lasx_xvreplgr2vr_h(coef_ver1); + + DUP2_ARG2(__lasx_xvld, chroma_mask_arr, 32, src, 0, mask, src0); + DUP4_ARG2(__lasx_xvldx, src, stride, src, stride_2, src, stride_3, + src, stride_4, src1, src2, src3, src4); + src += stride_4; + DUP4_ARG2(__lasx_xvldx, src, stride, src, stride_2, src, stride_3, + src, stride_4, src5, src6, src7, src8); + DUP4_ARG3(__lasx_xvshuf_b, src1, src0, mask, src2, src1, mask, src3, src2, mask, + src4, src3, mask, src0, src1, src2, src3); + DUP4_ARG3(__lasx_xvshuf_b, src5, src4, mask, src6, src5, mask, src7, src6, mask, + src8, src7, mask, src4, src5, src6, src7); + DUP4_ARG3(__lasx_xvpermi_q, src0, src2, 0x02, src1, src3, 0x02, src4, src6, 0x02, + src5, src7, 0x02, src0, src1, src4, src5); + DUP4_ARG2(__lasx_xvdp2_h_bu, src0, coeff_hz_vec, src1, coeff_hz_vec, src4, coeff_hz_vec, + src5, coeff_hz_vec, res_hz0, res_hz1, res_hz2, res_hz3); + DUP4_ARG2(__lasx_xvmul_h, res_hz0, coeff_vt_vec1, res_hz1, coeff_vt_vec0, res_hz2, + coeff_vt_vec1, res_hz3, coeff_vt_vec0, res_vt0, res_vt1, res_vt2, res_vt3); + DUP2_ARG2(__lasx_xvadd_h, res_vt0, res_vt1, res_vt2, res_vt3, res_vt0, res_vt2); + res_hz0 = __lasx_xvssrarni_bu_h(res_vt2, res_vt0, 6); + __lasx_xvstelm_w(res_hz0, dst, 0, 0); + __lasx_xvstelm_w(res_hz0, dst + stride, 0, 1); + __lasx_xvstelm_w(res_hz0, dst + stride_2, 0, 4); + __lasx_xvstelm_w(res_hz0, dst + stride_3, 0, 5); + dst += stride_4; + __lasx_xvstelm_w(res_hz0, dst, 0, 2); + __lasx_xvstelm_w(res_hz0, dst + stride, 0, 3); + __lasx_xvstelm_w(res_hz0, dst + stride_2, 0, 6); + __lasx_xvstelm_w(res_hz0, dst + stride_3, 0, 7); +} + +static void avc_chroma_hv_4w_lasx(uint8_t *src, uint8_t *dst, ptrdiff_t stride, + uint32_t coef_hor0, uint32_t coef_hor1, + uint32_t coef_ver0, uint32_t coef_ver1, + int32_t height) +{ + if (8 == height) { + avc_chroma_hv_4x8_lasx(src, dst, stride, coef_hor0, coef_hor1, coef_ver0, + coef_ver1); + } else if (4 == height) { + avc_chroma_hv_4x4_lasx(src, dst, stride, coef_hor0, coef_hor1, coef_ver0, + coef_ver1); + } else if (2 == height) { + avc_chroma_hv_4x2_lasx(src, dst, stride, coef_hor0, coef_hor1, coef_ver0, + coef_ver1); + } +} + +static void avc_chroma_hz_4x2_lasx(uint8_t *src, uint8_t *dst, ptrdiff_t stride, + uint32_t coeff0, uint32_t coeff1) +{ + __m256i src0, src1; + __m256i res, mask; + __m256i coeff_vec0 = __lasx_xvreplgr2vr_b(coeff0); + __m256i coeff_vec1 = __lasx_xvreplgr2vr_b(coeff1); + __m256i coeff_vec = __lasx_xvilvl_b(coeff_vec0, coeff_vec1); + + DUP2_ARG2(__lasx_xvld, chroma_mask_arr, 32, src, 0, mask, src0); + src1 = __lasx_xvldx(src, stride); + src0 = __lasx_xvshuf_b(src1, src0, mask); + res = __lasx_xvdp2_h_bu(src0, coeff_vec); + res = __lasx_xvslli_h(res, 3); + res = __lasx_xvssrarni_bu_h(res, res, 6); + __lasx_xvstelm_w(res, dst, 0, 0); + __lasx_xvstelm_w(res, dst + stride, 0, 1); +} + +static void avc_chroma_hz_4x4_lasx(uint8_t *src, uint8_t *dst, ptrdiff_t stride, + uint32_t coeff0, uint32_t coeff1) +{ + ptrdiff_t stride_2 = stride << 1; + ptrdiff_t stride_3 = stride_2 + stride; + __m256i src0, src1, src2, src3; + __m256i res, mask; + __m256i coeff_vec0 = __lasx_xvreplgr2vr_b(coeff0); + __m256i coeff_vec1 = __lasx_xvreplgr2vr_b(coeff1); + __m256i coeff_vec = __lasx_xvilvl_b(coeff_vec0, coeff_vec1); + + DUP2_ARG2(__lasx_xvld, chroma_mask_arr, 32, src, 0, mask, src0); + DUP2_ARG2(__lasx_xvldx, src, stride, src, stride_2, src1, src2); + src3 = __lasx_xvldx(src, stride_3); + DUP2_ARG3(__lasx_xvshuf_b, src1, src0, mask, src3, src2, mask, src0, src2); + src0 = __lasx_xvpermi_q(src0, src2, 0x02); + res = __lasx_xvdp2_h_bu(src0, coeff_vec); + res = __lasx_xvslli_h(res, 3); + res = __lasx_xvssrarni_bu_h(res, res, 6); + __lasx_xvstelm_w(res, dst, 0, 0); + __lasx_xvstelm_w(res, dst + stride, 0, 1); + __lasx_xvstelm_w(res, dst + stride_2, 0, 4); + __lasx_xvstelm_w(res, dst + stride_3, 0, 5); +} + +static void avc_chroma_hz_4x8_lasx(uint8_t *src, uint8_t *dst, ptrdiff_t stride, + uint32_t coeff0, uint32_t coeff1) +{ + ptrdiff_t stride_2 = stride << 1; + ptrdiff_t stride_3 = stride_2 + stride; + ptrdiff_t stride_4 = stride_2 << 1; + __m256i src0, src1, src2, src3, src4, src5, src6, src7; + __m256i res0, res1, mask; + __m256i coeff_vec0 = __lasx_xvreplgr2vr_b(coeff0); + __m256i coeff_vec1 = __lasx_xvreplgr2vr_b(coeff1); + __m256i coeff_vec = __lasx_xvilvl_b(coeff_vec0, coeff_vec1); + + coeff_vec = __lasx_xvslli_b(coeff_vec, 3); + DUP2_ARG2(__lasx_xvld, chroma_mask_arr, 32, src, 0, mask, src0); + DUP4_ARG2(__lasx_xvldx, src, stride, src, stride_2, src, stride_3, + src, stride_4, src1, src2, src3, src4); + src += stride_4; + DUP2_ARG2(__lasx_xvldx, src, stride, src, stride_2, src5, src6); + src7 = __lasx_xvldx(src, stride_3); + DUP4_ARG3(__lasx_xvshuf_b, src1, src0, mask, src3, src2, mask, src5, src4, mask, + src7, src6, mask, src0, src2, src4, src6); + DUP2_ARG3(__lasx_xvpermi_q, src0, src2, 0x02, src4, src6, 0x02, src0, src4); + DUP2_ARG2(__lasx_xvdp2_h_bu, src0, coeff_vec, src4, coeff_vec, res0, res1); + res0 = __lasx_xvssrarni_bu_h(res1, res0, 6); + __lasx_xvstelm_w(res0, dst, 0, 0); + __lasx_xvstelm_w(res0, dst + stride, 0, 1); + __lasx_xvstelm_w(res0, dst + stride_2, 0, 4); + __lasx_xvstelm_w(res0, dst + stride_3, 0, 5); + dst += stride_4; + __lasx_xvstelm_w(res0, dst, 0, 2); + __lasx_xvstelm_w(res0, dst + stride, 0, 3); + __lasx_xvstelm_w(res0, dst + stride_2, 0, 6); + __lasx_xvstelm_w(res0, dst + stride_3, 0, 7); +} + +static void avc_chroma_hz_4w_lasx(uint8_t *src, uint8_t *dst, ptrdiff_t stride, + uint32_t coeff0, uint32_t coeff1, + int32_t height) +{ + if (8 == height) { + avc_chroma_hz_4x8_lasx(src, dst, stride, coeff0, coeff1); + } else if (4 == height) { + avc_chroma_hz_4x4_lasx(src, dst, stride, coeff0, coeff1); + } else if (2 == height) { + avc_chroma_hz_4x2_lasx(src, dst, stride, coeff0, coeff1); + } +} + static void avc_chroma_hz_8w_lasx(uint8_t *src, uint8_t *dst, ptrdiff_t stride, uint32_t coeff0, uint32_t coeff1, int32_t height) @@ -454,6 +614,110 @@ static void avc_chroma_hz_8w_lasx(uint8_t *src, uint8_t *dst, ptrdiff_t stride, } } +static void avc_chroma_vt_4x2_lasx(uint8_t *src, uint8_t *dst, ptrdiff_t stride, + uint32_t coeff0, uint32_t coeff1) +{ + __m256i src0, src1, src2; + __m256i tmp0, tmp1; + __m256i res; + __m256i coeff_vec0 = __lasx_xvreplgr2vr_b(coeff0); + __m256i coeff_vec1 = __lasx_xvreplgr2vr_b(coeff1); + __m256i coeff_vec = __lasx_xvilvl_b(coeff_vec0, coeff_vec1); + + src0 = __lasx_xvld(src, 0); + DUP2_ARG2(__lasx_xvldx, src, stride, src, stride << 1, src1, src2); + DUP2_ARG2(__lasx_xvilvl_b, src1, src0, src2, src1, tmp0, tmp1); + tmp0 = __lasx_xvilvl_d(tmp1, tmp0); + res = __lasx_xvdp2_h_bu(tmp0, coeff_vec); + res = __lasx_xvslli_h(res, 3); + res = __lasx_xvssrarni_bu_h(res, res, 6); + __lasx_xvstelm_w(res, dst, 0, 0); + __lasx_xvstelm_w(res, dst + stride, 0, 1); +} + +static void avc_chroma_vt_4x4_lasx(uint8_t *src, uint8_t *dst, ptrdiff_t stride, + uint32_t coeff0, uint32_t coeff1) +{ + ptrdiff_t stride_2 = stride << 1; + ptrdiff_t stride_3 = stride_2 + stride; + ptrdiff_t stride_4 = stride_2 << 1; + __m256i src0, src1, src2, src3, src4; + __m256i tmp0, tmp1, tmp2, tmp3; + __m256i res; + __m256i coeff_vec0 = __lasx_xvreplgr2vr_b(coeff0); + __m256i coeff_vec1 = __lasx_xvreplgr2vr_b(coeff1); + __m256i coeff_vec = __lasx_xvilvl_b(coeff_vec0, coeff_vec1); + + src0 = __lasx_xvld(src, 0); + DUP4_ARG2(__lasx_xvldx, src, stride, src, stride_2, src, stride_3, + src, stride_4, src1, src2, src3, src4); + DUP4_ARG2(__lasx_xvilvl_b, src1, src0, src2, src1, src3, src2, src4, src3, + tmp0, tmp1, tmp2, tmp3); + DUP2_ARG2(__lasx_xvilvl_d, tmp1, tmp0, tmp3, tmp2, tmp0, tmp2); + tmp0 = __lasx_xvpermi_q(tmp0, tmp2, 0x02); + res = __lasx_xvdp2_h_bu(tmp0, coeff_vec); + res = __lasx_xvslli_h(res, 3); + res = __lasx_xvssrarni_bu_h(res, res, 6); + __lasx_xvstelm_w(res, dst, 0, 0); + __lasx_xvstelm_w(res, dst + stride, 0, 1); + __lasx_xvstelm_w(res, dst + stride_2, 0, 4); + __lasx_xvstelm_w(res, dst + stride_3, 0, 5); +} + +static void avc_chroma_vt_4x8_lasx(uint8_t *src, uint8_t *dst, ptrdiff_t stride, + uint32_t coeff0, uint32_t coeff1) +{ + ptrdiff_t stride_2 = stride << 1; + ptrdiff_t stride_3 = stride_2 + stride; + ptrdiff_t stride_4 = stride_2 << 1; + __m256i src0, src1, src2, src3, src4, src5, src6, src7, src8; + __m256i tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + __m256i res0, res1; + __m256i coeff_vec0 = __lasx_xvreplgr2vr_b(coeff0); + __m256i coeff_vec1 = __lasx_xvreplgr2vr_b(coeff1); + __m256i coeff_vec = __lasx_xvilvl_b(coeff_vec0, coeff_vec1); + + coeff_vec = __lasx_xvslli_b(coeff_vec, 3); + src0 = __lasx_xvld(src, 0); + DUP4_ARG2(__lasx_xvldx, src, stride, src, stride_2, src, stride_3, + src, stride_4, src1, src2, src3, src4); + src += stride_4; + DUP4_ARG2(__lasx_xvldx, src, stride, src, stride_2, src, stride_3, + src, stride_4, src5, src6, src7, src8); + DUP4_ARG2(__lasx_xvilvl_b, src1, src0, src2, src1, src3, src2, src4, src3, + tmp0, tmp1, tmp2, tmp3); + DUP4_ARG2(__lasx_xvilvl_b, src5, src4, src6, src5, src7, src6, src8, src7, + tmp4, tmp5, tmp6, tmp7); + DUP4_ARG2(__lasx_xvilvl_d, tmp1, tmp0, tmp3, tmp2, tmp5, tmp4, tmp7, tmp6, + tmp0, tmp2, tmp4, tmp6); + tmp0 = __lasx_xvpermi_q(tmp0, tmp2, 0x02); + tmp4 = __lasx_xvpermi_q(tmp4, tmp6, 0x02); + DUP2_ARG2(__lasx_xvdp2_h_bu, tmp0, coeff_vec, tmp4, coeff_vec, res0, res1); + res0 = __lasx_xvssrarni_bu_h(res1, res0, 6); + __lasx_xvstelm_w(res0, dst, 0, 0); + __lasx_xvstelm_w(res0, dst + stride, 0, 1); + __lasx_xvstelm_w(res0, dst + stride_2, 0, 4); + __lasx_xvstelm_w(res0, dst + stride_3, 0, 5); + dst += stride_4; + __lasx_xvstelm_w(res0, dst, 0, 2); + __lasx_xvstelm_w(res0, dst + stride, 0, 3); + __lasx_xvstelm_w(res0, dst + stride_2, 0, 6); + __lasx_xvstelm_w(res0, dst + stride_3, 0, 7); +} + +static void avc_chroma_vt_4w_lasx(uint8_t *src, uint8_t *dst, ptrdiff_t stride, + uint32_t coeff0, uint32_t coeff1, + int32_t height) +{ + if (8 == height) { + avc_chroma_vt_4x8_lasx(src, dst, stride, coeff0, coeff1); + } else if (4 == height) { + avc_chroma_vt_4x4_lasx(src, dst, stride, coeff0, coeff1); + } else if (2 == height) { + avc_chroma_vt_4x2_lasx(src, dst, stride, coeff0, coeff1); + } +} + static void avc_chroma_vt_8w_lasx(uint8_t *src, uint8_t *dst, ptrdiff_t stride, uint32_t coeff0, uint32_t coeff1, int32_t height) @@ -465,6 +729,76 @@ static void avc_chroma_vt_8w_lasx(uint8_t *src, uint8_t *dst, ptrdiff_t stride, } } +static void copy_width4_lasx(uint8_t *src, uint8_t *dst, ptrdiff_t stride, + int32_t height) +{ + uint32_t tp0, tp1, tp2, tp3, tp4, tp5, tp6, tp7; + + if (8 == height) { + ptrdiff_t stride_2, stride_3, stride_4; + + __asm__ volatile ( + "slli.d %[stride_2], %[stride], 1 \n\t" + "add.d %[stride_3], %[stride_2], %[stride] \n\t" + "slli.d %[stride_4], %[stride_2], 1 \n\t" + "ld.wu %[tp0], %[src], 0 \n\t" + "ldx.wu %[tp1], %[src], %[stride] \n\t" + "ldx.wu %[tp2], %[src], %[stride_2] \n\t" + "ldx.wu %[tp3], %[src], %[stride_3] \n\t" + "add.d %[src], %[src], %[stride_4] \n\t" + "ld.wu %[tp4], %[src], 0 \n\t" + "ldx.wu %[tp5], %[src], %[stride] \n\t" + "ldx.wu %[tp6], %[src], %[stride_2] \n\t" + "ldx.wu %[tp7], %[src], %[stride_3] \n\t" + "st.w %[tp0], %[dst], 0 \n\t" + "stx.w %[tp1], %[dst], %[stride] \n\t" + "stx.w %[tp2], %[dst], %[stride_2] \n\t" + "stx.w %[tp3], %[dst], %[stride_3] \n\t" + "add.d %[dst], %[dst], %[stride_4] \n\t" + "st.w %[tp4], %[dst], 0 \n\t" + "stx.w %[tp5], %[dst], %[stride] \n\t" + "stx.w %[tp6], %[dst], %[stride_2] \n\t" + "stx.w %[tp7], %[dst], %[stride_3] \n\t" + : [stride_2]"+&r"(stride_2), [stride_3]"+&r"(stride_3), [stride_4]"+&r"(stride_4), + [src]"+&r"(src), [dst]"+&r"(dst), [tp0]"+&r"(tp0), [tp1]"+&r"(tp1), + [tp2]"+&r"(tp2), [tp3]"+&r"(tp3), [tp4]"+&r"(tp4), [tp5]"+&r"(tp5), + [tp6]"+&r"(tp6), [tp7]"+&r"(tp7) + : [stride]"r"(stride) + : "memory" + ); + } else if (4 == height) { + ptrdiff_t stride_2, stride_3; + + __asm__ volatile ( + "slli.d %[stride_2], %[stride], 1 \n\t" + "add.d %[stride_3], %[stride_2], %[stride] \n\t" + "ld.wu %[tp0], %[src], 0 \n\t" + "ldx.wu %[tp1], %[src], %[stride] \n\t" + "ldx.wu %[tp2], %[src], %[stride_2] \n\t" + "ldx.wu %[tp3], %[src], %[stride_3] \n\t" + "st.w %[tp0], %[dst], 0 \n\t" + "stx.w %[tp1], %[dst], %[stride] \n\t" + "stx.w %[tp2], %[dst], %[stride_2] \n\t" + "stx.w %[tp3], %[dst], %[stride_3] \n\t" + : [stride_2]"+&r"(stride_2), [stride_3]"+&r"(stride_3), + [src]"+&r"(src), [dst]"+&r"(dst), [tp0]"+&r"(tp0), [tp1]"+&r"(tp1), + [tp2]"+&r"(tp2), [tp3]"+&r"(tp3) + : [stride]"r"(stride) + : "memory" + ); + } else if (2 == height) { + __asm__ volatile ( + "ld.wu %[tp0], %[src], 0 \n\t" + "ldx.wu %[tp1], %[src], %[stride] \n\t" + "st.w %[tp0], %[dst], 0 \n\t" + "stx.w %[tp1], %[dst], %[stride] \n\t" + : [tp0]"+&r"(tp0), [tp1]"+&r"(tp1) + : [src]"r"(src), [dst]"r"(dst), [stride]"r"(stride) + : "memory" + ); + } +} + static void copy_width8_lasx(uint8_t *src, uint8_t *dst, ptrdiff_t stride, int32_t height) { @@ -475,6 +809,22 @@ static void copy_width8_lasx(uint8_t *src, uint8_t *dst, ptrdiff_t stride, } } +void ff_put_h264_chroma_mc4_lasx(uint8_t *dst, uint8_t *src, ptrdiff_t stride, + int height, int x, int y) +{ + av_assert2(x < 8 && y < 8 && x >= 0 && y >= 0); + + if(x && y) { + avc_chroma_hv_4w_lasx(src, dst, stride, x, (8 - x), y, (8 - y), height); + } else if (x) { + avc_chroma_hz_4w_lasx(src, dst, stride, x, (8 - x), height); + } else if (y) { + avc_chroma_vt_4w_lasx(src, dst, stride, y, (8 - y), height); + } else { + copy_width4_lasx(src, dst, stride, height); + } +} + void ff_put_h264_chroma_mc8_lasx(uint8_t *dst, uint8_t *src, ptrdiff_t stride, int height, int x, int y) { @@ -521,14 +871,9 @@ static av_always_inline void avc_chroma_hv_and_aver_dst_8x4_lasx(uint8_t *src, res_vt1 = __lasx_xvmul_h(res_hz2, coeff_vt_vec0); res_hz0 = __lasx_xvpermi_q(res_hz1, res_hz0, 0x20); res_hz1 = __lasx_xvpermi_q(res_hz1, res_hz2, 0x3); - res_hz0 = __lasx_xvmul_h(res_hz0, coeff_vt_vec1); - res_hz1 = __lasx_xvmul_h(res_hz1, coeff_vt_vec1); - res_vt0 = __lasx_xvadd_h(res_vt0, res_hz0); - res_vt1 = __lasx_xvadd_h(res_vt1, res_hz1); - DUP2_ARG2(__lasx_xvsrari_h, res_vt0, 6, res_vt1, 6, res_vt0, res_vt1); - res_vt0 = __lasx_xvsat_hu(res_vt0, 7); - res_vt1 = __lasx_xvsat_hu(res_vt1, 7); - out = __lasx_xvpickev_b(res_vt1, res_vt0); + res_vt0 = __lasx_xvmadd_h(res_vt0, res_hz0, coeff_vt_vec1); + res_vt1 = __lasx_xvmadd_h(res_vt1, res_hz1, coeff_vt_vec1); + out = __lasx_xvssrarni_bu_h(res_vt1, res_vt0, 6); DUP4_ARG2(__lasx_xvldx, dst, 0, dst, stride, dst, stride_2x, dst, stride_3x, tp0, tp1, tp2, tp3); DUP2_ARG2(__lasx_xvilvl_d, tp2, tp0, tp3, tp1, tp0, tp2); @@ -583,21 +928,12 @@ static av_always_inline void avc_chroma_hv_and_aver_dst_8x8_lasx(uint8_t *src, res_hz1 = __lasx_xvpermi_q(res_hz1, res_hz2, 0x3); res_hz2 = __lasx_xvpermi_q(res_hz2, res_hz3, 0x3); res_hz3 = __lasx_xvpermi_q(res_hz3, res_hz4, 0x3); - res_hz0 = __lasx_xvmul_h(res_hz0, coeff_vt_vec1); - res_hz1 = __lasx_xvmul_h(res_hz1, coeff_vt_vec1); - res_hz2 = __lasx_xvmul_h(res_hz2, coeff_vt_vec1); - res_hz3 = __lasx_xvmul_h(res_hz3, coeff_vt_vec1); - res_vt0 = __lasx_xvadd_h(res_vt0, res_hz0); - res_vt1 = __lasx_xvadd_h(res_vt1, res_hz1); - res_vt2 = __lasx_xvadd_h(res_vt2, res_hz2); - res_vt3 = __lasx_xvadd_h(res_vt3, res_hz3); - DUP4_ARG2(__lasx_xvsrari_h, res_vt0, 6, res_vt1, 6, res_vt2, 6, res_vt3, 6, - res_vt0, res_vt1, res_vt2, res_vt3); - res_vt0 = __lasx_xvsat_hu(res_vt0, 7); - res_vt1 = __lasx_xvsat_hu(res_vt1, 7); - res_vt2 = __lasx_xvsat_hu(res_vt2, 7); - res_vt3 = __lasx_xvsat_hu(res_vt3, 7); - DUP2_ARG2(__lasx_xvpickev_b, res_vt1, res_vt0, res_vt3, res_vt2, out0, out1); + res_vt0 = __lasx_xvmadd_h(res_vt0, res_hz0, coeff_vt_vec1); + res_vt1 = __lasx_xvmadd_h(res_vt1, res_hz1, coeff_vt_vec1); + res_vt2 = __lasx_xvmadd_h(res_vt2, res_hz2, coeff_vt_vec1); + res_vt3 = __lasx_xvmadd_h(res_vt3, res_hz3, coeff_vt_vec1); + DUP2_ARG3(__lasx_xvssrarni_bu_h, res_vt1, res_vt0, 6, res_vt3, res_vt2, 6, + out0, out1); DUP4_ARG2(__lasx_xvldx, dst, 0, dst, stride, dst, stride_2x, dst, stride_3x, tp0, tp1, tp2, tp3); DUP2_ARG2(__lasx_xvilvl_d, tp2, tp0, tp3, tp1, tp0, tp2); @@ -635,18 +971,14 @@ static av_always_inline void avc_chroma_hz_and_aver_dst_8x4_lasx(uint8_t *src, __m256i coeff_vec1 = __lasx_xvreplgr2vr_b(coeff1); __m256i coeff_vec = __lasx_xvilvl_b(coeff_vec0, coeff_vec1); + coeff_vec = __lasx_xvslli_b(coeff_vec, 3); mask = __lasx_xvld(chroma_mask_arr, 0); DUP4_ARG2(__lasx_xvldx, src, 0, src, stride, src, stride_2x, src, stride_3x, src0, src1, src2, src3); DUP2_ARG3(__lasx_xvpermi_q, src1, src0, 0x20, src3, src2, 0x20, src0, src2); DUP2_ARG3(__lasx_xvshuf_b, src0, src0, mask, src2, src2, mask, src0, src2); DUP2_ARG2(__lasx_xvdp2_h_bu, src0, coeff_vec, src2, coeff_vec, res0, res1); - res0 = __lasx_xvslli_h(res0, 3); - res1 = __lasx_xvslli_h(res1, 3); - DUP2_ARG2(__lasx_xvsrari_h, res0, 6, res1, 6, res0, res1); - res0 = __lasx_xvsat_hu(res0, 7); - res1 = __lasx_xvsat_hu(res1, 7); - out = __lasx_xvpickev_b(res1, res0); + out = __lasx_xvssrarni_bu_h(res1, res0, 6); DUP4_ARG2(__lasx_xvldx, dst, 0, dst, stride, dst, stride_2x, dst, stride_3x, tp0, tp1, tp2, tp3); DUP2_ARG2(__lasx_xvilvl_d, tp2, tp0, tp3, tp1, tp0, tp2); @@ -674,6 +1006,7 @@ static av_always_inline void avc_chroma_hz_and_aver_dst_8x8_lasx(uint8_t *src, __m256i coeff_vec1 = __lasx_xvreplgr2vr_b(coeff1); __m256i coeff_vec = __lasx_xvilvl_b(coeff_vec0, coeff_vec1); + coeff_vec = __lasx_xvslli_b(coeff_vec, 3); mask = __lasx_xvld(chroma_mask_arr, 0); DUP4_ARG2(__lasx_xvldx, src, 0, src, stride, src, stride_2x, src, stride_3x, src0, src1, src2, src3); @@ -686,16 +1019,7 @@ static av_always_inline void avc_chroma_hz_and_aver_dst_8x8_lasx(uint8_t *src, mask, src6, src6, mask, src0, src2, src4, src6); DUP4_ARG2(__lasx_xvdp2_h_bu, src0, coeff_vec, src2, coeff_vec, src4, coeff_vec, src6, coeff_vec, res0, res1, res2, res3); - res0 = __lasx_xvslli_h(res0, 3); - res1 = __lasx_xvslli_h(res1, 3); - res2 = __lasx_xvslli_h(res2, 3); - res3 = __lasx_xvslli_h(res3, 3); - DUP4_ARG2(__lasx_xvsrari_h, res0, 6, res1, 6, res2, 6, res3, 6, res0, res1, res2, res3); - res0 = __lasx_xvsat_hu(res0, 7); - res1 = __lasx_xvsat_hu(res1, 7); - res2 = __lasx_xvsat_hu(res2, 7); - res3 = __lasx_xvsat_hu(res3, 7); - DUP2_ARG2(__lasx_xvpickev_b, res1, res0, res3, res2, out0, out1); + DUP2_ARG3(__lasx_xvssrarni_bu_h, res1, res0, 6, res3, res2, 6, out0, out1); DUP4_ARG2(__lasx_xvldx, dst, 0, dst, stride, dst, stride_2x, dst, stride_3x, tp0, tp1, tp2, tp3); DUP2_ARG2(__lasx_xvilvl_d, tp2, tp0, tp3, tp1, tp0, tp2); @@ -733,6 +1057,7 @@ static av_always_inline void avc_chroma_vt_and_aver_dst_8x4_lasx(uint8_t *src, __m256i coeff_vec1 = __lasx_xvreplgr2vr_b(coeff1); __m256i coeff_vec = __lasx_xvilvl_b(coeff_vec0, coeff_vec1); + coeff_vec = __lasx_xvslli_b(coeff_vec, 3); src0 = __lasx_xvld(src, 0); DUP4_ARG2(__lasx_xvldx, src, stride, src, stride_2x, src, stride_3x, src, stride_4x, src1, src2, src3, src4); @@ -740,12 +1065,7 @@ static av_always_inline void avc_chroma_vt_and_aver_dst_8x4_lasx(uint8_t *src, src4, src3, 0x20, src0, src1, src2, src3); DUP2_ARG2(__lasx_xvilvl_b, src1, src0, src3, src2, src0, src2); DUP2_ARG2(__lasx_xvdp2_h_bu, src0, coeff_vec, src2, coeff_vec, res0, res1); - res0 = __lasx_xvslli_h(res0, 3); - res1 = __lasx_xvslli_h(res1, 3); - DUP2_ARG2(__lasx_xvsrari_h, res0, 6, res1, 6, res0, res1) - res0 = __lasx_xvsat_hu(res0, 7); - res1 = __lasx_xvsat_hu(res1, 7); - out = __lasx_xvpickev_b(res1, res0); + out = __lasx_xvssrarni_bu_h(res1, res0, 6); DUP4_ARG2(__lasx_xvldx, dst, 0, dst, stride, dst, stride_2x, dst, stride_3x, tp0, tp1, tp2, tp3); DUP2_ARG2(__lasx_xvilvl_d, tp2, tp0, tp3, tp1, tp0, tp2); @@ -772,6 +1092,7 @@ static av_always_inline void avc_chroma_vt_and_aver_dst_8x8_lasx(uint8_t *src, __m256i coeff_vec1 = __lasx_xvreplgr2vr_b(coeff1); __m256i coeff_vec = __lasx_xvilvl_b(coeff_vec0, coeff_vec1); + coeff_vec = __lasx_xvslli_b(coeff_vec, 3); src0 = __lasx_xvld(src, 0); src += stride; DUP4_ARG2(__lasx_xvldx, src, 0, src, stride, src, stride_2x, src, stride_3x, @@ -787,17 +1108,7 @@ static av_always_inline void avc_chroma_vt_and_aver_dst_8x8_lasx(uint8_t *src, src0, src2, src4, src6); DUP4_ARG2(__lasx_xvdp2_h_bu, src0, coeff_vec, src2, coeff_vec, src4, coeff_vec, src6, coeff_vec, res0, res1, res2, res3); - res0 = __lasx_xvslli_h(res0, 3); - res1 = __lasx_xvslli_h(res1, 3); - res2 = __lasx_xvslli_h(res2, 3); - res3 = __lasx_xvslli_h(res3, 3); - DUP4_ARG2(__lasx_xvsrari_h, res0, 6, res1, 6, res2, 6, res3, 6, - res0, res1, res2, res3); - res0 = __lasx_xvsat_hu(res0, 7); - res1 = __lasx_xvsat_hu(res1, 7); - res2 = __lasx_xvsat_hu(res2, 7); - res3 = __lasx_xvsat_hu(res3, 7); - DUP2_ARG2(__lasx_xvpickev_b, res1, res0, res3, res2, out0, out1); + DUP2_ARG3(__lasx_xvssrarni_bu_h, res1, res0, 6, res3, res2, 6, out0, out1); DUP4_ARG2(__lasx_xvldx, dst, 0, dst, stride, dst, stride_2x, dst, stride_3x, tp0, tp1, tp2, tp3); DUP2_ARG2(__lasx_xvilvl_d, tp2, tp0, tp3, tp1, tp0, tp2); diff --git a/libavcodec/loongarch/h264chroma_lasx.h b/libavcodec/loongarch/h264chroma_lasx.h index 3b70e1dccb..4aac8db8cb 100644 --- a/libavcodec/loongarch/h264chroma_lasx.h +++ b/libavcodec/loongarch/h264chroma_lasx.h @@ -26,6 +26,8 @@ #include #include "libavcodec/h264.h" +void ff_put_h264_chroma_mc4_lasx(uint8_t *dst, uint8_t *src, ptrdiff_t stride, + int h, int x, int y); void ff_put_h264_chroma_mc8_lasx(uint8_t *dst, uint8_t *src, ptrdiff_t stride, int h, int x, int y); void ff_avg_h264_chroma_mc8_lasx(uint8_t *dst, uint8_t *src, ptrdiff_t stride, diff --git a/libavcodec/loongarch/h264dsp_init_loongarch.c b/libavcodec/loongarch/h264dsp_init_loongarch.c index f1b927c72e..e02e3d7fa9 100644 --- a/libavcodec/loongarch/h264dsp_init_loongarch.c +++ b/libavcodec/loongarch/h264dsp_init_loongarch.c @@ -32,6 +32,8 @@ av_cold void ff_h264dsp_init_loongarch(H264DSPContext *c, const int bit_depth, if (chroma_format_idc <= 1) c->h264_loop_filter_strength = ff_h264_loop_filter_strength_lasx; if (bit_depth == 8) { + c->h264_add_pixels4_clear = ff_h264_add_pixels4_8_lasx; + c->h264_add_pixels8_clear = ff_h264_add_pixels8_8_lasx; c->h264_v_loop_filter_luma = ff_h264_v_lpf_luma_8_lasx; c->h264_h_loop_filter_luma = ff_h264_h_lpf_luma_8_lasx; c->h264_v_loop_filter_luma_intra = ff_h264_v_lpf_luma_intra_8_lasx; diff --git a/libavcodec/loongarch/h264dsp_lasx.c b/libavcodec/loongarch/h264dsp_lasx.c index 873c109413..b6f8b158e9 100644 --- a/libavcodec/loongarch/h264dsp_lasx.c +++ b/libavcodec/loongarch/h264dsp_lasx.c @@ -2000,3 +2000,85 @@ void ff_weight_h264_pixels4_8_lasx(uint8_t *src, ptrdiff_t stride, avc_wgt_4x8_lasx(src, stride, log2_denom, weight_src, offset); } } + +void ff_h264_add_pixels4_8_lasx(uint8_t *_dst, int16_t *_src, int stride) +{ + __m256i src0, dst0, dst1, dst2, dst3, zero; + __m256i tmp0, tmp1; + uint8_t* _dst1 = _dst + stride; + uint8_t* _dst2 = _dst1 + stride; + uint8_t* _dst3 = _dst2 + stride; + + src0 = __lasx_xvld(_src, 0); + dst0 = __lasx_xvldrepl_w(_dst, 0); + dst1 = __lasx_xvldrepl_w(_dst1, 0); + dst2 = __lasx_xvldrepl_w(_dst2, 0); + dst3 = __lasx_xvldrepl_w(_dst3, 0); + tmp0 = __lasx_xvilvl_w(dst1, dst0); + tmp1 = __lasx_xvilvl_w(dst3, dst2); + dst0 = __lasx_xvilvl_d(tmp1, tmp0); + tmp0 = __lasx_vext2xv_hu_bu(dst0); + zero = __lasx_xvldi(0); + tmp1 = __lasx_xvadd_h(src0, tmp0); + dst0 = __lasx_xvpickev_b(tmp1, tmp1); + __lasx_xvstelm_w(dst0, _dst, 0, 0); + __lasx_xvstelm_w(dst0, _dst1, 0, 1); + __lasx_xvstelm_w(dst0, _dst2, 0, 4); + __lasx_xvstelm_w(dst0, _dst3, 0, 5); + __lasx_xvst(zero, _src, 0); +} + +void ff_h264_add_pixels8_8_lasx(uint8_t *_dst, int16_t *_src, int stride) +{ + __m256i src0, src1, src2, src3; + __m256i dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + __m256i tmp0, tmp1, tmp2, tmp3; + __m256i zero = __lasx_xvldi(0); + uint8_t *_dst1 = _dst + stride; + uint8_t *_dst2 = _dst1 + stride; + uint8_t *_dst3 = _dst2 + stride; + uint8_t *_dst4 = _dst3 + stride; + uint8_t *_dst5 = _dst4 + stride; + uint8_t *_dst6 = _dst5 + stride; + uint8_t *_dst7 = _dst6 + stride; + + src0 = __lasx_xvld(_src, 0); + src1 = __lasx_xvld(_src, 32); + src2 = __lasx_xvld(_src, 64); + src3 = __lasx_xvld(_src, 96); + dst0 = __lasx_xvldrepl_d(_dst, 0); + dst1 = __lasx_xvldrepl_d(_dst1, 0); + dst2 = __lasx_xvldrepl_d(_dst2, 0); + dst3 = __lasx_xvldrepl_d(_dst3, 0); + dst4 = __lasx_xvldrepl_d(_dst4, 0); + dst5 = __lasx_xvldrepl_d(_dst5, 0); + dst6 = __lasx_xvldrepl_d(_dst6, 0); + dst7 = __lasx_xvldrepl_d(_dst7, 0); + tmp0 = __lasx_xvilvl_d(dst1, dst0); + tmp1 = __lasx_xvilvl_d(dst3, dst2); + tmp2 = __lasx_xvilvl_d(dst5, dst4); + tmp3 = __lasx_xvilvl_d(dst7, dst6); + dst0 = __lasx_vext2xv_hu_bu(tmp0); + dst1 = __lasx_vext2xv_hu_bu(tmp1); + dst1 = __lasx_vext2xv_hu_bu(tmp1); + dst2 = __lasx_vext2xv_hu_bu(tmp2); + dst3 = __lasx_vext2xv_hu_bu(tmp3); + tmp0 = __lasx_xvadd_h(src0, dst0); + tmp1 = __lasx_xvadd_h(src1, dst1); + tmp2 = __lasx_xvadd_h(src2, dst2); + tmp3 = __lasx_xvadd_h(src3, dst3); + dst1 = __lasx_xvpickev_b(tmp1, tmp0); + dst2 = __lasx_xvpickev_b(tmp3, tmp2); + __lasx_xvst(zero, _src, 0); + __lasx_xvst(zero, _src, 32); + __lasx_xvst(zero, _src, 64); + __lasx_xvst(zero, _src, 96); + __lasx_xvstelm_d(dst1, _dst, 0, 0); + __lasx_xvstelm_d(dst1, _dst1, 0, 2); + __lasx_xvstelm_d(dst1, _dst2, 0, 1); + __lasx_xvstelm_d(dst1, _dst3, 0, 3); + __lasx_xvstelm_d(dst2, _dst4, 0, 0); + __lasx_xvstelm_d(dst2, _dst5, 0, 2); + __lasx_xvstelm_d(dst2, _dst6, 0, 1); + __lasx_xvstelm_d(dst2, _dst7, 0, 3); +} diff --git a/libavcodec/loongarch/h264dsp_lasx.h b/libavcodec/loongarch/h264dsp_lasx.h index 54c57853a2..f3dcc0f3e3 100644 --- a/libavcodec/loongarch/h264dsp_lasx.h +++ b/libavcodec/loongarch/h264dsp_lasx.h @@ -96,4 +96,8 @@ void ff_h264_loop_filter_strength_lasx(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_lasx(uint8_t *_dst, int16_t *_src, int stride); + +void ff_h264_add_pixels8_8_lasx(uint8_t *_dst, int16_t *_src, int stride); #endif // #ifndef AVCODEC_LOONGARCH_H264DSP_LASX_H diff --git a/libavutil/intmath.h b/libavutil/intmath.h index 9573109e9d..6d35a6f9e0 100644 --- a/libavutil/intmath.h +++ b/libavutil/intmath.h @@ -32,6 +32,9 @@ #if ARCH_X86 # include "x86/intmath.h" #endif +#if ARCH_LOONGARCH64 +# include "loongarch/intmath.h" +#endif #if HAVE_FAST_CLZ #if AV_GCC_VERSION_AT_LEAST(3,4) diff --git a/libavutil/loongarch/intmath.h b/libavutil/loongarch/intmath.h new file mode 100644 index 0000000000..c095b3a3e4 --- /dev/null +++ b/libavutil/loongarch/intmath.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + * Contributed by Hao Chen + * + * 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 + */ + +#ifndef AVUTIL_LOONGARCH_INTMATH_H +#define AVUTIL_LOONGARCH_INTMATH_H + +#include +#include +#include "config.h" + +#if HAVE_FAST_CLZ + +static av_always_inline unsigned ff_loongarch_clz(unsigned _1) +{ + unsigned out; + __asm__ volatile ( + "clz.w %[out], %[in] \n\t" + : [out]"=&r"(out) + : [in]"r"(_1) + ); + return out; +} + +static av_always_inline int ff_loongarch_ctz_w(int _1) +{ + int out; + __asm__ volatile ( + "ctz.w %[out], %[in] \n\t" + "andi %[out], %[out], 31 \n\t" + : [out]"=&r"(out) + : [in]"r"(_1) + ); + return out; +} + +static av_always_inline int ff_loongarch_ctz_d(long long _1) +{ + int out; + __asm__ volatile ( + "ctz.d %[out], %[in] \n\t" + "andi %[out], %[out], 63 \n\t" + : [out]"=&r"(out) + : [in]"r"(_1) + ); + return out; +} + +#define ff_log2(x) (31 - ff_loongarch_clz((x)|1)) + +#define ff_clz(x) ff_loongarch_clz(x) +#define ff_ctz(x) ff_loongarch_ctz_w(x) +#define ff_ctzll(x) ff_loongarch_ctz_d(x) + +#endif /* HAVE_FAST_CLZ */ +#endif /* AVUTIL_LOONGARCH_INTMATH_H */