1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
4 
5   This software is provided 'as-is', without any express or implied
6   warranty.  In no event will the authors be held liable for any damages
7   arising from the use of this software.
8 
9   Permission is granted to anyone to use this software for any purpose,
10   including commercial applications, and to alter it and redistribute it
11   freely, subject to the following restrictions:
12 
13   1. The origin of this software must not be misrepresented; you must not
14      claim that you wrote the original software. If you use this software
15      in a product, an acknowledgment in the product documentation would be
16      appreciated but is not required.
17   2. Altered source versions must be plainly marked as such, and must not be
18      misrepresented as being the original software.
19   3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../SDL_internal.h"
22 
23 /* This is the software implementation of the YUV texture support */
24 
25 /* This code was derived from code carrying the following copyright notices:
26 
27  * Copyright (c) 1995 The Regents of the University of California.
28  * All rights reserved.
29  *
30  * Permission to use, copy, modify, and distribute this software and its
31  * documentation for any purpose, without fee, and without written agreement is
32  * hereby granted, provided that the above copyright notice and the following
33  * two paragraphs appear in all copies of this software.
34  *
35  * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
36  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
37  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
38  * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39  *
40  * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
41  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
42  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
43  * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
44  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
45 
46  * Copyright (c) 1995 Erik Corry
47  * All rights reserved.
48  *
49  * Permission to use, copy, modify, and distribute this software and its
50  * documentation for any purpose, without fee, and without written agreement is
51  * hereby granted, provided that the above copyright notice and the following
52  * two paragraphs appear in all copies of this software.
53  *
54  * IN NO EVENT SHALL ERIK CORRY BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
55  * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF
56  * THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF ERIK CORRY HAS BEEN ADVISED
57  * OF THE POSSIBILITY OF SUCH DAMAGE.
58  *
59  * ERIK CORRY SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
60  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
61  * PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
62  * BASIS, AND ERIK CORRY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
63  * UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
64 
65  * Portions of this software Copyright (c) 1995 Brown University.
66  * All rights reserved.
67  *
68  * Permission to use, copy, modify, and distribute this software and its
69  * documentation for any purpose, without fee, and without written agreement
70  * is hereby granted, provided that the above copyright notice and the
71  * following two paragraphs appear in all copies of this software.
72  *
73  * IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE TO ANY PARTY FOR
74  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
75  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF BROWN
76  * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
77  *
78  * BROWN UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
79  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
80  * PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
81  * BASIS, AND BROWN UNIVERSITY HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
82  * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
83  */
84 
85 #include "SDL_assert.h"
86 #include "SDL_video.h"
87 #include "SDL_cpuinfo.h"
88 #include "SDL_yuv_sw_c.h"
89 
90 
91 /* The colorspace conversion functions */
92 
93 #if (__GNUC__ > 2) && defined(__i386__) && __OPTIMIZE__ && SDL_ASSEMBLY_ROUTINES
94 extern void Color565DitherYV12MMX1X(int *colortab, Uint32 * rgb_2_pix,
95                                     unsigned char *lum, unsigned char *cr,
96                                     unsigned char *cb, unsigned char *out,
97                                     int rows, int cols, int mod);
98 extern void ColorRGBDitherYV12MMX1X(int *colortab, Uint32 * rgb_2_pix,
99                                     unsigned char *lum, unsigned char *cr,
100                                     unsigned char *cb, unsigned char *out,
101                                     int rows, int cols, int mod);
102 #endif
103 
104 static void
Color16DitherYV12Mod1X(int * colortab,Uint32 * rgb_2_pix,unsigned char * lum,unsigned char * cr,unsigned char * cb,unsigned char * out,int rows,int cols,int mod)105 Color16DitherYV12Mod1X(int *colortab, Uint32 * rgb_2_pix,
106                        unsigned char *lum, unsigned char *cr,
107                        unsigned char *cb, unsigned char *out,
108                        int rows, int cols, int mod)
109 {
110     unsigned short *row1;
111     unsigned short *row2;
112     unsigned char *lum2;
113     int x, y;
114     int cr_r;
115     int crb_g;
116     int cb_b;
117     int cols_2 = cols / 2;
118 
119     row1 = (unsigned short *) out;
120     row2 = row1 + cols + mod;
121     lum2 = lum + cols;
122 
123     mod += cols + mod;
124 
125     y = rows / 2;
126     while (y--) {
127         x = cols_2;
128         while (x--) {
129             register int L;
130 
131             cr_r = 0 * 768 + 256 + colortab[*cr + 0 * 256];
132             crb_g = 1 * 768 + 256 + colortab[*cr + 1 * 256]
133                 + colortab[*cb + 2 * 256];
134             cb_b = 2 * 768 + 256 + colortab[*cb + 3 * 256];
135             ++cr;
136             ++cb;
137 
138             L = *lum++;
139             *row1++ = (unsigned short) (rgb_2_pix[L + cr_r] |
140                                         rgb_2_pix[L + crb_g] |
141                                         rgb_2_pix[L + cb_b]);
142 
143             L = *lum++;
144             *row1++ = (unsigned short) (rgb_2_pix[L + cr_r] |
145                                         rgb_2_pix[L + crb_g] |
146                                         rgb_2_pix[L + cb_b]);
147 
148 
149             /* Now, do second row.  */
150 
151             L = *lum2++;
152             *row2++ = (unsigned short) (rgb_2_pix[L + cr_r] |
153                                         rgb_2_pix[L + crb_g] |
154                                         rgb_2_pix[L + cb_b]);
155 
156             L = *lum2++;
157             *row2++ = (unsigned short) (rgb_2_pix[L + cr_r] |
158                                         rgb_2_pix[L + crb_g] |
159                                         rgb_2_pix[L + cb_b]);
160         }
161 
162         /*
163          * These values are at the start of the next line, (due
164          * to the ++'s above),but they need to be at the start
165          * of the line after that.
166          */
167         lum += cols;
168         lum2 += cols;
169         row1 += mod;
170         row2 += mod;
171     }
172 }
173 
174 static void
Color24DitherYV12Mod1X(int * colortab,Uint32 * rgb_2_pix,unsigned char * lum,unsigned char * cr,unsigned char * cb,unsigned char * out,int rows,int cols,int mod)175 Color24DitherYV12Mod1X(int *colortab, Uint32 * rgb_2_pix,
176                        unsigned char *lum, unsigned char *cr,
177                        unsigned char *cb, unsigned char *out,
178                        int rows, int cols, int mod)
179 {
180     unsigned int value;
181     unsigned char *row1;
182     unsigned char *row2;
183     unsigned char *lum2;
184     int x, y;
185     int cr_r;
186     int crb_g;
187     int cb_b;
188     int cols_2 = cols / 2;
189 
190     row1 = out;
191     row2 = row1 + cols * 3 + mod * 3;
192     lum2 = lum + cols;
193 
194     mod += cols + mod;
195     mod *= 3;
196 
197     y = rows / 2;
198     while (y--) {
199         x = cols_2;
200         while (x--) {
201             register int L;
202 
203             cr_r = 0 * 768 + 256 + colortab[*cr + 0 * 256];
204             crb_g = 1 * 768 + 256 + colortab[*cr + 1 * 256]
205                 + colortab[*cb + 2 * 256];
206             cb_b = 2 * 768 + 256 + colortab[*cb + 3 * 256];
207             ++cr;
208             ++cb;
209 
210             L = *lum++;
211             value = (rgb_2_pix[L + cr_r] |
212                      rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
213             *row1++ = (value) & 0xFF;
214             *row1++ = (value >> 8) & 0xFF;
215             *row1++ = (value >> 16) & 0xFF;
216 
217             L = *lum++;
218             value = (rgb_2_pix[L + cr_r] |
219                      rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
220             *row1++ = (value) & 0xFF;
221             *row1++ = (value >> 8) & 0xFF;
222             *row1++ = (value >> 16) & 0xFF;
223 
224 
225             /* Now, do second row.  */
226 
227             L = *lum2++;
228             value = (rgb_2_pix[L + cr_r] |
229                      rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
230             *row2++ = (value) & 0xFF;
231             *row2++ = (value >> 8) & 0xFF;
232             *row2++ = (value >> 16) & 0xFF;
233 
234             L = *lum2++;
235             value = (rgb_2_pix[L + cr_r] |
236                      rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
237             *row2++ = (value) & 0xFF;
238             *row2++ = (value >> 8) & 0xFF;
239             *row2++ = (value >> 16) & 0xFF;
240         }
241 
242         /*
243          * These values are at the start of the next line, (due
244          * to the ++'s above),but they need to be at the start
245          * of the line after that.
246          */
247         lum += cols;
248         lum2 += cols;
249         row1 += mod;
250         row2 += mod;
251     }
252 }
253 
254 static void
Color32DitherYV12Mod1X(int * colortab,Uint32 * rgb_2_pix,unsigned char * lum,unsigned char * cr,unsigned char * cb,unsigned char * out,int rows,int cols,int mod)255 Color32DitherYV12Mod1X(int *colortab, Uint32 * rgb_2_pix,
256                        unsigned char *lum, unsigned char *cr,
257                        unsigned char *cb, unsigned char *out,
258                        int rows, int cols, int mod)
259 {
260     unsigned int *row1;
261     unsigned int *row2;
262     unsigned char *lum2;
263     int x, y;
264     int cr_r;
265     int crb_g;
266     int cb_b;
267     int cols_2 = cols / 2;
268 
269     row1 = (unsigned int *) out;
270     row2 = row1 + cols + mod;
271     lum2 = lum + cols;
272 
273     mod += cols + mod;
274 
275     y = rows / 2;
276     while (y--) {
277         x = cols_2;
278         while (x--) {
279             register int L;
280 
281             cr_r = 0 * 768 + 256 + colortab[*cr + 0 * 256];
282             crb_g = 1 * 768 + 256 + colortab[*cr + 1 * 256]
283                 + colortab[*cb + 2 * 256];
284             cb_b = 2 * 768 + 256 + colortab[*cb + 3 * 256];
285             ++cr;
286             ++cb;
287 
288             L = *lum++;
289             *row1++ = (rgb_2_pix[L + cr_r] |
290                        rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
291 
292             L = *lum++;
293             *row1++ = (rgb_2_pix[L + cr_r] |
294                        rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
295 
296 
297             /* Now, do second row.  */
298 
299             L = *lum2++;
300             *row2++ = (rgb_2_pix[L + cr_r] |
301                        rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
302 
303             L = *lum2++;
304             *row2++ = (rgb_2_pix[L + cr_r] |
305                        rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
306         }
307 
308         /*
309          * These values are at the start of the next line, (due
310          * to the ++'s above),but they need to be at the start
311          * of the line after that.
312          */
313         lum += cols;
314         lum2 += cols;
315         row1 += mod;
316         row2 += mod;
317     }
318 }
319 
320 /*
321  * In this function I make use of a nasty trick. The tables have the lower
322  * 16 bits replicated in the upper 16. This means I can write ints and get
323  * the horisontal doubling for free (almost).
324  */
325 static void
Color16DitherYV12Mod2X(int * colortab,Uint32 * rgb_2_pix,unsigned char * lum,unsigned char * cr,unsigned char * cb,unsigned char * out,int rows,int cols,int mod)326 Color16DitherYV12Mod2X(int *colortab, Uint32 * rgb_2_pix,
327                        unsigned char *lum, unsigned char *cr,
328                        unsigned char *cb, unsigned char *out,
329                        int rows, int cols, int mod)
330 {
331     unsigned int *row1 = (unsigned int *) out;
332     const int next_row = cols + (mod / 2);
333     unsigned int *row2 = row1 + 2 * next_row;
334     unsigned char *lum2;
335     int x, y;
336     int cr_r;
337     int crb_g;
338     int cb_b;
339     int cols_2 = cols / 2;
340 
341     lum2 = lum + cols;
342 
343     mod = (next_row * 3) + (mod / 2);
344 
345     y = rows / 2;
346     while (y--) {
347         x = cols_2;
348         while (x--) {
349             register int L;
350 
351             cr_r = 0 * 768 + 256 + colortab[*cr + 0 * 256];
352             crb_g = 1 * 768 + 256 + colortab[*cr + 1 * 256]
353                 + colortab[*cb + 2 * 256];
354             cb_b = 2 * 768 + 256 + colortab[*cb + 3 * 256];
355             ++cr;
356             ++cb;
357 
358             L = *lum++;
359             row1[0] = row1[next_row] = (rgb_2_pix[L + cr_r] |
360                                         rgb_2_pix[L + crb_g] |
361                                         rgb_2_pix[L + cb_b]);
362             row1++;
363 
364             L = *lum++;
365             row1[0] = row1[next_row] = (rgb_2_pix[L + cr_r] |
366                                         rgb_2_pix[L + crb_g] |
367                                         rgb_2_pix[L + cb_b]);
368             row1++;
369 
370 
371             /* Now, do second row. */
372 
373             L = *lum2++;
374             row2[0] = row2[next_row] = (rgb_2_pix[L + cr_r] |
375                                         rgb_2_pix[L + crb_g] |
376                                         rgb_2_pix[L + cb_b]);
377             row2++;
378 
379             L = *lum2++;
380             row2[0] = row2[next_row] = (rgb_2_pix[L + cr_r] |
381                                         rgb_2_pix[L + crb_g] |
382                                         rgb_2_pix[L + cb_b]);
383             row2++;
384         }
385 
386         /*
387          * These values are at the start of the next line, (due
388          * to the ++'s above),but they need to be at the start
389          * of the line after that.
390          */
391         lum += cols;
392         lum2 += cols;
393         row1 += mod;
394         row2 += mod;
395     }
396 }
397 
398 static void
Color24DitherYV12Mod2X(int * colortab,Uint32 * rgb_2_pix,unsigned char * lum,unsigned char * cr,unsigned char * cb,unsigned char * out,int rows,int cols,int mod)399 Color24DitherYV12Mod2X(int *colortab, Uint32 * rgb_2_pix,
400                        unsigned char *lum, unsigned char *cr,
401                        unsigned char *cb, unsigned char *out,
402                        int rows, int cols, int mod)
403 {
404     unsigned int value;
405     unsigned char *row1 = out;
406     const int next_row = (cols * 2 + mod) * 3;
407     unsigned char *row2 = row1 + 2 * next_row;
408     unsigned char *lum2;
409     int x, y;
410     int cr_r;
411     int crb_g;
412     int cb_b;
413     int cols_2 = cols / 2;
414 
415     lum2 = lum + cols;
416 
417     mod = next_row * 3 + mod * 3;
418 
419     y = rows / 2;
420     while (y--) {
421         x = cols_2;
422         while (x--) {
423             register int L;
424 
425             cr_r = 0 * 768 + 256 + colortab[*cr + 0 * 256];
426             crb_g = 1 * 768 + 256 + colortab[*cr + 1 * 256]
427                 + colortab[*cb + 2 * 256];
428             cb_b = 2 * 768 + 256 + colortab[*cb + 3 * 256];
429             ++cr;
430             ++cb;
431 
432             L = *lum++;
433             value = (rgb_2_pix[L + cr_r] |
434                      rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
435             row1[0 + 0] = row1[3 + 0] = row1[next_row + 0] =
436                 row1[next_row + 3 + 0] = (value) & 0xFF;
437             row1[0 + 1] = row1[3 + 1] = row1[next_row + 1] =
438                 row1[next_row + 3 + 1] = (value >> 8) & 0xFF;
439             row1[0 + 2] = row1[3 + 2] = row1[next_row + 2] =
440                 row1[next_row + 3 + 2] = (value >> 16) & 0xFF;
441             row1 += 2 * 3;
442 
443             L = *lum++;
444             value = (rgb_2_pix[L + cr_r] |
445                      rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
446             row1[0 + 0] = row1[3 + 0] = row1[next_row + 0] =
447                 row1[next_row + 3 + 0] = (value) & 0xFF;
448             row1[0 + 1] = row1[3 + 1] = row1[next_row + 1] =
449                 row1[next_row + 3 + 1] = (value >> 8) & 0xFF;
450             row1[0 + 2] = row1[3 + 2] = row1[next_row + 2] =
451                 row1[next_row + 3 + 2] = (value >> 16) & 0xFF;
452             row1 += 2 * 3;
453 
454 
455             /* Now, do second row. */
456 
457             L = *lum2++;
458             value = (rgb_2_pix[L + cr_r] |
459                      rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
460             row2[0 + 0] = row2[3 + 0] = row2[next_row + 0] =
461                 row2[next_row + 3 + 0] = (value) & 0xFF;
462             row2[0 + 1] = row2[3 + 1] = row2[next_row + 1] =
463                 row2[next_row + 3 + 1] = (value >> 8) & 0xFF;
464             row2[0 + 2] = row2[3 + 2] = row2[next_row + 2] =
465                 row2[next_row + 3 + 2] = (value >> 16) & 0xFF;
466             row2 += 2 * 3;
467 
468             L = *lum2++;
469             value = (rgb_2_pix[L + cr_r] |
470                      rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
471             row2[0 + 0] = row2[3 + 0] = row2[next_row + 0] =
472                 row2[next_row + 3 + 0] = (value) & 0xFF;
473             row2[0 + 1] = row2[3 + 1] = row2[next_row + 1] =
474                 row2[next_row + 3 + 1] = (value >> 8) & 0xFF;
475             row2[0 + 2] = row2[3 + 2] = row2[next_row + 2] =
476                 row2[next_row + 3 + 2] = (value >> 16) & 0xFF;
477             row2 += 2 * 3;
478         }
479 
480         /*
481          * These values are at the start of the next line, (due
482          * to the ++'s above),but they need to be at the start
483          * of the line after that.
484          */
485         lum += cols;
486         lum2 += cols;
487         row1 += mod;
488         row2 += mod;
489     }
490 }
491 
492 static void
Color32DitherYV12Mod2X(int * colortab,Uint32 * rgb_2_pix,unsigned char * lum,unsigned char * cr,unsigned char * cb,unsigned char * out,int rows,int cols,int mod)493 Color32DitherYV12Mod2X(int *colortab, Uint32 * rgb_2_pix,
494                        unsigned char *lum, unsigned char *cr,
495                        unsigned char *cb, unsigned char *out,
496                        int rows, int cols, int mod)
497 {
498     unsigned int *row1 = (unsigned int *) out;
499     const int next_row = cols * 2 + mod;
500     unsigned int *row2 = row1 + 2 * next_row;
501     unsigned char *lum2;
502     int x, y;
503     int cr_r;
504     int crb_g;
505     int cb_b;
506     int cols_2 = cols / 2;
507 
508     lum2 = lum + cols;
509 
510     mod = (next_row * 3) + mod;
511 
512     y = rows / 2;
513     while (y--) {
514         x = cols_2;
515         while (x--) {
516             register int L;
517 
518             cr_r = 0 * 768 + 256 + colortab[*cr + 0 * 256];
519             crb_g = 1 * 768 + 256 + colortab[*cr + 1 * 256]
520                 + colortab[*cb + 2 * 256];
521             cb_b = 2 * 768 + 256 + colortab[*cb + 3 * 256];
522             ++cr;
523             ++cb;
524 
525             L = *lum++;
526             row1[0] = row1[1] = row1[next_row] = row1[next_row + 1] =
527                 (rgb_2_pix[L + cr_r] |
528                  rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
529             row1 += 2;
530 
531             L = *lum++;
532             row1[0] = row1[1] = row1[next_row] = row1[next_row + 1] =
533                 (rgb_2_pix[L + cr_r] |
534                  rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
535             row1 += 2;
536 
537 
538             /* Now, do second row. */
539 
540             L = *lum2++;
541             row2[0] = row2[1] = row2[next_row] = row2[next_row + 1] =
542                 (rgb_2_pix[L + cr_r] |
543                  rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
544             row2 += 2;
545 
546             L = *lum2++;
547             row2[0] = row2[1] = row2[next_row] = row2[next_row + 1] =
548                 (rgb_2_pix[L + cr_r] |
549                  rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
550             row2 += 2;
551         }
552 
553         /*
554          * These values are at the start of the next line, (due
555          * to the ++'s above),but they need to be at the start
556          * of the line after that.
557          */
558         lum += cols;
559         lum2 += cols;
560         row1 += mod;
561         row2 += mod;
562     }
563 }
564 
565 static void
Color16DitherYUY2Mod1X(int * colortab,Uint32 * rgb_2_pix,unsigned char * lum,unsigned char * cr,unsigned char * cb,unsigned char * out,int rows,int cols,int mod)566 Color16DitherYUY2Mod1X(int *colortab, Uint32 * rgb_2_pix,
567                        unsigned char *lum, unsigned char *cr,
568                        unsigned char *cb, unsigned char *out,
569                        int rows, int cols, int mod)
570 {
571     unsigned short *row;
572     int x, y;
573     int cr_r;
574     int crb_g;
575     int cb_b;
576     int cols_2 = cols / 2;
577 
578     row = (unsigned short *) out;
579 
580     y = rows;
581     while (y--) {
582         x = cols_2;
583         while (x--) {
584             register int L;
585 
586             cr_r = 0 * 768 + 256 + colortab[*cr + 0 * 256];
587             crb_g = 1 * 768 + 256 + colortab[*cr + 1 * 256]
588                 + colortab[*cb + 2 * 256];
589             cb_b = 2 * 768 + 256 + colortab[*cb + 3 * 256];
590             cr += 4;
591             cb += 4;
592 
593             L = *lum;
594             lum += 2;
595             *row++ = (unsigned short) (rgb_2_pix[L + cr_r] |
596                                        rgb_2_pix[L + crb_g] |
597                                        rgb_2_pix[L + cb_b]);
598 
599             L = *lum;
600             lum += 2;
601             *row++ = (unsigned short) (rgb_2_pix[L + cr_r] |
602                                        rgb_2_pix[L + crb_g] |
603                                        rgb_2_pix[L + cb_b]);
604 
605         }
606 
607         row += mod;
608     }
609 }
610 
611 static void
Color24DitherYUY2Mod1X(int * colortab,Uint32 * rgb_2_pix,unsigned char * lum,unsigned char * cr,unsigned char * cb,unsigned char * out,int rows,int cols,int mod)612 Color24DitherYUY2Mod1X(int *colortab, Uint32 * rgb_2_pix,
613                        unsigned char *lum, unsigned char *cr,
614                        unsigned char *cb, unsigned char *out,
615                        int rows, int cols, int mod)
616 {
617     unsigned int value;
618     unsigned char *row;
619     int x, y;
620     int cr_r;
621     int crb_g;
622     int cb_b;
623     int cols_2 = cols / 2;
624 
625     row = (unsigned char *) out;
626     mod *= 3;
627     y = rows;
628     while (y--) {
629         x = cols_2;
630         while (x--) {
631             register int L;
632 
633             cr_r = 0 * 768 + 256 + colortab[*cr + 0 * 256];
634             crb_g = 1 * 768 + 256 + colortab[*cr + 1 * 256]
635                 + colortab[*cb + 2 * 256];
636             cb_b = 2 * 768 + 256 + colortab[*cb + 3 * 256];
637             cr += 4;
638             cb += 4;
639 
640             L = *lum;
641             lum += 2;
642             value = (rgb_2_pix[L + cr_r] |
643                      rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
644             *row++ = (value) & 0xFF;
645             *row++ = (value >> 8) & 0xFF;
646             *row++ = (value >> 16) & 0xFF;
647 
648             L = *lum;
649             lum += 2;
650             value = (rgb_2_pix[L + cr_r] |
651                      rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
652             *row++ = (value) & 0xFF;
653             *row++ = (value >> 8) & 0xFF;
654             *row++ = (value >> 16) & 0xFF;
655 
656         }
657         row += mod;
658     }
659 }
660 
661 static void
Color32DitherYUY2Mod1X(int * colortab,Uint32 * rgb_2_pix,unsigned char * lum,unsigned char * cr,unsigned char * cb,unsigned char * out,int rows,int cols,int mod)662 Color32DitherYUY2Mod1X(int *colortab, Uint32 * rgb_2_pix,
663                        unsigned char *lum, unsigned char *cr,
664                        unsigned char *cb, unsigned char *out,
665                        int rows, int cols, int mod)
666 {
667     unsigned int *row;
668     int x, y;
669     int cr_r;
670     int crb_g;
671     int cb_b;
672     int cols_2 = cols / 2;
673 
674     row = (unsigned int *) out;
675     y = rows;
676     while (y--) {
677         x = cols_2;
678         while (x--) {
679             register int L;
680 
681             cr_r = 0 * 768 + 256 + colortab[*cr + 0 * 256];
682             crb_g = 1 * 768 + 256 + colortab[*cr + 1 * 256]
683                 + colortab[*cb + 2 * 256];
684             cb_b = 2 * 768 + 256 + colortab[*cb + 3 * 256];
685             cr += 4;
686             cb += 4;
687 
688             L = *lum;
689             lum += 2;
690             *row++ = (rgb_2_pix[L + cr_r] |
691                       rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
692 
693             L = *lum;
694             lum += 2;
695             *row++ = (rgb_2_pix[L + cr_r] |
696                       rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
697 
698 
699         }
700         row += mod;
701     }
702 }
703 
704 /*
705  * In this function I make use of a nasty trick. The tables have the lower
706  * 16 bits replicated in the upper 16. This means I can write ints and get
707  * the horisontal doubling for free (almost).
708  */
709 static void
Color16DitherYUY2Mod2X(int * colortab,Uint32 * rgb_2_pix,unsigned char * lum,unsigned char * cr,unsigned char * cb,unsigned char * out,int rows,int cols,int mod)710 Color16DitherYUY2Mod2X(int *colortab, Uint32 * rgb_2_pix,
711                        unsigned char *lum, unsigned char *cr,
712                        unsigned char *cb, unsigned char *out,
713                        int rows, int cols, int mod)
714 {
715     unsigned int *row = (unsigned int *) out;
716     const int next_row = cols + (mod / 2);
717     int x, y;
718     int cr_r;
719     int crb_g;
720     int cb_b;
721     int cols_2 = cols / 2;
722 
723     y = rows;
724     while (y--) {
725         x = cols_2;
726         while (x--) {
727             register int L;
728 
729             cr_r = 0 * 768 + 256 + colortab[*cr + 0 * 256];
730             crb_g = 1 * 768 + 256 + colortab[*cr + 1 * 256]
731                 + colortab[*cb + 2 * 256];
732             cb_b = 2 * 768 + 256 + colortab[*cb + 3 * 256];
733             cr += 4;
734             cb += 4;
735 
736             L = *lum;
737             lum += 2;
738             row[0] = row[next_row] = (rgb_2_pix[L + cr_r] |
739                                       rgb_2_pix[L + crb_g] |
740                                       rgb_2_pix[L + cb_b]);
741             row++;
742 
743             L = *lum;
744             lum += 2;
745             row[0] = row[next_row] = (rgb_2_pix[L + cr_r] |
746                                       rgb_2_pix[L + crb_g] |
747                                       rgb_2_pix[L + cb_b]);
748             row++;
749 
750         }
751         row += next_row;
752     }
753 }
754 
755 static void
Color24DitherYUY2Mod2X(int * colortab,Uint32 * rgb_2_pix,unsigned char * lum,unsigned char * cr,unsigned char * cb,unsigned char * out,int rows,int cols,int mod)756 Color24DitherYUY2Mod2X(int *colortab, Uint32 * rgb_2_pix,
757                        unsigned char *lum, unsigned char *cr,
758                        unsigned char *cb, unsigned char *out,
759                        int rows, int cols, int mod)
760 {
761     unsigned int value;
762     unsigned char *row = out;
763     const int next_row = (cols * 2 + mod) * 3;
764     int x, y;
765     int cr_r;
766     int crb_g;
767     int cb_b;
768     int cols_2 = cols / 2;
769     y = rows;
770     while (y--) {
771         x = cols_2;
772         while (x--) {
773             register int L;
774 
775             cr_r = 0 * 768 + 256 + colortab[*cr + 0 * 256];
776             crb_g = 1 * 768 + 256 + colortab[*cr + 1 * 256]
777                 + colortab[*cb + 2 * 256];
778             cb_b = 2 * 768 + 256 + colortab[*cb + 3 * 256];
779             cr += 4;
780             cb += 4;
781 
782             L = *lum;
783             lum += 2;
784             value = (rgb_2_pix[L + cr_r] |
785                      rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
786             row[0 + 0] = row[3 + 0] = row[next_row + 0] =
787                 row[next_row + 3 + 0] = (value) & 0xFF;
788             row[0 + 1] = row[3 + 1] = row[next_row + 1] =
789                 row[next_row + 3 + 1] = (value >> 8) & 0xFF;
790             row[0 + 2] = row[3 + 2] = row[next_row + 2] =
791                 row[next_row + 3 + 2] = (value >> 16) & 0xFF;
792             row += 2 * 3;
793 
794             L = *lum;
795             lum += 2;
796             value = (rgb_2_pix[L + cr_r] |
797                      rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
798             row[0 + 0] = row[3 + 0] = row[next_row + 0] =
799                 row[next_row + 3 + 0] = (value) & 0xFF;
800             row[0 + 1] = row[3 + 1] = row[next_row + 1] =
801                 row[next_row + 3 + 1] = (value >> 8) & 0xFF;
802             row[0 + 2] = row[3 + 2] = row[next_row + 2] =
803                 row[next_row + 3 + 2] = (value >> 16) & 0xFF;
804             row += 2 * 3;
805 
806         }
807         row += next_row;
808     }
809 }
810 
811 static void
Color32DitherYUY2Mod2X(int * colortab,Uint32 * rgb_2_pix,unsigned char * lum,unsigned char * cr,unsigned char * cb,unsigned char * out,int rows,int cols,int mod)812 Color32DitherYUY2Mod2X(int *colortab, Uint32 * rgb_2_pix,
813                        unsigned char *lum, unsigned char *cr,
814                        unsigned char *cb, unsigned char *out,
815                        int rows, int cols, int mod)
816 {
817     unsigned int *row = (unsigned int *) out;
818     const int next_row = cols * 2 + mod;
819     int x, y;
820     int cr_r;
821     int crb_g;
822     int cb_b;
823     int cols_2 = cols / 2;
824     mod += mod;
825     y = rows;
826     while (y--) {
827         x = cols_2;
828         while (x--) {
829             register int L;
830 
831             cr_r = 0 * 768 + 256 + colortab[*cr + 0 * 256];
832             crb_g = 1 * 768 + 256 + colortab[*cr + 1 * 256]
833                 + colortab[*cb + 2 * 256];
834             cb_b = 2 * 768 + 256 + colortab[*cb + 3 * 256];
835             cr += 4;
836             cb += 4;
837 
838             L = *lum;
839             lum += 2;
840             row[0] = row[1] = row[next_row] = row[next_row + 1] =
841                 (rgb_2_pix[L + cr_r] |
842                  rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
843             row += 2;
844 
845             L = *lum;
846             lum += 2;
847             row[0] = row[1] = row[next_row] = row[next_row + 1] =
848                 (rgb_2_pix[L + cr_r] |
849                  rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
850             row += 2;
851 
852 
853         }
854 
855         row += next_row;
856     }
857 }
858 
859 /*
860  * How many 1 bits are there in the Uint32.
861  * Low performance, do not call often.
862  */
863 static int
number_of_bits_set(Uint32 a)864 number_of_bits_set(Uint32 a)
865 {
866     if (!a)
867         return 0;
868     if (a & 1)
869         return 1 + number_of_bits_set(a >> 1);
870     return (number_of_bits_set(a >> 1));
871 }
872 
873 /*
874  * How many 0 bits are there at least significant end of Uint32.
875  * Low performance, do not call often.
876  */
877 static int
free_bits_at_bottom(Uint32 a)878 free_bits_at_bottom(Uint32 a)
879 {
880     /* assume char is 8 bits */
881     if (!a)
882         return sizeof(Uint32) * 8;
883     if (((Sint32) a) & 1l)
884         return 0;
885     return 1 + free_bits_at_bottom(a >> 1);
886 }
887 
888 static int
SDL_SW_SetupYUVDisplay(SDL_SW_YUVTexture * swdata,Uint32 target_format)889 SDL_SW_SetupYUVDisplay(SDL_SW_YUVTexture * swdata, Uint32 target_format)
890 {
891     Uint32 *r_2_pix_alloc;
892     Uint32 *g_2_pix_alloc;
893     Uint32 *b_2_pix_alloc;
894     int i;
895     int bpp;
896     Uint32 Rmask, Gmask, Bmask, Amask;
897 
898     if (!SDL_PixelFormatEnumToMasks
899         (target_format, &bpp, &Rmask, &Gmask, &Bmask, &Amask) || bpp < 15) {
900         return SDL_SetError("Unsupported YUV destination format");
901     }
902 
903     swdata->target_format = target_format;
904     r_2_pix_alloc = &swdata->rgb_2_pix[0 * 768];
905     g_2_pix_alloc = &swdata->rgb_2_pix[1 * 768];
906     b_2_pix_alloc = &swdata->rgb_2_pix[2 * 768];
907 
908     /*
909      * Set up entries 0-255 in rgb-to-pixel value tables.
910      */
911     for (i = 0; i < 256; ++i) {
912         r_2_pix_alloc[i + 256] = i >> (8 - number_of_bits_set(Rmask));
913         r_2_pix_alloc[i + 256] <<= free_bits_at_bottom(Rmask);
914         r_2_pix_alloc[i + 256] |= Amask;
915         g_2_pix_alloc[i + 256] = i >> (8 - number_of_bits_set(Gmask));
916         g_2_pix_alloc[i + 256] <<= free_bits_at_bottom(Gmask);
917         g_2_pix_alloc[i + 256] |= Amask;
918         b_2_pix_alloc[i + 256] = i >> (8 - number_of_bits_set(Bmask));
919         b_2_pix_alloc[i + 256] <<= free_bits_at_bottom(Bmask);
920         b_2_pix_alloc[i + 256] |= Amask;
921     }
922 
923     /*
924      * If we have 16-bit output depth, then we double the value
925      * in the top word. This means that we can write out both
926      * pixels in the pixel doubling mode with one op. It is
927      * harmless in the normal case as storing a 32-bit value
928      * through a short pointer will lose the top bits anyway.
929      */
930     if (SDL_BYTESPERPIXEL(target_format) == 2) {
931         for (i = 0; i < 256; ++i) {
932             r_2_pix_alloc[i + 256] |= (r_2_pix_alloc[i + 256]) << 16;
933             g_2_pix_alloc[i + 256] |= (g_2_pix_alloc[i + 256]) << 16;
934             b_2_pix_alloc[i + 256] |= (b_2_pix_alloc[i + 256]) << 16;
935         }
936     }
937 
938     /*
939      * Spread out the values we have to the rest of the array so that
940      * we do not need to check for overflow.
941      */
942     for (i = 0; i < 256; ++i) {
943         r_2_pix_alloc[i] = r_2_pix_alloc[256];
944         r_2_pix_alloc[i + 512] = r_2_pix_alloc[511];
945         g_2_pix_alloc[i] = g_2_pix_alloc[256];
946         g_2_pix_alloc[i + 512] = g_2_pix_alloc[511];
947         b_2_pix_alloc[i] = b_2_pix_alloc[256];
948         b_2_pix_alloc[i + 512] = b_2_pix_alloc[511];
949     }
950 
951     /* You have chosen wisely... */
952     switch (swdata->format) {
953     case SDL_PIXELFORMAT_YV12:
954     case SDL_PIXELFORMAT_IYUV:
955         if (SDL_BYTESPERPIXEL(target_format) == 2) {
956 #if (__GNUC__ > 2) && defined(__i386__) && __OPTIMIZE__ && SDL_ASSEMBLY_ROUTINES
957             /* inline assembly functions */
958             if (SDL_HasMMX() && (Rmask == 0xF800) &&
959                 (Gmask == 0x07E0) && (Bmask == 0x001F)
960                 && (swdata->w & 15) == 0) {
961 /* printf("Using MMX 16-bit 565 dither\n"); */
962                 swdata->Display1X = Color565DitherYV12MMX1X;
963             } else {
964 /* printf("Using C 16-bit dither\n"); */
965                 swdata->Display1X = Color16DitherYV12Mod1X;
966             }
967 #else
968             swdata->Display1X = Color16DitherYV12Mod1X;
969 #endif
970             swdata->Display2X = Color16DitherYV12Mod2X;
971         }
972         if (SDL_BYTESPERPIXEL(target_format) == 3) {
973             swdata->Display1X = Color24DitherYV12Mod1X;
974             swdata->Display2X = Color24DitherYV12Mod2X;
975         }
976         if (SDL_BYTESPERPIXEL(target_format) == 4) {
977 #if (__GNUC__ > 2) && defined(__i386__) && __OPTIMIZE__ && SDL_ASSEMBLY_ROUTINES
978             /* inline assembly functions */
979             if (SDL_HasMMX() && (Rmask == 0x00FF0000) &&
980                 (Gmask == 0x0000FF00) &&
981                 (Bmask == 0x000000FF) && (swdata->w & 15) == 0) {
982 /* printf("Using MMX 32-bit dither\n"); */
983                 swdata->Display1X = ColorRGBDitherYV12MMX1X;
984             } else {
985 /* printf("Using C 32-bit dither\n"); */
986                 swdata->Display1X = Color32DitherYV12Mod1X;
987             }
988 #else
989             swdata->Display1X = Color32DitherYV12Mod1X;
990 #endif
991             swdata->Display2X = Color32DitherYV12Mod2X;
992         }
993         break;
994     case SDL_PIXELFORMAT_YUY2:
995     case SDL_PIXELFORMAT_UYVY:
996     case SDL_PIXELFORMAT_YVYU:
997         if (SDL_BYTESPERPIXEL(target_format) == 2) {
998             swdata->Display1X = Color16DitherYUY2Mod1X;
999             swdata->Display2X = Color16DitherYUY2Mod2X;
1000         }
1001         if (SDL_BYTESPERPIXEL(target_format) == 3) {
1002             swdata->Display1X = Color24DitherYUY2Mod1X;
1003             swdata->Display2X = Color24DitherYUY2Mod2X;
1004         }
1005         if (SDL_BYTESPERPIXEL(target_format) == 4) {
1006             swdata->Display1X = Color32DitherYUY2Mod1X;
1007             swdata->Display2X = Color32DitherYUY2Mod2X;
1008         }
1009         break;
1010     default:
1011         /* We should never get here (caught above) */
1012         break;
1013     }
1014 
1015     SDL_FreeSurface(swdata->display);
1016     swdata->display = NULL;
1017     return 0;
1018 }
1019 
1020 SDL_SW_YUVTexture *
SDL_SW_CreateYUVTexture(Uint32 format,int w,int h)1021 SDL_SW_CreateYUVTexture(Uint32 format, int w, int h)
1022 {
1023     SDL_SW_YUVTexture *swdata;
1024     int *Cr_r_tab;
1025     int *Cr_g_tab;
1026     int *Cb_g_tab;
1027     int *Cb_b_tab;
1028     int i;
1029     int CR, CB;
1030 
1031     switch (format) {
1032     case SDL_PIXELFORMAT_YV12:
1033     case SDL_PIXELFORMAT_IYUV:
1034     case SDL_PIXELFORMAT_YUY2:
1035     case SDL_PIXELFORMAT_UYVY:
1036     case SDL_PIXELFORMAT_YVYU:
1037         break;
1038     default:
1039         SDL_SetError("Unsupported YUV format");
1040         return NULL;
1041     }
1042 
1043     swdata = (SDL_SW_YUVTexture *) SDL_calloc(1, sizeof(*swdata));
1044     if (!swdata) {
1045         SDL_OutOfMemory();
1046         return NULL;
1047     }
1048 
1049     swdata->format = format;
1050     swdata->target_format = SDL_PIXELFORMAT_UNKNOWN;
1051     swdata->w = w;
1052     swdata->h = h;
1053     swdata->pixels = (Uint8 *) SDL_malloc(w * h * 2);
1054     swdata->colortab = (int *) SDL_malloc(4 * 256 * sizeof(int));
1055     swdata->rgb_2_pix = (Uint32 *) SDL_malloc(3 * 768 * sizeof(Uint32));
1056     if (!swdata->pixels || !swdata->colortab || !swdata->rgb_2_pix) {
1057         SDL_SW_DestroyYUVTexture(swdata);
1058         SDL_OutOfMemory();
1059         return NULL;
1060     }
1061 
1062     /* Generate the tables for the display surface */
1063     Cr_r_tab = &swdata->colortab[0 * 256];
1064     Cr_g_tab = &swdata->colortab[1 * 256];
1065     Cb_g_tab = &swdata->colortab[2 * 256];
1066     Cb_b_tab = &swdata->colortab[3 * 256];
1067     for (i = 0; i < 256; i++) {
1068         /* Gamma correction (luminescence table) and chroma correction
1069            would be done here.  See the Berkeley mpeg_play sources.
1070          */
1071         CB = CR = (i - 128);
1072         Cr_r_tab[i] = (int) ((0.419 / 0.299) * CR);
1073         Cr_g_tab[i] = (int) (-(0.299 / 0.419) * CR);
1074         Cb_g_tab[i] = (int) (-(0.114 / 0.331) * CB);
1075         Cb_b_tab[i] = (int) ((0.587 / 0.331) * CB);
1076     }
1077 
1078     /* Find the pitch and offset values for the overlay */
1079     switch (format) {
1080     case SDL_PIXELFORMAT_YV12:
1081     case SDL_PIXELFORMAT_IYUV:
1082         swdata->pitches[0] = w;
1083         swdata->pitches[1] = swdata->pitches[0] / 2;
1084         swdata->pitches[2] = swdata->pitches[0] / 2;
1085         swdata->planes[0] = swdata->pixels;
1086         swdata->planes[1] = swdata->planes[0] + swdata->pitches[0] * h;
1087         swdata->planes[2] = swdata->planes[1] + swdata->pitches[1] * h / 2;
1088         break;
1089     case SDL_PIXELFORMAT_YUY2:
1090     case SDL_PIXELFORMAT_UYVY:
1091     case SDL_PIXELFORMAT_YVYU:
1092         swdata->pitches[0] = w * 2;
1093         swdata->planes[0] = swdata->pixels;
1094         break;
1095     default:
1096         SDL_assert(0 && "We should never get here (caught above)");
1097         break;
1098     }
1099 
1100     /* We're all done.. */
1101     return (swdata);
1102 }
1103 
1104 int
SDL_SW_QueryYUVTexturePixels(SDL_SW_YUVTexture * swdata,void ** pixels,int * pitch)1105 SDL_SW_QueryYUVTexturePixels(SDL_SW_YUVTexture * swdata, void **pixels,
1106                              int *pitch)
1107 {
1108     *pixels = swdata->planes[0];
1109     *pitch = swdata->pitches[0];
1110     return 0;
1111 }
1112 
1113 int
SDL_SW_UpdateYUVTexture(SDL_SW_YUVTexture * swdata,const SDL_Rect * rect,const void * pixels,int pitch)1114 SDL_SW_UpdateYUVTexture(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect,
1115                         const void *pixels, int pitch)
1116 {
1117     switch (swdata->format) {
1118     case SDL_PIXELFORMAT_YV12:
1119     case SDL_PIXELFORMAT_IYUV:
1120         if (rect->x == 0 && rect->y == 0 &&
1121             rect->w == swdata->w && rect->h == swdata->h) {
1122                 SDL_memcpy(swdata->pixels, pixels,
1123                            (swdata->h * swdata->w) + (swdata->h * swdata->w) / 2);
1124         } else {
1125             Uint8 *src, *dst;
1126             int row;
1127             size_t length;
1128 
1129             /* Copy the Y plane */
1130             src = (Uint8 *) pixels;
1131             dst = swdata->pixels + rect->y * swdata->w + rect->x;
1132             length = rect->w;
1133             for (row = 0; row < rect->h; ++row) {
1134                 SDL_memcpy(dst, src, length);
1135                 src += pitch;
1136                 dst += swdata->w;
1137             }
1138 
1139             /* Copy the next plane */
1140             src = (Uint8 *) pixels + rect->h * pitch;
1141             dst = swdata->pixels + swdata->h * swdata->w;
1142             dst += rect->y/2 * swdata->w/2 + rect->x/2;
1143             length = rect->w / 2;
1144             for (row = 0; row < rect->h/2; ++row) {
1145                 SDL_memcpy(dst, src, length);
1146                 src += pitch/2;
1147                 dst += swdata->w/2;
1148             }
1149 
1150             /* Copy the next plane */
1151             src = (Uint8 *) pixels + rect->h * pitch + (rect->h * pitch) / 4;
1152             dst = swdata->pixels + swdata->h * swdata->w +
1153                   (swdata->h * swdata->w) / 4;
1154             dst += rect->y/2 * swdata->w/2 + rect->x/2;
1155             length = rect->w / 2;
1156             for (row = 0; row < rect->h/2; ++row) {
1157                 SDL_memcpy(dst, src, length);
1158                 src += pitch/2;
1159                 dst += swdata->w/2;
1160             }
1161         }
1162         break;
1163     case SDL_PIXELFORMAT_YUY2:
1164     case SDL_PIXELFORMAT_UYVY:
1165     case SDL_PIXELFORMAT_YVYU:
1166         {
1167             Uint8 *src, *dst;
1168             int row;
1169             size_t length;
1170 
1171             src = (Uint8 *) pixels;
1172             dst =
1173                 swdata->planes[0] + rect->y * swdata->pitches[0] +
1174                 rect->x * 2;
1175             length = rect->w * 2;
1176             for (row = 0; row < rect->h; ++row) {
1177                 SDL_memcpy(dst, src, length);
1178                 src += pitch;
1179                 dst += swdata->pitches[0];
1180             }
1181         }
1182         break;
1183     }
1184     return 0;
1185 }
1186 
1187 int
SDL_SW_UpdateYUVTexturePlanar(SDL_SW_YUVTexture * swdata,const SDL_Rect * rect,const Uint8 * Yplane,int Ypitch,const Uint8 * Uplane,int Upitch,const Uint8 * Vplane,int Vpitch)1188 SDL_SW_UpdateYUVTexturePlanar(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect,
1189                               const Uint8 *Yplane, int Ypitch,
1190                               const Uint8 *Uplane, int Upitch,
1191                               const Uint8 *Vplane, int Vpitch)
1192 {
1193     const Uint8 *src;
1194     Uint8 *dst;
1195     int row;
1196     size_t length;
1197 
1198     /* Copy the Y plane */
1199     src = Yplane;
1200     dst = swdata->pixels + rect->y * swdata->w + rect->x;
1201     length = rect->w;
1202     for (row = 0; row < rect->h; ++row) {
1203         SDL_memcpy(dst, src, length);
1204         src += Ypitch;
1205         dst += swdata->w;
1206     }
1207 
1208     /* Copy the U plane */
1209     src = Uplane;
1210     if (swdata->format == SDL_PIXELFORMAT_IYUV) {
1211         dst = swdata->pixels + swdata->h * swdata->w;
1212     } else {
1213         dst = swdata->pixels + swdata->h * swdata->w +
1214               (swdata->h * swdata->w) / 4;
1215     }
1216     dst += rect->y/2 * swdata->w/2 + rect->x/2;
1217     length = rect->w / 2;
1218     for (row = 0; row < rect->h/2; ++row) {
1219         SDL_memcpy(dst, src, length);
1220         src += Upitch;
1221         dst += swdata->w/2;
1222     }
1223 
1224     /* Copy the V plane */
1225     src = Vplane;
1226     if (swdata->format == SDL_PIXELFORMAT_YV12) {
1227         dst = swdata->pixels + swdata->h * swdata->w;
1228     } else {
1229         dst = swdata->pixels + swdata->h * swdata->w +
1230               (swdata->h * swdata->w) / 4;
1231     }
1232     dst += rect->y/2 * swdata->w/2 + rect->x/2;
1233     length = rect->w / 2;
1234     for (row = 0; row < rect->h/2; ++row) {
1235         SDL_memcpy(dst, src, length);
1236         src += Vpitch;
1237         dst += swdata->w/2;
1238     }
1239     return 0;
1240 }
1241 
1242 int
SDL_SW_LockYUVTexture(SDL_SW_YUVTexture * swdata,const SDL_Rect * rect,void ** pixels,int * pitch)1243 SDL_SW_LockYUVTexture(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect,
1244                       void **pixels, int *pitch)
1245 {
1246     switch (swdata->format) {
1247     case SDL_PIXELFORMAT_YV12:
1248     case SDL_PIXELFORMAT_IYUV:
1249         if (rect
1250             && (rect->x != 0 || rect->y != 0 || rect->w != swdata->w
1251                 || rect->h != swdata->h)) {
1252             return SDL_SetError
1253                 ("YV12 and IYUV textures only support full surface locks");
1254         }
1255         break;
1256     }
1257 
1258     if (rect) {
1259         *pixels = swdata->planes[0] + rect->y * swdata->pitches[0] + rect->x * 2;
1260     } else {
1261         *pixels = swdata->planes[0];
1262     }
1263     *pitch = swdata->pitches[0];
1264     return 0;
1265 }
1266 
1267 void
SDL_SW_UnlockYUVTexture(SDL_SW_YUVTexture * swdata)1268 SDL_SW_UnlockYUVTexture(SDL_SW_YUVTexture * swdata)
1269 {
1270 }
1271 
1272 int
SDL_SW_CopyYUVToRGB(SDL_SW_YUVTexture * swdata,const SDL_Rect * srcrect,Uint32 target_format,int w,int h,void * pixels,int pitch)1273 SDL_SW_CopyYUVToRGB(SDL_SW_YUVTexture * swdata, const SDL_Rect * srcrect,
1274                     Uint32 target_format, int w, int h, void *pixels,
1275                     int pitch)
1276 {
1277     const int targetbpp = SDL_BYTESPERPIXEL(target_format);
1278     int stretch;
1279     int scale_2x;
1280     Uint8 *lum, *Cr, *Cb;
1281     int mod;
1282 
1283     if (targetbpp == 0) {
1284         return SDL_SetError("Invalid target pixel format");
1285     }
1286 
1287     /* Make sure we're set up to display in the desired format */
1288     if (target_format != swdata->target_format) {
1289         if (SDL_SW_SetupYUVDisplay(swdata, target_format) < 0) {
1290             return -1;
1291         }
1292     }
1293 
1294     stretch = 0;
1295     scale_2x = 0;
1296     if (srcrect->x || srcrect->y || srcrect->w < swdata->w
1297         || srcrect->h < swdata->h) {
1298         /* The source rectangle has been clipped.
1299            Using a scratch surface is easier than adding clipped
1300            source support to all the blitters, plus that would
1301            slow them down in the general unclipped case.
1302          */
1303         stretch = 1;
1304     } else if ((srcrect->w != w) || (srcrect->h != h)) {
1305         if ((w == 2 * srcrect->w) && (h == 2 * srcrect->h)) {
1306             scale_2x = 1;
1307         } else {
1308             stretch = 1;
1309         }
1310     }
1311     if (stretch) {
1312         int bpp;
1313         Uint32 Rmask, Gmask, Bmask, Amask;
1314 
1315         if (swdata->display) {
1316             swdata->display->w = w;
1317             swdata->display->h = h;
1318             swdata->display->pixels = pixels;
1319             swdata->display->pitch = pitch;
1320         } else {
1321             /* This must have succeeded in SDL_SW_SetupYUVDisplay() earlier */
1322             SDL_PixelFormatEnumToMasks(target_format, &bpp, &Rmask, &Gmask,
1323                                        &Bmask, &Amask);
1324             swdata->display =
1325                 SDL_CreateRGBSurfaceFrom(pixels, w, h, bpp, pitch, Rmask,
1326                                          Gmask, Bmask, Amask);
1327             if (!swdata->display) {
1328                 return (-1);
1329             }
1330         }
1331         if (!swdata->stretch) {
1332             /* This must have succeeded in SDL_SW_SetupYUVDisplay() earlier */
1333             SDL_PixelFormatEnumToMasks(target_format, &bpp, &Rmask, &Gmask,
1334                                        &Bmask, &Amask);
1335             swdata->stretch =
1336                 SDL_CreateRGBSurface(0, swdata->w, swdata->h, bpp, Rmask,
1337                                      Gmask, Bmask, Amask);
1338             if (!swdata->stretch) {
1339                 return (-1);
1340             }
1341         }
1342         pixels = swdata->stretch->pixels;
1343         pitch = swdata->stretch->pitch;
1344     }
1345     switch (swdata->format) {
1346     case SDL_PIXELFORMAT_YV12:
1347         lum = swdata->planes[0];
1348         Cr = swdata->planes[1];
1349         Cb = swdata->planes[2];
1350         break;
1351     case SDL_PIXELFORMAT_IYUV:
1352         lum = swdata->planes[0];
1353         Cr = swdata->planes[2];
1354         Cb = swdata->planes[1];
1355         break;
1356     case SDL_PIXELFORMAT_YUY2:
1357         lum = swdata->planes[0];
1358         Cr = lum + 3;
1359         Cb = lum + 1;
1360         break;
1361     case SDL_PIXELFORMAT_UYVY:
1362         lum = swdata->planes[0] + 1;
1363         Cr = lum + 1;
1364         Cb = lum - 1;
1365         break;
1366     case SDL_PIXELFORMAT_YVYU:
1367         lum = swdata->planes[0];
1368         Cr = lum + 1;
1369         Cb = lum + 3;
1370         break;
1371     default:
1372         return SDL_SetError("Unsupported YUV format in copy");
1373     }
1374     mod = (pitch / targetbpp);
1375 
1376     if (scale_2x) {
1377         mod -= (swdata->w * 2);
1378         swdata->Display2X(swdata->colortab, swdata->rgb_2_pix,
1379                           lum, Cr, Cb, pixels, swdata->h, swdata->w, mod);
1380     } else {
1381         mod -= swdata->w;
1382         swdata->Display1X(swdata->colortab, swdata->rgb_2_pix,
1383                           lum, Cr, Cb, pixels, swdata->h, swdata->w, mod);
1384     }
1385     if (stretch) {
1386         SDL_Rect rect = *srcrect;
1387         SDL_SoftStretch(swdata->stretch, &rect, swdata->display, NULL);
1388     }
1389     return 0;
1390 }
1391 
1392 void
SDL_SW_DestroyYUVTexture(SDL_SW_YUVTexture * swdata)1393 SDL_SW_DestroyYUVTexture(SDL_SW_YUVTexture * swdata)
1394 {
1395     if (swdata) {
1396         SDL_free(swdata->pixels);
1397         SDL_free(swdata->colortab);
1398         SDL_free(swdata->rgb_2_pix);
1399         SDL_FreeSurface(swdata->stretch);
1400         SDL_FreeSurface(swdata->display);
1401         SDL_free(swdata);
1402     }
1403 }
1404 
1405 /* vi: set ts=4 sw=4 expandtab: */
1406