]> git.sesse.net Git - ffmpeg/blob - libswscale/x86/scale.asm
indeo4: update AVCodecContext width/height on size change
[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, 10, %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 %define srcq    r8
249 %define pos1q   r7
250 %define srcendq r9
251     movsxd  fltsizeq, fltsized                  ; filterSize
252     lea      srcendq, [srcmemq+(fltsizeq-dlt)*srcmul] ; &src[filterSize&~4]
253 %else ; x86-32
254 %define srcq    srcmemq
255 %define pos1q   dstq
256 %define srcendq r6m
257     lea        pos0q, [srcmemq+(fltsizeq-dlt)*srcmul] ; &src[filterSize&~4]
258     mov      srcendq, pos0q
259 %endif ; x86-32/64
260     lea      fltposq, [fltposq+wq*4]
261 %if %2 == 15
262     lea         dstq, [dstq+wq*2]
263 %else ; %2 == 19
264     lea         dstq, [dstq+wq*4]
265 %endif ; %2 == 15/19
266     movifnidn  dstmp, dstq
267     neg           wq
268
269 .loop:
270     mov32      pos0q, dword [fltposq+wq*4+0]    ; filterPos[0]
271     mov32      pos1q, dword [fltposq+wq*4+4]    ; filterPos[1]
272     ; FIXME maybe do 4px/iteration on x86-64 (x86-32 wouldn't have enough regs)?
273     pxor          m4, m4
274     pxor          m5, m5
275     mov         srcq, srcmemmp
276
277 .innerloop:
278     ; load 2x4 (mmx) or 2x8 (sse) source pixels into m0/m1 -> m4/m5
279     movbh         m0, [srcq+ pos0q     *srcmul] ; src[filterPos[0] + {0,1,2,3(,4,5,6,7)}]
280     movbh         m1, [srcq+(pos1q+dlt)*srcmul] ; src[filterPos[1] + {0,1,2,3(,4,5,6,7)}]
281 %if %1 == 8
282     punpcklbw     m0, m3
283     punpcklbw     m1, m3
284 %endif ; %1 == 8
285
286     ; multiply
287 %if %1 == 16 ; pmaddwd needs signed adds, so this moves unsigned -> signed, we'll
288              ; add back 0x8000 * sum(coeffs) after the horizontal add
289     psubw         m0, m6
290     psubw         m1, m6
291 %endif ; %1 == 16
292     pmaddwd       m0, [filterq]                 ; filter[{0,1,2,3(,4,5,6,7)}]
293     pmaddwd       m1, [filterq+(fltsizeq+dlt)*2]; filter[filtersize+{0,1,2,3(,4,5,6,7)}]
294     paddd         m4, m0
295     paddd         m5, m1
296     add      filterq, mmsize
297     add         srcq, srcmul*mmsize/2
298     cmp         srcq, srcendq                   ; while (src += 4) < &src[filterSize]
299     jl .innerloop
300
301 %ifidn %4, X4
302     mov32      pos1q, dword [fltposq+wq*4+4]    ; filterPos[1]
303     movlh         m0, [srcq+ pos0q     *srcmul] ; split last 4 srcpx of dstpx[0]
304     sub        pos1q, fltsizeq                  ; and first 4 srcpx of dstpx[1]
305 %if %1 > 8
306     movhps        m0, [srcq+(pos1q+dlt)*srcmul]
307 %else ; %1 == 8
308     movd          m1, [srcq+(pos1q+dlt)*srcmul]
309     punpckldq     m0, m1
310 %endif ; %1 == 8
311 %if %1 == 8
312     punpcklbw     m0, m3
313 %endif ; %1 == 8
314 %if %1 == 16 ; pmaddwd needs signed adds, so this moves unsigned -> signed, we'll
315              ; add back 0x8000 * sum(coeffs) after the horizontal add
316     psubw         m0, m6
317 %endif ; %1 == 16
318     pmaddwd       m0, [filterq]
319 %endif ; %4 == X4
320
321     lea      filterq, [filterq+(fltsizeq+dlt)*2]
322
323 %if mmsize == 8 ; mmx
324     movq          m0, m4
325     punpckldq     m4, m5
326     punpckhdq     m0, m5
327     paddd         m0, m4
328 %else ; mmsize == 16
329 %if notcpuflag(ssse3) ; sse2
330     mova          m1, m4
331     punpcklqdq    m4, m5
332     punpckhqdq    m1, m5
333     paddd         m4, m1
334 %else ; ssse3/sse4
335     phaddd        m4, m5
336 %endif ; sse2/ssse3/sse4
337 %ifidn %4, X4
338     paddd         m4, m0
339 %endif ; %3 == X4
340 %if notcpuflag(ssse3) ; sse2
341     pshufd        m4, m4, 11011000b
342     movhlps       m0, m4
343     paddd         m0, m4
344 %else ; ssse3/sse4
345     phaddd        m4, m4
346     SWAP           0, 4
347 %endif ; sse2/ssse3/sse4
348 %endif ; mmsize == 8/16
349 %endif ; %3 ==/!= X
350
351 %if %1 == 16 ; add 0x8000 * sum(coeffs), i.e. back from signed -> unsigned
352     paddd         m0, m7
353 %endif ; %1 == 16
354
355     ; clip, store
356     psrad         m0, 14 + %1 - %2
357 %ifidn %3, X
358     movifnidn   dstq, dstmp
359 %endif ; %3 == X
360 %if %2 == 15
361     packssdw      m0, m0
362 %ifnidn %3, X
363     movh [dstq+wq*(2>>wshr)], m0
364 %else ; %3 == X
365     movd [dstq+wq*2], m0
366 %endif ; %3 ==/!= X
367 %else ; %2 == 19
368 %if mmsize == 8
369     PMINSD_MMX    m0, m2, m4
370 %elif cpuflag(sse4)
371     pminsd        m0, m2
372 %else ; sse2/ssse3
373     cvtdq2ps      m0, m0
374     minps         m0, m2
375     cvtps2dq      m0, m0
376 %endif ; mmx/sse2/ssse3/sse4
377 %ifnidn %3, X
378     mova [dstq+wq*(4>>wshr)], m0
379 %else ; %3 == X
380     movq [dstq+wq*4], m0
381 %endif ; %3 ==/!= X
382 %endif ; %2 == 15/19
383 %ifnidn %3, X
384     add           wq, (mmsize<<wshr)/4          ; both 8tap and 4tap really only do 4 pixels (or for mmx: 2 pixels)
385                                                 ; per iteration. see "shl wq,1" above as for why we do this
386 %else ; %3 == X
387     add           wq, 2
388 %endif ; %3 ==/!= X
389     jl .loop
390     REP_RET
391 %endmacro
392
393 ; SCALE_FUNCS source_width, intermediate_nbits, n_xmm
394 %macro SCALE_FUNCS 3
395 SCALE_FUNC %1, %2, 4, 4,  6, %3
396 SCALE_FUNC %1, %2, 8, 8,  6, %3
397 %if mmsize == 8
398 SCALE_FUNC %1, %2, X, X,  7, %3
399 %else
400 SCALE_FUNC %1, %2, X, X4, 7, %3
401 SCALE_FUNC %1, %2, X, X8, 7, %3
402 %endif
403 %endmacro
404
405 ; SCALE_FUNCS2 8_xmm_args, 9to10_xmm_args, 16_xmm_args
406 %macro SCALE_FUNCS2 3
407 %if notcpuflag(sse4)
408 SCALE_FUNCS  8, 15, %1
409 SCALE_FUNCS  9, 15, %2
410 SCALE_FUNCS 10, 15, %2
411 SCALE_FUNCS 16, 15, %3
412 %endif ; !sse4
413 SCALE_FUNCS  8, 19, %1
414 SCALE_FUNCS  9, 19, %2
415 SCALE_FUNCS 10, 19, %2
416 SCALE_FUNCS 16, 19, %3
417 %endmacro
418
419 %if ARCH_X86_32
420 INIT_MMX mmx
421 SCALE_FUNCS2 0, 0, 0
422 %endif
423 INIT_XMM sse2
424 SCALE_FUNCS2 6, 7, 8
425 INIT_XMM ssse3
426 SCALE_FUNCS2 6, 6, 8
427 INIT_XMM sse4
428 SCALE_FUNCS2 6, 6, 8