c6f33dcc262319ecc2b07193e1e36f96ca0c481a
[ffmpeg.git] / libavcodec / x86 / dsputilenc.asm
1 ;*****************************************************************************
2 ;* MMX optimized DSP utils
3 ;*****************************************************************************
4 ;* Copyright (c) 2000, 2001 Fabrice Bellard
5 ;* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
6 ;*
7 ;* This file is part of FFmpeg.
8 ;*
9 ;* FFmpeg is free software; you can redistribute it and/or
10 ;* modify it under the terms of the GNU Lesser General Public
11 ;* License as published by the Free Software Foundation; either
12 ;* version 2.1 of the License, or (at your option) any later version.
13 ;*
14 ;* FFmpeg is distributed in the hope that it will be useful,
15 ;* but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 ;* Lesser General Public License for more details.
18 ;*
19 ;* You should have received a copy of the GNU Lesser General Public
20 ;* License along with FFmpeg; if not, write to the Free Software
21 ;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 ;*****************************************************************************
23
24 %include "libavutil/x86/x86util.asm"
25
26 SECTION .text
27
28 %macro DIFF_PIXELS_1 4
29     movh            %1, %3
30     movh            %2, %4
31     punpcklbw       %2, %1
32     punpcklbw       %1, %1
33     psubw           %1, %2
34 %endmacro
35
36 ; %1=uint8_t *pix1, %2=uint8_t *pix2, %3=static offset, %4=stride, %5=stride*3
37 ; %6=temporary storage location
38 ; this macro requires $mmsize stack space (aligned) on %6 (except on SSE+x86-64)
39 %macro DIFF_PIXELS_8 6
40     DIFF_PIXELS_1   m0, m7, [%1     +%3], [%2     +%3]
41     DIFF_PIXELS_1   m1, m7, [%1+%4  +%3], [%2+%4  +%3]
42     DIFF_PIXELS_1   m2, m7, [%1+%4*2+%3], [%2+%4*2+%3]
43     add             %1, %5
44     add             %2, %5
45     DIFF_PIXELS_1   m3, m7, [%1     +%3], [%2     +%3]
46     DIFF_PIXELS_1   m4, m7, [%1+%4  +%3], [%2+%4  +%3]
47     DIFF_PIXELS_1   m5, m7, [%1+%4*2+%3], [%2+%4*2+%3]
48     DIFF_PIXELS_1   m6, m7, [%1+%5  +%3], [%2+%5  +%3]
49 %ifdef m8
50     DIFF_PIXELS_1   m7, m8, [%1+%4*4+%3], [%2+%4*4+%3]
51 %else
52     mova          [%6], m0
53     DIFF_PIXELS_1   m7, m0, [%1+%4*4+%3], [%2+%4*4+%3]
54     mova            m0, [%6]
55 %endif
56     sub             %1, %5
57     sub             %2, %5
58 %endmacro
59
60 %macro HADAMARD8 0
61     SUMSUB_BADC       w, 0, 1, 2, 3
62     SUMSUB_BADC       w, 4, 5, 6, 7
63     SUMSUB_BADC       w, 0, 2, 1, 3
64     SUMSUB_BADC       w, 4, 6, 5, 7
65     SUMSUB_BADC       w, 0, 4, 1, 5
66     SUMSUB_BADC       w, 2, 6, 3, 7
67 %endmacro
68
69 %macro ABS1_SUM 3
70     ABS1            %1, %2
71     paddusw         %3, %1
72 %endmacro
73
74 %macro ABS2_SUM 6
75     ABS2            %1, %2, %3, %4
76     paddusw         %5, %1
77     paddusw         %6, %2
78 %endmacro
79
80 %macro ABS_SUM_8x8_64 1
81     ABS2            m0, m1, m8, m9
82     ABS2_SUM        m2, m3, m8, m9, m0, m1
83     ABS2_SUM        m4, m5, m8, m9, m0, m1
84     ABS2_SUM        m6, m7, m8, m9, m0, m1
85     paddusw         m0, m1
86 %endmacro
87
88 %macro ABS_SUM_8x8_32 1
89     mova          [%1], m7
90     ABS1            m0, m7
91     ABS1            m1, m7
92     ABS1_SUM        m2, m7, m0
93     ABS1_SUM        m3, m7, m1
94     ABS1_SUM        m4, m7, m0
95     ABS1_SUM        m5, m7, m1
96     ABS1_SUM        m6, m7, m0
97     mova            m2, [%1]
98     ABS1_SUM        m2, m7, m1
99     paddusw         m0, m1
100 %endmacro
101
102 ; FIXME: HSUM saturates at 64k, while an 8x8 hadamard or dct block can get up to
103 ; about 100k on extreme inputs. But that's very unlikely to occur in natural video,
104 ; and it's even more unlikely to not have any alternative mvs/modes with lower cost.
105 %macro HSUM 3
106 %if cpuflag(sse2)
107     movhlps         %2, %1
108     paddusw         %1, %2
109     pshuflw         %2, %1, 0xE
110     paddusw         %1, %2
111     pshuflw         %2, %1, 0x1
112     paddusw         %1, %2
113     movd            %3, %1
114 %elif cpuflag(mmxext)
115     pshufw          %2, %1, 0xE
116     paddusw         %1, %2
117     pshufw          %2, %1, 0x1
118     paddusw         %1, %2
119     movd            %3, %1
120 %elif cpuflag(mmx)
121     mova            %2, %1
122     psrlq           %1, 32
123     paddusw         %1, %2
124     mova            %2, %1
125     psrlq           %1, 16
126     paddusw         %1, %2
127     movd            %3, %1
128 %endif
129 %endmacro
130
131 %macro STORE4 5
132     mova [%1+mmsize*0], %2
133     mova [%1+mmsize*1], %3
134     mova [%1+mmsize*2], %4
135     mova [%1+mmsize*3], %5
136 %endmacro
137
138 %macro LOAD4 5
139     mova            %2, [%1+mmsize*0]
140     mova            %3, [%1+mmsize*1]
141     mova            %4, [%1+mmsize*2]
142     mova            %5, [%1+mmsize*3]
143 %endmacro
144
145 %macro hadamard8_16_wrapper 2
146 cglobal hadamard8_diff, 4, 4, %1
147 %ifndef m8
148     %assign pad %2*mmsize-(4+stack_offset&(mmsize-1))
149     SUB            rsp, pad
150 %endif
151     call hadamard8x8_diff %+ SUFFIX
152 %ifndef m8
153     ADD            rsp, pad
154 %endif
155     RET
156
157 cglobal hadamard8_diff16, 5, 6, %1
158 %ifndef m8
159     %assign pad %2*mmsize-(4+stack_offset&(mmsize-1))
160     SUB            rsp, pad
161 %endif
162
163     call hadamard8x8_diff %+ SUFFIX
164     mov            r5d, eax
165
166     add             r1, 8
167     add             r2, 8
168     call hadamard8x8_diff %+ SUFFIX
169     add            r5d, eax
170
171     cmp            r4d, 16
172     jne .done
173
174     lea             r1, [r1+r3*8-8]
175     lea             r2, [r2+r3*8-8]
176     call hadamard8x8_diff %+ SUFFIX
177     add            r5d, eax
178
179     add             r1, 8
180     add             r2, 8
181     call hadamard8x8_diff %+ SUFFIX
182     add            r5d, eax
183
184 .done:
185     mov            eax, r5d
186 %ifndef m8
187     ADD            rsp, pad
188 %endif
189     RET
190 %endmacro
191
192 %macro HADAMARD8_DIFF 0-1
193 %if cpuflag(sse2)
194 hadamard8x8_diff %+ SUFFIX:
195     lea                          r0, [r3*3]
196     DIFF_PIXELS_8                r1, r2,  0, r3, r0, rsp+gprsize
197     HADAMARD8
198 %if ARCH_X86_64
199     TRANSPOSE8x8W                 0,  1,  2,  3,  4,  5,  6,  7,  8
200 %else
201     TRANSPOSE8x8W                 0,  1,  2,  3,  4,  5,  6,  7, [rsp+gprsize], [rsp+mmsize+gprsize]
202 %endif
203     HADAMARD8
204     ABS_SUM_8x8         rsp+gprsize
205     HSUM                        m0, m1, eax
206     and                         eax, 0xFFFF
207     ret
208
209 hadamard8_16_wrapper %1, 3
210 %elif cpuflag(mmx)
211 ALIGN 16
212 ; int ff_hadamard8_diff_ ## cpu(MpegEncContext *s, uint8_t *src1,
213 ;                               uint8_t *src2, int stride, int h)
214 ; r0 = void *s = unused, int h = unused (always 8)
215 ; note how r1, r2 and r3 are not clobbered in this function, so 16x16
216 ; can simply call this 2x2x (and that's why we access rsp+gprsize
217 ; everywhere, which is rsp of calling func
218 hadamard8x8_diff %+ SUFFIX:
219     lea                          r0, [r3*3]
220
221     ; first 4x8 pixels
222     DIFF_PIXELS_8                r1, r2,  0, r3, r0, rsp+gprsize+0x60
223     HADAMARD8
224     mova         [rsp+gprsize+0x60], m7
225     TRANSPOSE4x4W                 0,  1,  2,  3,  7
226     STORE4              rsp+gprsize, m0, m1, m2, m3
227     mova                         m7, [rsp+gprsize+0x60]
228     TRANSPOSE4x4W                 4,  5,  6,  7,  0
229     STORE4         rsp+gprsize+0x40, m4, m5, m6, m7
230
231     ; second 4x8 pixels
232     DIFF_PIXELS_8                r1, r2,  4, r3, r0, rsp+gprsize+0x60
233     HADAMARD8
234     mova         [rsp+gprsize+0x60], m7
235     TRANSPOSE4x4W                 0,  1,  2,  3,  7
236     STORE4         rsp+gprsize+0x20, m0, m1, m2, m3
237     mova                         m7, [rsp+gprsize+0x60]
238     TRANSPOSE4x4W                 4,  5,  6,  7,  0
239
240     LOAD4          rsp+gprsize+0x40, m0, m1, m2, m3
241     HADAMARD8
242     ABS_SUM_8x8_32 rsp+gprsize+0x60
243     mova         [rsp+gprsize+0x60], m0
244
245     LOAD4          rsp+gprsize     , m0, m1, m2, m3
246     LOAD4          rsp+gprsize+0x20, m4, m5, m6, m7
247     HADAMARD8
248     ABS_SUM_8x8_32 rsp+gprsize
249     paddusw                      m0, [rsp+gprsize+0x60]
250
251     HSUM                         m0, m1, eax
252     and                         rax, 0xFFFF
253     ret
254
255 hadamard8_16_wrapper 0, 14
256 %endif
257 %endmacro
258
259 INIT_MMX mmx
260 HADAMARD8_DIFF
261
262 INIT_MMX mmxext
263 HADAMARD8_DIFF
264
265 INIT_XMM sse2
266 %if ARCH_X86_64
267 %define ABS_SUM_8x8 ABS_SUM_8x8_64
268 %else
269 %define ABS_SUM_8x8 ABS_SUM_8x8_32
270 %endif
271 HADAMARD8_DIFF 10
272
273 INIT_XMM ssse3
274 %define ABS_SUM_8x8 ABS_SUM_8x8_64
275 HADAMARD8_DIFF 9
276
277 ; int ff_sse*_*(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
278 ;               int line_size, int h)
279
280 %macro SUM_SQUARED_ERRORS 2
281 cglobal sse%1, 5,5,%2, v, pix1, pix2, lsize, h
282 %if %1 == mmsize
283     shr       hd, 1
284 %endif
285     pxor      m0, m0         ; mm0 = 0
286     pxor      m7, m7         ; mm7 holds the sum
287
288 .next2lines: ; FIXME why are these unaligned movs? pix1[] is aligned
289     movu      m1, [pix1q]    ; m1 = pix1[0][0-15], [0-7] for mmx
290     movu      m2, [pix2q]    ; m2 = pix2[0][0-15], [0-7] for mmx
291 %if %1 == mmsize
292     movu      m3, [pix1q+lsizeq] ; m3 = pix1[1][0-15], [0-7] for mmx
293     movu      m4, [pix2q+lsizeq] ; m4 = pix2[1][0-15], [0-7] for mmx
294 %else  ; %1 / 2 == mmsize; mmx only
295     mova      m3, [pix1q+8]  ; m3 = pix1[0][8-15]
296     mova      m4, [pix2q+8]  ; m4 = pix2[0][8-15]
297 %endif
298
299     ; todo: mm1-mm2, mm3-mm4
300     ; algo: subtract mm1 from mm2 with saturation and vice versa
301     ;       OR the result to get the absolute difference
302     mova      m5, m1
303     mova      m6, m3
304     psubusb   m1, m2
305     psubusb   m3, m4
306     psubusb   m2, m5
307     psubusb   m4, m6
308
309     por       m2, m1
310     por       m4, m3
311
312     ; now convert to 16-bit vectors so we can square them
313     mova      m1, m2
314     mova      m3, m4
315
316     punpckhbw m2, m0
317     punpckhbw m4, m0
318     punpcklbw m1, m0         ; mm1 not spread over (mm1,mm2)
319     punpcklbw m3, m0         ; mm4 not spread over (mm3,mm4)
320
321     pmaddwd   m2, m2
322     pmaddwd   m4, m4
323     pmaddwd   m1, m1
324     pmaddwd   m3, m3
325
326     paddd     m1, m2
327     paddd     m3, m4
328     paddd     m7, m1
329     paddd     m7, m3
330
331 %if %1 == mmsize
332     lea    pix1q, [pix1q + 2*lsizeq]
333     lea    pix2q, [pix2q + 2*lsizeq]
334 %else
335     add    pix1q, lsizeq
336     add    pix2q, lsizeq
337 %endif
338     dec       hd
339     jnz .next2lines
340
341     mova      m1, m7
342 %if mmsize == 8
343     psrlq     m7, 32         ; shift hi dword to lo
344 %else
345     psrldq    m7, 8          ; shift hi qword to lo
346     paddd     m7, m1
347     mova      m1, m7
348     psrldq    m7, 4          ; shift hi dword to lo
349 %endif
350     paddd     m7, m1
351     movd     eax, m7         ; return value
352     RET
353 %endmacro
354
355 INIT_MMX mmx
356 SUM_SQUARED_ERRORS 8,  0
357
358 INIT_MMX mmx
359 SUM_SQUARED_ERRORS 16, 0
360
361 INIT_XMM sse2
362 SUM_SQUARED_ERRORS 16, 8
363
364 INIT_MMX mmx
365 ; void ff_get_pixels_mmx(int16_t *block, const uint8_t *pixels, int line_size)
366 cglobal get_pixels, 3,4
367     movsxdifnidn r2, r2d
368     add          r0, 128
369     mov          r3, -128
370     pxor         m7, m7
371 .loop:
372     mova         m0, [r1]
373     mova         m2, [r1+r2]
374     mova         m1, m0
375     mova         m3, m2
376     punpcklbw    m0, m7
377     punpckhbw    m1, m7
378     punpcklbw    m2, m7
379     punpckhbw    m3, m7
380     mova [r0+r3+ 0], m0
381     mova [r0+r3+ 8], m1
382     mova [r0+r3+16], m2
383     mova [r0+r3+24], m3
384     lea          r1, [r1+r2*2]
385     add          r3, 32
386     js .loop
387     REP_RET
388
389 INIT_XMM sse2
390 cglobal get_pixels, 3, 4
391     movsxdifnidn r2, r2d
392     lea          r3, [r2*3]
393     pxor         m4, m4
394     movh         m0, [r1]
395     movh         m1, [r1+r2]
396     movh         m2, [r1+r2*2]
397     movh         m3, [r1+r3]
398     lea          r1, [r1+r2*4]
399     punpcklbw    m0, m4
400     punpcklbw    m1, m4
401     punpcklbw    m2, m4
402     punpcklbw    m3, m4
403     mova       [r0], m0
404     mova  [r0+0x10], m1
405     mova  [r0+0x20], m2
406     mova  [r0+0x30], m3
407     movh         m0, [r1]
408     movh         m1, [r1+r2*1]
409     movh         m2, [r1+r2*2]
410     movh         m3, [r1+r3]
411     punpcklbw    m0, m4
412     punpcklbw    m1, m4
413     punpcklbw    m2, m4
414     punpcklbw    m3, m4
415     mova  [r0+0x40], m0
416     mova  [r0+0x50], m1
417     mova  [r0+0x60], m2
418     mova  [r0+0x70], m3
419     RET
420
421 INIT_MMX mmx
422 ; void ff_diff_pixels_mmx(int16_t *block, const uint8_t *s1, const uint8_t *s2,
423 ;                         int stride);
424 cglobal diff_pixels, 4,5
425     movsxdifnidn r3, r3d
426     pxor         m7, m7
427     add          r0,  128
428     mov          r4, -128
429 .loop:
430     mova         m0, [r1]
431     mova         m2, [r2]
432     mova         m1, m0
433     mova         m3, m2
434     punpcklbw    m0, m7
435     punpckhbw    m1, m7
436     punpcklbw    m2, m7
437     punpckhbw    m3, m7
438     psubw        m0, m2
439     psubw        m1, m3
440     mova  [r0+r4+0], m0
441     mova  [r0+r4+8], m1
442     add          r1, r3
443     add          r2, r3
444     add          r4, 16
445     jne .loop
446     REP_RET
447
448 INIT_MMX mmx
449 ; int ff_pix_sum16_mmx(uint8_t *pix, int line_size)
450 cglobal pix_sum16, 2, 3
451     movsxdifnidn r1, r1d
452     mov          r2, r1
453     neg          r2
454     shl          r2, 4
455     sub          r0, r2
456     pxor         m7, m7
457     pxor         m6, m6
458 .loop:
459     mova         m0, [r0+r2+0]
460     mova         m1, [r0+r2+0]
461     mova         m2, [r0+r2+8]
462     mova         m3, [r0+r2+8]
463     punpcklbw    m0, m7
464     punpckhbw    m1, m7
465     punpcklbw    m2, m7
466     punpckhbw    m3, m7
467     paddw        m1, m0
468     paddw        m3, m2
469     paddw        m3, m1
470     paddw        m6, m3
471     add          r2, r1
472     js .loop
473     mova         m5, m6
474     psrlq        m6, 32
475     paddw        m6, m5
476     mova         m5, m6
477     psrlq        m6, 16
478     paddw        m6, m5
479     movd        eax, m6
480     and         eax, 0xffff
481     RET
482
483 INIT_MMX mmx
484 ; int ff_pix_norm1_mmx(uint8_t *pix, int line_size)
485 cglobal pix_norm1, 2, 4
486     movsxdifnidn r1, r1d
487     mov          r2, 16
488     pxor         m0, m0
489     pxor         m7, m7
490 .loop:
491     mova         m2, [r0+0]
492     mova         m3, [r0+8]
493     mova         m1, m2
494     punpckhbw    m1, m0
495     punpcklbw    m2, m0
496     mova         m4, m3
497     punpckhbw    m3, m0
498     punpcklbw    m4, m0
499     pmaddwd      m1, m1
500     pmaddwd      m2, m2
501     pmaddwd      m3, m3
502     pmaddwd      m4, m4
503     paddd        m2, m1
504     paddd        m4, m3
505     paddd        m7, m2
506     add          r0, r1
507     paddd        m7, m4
508     dec r2
509     jne .loop
510     mova         m1, m7
511     psrlq        m7, 32
512     paddd        m1, m7
513     movd        eax, m1
514     RET
515
516 ;-----------------------------------------------
517 ;int ff_sum_abs_dctelem(int16_t *block)
518 ;-----------------------------------------------
519 ; %1 = number of xmm registers used
520 ; %2 = number of inline loops
521
522 %macro SUM_ABS_DCTELEM 2
523 cglobal sum_abs_dctelem, 1, 1, %1, block
524     pxor    m0, m0
525     pxor    m1, m1
526 %assign %%i 0
527 %rep %2
528     mova      m2, [blockq+mmsize*(0+%%i)]
529     mova      m3, [blockq+mmsize*(1+%%i)]
530     mova      m4, [blockq+mmsize*(2+%%i)]
531     mova      m5, [blockq+mmsize*(3+%%i)]
532     ABS1_SUM  m2, m6, m0
533     ABS1_SUM  m3, m6, m1
534     ABS1_SUM  m4, m6, m0
535     ABS1_SUM  m5, m6, m1
536 %assign %%i %%i+4
537 %endrep
538     paddusw m0, m1
539     HSUM    m0, m1, eax
540     and     eax, 0xFFFF
541     RET
542 %endmacro
543
544 INIT_MMX mmx
545 SUM_ABS_DCTELEM 0, 4
546 INIT_MMX mmxext
547 SUM_ABS_DCTELEM 0, 4
548 INIT_XMM sse2
549 SUM_ABS_DCTELEM 7, 2
550 INIT_XMM ssse3
551 SUM_ABS_DCTELEM 6, 2