]> 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/vertical line scaling functions
3 ;* Copyright (c) 2011 Ronald S. Bultje <rsbultje@gmail.com>
4 ;*                    Kieran Kunhya <kieran@kunhya.com>
5 ;*
6 ;* This file is part of Libav.
7 ;*
8 ;* Libav is free software; you can redistribute it and/or
9 ;* modify it under the terms of the GNU Lesser General Public
10 ;* License as published by the Free Software Foundation; either
11 ;* version 2.1 of the License, or (at your option) any later version.
12 ;*
13 ;* Libav is distributed in the hope that it will be useful,
14 ;* but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 ;* Lesser General Public License for more details.
17 ;*
18 ;* You should have received a copy of the GNU Lesser General Public
19 ;* License along with Libav; if not, write to the Free Software
20 ;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 ;******************************************************************************
22
23 %include "x86inc.asm"
24 %include "x86util.asm"
25
26 SECTION_RODATA
27
28 max_19bit_int: times 4 dd 0x7ffff
29 max_19bit_flt: times 4 dd 524287.0
30 minshort:      times 8 dw 0x8000
31 unicoeff:      times 4 dd 0x20000000
32 yuv2yuvX_16_start:  times 4 dd 0x4000 - 0x40000000
33 yuv2yuvX_10_start:  times 4 dd 0x10000
34 yuv2yuvX_9_start:   times 4 dd 0x20000
35 yuv2yuvX_10_upper:  times 8 dw 0x3ff
36 yuv2yuvX_9_upper:   times 8 dw 0x1ff
37 pd_4:          times 4 dd 4
38 pd_4min0x40000:times 4 dd 4 - (0x40000)
39 pw_16:         times 8 dw 16
40 pw_32:         times 8 dw 32
41 pw_512:        times 8 dw 512
42 pw_1024:       times 8 dw 1024
43
44 SECTION .text
45
46 ;-----------------------------------------------------------------------------
47 ; horizontal line scaling
48 ;
49 ; void hscale<source_width>to<intermediate_nbits>_<filterSize>_<opt>
50 ;                               (SwsContext *c, int{16,32}_t *dst,
51 ;                                int dstW, const uint{8,16}_t *src,
52 ;                                const int16_t *filter,
53 ;                                const int16_t *filterPos, int filterSize);
54 ;
55 ; Scale one horizontal line. Input is either 8-bits width or 16-bits width
56 ; ($source_width can be either 8, 9, 10 or 16, difference is whether we have to
57 ; downscale before multiplying). Filter is 14-bits. Output is either 15bits
58 ; (in int16_t) or 19bits (in int32_t), as given in $intermediate_nbits. Each
59 ; output pixel is generated from $filterSize input pixels, the position of
60 ; the first pixel is given in filterPos[nOutputPixel].
61 ;-----------------------------------------------------------------------------
62
63 ; SCALE_FUNC source_width, intermediate_nbits, filtersize, filtersuffix, opt, n_args, n_xmm
64 %macro SCALE_FUNC 7
65 cglobal hscale%1to%2_%4_%5, %6, 7, %7
66 %ifdef ARCH_X86_64
67     movsxd        r2, r2d
68 %endif ; x86-64
69 %if %2 == 19
70 %if mmsize == 8 ; mmx
71     mova          m2, [max_19bit_int]
72 %elifidn %5, sse4
73     mova          m2, [max_19bit_int]
74 %else ; ssse3/sse2
75     mova          m2, [max_19bit_flt]
76 %endif ; mmx/sse2/ssse3/sse4
77 %endif ; %2 == 19
78 %if %1 == 16
79     mova          m6, [minshort]
80     mova          m7, [unicoeff]
81 %elif %1 == 8
82     pxor          m3, m3
83 %endif ; %1 == 8/16
84
85 %if %1 == 8
86 %define movlh movd
87 %define movbh movh
88 %define srcmul 1
89 %else ; %1 == 9-16
90 %define movlh movq
91 %define movbh movu
92 %define srcmul 2
93 %endif ; %1 == 8/9-16
94
95 %ifnidn %3, X
96
97     ; setup loop
98 %if %3 == 8
99     shl           r2, 1                  ; this allows *16 (i.e. now *8) in lea instructions for the 8-tap filter
100 %define r2shr 1
101 %else ; %3 == 4
102 %define r2shr 0
103 %endif ; %3 == 8
104     lea           r4, [r4+r2*8]
105 %if %2 == 15
106     lea           r1, [r1+r2*(2>>r2shr)]
107 %else ; %2 == 19
108     lea           r1, [r1+r2*(4>>r2shr)]
109 %endif ; %2 == 15/19
110     lea           r5, [r5+r2*(2>>r2shr)]
111     neg           r2
112
113 .loop:
114 %if %3 == 4 ; filterSize == 4 scaling
115     ; load 2x4 or 4x4 source pixels into m0/m1
116     movsx         r0, word [r5+r2*2+0]   ; filterPos[0]
117     movsx         r6, word [r5+r2*2+2]   ; filterPos[1]
118     movlh         m0, [r3+r0*srcmul]     ; src[filterPos[0] + {0,1,2,3}]
119 %if mmsize == 8
120     movlh         m1, [r3+r6*srcmul]     ; src[filterPos[1] + {0,1,2,3}]
121 %else ; mmsize == 16
122 %if %1 > 8
123     movhps        m0, [r3+r6*srcmul]     ; src[filterPos[1] + {0,1,2,3}]
124 %else ; %1 == 8
125     movd          m4, [r3+r6*srcmul]     ; src[filterPos[1] + {0,1,2,3}]
126 %endif
127     movsx         r0, word [r5+r2*2+4]   ; filterPos[2]
128     movsx         r6, word [r5+r2*2+6]   ; filterPos[3]
129     movlh         m1, [r3+r0*srcmul]     ; src[filterPos[2] + {0,1,2,3}]
130 %if %1 > 8
131     movhps        m1, [r3+r6*srcmul]     ; src[filterPos[3] + {0,1,2,3}]
132 %else ; %1 == 8
133     movd          m5, [r3+r6*srcmul]     ; src[filterPos[3] + {0,1,2,3}]
134     punpckldq     m0, m4
135     punpckldq     m1, m5
136 %endif ; %1 == 8 && %5 <= ssse
137 %endif ; mmsize == 8/16
138 %if %1 == 8
139     punpcklbw     m0, m3                 ; byte -> word
140     punpcklbw     m1, m3                 ; byte -> word
141 %endif ; %1 == 8
142
143     ; multiply with filter coefficients
144 %if %1 == 16 ; pmaddwd needs signed adds, so this moves unsigned -> signed, we'll
145              ; add back 0x8000 * sum(coeffs) after the horizontal add
146     psubw         m0, m6
147     psubw         m1, m6
148 %endif ; %1 == 16
149     pmaddwd       m0, [r4+r2*8+mmsize*0] ; *= filter[{0,1,..,6,7}]
150     pmaddwd       m1, [r4+r2*8+mmsize*1] ; *= filter[{8,9,..,14,15}]
151
152     ; add up horizontally (4 srcpix * 4 coefficients -> 1 dstpix)
153 %if mmsize == 8 ; mmx
154     movq          m4, m0
155     punpckldq     m0, m1
156     punpckhdq     m4, m1
157     paddd         m0, m4
158 %elifidn %5, sse2
159     mova          m4, m0
160     shufps        m0, m1, 10001000b
161     shufps        m4, m1, 11011101b
162     paddd         m0, m4
163 %else ; ssse3/sse4
164     phaddd        m0, m1                 ; filter[{ 0, 1, 2, 3}]*src[filterPos[0]+{0,1,2,3}],
165                                          ; filter[{ 4, 5, 6, 7}]*src[filterPos[1]+{0,1,2,3}],
166                                          ; filter[{ 8, 9,10,11}]*src[filterPos[2]+{0,1,2,3}],
167                                          ; filter[{12,13,14,15}]*src[filterPos[3]+{0,1,2,3}]
168 %endif ; mmx/sse2/ssse3/sse4
169 %else ; %3 == 8, i.e. filterSize == 8 scaling
170     ; load 2x8 or 4x8 source pixels into m0, m1, m4 and m5
171     movsx         r0, word [r5+r2*1+0]   ; filterPos[0]
172     movsx         r6, word [r5+r2*1+2]   ; filterPos[1]
173     movbh         m0, [r3+ r0   *srcmul] ; src[filterPos[0] + {0,1,2,3,4,5,6,7}]
174 %if mmsize == 8
175     movbh         m1, [r3+(r0+4)*srcmul] ; src[filterPos[0] + {4,5,6,7}]
176     movbh         m4, [r3+ r6   *srcmul] ; src[filterPos[1] + {0,1,2,3}]
177     movbh         m5, [r3+(r6+4)*srcmul] ; src[filterPos[1] + {4,5,6,7}]
178 %else ; mmsize == 16
179     movbh         m1, [r3+ r6   *srcmul] ; src[filterPos[1] + {0,1,2,3,4,5,6,7}]
180     movsx         r0, word [r5+r2*1+4]   ; filterPos[2]
181     movsx         r6, word [r5+r2*1+6]   ; filterPos[3]
182     movbh         m4, [r3+ r0   *srcmul] ; src[filterPos[2] + {0,1,2,3,4,5,6,7}]
183     movbh         m5, [r3+ r6   *srcmul] ; src[filterPos[3] + {0,1,2,3,4,5,6,7}]
184 %endif ; mmsize == 8/16
185 %if %1 == 8
186     punpcklbw     m0, m3                 ; byte -> word
187     punpcklbw     m1, m3                 ; byte -> word
188     punpcklbw     m4, m3                 ; byte -> word
189     punpcklbw     m5, m3                 ; byte -> word
190 %endif ; %1 == 8
191
192     ; multiply
193 %if %1 == 16 ; pmaddwd needs signed adds, so this moves unsigned -> signed, we'll
194              ; add back 0x8000 * sum(coeffs) after the horizontal add
195     psubw         m0, m6
196     psubw         m1, m6
197     psubw         m4, m6
198     psubw         m5, m6
199 %endif ; %1 == 16
200     pmaddwd       m0, [r4+r2*8+mmsize*0] ; *= filter[{0,1,..,6,7}]
201     pmaddwd       m1, [r4+r2*8+mmsize*1] ; *= filter[{8,9,..,14,15}]
202     pmaddwd       m4, [r4+r2*8+mmsize*2] ; *= filter[{16,17,..,22,23}]
203     pmaddwd       m5, [r4+r2*8+mmsize*3] ; *= filter[{24,25,..,30,31}]
204
205     ; add up horizontally (8 srcpix * 8 coefficients -> 1 dstpix)
206 %if mmsize == 8
207     paddd         m0, m1
208     paddd         m4, m5
209     movq          m1, m0
210     punpckldq     m0, m4
211     punpckhdq     m1, m4
212     paddd         m0, m1
213 %elifidn %5, sse2
214 %if %1 == 8
215 %define mex m6
216 %else
217 %define mex m3
218 %endif
219     ; emulate horizontal add as transpose + vertical add
220     mova         mex, m0
221     punpckldq     m0, m1
222     punpckhdq    mex, m1
223     paddd         m0, mex
224     mova          m1, m4
225     punpckldq     m4, m5
226     punpckhdq     m1, m5
227     paddd         m4, m1
228     mova          m1, m0
229     punpcklqdq    m0, m4
230     punpckhqdq    m1, m4
231     paddd         m0, m1
232 %else ; ssse3/sse4
233     ; FIXME if we rearrange the filter in pairs of 4, we can
234     ; load pixels likewise and use 2 x paddd + phaddd instead
235     ; of 3 x phaddd here, faster on older cpus
236     phaddd        m0, m1
237     phaddd        m4, m5
238     phaddd        m0, m4                 ; filter[{ 0, 1,..., 6, 7}]*src[filterPos[0]+{0,1,...,6,7}],
239                                          ; filter[{ 8, 9,...,14,15}]*src[filterPos[1]+{0,1,...,6,7}],
240                                          ; filter[{16,17,...,22,23}]*src[filterPos[2]+{0,1,...,6,7}],
241                                          ; filter[{24,25,...,30,31}]*src[filterPos[3]+{0,1,...,6,7}]
242 %endif ; mmx/sse2/ssse3/sse4
243 %endif ; %3 == 4/8
244
245 %else ; %3 == X, i.e. any filterSize scaling
246
247 %ifidn %4, X4
248 %define r6sub 4
249 %else ; %4 == X || %4 == X8
250 %define r6sub 0
251 %endif ; %4 ==/!= X4
252 %ifdef ARCH_X86_64
253     push         r12
254     movsxd        r6, r6d                ; filterSize
255     lea          r12, [r3+(r6-r6sub)*srcmul] ; &src[filterSize&~4]
256 %define src_reg r11
257 %define r1x     r10
258 %define filter2 r12
259 %else ; x86-32
260     lea           r0, [r3+(r6-r6sub)*srcmul] ; &src[filterSize&~4]
261     mov          r6m, r0
262 %define src_reg r3
263 %define r1x     r1
264 %define filter2 r6m
265 %endif ; x86-32/64
266     lea           r5, [r5+r2*2]
267 %if %2 == 15
268     lea           r1, [r1+r2*2]
269 %else ; %2 == 19
270     lea           r1, [r1+r2*4]
271 %endif ; %2 == 15/19
272     movifnidn   r1mp, r1
273     neg           r2
274
275 .loop:
276     movsx         r0, word [r5+r2*2+0]   ; filterPos[0]
277     movsx        r1x, word [r5+r2*2+2]   ; filterPos[1]
278     ; FIXME maybe do 4px/iteration on x86-64 (x86-32 wouldn't have enough regs)?
279     pxor          m4, m4
280     pxor          m5, m5
281     mov      src_reg, r3mp
282
283 .innerloop:
284     ; load 2x4 (mmx) or 2x8 (sse) source pixels into m0/m1 -> m4/m5
285     movbh         m0, [src_reg+r0 *srcmul]    ; src[filterPos[0] + {0,1,2,3(,4,5,6,7)}]
286     movbh         m1, [src_reg+(r1x+r6sub)*srcmul]    ; src[filterPos[1] + {0,1,2,3(,4,5,6,7)}]
287 %if %1 == 8
288     punpcklbw     m0, m3
289     punpcklbw     m1, m3
290 %endif ; %1 == 8
291
292     ; multiply
293 %if %1 == 16 ; pmaddwd needs signed adds, so this moves unsigned -> signed, we'll
294              ; add back 0x8000 * sum(coeffs) after the horizontal add
295     psubw         m0, m6
296     psubw         m1, m6
297 %endif ; %1 == 16
298     pmaddwd       m0, [r4     ]          ; filter[{0,1,2,3(,4,5,6,7)}]
299     pmaddwd       m1, [r4+(r6+r6sub)*2]          ; filter[filtersize+{0,1,2,3(,4,5,6,7)}]
300     paddd         m4, m0
301     paddd         m5, m1
302     add           r4, mmsize
303     add      src_reg, srcmul*mmsize/2
304     cmp      src_reg, filter2            ; while (src += 4) < &src[filterSize]
305     jl .innerloop
306
307 %ifidn %4, X4
308     movsx        r1x, word [r5+r2*2+2]   ; filterPos[1]
309     movlh         m0, [src_reg+r0 *srcmul] ; split last 4 srcpx of dstpx[0]
310     sub          r1x, r6                   ; and first 4 srcpx of dstpx[1]
311 %if %1 > 8
312     movhps        m0, [src_reg+(r1x+r6sub)*srcmul]
313 %else ; %1 == 8
314     movd          m1, [src_reg+(r1x+r6sub)*srcmul]
315     punpckldq     m0, m1
316 %endif ; %1 == 8 && %5 <= ssse
317 %if %1 == 8
318     punpcklbw     m0, m3
319 %endif ; %1 == 8
320 %if %1 == 16 ; pmaddwd needs signed adds, so this moves unsigned -> signed, we'll
321              ; add back 0x8000 * sum(coeffs) after the horizontal add
322     psubw         m0, m6
323 %endif ; %1 == 16
324     pmaddwd       m0, [r4]
325 %endif ; %4 == X4
326
327     lea           r4, [r4+(r6+r6sub)*2]
328
329 %if mmsize == 8 ; mmx
330     movq          m0, m4
331     punpckldq     m4, m5
332     punpckhdq     m0, m5
333     paddd         m0, m4
334 %else ; mmsize == 16
335 %ifidn %5, sse2
336     mova          m1, m4
337     punpcklqdq    m4, m5
338     punpckhqdq    m1, m5
339     paddd         m4, m1
340 %else ; ssse3/sse4
341     phaddd        m4, m5
342 %endif ; sse2/ssse3/sse4
343 %ifidn %4, X4
344     paddd         m4, m0
345 %endif ; %3 == X4
346 %ifidn %5, sse2
347     pshufd        m4, m4, 11011000b
348     movhlps       m0, m4
349     paddd         m0, m4
350 %else ; ssse3/sse4
351     phaddd        m4, m4
352     SWAP           0, 4
353 %endif ; sse2/ssse3/sse4
354 %endif ; mmsize == 8/16
355 %endif ; %3 ==/!= X
356
357 %if %1 == 16 ; add 0x8000 * sum(coeffs), i.e. back from signed -> unsigned
358     paddd         m0, m7
359 %endif ; %1 == 16
360
361     ; clip, store
362     psrad         m0, 14 + %1 - %2
363 %ifidn %3, X
364     movifnidn     r1, r1mp
365 %endif ; %3 == X
366 %if %2 == 15
367     packssdw      m0, m0
368 %ifnidn %3, X
369     movh [r1+r2*(2>>r2shr)], m0
370 %else ; %3 == X
371     movd   [r1+r2*2], m0
372 %endif ; %3 ==/!= X
373 %else ; %2 == 19
374 %if mmsize == 8
375     PMINSD_MMX    m0, m2, m4
376 %elifidn %5, sse4
377     pminsd        m0, m2
378 %else ; sse2/ssse3
379     cvtdq2ps      m0, m0
380     minps         m0, m2
381     cvtps2dq      m0, m0
382 %endif ; mmx/sse2/ssse3/sse4
383 %ifnidn %3, X
384     mova [r1+r2*(4>>r2shr)], m0
385 %else ; %3 == X
386     movq   [r1+r2*4], m0
387 %endif ; %3 ==/!= X
388 %endif ; %2 == 15/19
389 %ifnidn %3, X
390     add           r2, (mmsize<<r2shr)/4  ; both 8tap and 4tap really only do 4 pixels (or for mmx: 2 pixels)
391                                          ; per iteration. see "shl r2,1" above as for why we do this
392 %else ; %3 == X
393     add           r2, 2
394 %endif ; %3 ==/!= X
395     jl .loop
396 %ifnidn %3, X
397     REP_RET
398 %else ; %3 == X
399 %ifdef ARCH_X86_64
400     pop          r12
401     RET
402 %else ; x86-32
403     REP_RET
404 %endif ; x86-32/64
405 %endif ; %3 ==/!= X
406 %endmacro
407
408 ; SCALE_FUNCS source_width, intermediate_nbits, opt, n_xmm
409 %macro SCALE_FUNCS 4
410 SCALE_FUNC %1, %2, 4, 4,  %3, 6, %4
411 SCALE_FUNC %1, %2, 8, 8,  %3, 6, %4
412 %if mmsize == 8
413 SCALE_FUNC %1, %2, X, X,  %3, 7, %4
414 %else
415 SCALE_FUNC %1, %2, X, X4, %3, 7, %4
416 SCALE_FUNC %1, %2, X, X8, %3, 7, %4
417 %endif
418 %endmacro
419
420 ; SCALE_FUNCS2 opt, 8_xmm_args, 9to10_xmm_args, 16_xmm_args
421 %macro SCALE_FUNCS2 4
422 %ifnidn %1, sse4
423 SCALE_FUNCS  8, 15, %1, %2
424 SCALE_FUNCS  9, 15, %1, %3
425 SCALE_FUNCS 10, 15, %1, %3
426 SCALE_FUNCS 14, 15, %1, %3
427 SCALE_FUNCS 16, 15, %1, %4
428 %endif ; !sse4
429 SCALE_FUNCS  8, 19, %1, %2
430 SCALE_FUNCS  9, 19, %1, %3
431 SCALE_FUNCS 10, 19, %1, %3
432 SCALE_FUNCS 14, 19, %1, %3
433 SCALE_FUNCS 16, 19, %1, %4
434 %endmacro
435
436 %ifdef ARCH_X86_32
437 INIT_MMX
438 SCALE_FUNCS2 mmx,   0, 0, 0
439 %endif
440 INIT_XMM
441 SCALE_FUNCS2 sse2,  6, 7, 8
442 SCALE_FUNCS2 ssse3, 6, 6, 8
443 SCALE_FUNCS2 sse4,  6, 6, 8
444
445 ;-----------------------------------------------------------------------------
446 ; vertical line scaling
447 ;
448 ; void yuv2plane1_<output_size>_<opt>(const int16_t *src, uint8_t *dst, int dstW,
449 ;                                     const uint8_t *dither, int offset)
450 ; and
451 ; void yuv2planeX_<output_size>_<opt>(const int16_t *filter, int filterSize,
452 ;                                     const int16_t **src, uint8_t *dst, int dstW,
453 ;                                     const uint8_t *dither, int offset)
454 ;
455 ; Scale one or $filterSize lines of source data to generate one line of output
456 ; data. The input is 15-bit in int16_t if $output_size is [8,10] and 19-bit in
457 ; int32_t if $output_size is 16. $filter is 12-bits. $filterSize is a multiple
458 ; of 2. $offset is either 0 or 3. $dither holds 8 values.
459 ;-----------------------------------------------------------------------------
460
461 %macro yuv2planeX_fn 4
462
463 %ifdef ARCH_X86_32
464 %define cntr_reg r1
465 %define movsx mov
466 %else
467 %define cntr_reg r11
468 %define movsx movsxd
469 %endif
470
471 cglobal yuv2planeX_%2_%1, %4, 7, %3
472 %if %2 == 8 || %2 == 9 || %2 == 10
473     pxor            m6,  m6
474 %endif ; %2 == 8/9/10
475
476 %if %2 == 8
477 %ifdef ARCH_X86_32
478 %assign pad 0x2c - (stack_offset & 15)
479     SUB             rsp, pad
480 %define m_dith m7
481 %else ; x86-64
482 %define m_dith m9
483 %endif ; x86-32
484
485     ; create registers holding dither
486     movq        m_dith, [r5]             ; dither
487     test            r6d, r6d
488     jz              .no_rot
489 %if mmsize == 16
490     punpcklqdq  m_dith,  m_dith
491 %endif ; mmsize == 16
492     PALIGNR     m_dith,  m_dith,  3,  m0
493 .no_rot:
494 %if mmsize == 16
495     punpcklbw   m_dith,  m6
496 %ifdef ARCH_X86_64
497     punpcklwd       m8,  m_dith,  m6
498     pslld           m8,  12
499 %else ; x86-32
500     punpcklwd       m5,  m_dith,  m6
501     pslld           m5,  12
502 %endif ; x86-32/64
503     punpckhwd   m_dith,  m6
504     pslld       m_dith,  12
505 %ifdef ARCH_X86_32
506     mova      [rsp+ 0],  m5
507     mova      [rsp+16],  m_dith
508 %endif
509 %else ; mmsize == 8
510     punpcklbw       m5,  m_dith,  m6
511     punpckhbw   m_dith,  m6
512     punpcklwd       m4,  m5,  m6
513     punpckhwd       m5,  m6
514     punpcklwd       m3,  m_dith,  m6
515     punpckhwd   m_dith,  m6
516     pslld           m4,  12
517     pslld           m5,  12
518     pslld           m3,  12
519     pslld       m_dith,  12
520     mova      [rsp+ 0],  m4
521     mova      [rsp+ 8],  m5
522     mova      [rsp+16],  m3
523     mova      [rsp+24],  m_dith
524 %endif ; mmsize == 8/16
525 %endif ; %2 == 8
526
527     xor             r5,  r5
528
529 .pixelloop:
530 %assign %%i 0
531     ; the rep here is for the 8bit output mmx case, where dither covers
532     ; 8 pixels but we can only handle 2 pixels per register, and thus 4
533     ; pixels per iteration. In order to not have to keep track of where
534     ; we are w.r.t. dithering, we unroll the mmx/8bit loop x2.
535 %if %2 == 8
536 %rep 16/mmsize
537 %endif ; %2 == 8
538
539 %if %2 == 8
540 %ifdef ARCH_X86_32
541     mova            m2, [rsp+mmsize*(0+%%i)]
542     mova            m1, [rsp+mmsize*(1+%%i)]
543 %else ; x86-64
544     mova            m2,  m8
545     mova            m1,  m_dith
546 %endif ; x86-32/64
547 %else ; %2 == 9/10/16
548     mova            m1, [yuv2yuvX_%2_start]
549     mova            m2,  m1
550 %endif ; %2 == 8/9/10/16
551     movsx     cntr_reg,  r1m
552 .filterloop_ %+ %%i:
553     ; input pixels
554     mov             r6, [r2+gprsize*cntr_reg-2*gprsize]
555 %if %2 == 16
556     mova            m3, [r6+r5*4]
557     mova            m5, [r6+r5*4+mmsize]
558 %else ; %2 == 8/9/10
559     mova            m3, [r6+r5*2]
560 %endif ; %2 == 8/9/10/16
561     mov             r6, [r2+gprsize*cntr_reg-gprsize]
562 %if %2 == 16
563     mova            m4, [r6+r5*4]
564     mova            m6, [r6+r5*4+mmsize]
565 %else ; %2 == 8/9/10
566     mova            m4, [r6+r5*2]
567 %endif ; %2 == 8/9/10/16
568
569     ; coefficients
570     movd            m0, [r0+2*cntr_reg-4]; coeff[0], coeff[1]
571 %if %2 == 16
572     pshuflw         m7,  m0,  0          ; coeff[0]
573     pshuflw         m0,  m0,  0x55       ; coeff[1]
574     pmovsxwd        m7,  m7              ; word -> dword
575     pmovsxwd        m0,  m0              ; word -> dword
576
577     pmulld          m3,  m7
578     pmulld          m5,  m7
579     pmulld          m4,  m0
580     pmulld          m6,  m0
581
582     paddd           m2,  m3
583     paddd           m1,  m5
584     paddd           m2,  m4
585     paddd           m1,  m6
586 %else ; %2 == 10/9/8
587     punpcklwd       m5,  m3,  m4
588     punpckhwd       m3,  m4
589     SPLATD          m0,  m0
590
591     pmaddwd         m5,  m0
592     pmaddwd         m3,  m0
593
594     paddd           m2,  m5
595     paddd           m1,  m3
596 %endif ; %2 == 8/9/10/16
597
598     sub       cntr_reg,  2
599     jg .filterloop_ %+ %%i
600
601 %if %2 == 16
602     psrad           m2,  31 - %2
603     psrad           m1,  31 - %2
604 %else ; %2 == 10/9/8
605     psrad           m2,  27 - %2
606     psrad           m1,  27 - %2
607 %endif ; %2 == 8/9/10/16
608
609 %if %2 == 8
610     packssdw        m2,  m1
611     packuswb        m2,  m2
612     movh     [r3+r5*1],  m2
613 %else ; %2 == 9/10/16
614 %if %2 == 16
615     packssdw        m2,  m1
616     paddw           m2, [minshort]
617 %else ; %2 == 9/10
618 %ifidn %1, sse4
619     packusdw        m2,  m1
620 %elifidn %1, avx
621     packusdw        m2,  m1
622 %else ; mmx2/sse2
623     packssdw        m2,  m1
624     pmaxsw          m2,  m6
625 %endif ; mmx2/sse2/sse4/avx
626     pminsw          m2, [yuv2yuvX_%2_upper]
627 %endif ; %2 == 9/10/16
628     mova     [r3+r5*2],  m2
629 %endif ; %2 == 8/9/10/16
630
631     add             r5,  mmsize/2
632     sub             r4d, mmsize/2
633 %if %2 == 8
634 %assign %%i %%i+2
635 %endrep
636 %endif ; %2 == 8
637     jg .pixelloop
638
639 %if %2 == 8
640 %ifdef ARCH_X86_32
641     ADD             rsp, pad
642     RET
643 %else ; x86-64
644     REP_RET
645 %endif ; x86-32/64
646 %else ; %2 == 9/10/16
647     REP_RET
648 %endif ; %2 == 8/9/10/16
649 %endmacro
650
651 %define PALIGNR PALIGNR_MMX
652 %ifdef ARCH_X86_32
653 INIT_MMX
654 yuv2planeX_fn mmx2,  8,  0, 7
655 yuv2planeX_fn mmx2,  9,  0, 5
656 yuv2planeX_fn mmx2, 10,  0, 5
657 %endif
658
659 INIT_XMM
660 yuv2planeX_fn sse2,  8, 10, 7
661 yuv2planeX_fn sse2,  9,  7, 5
662 yuv2planeX_fn sse2, 10,  7, 5
663
664 %define PALIGNR PALIGNR_SSSE3
665 yuv2planeX_fn sse4,  8, 10, 7
666 yuv2planeX_fn sse4,  9,  7, 5
667 yuv2planeX_fn sse4, 10,  7, 5
668 yuv2planeX_fn sse4, 16,  8, 5
669
670 INIT_AVX
671 yuv2planeX_fn avx,   8, 10, 7
672 yuv2planeX_fn avx,   9,  7, 5
673 yuv2planeX_fn avx,  10,  7, 5
674
675 ; %1=outout-bpc, %2=alignment (u/a)
676 %macro yuv2plane1_mainloop 2
677 .loop_%2:
678 %if %1 == 8
679     paddsw          m0, m2, [r0+r2*2+mmsize*0]
680     paddsw          m1, m3, [r0+r2*2+mmsize*1]
681     psraw           m0, 7
682     psraw           m1, 7
683     packuswb        m0, m1
684     mov%2      [r1+r2], m0
685 %elif %1 == 16
686     paddd           m0, m4, [r0+r2*4+mmsize*0]
687     paddd           m1, m4, [r0+r2*4+mmsize*1]
688     paddd           m2, m4, [r0+r2*4+mmsize*2]
689     paddd           m3, m4, [r0+r2*4+mmsize*3]
690     psrad           m0, 3
691     psrad           m1, 3
692     psrad           m2, 3
693     psrad           m3, 3
694 %if cpuflag(sse4) ; avx/sse4
695     packusdw        m0, m1
696     packusdw        m2, m3
697 %else ; mmx/sse2
698     packssdw        m0, m1
699     packssdw        m2, m3
700     paddw           m0, m5
701     paddw           m2, m5
702 %endif ; mmx/sse2/sse4/avx
703     mov%2    [r1+r2*2], m0
704     mov%2    [r1+r2*2+mmsize], m2
705 %else
706     paddsw          m0, m2, [r0+r2*2+mmsize*0]
707     paddsw          m1, m2, [r0+r2*2+mmsize*1]
708     psraw           m0, 15 - %1
709     psraw           m1, 15 - %1
710     pmaxsw          m0, m4
711     pmaxsw          m1, m4
712     pminsw          m0, m3
713     pminsw          m1, m3
714     mov%2    [r1+r2*2], m0
715     mov%2    [r1+r2*2+mmsize], m1
716 %endif
717     add             r2, mmsize
718     jl .loop_%2
719 %endmacro
720
721 %macro yuv2plane1_fn 3
722 cglobal yuv2plane1_%1, %3, %3, %2
723     add             r2, mmsize - 1
724     and             r2, ~(mmsize - 1)
725 %if %1 == 8
726     add             r1, r2
727 %else ; %1 != 8
728     lea             r1, [r1+r2*2]
729 %endif ; %1 == 8
730 %if %1 == 16
731     lea             r0, [r0+r2*4]
732 %else ; %1 != 16
733     lea             r0, [r0+r2*2]
734 %endif ; %1 == 16
735     neg             r2
736
737 %if %1 == 8
738     pxor            m4, m4               ; zero
739
740     ; create registers holding dither
741     movq            m3, [r3]             ; dither
742     test           r4d, r4d
743     jz              .no_rot
744 %if mmsize == 16
745     punpcklqdq      m3, m3
746 %endif ; mmsize == 16
747     PALIGNR_MMX     m3, m3, 3, m2
748 .no_rot:
749 %if mmsize == 8
750     mova            m2, m3
751     punpckhbw       m3, m4               ; byte->word
752     punpcklbw       m2, m4               ; byte->word
753 %else
754     punpcklbw       m3, m4
755     mova            m2, m3
756 %endif
757 %elif %1 == 9
758     pxor            m4, m4
759     mova            m3, [pw_512]
760     mova            m2, [pw_32]
761 %elif %1 == 10
762     pxor            m4, m4
763     mova            m3, [pw_1024]
764     mova            m2, [pw_16]
765 %else ; %1 == 16
766 %if cpuflag(sse4) ; sse4/avx
767     mova            m4, [pd_4]
768 %else ; mmx/sse2
769     mova            m4, [pd_4min0x40000]
770     mova            m5, [minshort]
771 %endif ; mmx/sse2/sse4/avx
772 %endif ; %1 == ..
773
774     ; actual pixel scaling
775 %if mmsize == 8
776     yuv2plane1_mainloop %1, a
777 %else ; mmsize == 16
778     test            r1, 15
779     jnz .unaligned
780     yuv2plane1_mainloop %1, a
781     REP_RET
782 .unaligned:
783     yuv2plane1_mainloop %1, u
784 %endif ; mmsize == 8/16
785     REP_RET
786 %endmacro
787
788 %ifdef ARCH_X86_32
789 INIT_MMX mmx
790 yuv2plane1_fn  8, 0, 5
791 yuv2plane1_fn 16, 0, 3
792
793 INIT_MMX mmx2
794 yuv2plane1_fn  9, 0, 3
795 yuv2plane1_fn 10, 0, 3
796 %endif
797
798 INIT_XMM sse2
799 yuv2plane1_fn  8, 5, 5
800 yuv2plane1_fn  9, 5, 3
801 yuv2plane1_fn 10, 5, 3
802 yuv2plane1_fn 16, 6, 3
803
804 INIT_XMM sse4
805 yuv2plane1_fn 16, 5, 3
806
807 INIT_XMM avx
808 yuv2plane1_fn  8, 5, 5
809 yuv2plane1_fn  9, 5, 3
810 yuv2plane1_fn 10, 5, 3
811 yuv2plane1_fn 16, 5, 3