13% faster on penryn, 16% on sandybridge, 15% on bulldozer
Not simd; a compiler should have generated this, but gcc didn't.
... | ... |
@@ -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), |
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 |