1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 */
16
17 #include "types.h"
18 #include "libs/graphics/sdl/sdl_common.h"
19 #include "libs/platform.h"
20 #include "libs/log.h"
21 #include "scalers.h"
22 #include "scaleint.h"
23 #include "2xscalers.h"
24 #ifdef USE_PLATFORM_ACCEL
25 # ifndef __APPLE__
26 // MacOS X framework has no SDL_cpuinfo.h for some reason
27 # include SDL_INCLUDE(SDL_cpuinfo.h)
28 # endif
29 # ifdef MMX_ASM
30 # include "2xscalers_mmx.h"
31 # endif /* MMX_ASM */
32 #endif /* USE_PLATFORM_ACCEL */
33
34 #if SDL_MAJOR_VERSION == 1
35 #define SDL_HasMMX SDL_HasMMXExt
36 #endif
37
38 typedef enum
39 {
40 SCALEPLAT_NULL = PLATFORM_NULL,
41 SCALEPLAT_C = PLATFORM_C,
42 SCALEPLAT_MMX = PLATFORM_MMX,
43 SCALEPLAT_SSE = PLATFORM_SSE,
44 SCALEPLAT_3DNOW = PLATFORM_3DNOW,
45 SCALEPLAT_ALTIVEC = PLATFORM_ALTIVEC,
46
47 SCALEPLAT_C_RGBA,
48 SCALEPLAT_C_BGRA,
49 SCALEPLAT_C_ARGB,
50 SCALEPLAT_C_ABGR,
51
52 } Scale_PlatType_t;
53
54
55 // RGB -> YUV transformation
56 // the RGB vector is multiplied by the transformation matrix
57 // to get the YUV vector
58 #if 0
59 // original table -- not used
60 const int YUV_matrix[3][3] =
61 {
62 /* Y U V */
63 /* R */ {0.2989, -0.1687, 0.5000},
64 /* G */ {0.5867, -0.3312, -0.4183},
65 /* B */ {0.1144, 0.5000, -0.0816}
66 };
67 #else
68 // scaled up by a 2^14 factor, with Y doubled
69 const int YUV_matrix[3][3] =
70 {
71 /* Y U V */
72 /* R */ { 9794, -2764, 8192},
73 /* G */ {19224, -5428, -6853},
74 /* B */ { 3749, 8192, -1339}
75 };
76 #endif
77
78 // pre-computed transformations for 8 bits per channel
79 int RGB_to_YUV[/*RGB*/ 3][/*YUV*/ 3][ /*mult-res*/ 256];
80 sint16 dRGB_to_dYUV[/*RGB*/ 3][/*YUV*/ 3][ /*mult-res*/ 512];
81
82 // pre-computed transformations for RGB555
83 YUV_VECTOR RGB15_to_YUV[0x8000];
84
85 PLATFORM_TYPE force_platform = PLATFORM_NULL;
86 Scale_PlatType_t Scale_Platform = SCALEPLAT_NULL;
87
88
89 // pre-compute the RGB->YUV transformations
90 void
Scale_Init(void)91 Scale_Init (void)
92 {
93 int i1, i2, i3;
94
95 for (i1 = 0; i1 < 3; i1++) // enum R,G,B
96 for (i2 = 0; i2 < 3; i2++) // enum Y,U,V
97 for (i3 = 0; i3 < 256; i3++) // enum possible channel vals
98 {
99 RGB_to_YUV[i1][i2][i3] =
100 (YUV_matrix[i1][i2] * i3) >> 14;
101 }
102
103 for (i1 = 0; i1 < 3; i1++) // enum R,G,B
104 for (i2 = 0; i2 < 3; i2++) // enum Y,U,V
105 for (i3 = -255; i3 < 256; i3++) // enum possible channel delta vals
106 {
107 dRGB_to_dYUV[i1][i2][i3 + 255] =
108 (YUV_matrix[i1][i2] * i3) >> 14;
109 }
110
111 for (i1 = 0; i1 < 32; ++i1)
112 for (i2 = 0; i2 < 32; ++i2)
113 for (i3 = 0; i3 < 32; ++i3)
114 {
115 int y, u, v;
116 // adding upper bits halved for error correction
117 int r = (i1 << 3) | (i1 >> 3);
118 int g = (i2 << 3) | (i2 >> 3);
119 int b = (i3 << 3) | (i3 >> 3);
120
121 y = ( r * YUV_matrix[YUV_XFORM_R][YUV_XFORM_Y]
122 + g * YUV_matrix[YUV_XFORM_G][YUV_XFORM_Y]
123 + b * YUV_matrix[YUV_XFORM_B][YUV_XFORM_Y]
124 ) >> 15; // we dont need Y doubled, need Y to fit 8 bits
125
126 // U and V are half the importance of Y
127 u = 64+(( r * YUV_matrix[YUV_XFORM_R][YUV_XFORM_U]
128 + g * YUV_matrix[YUV_XFORM_G][YUV_XFORM_U]
129 + b * YUV_matrix[YUV_XFORM_B][YUV_XFORM_U]
130 ) >> 15); // halved
131
132 v = 64+(( r * YUV_matrix[YUV_XFORM_R][YUV_XFORM_V]
133 + g * YUV_matrix[YUV_XFORM_G][YUV_XFORM_V]
134 + b * YUV_matrix[YUV_XFORM_B][YUV_XFORM_V]
135 ) >> 15); // halved
136
137 RGB15_to_YUV[(i1 << 10) | (i2 << 5) | i3] = (y << 16) | (u << 8) | v;
138 }
139 }
140
141
142 // expands the given rectangle in all directions by 'expansion'
143 // guarded by 'limits'
144 void
Scale_ExpandRect(SDL_Rect * rect,int expansion,const SDL_Rect * limits)145 Scale_ExpandRect (SDL_Rect* rect, int expansion, const SDL_Rect* limits)
146 {
147 if (rect->x - expansion >= limits->x)
148 {
149 rect->w += expansion;
150 rect->x -= expansion;
151 }
152 else
153 {
154 rect->w += rect->x - limits->x;
155 rect->x = limits->x;
156 }
157
158 if (rect->y - expansion >= limits->y)
159 {
160 rect->h += expansion;
161 rect->y -= expansion;
162 }
163 else
164 {
165 rect->h += rect->y - limits->y;
166 rect->y = limits->y;
167 }
168
169 if (rect->x + rect->w + expansion <= limits->w)
170 rect->w += expansion;
171 else
172 rect->w = limits->w - rect->x;
173
174 if (rect->y + rect->h + expansion <= limits->h)
175 rect->h += expansion;
176 else
177 rect->h = limits->h - rect->y;
178 }
179
180
181 // Platform+Scaler function lookups
182
183 typedef struct
184 {
185 Scale_PlatType_t platform;
186 const Scale_FuncDef_t* funcdefs;
187 } Scale_PlatDef_t;
188
189
190 static const Scale_PlatDef_t
191 Scale_PlatDefs[] =
192 {
193 #if defined(MMX_ASM)
194 {SCALEPLAT_SSE, Scale_SSE_Functions},
195 {SCALEPLAT_3DNOW, Scale_3DNow_Functions},
196 {SCALEPLAT_MMX, Scale_MMX_Functions},
197 #endif /* MMX_ASM */
198 // Default
199 {SCALEPLAT_NULL, Scale_C_Functions}
200 };
201
202
203 TFB_ScaleFunc
Scale_PrepPlatform(int flags,const SDL_PixelFormat * fmt)204 Scale_PrepPlatform (int flags, const SDL_PixelFormat* fmt)
205 {
206 const Scale_PlatDef_t* pdef;
207 const Scale_FuncDef_t* fdef;
208
209 (void)flags;
210
211 Scale_Platform = SCALEPLAT_NULL;
212
213 // first match wins
214 // add better platform techs to the top
215 #ifdef MMX_ASM
216 if ( (!force_platform && (SDL_HasSSE () || SDL_HasMMX ()))
217 || force_platform == PLATFORM_SSE)
218 {
219 log_add (log_Info, "Screen scalers are using SSE/MMX-Ext/MMX code");
220 Scale_Platform = SCALEPLAT_SSE;
221
222 Scale_SSE_PrepPlatform (fmt);
223 }
224 else
225 if ( (!force_platform && SDL_HasAltiVec ())
226 || force_platform == PLATFORM_ALTIVEC)
227 {
228 log_add (log_Info, "Screen scalers would use AltiVec code "
229 "if someone actually wrote it");
230 //Scale_Platform = SCALEPLAT_ALTIVEC;
231 }
232 else
233 if ( (!force_platform && SDL_Has3DNow ())
234 || force_platform == PLATFORM_3DNOW)
235 {
236 log_add (log_Info, "Screen scalers are using 3DNow/MMX code");
237 Scale_Platform = SCALEPLAT_3DNOW;
238
239 Scale_3DNow_PrepPlatform (fmt);
240 }
241 else
242 if ( (!force_platform && SDL_HasMMX ())
243 || force_platform == PLATFORM_MMX)
244 {
245 log_add (log_Info, "Screen scalers are using MMX code");
246 Scale_Platform = SCALEPLAT_MMX;
247
248 Scale_MMX_PrepPlatform (fmt);
249 }
250 #endif
251
252 if (Scale_Platform == SCALEPLAT_NULL)
253 { // Plain C versions
254 if (fmt->Rmask == 0xff000000 && fmt->Bmask == 0x0000ff00)
255 Scale_Platform = SCALEPLAT_C_RGBA;
256 else if (fmt->Rmask == 0x00ff0000 && fmt->Bmask == 0x000000ff)
257 Scale_Platform = SCALEPLAT_C_ARGB;
258 else if (fmt->Rmask == 0x0000ff00 && fmt->Bmask == 0xff000000)
259 Scale_Platform = SCALEPLAT_C_BGRA;
260 else if (fmt->Rmask == 0x000000ff && fmt->Bmask == 0x00ff0000)
261 Scale_Platform = SCALEPLAT_C_ABGR;
262 else
263 { // use slowest default
264 log_add (log_Warning, "Scale_PrepPlatform(): unknown masks "
265 "(Red %08x, Blue %08x)", fmt->Rmask, fmt->Bmask);
266 Scale_Platform = SCALEPLAT_C;
267 }
268
269 if (Scale_Platform == SCALEPLAT_C)
270 log_add (log_Info, "Screen scalers are using slow generic C code");
271 else
272 log_add (log_Info, "Screen scalers are using optimized C code");
273 }
274
275 // Lookup the scaling function
276 // First find the right platform
277 for (pdef = Scale_PlatDefs;
278 pdef->platform != Scale_Platform && pdef->platform != SCALEPLAT_NULL;
279 ++pdef)
280 ;
281 // Next find the right function
282 for (fdef = pdef->funcdefs;
283 (flags & fdef->flag) != fdef->flag;
284 ++fdef)
285 ;
286
287 return fdef->func;
288 }
289
290