1 /*
2  * This file is part of the Scale2x project.
3  *
4  * Copyright (C) 2001, 2002, 2003, 2004 Andrea Mazzoleni
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20 
21 /*
22  * This file contains a C and MMX implementation of the Scale2x effect.
23  *
24  * You can find an high level description of the effect at :
25  *
26  * http://scale2x.sourceforge.net/
27  *
28  * Alternatively at the previous license terms, you are allowed to use this
29  * code in your program with these conditions:
30  * - the program is not used in commercial activities.
31  * - the whole source code of the program is released with the binary.
32  * - derivative works of the program are allowed.
33  */
34 
35 #include "scale3x.h"
36 
37 #include <assert.h>
38 
39 /***************************************************************************/
40 /* Scale3x C implementation */
41 
42 /**
43  * Define the macro USE_SCALE_RANDOMWRITE to enable
44  * an optimized version which writes memory in random order.
45  * This version is a little faster if you write in system memory.
46  * But it's a lot slower if you write in video memory.
47  * So, enable it only if you are sure to never write directly in video memory.
48  */
49 /* #define USE_SCALE_RANDOMWRITE */
50 
51 #ifdef USE_SCALE_RANDOMWRITE
52 
scale3x_8_def_whole(scale3x_uint8 * restrict dst0,scale3x_uint8 * restrict dst1,scale3x_uint8 * restrict dst2,const scale3x_uint8 * restrict src0,const scale3x_uint8 * restrict src1,const scale3x_uint8 * restrict src2,unsigned count)53 static inline void scale3x_8_def_whole(scale3x_uint8* restrict dst0, scale3x_uint8* restrict dst1, scale3x_uint8* restrict dst2, const scale3x_uint8* restrict src0, const scale3x_uint8* restrict src1, const scale3x_uint8* restrict src2, unsigned count)
54 {
55 	assert(count >= 2);
56 
57 	/* first pixel */
58 	if (src0[0] != src2[0] && src1[0] != src1[1]) {
59 		dst0[0] = src1[0];
60 		dst0[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0]) ? src0[0] : src1[0];
61 		dst0[2] = src1[1] == src0[0] ? src1[1] : src1[0];
62 		dst1[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
63 		dst1[1] = src1[0];
64 		dst1[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
65 		dst2[0] = src1[0];
66 		dst2[1] = (src1[0] == src2[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src2[0]) ? src2[0] : src1[0];
67 		dst2[2] = src1[1] == src2[0] ? src1[1] : src1[0];
68 	} else {
69 		dst0[0] = src1[0];
70 		dst0[1] = src1[0];
71 		dst0[2] = src1[0];
72 		dst1[0] = src1[0];
73 		dst1[1] = src1[0];
74 		dst1[2] = src1[0];
75 		dst2[0] = src1[0];
76 		dst2[1] = src1[0];
77 		dst2[2] = src1[0];
78 	}
79 	++src0;
80 	++src1;
81 	++src2;
82 	dst0 += 3;
83 	dst1 += 3;
84 	dst2 += 3;
85 
86 	/* central pixels */
87 	count -= 2;
88 	while (count) {
89 		if (src0[0] != src2[0] && src1[-1] != src1[1]) {
90 			dst0[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
91 			dst0[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
92 			dst0[2] = src1[1] == src0[0] ? src1[1] : src1[0];
93 			dst1[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
94 			dst1[1] = src1[0];
95 			dst1[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
96 			dst2[0] = src1[-1] == src2[0] ? src1[-1] : src1[0];
97 			dst2[1] = (src1[-1] == src2[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src2[-1]) ? src2[0] : src1[0];
98 			dst2[2] = src1[1] == src2[0] ? src1[1] : src1[0];
99 		} else {
100 			dst0[0] = src1[0];
101 			dst0[1] = src1[0];
102 			dst0[2] = src1[0];
103 			dst1[0] = src1[0];
104 			dst1[1] = src1[0];
105 			dst1[2] = src1[0];
106 			dst2[0] = src1[0];
107 			dst2[1] = src1[0];
108 			dst2[2] = src1[0];
109 		}
110 
111 		++src0;
112 		++src1;
113 		++src2;
114 		dst0 += 3;
115 		dst1 += 3;
116 		dst2 += 3;
117 		--count;
118 	}
119 
120 	/* last pixel */
121 	if (src0[0] != src2[0] && src1[-1] != src1[0]) {
122 		dst0[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
123 		dst0[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
124 		dst0[2] = src1[0];
125 		dst1[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
126 		dst1[1] = src1[0];
127 		dst1[2] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
128 		dst2[0] = src1[-1] == src2[0] ? src1[-1] : src1[0];
129 		dst2[1] = (src1[-1] == src2[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src2[-1]) ? src2[0] : src1[0];
130 		dst2[2] = src1[0];
131 	} else {
132 		dst0[0] = src1[0];
133 		dst0[1] = src1[0];
134 		dst0[2] = src1[0];
135 		dst1[0] = src1[0];
136 		dst1[1] = src1[0];
137 		dst1[2] = src1[0];
138 		dst2[0] = src1[0];
139 		dst2[1] = src1[0];
140 		dst2[2] = src1[0];
141 	}
142 }
143 
144 #endif
145 
scale3x_8_def_border(scale3x_uint8 * restrict dst,const scale3x_uint8 * restrict src0,const scale3x_uint8 * restrict src1,const scale3x_uint8 * restrict src2,unsigned count)146 static inline void scale3x_8_def_border(scale3x_uint8* restrict dst, const scale3x_uint8* restrict src0, const scale3x_uint8* restrict src1, const scale3x_uint8* restrict src2, unsigned count)
147 {
148 	assert(count >= 2);
149 
150 	/* first pixel */
151 	if (src0[0] != src2[0] && src1[0] != src1[1]) {
152 		dst[0] = src1[0];
153 		dst[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0]) ? src0[0] : src1[0];
154 		dst[2] = src1[1] == src0[0] ? src1[1] : src1[0];
155 	} else {
156 		dst[0] = src1[0];
157 		dst[1] = src1[0];
158 		dst[2] = src1[0];
159 	}
160 	++src0;
161 	++src1;
162 	++src2;
163 	dst += 3;
164 
165 	/* central pixels */
166 	count -= 2;
167 	while (count) {
168 		if (src0[0] != src2[0] && src1[-1] != src1[1]) {
169 			dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
170 			dst[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
171 			dst[2] = src1[1] == src0[0] ? src1[1] : src1[0];
172 		} else {
173 			dst[0] = src1[0];
174 			dst[1] = src1[0];
175 			dst[2] = src1[0];
176 		}
177 
178 		++src0;
179 		++src1;
180 		++src2;
181 		dst += 3;
182 		--count;
183 	}
184 
185 	/* last pixel */
186 	if (src0[0] != src2[0] && src1[-1] != src1[0]) {
187 		dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
188 		dst[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
189 		dst[2] = src1[0];
190 	} else {
191 		dst[0] = src1[0];
192 		dst[1] = src1[0];
193 		dst[2] = src1[0];
194 	}
195 }
196 
scale3x_8_def_center(scale3x_uint8 * restrict dst,const scale3x_uint8 * restrict src0,const scale3x_uint8 * restrict src1,const scale3x_uint8 * restrict src2,unsigned count)197 static inline void scale3x_8_def_center(scale3x_uint8* restrict dst, const scale3x_uint8* restrict src0, const scale3x_uint8* restrict src1, const scale3x_uint8* restrict src2, unsigned count)
198 {
199 	assert(count >= 2);
200 
201 	/* first pixel */
202 	if (src0[0] != src2[0] && src1[0] != src1[1]) {
203 		dst[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
204 		dst[1] = src1[0];
205 		dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
206 	} else {
207 		dst[0] = src1[0];
208 		dst[1] = src1[0];
209 		dst[2] = src1[0];
210 	}
211 	++src0;
212 	++src1;
213 	++src2;
214 	dst += 3;
215 
216 	/* central pixels */
217 	count -= 2;
218 	while (count) {
219 		if (src0[0] != src2[0] && src1[-1] != src1[1]) {
220 			dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
221 			dst[1] = src1[0];
222 			dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
223 		} else {
224 			dst[0] = src1[0];
225 			dst[1] = src1[0];
226 			dst[2] = src1[0];
227 		}
228 
229 		++src0;
230 		++src1;
231 		++src2;
232 		dst += 3;
233 		--count;
234 	}
235 
236 	/* last pixel */
237 	if (src0[0] != src2[0] && src1[-1] != src1[0]) {
238 		dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
239 		dst[1] = src1[0];
240 		dst[2] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
241 	} else {
242 		dst[0] = src1[0];
243 		dst[1] = src1[0];
244 		dst[2] = src1[0];
245 	}
246 }
247 
248 #ifdef USE_SCALE_RANDOMWRITE
249 
scale3x_16_def_whole(scale3x_uint16 * restrict dst0,scale3x_uint16 * restrict dst1,scale3x_uint16 * restrict dst2,const scale3x_uint16 * restrict src0,const scale3x_uint16 * restrict src1,const scale3x_uint16 * restrict src2,unsigned count)250 static inline void scale3x_16_def_whole(scale3x_uint16* restrict dst0, scale3x_uint16* restrict dst1, scale3x_uint16* restrict dst2, const scale3x_uint16* restrict src0, const scale3x_uint16* restrict src1, const scale3x_uint16* restrict src2, unsigned count)
251 {
252 	assert(count >= 2);
253 
254 	/* first pixel */
255 	if (src0[0] != src2[0] && src1[0] != src1[1]) {
256 		dst0[0] = src1[0];
257 		dst0[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0]) ? src0[0] : src1[0];
258 		dst0[2] = src1[1] == src0[0] ? src1[1] : src1[0];
259 		dst1[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
260 		dst1[1] = src1[0];
261 		dst1[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
262 		dst2[0] = src1[0];
263 		dst2[1] = (src1[0] == src2[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src2[0]) ? src2[0] : src1[0];
264 		dst2[2] = src1[1] == src2[0] ? src1[1] : src1[0];
265 	} else {
266 		dst0[0] = src1[0];
267 		dst0[1] = src1[0];
268 		dst0[2] = src1[0];
269 		dst1[0] = src1[0];
270 		dst1[1] = src1[0];
271 		dst1[2] = src1[0];
272 		dst2[0] = src1[0];
273 		dst2[1] = src1[0];
274 		dst2[2] = src1[0];
275 	}
276 	++src0;
277 	++src1;
278 	++src2;
279 	dst0 += 3;
280 	dst1 += 3;
281 	dst2 += 3;
282 
283 	/* central pixels */
284 	count -= 2;
285 	while (count) {
286 		if (src0[0] != src2[0] && src1[-1] != src1[1]) {
287 			dst0[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
288 			dst0[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
289 			dst0[2] = src1[1] == src0[0] ? src1[1] : src1[0];
290 			dst1[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
291 			dst1[1] = src1[0];
292 			dst1[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
293 			dst2[0] = src1[-1] == src2[0] ? src1[-1] : src1[0];
294 			dst2[1] = (src1[-1] == src2[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src2[-1]) ? src2[0] : src1[0];
295 			dst2[2] = src1[1] == src2[0] ? src1[1] : src1[0];
296 		} else {
297 			dst0[0] = src1[0];
298 			dst0[1] = src1[0];
299 			dst0[2] = src1[0];
300 			dst1[0] = src1[0];
301 			dst1[1] = src1[0];
302 			dst1[2] = src1[0];
303 			dst2[0] = src1[0];
304 			dst2[1] = src1[0];
305 			dst2[2] = src1[0];
306 		}
307 
308 		++src0;
309 		++src1;
310 		++src2;
311 		dst0 += 3;
312 		dst1 += 3;
313 		dst2 += 3;
314 		--count;
315 	}
316 
317 	/* last pixel */
318 	if (src0[0] != src2[0] && src1[-1] != src1[0]) {
319 		dst0[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
320 		dst0[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
321 		dst0[2] = src1[0];
322 		dst1[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
323 		dst1[1] = src1[0];
324 		dst1[2] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
325 		dst2[0] = src1[-1] == src2[0] ? src1[-1] : src1[0];
326 		dst2[1] = (src1[-1] == src2[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src2[-1]) ? src2[0] : src1[0];
327 		dst2[2] = src1[0];
328 	} else {
329 		dst0[0] = src1[0];
330 		dst0[1] = src1[0];
331 		dst0[2] = src1[0];
332 		dst1[0] = src1[0];
333 		dst1[1] = src1[0];
334 		dst1[2] = src1[0];
335 		dst2[0] = src1[0];
336 		dst2[1] = src1[0];
337 		dst2[2] = src1[0];
338 	}
339 }
340 
341 #endif
342 
scale3x_16_def_border(scale3x_uint16 * restrict dst,const scale3x_uint16 * restrict src0,const scale3x_uint16 * restrict src1,const scale3x_uint16 * restrict src2,unsigned count)343 static inline void scale3x_16_def_border(scale3x_uint16* restrict dst, const scale3x_uint16* restrict src0, const scale3x_uint16* restrict src1, const scale3x_uint16* restrict src2, unsigned count)
344 {
345 	assert(count >= 2);
346 
347 	/* first pixel */
348 	if (src0[0] != src2[0] && src1[0] != src1[1]) {
349 		dst[0] = src1[0];
350 		dst[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0]) ? src0[0] : src1[0];
351 		dst[2] = src1[1] == src0[0] ? src1[1] : src1[0];
352 	} else {
353 		dst[0] = src1[0];
354 		dst[1] = src1[0];
355 		dst[2] = src1[0];
356 	}
357 	++src0;
358 	++src1;
359 	++src2;
360 	dst += 3;
361 
362 	/* central pixels */
363 	count -= 2;
364 	while (count) {
365 		if (src0[0] != src2[0] && src1[-1] != src1[1]) {
366 			dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
367 			dst[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
368 			dst[2] = src1[1] == src0[0] ? src1[1] : src1[0];
369 		} else {
370 			dst[0] = src1[0];
371 			dst[1] = src1[0];
372 			dst[2] = src1[0];
373 		}
374 
375 		++src0;
376 		++src1;
377 		++src2;
378 		dst += 3;
379 		--count;
380 	}
381 
382 	/* last pixel */
383 	if (src0[0] != src2[0] && src1[-1] != src1[0]) {
384 		dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
385 		dst[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
386 		dst[2] = src1[0];
387 	} else {
388 		dst[0] = src1[0];
389 		dst[1] = src1[0];
390 		dst[2] = src1[0];
391 	}
392 }
393 
scale3x_16_def_center(scale3x_uint16 * restrict dst,const scale3x_uint16 * restrict src0,const scale3x_uint16 * restrict src1,const scale3x_uint16 * restrict src2,unsigned count)394 static inline void scale3x_16_def_center(scale3x_uint16* restrict dst, const scale3x_uint16* restrict src0, const scale3x_uint16* restrict src1, const scale3x_uint16* restrict src2, unsigned count)
395 {
396 	assert(count >= 2);
397 
398 	/* first pixel */
399 	if (src0[0] != src2[0] && src1[0] != src1[1]) {
400 		dst[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
401 		dst[1] = src1[0];
402 		dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
403 	} else {
404 		dst[0] = src1[0];
405 		dst[1] = src1[0];
406 		dst[2] = src1[0];
407 	}
408 	++src0;
409 	++src1;
410 	++src2;
411 	dst += 3;
412 
413 	/* central pixels */
414 	count -= 2;
415 	while (count) {
416 		if (src0[0] != src2[0] && src1[-1] != src1[1]) {
417 			dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
418 			dst[1] = src1[0];
419 			dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
420 		} else {
421 			dst[0] = src1[0];
422 			dst[1] = src1[0];
423 			dst[2] = src1[0];
424 		}
425 
426 		++src0;
427 		++src1;
428 		++src2;
429 		dst += 3;
430 		--count;
431 	}
432 
433 	/* last pixel */
434 	if (src0[0] != src2[0] && src1[-1] != src1[0]) {
435 		dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
436 		dst[1] = src1[0];
437 		dst[2] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
438 	} else {
439 		dst[0] = src1[0];
440 		dst[1] = src1[0];
441 		dst[2] = src1[0];
442 	}
443 }
444 
445 #ifdef USE_SCALE_RANDOMWRITE
446 
scale3x_32_def_whole(scale3x_uint32 * restrict dst0,scale3x_uint32 * restrict dst1,scale3x_uint32 * restrict dst2,const scale3x_uint32 * restrict src0,const scale3x_uint32 * restrict src1,const scale3x_uint32 * restrict src2,unsigned count)447 static inline void scale3x_32_def_whole(scale3x_uint32* restrict dst0, scale3x_uint32* restrict dst1, scale3x_uint32* restrict dst2, const scale3x_uint32* restrict src0, const scale3x_uint32* restrict src1, const scale3x_uint32* restrict src2, unsigned count)
448 {
449 	assert(count >= 2);
450 
451 	/* first pixel */
452 	if (src0[0] != src2[0] && src1[0] != src1[1]) {
453 		dst0[0] = src1[0];
454 		dst0[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0]) ? src0[0] : src1[0];
455 		dst0[2] = src1[1] == src0[0] ? src1[1] : src1[0];
456 		dst1[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
457 		dst1[1] = src1[0];
458 		dst1[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
459 		dst2[0] = src1[0];
460 		dst2[1] = (src1[0] == src2[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src2[0]) ? src2[0] : src1[0];
461 		dst2[2] = src1[1] == src2[0] ? src1[1] : src1[0];
462 	} else {
463 		dst0[0] = src1[0];
464 		dst0[1] = src1[0];
465 		dst0[2] = src1[0];
466 		dst1[0] = src1[0];
467 		dst1[1] = src1[0];
468 		dst1[2] = src1[0];
469 		dst2[0] = src1[0];
470 		dst2[1] = src1[0];
471 		dst2[2] = src1[0];
472 	}
473 	++src0;
474 	++src1;
475 	++src2;
476 	dst0 += 3;
477 	dst1 += 3;
478 	dst2 += 3;
479 
480 	/* central pixels */
481 	count -= 2;
482 	while (count) {
483 		if (src0[0] != src2[0] && src1[-1] != src1[1]) {
484 			dst0[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
485 			dst0[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
486 			dst0[2] = src1[1] == src0[0] ? src1[1] : src1[0];
487 			dst1[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
488 			dst1[1] = src1[0];
489 			dst1[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
490 			dst2[0] = src1[-1] == src2[0] ? src1[-1] : src1[0];
491 			dst2[1] = (src1[-1] == src2[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src2[-1]) ? src2[0] : src1[0];
492 			dst2[2] = src1[1] == src2[0] ? src1[1] : src1[0];
493 		} else {
494 			dst0[0] = src1[0];
495 			dst0[1] = src1[0];
496 			dst0[2] = src1[0];
497 			dst1[0] = src1[0];
498 			dst1[1] = src1[0];
499 			dst1[2] = src1[0];
500 			dst2[0] = src1[0];
501 			dst2[1] = src1[0];
502 			dst2[2] = src1[0];
503 		}
504 
505 		++src0;
506 		++src1;
507 		++src2;
508 		dst0 += 3;
509 		dst1 += 3;
510 		dst2 += 3;
511 		--count;
512 	}
513 
514 	/* last pixel */
515 	if (src0[0] != src2[0] && src1[-1] != src1[0]) {
516 		dst0[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
517 		dst0[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
518 		dst0[2] = src1[0];
519 		dst1[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
520 		dst1[1] = src1[0];
521 		dst1[2] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
522 		dst2[0] = src1[-1] == src2[0] ? src1[-1] : src1[0];
523 		dst2[1] = (src1[-1] == src2[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src2[-1]) ? src2[0] : src1[0];
524 		dst2[2] = src1[0];
525 	} else {
526 		dst0[0] = src1[0];
527 		dst0[1] = src1[0];
528 		dst0[2] = src1[0];
529 		dst1[0] = src1[0];
530 		dst1[1] = src1[0];
531 		dst1[2] = src1[0];
532 		dst2[0] = src1[0];
533 		dst2[1] = src1[0];
534 		dst2[2] = src1[0];
535 	}
536 }
537 
538 #endif
539 
scale3x_32_def_border(scale3x_uint32 * restrict dst,const scale3x_uint32 * restrict src0,const scale3x_uint32 * restrict src1,const scale3x_uint32 * restrict src2,unsigned count)540 static inline void scale3x_32_def_border(scale3x_uint32* restrict dst, const scale3x_uint32* restrict src0, const scale3x_uint32* restrict src1, const scale3x_uint32* restrict src2, unsigned count)
541 {
542 	assert(count >= 2);
543 
544 	/* first pixel */
545 	if (src0[0] != src2[0] && src1[0] != src1[1]) {
546 		dst[0] = src1[0];
547 		dst[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0]) ? src0[0] : src1[0];
548 		dst[2] = src1[1] == src0[0] ? src1[1] : src1[0];
549 	} else {
550 		dst[0] = src1[0];
551 		dst[1] = src1[0];
552 		dst[2] = src1[0];
553 	}
554 	++src0;
555 	++src1;
556 	++src2;
557 	dst += 3;
558 
559 	/* central pixels */
560 	count -= 2;
561 	while (count) {
562 		if (src0[0] != src2[0] && src1[-1] != src1[1]) {
563 			dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
564 			dst[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
565 			dst[2] = src1[1] == src0[0] ? src1[1] : src1[0];
566 		} else {
567 			dst[0] = src1[0];
568 			dst[1] = src1[0];
569 			dst[2] = src1[0];
570 		}
571 
572 		++src0;
573 		++src1;
574 		++src2;
575 		dst += 3;
576 		--count;
577 	}
578 
579 	/* last pixel */
580 	if (src0[0] != src2[0] && src1[-1] != src1[0]) {
581 		dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
582 		dst[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
583 		dst[2] = src1[0];
584 	} else {
585 		dst[0] = src1[0];
586 		dst[1] = src1[0];
587 		dst[2] = src1[0];
588 	}
589 }
590 
scale3x_32_def_center(scale3x_uint32 * restrict dst,const scale3x_uint32 * restrict src0,const scale3x_uint32 * restrict src1,const scale3x_uint32 * restrict src2,unsigned count)591 static inline void scale3x_32_def_center(scale3x_uint32* restrict dst, const scale3x_uint32* restrict src0, const scale3x_uint32* restrict src1, const scale3x_uint32* restrict src2, unsigned count)
592 {
593 	assert(count >= 2);
594 
595 	/* first pixel */
596 	if (src0[0] != src2[0] && src1[0] != src1[1]) {
597 		dst[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
598 		dst[1] = src1[0];
599 		dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
600 	} else {
601 		dst[0] = src1[0];
602 		dst[1] = src1[0];
603 		dst[2] = src1[0];
604 	}
605 	++src0;
606 	++src1;
607 	++src2;
608 	dst += 3;
609 
610 	/* central pixels */
611 	count -= 2;
612 	while (count) {
613 		if (src0[0] != src2[0] && src1[-1] != src1[1]) {
614 			dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
615 			dst[1] = src1[0];
616 			dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
617 		} else {
618 			dst[0] = src1[0];
619 			dst[1] = src1[0];
620 			dst[2] = src1[0];
621 		}
622 
623 		++src0;
624 		++src1;
625 		++src2;
626 		dst += 3;
627 		--count;
628 	}
629 
630 	/* last pixel */
631 	if (src0[0] != src2[0] && src1[-1] != src1[0]) {
632 		dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
633 		dst[1] = src1[0];
634 		dst[2] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
635 	} else {
636 		dst[0] = src1[0];
637 		dst[1] = src1[0];
638 		dst[2] = src1[0];
639 	}
640 }
641 
642 /**
643  * Scale by a factor of 3 a row of pixels of 8 bits.
644  * The function is implemented in C.
645  * The pixels over the left and right borders are assumed of the same color of
646  * the pixels on the border.
647  * \param src0 Pointer at the first pixel of the previous row.
648  * \param src1 Pointer at the first pixel of the current row.
649  * \param src2 Pointer at the first pixel of the next row.
650  * \param count Length in pixels of the src0, src1 and src2 rows.
651  * It must be at least 2.
652  * \param dst0 First destination row, triple length in pixels.
653  * \param dst1 Second destination row, triple length in pixels.
654  * \param dst2 Third destination row, triple length in pixels.
655  */
scale3x_8_def(scale3x_uint8 * dst0,scale3x_uint8 * dst1,scale3x_uint8 * dst2,const scale3x_uint8 * src0,const scale3x_uint8 * src1,const scale3x_uint8 * src2,unsigned count)656 void scale3x_8_def(scale3x_uint8* dst0, scale3x_uint8* dst1, scale3x_uint8* dst2, const scale3x_uint8* src0, const scale3x_uint8* src1, const scale3x_uint8* src2, unsigned count)
657 {
658 #ifdef USE_SCALE_RANDOMWRITE
659 	scale3x_8_def_whole(dst0, dst1, dst2, src0, src1, src2, count);
660 #else
661 	scale3x_8_def_border(dst0, src0, src1, src2, count);
662 	scale3x_8_def_center(dst1, src0, src1, src2, count);
663 	scale3x_8_def_border(dst2, src2, src1, src0, count);
664 #endif
665 }
666 
667 /**
668  * Scale by a factor of 3 a row of pixels of 16 bits.
669  * This function operates like scale3x_8_def() but for 16 bits pixels.
670  * \param src0 Pointer at the first pixel of the previous row.
671  * \param src1 Pointer at the first pixel of the current row.
672  * \param src2 Pointer at the first pixel of the next row.
673  * \param count Length in pixels of the src0, src1 and src2 rows.
674  * It must be at least 2.
675  * \param dst0 First destination row, triple length in pixels.
676  * \param dst1 Second destination row, triple length in pixels.
677  * \param dst2 Third destination row, triple length in pixels.
678  */
scale3x_16_def(scale3x_uint16 * dst0,scale3x_uint16 * dst1,scale3x_uint16 * dst2,const scale3x_uint16 * src0,const scale3x_uint16 * src1,const scale3x_uint16 * src2,unsigned count)679 void scale3x_16_def(scale3x_uint16* dst0, scale3x_uint16* dst1, scale3x_uint16* dst2, const scale3x_uint16* src0, const scale3x_uint16* src1, const scale3x_uint16* src2, unsigned count)
680 {
681 #ifdef USE_SCALE_RANDOMWRITE
682 	scale3x_16_def_whole(dst0, dst1, dst2, src0, src1, src2, count);
683 #else
684 	scale3x_16_def_border(dst0, src0, src1, src2, count);
685 	scale3x_16_def_center(dst1, src0, src1, src2, count);
686 	scale3x_16_def_border(dst2, src2, src1, src0, count);
687 #endif
688 }
689 
690 /**
691  * Scale by a factor of 3 a row of pixels of 32 bits.
692  * This function operates like scale3x_8_def() but for 32 bits pixels.
693  * \param src0 Pointer at the first pixel of the previous row.
694  * \param src1 Pointer at the first pixel of the current row.
695  * \param src2 Pointer at the first pixel of the next row.
696  * \param count Length in pixels of the src0, src1 and src2 rows.
697  * It must be at least 2.
698  * \param dst0 First destination row, triple length in pixels.
699  * \param dst1 Second destination row, triple length in pixels.
700  * \param dst2 Third destination row, triple length in pixels.
701  */
scale3x_32_def(scale3x_uint32 * dst0,scale3x_uint32 * dst1,scale3x_uint32 * dst2,const scale3x_uint32 * src0,const scale3x_uint32 * src1,const scale3x_uint32 * src2,unsigned count)702 void scale3x_32_def(scale3x_uint32* dst0, scale3x_uint32* dst1, scale3x_uint32* dst2, const scale3x_uint32* src0, const scale3x_uint32* src1, const scale3x_uint32* src2, unsigned count)
703 {
704 #ifdef USE_SCALE_RANDOMWRITE
705 	scale3x_32_def_whole(dst0, dst1, dst2, src0, src1, src2, count);
706 #else
707 	scale3x_32_def_border(dst0, src0, src1, src2, count);
708 	scale3x_32_def_center(dst1, src0, src1, src2, count);
709 	scale3x_32_def_border(dst2, src2, src1, src0, count);
710 #endif
711 }
712 
713