lavc: Edge emulation with dst/src linesize
[ffmpeg.git] / 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 Libav.
6 ;*
7 ;* Libav 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 ;* Libav 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 Libav; 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, src, dst_stride, 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 r2mp
63     mov            srcq, r1mp
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     ; FIXME also write a ssse3 version using pshufb
101     movzx            wd, byte [dstq+start_xq]   ;   w = read(1)
102     imul             wd, 0x01010101             ;   w *= 0x01010101
103     movd             m0, wd
104     mov              wq, n_wordsq               ;   initialize w
105 %if cpuflag(sse)
106     shufps           m0, m0, q0000              ;   splat
107 %else ; mmx
108     punpckldq        m0, m0                     ;   splat
109 %endif ; mmx/sse
110 .x_loop:                                        ;   do {
111     movu    [dstq+wq*2], m0                     ;     write($reg, $mmsize)
112     add              wq, mmsize/2               ;     w -= $mmsize/2
113     cmp              wq, -mmsize/2              ;   } while (w > $mmsize/2)
114     jl .x_loop
115     movu  [dstq-mmsize], m0                     ;   write($reg, $mmsize)
116     add            dstq, dst_strideq            ;   dst += dst_stride
117     dec              hq                         ; } while (h--)
118     jnz .y_loop
119     RET
120 %endmacro
121
122 %if ARCH_X86_32
123 INIT_MMX mmx
124 hvar_fn
125 %endif
126
127 INIT_XMM sse
128 hvar_fn
129
130 ; macro to read/write a horizontal number of pixels (%2) to/from registers
131 ; on sse, - fills xmm0-15 for consecutive sets of 16 pixels
132 ;         - if (%2 & 8)  fills 8 bytes into xmm$next
133 ;         - if (%2 & 4)  fills 4 bytes into xmm$next
134 ;         - if (%2 & 3)  fills 1, 2 or 4 bytes in eax
135 ; on mmx, - fills mm0-7 for consecutive sets of 8 pixels
136 ;         - if (%2 & 4)  fills 4 bytes into mm$next
137 ;         - if (%2 & 3)  fills 1, 2 or 4 bytes in eax
138 ; writing data out is in the same way
139 %macro READ_NUM_BYTES 2
140 %assign %%off 0 ; offset in source buffer
141 %assign %%idx 0 ; mmx/xmm register index
142
143 %rep %2/mmsize
144     movu     m %+ %%idx, [srcq+%%off]
145 %assign %%off %%off+mmsize
146 %assign %%idx %%idx+1
147 %endrep ; %2/mmsize
148
149 %if mmsize == 16
150 %if (%2-%%off) >= 8
151 %if %2 > 16 && (%2-%%off) > 8
152     movu     m %+ %%idx, [srcq+%2-16]
153 %assign %%off %2
154 %else
155     movq     m %+ %%idx, [srcq+%%off]
156 %assign %%off %%off+8
157 %endif
158 %assign %%idx %%idx+1
159 %endif ; (%2-%%off) >= 8
160 %endif
161
162 %if (%2-%%off) >= 4
163 %if %2 > 8 && (%2-%%off) > 4
164     movq     m %+ %%idx, [srcq+%2-8]
165 %assign %%off %2
166 %else
167     movd     m %+ %%idx, [srcq+%%off]
168 %assign %%off %%off+4
169 %endif
170 %assign %%idx %%idx+1
171 %endif ; (%2-%%off) >= 4
172
173 %if (%2-%%off) >= 1
174 %if %2 >= 4
175     movd     m %+ %%idx, [srcq+%2-4]
176 %elif (%2-%%off) == 1
177     mov            valb, [srcq+%2-1]
178 %elif (%2-%%off) == 2
179     mov            valw, [srcq+%2-2]
180 %elifidn %1, body
181     mov            vald, [srcq+%2-3]
182 %else
183     movd     m %+ %%idx, [srcq+%2-3]
184 %endif
185 %endif ; (%2-%%off) >= 1
186 %endmacro ; READ_NUM_BYTES
187
188 %macro WRITE_NUM_BYTES 2
189 %assign %%off 0 ; offset in destination buffer
190 %assign %%idx 0 ; mmx/xmm register index
191
192 %rep %2/mmsize
193     movu   [dstq+%%off], m %+ %%idx
194 %assign %%off %%off+mmsize
195 %assign %%idx %%idx+1
196 %endrep ; %2/mmsize
197
198 %if mmsize == 16
199 %if (%2-%%off) >= 8
200 %if %2 > 16 && (%2-%%off) > 8
201     movu   [dstq+%2-16], m %+ %%idx
202 %assign %%off %2
203 %else
204     movq   [dstq+%%off], m %+ %%idx
205 %assign %%off %%off+8
206 %endif
207 %assign %%idx %%idx+1
208 %endif ; (%2-%%off) >= 8
209 %endif
210
211 %if (%2-%%off) >= 4
212 %if %2 > 8 && (%2-%%off) > 4
213     movq    [dstq+%2-8], m %+ %%idx
214 %assign %%off %2
215 %else
216     movd   [dstq+%%off], m %+ %%idx
217 %assign %%off %%off+4
218 %endif
219 %assign %%idx %%idx+1
220 %endif ; (%2-%%off) >= 4
221
222 %if (%2-%%off) >= 1
223 %if %2 >= 4
224     movd    [dstq+%2-4], m %+ %%idx
225 %elif (%2-%%off) == 1
226     mov     [dstq+%2-1], valb
227 %elif (%2-%%off) == 2
228     mov     [dstq+%2-2], valw
229 %elifidn %1, body
230     mov     [dstq+%2-3], valw
231     shr            vald, 16
232     mov     [dstq+%2-1], valb
233 %else
234     movd           vald, m %+ %%idx
235     mov     [dstq+%2-3], valw
236     shr            vald, 16
237     mov     [dstq+%2-1], valb
238 %endif
239 %endif ; (%2-%%off) >= 1
240 %endmacro ; WRITE_NUM_BYTES
241
242 ; vertical top/bottom extend and body copy fast loops
243 ; these are function pointers to set-width line copy functions, i.e.
244 ; they read a fixed number of pixels into set registers, and write
245 ; those out into the destination buffer
246 %macro VERTICAL_EXTEND 2
247 %assign %%n %1
248 %rep 1+%2-%1
249 %if %%n <= 3
250 %if ARCH_X86_64
251 cglobal emu_edge_vfix %+ %%n, 6, 8, 0, dst, src, dst_stride, src_stride, \
252                                        start_y, end_y, val, bh
253     mov             bhq, r6mp                   ; r6mp = bhmp
254 %else ; x86-32
255 cglobal emu_edge_vfix %+ %%n, 0, 6, 0, val, dst, src, start_y, end_y, bh
256     mov            dstq, r0mp
257     mov            srcq, r1mp
258     mov        start_yq, r4mp
259     mov          end_yq, r5mp
260     mov             bhq, r6mp
261 %define dst_strideq r2mp
262 %define src_strideq r3mp
263 %endif ; x86-64/32
264 %else
265 %if ARCH_X86_64
266 cglobal emu_edge_vfix %+ %%n, 7, 7, 1, dst, src, dst_stride, src_stride, \
267                                        start_y, end_y, bh
268 %else ; x86-32
269 cglobal emu_edge_vfix %+ %%n, 1, 5, 1, dst, src, start_y, end_y, bh
270     mov            srcq, r1mp
271     mov        start_yq, r4mp
272     mov          end_yq, r5mp
273     mov             bhq, r6mp
274 %define dst_strideq r2mp
275 %define src_strideq r3mp
276 %endif ; x86-64/32
277 %endif
278     ; FIXME move this to c wrapper?
279     sub             bhq, end_yq                 ; bh    -= end_y
280     sub          end_yq, start_yq               ; end_y -= start_y
281
282     ; extend pixels above body
283     test       start_yq, start_yq               ; if (start_y) {
284     jz .body_loop
285     READ_NUM_BYTES  top, %%n                    ;   $variable_regs = read($n)
286 .top_loop:                                      ;   do {
287     WRITE_NUM_BYTES top, %%n                    ;     write($variable_regs, $n)
288     add            dstq, dst_strideq            ;     dst += linesize
289     dec        start_yq                         ;   } while (--start_y)
290     jnz .top_loop                               ; }
291
292     ; copy body pixels
293 .body_loop:                                     ; do {
294     READ_NUM_BYTES  body, %%n                   ;   $variable_regs = read($n)
295     WRITE_NUM_BYTES body, %%n                   ;   write($variable_regs, $n)
296     add            dstq, dst_strideq            ;   dst += dst_stride
297     add            srcq, src_strideq            ;   src += src_stride
298     dec          end_yq                         ; } while (--end_y)
299     jnz .body_loop
300
301     ; copy bottom pixels
302     test            bhq, bhq                    ; if (block_h) {
303     jz .end
304     sub            srcq, src_strideq            ;   src -= linesize
305     READ_NUM_BYTES  bottom, %%n                 ;   $variable_regs = read($n)
306 .bottom_loop:                                   ;   do {
307     WRITE_NUM_BYTES bottom, %%n                 ;     write($variable_regs, $n)
308     add            dstq, dst_strideq            ;     dst += linesize
309     dec             bhq                         ;   } while (--bh)
310     jnz .bottom_loop                            ; }
311
312 .end:
313     RET
314 %assign %%n %%n+1
315 %endrep ; 1+%2-%1
316 %endmacro ; VERTICAL_EXTEND
317
318 INIT_MMX mmx
319 VERTICAL_EXTEND 1, 15
320 %if ARCH_X86_32
321 VERTICAL_EXTEND 16, 22
322 %endif
323
324 INIT_XMM sse
325 VERTICAL_EXTEND 16, 22
326
327 ; left/right (horizontal) fast extend functions
328 ; these are essentially identical to the vertical extend ones above,
329 ; just left/right separated because number of pixels to extend is
330 ; obviously not the same on both sides.
331
332 %macro READ_V_PIXEL 2
333 %if %1 == 2
334     movzx          valw, byte %2
335     imul           valw, 0x0101
336 %else
337     movzx          vald, byte %2
338     imul           vald, 0x01010101
339 %if %1 >= 8
340     movd             m0, vald
341 %if mmsize == 16
342     shufps           m0, m0, q0000
343 %else
344     punpckldq        m0, m0
345 %endif
346 %endif ; %1 >= 8
347 %endif
348 %endmacro ; READ_V_PIXEL
349
350 %macro WRITE_V_PIXEL 2
351 %assign %%off 0
352 %rep %1/mmsize
353     movu     [%2+%%off], m0
354 %assign %%off %%off+mmsize
355 %endrep ; %1/mmsize
356
357 %if mmsize == 16
358 %if %1-%%off >= 8
359 %if %1 > 16 && %1-%%off > 8
360     movu     [%2+%1-16], m0
361 %assign %%off %1
362 %else
363     movq     [%2+%%off], m0
364 %assign %%off %%off+8
365 %endif
366 %endif ; %1-%%off >= 8
367 %endif
368
369 %if %1-%%off >= 4
370 %if %1 > 8 %% %1-%%off > 4
371     movq      [%2+%1-8], m0
372 %assign %%off %1
373 %elif %1 >= 8 && %1-%%off >= 4
374     movd     [%2+%%off], m0
375 %assign %%off %%off+4
376 %else
377     mov      [%2+%%off], vald
378 %assign %%off %%off+4
379 %endif
380 %endif ; %1-%%off >= 4
381
382 %if %1-%%off >= 2
383 %if %1 >= 8
384     movd      [%2+%1-4], m0
385 %else
386     mov      [%2+%%off], valw
387 %endif
388 %endif ; (%1-%%off)/2
389 %endmacro ; WRITE_V_PIXEL
390
391 %macro H_EXTEND 2
392 %assign %%n %1
393 %rep 1+(%2-%1)/2
394 cglobal emu_edge_hfix %+ %%n, 4, 5, 1, dst, dst_stride, start_x, bh, val
395 .loop_y:                                        ; do {
396     READ_V_PIXEL    %%n, [dstq+start_xq]        ;   $variable_regs = read($n)
397     WRITE_V_PIXEL   %%n, dstq                   ;   write($variable_regs, $n)
398     add            dstq, dst_strideq            ;   dst += dst_stride
399     dec             bhq                         ; } while (--bh)
400     jnz .loop_y
401     RET
402 %assign %%n %%n+2
403 %endrep ; 1+(%2-%1)/2
404 %endmacro ; H_EXTEND
405
406 INIT_MMX mmx
407 H_EXTEND 2, 14
408 %if ARCH_X86_32
409 H_EXTEND 16, 22
410 %endif
411
412 INIT_XMM sse
413 H_EXTEND 16, 22
414
415 %macro PREFETCH_FN 1
416 cglobal prefetch, 3, 3, 0, buf, stride, h
417 .loop:
418     %1      [bufq]
419     add      bufq, strideq
420     dec        hd
421     jg .loop
422     REP_RET
423 %endmacro
424
425 INIT_MMX mmxext
426 PREFETCH_FN prefetcht0
427 %if ARCH_X86_32
428 INIT_MMX 3dnow
429 PREFETCH_FN prefetch
430 %endif