]> git.sesse.net Git - ffmpeg/blob - libswscale/x86/scale.asm
Merge remote-tracking branch 'qatar/master'
[ffmpeg] / libswscale / x86 / scale.asm
1 ;******************************************************************************
2 ;* x86-optimized horizontal line scaling functions
3 ;* Copyright (c) 2011 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 "x86inc.asm"
23 %include "x86util.asm"
24
25 SECTION_RODATA
26
27 max_19bit_int: times 4 dd 0x7ffff
28 max_19bit_flt: times 4 dd 524287.0
29 minshort:      times 8 dw 0x8000
30 unicoeff:      times 4 dd 0x20000000
31
32 SECTION .text
33
34 ;-----------------------------------------------------------------------------
35 ; horizontal line scaling
36 ;
37 ; void hscale<source_width>to<intermediate_nbits>_<filterSize>_<opt>
38 ;                               (SwsContext *c, int{16,32}_t *dst,
39 ;                                int dstW, const uint{8,16}_t *src,
40 ;                                const int16_t *filter,
41 ;                                const int32_t *filterPos, int filterSize);
42 ;
43 ; Scale one horizontal line. Input is either 8-bits width or 16-bits width
44 ; ($source_width can be either 8, 9, 10 or 16, difference is whether we have to
45 ; downscale before multiplying). Filter is 14-bits. Output is either 15bits
46 ; (in int16_t) or 19bits (in int32_t), as given in $intermediate_nbits. Each
47 ; output pixel is generated from $filterSize input pixels, the position of
48 ; the first pixel is given in filterPos[nOutputPixel].
49 ;-----------------------------------------------------------------------------
50
51 ; SCALE_FUNC source_width, intermediate_nbits, filtersize, filtersuffix, n_args, n_xmm
52 %macro SCALE_FUNC 6
53 %ifnidn %3, X
54 cglobal hscale%1to%2_%4, %5, 7, %6, pos0, dst, w, src, filter, fltpos, pos1
55 %else
56 cglobal hscale%1to%2_%4, %5, 7, %6, pos0, dst, w, srcmem, filter, fltpos, fltsize
57 %endif
58 %if ARCH_X86_64
59     movsxd        wq, wd
60 %define mov32 movsxd
61 %else ; x86-32
62 %define mov32 mov
63 %endif ; x86-64
64 %if %2 == 19
65 %if mmsize == 8 ; mmx
66     mova          m2, [max_19bit_int]
67 %elif cpuflag(sse4)
68     mova          m2, [max_19bit_int]
69 %else ; ssse3/sse2
70     mova          m2, [max_19bit_flt]
71 %endif ; mmx/sse2/ssse3/sse4
72 %endif ; %2 == 19
73 %if %1 == 16
74     mova          m6, [minshort]
75     mova          m7, [unicoeff]
76 %elif %1 == 8
77     pxor          m3, m3
78 %endif ; %1 == 8/16
79
80 %if %1 == 8
81 %define movlh movd
82 %define movbh movh
83 %define srcmul 1
84 %else ; %1 == 9-16
85 %define movlh movq
86 %define movbh movu
87 %define srcmul 2
88 %endif ; %1 == 8/9-16
89
90 %ifnidn %3, X
91
92     ; setup loop
93 %if %3 == 8
94     shl           wq, 1                         ; this allows *16 (i.e. now *8) in lea instructions for the 8-tap filter
95 %define wshr 1
96 %else ; %3 == 4
97 %define wshr 0
98 %endif ; %3 == 8
99     lea      filterq, [filterq+wq*8]
100 %if %2 == 15
101     lea         dstq, [dstq+wq*(2>>wshr)]
102 %else ; %2 == 19
103     lea         dstq, [dstq+wq*(4>>wshr)]
104 %endif ; %2 == 15/19
105     lea      fltposq, [fltposq+wq*(4>>wshr)]
106     neg           wq
107
108 .loop:
109 %if %3 == 4 ; filterSize == 4 scaling
110     ; load 2x4 or 4x4 source pixels into m0/m1
111     mov32      pos0q, dword [fltposq+wq*4+ 0]   ; filterPos[0]
112     mov32      pos1q, dword [fltposq+wq*4+ 4]   ; filterPos[1]
113     movlh         m0, [srcq+pos0q*srcmul]       ; src[filterPos[0] + {0,1,2,3}]
114 %if mmsize == 8
115     movlh         m1, [srcq+pos1q*srcmul]       ; src[filterPos[1] + {0,1,2,3}]
116 %else ; mmsize == 16
117 %if %1 > 8
118     movhps        m0, [srcq+pos1q*srcmul]       ; src[filterPos[1] + {0,1,2,3}]
119 %else ; %1 == 8
120     movd          m4, [srcq+pos1q*srcmul]       ; src[filterPos[1] + {0,1,2,3}]
121 %endif
122     mov32      pos0q, dword [fltposq+wq*4+ 8]   ; filterPos[2]
123     mov32      pos1q, dword [fltposq+wq*4+12]   ; filterPos[3]
124     movlh         m1, [srcq+pos0q*srcmul]       ; src[filterPos[2] + {0,1,2,3}]
125 %if %1 > 8
126     movhps        m1, [srcq+pos1q*srcmul]       ; src[filterPos[3] + {0,1,2,3}]
127 %else ; %1 == 8
128     movd          m5, [srcq+pos1q*srcmul]       ; src[filterPos[3] + {0,1,2,3}]
129     punpckldq     m0, m4
130     punpckldq     m1, m5
131 %endif ; %1 == 8
132 %endif ; mmsize == 8/16
133 %if %1 == 8
134     punpcklbw     m0, m3                        ; byte -> word
135     punpcklbw     m1, m3                        ; byte -> word
136 %endif ; %1 == 8
137
138     ; multiply with filter coefficients
139 %if %1 == 16 ; pmaddwd needs signed adds, so this moves unsigned -> signed, we'll
140              ; add back 0x8000 * sum(coeffs) after the horizontal add
141     psubw         m0, m6
142     psubw         m1, m6
143 %endif ; %1 == 16
144     pmaddwd       m0, [filterq+wq*8+mmsize*0]   ; *= filter[{0,1,..,6,7}]
145     pmaddwd       m1, [filterq+wq*8+mmsize*1]   ; *= filter[{8,9,..,14,15}]
146
147     ; add up horizontally (4 srcpix * 4 coefficients -> 1 dstpix)
148 %if mmsize == 8 ; mmx
149     movq          m4, m0
150     punpckldq     m0, m1
151     punpckhdq     m4, m1
152     paddd         m0, m4
153 %elif notcpuflag(ssse3) ; sse2
154     mova          m4, m0
155     shufps        m0, m1, 10001000b
156     shufps        m4, m1, 11011101b
157     paddd         m0, m4
158 %else ; ssse3/sse4
159     phaddd        m0, m1                        ; filter[{ 0, 1, 2, 3}]*src[filterPos[0]+{0,1,2,3}],
160                                                 ; filter[{ 4, 5, 6, 7}]*src[filterPos[1]+{0,1,2,3}],
161                                                 ; filter[{ 8, 9,10,11}]*src[filterPos[2]+{0,1,2,3}],
162                                                 ; filter[{12,13,14,15}]*src[filterPos[3]+{0,1,2,3}]
163 %endif ; mmx/sse2/ssse3/sse4
164 %else ; %3 == 8, i.e. filterSize == 8 scaling
165     ; load 2x8 or 4x8 source pixels into m0, m1, m4 and m5
166     mov32      pos0q, dword [fltposq+wq*2+0]    ; filterPos[0]
167     mov32      pos1q, dword [fltposq+wq*2+4]    ; filterPos[1]
168     movbh         m0, [srcq+ pos0q   *srcmul]   ; src[filterPos[0] + {0,1,2,3,4,5,6,7}]
169 %if mmsize == 8
170     movbh         m1, [srcq+(pos0q+4)*srcmul]   ; src[filterPos[0] + {4,5,6,7}]
171     movbh         m4, [srcq+ pos1q   *srcmul]   ; src[filterPos[1] + {0,1,2,3}]
172     movbh         m5, [srcq+(pos1q+4)*srcmul]   ; src[filterPos[1] + {4,5,6,7}]
173 %else ; mmsize == 16
174     movbh         m1, [srcq+ pos1q   *srcmul]   ; src[filterPos[1] + {0,1,2,3,4,5,6,7}]
175     mov32      pos0q, dword [fltposq+wq*2+8]    ; filterPos[2]
176     mov32      pos1q, dword [fltposq+wq*2+12]   ; filterPos[3]
177     movbh         m4, [srcq+ pos0q   *srcmul]   ; src[filterPos[2] + {0,1,2,3,4,5,6,7}]
178     movbh         m5, [srcq+ pos1q   *srcmul]   ; src[filterPos[3] + {0,1,2,3,4,5,6,7}]
179 %endif ; mmsize == 8/16
180 %if %1 == 8
181     punpcklbw     m0, m3                        ; byte -> word
182     punpcklbw     m1, m3                        ; byte -> word
183     punpcklbw     m4, m3                        ; byte -> word
184     punpcklbw     m5, m3                        ; byte -> word
185 %endif ; %1 == 8
186
187     ; multiply
188 %if %1 == 16 ; pmaddwd needs signed adds, so this moves unsigned -> signed, we'll
189              ; add back 0x8000 * sum(coeffs) after the horizontal add
190     psubw         m0, m6
191     psubw         m1, m6
192     psubw         m4, m6
193     psubw         m5, m6
194 %endif ; %1 == 16
195     pmaddwd       m0, [filterq+wq*8+mmsize*0]   ; *= filter[{0,1,..,6,7}]
196     pmaddwd       m1, [filterq+wq*8+mmsize*1]   ; *= filter[{8,9,..,14,15}]
197     pmaddwd       m4, [filterq+wq*8+mmsize*2]   ; *= filter[{16,17,..,22,23}]
198     pmaddwd       m5, [filterq+wq*8+mmsize*3]   ; *= filter[{24,25,..,30,31}]
199
200     ; add up horizontally (8 srcpix * 8 coefficients -> 1 dstpix)
201 %if mmsize == 8
202     paddd         m0, m1
203     paddd         m4, m5
204     movq          m1, m0
205     punpckldq     m0, m4
206     punpckhdq     m1, m4
207     paddd         m0, m1
208 %elif notcpuflag(ssse3) ; sse2
209 %if %1 == 8
210 %define mex m6
211 %else
212 %define mex m3
213 %endif
214     ; emulate horizontal add as transpose + vertical add
215     mova         mex, m0
216     punpckldq     m0, m1
217     punpckhdq    mex, m1
218     paddd         m0, mex
219     mova          m1, m4
220     punpckldq     m4, m5
221     punpckhdq     m1, m5
222     paddd         m4, m1
223     mova          m1, m0
224     punpcklqdq    m0, m4
225     punpckhqdq    m1, m4
226     paddd         m0, m1
227 %else ; ssse3/sse4
228     ; FIXME if we rearrange the filter in pairs of 4, we can
229     ; load pixels likewise and use 2 x paddd + phaddd instead
230     ; of 3 x phaddd here, faster on older cpus
231     phaddd        m0, m1
232     phaddd        m4, m5
233     phaddd        m0, m4                        ; filter[{ 0, 1,..., 6, 7}]*src[filterPos[0]+{0,1,...,6,7}],
234                                                 ; filter[{ 8, 9,...,14,15}]*src[filterPos[1]+{0,1,...,6,7}],
235                                                 ; filter[{16,17,...,22,23}]*src[filterPos[2]+{0,1,...,6,7}],
236                                                 ; filter[{24,25,...,30,31}]*src[filterPos[3]+{0,1,...,6,7}]
237 %endif ; mmx/sse2/ssse3/sse4
238 %endif ; %3 == 4/8
239
240 %else ; %3 == X, i.e. any filterSize scaling
241
242 %ifidn %4, X4
243 %define dlt 4
244 %else ; %4 == X || %4 == X8
245 %define dlt 0
246 %endif ; %4 ==/!= X4
247 %if ARCH_X86_64
248     push         r12
249 %define srcq    r11
250 %define pos1q   r10
251 %define srcendq r12
252     movsxd  fltsizeq, fltsized                  ; filterSize
253     lea      srcendq, [srcmemq+(fltsizeq-dlt)*srcmul] ; &src[filterSize&~4]
254 %else ; x86-32
255 %define srcq    srcmemq
256 %define pos1q   dstq
257 %define srcendq r6m
258     lea        pos0q, [srcmemq+(fltsizeq-dlt)*srcmul] ; &src[filterSize&~4]
259     mov      srcendq, pos0q
260 %endif ; x86-32/64
261     lea      fltposq, [fltposq+wq*4]
262 %if %2 == 15
263     lea         dstq, [dstq+wq*2]
264 %else ; %2 == 19
265     lea         dstq, [dstq+wq*4]
266 %endif ; %2 == 15/19
267     movifnidn  dstmp, dstq
268     neg           wq
269
270 .loop:
271     mov32      pos0q, dword [fltposq+wq*4+0]    ; filterPos[0]
272     mov32      pos1q, dword [fltposq+wq*4+4]    ; filterPos[1]
273     ; FIXME maybe do 4px/iteration on x86-64 (x86-32 wouldn't have enough regs)?
274     pxor          m4, m4
275     pxor          m5, m5
276     mov         srcq, srcmemmp
277
278 .innerloop:
279     ; load 2x4 (mmx) or 2x8 (sse) source pixels into m0/m1 -> m4/m5
280     movbh         m0, [srcq+ pos0q     *srcmul] ; src[filterPos[0] + {0,1,2,3(,4,5,6,7)}]
281     movbh         m1, [srcq+(pos1q+dlt)*srcmul] ; src[filterPos[1] + {0,1,2,3(,4,5,6,7)}]
282 %if %1 == 8
283     punpcklbw     m0, m3
284     punpcklbw     m1, m3
285 %endif ; %1 == 8
286
287     ; multiply
288 %if %1 == 16 ; pmaddwd needs signed adds, so this moves unsigned -> signed, we'll
289              ; add back 0x8000 * sum(coeffs) after the horizontal add
290     psubw         m0, m6
291     psubw         m1, m6
292 %endif ; %1 == 16
293     pmaddwd       m0, [filterq]                 ; filter[{0,1,2,3(,4,5,6,7)}]
294     pmaddwd       m1, [filterq+(fltsizeq+dlt)*2]; filter[filtersize+{0,1,2,3(,4,5,6,7)}]
295     paddd         m4, m0
296     paddd         m5, m1
297     add      filterq, mmsize
298     add         srcq, srcmul*mmsize/2
299     cmp         srcq, srcendq                   ; while (src += 4) < &src[filterSize]
300     jl .innerloop
301
302 %ifidn %4, X4
303     mov32      pos1q, dword [fltposq+wq*4+4]    ; filterPos[1]
304     movlh         m0, [srcq+ pos0q     *srcmul] ; split last 4 srcpx of dstpx[0]
305     sub        pos1q, fltsizeq                  ; and first 4 srcpx of dstpx[1]
306 %if %1 > 8
307     movhps        m0, [srcq+(pos1q+dlt)*srcmul]
308 %else ; %1 == 8
309     movd          m1, [srcq+(pos1q+dlt)*srcmul]
310     punpckldq     m0, m1
311 %endif ; %1 == 8
312 %if %1 == 8
313     punpcklbw     m0, m3
314 %endif ; %1 == 8
315 %if %1 == 16 ; pmaddwd needs signed adds, so this moves unsigned -> signed, we'll
316              ; add back 0x8000 * sum(coeffs) after the horizontal add
317     psubw         m0, m6
318 %endif ; %1 == 16
319     pmaddwd       m0, [filterq]
320 %endif ; %4 == X4
321
322     lea      filterq, [filterq+(fltsizeq+dlt)*2]
323
324 %if mmsize == 8 ; mmx
325     movq          m0, m4
326     punpckldq     m4, m5
327     punpckhdq     m0, m5
328     paddd         m0, m4
329 %else ; mmsize == 16
330 %if notcpuflag(ssse3) ; sse2
331     mova          m1, m4
332     punpcklqdq    m4, m5
333     punpckhqdq    m1, m5
334     paddd         m4, m1
335 %else ; ssse3/sse4
336     phaddd        m4, m5
337 %endif ; sse2/ssse3/sse4
338 %ifidn %4, X4
339     paddd         m4, m0
340 %endif ; %3 == X4
341 %if notcpuflag(ssse3) ; sse2
342     pshufd        m4, m4, 11011000b
343     movhlps       m0, m4
344     paddd         m0, m4
345 %else ; ssse3/sse4
346     phaddd        m4, m4
347     SWAP           0, 4
348 %endif ; sse2/ssse3/sse4
349 %endif ; mmsize == 8/16
350 %endif ; %3 ==/!= X
351
352 %if %1 == 16 ; add 0x8000 * sum(coeffs), i.e. back from signed -> unsigned
353     paddd         m0, m7
354 %endif ; %1 == 16
355
356     ; clip, store
357     psrad         m0, 14 + %1 - %2
358 %ifidn %3, X
359     movifnidn   dstq, dstmp
360 %endif ; %3 == X
361 %if %2 == 15
362     packssdw      m0, m0
363 %ifnidn %3, X
364     movh [dstq+wq*(2>>wshr)], m0
365 %else ; %3 == X
366     movd [dstq+wq*2], m0
367 %endif ; %3 ==/!= X
368 %else ; %2 == 19
369 %if mmsize == 8
370     PMINSD_MMX    m0, m2, m4
371 %elif cpuflag(sse4)
372     pminsd        m0, m2
373 %else ; sse2/ssse3
374     cvtdq2ps      m0, m0
375     minps         m0, m2
376     cvtps2dq      m0, m0
377 %endif ; mmx/sse2/ssse3/sse4
378 %ifnidn %3, X
379     mova [dstq+wq*(4>>wshr)], m0
380 %else ; %3 == X
381     movq [dstq+wq*4], m0
382 %endif ; %3 ==/!= X
383 %endif ; %2 == 15/19
384 %ifnidn %3, X
385     add           wq, (mmsize<<wshr)/4          ; both 8tap and 4tap really only do 4 pixels (or for mmx: 2 pixels)
386                                                 ; per iteration. see "shl wq,1" above as for why we do this
387 %else ; %3 == X
388     add           wq, 2
389 %endif ; %3 ==/!= X
390     jl .loop
391 %ifnidn %3, X
392     REP_RET
393 %else ; %3 == X
394 %if ARCH_X86_64
395     pop          r12
396     RET
397 %else ; x86-32
398     REP_RET
399 %endif ; x86-32/64
400 %endif ; %3 ==/!= X
401 %endmacro
402
403 ; SCALE_FUNCS source_width, intermediate_nbits, n_xmm
404 %macro SCALE_FUNCS 3
405 SCALE_FUNC %1, %2, 4, 4,  6, %3
406 SCALE_FUNC %1, %2, 8, 8,  6, %3
407 %if mmsize == 8
408 SCALE_FUNC %1, %2, X, X,  7, %3
409 %else
410 SCALE_FUNC %1, %2, X, X4, 7, %3
411 SCALE_FUNC %1, %2, X, X8, 7, %3
412 %endif
413 %endmacro
414
415 ; SCALE_FUNCS2 8_xmm_args, 9to10_xmm_args, 16_xmm_args
416 %macro SCALE_FUNCS2 3
417 %if notcpuflag(sse4)
418 SCALE_FUNCS  8, 15, %1
419 SCALE_FUNCS  9, 15, %2
420 SCALE_FUNCS 10, 15, %2
421 SCALE_FUNCS 14, 15, %2
422 SCALE_FUNCS 16, 15, %3
423 %endif ; !sse4
424 SCALE_FUNCS  8, 19, %1
425 SCALE_FUNCS  9, 19, %2
426 SCALE_FUNCS 10, 19, %2
427 SCALE_FUNCS 14, 19, %2
428 SCALE_FUNCS 16, 19, %3
429 %endmacro
430
431 %if ARCH_X86_32
432 INIT_MMX mmx
433 SCALE_FUNCS2 0, 0, 0
434 %endif
435 INIT_XMM sse2
436 SCALE_FUNCS2 6, 7, 8
437 INIT_XMM ssse3
438 SCALE_FUNCS2 6, 6, 8
439 INIT_XMM sse4
440 SCALE_FUNCS2 6, 6, 8