android_external_ffmpeg/libavcodec/x86/cavs_qpel.asm
Andreas Rheinhardt 650098955e avcodec/x86/cavs_qpel: Add SSE2 vertical motion compensation
This is not based on the MMXEXT one, because the latter is quite
suboptimal: Motion vector types mc01 and mc03 (vertical motion vectors
with remainder of one quarter or three quarter) use different neighboring
lines for interpolation: mc01 uses two lines above and two lines below,
mc03 one line above and three lines below. The MMXEXT code uses
a common macro for all of them and therefore reads six lines
before it processes them (even reading lines which are not used
at all), leading to severe register pressure.

Another difference to the old code is that the positive and negative
parts of the sum to calculate are accumulated separately and
the subtraction is performed with unsigned saturation, so
that one can avoid biasing the sum.

The fact that the mc01 and mc03 filter coefficients are mirrors
of each other has been exploited to reduce mc01 to mc03.

But of course the most important different difference between
this code and the MMXEXT one is that XMM registers allow to
process eight words at a time, ideal for 8x8 subblocks,
whereas the MMXEXT code processes them in 4x8 or 4x16 blocks.

Benchmarks:
avg_cavs_qpel_pixels_tab[0][4]_c:                      917.0 ( 1.00x)
avg_cavs_qpel_pixels_tab[0][4]_mmxext:                 222.0 ( 4.13x)
avg_cavs_qpel_pixels_tab[0][4]_sse2:                    89.0 (10.31x)
avg_cavs_qpel_pixels_tab[0][12]_c:                     885.7 ( 1.00x)
avg_cavs_qpel_pixels_tab[0][12]_mmxext:                223.2 ( 3.97x)
avg_cavs_qpel_pixels_tab[0][12]_sse2:                   88.5 (10.01x)
avg_cavs_qpel_pixels_tab[1][4]_c:                      222.4 ( 1.00x)
avg_cavs_qpel_pixels_tab[1][4]_mmxext:                  57.2 ( 3.89x)
avg_cavs_qpel_pixels_tab[1][4]_sse2:                    23.3 ( 9.55x)
avg_cavs_qpel_pixels_tab[1][12]_c:                     216.0 ( 1.00x)
avg_cavs_qpel_pixels_tab[1][12]_mmxext:                 57.4 ( 3.76x)
avg_cavs_qpel_pixels_tab[1][12]_sse2:                   22.6 ( 9.56x)
put_cavs_qpel_pixels_tab[0][4]_c:                      750.9 ( 1.00x)
put_cavs_qpel_pixels_tab[0][4]_mmxext:                 210.4 ( 3.57x)
put_cavs_qpel_pixels_tab[0][4]_sse2:                    84.2 ( 8.92x)
put_cavs_qpel_pixels_tab[0][12]_c:                     731.6 ( 1.00x)
put_cavs_qpel_pixels_tab[0][12]_mmxext:                210.7 ( 3.47x)
put_cavs_qpel_pixels_tab[0][12]_sse2:                   84.1 ( 8.70x)
put_cavs_qpel_pixels_tab[1][4]_c:                      191.7 ( 1.00x)
put_cavs_qpel_pixels_tab[1][4]_mmxext:                  53.8 ( 3.56x)
put_cavs_qpel_pixels_tab[1][4]_sse2:                    24.5 ( 7.83x)
put_cavs_qpel_pixels_tab[1][12]_c:                     179.1 ( 1.00x)
put_cavs_qpel_pixels_tab[1][12]_mmxext:                 53.9 ( 3.32x)
put_cavs_qpel_pixels_tab[1][12]_sse2:                   24.0 ( 7.47x)

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
2025-10-08 20:40:08 +02:00

220 lines
5.7 KiB
NASM

;*****************************************************************************
;* SSE2-optimized CAVS QPEL code
;*****************************************************************************
;* Copyright (c) 2006 Stefan Gehrer <stefan.gehrer@gmx.de>
;* based on H.264 optimizations by Michael Niedermayer and Loren Merritt
;* Copyright (c) 2025 Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
;*
;* 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"
SECTION_RODATA
cextern pw_4
cextern pw_5
cextern pw_7
cextern pw_64
pw_42: times 8 dw 42
pw_96: times 8 dw 96
SECTION .text
%macro op_avgh 3
movh %3, %2
pavgb %1, %3
movh %2, %1
%endmacro
%macro op_puth 2-3
movh %2, %1
%endmacro
%macro CAVS_QPEL_H 1
; ff_put_cavs_qpel8_mc20(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)
cglobal %1_cavs_qpel8_mc20, 3,4,6
mov r3d, 8
jmp %1_cavs_qpel8_h_after_prologue
; ff_put_cavs_qpel8_h(uint8_t *dst, const uint8_t *src, ptrdiff_t stride, int h)
cglobal %1_cavs_qpel8_h, 4,4,6
%1_cavs_qpel8_h_after_prologue:
mova m3, [pw_4]
mova m4, [pw_5]
pxor m5, m5
.loop:
movh m0, [r1]
movh m1, [r1+1]
punpcklbw m0, m5
punpcklbw m1, m5
paddw m0, m1
movh m1, [r1-1]
movh m2, [r1+2]
pmullw m0, m4
punpcklbw m1, m5
punpcklbw m2, m5
paddw m0, m3
add r1, r2
paddw m1, m2
psubw m0, m1
psraw m0, 3
packuswb m0, m5
op_%1h m0, [r0], m1
add r0, r2
dec r3d
jne .loop
RET
%endmacro
INIT_XMM sse2
CAVS_QPEL_H avg
CAVS_QPEL_H put
%macro FILT_V 1
movh m3, [r1]
punpcklbw m3, m7
mova m4, m1
paddw m4, m2
paddw m0, m3
add r1, r2
pmullw m4, m5
psubw m4, m0
paddw m4, m6
psraw m4, 3
packuswb m4, m7
op_%1h m4, [r0], m0
add r0, r2
SWAP 0, 1, 2, 3
%endmacro
%macro CAVS_QPEL_MC02 1
; ff_put_cavs_qpel8_mc02(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)
cglobal %1_cavs_qpel8_mc02, 3,4,8
mov r3d, 8
jmp %1_cavs_qpel8_v2_after_prologue
; ff_put_cavs_qpel8_v2(uint8_t *dst, const uint8_t *src, ptrdiff_t stride, int h)
cglobal %1_cavs_qpel8_v2, 4,4,8
%1_cavs_qpel8_v2_after_prologue:
movh m1, [r1]
sub r1, r2
movh m0, [r1]
lea r1, [r1+2*r2]
pxor m7, m7
movh m2, [r1]
add r1, r2
punpcklbw m1, m7
punpcklbw m0, m7
punpcklbw m2, m7
mova m5, [pw_5]
mova m6, [pw_4]
.loop:
FILT_V %1
FILT_V %1
FILT_V %1
FILT_V %1
sub r3d, 4
jne .loop
RET
%endmacro
INIT_XMM sse2
CAVS_QPEL_MC02 avg
CAVS_QPEL_MC02 put
%macro FILT_V3 1
pmullw m0, PW_7
movh m4, [r1]
mova m5, m1
mova m6, m2
pmullw m5, PW_42
punpcklbw m4, m7
pmullw m6, PW_96
paddw m0, m3
add r1, r2
paddw m0, m3
paddw m5, m6
paddw m0, m4
; m5-m0 can be in the -10*255..(42 + 96)*255 range and
; therefore is not guaranteed to fit into either a signed or
; an unsigned word. Because we need to clamp the result to 0..255
; anyway, we use saturated subtraction and a logical right shift
; for rescaling.
psubusw m5, m0
paddw m5, PW_64
psrlw m5, 7
packuswb m5, m7
op_%1h m5, [r0], m0
add r0, r2
SWAP 0, 1, 2, 3, 4
%endmacro
%macro CAVS_QPEL_MC03 1
; ff_put_cavs_qpel8_mc03(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)
cglobal %1_cavs_qpel8_mc03, 3,4,8+4*ARCH_X86_64
mov r3d, 8
jmp %1_cavs_qpel8_v3_after_prologue
; ff_put_cavs_qpel8_v3(uint8_t *dst, const uint8_t *src, ptrdiff_t stride, int h)
cglobal %1_cavs_qpel8_v3, 4,4,8+4*ARCH_X86_64
%1_cavs_qpel8_v3_after_prologue:
movh m1, [r1]
movh m2, [r1+r2]
movh m3, [r1+2*r2]
sub r1, r2
pxor m7, m7
movh m0, [r1]
lea r1, [r1+4*r2]
punpcklbw m1, m7
punpcklbw m2, m7
%if ARCH_X86_64
%define PW_7 m8
%define PW_42 m9
%define PW_96 m10
%define PW_64 m11
mova m8, [pw_7]
mova m9, [pw_42]
mova m10, [pw_96]
mova m11, [pw_64]
%else
%define PW_7 [pw_7]
%define PW_42 [pw_42]
%define PW_96 [pw_96]
%define PW_64 [pw_64]
%endif
punpcklbw m3, m7
punpcklbw m0, m7
.loop:
FILT_V3 %1
FILT_V3 %1
FILT_V3 %1
FILT_V3 %1
SWAP 0, 1, 2, 3, 4
mova m3, m2
mova m2, m1
mova m1, m0
mova m0, m4
sub r3d, 4
jne .loop
RET
%endmacro
INIT_XMM sse2
CAVS_QPEL_MC03 avg
CAVS_QPEL_MC03 put