Browse code

vf_hqdn3d: x86 asm

13% faster on penryn, 16% on sandybridge, 15% on bulldozer
Not simd; a compiler should have generated this, but gcc didn't.

Loren Merritt authored on 2012/08/26 19:26:42
Showing 4 changed files
... ...
@@ -41,8 +41,14 @@ typedef struct {
41 41
     double strength[4];
42 42
     int hsub, vsub;
43 43
     int depth;
44
+    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);
44 45
 } HQDN3DContext;
45 46
 
47
+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);
48
+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);
49
+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);
50
+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);
51
+
46 52
 #define LUT_BITS (depth==16 ? 8 : 4)
47 53
 #define RIGHTSHIFT(a,b) (((a)+(((1<<(b))-1)>>1))>>(b))
48 54
 #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,
79 79
 }
80 80
 
81 81
 av_always_inline
82
-static void denoise_spatial(uint8_t *src, uint8_t *dst,
82
+static void denoise_spatial(HQDN3DContext *hqdn3d,
83
+                            uint8_t *src, uint8_t *dst,
83 84
                             uint16_t *line_ant, uint16_t *frame_ant,
84 85
                             int w, int h, int sstride, int dstride,
85 86
                             int16_t *spatial, int16_t *temporal, int depth)
... ...
@@ -104,6 +111,10 @@ static void denoise_spatial(uint8_t *src, uint8_t *dst,
104 104
         src += sstride;
105 105
         dst += dstride;
106 106
         frame_ant += w;
107
+        if (hqdn3d->denoise_row[depth]) {
108
+            hqdn3d->denoise_row[depth](src, dst, line_ant, frame_ant, w, spatial, temporal);
109
+            continue;
110
+        }
107 111
         pixel_ant = LOAD(0);
108 112
         for (x = 0; x < w-1; x++) {
109 113
             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,
118 118
 }
119 119
 
120 120
 av_always_inline
121
-static void denoise_depth(uint8_t *src, uint8_t *dst,
121
+static void denoise_depth(HQDN3DContext *hqdn3d,
122
+                          uint8_t *src, uint8_t *dst,
122 123
                           uint16_t *line_ant, uint16_t **frame_ant_ptr,
123 124
                           int w, int h, int sstride, int dstride,
124 125
                           int16_t *spatial, int16_t *temporal, int depth)
... ...
@@ -138,7 +150,7 @@ static void denoise_depth(uint8_t *src, uint8_t *dst,
138 138
     }
139 139
 
140 140
     if (spatial[0])
141
-        denoise_spatial(src, dst, line_ant, frame_ant,
141
+        denoise_spatial(hqdn3d, src, dst, line_ant, frame_ant,
142 142
                         w, h, sstride, dstride, spatial, temporal, depth);
143 143
     else
144 144
         denoise_temporal(src, dst, frame_ant,
... ...
@@ -298,6 +310,13 @@ static int config_input(AVFilterLink *inlink)
298 298
             return AVERROR(ENOMEM);
299 299
     }
300 300
 
301
+#if HAVE_YASM
302
+    hqdn3d->denoise_row[ 8] = ff_hqdn3d_row_8_x86;
303
+    hqdn3d->denoise_row[ 9] = ff_hqdn3d_row_9_x86;
304
+    hqdn3d->denoise_row[10] = ff_hqdn3d_row_10_x86;
305
+    hqdn3d->denoise_row[16] = ff_hqdn3d_row_16_x86;
306
+#endif
307
+
301 308
     return 0;
302 309
 }
303 310
 
... ...
@@ -315,7 +334,7 @@ static int end_frame(AVFilterLink *inlink)
315 315
     int ret, c;
316 316
 
317 317
     for (c = 0; c < 3; c++) {
318
-        denoise(inpic->data[c], outpic->data[c],
318
+        denoise(hqdn3d, inpic->data[c], outpic->data[c],
319 319
                 hqdn3d->line, &hqdn3d->frame_prev[c],
320 320
                 inpic->video->w >> (!!c * hqdn3d->hsub),
321 321
                 inpic->video->h >> (!!c * hqdn3d->vsub),
... ...
@@ -1,2 +1,3 @@
1 1
 MMX-OBJS-$(CONFIG_YADIF_FILTER)              += x86/yadif.o
2 2
 MMX-OBJS-$(CONFIG_GRADFUN_FILTER)            += x86/gradfun.o
3
+YASM-OBJS-$(CONFIG_HQDN3D_FILTER)            += x86/hqdn3d.o
3 4
new file mode 100644
... ...
@@ -0,0 +1,106 @@
0
+;******************************************************************************
1
+;* Copyright (c) 2012 Loren Merritt
2
+;*
3
+;* This file is part of Libav.
4
+;*
5
+;* Libav is free software; you can redistribute it and/or
6
+;* modify it under the terms of the GNU Lesser General Public
7
+;* License as published by the Free Software Foundation; either
8
+;* version 2.1 of the License, or (at your option) any later version.
9
+;*
10
+;* Libav is distributed in the hope that it will be useful,
11
+;* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
+;* Lesser General Public License for more details.
14
+;*
15
+;* You should have received a copy of the GNU Lesser General Public
16
+;* License along with Libav; if not, write to the Free Software
17
+;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+;******************************************************************************
19
+
20
+%include "x86inc.asm"
21
+
22
+SECTION .text
23
+
24
+%macro LOWPASS 3 ; prevsample, cursample, lut
25
+    sub    %1q, %2q
26
+%if lut_bits != 8
27
+    sar    %1q, 8-lut_bits
28
+%endif
29
+    movsx  %1d, word [%3q+%1q*2]
30
+    add    %1d, %2d
31
+%endmacro
32
+
33
+%macro LOAD 3 ; dstreg, x, bitdepth
34
+%if %3 == 8
35
+    movzx  %1, byte [srcq+%2]
36
+%else
37
+    movzx  %1, word [srcq+(%2)*2]
38
+%endif
39
+%if %3 != 16
40
+    shl    %1, 16-%3
41
+%endif
42
+%endmacro
43
+
44
+%macro HQDN3D_ROW 1 ; bitdepth
45
+%if ARCH_X86_64
46
+cglobal hqdn3d_row_%1_x86, 7,10,0, src, dst, lineant, frameant, width, spatial, temporal, pixelant, t0, t1
47
+%else
48
+cglobal hqdn3d_row_%1_x86, 7,7,0, src, dst, lineant, frameant, width, spatial, temporal
49
+%endif
50
+    %assign bytedepth (%1+7)>>3
51
+    %assign lut_bits 4+4*(%1/16)
52
+    dec    widthq
53
+    lea    srcq, [srcq+widthq*bytedepth]
54
+    lea    dstq, [dstq+widthq*bytedepth]
55
+    lea    frameantq, [frameantq+widthq*2]
56
+    lea    lineantq,  [lineantq+widthq*2]
57
+    neg    widthq
58
+    %define xq widthq
59
+%if ARCH_X86_32
60
+    mov    dstmp, dstq
61
+    mov    srcmp, srcq
62
+    mov    frameantmp, frameantq
63
+    mov    lineantmp,  lineantq
64
+    %define dstq r0
65
+    %define frameantq r0
66
+    %define lineantq  r0
67
+    %define pixelantq r1
68
+    %define pixelantd r1d
69
+    DECLARE_REG_TMP 2,3
70
+%endif
71
+    LOAD   pixelantd, xq, %1
72
+ALIGN 16
73
+.loop:
74
+    movifnidn srcq, srcmp
75
+    LOAD      t0d, xq+1, %1 ; skip on the last iteration to avoid overread
76
+.loop2:
77
+    movifnidn lineantq, lineantmp
78
+    movzx     t1d, word [lineantq+xq*2]
79
+    LOWPASS   t1, pixelant, spatial
80
+    mov       [lineantq+xq*2], t1w
81
+    LOWPASS   pixelant, t0, spatial
82
+    movifnidn frameantq, frameantmp
83
+    movzx     t0d, word [frameantq+xq*2]
84
+    LOWPASS   t0, t1, temporal
85
+    mov       [frameantq+xq*2], t0w
86
+    movifnidn dstq, dstmp
87
+%if %1 != 16
88
+    add    t0d, (1<<(15-%1))-1
89
+    shr    t0d, 16-%1 ; could eliminate this by storing from t0h, but only with some contraints on register allocation
90
+%endif
91
+%if %1 == 8
92
+    mov    [dstq+xq], t0b
93
+%else
94
+    mov    [dstq+xq*2], t0w
95
+%endif
96
+    inc    xq
97
+    jl .loop
98
+    je .loop2
99
+    REP_RET
100
+%endmacro ; HQDN3D_ROW
101
+
102
+HQDN3D_ROW 8
103
+HQDN3D_ROW 9
104
+HQDN3D_ROW 10
105
+HQDN3D_ROW 16
... ...
@@ -140,6 +140,7 @@ CPUNOP amdnop
140 140
     %define r%1w %2w
141 141
     %define r%1b %2b
142 142
     %define r%1h %2h
143
+    %define %2q %2
143 144
     %if %0 == 2
144 145
         %define r%1m  %2d
145 146
         %define r%1mp %2