9570969cea0c6526a9e01504430ba208a0243a32
[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 FFmpeg.
7 ;*
8 ;* FFmpeg 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 ;* FFmpeg 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 FFmpeg; if not, write to the Free Software
20 ;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 ;******************************************************************************
22
23 %include "libavutil/x86/x86util.asm"
24
25 SECTION_RODATA
26
27 minshort:      times 8 dw 0x8000
28 yuv2yuvX_16_start:  times 4 dd 0x4000 - 0x40000000
29 yuv2yuvX_10_start:  times 4 dd 0x10000
30 yuv2yuvX_9_start:   times 4 dd 0x20000
31 yuv2yuvX_10_upper:  times 8 dw 0x3ff
32 yuv2yuvX_9_upper:   times 8 dw 0x1ff
33 pd_4:          times 4 dd 4
34 pd_4min0x40000:times 4 dd 4 - (0x40000)
35 pw_16:         times 8 dw 16
36 pw_32:         times 8 dw 32
37 pw_512:        times 8 dw 512
38 pw_1024:       times 8 dw 1024
39
40 SECTION .text
41
42 ;-----------------------------------------------------------------------------
43 ; vertical line scaling
44 ;
45 ; void yuv2plane1_<output_size>_<opt>(const int16_t *src, uint8_t *dst, int dstW,
46 ;                                     const uint8_t *dither, int offset)
47 ; and
48 ; void yuv2planeX_<output_size>_<opt>(const int16_t *filter, int filterSize,
49 ;                                     const int16_t **src, uint8_t *dst, int dstW,
50 ;                                     const uint8_t *dither, int offset)
51 ;
52 ; Scale one or $filterSize lines of source data to generate one line of output
53 ; data. The input is 15-bit in int16_t if $output_size is [8,10] and 19-bit in
54 ; int32_t if $output_size is 16. $filter is 12-bits. $filterSize is a multiple
55 ; of 2. $offset is either 0 or 3. $dither holds 8 values.
56 ;-----------------------------------------------------------------------------
57 %macro yuv2planeX_mainloop 1
58 .pixelloop:
59 %assign %%i 0
60     ; the rep here is for the 8bit output mmx case, where dither covers
61     ; 8 pixels but we can only handle 2 pixels per register, and thus 4
62     ; pixels per iteration. In order to not have to keep track of where
63     ; we are w.r.t. dithering, we unroll the mmx/8bit loop x2.
64 %if %1 == 8
65 %assign %%repcnt 16/mmsize
66 %else
67 %assign %%repcnt 1
68 %endif
69
70 %rep %%repcnt
71
72 %if %1 == 8
73 %if ARCH_X86_32
74     mova            m2, [rsp+mmsize*(0+%%i)]
75     mova            m1, [rsp+mmsize*(1+%%i)]
76 %else ; x86-64
77     mova            m2,  m8
78     mova            m1,  m_dith
79 %endif ; x86-32/64
80 %else ; %1 == 9/10/16
81     mova            m1, [yuv2yuvX_%1_start]
82     mova            m2,  m1
83 %endif ; %1 == 8/9/10/16
84     movsx     cntr_reg,  fltsizem
85 .filterloop_ %+ %%i:
86     ; input pixels
87     mov             r6, [srcq+gprsize*cntr_reg-2*gprsize]
88 %if %1 == 16
89     mova            m3, [r6+r5*4]
90     mova            m5, [r6+r5*4+mmsize]
91 %else ; %1 == 8/9/10
92     mova            m3, [r6+r5*2]
93 %endif ; %1 == 8/9/10/16
94     mov             r6, [srcq+gprsize*cntr_reg-gprsize]
95 %if %1 == 16
96     mova            m4, [r6+r5*4]
97     mova            m6, [r6+r5*4+mmsize]
98 %else ; %1 == 8/9/10
99     mova            m4, [r6+r5*2]
100 %endif ; %1 == 8/9/10/16
101
102     ; coefficients
103     movd            m0, [filterq+2*cntr_reg-4] ; coeff[0], coeff[1]
104 %if %1 == 16
105     pshuflw         m7,  m0,  0          ; coeff[0]
106     pshuflw         m0,  m0,  0x55       ; coeff[1]
107     pmovsxwd        m7,  m7              ; word -> dword
108     pmovsxwd        m0,  m0              ; word -> dword
109
110     pmulld          m3,  m7
111     pmulld          m5,  m7
112     pmulld          m4,  m0
113     pmulld          m6,  m0
114
115     paddd           m2,  m3
116     paddd           m1,  m5
117     paddd           m2,  m4
118     paddd           m1,  m6
119 %else ; %1 == 10/9/8
120     punpcklwd       m5,  m3,  m4
121     punpckhwd       m3,  m4
122     SPLATD          m0
123
124     pmaddwd         m5,  m0
125     pmaddwd         m3,  m0
126
127     paddd           m2,  m5
128     paddd           m1,  m3
129 %endif ; %1 == 8/9/10/16
130
131     sub       cntr_reg,  2
132     jg .filterloop_ %+ %%i
133
134 %if %1 == 16
135     psrad           m2,  31 - %1
136     psrad           m1,  31 - %1
137 %else ; %1 == 10/9/8
138     psrad           m2,  27 - %1
139     psrad           m1,  27 - %1
140 %endif ; %1 == 8/9/10/16
141
142 %if %1 == 8
143     packssdw        m2,  m1
144     packuswb        m2,  m2
145     movh   [dstq+r5*1],  m2
146 %else ; %1 == 9/10/16
147 %if %1 == 16
148     packssdw        m2,  m1
149     paddw           m2, [minshort]
150 %else ; %1 == 9/10
151 %if cpuflag(sse4)
152     packusdw        m2,  m1
153 %else ; mmxext/sse2
154     packssdw        m2,  m1
155     pmaxsw          m2,  m6
156 %endif ; mmxext/sse2/sse4/avx
157     pminsw          m2, [yuv2yuvX_%1_upper]
158 %endif ; %1 == 9/10/16
159     mova   [dstq+r5*2],  m2
160 %endif ; %1 == 8/9/10/16
161
162     add             r5,  mmsize/2
163     sub             wd,  mmsize/2
164
165 %assign %%i %%i+2
166 %endrep
167     jg .pixelloop
168 %endmacro
169
170 %macro yuv2planeX_fn 3
171
172 %if ARCH_X86_32
173 %define cntr_reg fltsizeq
174 %define movsx mov
175 %else
176 %define cntr_reg r7
177 %define movsx movsxd
178 %endif
179
180 cglobal yuv2planeX_%1, %3, 8, %2, filter, fltsize, src, dst, w, dither, offset
181 %if %1 == 8 || %1 == 9 || %1 == 10
182     pxor            m6,  m6
183 %endif ; %1 == 8/9/10
184
185 %if %1 == 8
186 %if ARCH_X86_32
187 %assign pad 0x2c - (stack_offset & 15)
188     SUB             rsp, pad
189 %define m_dith m7
190 %else ; x86-64
191 %define m_dith m9
192 %endif ; x86-32
193
194     ; create registers holding dither
195     movq        m_dith, [ditherq]        ; dither
196     test        offsetd, offsetd
197     jz              .no_rot
198 %if mmsize == 16
199     punpcklqdq  m_dith,  m_dith
200 %endif ; mmsize == 16
201     PALIGNR     m_dith,  m_dith,  3,  m0
202 .no_rot:
203 %if mmsize == 16
204     punpcklbw   m_dith,  m6
205 %if ARCH_X86_64
206     punpcklwd       m8,  m_dith,  m6
207     pslld           m8,  12
208 %else ; x86-32
209     punpcklwd       m5,  m_dith,  m6
210     pslld           m5,  12
211 %endif ; x86-32/64
212     punpckhwd   m_dith,  m6
213     pslld       m_dith,  12
214 %if ARCH_X86_32
215     mova      [rsp+ 0],  m5
216     mova      [rsp+16],  m_dith
217 %endif
218 %else ; mmsize == 8
219     punpcklbw       m5,  m_dith,  m6
220     punpckhbw   m_dith,  m6
221     punpcklwd       m4,  m5,  m6
222     punpckhwd       m5,  m6
223     punpcklwd       m3,  m_dith,  m6
224     punpckhwd   m_dith,  m6
225     pslld           m4,  12
226     pslld           m5,  12
227     pslld           m3,  12
228     pslld       m_dith,  12
229     mova      [rsp+ 0],  m4
230     mova      [rsp+ 8],  m5
231     mova      [rsp+16],  m3
232     mova      [rsp+24],  m_dith
233 %endif ; mmsize == 8/16
234 %endif ; %1 == 8
235
236     xor             r5,  r5
237
238 yuv2planeX_mainloop %1
239
240 %if %1 == 8
241 %if ARCH_X86_32
242     ADD             rsp, pad
243     RET
244 %else ; x86-64
245     REP_RET
246 %endif ; x86-32/64
247 %else ; %1 == 9/10/16
248     REP_RET
249 %endif ; %1 == 8/9/10/16
250 %endmacro
251
252 %if ARCH_X86_32
253 INIT_MMX mmxext
254 yuv2planeX_fn  8,  0, 7
255 yuv2planeX_fn  9,  0, 5
256 yuv2planeX_fn 10,  0, 5
257 %endif
258
259 INIT_XMM sse2
260 yuv2planeX_fn  8, 10, 7
261 yuv2planeX_fn  9,  7, 5
262 yuv2planeX_fn 10,  7, 5
263
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_EXTERNAL
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         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 mmxext
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_EXTERNAL
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