swscale: Mark yuv2planeX_8_mmx as MMX2; it contains MMX2 instructions.
[ffmpeg.git] / 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 16, 15, %1, %4
427 %endif ; !sse4
428 SCALE_FUNCS  8, 19, %1, %2
429 SCALE_FUNCS  9, 19, %1, %3
430 SCALE_FUNCS 10, 19, %1, %3
431 SCALE_FUNCS 16, 19, %1, %4
432 %endmacro
433
434 %ifdef ARCH_X86_32
435 INIT_MMX
436 SCALE_FUNCS2 mmx,   0, 0, 0
437 %endif
438 INIT_XMM
439 SCALE_FUNCS2 sse2,  6, 7, 8
440 SCALE_FUNCS2 ssse3, 6, 6, 8
441 SCALE_FUNCS2 sse4,  6, 6, 8
442
443 ;-----------------------------------------------------------------------------
444 ; vertical line scaling
445 ;
446 ; void yuv2plane1_<output_size>_<opt>(const int16_t *src, uint8_t *dst, int dstW,
447 ;                                     const uint8_t *dither, int offset)
448 ; and
449 ; void yuv2planeX_<output_size>_<opt>(const int16_t *filter, int filterSize,
450 ;                                     const int16_t **src, uint8_t *dst, int dstW,
451 ;                                     const uint8_t *dither, int offset)
452 ;
453 ; Scale one or $filterSize lines of source data to generate one line of output
454 ; data. The input is 15-bit in int16_t if $output_size is [8,10] and 19-bit in
455 ; int32_t if $output_size is 16. $filter is 12-bits. $filterSize is a multiple
456 ; of 2. $offset is either 0 or 3. $dither holds 8 values.
457 ;-----------------------------------------------------------------------------
458
459 %macro yuv2planeX_fn 4
460
461 %ifdef ARCH_X86_32
462 %define cntr_reg r1
463 %define movsx mov
464 %else
465 %define cntr_reg r11
466 %define movsx movsxd
467 %endif
468
469 cglobal yuv2planeX_%2_%1, %4, 7, %3
470 %if %2 == 8 || %2 == 9 || %2 == 10
471     pxor            m6,  m6
472 %endif ; %2 == 8/9/10
473
474 %if %2 == 8
475 %ifdef ARCH_X86_32
476 %assign pad 0x2c - (stack_offset & 15)
477     SUB             rsp, pad
478 %define m_dith m7
479 %else ; x86-64
480 %define m_dith m9
481 %endif ; x86-32
482
483     ; create registers holding dither
484     movq        m_dith, [r5]             ; dither
485     test            r6d, r6d
486     jz              .no_rot
487 %if mmsize == 16
488     punpcklqdq  m_dith,  m_dith
489 %endif ; mmsize == 16
490     PALIGNR     m_dith,  m_dith,  3,  m0
491 .no_rot:
492 %if mmsize == 16
493     punpcklbw   m_dith,  m6
494 %ifdef ARCH_X86_64
495     punpcklwd       m8,  m_dith,  m6
496     pslld           m8,  12
497 %else ; x86-32
498     punpcklwd       m5,  m_dith,  m6
499     pslld           m5,  12
500 %endif ; x86-32/64
501     punpckhwd   m_dith,  m6
502     pslld       m_dith,  12
503 %ifdef ARCH_X86_32
504     mova      [rsp+ 0],  m5
505     mova      [rsp+16],  m_dith
506 %endif
507 %else ; mmsize == 8
508     punpcklbw       m5,  m_dith,  m6
509     punpckhbw   m_dith,  m6
510     punpcklwd       m4,  m5,  m6
511     punpckhwd       m5,  m6
512     punpcklwd       m3,  m_dith,  m6
513     punpckhwd   m_dith,  m6
514     pslld           m4,  12
515     pslld           m5,  12
516     pslld           m3,  12
517     pslld       m_dith,  12
518     mova      [rsp+ 0],  m4
519     mova      [rsp+ 8],  m5
520     mova      [rsp+16],  m3
521     mova      [rsp+24],  m_dith
522 %endif ; mmsize == 8/16
523 %endif ; %2 == 8
524
525     xor             r5,  r5
526
527 .pixelloop:
528 %assign %%i 0
529     ; the rep here is for the 8bit output mmx case, where dither covers
530     ; 8 pixels but we can only handle 2 pixels per register, and thus 4
531     ; pixels per iteration. In order to not have to keep track of where
532     ; we are w.r.t. dithering, we unroll the mmx/8bit loop x2.
533 %if %2 == 8
534 %rep 16/mmsize
535 %endif ; %2 == 8
536
537 %if %2 == 8
538 %ifdef ARCH_X86_32
539     mova            m2, [rsp+mmsize*(0+%%i)]
540     mova            m1, [rsp+mmsize*(1+%%i)]
541 %else ; x86-64
542     mova            m2,  m8
543     mova            m1,  m_dith
544 %endif ; x86-32/64
545 %else ; %2 == 9/10/16
546     mova            m1, [yuv2yuvX_%2_start]
547     mova            m2,  m1
548 %endif ; %2 == 8/9/10/16
549     movsx     cntr_reg,  r1m
550 .filterloop_ %+ %%i:
551     ; input pixels
552     mov             r6, [r2+gprsize*cntr_reg-2*gprsize]
553 %if %2 == 16
554     mova            m3, [r6+r5*4]
555     mova            m5, [r6+r5*4+mmsize]
556 %else ; %2 == 8/9/10
557     mova            m3, [r6+r5*2]
558 %endif ; %2 == 8/9/10/16
559     mov             r6, [r2+gprsize*cntr_reg-gprsize]
560 %if %2 == 16
561     mova            m4, [r6+r5*4]
562     mova            m6, [r6+r5*4+mmsize]
563 %else ; %2 == 8/9/10
564     mova            m4, [r6+r5*2]
565 %endif ; %2 == 8/9/10/16
566
567     ; coefficients
568     movd            m0, [r0+2*cntr_reg-4]; coeff[0], coeff[1]
569 %if %2 == 16
570     pshuflw         m7,  m0,  0          ; coeff[0]
571     pshuflw         m0,  m0,  0x55       ; coeff[1]
572     pmovsxwd        m7,  m7              ; word -> dword
573     pmovsxwd        m0,  m0              ; word -> dword
574
575     pmulld          m3,  m7
576     pmulld          m5,  m7
577     pmulld          m4,  m0
578     pmulld          m6,  m0
579
580     paddd           m2,  m3
581     paddd           m1,  m5
582     paddd           m2,  m4
583     paddd           m1,  m6
584 %else ; %2 == 10/9/8
585     punpcklwd       m5,  m3,  m4
586     punpckhwd       m3,  m4
587     SPLATD          m0,  m0
588
589     pmaddwd         m5,  m0
590     pmaddwd         m3,  m0
591
592     paddd           m2,  m5
593     paddd           m1,  m3
594 %endif ; %2 == 8/9/10/16
595
596     sub       cntr_reg,  2
597     jg .filterloop_ %+ %%i
598
599 %if %2 == 16
600     psrad           m2,  31 - %2
601     psrad           m1,  31 - %2
602 %else ; %2 == 10/9/8
603     psrad           m2,  27 - %2
604     psrad           m1,  27 - %2
605 %endif ; %2 == 8/9/10/16
606
607 %if %2 == 8
608     packssdw        m2,  m1
609     packuswb        m2,  m2
610     movh     [r3+r5*1],  m2
611 %else ; %2 == 9/10/16
612 %if %2 == 16
613     packssdw        m2,  m1
614     paddw           m2, [minshort]
615 %else ; %2 == 9/10
616 %ifidn %1, sse4
617     packusdw        m2,  m1
618 %elifidn %1, avx
619     packusdw        m2,  m1
620 %else ; mmx2/sse2
621     packssdw        m2,  m1
622     pmaxsw          m2,  m6
623 %endif ; mmx2/sse2/sse4/avx
624     pminsw          m2, [yuv2yuvX_%2_upper]
625 %endif ; %2 == 9/10/16
626     mova     [r3+r5*2],  m2
627 %endif ; %2 == 8/9/10/16
628
629     add             r5,  mmsize/2
630     sub             r4d, mmsize/2
631 %if %2 == 8
632 %assign %%i %%i+2
633 %endrep
634 %endif ; %2 == 8
635     jg .pixelloop
636
637 %if %2 == 8
638 %ifdef ARCH_X86_32
639     ADD             rsp, pad
640     RET
641 %else ; x86-64
642     REP_RET
643 %endif ; x86-32/64
644 %else ; %2 == 9/10/16
645     REP_RET
646 %endif ; %2 == 8/9/10/16
647 %endmacro
648
649 %define PALIGNR PALIGNR_MMX
650 %ifdef ARCH_X86_32
651 INIT_MMX
652 yuv2planeX_fn mmx2,  8,  0, 7
653 yuv2planeX_fn mmx2,  9,  0, 5
654 yuv2planeX_fn mmx2, 10,  0, 5
655 %endif
656
657 INIT_XMM
658 yuv2planeX_fn sse2,  8, 10, 7
659 yuv2planeX_fn sse2,  9,  7, 5
660 yuv2planeX_fn sse2, 10,  7, 5
661
662 %define PALIGNR PALIGNR_SSSE3
663 yuv2planeX_fn sse4,  8, 10, 7
664 yuv2planeX_fn sse4,  9,  7, 5
665 yuv2planeX_fn sse4, 10,  7, 5
666 yuv2planeX_fn sse4, 16,  8, 5
667
668 INIT_AVX
669 yuv2planeX_fn avx,   8, 10, 7
670 yuv2planeX_fn avx,   9,  7, 5
671 yuv2planeX_fn avx,  10,  7, 5
672
673 ; %1=outout-bpc, %2=alignment (u/a)
674 %macro yuv2plane1_mainloop 2
675 .loop_%2:
676 %if %1 == 8
677     paddsw          m0, m2, [r0+r2*2+mmsize*0]
678     paddsw          m1, m3, [r0+r2*2+mmsize*1]
679     psraw           m0, 7
680     psraw           m1, 7
681     packuswb        m0, m1
682     mov%2      [r1+r2], m0
683 %elif %1 == 16
684     paddd           m0, m4, [r0+r2*4+mmsize*0]
685     paddd           m1, m4, [r0+r2*4+mmsize*1]
686     paddd           m2, m4, [r0+r2*4+mmsize*2]
687     paddd           m3, m4, [r0+r2*4+mmsize*3]
688     psrad           m0, 3
689     psrad           m1, 3
690     psrad           m2, 3
691     psrad           m3, 3
692 %if cpuflag(sse4) ; avx/sse4
693     packusdw        m0, m1
694     packusdw        m2, m3
695 %else ; mmx/sse2
696     packssdw        m0, m1
697     packssdw        m2, m3
698     paddw           m0, m5
699     paddw           m2, m5
700 %endif ; mmx/sse2/sse4/avx
701     mov%2    [r1+r2*2], m0
702     mov%2    [r1+r2*2+mmsize], m2
703 %else
704     paddsw          m0, m2, [r0+r2*2+mmsize*0]
705     paddsw          m1, m2, [r0+r2*2+mmsize*1]
706     psraw           m0, 15 - %1
707     psraw           m1, 15 - %1
708     pmaxsw          m0, m4
709     pmaxsw          m1, m4
710     pminsw          m0, m3
711     pminsw          m1, m3
712     mov%2    [r1+r2*2], m0
713     mov%2    [r1+r2*2+mmsize], m1
714 %endif
715     add             r2, mmsize
716     jl .loop_%2
717 %endmacro
718
719 %macro yuv2plane1_fn 3
720 cglobal yuv2plane1_%1, %3, %3, %2
721     add             r2, mmsize - 1
722     and             r2, ~(mmsize - 1)
723 %if %1 == 8
724     add             r1, r2
725 %else ; %1 != 8
726     lea             r1, [r1+r2*2]
727 %endif ; %1 == 8
728 %if %1 == 16
729     lea             r0, [r0+r2*4]
730 %else ; %1 != 16
731     lea             r0, [r0+r2*2]
732 %endif ; %1 == 16
733     neg             r2
734
735 %if %1 == 8
736     pxor            m4, m4               ; zero
737
738     ; create registers holding dither
739     movq            m3, [r3]             ; dither
740     test           r4d, r4d
741     jz              .no_rot
742 %if mmsize == 16
743     punpcklqdq      m3, m3
744 %endif ; mmsize == 16
745     PALIGNR_MMX     m3, m3, 3, m2
746 .no_rot:
747 %if mmsize == 8
748     mova            m2, m3
749     punpckhbw       m3, m4               ; byte->word
750     punpcklbw       m2, m4               ; byte->word
751 %else
752     punpcklbw       m3, m4
753     mova            m2, m3
754 %endif
755 %elif %1 == 9
756     pxor            m4, m4
757     mova            m3, [pw_512]
758     mova            m2, [pw_32]
759 %elif %1 == 10
760     pxor            m4, m4
761     mova            m3, [pw_1024]
762     mova            m2, [pw_16]
763 %else ; %1 == 16
764 %if cpuflag(sse4) ; sse4/avx
765     mova            m4, [pd_4]
766 %else ; mmx/sse2
767     mova            m4, [pd_4min0x40000]
768     mova            m5, [minshort]
769 %endif ; mmx/sse2/sse4/avx
770 %endif ; %1 == ..
771
772     ; actual pixel scaling
773 %if mmsize == 8
774     yuv2plane1_mainloop %1, a
775 %else ; mmsize == 16
776     test            r1, 15
777     jnz .unaligned
778     yuv2plane1_mainloop %1, a
779     REP_RET
780 .unaligned:
781     yuv2plane1_mainloop %1, u
782 %endif ; mmsize == 8/16
783     REP_RET
784 %endmacro
785
786 %ifdef ARCH_X86_32
787 INIT_MMX mmx
788 yuv2plane1_fn  8, 0, 5
789 yuv2plane1_fn 16, 0, 3
790
791 INIT_MMX mmx2
792 yuv2plane1_fn  9, 0, 3
793 yuv2plane1_fn 10, 0, 3
794 %endif
795
796 INIT_XMM sse2
797 yuv2plane1_fn  8, 5, 5
798 yuv2plane1_fn  9, 5, 3
799 yuv2plane1_fn 10, 5, 3
800 yuv2plane1_fn 16, 6, 3
801
802 INIT_XMM sse4
803 yuv2plane1_fn 16, 5, 3
804
805 INIT_XMM avx
806 yuv2plane1_fn  8, 5, 5
807 yuv2plane1_fn  9, 5, 3
808 yuv2plane1_fn 10, 5, 3
809 yuv2plane1_fn 16, 5, 3