vf_hqdn3d: x86 asm
authorLoren Merritt <lorenm@u.washington.edu>
Sun, 26 Aug 2012 10:26:42 +0000 (10:26 +0000)
committerLoren Merritt <pengvado@akuvian.org>
Sun, 26 Aug 2012 10:49:14 +0000 (10:49 +0000)
13% faster on penryn, 16% on sandybridge, 15% on bulldozer
Not simd; a compiler should have generated this, but gcc didn't.

libavfilter/vf_hqdn3d.c
libavfilter/x86/Makefile
libavfilter/x86/hqdn3d.asm [new file with mode: 0644]
libavutil/x86/x86inc.asm

index 499da1f..535657a 100644 (file)
@@ -41,8 +41,14 @@ typedef struct {
     double strength[4];
     int hsub, vsub;
     int depth;
+    void (*denoise_row[17])(uint8_t *src, uint8_t *dst, uint16_t *line_ant, uint16_t *frame_ant, ptrdiff_t w, int16_t *spatial, int16_t *temporal);
 } HQDN3DContext;
 
+void ff_hqdn3d_row_8_x86(uint8_t *src, uint8_t *dst, uint16_t *line_ant, uint16_t *frame_ant, ptrdiff_t w, int16_t *spatial, int16_t *temporal);
+void ff_hqdn3d_row_9_x86(uint8_t *src, uint8_t *dst, uint16_t *line_ant, uint16_t *frame_ant, ptrdiff_t w, int16_t *spatial, int16_t *temporal);
+void ff_hqdn3d_row_10_x86(uint8_t *src, uint8_t *dst, uint16_t *line_ant, uint16_t *frame_ant, ptrdiff_t w, int16_t *spatial, int16_t *temporal);
+void ff_hqdn3d_row_16_x86(uint8_t *src, uint8_t *dst, uint16_t *line_ant, uint16_t *frame_ant, ptrdiff_t w, int16_t *spatial, int16_t *temporal);
+
 #define LUT_BITS (depth==16 ? 8 : 4)
 #define RIGHTSHIFT(a,b) (((a)+(((1<<(b))-1)>>1))>>(b))
 #define LOAD(x) ((depth==8 ? src[x] : AV_RN16A(src+(x)*2)) << (16-depth))
@@ -79,7 +85,8 @@ static void denoise_temporal(uint8_t *src, uint8_t *dst,
 }
 
 av_always_inline
-static void denoise_spatial(uint8_t *src, uint8_t *dst,
+static void denoise_spatial(HQDN3DContext *hqdn3d,
+                            uint8_t *src, uint8_t *dst,
                             uint16_t *line_ant, uint16_t *frame_ant,
                             int w, int h, int sstride, int dstride,
                             int16_t *spatial, int16_t *temporal, int depth)
@@ -104,6 +111,10 @@ static void denoise_spatial(uint8_t *src, uint8_t *dst,
         src += sstride;
         dst += dstride;
         frame_ant += w;
+        if (hqdn3d->denoise_row[depth]) {
+            hqdn3d->denoise_row[depth](src, dst, line_ant, frame_ant, w, spatial, temporal);
+            continue;
+        }
         pixel_ant = LOAD(0);
         for (x = 0; x < w-1; x++) {
             line_ant[x] = tmp = lowpass(line_ant[x], pixel_ant, spatial, depth);
@@ -118,7 +129,8 @@ static void denoise_spatial(uint8_t *src, uint8_t *dst,
 }
 
 av_always_inline
-static void denoise_depth(uint8_t *src, uint8_t *dst,
+static void denoise_depth(HQDN3DContext *hqdn3d,
+                          uint8_t *src, uint8_t *dst,
                           uint16_t *line_ant, uint16_t **frame_ant_ptr,
                           int w, int h, int sstride, int dstride,
                           int16_t *spatial, int16_t *temporal, int depth)
@@ -138,7 +150,7 @@ static void denoise_depth(uint8_t *src, uint8_t *dst,
     }
 
     if (spatial[0])
-        denoise_spatial(src, dst, line_ant, frame_ant,
+        denoise_spatial(hqdn3d, src, dst, line_ant, frame_ant,
                         w, h, sstride, dstride, spatial, temporal, depth);
     else
         denoise_temporal(src, dst, frame_ant,
@@ -298,6 +310,13 @@ static int config_input(AVFilterLink *inlink)
             return AVERROR(ENOMEM);
     }
 
+#if HAVE_YASM
+    hqdn3d->denoise_row[ 8] = ff_hqdn3d_row_8_x86;
+    hqdn3d->denoise_row[ 9] = ff_hqdn3d_row_9_x86;
+    hqdn3d->denoise_row[10] = ff_hqdn3d_row_10_x86;
+    hqdn3d->denoise_row[16] = ff_hqdn3d_row_16_x86;
+#endif
+
     return 0;
 }
 
@@ -315,7 +334,7 @@ static int end_frame(AVFilterLink *inlink)
     int ret, c;
 
     for (c = 0; c < 3; c++) {
-        denoise(inpic->data[c], outpic->data[c],
+        denoise(hqdn3d, inpic->data[c], outpic->data[c],
                 hqdn3d->line, &hqdn3d->frame_prev[c],
                 inpic->video->w >> (!!c * hqdn3d->hsub),
                 inpic->video->h >> (!!c * hqdn3d->vsub),
index e98693d..46fc84f 100644 (file)
@@ -1,2 +1,3 @@
 MMX-OBJS-$(CONFIG_YADIF_FILTER)              += x86/yadif.o
 MMX-OBJS-$(CONFIG_GRADFUN_FILTER)            += x86/gradfun.o
+YASM-OBJS-$(CONFIG_HQDN3D_FILTER)            += x86/hqdn3d.o
diff --git a/libavfilter/x86/hqdn3d.asm b/libavfilter/x86/hqdn3d.asm
new file mode 100644 (file)
index 0000000..7254194
--- /dev/null
@@ -0,0 +1,106 @@
+;******************************************************************************
+;* Copyright (c) 2012 Loren Merritt
+;*
+;* This file is part of Libav.
+;*
+;* Libav 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.
+;*
+;* Libav 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 Libav; if not, write to the Free Software
+;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+;******************************************************************************
+
+%include "x86inc.asm"
+
+SECTION .text
+
+%macro LOWPASS 3 ; prevsample, cursample, lut
+    sub    %1q, %2q
+%if lut_bits != 8
+    sar    %1q, 8-lut_bits
+%endif
+    movsx  %1d, word [%3q+%1q*2]
+    add    %1d, %2d
+%endmacro
+
+%macro LOAD 3 ; dstreg, x, bitdepth
+%if %3 == 8
+    movzx  %1, byte [srcq+%2]
+%else
+    movzx  %1, word [srcq+(%2)*2]
+%endif
+%if %3 != 16
+    shl    %1, 16-%3
+%endif
+%endmacro
+
+%macro HQDN3D_ROW 1 ; bitdepth
+%if ARCH_X86_64
+cglobal hqdn3d_row_%1_x86, 7,10,0, src, dst, lineant, frameant, width, spatial, temporal, pixelant, t0, t1
+%else
+cglobal hqdn3d_row_%1_x86, 7,7,0, src, dst, lineant, frameant, width, spatial, temporal
+%endif
+    %assign bytedepth (%1+7)>>3
+    %assign lut_bits 4+4*(%1/16)
+    dec    widthq
+    lea    srcq, [srcq+widthq*bytedepth]
+    lea    dstq, [dstq+widthq*bytedepth]
+    lea    frameantq, [frameantq+widthq*2]
+    lea    lineantq,  [lineantq+widthq*2]
+    neg    widthq
+    %define xq widthq
+%if ARCH_X86_32
+    mov    dstmp, dstq
+    mov    srcmp, srcq
+    mov    frameantmp, frameantq
+    mov    lineantmp,  lineantq
+    %define dstq r0
+    %define frameantq r0
+    %define lineantq  r0
+    %define pixelantq r1
+    %define pixelantd r1d
+    DECLARE_REG_TMP 2,3
+%endif
+    LOAD   pixelantd, xq, %1
+ALIGN 16
+.loop:
+    movifnidn srcq, srcmp
+    LOAD      t0d, xq+1, %1 ; skip on the last iteration to avoid overread
+.loop2:
+    movifnidn lineantq, lineantmp
+    movzx     t1d, word [lineantq+xq*2]
+    LOWPASS   t1, pixelant, spatial
+    mov       [lineantq+xq*2], t1w
+    LOWPASS   pixelant, t0, spatial
+    movifnidn frameantq, frameantmp
+    movzx     t0d, word [frameantq+xq*2]
+    LOWPASS   t0, t1, temporal
+    mov       [frameantq+xq*2], t0w
+    movifnidn dstq, dstmp
+%if %1 != 16
+    add    t0d, (1<<(15-%1))-1
+    shr    t0d, 16-%1 ; could eliminate this by storing from t0h, but only with some contraints on register allocation
+%endif
+%if %1 == 8
+    mov    [dstq+xq], t0b
+%else
+    mov    [dstq+xq*2], t0w
+%endif
+    inc    xq
+    jl .loop
+    je .loop2
+    REP_RET
+%endmacro ; HQDN3D_ROW
+
+HQDN3D_ROW 8
+HQDN3D_ROW 9
+HQDN3D_ROW 10
+HQDN3D_ROW 16
index 5cb200f..d734c6e 100644 (file)
@@ -140,6 +140,7 @@ CPUNOP amdnop
     %define r%1w %2w
     %define r%1b %2b
     %define r%1h %2h
+    %define %2q %2
     %if %0 == 2
         %define r%1m  %2d
         %define r%1mp %2