Merge remote-tracking branch 'qatar/master'
[ffmpeg.git] / libswscale / x86 / output.asm
1 ;******************************************************************************
2 ;* x86-optimized 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 minshort:      times 8 dw 0x8000
29 yuv2yuvX_16_start:  times 4 dd 0x4000 - 0x40000000
30 yuv2yuvX_10_start:  times 4 dd 0x10000
31 yuv2yuvX_9_start:   times 4 dd 0x20000
32 yuv2yuvX_10_upper:  times 8 dw 0x3ff
33 yuv2yuvX_9_upper:   times 8 dw 0x1ff
34 pd_4:          times 4 dd 4
35 pd_4min0x40000:times 4 dd 4 - (0x40000)
36 pw_16:         times 8 dw 16
37 pw_32:         times 8 dw 32
38 pw_512:        times 8 dw 512
39 pw_1024:       times 8 dw 1024
40
41 SECTION .text
42
43 ;-----------------------------------------------------------------------------
44 ; vertical line scaling
45 ;
46 ; void yuv2plane1_<output_size>_<opt>(const int16_t *src, uint8_t *dst, int dstW,
47 ;                                     const uint8_t *dither, int offset)
48 ; and
49 ; void yuv2planeX_<output_size>_<opt>(const int16_t *filter, int filterSize,
50 ;                                     const int16_t **src, uint8_t *dst, int dstW,
51 ;                                     const uint8_t *dither, int offset)
52 ;
53 ; Scale one or $filterSize lines of source data to generate one line of output
54 ; data. The input is 15-bit in int16_t if $output_size is [8,10] and 19-bit in
55 ; int32_t if $output_size is 16. $filter is 12-bits. $filterSize is a multiple
56 ; of 2. $offset is either 0 or 3. $dither holds 8 values.
57 ;-----------------------------------------------------------------------------
58
59 %macro yuv2planeX_fn 3
60
61 %if ARCH_X86_32
62 %define cntr_reg fltsizeq
63 %define movsx mov
64 %else
65 %define cntr_reg r7
66 %define movsx movsxd
67 %endif
68
69 cglobal yuv2planeX_%1, %3, 8, %2, filter, fltsize, src, dst, w, dither, offset
70 %if %1 == 8 || %1 == 9 || %1 == 10
71     pxor            m6,  m6
72 %endif ; %1 == 8/9/10
73
74 %if %1 == 8
75 %if ARCH_X86_32
76 %assign pad 0x2c - (stack_offset & 15)
77     SUB             rsp, pad
78 %define m_dith m7
79 %else ; x86-64
80 %define m_dith m9
81 %endif ; x86-32
82
83     ; create registers holding dither
84     movq        m_dith, [ditherq]        ; dither
85     test        offsetd, offsetd
86     jz              .no_rot
87 %if mmsize == 16
88     punpcklqdq  m_dith,  m_dith
89 %endif ; mmsize == 16
90     PALIGNR     m_dith,  m_dith,  3,  m0
91 .no_rot:
92 %if mmsize == 16
93     punpcklbw   m_dith,  m6
94 %if ARCH_X86_64
95     punpcklwd       m8,  m_dith,  m6
96     pslld           m8,  12
97 %else ; x86-32
98     punpcklwd       m5,  m_dith,  m6
99     pslld           m5,  12
100 %endif ; x86-32/64
101     punpckhwd   m_dith,  m6
102     pslld       m_dith,  12
103 %if ARCH_X86_32
104     mova      [rsp+ 0],  m5
105     mova      [rsp+16],  m_dith
106 %endif
107 %else ; mmsize == 8
108     punpcklbw       m5,  m_dith,  m6
109     punpckhbw   m_dith,  m6
110     punpcklwd       m4,  m5,  m6
111     punpckhwd       m5,  m6
112     punpcklwd       m3,  m_dith,  m6
113     punpckhwd   m_dith,  m6
114     pslld           m4,  12
115     pslld           m5,  12
116     pslld           m3,  12
117     pslld       m_dith,  12
118     mova      [rsp+ 0],  m4
119     mova      [rsp+ 8],  m5
120     mova      [rsp+16],  m3
121     mova      [rsp+24],  m_dith
122 %endif ; mmsize == 8/16
123 %endif ; %1 == 8
124
125     xor             r5,  r5
126
127 .pixelloop:
128 %assign %%i 0
129     ; the rep here is for the 8bit output mmx case, where dither covers
130     ; 8 pixels but we can only handle 2 pixels per register, and thus 4
131     ; pixels per iteration. In order to not have to keep track of where
132     ; we are w.r.t. dithering, we unroll the mmx/8bit loop x2.
133 %if %1 == 8
134 %assign %%repcnt 16/mmsize
135 %else
136 %assign %%repcnt 1
137 %endif
138
139 %rep %%repcnt
140
141 %if %1 == 8
142 %if ARCH_X86_32
143     mova            m2, [rsp+mmsize*(0+%%i)]
144     mova            m1, [rsp+mmsize*(1+%%i)]
145 %else ; x86-64
146     mova            m2,  m8
147     mova            m1,  m_dith
148 %endif ; x86-32/64
149 %else ; %1 == 9/10/16
150     mova            m1, [yuv2yuvX_%1_start]
151     mova            m2,  m1
152 %endif ; %1 == 8/9/10/16
153     movsx     cntr_reg,  fltsizem
154 .filterloop_ %+ %%i:
155     ; input pixels
156     mov             r6, [srcq+gprsize*cntr_reg-2*gprsize]
157 %if %1 == 16
158     mova            m3, [r6+r5*4]
159     mova            m5, [r6+r5*4+mmsize]
160 %else ; %1 == 8/9/10
161     mova            m3, [r6+r5*2]
162 %endif ; %1 == 8/9/10/16
163     mov             r6, [srcq+gprsize*cntr_reg-gprsize]
164 %if %1 == 16
165     mova            m4, [r6+r5*4]
166     mova            m6, [r6+r5*4+mmsize]
167 %else ; %1 == 8/9/10
168     mova            m4, [r6+r5*2]
169 %endif ; %1 == 8/9/10/16
170
171     ; coefficients
172     movd            m0, [filterq+2*cntr_reg-4] ; coeff[0], coeff[1]
173 %if %1 == 16
174     pshuflw         m7,  m0,  0          ; coeff[0]
175     pshuflw         m0,  m0,  0x55       ; coeff[1]
176     pmovsxwd        m7,  m7              ; word -> dword
177     pmovsxwd        m0,  m0              ; word -> dword
178
179     pmulld          m3,  m7
180     pmulld          m5,  m7
181     pmulld          m4,  m0
182     pmulld          m6,  m0
183
184     paddd           m2,  m3
185     paddd           m1,  m5
186     paddd           m2,  m4
187     paddd           m1,  m6
188 %else ; %1 == 10/9/8
189     punpcklwd       m5,  m3,  m4
190     punpckhwd       m3,  m4
191     SPLATD          m0,  m0
192
193     pmaddwd         m5,  m0
194     pmaddwd         m3,  m0
195
196     paddd           m2,  m5
197     paddd           m1,  m3
198 %endif ; %1 == 8/9/10/16
199
200     sub       cntr_reg,  2
201     jg .filterloop_ %+ %%i
202
203 %if %1 == 16
204     psrad           m2,  31 - %1
205     psrad           m1,  31 - %1
206 %else ; %1 == 10/9/8
207     psrad           m2,  27 - %1
208     psrad           m1,  27 - %1
209 %endif ; %1 == 8/9/10/16
210
211 %if %1 == 8
212     packssdw        m2,  m1
213     packuswb        m2,  m2
214     movh   [dstq+r5*1],  m2
215 %else ; %1 == 9/10/16
216 %if %1 == 16
217     packssdw        m2,  m1
218     paddw           m2, [minshort]
219 %else ; %1 == 9/10
220 %if cpuflag(sse4)
221     packusdw        m2,  m1
222 %else ; mmx2/sse2
223     packssdw        m2,  m1
224     pmaxsw          m2,  m6
225 %endif ; mmx2/sse2/sse4/avx
226     pminsw          m2, [yuv2yuvX_%1_upper]
227 %endif ; %1 == 9/10/16
228     mova   [dstq+r5*2],  m2
229 %endif ; %1 == 8/9/10/16
230
231     add             r5,  mmsize/2
232     sub             wd,  mmsize/2
233
234 %assign %%i %%i+2
235 %endrep
236     jg .pixelloop
237
238 %if %1 == 8
239 %if ARCH_X86_32
240     ADD             rsp, pad
241     RET
242 %else ; x86-64
243     REP_RET
244 %endif ; x86-32/64
245 %else ; %1 == 9/10/16
246     REP_RET
247 %endif ; %1 == 8/9/10/16
248 %endmacro
249
250 %define PALIGNR PALIGNR_MMX
251 %if ARCH_X86_32
252 INIT_MMX mmx2
253 yuv2planeX_fn  8,  0, 7
254 yuv2planeX_fn  9,  0, 5
255 yuv2planeX_fn 10,  0, 5
256 %endif
257
258 INIT_XMM sse2
259 yuv2planeX_fn  8, 10, 7
260 yuv2planeX_fn  9,  7, 5
261 yuv2planeX_fn 10,  7, 5
262
263 %define PALIGNR PALIGNR_SSSE3
264 INIT_XMM sse4
265 yuv2planeX_fn  8, 10, 7
266 yuv2planeX_fn  9,  7, 5
267 yuv2planeX_fn 10,  7, 5
268 yuv2planeX_fn 16,  8, 5
269
270 %if HAVE_AVX
271 INIT_XMM avx
272 yuv2planeX_fn  8, 10, 7
273 yuv2planeX_fn  9,  7, 5
274 yuv2planeX_fn 10,  7, 5
275 %endif
276
277 ; %1=outout-bpc, %2=alignment (u/a)
278 %macro yuv2plane1_mainloop 2
279 .loop_%2:
280 %if %1 == 8
281     paddsw          m0, m2, [srcq+wq*2+mmsize*0]
282     paddsw          m1, m3, [srcq+wq*2+mmsize*1]
283     psraw           m0, 7
284     psraw           m1, 7
285     packuswb        m0, m1
286     mov%2    [dstq+wq], m0
287 %elif %1 == 16
288     paddd           m0, m4, [srcq+wq*4+mmsize*0]
289     paddd           m1, m4, [srcq+wq*4+mmsize*1]
290     paddd           m2, m4, [srcq+wq*4+mmsize*2]
291     paddd           m3, m4, [srcq+wq*4+mmsize*3]
292     psrad           m0, 3
293     psrad           m1, 3
294     psrad           m2, 3
295     psrad           m3, 3
296 %if cpuflag(sse4) ; avx/sse4
297     packusdw        m0, m1
298     packusdw        m2, m3
299 %else ; mmx/sse2
300     packssdw        m0, m1
301     packssdw        m2, m3
302     paddw           m0, m5
303     paddw           m2, m5
304 %endif ; mmx/sse2/sse4/avx
305     mov%2    [dstq+wq*2+mmsize*0], m0
306     mov%2    [dstq+wq*2+mmsize*1], m2
307 %else ; %1 == 9/10
308     paddsw          m0, m2, [srcq+wq*2+mmsize*0]
309     paddsw          m1, m2, [srcq+wq*2+mmsize*1]
310     psraw           m0, 15 - %1
311     psraw           m1, 15 - %1
312     pmaxsw          m0, m4
313     pmaxsw          m1, m4
314     pminsw          m0, m3
315     pminsw          m1, m3
316     mov%2    [dstq+wq*2+mmsize*0], m0
317     mov%2    [dstq+wq*2+mmsize*1], m1
318 %endif
319     add             wq, mmsize
320     jl .loop_%2
321 %endmacro
322
323 %macro yuv2plane1_fn 3
324 cglobal yuv2plane1_%1, %3, %3, %2, src, dst, w, dither, offset
325     movsxdifnidn    wq, wd
326     add             wq, mmsize - 1
327     and             wq, ~(mmsize - 1)
328 %if %1 == 8
329     add           dstq, wq
330 %else ; %1 != 8
331     lea           dstq, [dstq+wq*2]
332 %endif ; %1 == 8
333 %if %1 == 16
334     lea           srcq, [srcq+wq*4]
335 %else ; %1 != 16
336     lea           srcq, [srcq+wq*2]
337 %endif ; %1 == 16
338     neg             wq
339
340 %if %1 == 8
341     pxor            m4, m4               ; zero
342
343     ; create registers holding dither
344     movq            m3, [ditherq]        ; dither
345     test       offsetd, offsetd
346     jz              .no_rot
347 %if mmsize == 16
348     punpcklqdq      m3, m3
349 %endif ; mmsize == 16
350     PALIGNR_MMX     m3, m3, 3, m2
351 .no_rot:
352 %if mmsize == 8
353     mova            m2, m3
354     punpckhbw       m3, m4               ; byte->word
355     punpcklbw       m2, m4               ; byte->word
356 %else
357     punpcklbw       m3, m4
358     mova            m2, m3
359 %endif
360 %elif %1 == 9
361     pxor            m4, m4
362     mova            m3, [pw_512]
363     mova            m2, [pw_32]
364 %elif %1 == 10
365     pxor            m4, m4
366     mova            m3, [pw_1024]
367     mova            m2, [pw_16]
368 %else ; %1 == 16
369 %if cpuflag(sse4) ; sse4/avx
370     mova            m4, [pd_4]
371 %else ; mmx/sse2
372     mova            m4, [pd_4min0x40000]
373     mova            m5, [minshort]
374 %endif ; mmx/sse2/sse4/avx
375 %endif ; %1 == ..
376
377     ; actual pixel scaling
378 %if mmsize == 8
379     yuv2plane1_mainloop %1, a
380 %else ; mmsize == 16
381     test          dstq, 15
382     jnz .unaligned
383     yuv2plane1_mainloop %1, a
384     REP_RET
385 .unaligned:
386     yuv2plane1_mainloop %1, u
387 %endif ; mmsize == 8/16
388     REP_RET
389 %endmacro
390
391 %if ARCH_X86_32
392 INIT_MMX mmx
393 yuv2plane1_fn  8, 0, 5
394 yuv2plane1_fn 16, 0, 3
395
396 INIT_MMX mmx2
397 yuv2plane1_fn  9, 0, 3
398 yuv2plane1_fn 10, 0, 3
399 %endif
400
401 INIT_XMM sse2
402 yuv2plane1_fn  8, 5, 5
403 yuv2plane1_fn  9, 5, 3
404 yuv2plane1_fn 10, 5, 3
405 yuv2plane1_fn 16, 6, 3
406
407 INIT_XMM sse4
408 yuv2plane1_fn 16, 5, 3
409
410 %if HAVE_AVX
411 INIT_XMM avx
412 yuv2plane1_fn  8, 5, 5
413 yuv2plane1_fn  9, 5, 3
414 yuv2plane1_fn 10, 5, 3
415 yuv2plane1_fn 16, 5, 3
416 %endif