Moves volume icon update in the timer
[vlc.git] / modules / video_chroma / i420_rgb16.c
1 /*****************************************************************************
2  * i420_rgb16.c : YUV to bitmap RGB conversion module for vlc
3  *****************************************************************************
4  * Copyright (C) 2000 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *          Damien Fouilleul <damienf@videolan.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  * 
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28
29 #include <vlc/vlc.h>
30 #include <vlc_vout.h>
31
32 #include "i420_rgb.h"
33 #if defined (MODULE_NAME_IS_i420_rgb)
34 #   include "i420_rgb_c.h"
35 #elif defined (MODULE_NAME_IS_i420_rgb_mmx)
36 #   include "i420_rgb_mmx.h"
37 #elif defined (MODULE_NAME_IS_i420_rgb_sse2)
38 #   include "i420_rgb_mmx.h"
39 #endif
40
41 static void SetOffset( int, int, int, int, vlc_bool_t *,
42                        unsigned int *, int * );
43
44 #if defined (MODULE_NAME_IS_i420_rgb)
45 /*****************************************************************************
46  * I420_RGB16: color YUV 4:2:0 to RGB 16 bpp with dithering
47  *****************************************************************************
48  * Horizontal alignment needed:
49  *  - input: 8 pixels (8 Y bytes, 4 U/V bytes), margins not allowed
50  *  - output: 1 pixel (2 bytes), margins allowed
51  * Vertical alignment needed:
52  *  - input: 2 lines (2 Y lines, 1 U/V line)
53  *  - output: 1 line
54  *****************************************************************************/
55 void E_(I420_RGB16_dither)( vout_thread_t *p_vout, picture_t *p_src,
56                                                       picture_t *p_dest )
57 {
58     /* We got this one from the old arguments */
59     uint16_t *p_pic = (uint16_t*)p_dest->p->p_pixels;
60     uint8_t  *p_y   = p_src->Y_PIXELS;
61     uint8_t  *p_u   = p_src->U_PIXELS;
62     uint8_t  *p_v   = p_src->V_PIXELS;
63
64     vlc_bool_t   b_hscale;                        /* horizontal scaling type */
65     unsigned int i_vscale;                          /* vertical scaling type */
66     unsigned int i_x, i_y;                /* horizontal and vertical indexes */
67     unsigned int i_real_y;                                          /* y % 4 */
68
69     int         i_right_margin;
70     int         i_rewind;
71     int         i_scale_count;                       /* scale modulo counter */
72     int         i_chroma_width = p_vout->render.i_width / 2; /* chroma width */
73     uint16_t *  p_pic_start;       /* beginning of the current line for copy */
74     int         i_uval, i_vval;                           /* U and V samples */
75     int         i_red, i_green, i_blue;          /* U and V modified samples */
76     uint16_t *  p_yuv = p_vout->chroma.p_sys->p_rgb16;
77     uint16_t *  p_ybase;                     /* Y dependant conversion table */
78
79     /* Conversion buffer pointer */
80     uint16_t *  p_buffer_start = (uint16_t*)p_vout->chroma.p_sys->p_buffer;
81     uint16_t *  p_buffer;
82
83     /* Offset array pointer */
84     int *       p_offset_start = p_vout->chroma.p_sys->p_offset;
85     int *       p_offset;
86
87     const int i_source_margin = p_src->p[0].i_pitch
88                                  - p_src->p[0].i_visible_pitch;
89     const int i_source_margin_c = p_src->p[1].i_pitch
90                                  - p_src->p[1].i_visible_pitch;
91
92     /* The dithering matrices */
93     int dither10[4] = {  0x0,  0x8,  0x2,  0xa };
94     int dither11[4] = {  0xc,  0x4,  0xe,  0x6 };
95     int dither12[4] = {  0x3,  0xb,  0x1,  0x9 };
96     int dither13[4] = {  0xf,  0x7,  0xd,  0x5 };
97
98     for(i_x = 0; i_x < 4; i_x++)
99     {
100         dither10[i_x] = dither10[i_x] << (SHIFT - 4 + p_vout->output.i_rrshift);
101         dither11[i_x] = dither11[i_x] << (SHIFT - 4 + p_vout->output.i_rrshift);
102         dither12[i_x] = dither12[i_x] << (SHIFT - 4 + p_vout->output.i_rrshift);
103         dither13[i_x] = dither13[i_x] << (SHIFT - 4 + p_vout->output.i_rrshift);
104     }
105
106     i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch;
107
108     if( p_vout->render.i_width & 7 )
109     {
110         i_rewind = 8 - ( p_vout->render.i_width & 7 );
111     }
112     else
113     {
114         i_rewind = 0;
115     }
116
117     /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
118      * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
119      * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
120     SetOffset( p_vout->render.i_width, p_vout->render.i_height,
121                p_vout->output.i_width, p_vout->output.i_height,
122                &b_hscale, &i_vscale, p_offset_start );
123
124     /*
125      * Perform conversion
126      */
127     i_scale_count = ( i_vscale == 1 ) ?
128                     p_vout->output.i_height : p_vout->render.i_height;
129     for( i_y = 0; i_y < p_vout->render.i_height; i_y++ )
130     {
131         i_real_y = i_y & 0x3;
132         p_pic_start = p_pic;
133         p_buffer = b_hscale ? p_buffer_start : p_pic;
134
135         for ( i_x = p_vout->render.i_width / 8; i_x--; )
136         {
137             int *p_dither = dither10;
138             CONVERT_YUV_PIXEL_DITHER(2);
139             p_dither = dither11;
140             CONVERT_Y_PIXEL_DITHER(2);
141             p_dither = dither12;
142             CONVERT_YUV_PIXEL_DITHER(2);
143             p_dither = dither13;
144             CONVERT_Y_PIXEL_DITHER(2);
145             p_dither = dither10;
146             CONVERT_YUV_PIXEL_DITHER(2);
147             p_dither = dither11;
148             CONVERT_Y_PIXEL_DITHER(2);
149             p_dither = dither12;
150             CONVERT_YUV_PIXEL_DITHER(2);
151             p_dither = dither13;
152             CONVERT_Y_PIXEL_DITHER(2);
153         }
154
155         /* Here we do some unaligned reads and duplicate conversions, but
156          * at least we have all the pixels */
157         if( i_rewind )
158         {
159             int *p_dither = dither10;
160             p_y -= i_rewind;
161             p_u -= i_rewind >> 1;
162             p_v -= i_rewind >> 1;
163             p_buffer -= i_rewind;
164             CONVERT_YUV_PIXEL_DITHER(2);
165             p_dither = dither11;
166             CONVERT_Y_PIXEL_DITHER(2);
167             p_dither = dither12;
168             CONVERT_YUV_PIXEL_DITHER(2);
169             p_dither = dither13;
170             CONVERT_Y_PIXEL_DITHER(2);
171             p_dither = dither10;
172             CONVERT_YUV_PIXEL_DITHER(2);
173             p_dither = dither11;
174             CONVERT_Y_PIXEL_DITHER(2);
175             p_dither = dither12;
176             CONVERT_YUV_PIXEL_DITHER(2);
177             p_dither = dither13;
178             CONVERT_Y_PIXEL_DITHER(2);
179         }
180         SCALE_WIDTH;
181         SCALE_HEIGHT( 420, 2 );
182
183         p_y += i_source_margin;
184         if( i_y % 2 )
185         {
186             p_u += i_source_margin_c;
187             p_v += i_source_margin_c;
188         }
189     }
190 }
191 #endif
192
193 /*****************************************************************************
194  * I420_RGB16: color YUV 4:2:0 to RGB 16 bpp
195  *****************************************************************************
196  * Horizontal alignment needed:
197  *  - input: 8 pixels (8 Y bytes, 4 U/V bytes), margins not allowed
198  *  - output: 1 pixel (2 bytes), margins allowed
199  * Vertical alignment needed:
200  *  - input: 2 lines (2 Y lines, 1 U/V line)
201  *  - output: 1 line
202  *****************************************************************************/
203
204 #if defined (MODULE_NAME_IS_i420_rgb)
205
206 void E_(I420_RGB16)( vout_thread_t *p_vout, picture_t *p_src,
207                                             picture_t *p_dest )
208 {
209     /* We got this one from the old arguments */
210     uint16_t *p_pic = (uint16_t*)p_dest->p->p_pixels;
211     uint8_t  *p_y   = p_src->Y_PIXELS;
212     uint8_t  *p_u   = p_src->U_PIXELS;
213     uint8_t  *p_v   = p_src->V_PIXELS;
214
215     vlc_bool_t  b_hscale;                         /* horizontal scaling type */
216     unsigned int i_vscale;                          /* vertical scaling type */
217     unsigned int i_x, i_y;                /* horizontal and vertical indexes */
218
219     int         i_right_margin;
220     int         i_rewind;
221     int         i_scale_count;                       /* scale modulo counter */
222     int         i_chroma_width = p_vout->render.i_width / 2; /* chroma width */
223     uint16_t *  p_pic_start;       /* beginning of the current line for copy */
224     int         i_uval, i_vval;                           /* U and V samples */
225     int         i_red, i_green, i_blue;          /* U and V modified samples */
226     uint16_t *  p_yuv = p_vout->chroma.p_sys->p_rgb16;
227     uint16_t *  p_ybase;                     /* Y dependant conversion table */
228
229     /* Conversion buffer pointer */
230     uint16_t *  p_buffer_start = (uint16_t*)p_vout->chroma.p_sys->p_buffer;
231     uint16_t *  p_buffer;
232
233     /* Offset array pointer */
234     int *       p_offset_start = p_vout->chroma.p_sys->p_offset;
235     int *       p_offset;
236
237     const int i_source_margin = p_src->p[0].i_pitch
238                                  - p_src->p[0].i_visible_pitch;
239     const int i_source_margin_c = p_src->p[1].i_pitch
240                                  - p_src->p[1].i_visible_pitch;
241
242     i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch;
243
244     if( p_vout->render.i_width & 7 )
245     {
246         i_rewind = 8 - ( p_vout->render.i_width & 7 );
247     }
248     else
249     {
250         i_rewind = 0;
251     }
252
253     /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
254      * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
255      * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
256     SetOffset( p_vout->render.i_width, p_vout->render.i_height,
257                p_vout->output.i_width, p_vout->output.i_height,
258                &b_hscale, &i_vscale, p_offset_start );
259
260     /*
261      * Perform conversion
262      */
263     i_scale_count = ( i_vscale == 1 ) ?
264                     p_vout->output.i_height : p_vout->render.i_height;
265     for( i_y = 0; i_y < p_vout->render.i_height; i_y++ )
266     {
267         p_pic_start = p_pic;
268         p_buffer = b_hscale ? p_buffer_start : p_pic;
269
270         for ( i_x = p_vout->render.i_width / 8; i_x--; )
271         {
272             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
273             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
274             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
275             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
276         }
277
278         /* Here we do some unaligned reads and duplicate conversions, but
279          * at least we have all the pixels */
280         if( i_rewind )
281         {
282             p_y -= i_rewind;
283             p_u -= i_rewind >> 1;
284             p_v -= i_rewind >> 1;
285             p_buffer -= i_rewind;
286
287             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
288             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
289             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
290             CONVERT_YUV_PIXEL(2);  CONVERT_Y_PIXEL(2);
291         }
292         SCALE_WIDTH;
293         SCALE_HEIGHT( 420, 2 );
294
295         p_y += i_source_margin;
296         if( i_y % 2 )
297         {
298             p_u += i_source_margin_c;
299             p_v += i_source_margin_c;
300         }
301     }
302 }
303
304 #else // ! defined (MODULE_NAME_IS_i420_rgb)
305
306 void E_(I420_R5G5B5)( vout_thread_t *p_vout, picture_t *p_src,
307                                             picture_t *p_dest )
308 {
309     /* We got this one from the old arguments */
310     uint16_t *p_pic = (uint16_t*)p_dest->p->p_pixels;
311     uint8_t  *p_y   = p_src->Y_PIXELS;
312     uint8_t  *p_u   = p_src->U_PIXELS;
313     uint8_t  *p_v   = p_src->V_PIXELS;
314
315     vlc_bool_t  b_hscale;                         /* horizontal scaling type */
316     unsigned int i_vscale;                          /* vertical scaling type */
317     unsigned int i_x, i_y;                /* horizontal and vertical indexes */
318
319     int         i_right_margin;
320     int         i_rewind;
321     int         i_scale_count;                       /* scale modulo counter */
322     int         i_chroma_width = p_vout->render.i_width / 2; /* chroma width */
323     uint16_t *  p_pic_start;       /* beginning of the current line for copy */
324
325     /* Conversion buffer pointer */
326     uint16_t *  p_buffer_start = (uint16_t*)p_vout->chroma.p_sys->p_buffer;
327     uint16_t *  p_buffer;
328
329     /* Offset array pointer */
330     int *       p_offset_start = p_vout->chroma.p_sys->p_offset;
331     int *       p_offset;
332
333     const int i_source_margin = p_src->p[0].i_pitch
334                                  - p_src->p[0].i_visible_pitch;
335     const int i_source_margin_c = p_src->p[1].i_pitch
336                                  - p_src->p[1].i_visible_pitch;
337
338     i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch;
339
340     /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
341      * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
342      * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
343     SetOffset( p_vout->render.i_width, p_vout->render.i_height,
344                p_vout->output.i_width, p_vout->output.i_height,
345                &b_hscale, &i_vscale, p_offset_start );
346
347
348     /*
349      * Perform conversion
350      */
351     i_scale_count = ( i_vscale == 1 ) ?
352                     p_vout->output.i_height : p_vout->render.i_height;
353
354 #if defined (MODULE_NAME_IS_i420_rgb_sse2)
355
356     if( p_vout->render.i_width & 15 )
357     {
358         i_rewind = 16 - ( p_vout->render.i_width & 15 );
359     }
360     else
361     {
362         i_rewind = 0;
363     }
364
365     /*
366     ** SSE2 128 bits fetch/store instructions are faster 
367     ** if memory access is 16 bytes aligned
368     */
369
370     p_buffer = b_hscale ? p_buffer_start : p_pic;
371     if( 0 == (15 & (p_src->p[Y_PLANE].i_pitch|
372                     p_dest->p->i_pitch|
373                     ((intptr_t)p_y)|
374                     ((intptr_t)p_buffer))) )
375     {
376         /* use faster SSE2 aligned fetch and store */
377         for( i_y = 0; i_y < p_vout->render.i_height; i_y++ )
378         {
379             p_pic_start = p_pic;
380
381             for ( i_x = p_vout->render.i_width/16; i_x--; )
382             {
383                 SSE2_CALL (
384                     SSE2_INIT_16_ALIGNED
385                     SSE2_YUV_MUL
386                     SSE2_YUV_ADD
387                     SSE2_UNPACK_15_ALIGNED
388                 );
389                 p_y += 16;
390                 p_u += 8;
391                 p_v += 8;
392                 p_buffer += 16;
393             }
394             /* Here we do some unaligned reads and duplicate conversions, but
395              * at least we have all the pixels */
396             if( i_rewind )
397             {
398                 p_y -= i_rewind;
399                 p_u -= i_rewind >> 1;
400                 p_v -= i_rewind >> 1;
401                 p_buffer -= i_rewind;
402
403                 SSE2_CALL (
404                     SSE2_INIT_16_UNALIGNED
405                     SSE2_YUV_MUL
406                     SSE2_YUV_ADD
407                     SSE2_UNPACK_15_UNALIGNED
408                 );
409                 p_y += 16;
410                 p_u += 8;
411                 p_v += 8;
412             }
413             SCALE_WIDTH;
414             SCALE_HEIGHT( 420, 2 );
415
416             p_y += i_source_margin;
417             if( i_y % 2 )
418             {
419                 p_u += i_source_margin_c;
420                 p_v += i_source_margin_c;
421             }
422             p_buffer = b_hscale ? p_buffer_start : p_pic;
423         }
424     }
425     else
426     {
427         /* use slower SSE2 unaligned fetch and store */
428         for( i_y = 0; i_y < p_vout->render.i_height; i_y++ )
429         {
430             p_pic_start = p_pic;
431             p_buffer = b_hscale ? p_buffer_start : p_pic;
432
433             for ( i_x = p_vout->render.i_width/16; i_x--; )
434             {
435                 SSE2_CALL (
436                     SSE2_INIT_16_UNALIGNED
437                     SSE2_YUV_MUL
438                     SSE2_YUV_ADD
439                     SSE2_UNPACK_15_UNALIGNED
440                 );
441                 p_y += 16;
442                 p_u += 8;
443                 p_v += 8;
444                 p_buffer += 16;
445             }
446             /* Here we do some unaligned reads and duplicate conversions, but
447              * at least we have all the pixels */
448             if( i_rewind )
449             {
450                 p_y -= i_rewind;
451                 p_u -= i_rewind >> 1;
452                 p_v -= i_rewind >> 1;
453                 p_buffer -= i_rewind;
454
455                 SSE2_CALL (
456                     SSE2_INIT_16_UNALIGNED
457                     SSE2_YUV_MUL
458                     SSE2_YUV_ADD
459                     SSE2_UNPACK_15_UNALIGNED
460                 );
461                 p_y += 16;
462                 p_u += 8;
463                 p_v += 8;
464             }
465             SCALE_WIDTH;
466             SCALE_HEIGHT( 420, 2 );
467
468             p_y += i_source_margin;
469             if( i_y % 2 )
470             {
471                 p_u += i_source_margin_c;
472                 p_v += i_source_margin_c;
473             }
474             p_buffer = b_hscale ? p_buffer_start : p_pic;
475         }
476     }
477
478     /* make sure all SSE2 stores are visible thereafter */
479     SSE2_END;
480
481 #else // defined (MODULE_NAME_IS_i420_rgb_mmx)
482
483     if( p_vout->render.i_width & 7 )
484     {
485         i_rewind = 8 - ( p_vout->render.i_width & 7 );
486     }
487     else
488     {
489         i_rewind = 0;
490     }
491
492     for( i_y = 0; i_y < p_vout->render.i_height; i_y++ )
493     {
494         p_pic_start = p_pic;
495         p_buffer = b_hscale ? p_buffer_start : p_pic;
496
497         for ( i_x = p_vout->render.i_width / 8; i_x--; )
498         {
499             MMX_CALL (
500                 MMX_INIT_16
501                 MMX_YUV_MUL
502                 MMX_YUV_ADD
503                 MMX_UNPACK_15
504             );
505             p_y += 8;
506             p_u += 4;
507             p_v += 4;
508             p_buffer += 8;
509         }
510
511         /* Here we do some unaligned reads and duplicate conversions, but
512          * at least we have all the pixels */
513         if( i_rewind )
514         {
515             p_y -= i_rewind;
516             p_u -= i_rewind >> 1;
517             p_v -= i_rewind >> 1;
518             p_buffer -= i_rewind;
519
520             MMX_CALL (
521                 MMX_INIT_16
522                 MMX_YUV_MUL
523                 MMX_YUV_ADD
524                 MMX_UNPACK_15
525             );
526             p_y += 8;
527             p_u += 4;
528             p_v += 4;
529             p_buffer += 8;
530         }
531         SCALE_WIDTH;
532         SCALE_HEIGHT( 420, 2 );
533
534         p_y += i_source_margin;
535         if( i_y % 2 )
536         {
537             p_u += i_source_margin_c;
538             p_v += i_source_margin_c;
539         }
540     }
541     /* re-enable FPU registers */
542     MMX_END;
543
544 #endif
545 }
546
547 void E_(I420_R5G6B5)( vout_thread_t *p_vout, picture_t *p_src,
548                                             picture_t *p_dest )
549 {
550     /* We got this one from the old arguments */
551     uint16_t *p_pic = (uint16_t*)p_dest->p->p_pixels;
552     uint8_t  *p_y   = p_src->Y_PIXELS;
553     uint8_t  *p_u   = p_src->U_PIXELS;
554     uint8_t  *p_v   = p_src->V_PIXELS;
555
556     vlc_bool_t  b_hscale;                         /* horizontal scaling type */
557     unsigned int i_vscale;                          /* vertical scaling type */
558     unsigned int i_x, i_y;                /* horizontal and vertical indexes */
559
560     int         i_right_margin;
561     int         i_rewind;
562     int         i_scale_count;                       /* scale modulo counter */
563     int         i_chroma_width = p_vout->render.i_width / 2; /* chroma width */
564     uint16_t *  p_pic_start;       /* beginning of the current line for copy */
565
566     /* Conversion buffer pointer */
567     uint16_t *  p_buffer_start = (uint16_t*)p_vout->chroma.p_sys->p_buffer;
568     uint16_t *  p_buffer;
569
570     /* Offset array pointer */
571     int *       p_offset_start = p_vout->chroma.p_sys->p_offset;
572     int *       p_offset;
573
574     const int i_source_margin = p_src->p[0].i_pitch
575                                  - p_src->p[0].i_visible_pitch;
576     const int i_source_margin_c = p_src->p[1].i_pitch
577                                  - p_src->p[1].i_visible_pitch;
578
579     i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch;
580
581     /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
582      * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
583      * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
584     SetOffset( p_vout->render.i_width, p_vout->render.i_height,
585                p_vout->output.i_width, p_vout->output.i_height,
586                &b_hscale, &i_vscale, p_offset_start );
587
588
589     /*
590      * Perform conversion
591      */
592     i_scale_count = ( i_vscale == 1 ) ?
593                     p_vout->output.i_height : p_vout->render.i_height;
594
595 #if defined (MODULE_NAME_IS_i420_rgb_sse2)
596
597     if( p_vout->render.i_width & 15 )
598     {
599         i_rewind = 16 - ( p_vout->render.i_width & 15 );
600     }
601     else
602     {
603         i_rewind = 0;
604     }
605
606     /*
607     ** SSE2 128 bits fetch/store instructions are faster 
608     ** if memory access is 16 bytes aligned
609     */
610
611     p_buffer = b_hscale ? p_buffer_start : p_pic;
612     if( 0 == (15 & (p_src->p[Y_PLANE].i_pitch|
613                     p_dest->p->i_pitch|
614                     ((intptr_t)p_y)|
615                     ((intptr_t)p_buffer))) )
616     {
617         /* use faster SSE2 aligned fetch and store */
618         for( i_y = 0; i_y < p_vout->render.i_height; i_y++ )
619         {
620             p_pic_start = p_pic;
621
622             for ( i_x = p_vout->render.i_width/16; i_x--; )
623             {
624                 SSE2_CALL (
625                     SSE2_INIT_16_ALIGNED
626                     SSE2_YUV_MUL
627                     SSE2_YUV_ADD
628                     SSE2_UNPACK_16_ALIGNED
629                 );
630                 p_y += 16;
631                 p_u += 8;
632                 p_v += 8;
633                 p_buffer += 16;
634             }
635             /* Here we do some unaligned reads and duplicate conversions, but
636              * at least we have all the pixels */
637             if( i_rewind )
638             {
639                 p_y -= i_rewind;
640                 p_u -= i_rewind >> 1;
641                 p_v -= i_rewind >> 1;
642                 p_buffer -= i_rewind;
643
644                 SSE2_CALL (
645                     SSE2_INIT_16_UNALIGNED
646                     SSE2_YUV_MUL
647                     SSE2_YUV_ADD
648                     SSE2_UNPACK_16_UNALIGNED
649                 );
650                 p_y += 16;
651                 p_u += 8;
652                 p_v += 8;
653             }
654             SCALE_WIDTH;
655             SCALE_HEIGHT( 420, 2 );
656
657             p_y += i_source_margin;
658             if( i_y % 2 )
659             {
660                 p_u += i_source_margin_c;
661                 p_v += i_source_margin_c;
662             }
663             p_buffer = b_hscale ? p_buffer_start : p_pic;
664         }
665     }
666     else
667     {
668         /* use slower SSE2 unaligned fetch and store */
669         for( i_y = 0; i_y < p_vout->render.i_height; i_y++ )
670         {
671             p_pic_start = p_pic;
672             p_buffer = b_hscale ? p_buffer_start : p_pic;
673
674             for ( i_x = p_vout->render.i_width/16; i_x--; )
675             {
676                 SSE2_CALL(
677                     SSE2_INIT_16_UNALIGNED
678                     SSE2_YUV_MUL
679                     SSE2_YUV_ADD
680                     SSE2_UNPACK_16_UNALIGNED
681                 );
682                 p_y += 16;
683                 p_u += 8;
684                 p_v += 8;
685                 p_buffer += 16;
686             }
687             /* Here we do some unaligned reads and duplicate conversions, but
688              * at least we have all the pixels */
689             if( i_rewind )
690             {
691                 p_y -= i_rewind;
692                 p_u -= i_rewind >> 1;
693                 p_v -= i_rewind >> 1;
694                 p_buffer -= i_rewind;
695
696                 SSE2_CALL(
697                     SSE2_INIT_16_UNALIGNED
698                     SSE2_YUV_MUL
699                     SSE2_YUV_ADD
700                     SSE2_UNPACK_16_UNALIGNED
701                 );
702                 p_y += 16;
703                 p_u += 8;
704                 p_v += 8;
705             }
706             SCALE_WIDTH;
707             SCALE_HEIGHT( 420, 2 );
708
709             p_y += i_source_margin;
710             if( i_y % 2 )
711             {
712                 p_u += i_source_margin_c;
713                 p_v += i_source_margin_c;
714             }
715             p_buffer = b_hscale ? p_buffer_start : p_pic;
716         }
717     }
718
719     /* make sure all SSE2 stores are visible thereafter */
720     SSE2_END;
721
722 #else // defined (MODULE_NAME_IS_i420_rgb_mmx)
723
724     if( p_vout->render.i_width & 7 )
725     {
726         i_rewind = 8 - ( p_vout->render.i_width & 7 );
727     }
728     else
729     {
730         i_rewind = 0;
731     }
732
733     for( i_y = 0; i_y < p_vout->render.i_height; i_y++ )
734     {
735         p_pic_start = p_pic;
736         p_buffer = b_hscale ? p_buffer_start : p_pic;
737
738         for ( i_x = p_vout->render.i_width / 8; i_x--; )
739         {
740             MMX_CALL (
741                 MMX_INIT_16
742                 MMX_YUV_MUL
743                 MMX_YUV_ADD
744                 MMX_UNPACK_16
745             );
746             p_y += 8;
747             p_u += 4;
748             p_v += 4;
749             p_buffer += 8;
750         }
751
752         /* Here we do some unaligned reads and duplicate conversions, but
753          * at least we have all the pixels */
754         if( i_rewind )
755         {
756             p_y -= i_rewind;
757             p_u -= i_rewind >> 1;
758             p_v -= i_rewind >> 1;
759             p_buffer -= i_rewind;
760
761             MMX_CALL (
762                 MMX_INIT_16
763                 MMX_YUV_MUL
764                 MMX_YUV_ADD
765                 MMX_UNPACK_16
766             );
767             p_y += 8;
768             p_u += 4;
769             p_v += 4;
770             p_buffer += 8;
771         }
772         SCALE_WIDTH;
773         SCALE_HEIGHT( 420, 2 );
774
775         p_y += i_source_margin;
776         if( i_y % 2 )
777         {
778             p_u += i_source_margin_c;
779             p_v += i_source_margin_c;
780         }
781     }
782     /* re-enable FPU registers */
783     MMX_END;
784
785 #endif
786 }
787
788 #endif
789
790 /*****************************************************************************
791  * I420_RGB32: color YUV 4:2:0 to RGB 32 bpp
792  *****************************************************************************
793  * Horizontal alignment needed:
794  *  - input: 8 pixels (8 Y bytes, 4 U/V bytes), margins not allowed
795  *  - output: 1 pixel (2 bytes), margins allowed
796  * Vertical alignment needed:
797  *  - input: 2 lines (2 Y lines, 1 U/V line)
798  *  - output: 1 line
799  *****************************************************************************/
800
801 #if defined (MODULE_NAME_IS_i420_rgb)
802
803 void E_(I420_RGB32)( vout_thread_t *p_vout, picture_t *p_src,
804                                             picture_t *p_dest )
805 {
806     /* We got this one from the old arguments */
807     uint32_t *p_pic = (uint32_t*)p_dest->p->p_pixels;
808     uint8_t  *p_y   = p_src->Y_PIXELS;
809     uint8_t  *p_u   = p_src->U_PIXELS;
810     uint8_t  *p_v   = p_src->V_PIXELS;
811
812     vlc_bool_t  b_hscale;                         /* horizontal scaling type */
813     unsigned int i_vscale;                          /* vertical scaling type */
814     unsigned int i_x, i_y;                /* horizontal and vertical indexes */
815
816     int         i_right_margin;
817     int         i_rewind;
818     int         i_scale_count;                       /* scale modulo counter */
819     int         i_chroma_width = p_vout->render.i_width / 2; /* chroma width */
820     uint32_t *  p_pic_start;       /* beginning of the current line for copy */
821     int         i_uval, i_vval;                           /* U and V samples */
822     int         i_red, i_green, i_blue;          /* U and V modified samples */
823     uint32_t *  p_yuv = p_vout->chroma.p_sys->p_rgb32;
824     uint32_t *  p_ybase;                     /* Y dependant conversion table */
825
826     /* Conversion buffer pointer */
827     uint32_t *  p_buffer_start = (uint32_t*)p_vout->chroma.p_sys->p_buffer;
828     uint32_t *  p_buffer;
829
830     /* Offset array pointer */
831     int *       p_offset_start = p_vout->chroma.p_sys->p_offset;
832     int *       p_offset;
833
834     const int i_source_margin = p_src->p[0].i_pitch
835                                  - p_src->p[0].i_visible_pitch;
836     const int i_source_margin_c = p_src->p[1].i_pitch
837                                  - p_src->p[1].i_visible_pitch;
838
839     i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch;
840
841     if( p_vout->render.i_width & 7 )
842     {
843         i_rewind = 8 - ( p_vout->render.i_width & 7 );
844     }
845     else
846     {
847         i_rewind = 0;
848     }
849
850     /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
851      * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
852      * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
853     SetOffset( p_vout->render.i_width, p_vout->render.i_height,
854                p_vout->output.i_width, p_vout->output.i_height,
855                &b_hscale, &i_vscale, p_offset_start );
856
857     /*
858      * Perform conversion
859      */
860     i_scale_count = ( i_vscale == 1 ) ?
861                     p_vout->output.i_height : p_vout->render.i_height;
862     for( i_y = 0; i_y < p_vout->render.i_height; i_y++ )
863     {
864         p_pic_start = p_pic;
865         p_buffer = b_hscale ? p_buffer_start : p_pic;
866
867         for ( i_x = p_vout->render.i_width / 8; i_x--; )
868         {
869             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
870             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
871             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
872             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
873         }
874
875         /* Here we do some unaligned reads and duplicate conversions, but
876          * at least we have all the pixels */
877         if( i_rewind )
878         {
879             p_y -= i_rewind;
880             p_u -= i_rewind >> 1;
881             p_v -= i_rewind >> 1;
882             p_buffer -= i_rewind;
883             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
884             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
885             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
886             CONVERT_YUV_PIXEL(4);  CONVERT_Y_PIXEL(4);
887         }
888         SCALE_WIDTH;
889         SCALE_HEIGHT( 420, 4 );
890
891         p_y += i_source_margin;
892         if( i_y % 2 )
893         {
894             p_u += i_source_margin_c;
895             p_v += i_source_margin_c;
896         }
897     }
898 }
899
900 #else // defined (MODULE_NAME_IS_i420_rgb_mmx) || defined (MODULE_NAME_IS_i420_rgb_sse2)
901
902 void E_(I420_A8R8G8B8)( vout_thread_t *p_vout, picture_t *p_src,
903                                             picture_t *p_dest )
904 {
905     /* We got this one from the old arguments */
906     uint32_t *p_pic = (uint32_t*)p_dest->p->p_pixels;
907     uint8_t  *p_y   = p_src->Y_PIXELS;
908     uint8_t  *p_u   = p_src->U_PIXELS;
909     uint8_t  *p_v   = p_src->V_PIXELS;
910
911     vlc_bool_t  b_hscale;                         /* horizontal scaling type */
912     unsigned int i_vscale;                          /* vertical scaling type */
913     unsigned int i_x, i_y;                /* horizontal and vertical indexes */
914
915     int         i_right_margin;
916     int         i_rewind;
917     int         i_scale_count;                       /* scale modulo counter */
918     int         i_chroma_width = p_vout->render.i_width / 2; /* chroma width */
919     uint32_t *  p_pic_start;       /* beginning of the current line for copy */
920     /* Conversion buffer pointer */
921     uint32_t *  p_buffer_start = (uint32_t*)p_vout->chroma.p_sys->p_buffer;
922     uint32_t *  p_buffer;
923
924     /* Offset array pointer */
925     int *       p_offset_start = p_vout->chroma.p_sys->p_offset;
926     int *       p_offset;
927
928     const int i_source_margin = p_src->p[0].i_pitch
929                                  - p_src->p[0].i_visible_pitch;
930     const int i_source_margin_c = p_src->p[1].i_pitch
931                                  - p_src->p[1].i_visible_pitch;
932
933     i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch;
934
935     /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
936      * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
937      * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
938     SetOffset( p_vout->render.i_width, p_vout->render.i_height,
939                p_vout->output.i_width, p_vout->output.i_height,
940                &b_hscale, &i_vscale, p_offset_start );
941
942     /*
943      * Perform conversion
944      */
945     i_scale_count = ( i_vscale == 1 ) ?
946                     p_vout->output.i_height : p_vout->render.i_height;
947
948 #if defined (MODULE_NAME_IS_i420_rgb_sse2)
949
950     if( p_vout->render.i_width & 15 )
951     {
952         i_rewind = 16 - ( p_vout->render.i_width & 15 );
953     }
954     else
955     {
956         i_rewind = 0;
957     }
958
959     /*
960     ** SSE2 128 bits fetch/store instructions are faster 
961     ** if memory access is 16 bytes aligned
962     */
963
964     p_buffer = b_hscale ? p_buffer_start : p_pic;
965     if( 0 == (15 & (p_src->p[Y_PLANE].i_pitch|
966                     p_dest->p->i_pitch|
967                     ((intptr_t)p_y)|
968                     ((intptr_t)p_buffer))) )
969     {
970         /* use faster SSE2 aligned fetch and store */
971         for( i_y = 0; i_y < p_vout->render.i_height; i_y++ )
972         {
973             p_pic_start = p_pic;
974
975             for ( i_x = p_vout->render.i_width / 16; i_x--; )
976             {
977                 SSE2_CALL (
978                     SSE2_INIT_32_ALIGNED
979                     SSE2_YUV_MUL
980                     SSE2_YUV_ADD
981                     SSE2_UNPACK_32_ARGB_ALIGNED
982                 );
983                 p_y += 16;
984                 p_u += 8;
985                 p_v += 8;
986                 p_buffer += 16;
987             }
988
989             /* Here we do some unaligned reads and duplicate conversions, but
990              * at least we have all the pixels */
991             if( i_rewind )
992             {
993                 p_y -= i_rewind;
994                 p_u -= i_rewind >> 1;
995                 p_v -= i_rewind >> 1;
996                 p_buffer -= i_rewind;
997                 SSE2_CALL (
998                     SSE2_INIT_32_UNALIGNED
999                     SSE2_YUV_MUL
1000                     SSE2_YUV_ADD
1001                     SSE2_UNPACK_32_ARGB_UNALIGNED
1002                 );
1003                 p_y += 16;
1004                 p_u += 4;
1005                 p_v += 4;
1006             }
1007             SCALE_WIDTH;
1008             SCALE_HEIGHT( 420, 4 );
1009
1010             p_y += i_source_margin;
1011             if( i_y % 2 )
1012             {
1013                 p_u += i_source_margin_c;
1014                 p_v += i_source_margin_c;
1015             }
1016             p_buffer = b_hscale ? p_buffer_start : p_pic;
1017         }
1018     }
1019     else
1020     {
1021         /* use slower SSE2 unaligned fetch and store */
1022         for( i_y = 0; i_y < p_vout->render.i_height; i_y++ )
1023         {
1024             p_pic_start = p_pic;
1025             p_buffer = b_hscale ? p_buffer_start : p_pic;
1026
1027             for ( i_x = p_vout->render.i_width / 16; i_x--; )
1028             {
1029                 SSE2_CALL (
1030                     SSE2_INIT_32_UNALIGNED
1031                     SSE2_YUV_MUL
1032                     SSE2_YUV_ADD
1033                     SSE2_UNPACK_32_ARGB_UNALIGNED
1034                 );
1035                 p_y += 16;
1036                 p_u += 8;
1037                 p_v += 8;
1038                 p_buffer += 16;
1039             }
1040
1041             /* Here we do some unaligned reads and duplicate conversions, but
1042              * at least we have all the pixels */
1043             if( i_rewind )
1044             {
1045                 p_y -= i_rewind;
1046                 p_u -= i_rewind >> 1;
1047                 p_v -= i_rewind >> 1;
1048                 p_buffer -= i_rewind;
1049                 SSE2_CALL (
1050                     SSE2_INIT_32_UNALIGNED
1051                     SSE2_YUV_MUL
1052                     SSE2_YUV_ADD
1053                     SSE2_UNPACK_32_ARGB_UNALIGNED
1054                 );
1055                 p_y += 16;
1056                 p_u += 8;
1057                 p_v += 8;
1058             }
1059             SCALE_WIDTH;
1060             SCALE_HEIGHT( 420, 4 );
1061
1062             p_y += i_source_margin;
1063             if( i_y % 2 )
1064             {
1065                 p_u += i_source_margin_c;
1066                 p_v += i_source_margin_c;
1067             }
1068             p_buffer = b_hscale ? p_buffer_start : p_pic;
1069         }
1070     }
1071
1072     /* make sure all SSE2 stores are visible thereafter */
1073     SSE2_END;
1074
1075 #else // defined (MODULE_NAME_IS_i420_rgb_mmx)
1076
1077     if( p_vout->render.i_width & 7 )
1078     {
1079         i_rewind = 8 - ( p_vout->render.i_width & 7 );
1080     }
1081     else
1082     {
1083         i_rewind = 0;
1084     }
1085
1086     for( i_y = 0; i_y < p_vout->render.i_height; i_y++ )
1087     {
1088         p_pic_start = p_pic;
1089         p_buffer = b_hscale ? p_buffer_start : p_pic;
1090
1091         for ( i_x = p_vout->render.i_width / 8; i_x--; )
1092         {
1093             MMX_CALL (
1094                 MMX_INIT_32
1095                 MMX_YUV_MUL
1096                 MMX_YUV_ADD
1097                 MMX_UNPACK_32_ARGB
1098             );
1099             p_y += 8;
1100             p_u += 4;
1101             p_v += 4;
1102             p_buffer += 8;
1103         }
1104
1105         /* Here we do some unaligned reads and duplicate conversions, but
1106          * at least we have all the pixels */
1107         if( i_rewind )
1108         {
1109             p_y -= i_rewind;
1110             p_u -= i_rewind >> 1;
1111             p_v -= i_rewind >> 1;
1112             p_buffer -= i_rewind;
1113             MMX_CALL (
1114                 MMX_INIT_32
1115                 MMX_YUV_MUL
1116                 MMX_YUV_ADD
1117                 MMX_UNPACK_32_ARGB
1118             );
1119             p_y += 8;
1120             p_u += 4;
1121             p_v += 4;
1122             p_buffer += 8;
1123         }
1124         SCALE_WIDTH;
1125         SCALE_HEIGHT( 420, 4 );
1126
1127         p_y += i_source_margin;
1128         if( i_y % 2 )
1129         {
1130             p_u += i_source_margin_c;
1131             p_v += i_source_margin_c;
1132         }
1133     }
1134
1135     /* re-enable FPU registers */
1136     MMX_END;
1137
1138 #endif
1139 }
1140
1141 void E_(I420_R8G8B8A8)( vout_thread_t *p_vout, picture_t *p_src,
1142                                             picture_t *p_dest )
1143 {
1144     /* We got this one from the old arguments */
1145     uint32_t *p_pic = (uint32_t*)p_dest->p->p_pixels;
1146     uint8_t  *p_y   = p_src->Y_PIXELS;
1147     uint8_t  *p_u   = p_src->U_PIXELS;
1148     uint8_t  *p_v   = p_src->V_PIXELS;
1149
1150     vlc_bool_t  b_hscale;                         /* horizontal scaling type */
1151     unsigned int i_vscale;                          /* vertical scaling type */
1152     unsigned int i_x, i_y;                /* horizontal and vertical indexes */
1153
1154     int         i_right_margin;
1155     int         i_rewind;
1156     int         i_scale_count;                       /* scale modulo counter */
1157     int         i_chroma_width = p_vout->render.i_width / 2; /* chroma width */
1158     uint32_t *  p_pic_start;       /* beginning of the current line for copy */
1159     /* Conversion buffer pointer */
1160     uint32_t *  p_buffer_start = (uint32_t*)p_vout->chroma.p_sys->p_buffer;
1161     uint32_t *  p_buffer;
1162
1163     /* Offset array pointer */
1164     int *       p_offset_start = p_vout->chroma.p_sys->p_offset;
1165     int *       p_offset;
1166
1167     const int i_source_margin = p_src->p[0].i_pitch
1168                                  - p_src->p[0].i_visible_pitch;
1169     const int i_source_margin_c = p_src->p[1].i_pitch
1170                                  - p_src->p[1].i_visible_pitch;
1171
1172     i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch;
1173
1174     /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
1175      * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
1176      * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
1177     SetOffset( p_vout->render.i_width, p_vout->render.i_height,
1178                p_vout->output.i_width, p_vout->output.i_height,
1179                &b_hscale, &i_vscale, p_offset_start );
1180
1181     /*
1182      * Perform conversion
1183      */
1184     i_scale_count = ( i_vscale == 1 ) ?
1185                     p_vout->output.i_height : p_vout->render.i_height;
1186
1187 #if defined (MODULE_NAME_IS_i420_rgb_sse2)
1188
1189     if( p_vout->render.i_width & 15 )
1190     {
1191         i_rewind = 16 - ( p_vout->render.i_width & 15 );
1192     }
1193     else
1194     {
1195         i_rewind = 0;
1196     }
1197
1198     /*
1199     ** SSE2 128 bits fetch/store instructions are faster 
1200     ** if memory access is 16 bytes aligned
1201     */
1202
1203     p_buffer = b_hscale ? p_buffer_start : p_pic;
1204     if( 0 == (15 & (p_src->p[Y_PLANE].i_pitch|
1205                     p_dest->p->i_pitch|
1206                     ((intptr_t)p_y)|
1207                     ((intptr_t)p_buffer))) )
1208     {
1209         /* use faster SSE2 aligned fetch and store */
1210         for( i_y = 0; i_y < p_vout->render.i_height; i_y++ )
1211         {
1212             p_pic_start = p_pic;
1213
1214             for ( i_x = p_vout->render.i_width / 16; i_x--; )
1215             {
1216                 SSE2_CALL (
1217                     SSE2_INIT_32_ALIGNED
1218                     SSE2_YUV_MUL
1219                     SSE2_YUV_ADD
1220                     SSE2_UNPACK_32_RGBA_ALIGNED
1221                 );
1222                 p_y += 16;
1223                 p_u += 8;
1224                 p_v += 8;
1225                 p_buffer += 16;
1226             }
1227
1228             /* Here we do some unaligned reads and duplicate conversions, but
1229              * at least we have all the pixels */
1230             if( i_rewind )
1231             {
1232                 p_y -= i_rewind;
1233                 p_u -= i_rewind >> 1;
1234                 p_v -= i_rewind >> 1;
1235                 p_buffer -= i_rewind;
1236                 SSE2_CALL (
1237                     SSE2_INIT_32_UNALIGNED
1238                     SSE2_YUV_MUL
1239                     SSE2_YUV_ADD
1240                     SSE2_UNPACK_32_RGBA_UNALIGNED
1241                 );
1242                 p_y += 16;
1243                 p_u += 4;
1244                 p_v += 4;
1245             }
1246             SCALE_WIDTH;
1247             SCALE_HEIGHT( 420, 4 );
1248
1249             p_y += i_source_margin;
1250             if( i_y % 2 )
1251             {
1252                 p_u += i_source_margin_c;
1253                 p_v += i_source_margin_c;
1254             }
1255             p_buffer = b_hscale ? p_buffer_start : p_pic;
1256         }
1257     }
1258     else
1259     {
1260         /* use slower SSE2 unaligned fetch and store */
1261         for( i_y = 0; i_y < p_vout->render.i_height; i_y++ )
1262         {
1263             p_pic_start = p_pic;
1264             p_buffer = b_hscale ? p_buffer_start : p_pic;
1265
1266             for ( i_x = p_vout->render.i_width / 16; i_x--; )
1267             {
1268                 SSE2_CALL (
1269                     SSE2_INIT_32_UNALIGNED
1270                     SSE2_YUV_MUL
1271                     SSE2_YUV_ADD
1272                     SSE2_UNPACK_32_RGBA_UNALIGNED
1273                 );
1274                 p_y += 16;
1275                 p_u += 8;
1276                 p_v += 8;
1277                 p_buffer += 16;
1278             }
1279
1280             /* Here we do some unaligned reads and duplicate conversions, but
1281              * at least we have all the pixels */
1282             if( i_rewind )
1283             {
1284                 p_y -= i_rewind;
1285                 p_u -= i_rewind >> 1;
1286                 p_v -= i_rewind >> 1;
1287                 p_buffer -= i_rewind;
1288                 SSE2_CALL (
1289                     SSE2_INIT_32_UNALIGNED
1290                     SSE2_YUV_MUL
1291                     SSE2_YUV_ADD
1292                     SSE2_UNPACK_32_RGBA_UNALIGNED
1293                 );
1294                 p_y += 16;
1295                 p_u += 8;
1296                 p_v += 8;
1297             }
1298             SCALE_WIDTH;
1299             SCALE_HEIGHT( 420, 4 );
1300
1301             p_y += i_source_margin;
1302             if( i_y % 2 )
1303             {
1304                 p_u += i_source_margin_c;
1305                 p_v += i_source_margin_c;
1306             }
1307             p_buffer = b_hscale ? p_buffer_start : p_pic;
1308         }
1309     }
1310
1311     /* make sure all SSE2 stores are visible thereafter */
1312     SSE2_END;
1313
1314 #else // defined (MODULE_NAME_IS_i420_rgb_mmx)
1315
1316     if( p_vout->render.i_width & 7 )
1317     {
1318         i_rewind = 8 - ( p_vout->render.i_width & 7 );
1319     }
1320     else
1321     {
1322         i_rewind = 0;
1323     }
1324
1325     for( i_y = 0; i_y < p_vout->render.i_height; i_y++ )
1326     {
1327         p_pic_start = p_pic;
1328         p_buffer = b_hscale ? p_buffer_start : p_pic;
1329
1330         for ( i_x = p_vout->render.i_width / 8; i_x--; )
1331         {
1332             MMX_CALL (
1333                 MMX_INIT_32
1334                 MMX_YUV_MUL
1335                 MMX_YUV_ADD
1336                 MMX_UNPACK_32_RGBA
1337             );
1338             p_y += 8;
1339             p_u += 4;
1340             p_v += 4;
1341             p_buffer += 8;
1342         }
1343
1344         /* Here we do some unaligned reads and duplicate conversions, but
1345          * at least we have all the pixels */
1346         if( i_rewind )
1347         {
1348             p_y -= i_rewind;
1349             p_u -= i_rewind >> 1;
1350             p_v -= i_rewind >> 1;
1351             p_buffer -= i_rewind;
1352             MMX_CALL (
1353                 MMX_INIT_32
1354                 MMX_YUV_MUL
1355                 MMX_YUV_ADD
1356                 MMX_UNPACK_32_RGBA
1357             );
1358             p_y += 8;
1359             p_u += 4;
1360             p_v += 4;
1361             p_buffer += 8;
1362         }
1363         SCALE_WIDTH;
1364         SCALE_HEIGHT( 420, 4 );
1365
1366         p_y += i_source_margin;
1367         if( i_y % 2 )
1368         {
1369             p_u += i_source_margin_c;
1370             p_v += i_source_margin_c;
1371         }
1372     }
1373
1374     /* re-enable FPU registers */
1375     MMX_END;
1376
1377 #endif
1378 }
1379
1380 void E_(I420_B8G8R8A8)( vout_thread_t *p_vout, picture_t *p_src,
1381                                             picture_t *p_dest )
1382 {
1383     /* We got this one from the old arguments */
1384     uint32_t *p_pic = (uint32_t*)p_dest->p->p_pixels;
1385     uint8_t  *p_y   = p_src->Y_PIXELS;
1386     uint8_t  *p_u   = p_src->U_PIXELS;
1387     uint8_t  *p_v   = p_src->V_PIXELS;
1388
1389     vlc_bool_t  b_hscale;                         /* horizontal scaling type */
1390     unsigned int i_vscale;                          /* vertical scaling type */
1391     unsigned int i_x, i_y;                /* horizontal and vertical indexes */
1392
1393     int         i_right_margin;
1394     int         i_rewind;
1395     int         i_scale_count;                       /* scale modulo counter */
1396     int         i_chroma_width = p_vout->render.i_width / 2; /* chroma width */
1397     uint32_t *  p_pic_start;       /* beginning of the current line for copy */
1398     /* Conversion buffer pointer */
1399     uint32_t *  p_buffer_start = (uint32_t*)p_vout->chroma.p_sys->p_buffer;
1400     uint32_t *  p_buffer;
1401
1402     /* Offset array pointer */
1403     int *       p_offset_start = p_vout->chroma.p_sys->p_offset;
1404     int *       p_offset;
1405
1406     const int i_source_margin = p_src->p[0].i_pitch
1407                                  - p_src->p[0].i_visible_pitch;
1408     const int i_source_margin_c = p_src->p[1].i_pitch
1409                                  - p_src->p[1].i_visible_pitch;
1410
1411     i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch;
1412
1413     /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
1414      * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
1415      * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
1416     SetOffset( p_vout->render.i_width, p_vout->render.i_height,
1417                p_vout->output.i_width, p_vout->output.i_height,
1418                &b_hscale, &i_vscale, p_offset_start );
1419
1420     /*
1421      * Perform conversion
1422      */
1423     i_scale_count = ( i_vscale == 1 ) ?
1424                     p_vout->output.i_height : p_vout->render.i_height;
1425
1426 #if defined (MODULE_NAME_IS_i420_rgb_sse2)
1427
1428     if( p_vout->render.i_width & 15 )
1429     {
1430         i_rewind = 16 - ( p_vout->render.i_width & 15 );
1431     }
1432     else
1433     {
1434         i_rewind = 0;
1435     }
1436
1437     /*
1438     ** SSE2 128 bits fetch/store instructions are faster 
1439     ** if memory access is 16 bytes aligned
1440     */
1441
1442     p_buffer = b_hscale ? p_buffer_start : p_pic;
1443     if( 0 == (15 & (p_src->p[Y_PLANE].i_pitch|
1444                     p_dest->p->i_pitch|
1445                     ((intptr_t)p_y)|
1446                     ((intptr_t)p_buffer))) )
1447     {
1448         /* use faster SSE2 aligned fetch and store */
1449         for( i_y = 0; i_y < p_vout->render.i_height; i_y++ )
1450         {
1451             p_pic_start = p_pic;
1452
1453             for ( i_x = p_vout->render.i_width / 16; i_x--; )
1454             {
1455                 SSE2_CALL (
1456                     SSE2_INIT_32_ALIGNED
1457                     SSE2_YUV_MUL
1458                     SSE2_YUV_ADD
1459                     SSE2_UNPACK_32_BGRA_ALIGNED
1460                 );
1461                 p_y += 16;
1462                 p_u += 8;
1463                 p_v += 8;
1464                 p_buffer += 16;
1465             }
1466
1467             /* Here we do some unaligned reads and duplicate conversions, but
1468              * at least we have all the pixels */
1469             if( i_rewind )
1470             {
1471                 p_y -= i_rewind;
1472                 p_u -= i_rewind >> 1;
1473                 p_v -= i_rewind >> 1;
1474                 p_buffer -= i_rewind;
1475                 SSE2_CALL (
1476                     SSE2_INIT_32_UNALIGNED
1477                     SSE2_YUV_MUL
1478                     SSE2_YUV_ADD
1479                     SSE2_UNPACK_32_BGRA_UNALIGNED
1480                 );
1481                 p_y += 16;
1482                 p_u += 4;
1483                 p_v += 4;
1484             }
1485             SCALE_WIDTH;
1486             SCALE_HEIGHT( 420, 4 );
1487
1488             p_y += i_source_margin;
1489             if( i_y % 2 )
1490             {
1491                 p_u += i_source_margin_c;
1492                 p_v += i_source_margin_c;
1493             }
1494             p_buffer = b_hscale ? p_buffer_start : p_pic;
1495         }
1496     }
1497     else
1498     {
1499         /* use slower SSE2 unaligned fetch and store */
1500         for( i_y = 0; i_y < p_vout->render.i_height; i_y++ )
1501         {
1502             p_pic_start = p_pic;
1503             p_buffer = b_hscale ? p_buffer_start : p_pic;
1504
1505             for ( i_x = p_vout->render.i_width / 16; i_x--; )
1506             {
1507                 SSE2_CALL (
1508                     SSE2_INIT_32_UNALIGNED
1509                     SSE2_YUV_MUL
1510                     SSE2_YUV_ADD
1511                     SSE2_UNPACK_32_BGRA_UNALIGNED
1512                 );
1513                 p_y += 16;
1514                 p_u += 8;
1515                 p_v += 8;
1516                 p_buffer += 16;
1517             }
1518
1519             /* Here we do some unaligned reads and duplicate conversions, but
1520              * at least we have all the pixels */
1521             if( i_rewind )
1522             {
1523                 p_y -= i_rewind;
1524                 p_u -= i_rewind >> 1;
1525                 p_v -= i_rewind >> 1;
1526                 p_buffer -= i_rewind;
1527                 SSE2_CALL (
1528                     SSE2_INIT_32_UNALIGNED
1529                     SSE2_YUV_MUL
1530                     SSE2_YUV_ADD
1531                     SSE2_UNPACK_32_BGRA_UNALIGNED
1532                 );
1533                 p_y += 16;
1534                 p_u += 8;
1535                 p_v += 8;
1536             }
1537             SCALE_WIDTH;
1538             SCALE_HEIGHT( 420, 4 );
1539
1540             p_y += i_source_margin;
1541             if( i_y % 2 )
1542             {
1543                 p_u += i_source_margin_c;
1544                 p_v += i_source_margin_c;
1545             }
1546             p_buffer = b_hscale ? p_buffer_start : p_pic;
1547         }
1548     }
1549
1550 #else
1551
1552     if( p_vout->render.i_width & 7 )
1553     {
1554         i_rewind = 8 - ( p_vout->render.i_width & 7 );
1555     }
1556     else
1557     {
1558         i_rewind = 0;
1559     }
1560
1561     for( i_y = 0; i_y < p_vout->render.i_height; i_y++ )
1562     {
1563         p_pic_start = p_pic;
1564         p_buffer = b_hscale ? p_buffer_start : p_pic;
1565
1566         for ( i_x = p_vout->render.i_width / 8; i_x--; )
1567         {
1568             MMX_CALL (
1569                 MMX_INIT_32
1570                 MMX_YUV_MUL
1571                 MMX_YUV_ADD
1572                 MMX_UNPACK_32_BGRA
1573             );
1574             p_y += 8;
1575             p_u += 4;
1576             p_v += 4;
1577             p_buffer += 8;
1578         }
1579
1580         /* Here we do some unaligned reads and duplicate conversions, but
1581          * at least we have all the pixels */
1582         if( i_rewind )
1583         {
1584             p_y -= i_rewind;
1585             p_u -= i_rewind >> 1;
1586             p_v -= i_rewind >> 1;
1587             p_buffer -= i_rewind;
1588             MMX_CALL (
1589                 MMX_INIT_32
1590                 MMX_YUV_MUL
1591                 MMX_YUV_ADD
1592                 MMX_UNPACK_32_BGRA
1593             );
1594             p_y += 8;
1595             p_u += 4;
1596             p_v += 4;
1597             p_buffer += 8;
1598         }
1599         SCALE_WIDTH;
1600         SCALE_HEIGHT( 420, 4 );
1601
1602         p_y += i_source_margin;
1603         if( i_y % 2 )
1604         {
1605             p_u += i_source_margin_c;
1606             p_v += i_source_margin_c;
1607         }
1608     }
1609
1610     /* re-enable FPU registers */
1611     MMX_END;
1612
1613 #endif
1614 }
1615
1616 void E_(I420_A8B8G8R8)( vout_thread_t *p_vout, picture_t *p_src,
1617                                             picture_t *p_dest )
1618 {
1619     /* We got this one from the old arguments */
1620     uint32_t *p_pic = (uint32_t*)p_dest->p->p_pixels;
1621     uint8_t  *p_y   = p_src->Y_PIXELS;
1622     uint8_t  *p_u   = p_src->U_PIXELS;
1623     uint8_t  *p_v   = p_src->V_PIXELS;
1624
1625     vlc_bool_t  b_hscale;                         /* horizontal scaling type */
1626     unsigned int i_vscale;                          /* vertical scaling type */
1627     unsigned int i_x, i_y;                /* horizontal and vertical indexes */
1628
1629     int         i_right_margin;
1630     int         i_rewind;
1631     int         i_scale_count;                       /* scale modulo counter */
1632     int         i_chroma_width = p_vout->render.i_width / 2; /* chroma width */
1633     uint32_t *  p_pic_start;       /* beginning of the current line for copy */
1634     /* Conversion buffer pointer */
1635     uint32_t *  p_buffer_start = (uint32_t*)p_vout->chroma.p_sys->p_buffer;
1636     uint32_t *  p_buffer;
1637
1638     /* Offset array pointer */
1639     int *       p_offset_start = p_vout->chroma.p_sys->p_offset;
1640     int *       p_offset;
1641
1642     const int i_source_margin = p_src->p[0].i_pitch
1643                                  - p_src->p[0].i_visible_pitch;
1644     const int i_source_margin_c = p_src->p[1].i_pitch
1645                                  - p_src->p[1].i_visible_pitch;
1646
1647     i_right_margin = p_dest->p->i_pitch - p_dest->p->i_visible_pitch;
1648
1649     /* Rule: when a picture of size (x1,y1) with aspect ratio r1 is rendered
1650      * on a picture of size (x2,y2) with aspect ratio r2, if x1 grows to x1'
1651      * then y1 grows to y1' = x1' * y2/x2 * r2/r1 */
1652     SetOffset( p_vout->render.i_width, p_vout->render.i_height,
1653                p_vout->output.i_width, p_vout->output.i_height,
1654                &b_hscale, &i_vscale, p_offset_start );
1655
1656     /*
1657      * Perform conversion
1658      */
1659     i_scale_count = ( i_vscale == 1 ) ?
1660                     p_vout->output.i_height : p_vout->render.i_height;
1661
1662 #if defined (MODULE_NAME_IS_i420_rgb_sse2)
1663
1664     if( p_vout->render.i_width & 15 )
1665     {
1666         i_rewind = 16 - ( p_vout->render.i_width & 15 );
1667     }
1668     else
1669     {
1670         i_rewind = 0;
1671     }
1672
1673     /*
1674     ** SSE2 128 bits fetch/store instructions are faster 
1675     ** if memory access is 16 bytes aligned
1676     */
1677
1678     p_buffer = b_hscale ? p_buffer_start : p_pic;
1679     if( 0 == (15 & (p_src->p[Y_PLANE].i_pitch|
1680                     p_dest->p->i_pitch|
1681                     ((intptr_t)p_y)|
1682                     ((intptr_t)p_buffer))) )
1683     {
1684         /* use faster SSE2 aligned fetch and store */
1685         for( i_y = 0; i_y < p_vout->render.i_height; i_y++ )
1686         {
1687             p_pic_start = p_pic;
1688
1689             for ( i_x = p_vout->render.i_width / 16; i_x--; )
1690             {
1691                 SSE2_CALL (
1692                     SSE2_INIT_32_ALIGNED
1693                     SSE2_YUV_MUL
1694                     SSE2_YUV_ADD
1695                     SSE2_UNPACK_32_ABGR_ALIGNED
1696                 );
1697                 p_y += 16;
1698                 p_u += 8;
1699                 p_v += 8;
1700                 p_buffer += 16;
1701             }
1702
1703             /* Here we do some unaligned reads and duplicate conversions, but
1704              * at least we have all the pixels */
1705             if( i_rewind )
1706             {
1707                 p_y -= i_rewind;
1708                 p_u -= i_rewind >> 1;
1709                 p_v -= i_rewind >> 1;
1710                 p_buffer -= i_rewind;
1711                 SSE2_CALL (
1712                     SSE2_INIT_32_UNALIGNED
1713                     SSE2_YUV_MUL
1714                     SSE2_YUV_ADD
1715                     SSE2_UNPACK_32_ABGR_UNALIGNED
1716                 );
1717                 p_y += 16;
1718                 p_u += 4;
1719                 p_v += 4;
1720             }
1721             SCALE_WIDTH;
1722             SCALE_HEIGHT( 420, 4 );
1723
1724             p_y += i_source_margin;
1725             if( i_y % 2 )
1726             {
1727                 p_u += i_source_margin_c;
1728                 p_v += i_source_margin_c;
1729             }
1730             p_buffer = b_hscale ? p_buffer_start : p_pic;
1731         }
1732     }
1733     else
1734     {
1735         /* use slower SSE2 unaligned fetch and store */
1736         for( i_y = 0; i_y < p_vout->render.i_height; i_y++ )
1737         {
1738             p_pic_start = p_pic;
1739             p_buffer = b_hscale ? p_buffer_start : p_pic;
1740
1741             for ( i_x = p_vout->render.i_width / 16; i_x--; )
1742             {
1743                 SSE2_CALL (
1744                     SSE2_INIT_32_UNALIGNED
1745                     SSE2_YUV_MUL
1746                     SSE2_YUV_ADD
1747                     SSE2_UNPACK_32_ABGR_UNALIGNED
1748                 );
1749                 p_y += 16;
1750                 p_u += 8;
1751                 p_v += 8;
1752                 p_buffer += 16;
1753             }
1754
1755             /* Here we do some unaligned reads and duplicate conversions, but
1756              * at least we have all the pixels */
1757             if( i_rewind )
1758             {
1759                 p_y -= i_rewind;
1760                 p_u -= i_rewind >> 1;
1761                 p_v -= i_rewind >> 1;
1762                 p_buffer -= i_rewind;
1763                 SSE2_CALL (
1764                     SSE2_INIT_32_UNALIGNED
1765                     SSE2_YUV_MUL
1766                     SSE2_YUV_ADD
1767                     SSE2_UNPACK_32_ABGR_UNALIGNED
1768                 );
1769                 p_y += 16;
1770                 p_u += 8;
1771                 p_v += 8;
1772             }
1773             SCALE_WIDTH;
1774             SCALE_HEIGHT( 420, 4 );
1775
1776             p_y += i_source_margin;
1777             if( i_y % 2 )
1778             {
1779                 p_u += i_source_margin_c;
1780                 p_v += i_source_margin_c;
1781             }
1782             p_buffer = b_hscale ? p_buffer_start : p_pic;
1783         }
1784     }
1785
1786 #else
1787
1788     if( p_vout->render.i_width & 7 )
1789     {
1790         i_rewind = 8 - ( p_vout->render.i_width & 7 );
1791     }
1792     else
1793     {
1794         i_rewind = 0;
1795     }
1796
1797     for( i_y = 0; i_y < p_vout->render.i_height; i_y++ )
1798     {
1799         p_pic_start = p_pic;
1800         p_buffer = b_hscale ? p_buffer_start : p_pic;
1801
1802         for ( i_x = p_vout->render.i_width / 8; i_x--; )
1803         {
1804             MMX_CALL (
1805                 MMX_INIT_32
1806                 MMX_YUV_MUL
1807                 MMX_YUV_ADD
1808                 MMX_UNPACK_32_ABGR
1809             );
1810             p_y += 8;
1811             p_u += 4;
1812             p_v += 4;
1813             p_buffer += 8;
1814         }
1815
1816         /* Here we do some unaligned reads and duplicate conversions, but
1817          * at least we have all the pixels */
1818         if( i_rewind )
1819         {
1820             p_y -= i_rewind;
1821             p_u -= i_rewind >> 1;
1822             p_v -= i_rewind >> 1;
1823             p_buffer -= i_rewind;
1824             MMX_CALL (
1825                 MMX_INIT_32
1826                 MMX_YUV_MUL
1827                 MMX_YUV_ADD
1828                 MMX_UNPACK_32_ABGR
1829             );
1830             p_y += 8;
1831             p_u += 4;
1832             p_v += 4;
1833             p_buffer += 8;
1834         }
1835         SCALE_WIDTH;
1836         SCALE_HEIGHT( 420, 4 );
1837
1838         p_y += i_source_margin;
1839         if( i_y % 2 )
1840         {
1841             p_u += i_source_margin_c;
1842             p_v += i_source_margin_c;
1843         }
1844     }
1845
1846     /* re-enable FPU registers */
1847     MMX_END;
1848
1849 #endif
1850 }
1851
1852 #endif
1853
1854 /* Following functions are local */
1855
1856 /*****************************************************************************
1857  * SetOffset: build offset array for conversion functions
1858  *****************************************************************************
1859  * This function will build an offset array used in later conversion functions.
1860  * It will also set horizontal and vertical scaling indicators.
1861  *****************************************************************************/
1862 static void SetOffset( int i_width, int i_height, int i_pic_width,
1863                        int i_pic_height, vlc_bool_t *pb_hscale,
1864                        unsigned int *pi_vscale, int *p_offset )
1865 {
1866     int i_x;                                    /* x position in destination */
1867     int i_scale_count;                                     /* modulo counter */
1868
1869     /*
1870      * Prepare horizontal offset array
1871      */
1872     if( i_pic_width - i_width == 0 )
1873     {
1874         /* No horizontal scaling: YUV conversion is done directly to picture */
1875         *pb_hscale = 0;
1876     }
1877     else if( i_pic_width - i_width > 0 )
1878     {
1879         /* Prepare scaling array for horizontal extension */
1880         *pb_hscale = 1;
1881         i_scale_count = i_pic_width;
1882         for( i_x = i_width; i_x--; )
1883         {
1884             while( (i_scale_count -= i_width) > 0 )
1885             {
1886                 *p_offset++ = 0;
1887             }
1888             *p_offset++ = 1;
1889             i_scale_count += i_pic_width;
1890         }
1891     }
1892     else /* if( i_pic_width - i_width < 0 ) */
1893     {
1894         /* Prepare scaling array for horizontal reduction */
1895         *pb_hscale = 1;
1896         i_scale_count = i_width;
1897         for( i_x = i_pic_width; i_x--; )
1898         {
1899             *p_offset = 1;
1900             while( (i_scale_count -= i_pic_width) > 0 )
1901             {
1902                 *p_offset += 1;
1903             }
1904             p_offset++;
1905             i_scale_count += i_width;
1906         }
1907     }
1908
1909     /*
1910      * Set vertical scaling indicator
1911      */
1912     if( i_pic_height - i_height == 0 )
1913     {
1914         *pi_vscale = 0;
1915     }
1916     else if( i_pic_height - i_height > 0 )
1917     {
1918         *pi_vscale = 1;
1919     }
1920     else /* if( i_pic_height - i_height < 0 ) */
1921     {
1922         *pi_vscale = -1;
1923     }
1924 }
1925