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