]> git.sesse.net Git - ffmpeg/blob - libavcodec/x86/videodsp.asm
Merge commit 'be00ec832c519427cd92218abac77dafdc1d5487'
[ffmpeg] / libavcodec / x86 / videodsp.asm
1 ;******************************************************************************
2 ;* Core video DSP functions
3 ;* Copyright (c) 2012 Ronald S. Bultje <rsbultje@gmail.com>
4 ;*
5 ;* This file is part of FFmpeg.
6 ;*
7 ;* FFmpeg is free software; you can redistribute it and/or
8 ;* modify it under the terms of the GNU Lesser General Public
9 ;* License as published by the Free Software Foundation; either
10 ;* version 2.1 of the License, or (at your option) any later version.
11 ;*
12 ;* FFmpeg is distributed in the hope that it will be useful,
13 ;* but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 ;* Lesser General Public License for more details.
16 ;*
17 ;* You should have received a copy of the GNU Lesser General Public
18 ;* License along with FFmpeg; if not, write to the Free Software
19 ;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 ;******************************************************************************
21
22 %include "libavutil/x86/x86util.asm"
23
24 SECTION .text
25
26 ; slow vertical extension loop function. Works with variable-width, and
27 ; does per-line reading/writing of source data
28
29 %macro V_COPY_ROW 2 ; type (top/body/bottom), h
30 .%1_y_loop:                                     ; do {
31     mov              wq, r7mp                   ;   initialize w (r7mp = wmp)
32 .%1_x_loop:                                     ;   do {
33     movu             m0, [srcq+wq]              ;     m0 = read($mmsize)
34     movu      [dstq+wq], m0                     ;     write(m0, $mmsize)
35     add              wq, mmsize                 ;     w -= $mmsize
36     cmp              wq, -mmsize                ;   } while (w > $mmsize);
37     jl .%1_x_loop
38     movu             m0, [srcq-mmsize]          ;     m0 = read($mmsize)
39     movu  [dstq-mmsize], m0                     ;     write(m0, $mmsize)
40 %ifidn %1, body                                 ;   if ($type == body) {
41     add            srcq, src_strideq            ;     src += src_stride
42 %endif                                          ;   }
43     add            dstq, dst_strideq            ;   dst += dst_stride
44     dec              %2                         ; } while (--$h);
45     jnz .%1_y_loop
46 %endmacro
47
48 %macro vvar_fn 0
49 ; .----. <- zero
50 ; |    |    <- top is copied from first line in body of source
51 ; |----| <- start_y
52 ; |    |    <- body is copied verbatim (line-by-line) from source
53 ; |----| <- end_y
54 ; |    |    <- bottom is copied from last line in body of source
55 ; '----' <- bh
56 %if ARCH_X86_64
57 cglobal emu_edge_vvar, 7, 8, 1, dst, dst_stride, src, src_stride, \
58                                 start_y, end_y, bh, w
59 %else ; x86-32
60 cglobal emu_edge_vvar, 1, 6, 1, dst, src, start_y, end_y, bh, w
61 %define src_strideq r3mp
62 %define dst_strideq r1mp
63     mov            srcq, r2mp
64     mov        start_yq, r4mp
65     mov          end_yq, r5mp
66     mov             bhq, r6mp
67 %endif
68     sub             bhq, end_yq                 ; bh    -= end_q
69     sub          end_yq, start_yq               ; end_q -= start_q
70     add            srcq, r7mp                   ; (r7mp = wmp)
71     add            dstq, r7mp                   ; (r7mp = wmp)
72     neg            r7mp                         ; (r7mp = wmp)
73     test       start_yq, start_yq               ; if (start_q) {
74     jz .body
75     V_COPY_ROW      top, start_yq               ;   v_copy_row(top, start_yq)
76 .body:                                          ; }
77     V_COPY_ROW     body, end_yq                 ; v_copy_row(body, end_yq)
78     test            bhq, bhq                    ; if (bh) {
79     jz .end
80     sub            srcq, src_strideq            ;   src -= src_stride
81     V_COPY_ROW   bottom, bhq                    ;   v_copy_row(bottom, bh)
82 .end:                                           ; }
83     RET
84 %endmacro
85
86 %if ARCH_X86_32
87 INIT_MMX mmx
88 vvar_fn
89 %endif
90
91 INIT_XMM sse
92 vvar_fn
93
94 %macro hvar_fn 0
95 cglobal emu_edge_hvar, 5, 6, 1, dst, dst_stride, start_x, n_words, h, w
96     lea            dstq, [dstq+n_wordsq*2]
97     neg        n_wordsq
98     lea        start_xq, [start_xq+n_wordsq*2]
99 .y_loop:                                        ; do {
100 %if cpuflag(avx2)
101     vpbroadcastb     m0, [dstq+start_xq]
102     mov              wq, n_wordsq               ;   initialize w
103 %else
104     movzx            wd, byte [dstq+start_xq]   ;   w = read(1)
105     imul             wd, 0x01010101             ;   w *= 0x01010101
106     movd             m0, wd
107     mov              wq, n_wordsq               ;   initialize w
108 %if cpuflag(sse2)
109     pshufd           m0, m0, q0000              ;   splat
110 %else ; mmx
111     punpckldq        m0, m0                     ;   splat
112 %endif ; mmx/sse
113 %endif ; avx2
114 .x_loop:                                        ;   do {
115     movu    [dstq+wq*2], m0                     ;     write($reg, $mmsize)
116     add              wq, mmsize/2               ;     w -= $mmsize/2
117     cmp              wq, -mmsize/2              ;   } while (w > $mmsize/2)
118     jl .x_loop
119     movu  [dstq-mmsize], m0                     ;   write($reg, $mmsize)
120     add            dstq, dst_strideq            ;   dst += dst_stride
121     dec              hq                         ; } while (h--)
122     jnz .y_loop
123     RET
124 %endmacro
125
126 %if ARCH_X86_32
127 INIT_MMX mmx
128 hvar_fn
129 %endif
130
131 INIT_XMM sse2
132 hvar_fn
133
134 %if HAVE_AVX2_EXTERNAL
135 INIT_XMM avx2
136 hvar_fn
137 %endif
138
139 ; macro to read/write a horizontal number of pixels (%2) to/from registers
140 ; on sse, - fills xmm0-15 for consecutive sets of 16 pixels
141 ;         - if (%2 & 8)  fills 8 bytes into xmm$next
142 ;         - if (%2 & 4)  fills 4 bytes into xmm$next
143 ;         - if (%2 & 3)  fills 1, 2 or 4 bytes in eax
144 ; on mmx, - fills mm0-7 for consecutive sets of 8 pixels
145 ;         - if (%2 & 4)  fills 4 bytes into mm$next
146 ;         - if (%2 & 3)  fills 1, 2 or 4 bytes in eax
147 ; writing data out is in the same way
148 %macro READ_NUM_BYTES 2
149 %assign %%off 0     ; offset in source buffer
150 %assign %%mmx_idx 0 ; mmx register index
151 %assign %%xmm_idx 0 ; xmm register index
152
153 %rep %2/mmsize
154 %if mmsize == 16
155     movu   xmm %+ %%xmm_idx, [srcq+%%off]
156 %assign %%xmm_idx %%xmm_idx+1
157 %else ; mmx
158     movu    mm %+ %%mmx_idx, [srcq+%%off]
159 %assign %%mmx_idx %%mmx_idx+1
160 %endif
161 %assign %%off %%off+mmsize
162 %endrep ; %2/mmsize
163
164 %if mmsize == 16
165 %if (%2-%%off) >= 8
166 %if %2 > 16 && (%2-%%off) > 8
167     movu   xmm %+ %%xmm_idx, [srcq+%2-16]
168 %assign %%xmm_idx %%xmm_idx+1
169 %assign %%off %2
170 %else
171     movq    mm %+ %%mmx_idx, [srcq+%%off]
172 %assign %%mmx_idx %%mmx_idx+1
173 %assign %%off %%off+8
174 %endif
175 %endif ; (%2-%%off) >= 8
176 %endif
177
178 %if (%2-%%off) >= 4
179 %if %2 > 8 && (%2-%%off) > 4
180     movq    mm %+ %%mmx_idx, [srcq+%2-8]
181 %assign %%off %2
182 %else
183     movd    mm %+ %%mmx_idx, [srcq+%%off]
184 %assign %%off %%off+4
185 %endif
186 %assign %%mmx_idx %%mmx_idx+1
187 %endif ; (%2-%%off) >= 4
188
189 %if (%2-%%off) >= 1
190 %if %2 >= 4
191     movd mm %+ %%mmx_idx, [srcq+%2-4]
192 %elif (%2-%%off) == 1
193     mov            valb, [srcq+%2-1]
194 %elif (%2-%%off) == 2
195     mov            valw, [srcq+%2-2]
196 %elifidn %1, body
197     mov            valb, [srcq+%2-1]
198     sal            vald, 16
199     mov            valw, [srcq+%2-3]
200 %elifidn %1, bottom
201     movd mm %+ %%mmx_idx, [srcq+%2-4]
202 %else ; top
203     movd mm %+ %%mmx_idx, [srcq+%2-3]
204 %endif
205 %endif ; (%2-%%off) >= 1
206 %endmacro ; READ_NUM_BYTES
207
208 %macro WRITE_NUM_BYTES 2
209 %assign %%off 0     ; offset in destination buffer
210 %assign %%mmx_idx 0 ; mmx register index
211 %assign %%xmm_idx 0 ; xmm register index
212
213 %rep %2/mmsize
214 %if mmsize == 16
215     movu   [dstq+%%off], xmm %+ %%xmm_idx
216 %assign %%xmm_idx %%xmm_idx+1
217 %else ; mmx
218     movu   [dstq+%%off], mm %+ %%mmx_idx
219 %assign %%mmx_idx %%mmx_idx+1
220 %endif
221 %assign %%off %%off+mmsize
222 %endrep ; %2/mmsize
223
224 %if mmsize == 16
225 %if (%2-%%off) >= 8
226 %if %2 > 16 && (%2-%%off) > 8
227     movu   [dstq+%2-16], xmm %+ %%xmm_idx
228 %assign %%xmm_idx %%xmm_idx+1
229 %assign %%off %2
230 %else
231     movq   [dstq+%%off], mm %+ %%mmx_idx
232 %assign %%mmx_idx %%mmx_idx+1
233 %assign %%off %%off+8
234 %endif
235 %endif ; (%2-%%off) >= 8
236 %endif
237
238 %if (%2-%%off) >= 4
239 %if %2 > 8 && (%2-%%off) > 4
240     movq    [dstq+%2-8], mm %+ %%mmx_idx
241 %assign %%off %2
242 %else
243     movd   [dstq+%%off], mm %+ %%mmx_idx
244 %assign %%off %%off+4
245 %endif
246 %assign %%mmx_idx %%mmx_idx+1
247 %endif ; (%2-%%off) >= 4
248
249 %if (%2-%%off) >= 1
250 %if %2 >= 4
251     movd    [dstq+%2-4], mm %+ %%mmx_idx
252 %elif (%2-%%off) == 1
253     mov     [dstq+%2-1], valb
254 %elif (%2-%%off) == 2
255     mov     [dstq+%2-2], valw
256 %elifidn %1, body
257     mov     [dstq+%2-3], valw
258     sar            vald, 16
259     mov     [dstq+%2-1], valb
260 %else
261     movd           vald, mm %+ %%mmx_idx
262 %ifidn %1, bottom
263     sar            vald, 8
264 %endif
265     mov     [dstq+%2-3], valw
266     sar            vald, 16
267     mov     [dstq+%2-1], valb
268 %endif
269 %endif ; (%2-%%off) >= 1
270 %endmacro ; WRITE_NUM_BYTES
271
272 ; vertical top/bottom extend and body copy fast loops
273 ; these are function pointers to set-width line copy functions, i.e.
274 ; they read a fixed number of pixels into set registers, and write
275 ; those out into the destination buffer
276 %macro VERTICAL_EXTEND 2
277 %assign %%n %1
278 %rep 1+%2-%1
279 %if %%n <= 3
280 %if ARCH_X86_64
281 cglobal emu_edge_vfix %+ %%n, 6, 8, 0, dst, dst_stride, src, src_stride, \
282                                        start_y, end_y, val, bh
283     mov             bhq, r6mp                   ; r6mp = bhmp
284 %else ; x86-32
285 cglobal emu_edge_vfix %+ %%n, 0, 6, 0, val, dst, src, start_y, end_y, bh
286     mov            dstq, r0mp
287     mov            srcq, r2mp
288     mov        start_yq, r4mp
289     mov          end_yq, r5mp
290     mov             bhq, r6mp
291 %define dst_strideq r1mp
292 %define src_strideq r3mp
293 %endif ; x86-64/32
294 %else
295 %if ARCH_X86_64
296 cglobal emu_edge_vfix %+ %%n, 7, 7, 1, dst, dst_stride, src, src_stride, \
297                                        start_y, end_y, bh
298 %else ; x86-32
299 cglobal emu_edge_vfix %+ %%n, 1, 5, 1, dst, src, start_y, end_y, bh
300     mov            srcq, r2mp
301     mov        start_yq, r4mp
302     mov          end_yq, r5mp
303     mov             bhq, r6mp
304 %define dst_strideq r1mp
305 %define src_strideq r3mp
306 %endif ; x86-64/32
307 %endif
308     ; FIXME move this to c wrapper?
309     sub             bhq, end_yq                 ; bh    -= end_y
310     sub          end_yq, start_yq               ; end_y -= start_y
311
312     ; extend pixels above body
313     test       start_yq, start_yq               ; if (start_y) {
314     jz .body_loop
315     READ_NUM_BYTES  top, %%n                    ;   $variable_regs = read($n)
316 .top_loop:                                      ;   do {
317     WRITE_NUM_BYTES top, %%n                    ;     write($variable_regs, $n)
318     add            dstq, dst_strideq            ;     dst += linesize
319     dec        start_yq                         ;   } while (--start_y)
320     jnz .top_loop                               ; }
321
322     ; copy body pixels
323 .body_loop:                                     ; do {
324     READ_NUM_BYTES  body, %%n                   ;   $variable_regs = read($n)
325     WRITE_NUM_BYTES body, %%n                   ;   write($variable_regs, $n)
326     add            dstq, dst_strideq            ;   dst += dst_stride
327     add            srcq, src_strideq            ;   src += src_stride
328     dec          end_yq                         ; } while (--end_y)
329     jnz .body_loop
330
331     ; copy bottom pixels
332     test            bhq, bhq                    ; if (block_h) {
333     jz .end
334     sub            srcq, src_strideq            ;   src -= linesize
335     READ_NUM_BYTES  bottom, %%n                 ;   $variable_regs = read($n)
336 .bottom_loop:                                   ;   do {
337     WRITE_NUM_BYTES bottom, %%n                 ;     write($variable_regs, $n)
338     add            dstq, dst_strideq            ;     dst += linesize
339     dec             bhq                         ;   } while (--bh)
340     jnz .bottom_loop                            ; }
341
342 .end:
343     RET
344 %assign %%n %%n+1
345 %endrep ; 1+%2-%1
346 %endmacro ; VERTICAL_EXTEND
347
348 INIT_MMX mmx
349 VERTICAL_EXTEND 1, 15
350 %if ARCH_X86_32
351 VERTICAL_EXTEND 16, 22
352 %endif
353
354 INIT_XMM sse
355 VERTICAL_EXTEND 16, 22
356
357 ; left/right (horizontal) fast extend functions
358 ; these are essentially identical to the vertical extend ones above,
359 ; just left/right separated because number of pixels to extend is
360 ; obviously not the same on both sides.
361
362 %macro READ_V_PIXEL 2
363 %if cpuflag(avx2)
364     vpbroadcastb     m0, %2
365 %else
366     movzx          vald, byte %2
367     imul           vald, 0x01010101
368 %if %1 >= 8
369     movd             m0, vald
370 %if mmsize == 16
371     pshufd           m0, m0, q0000
372 %else
373     punpckldq        m0, m0
374 %endif ; mmsize == 16
375 %endif ; %1 > 16
376 %endif ; avx2
377 %endmacro ; READ_V_PIXEL
378
379 %macro WRITE_V_PIXEL 2
380 %assign %%off 0
381
382 %if %1 >= 8
383
384 %rep %1/mmsize
385     movu     [%2+%%off], m0
386 %assign %%off %%off+mmsize
387 %endrep ; %1/mmsize
388
389 %if mmsize == 16
390 %if %1-%%off >= 8
391 %if %1 > 16 && %1-%%off > 8
392     movu     [%2+%1-16], m0
393 %assign %%off %1
394 %else
395     movq     [%2+%%off], m0
396 %assign %%off %%off+8
397 %endif
398 %endif ; %1-%%off >= 8
399 %endif ; mmsize == 16
400
401 %if %1-%%off >= 4
402 %if %1 > 8 && %1-%%off > 4
403     movq      [%2+%1-8], m0
404 %assign %%off %1
405 %else
406     movd     [%2+%%off], m0
407 %assign %%off %%off+4
408 %endif
409 %endif ; %1-%%off >= 4
410
411 %else ; %1 < 8
412
413 %rep %1/4
414     mov      [%2+%%off], vald
415 %assign %%off %%off+4
416 %endrep ; %1/4
417
418 %endif ; %1 >=/< 8
419
420 %if %1-%%off == 2
421 %if cpuflag(avx2)
422     movd     [%2+%%off-2], m0
423 %else
424     mov      [%2+%%off], valw
425 %endif ; avx2
426 %endif ; (%1-%%off)/2
427 %endmacro ; WRITE_V_PIXEL
428
429 %macro H_EXTEND 2
430 %assign %%n %1
431 %rep 1+(%2-%1)/2
432 %if cpuflag(avx2)
433 cglobal emu_edge_hfix %+ %%n, 4, 4, 1, dst, dst_stride, start_x, bh
434 %else
435 cglobal emu_edge_hfix %+ %%n, 4, 5, 1, dst, dst_stride, start_x, bh, val
436 %endif
437 .loop_y:                                        ; do {
438     READ_V_PIXEL    %%n, [dstq+start_xq]        ;   $variable_regs = read($n)
439     WRITE_V_PIXEL   %%n, dstq                   ;   write($variable_regs, $n)
440     add            dstq, dst_strideq            ;   dst += dst_stride
441     dec             bhq                         ; } while (--bh)
442     jnz .loop_y
443     RET
444 %assign %%n %%n+2
445 %endrep ; 1+(%2-%1)/2
446 %endmacro ; H_EXTEND
447
448 INIT_MMX mmx
449 H_EXTEND 2, 14
450 %if ARCH_X86_32
451 H_EXTEND 16, 22
452 %endif
453
454 INIT_XMM sse2
455 H_EXTEND 16, 22
456
457 %if HAVE_AVX2_EXTERNAL
458 INIT_XMM avx2
459 H_EXTEND 8, 22
460 %endif
461
462 %macro PREFETCH_FN 1
463 cglobal prefetch, 3, 3, 0, buf, stride, h
464 .loop:
465     %1      [bufq]
466     add      bufq, strideq
467     dec        hd
468     jg .loop
469     REP_RET
470 %endmacro
471
472 INIT_MMX mmxext
473 PREFETCH_FN prefetcht0
474 %if ARCH_X86_32
475 INIT_MMX 3dnow
476 PREFETCH_FN prefetch
477 %endif