diff options
author | Franklin Wei <git@fwei.tk> | 2017-01-21 15:18:31 -0500 |
---|---|---|
committer | Franklin Wei <git@fwei.tk> | 2017-12-23 21:01:26 -0500 |
commit | a855d6202536ff28e5aae4f22a0f31d8f5b325d0 (patch) | |
tree | 8c75f224dd64ed360505afa8843d016b0d75000b /apps/plugins/sdl/src/video/SDL_stretch.c | |
parent | 01c6dcf6c7b9bb1ad2fa0450f99bacc5f3d3e04b (diff) | |
download | rockbox-a855d6202536ff28e5aae4f22a0f31d8f5b325d0.tar.gz rockbox-a855d6202536ff28e5aae4f22a0f31d8f5b325d0.zip |
Port of Duke Nukem 3D
This ports Fabien Sanglard's Chocolate Duke to run on a version of SDL
for Rockbox.
Change-Id: I8f2c4c78af19de10c1633ed7bb7a997b43256dd9
Diffstat (limited to 'apps/plugins/sdl/src/video/SDL_stretch.c')
-rw-r--r-- | apps/plugins/sdl/src/video/SDL_stretch.c | 358 |
1 files changed, 358 insertions, 0 deletions
diff --git a/apps/plugins/sdl/src/video/SDL_stretch.c b/apps/plugins/sdl/src/video/SDL_stretch.c new file mode 100644 index 0000000000..7ce401ff7a --- /dev/null +++ b/apps/plugins/sdl/src/video/SDL_stretch.c | |||
@@ -0,0 +1,358 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 Sam Lantinga | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Lesser General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this library; if not, write to the Free Software | ||
17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | |||
19 | Sam Lantinga | ||
20 | slouken@libsdl.org | ||
21 | */ | ||
22 | #include "SDL_config.h" | ||
23 | |||
24 | /* This a stretch blit implementation based on ideas given to me by | ||
25 | Tomasz Cejner - thanks! :) | ||
26 | |||
27 | April 27, 2000 - Sam Lantinga | ||
28 | */ | ||
29 | |||
30 | #include "SDL_video.h" | ||
31 | #include "SDL_blit.h" | ||
32 | |||
33 | /* This isn't ready for general consumption yet - it should be folded | ||
34 | into the general blitting mechanism. | ||
35 | */ | ||
36 | |||
37 | #if ((defined(_MFC_VER) && defined(_M_IX86)/* && !defined(_WIN32_WCE) still needed? */) || \ | ||
38 | defined(__WATCOMC__) || \ | ||
39 | (defined(__GNUC__) && defined(__i386__))) && SDL_ASSEMBLY_ROUTINES | ||
40 | /* There's a bug with gcc 4.4.1 and -O2 where srcp doesn't get the correct | ||
41 | * value after the first scanline. FIXME? */ | ||
42 | /*#define USE_ASM_STRETCH*/ | ||
43 | #endif | ||
44 | |||
45 | #ifdef USE_ASM_STRETCH | ||
46 | |||
47 | #ifdef HAVE_MPROTECT | ||
48 | #include <sys/types.h> | ||
49 | #include <sys/mman.h> | ||
50 | #endif | ||
51 | #ifdef __GNUC__ | ||
52 | #define PAGE_ALIGNED __attribute__((__aligned__(4096))) | ||
53 | #else | ||
54 | #define PAGE_ALIGNED | ||
55 | #endif | ||
56 | |||
57 | #if defined(_M_IX86) || defined(i386) | ||
58 | #define PREFIX16 0x66 | ||
59 | #define STORE_BYTE 0xAA | ||
60 | #define STORE_WORD 0xAB | ||
61 | #define LOAD_BYTE 0xAC | ||
62 | #define LOAD_WORD 0xAD | ||
63 | #define RETURN 0xC3 | ||
64 | #else | ||
65 | #error Need assembly opcodes for this architecture | ||
66 | #endif | ||
67 | |||
68 | static unsigned char copy_row[4096] PAGE_ALIGNED; | ||
69 | |||
70 | static int generate_rowbytes(int src_w, int dst_w, int bpp) | ||
71 | { | ||
72 | static struct { | ||
73 | int bpp; | ||
74 | int src_w; | ||
75 | int dst_w; | ||
76 | int status; | ||
77 | } last; | ||
78 | |||
79 | int i; | ||
80 | int pos, inc; | ||
81 | unsigned char *eip, *fence; | ||
82 | unsigned char load, store; | ||
83 | |||
84 | /* See if we need to regenerate the copy buffer */ | ||
85 | if ( (src_w == last.src_w) && | ||
86 | (dst_w == last.dst_w) && (bpp == last.bpp) ) { | ||
87 | return(last.status); | ||
88 | } | ||
89 | last.bpp = bpp; | ||
90 | last.src_w = src_w; | ||
91 | last.dst_w = dst_w; | ||
92 | last.status = -1; | ||
93 | |||
94 | switch (bpp) { | ||
95 | case 1: | ||
96 | load = LOAD_BYTE; | ||
97 | store = STORE_BYTE; | ||
98 | break; | ||
99 | case 2: | ||
100 | case 4: | ||
101 | load = LOAD_WORD; | ||
102 | store = STORE_WORD; | ||
103 | break; | ||
104 | default: | ||
105 | SDL_SetError("ASM stretch of %d bytes isn't supported\n", bpp); | ||
106 | return(-1); | ||
107 | } | ||
108 | #ifdef HAVE_MPROTECT | ||
109 | /* Make the code writeable */ | ||
110 | if ( mprotect(copy_row, sizeof(copy_row), PROT_READ|PROT_WRITE) < 0 ) { | ||
111 | SDL_SetError("Couldn't make copy buffer writeable"); | ||
112 | return(-1); | ||
113 | } | ||
114 | #endif | ||
115 | pos = 0x10000; | ||
116 | inc = (src_w << 16) / dst_w; | ||
117 | eip = copy_row; | ||
118 | fence = copy_row+sizeof(copy_row)-2; | ||
119 | for ( i=0; i<dst_w && eip < end; ++i ) { | ||
120 | while ( pos >= 0x10000L ) { | ||
121 | if ( eip == fence ) { | ||
122 | return -1; | ||
123 | } | ||
124 | if ( bpp == 2 ) { | ||
125 | *eip++ = PREFIX16; | ||
126 | } | ||
127 | *eip++ = load; | ||
128 | pos -= 0x10000L; | ||
129 | } | ||
130 | if ( eip == fence ) { | ||
131 | return -1; | ||
132 | } | ||
133 | if ( bpp == 2 ) { | ||
134 | *eip++ = PREFIX16; | ||
135 | } | ||
136 | *eip++ = store; | ||
137 | pos += inc; | ||
138 | } | ||
139 | *eip++ = RETURN; | ||
140 | |||
141 | #ifdef HAVE_MPROTECT | ||
142 | /* Make the code executable but not writeable */ | ||
143 | if ( mprotect(copy_row, sizeof(copy_row), PROT_READ|PROT_EXEC) < 0 ) { | ||
144 | SDL_SetError("Couldn't make copy buffer executable"); | ||
145 | return(-1); | ||
146 | } | ||
147 | #endif | ||
148 | last.status = 0; | ||
149 | return(0); | ||
150 | } | ||
151 | |||
152 | #endif /* USE_ASM_STRETCH */ | ||
153 | |||
154 | #define DEFINE_COPY_ROW(name, type) \ | ||
155 | void name(type *src, int src_w, type *dst, int dst_w) \ | ||
156 | { \ | ||
157 | int i; \ | ||
158 | int pos, inc; \ | ||
159 | type pixel = 0; \ | ||
160 | \ | ||
161 | pos = 0x10000; \ | ||
162 | inc = (src_w << 16) / dst_w; \ | ||
163 | for ( i=dst_w; i>0; --i ) { \ | ||
164 | while ( pos >= 0x10000L ) { \ | ||
165 | pixel = *src++; \ | ||
166 | pos -= 0x10000L; \ | ||
167 | } \ | ||
168 | *dst++ = pixel; \ | ||
169 | pos += inc; \ | ||
170 | } \ | ||
171 | } | ||
172 | DEFINE_COPY_ROW(copy_row1, Uint8) | ||
173 | DEFINE_COPY_ROW(copy_row2, Uint16) | ||
174 | DEFINE_COPY_ROW(copy_row4, Uint32) | ||
175 | |||
176 | /* The ASM code doesn't handle 24-bpp stretch blits */ | ||
177 | void copy_row3(Uint8 *src, int src_w, Uint8 *dst, int dst_w) | ||
178 | { | ||
179 | int i; | ||
180 | int pos, inc; | ||
181 | Uint8 pixel[3] = { 0, 0, 0 }; | ||
182 | |||
183 | pos = 0x10000; | ||
184 | inc = (src_w << 16) / dst_w; | ||
185 | for ( i=dst_w; i>0; --i ) { | ||
186 | while ( pos >= 0x10000L ) { | ||
187 | pixel[0] = *src++; | ||
188 | pixel[1] = *src++; | ||
189 | pixel[2] = *src++; | ||
190 | pos -= 0x10000L; | ||
191 | } | ||
192 | *dst++ = pixel[0]; | ||
193 | *dst++ = pixel[1]; | ||
194 | *dst++ = pixel[2]; | ||
195 | pos += inc; | ||
196 | } | ||
197 | } | ||
198 | |||
199 | /* Perform a stretch blit between two surfaces of the same format. | ||
200 | NOTE: This function is not safe to call from multiple threads! | ||
201 | */ | ||
202 | int SDL_SoftStretch(SDL_Surface *src, SDL_Rect *srcrect, | ||
203 | SDL_Surface *dst, SDL_Rect *dstrect) | ||
204 | { | ||
205 | int src_locked; | ||
206 | int dst_locked; | ||
207 | int pos, inc; | ||
208 | int dst_maxrow; | ||
209 | int src_row, dst_row; | ||
210 | Uint8 *srcp = NULL; | ||
211 | Uint8 *dstp; | ||
212 | SDL_Rect full_src; | ||
213 | SDL_Rect full_dst; | ||
214 | #ifdef USE_ASM_STRETCH | ||
215 | SDL_bool use_asm = SDL_TRUE; | ||
216 | #ifdef __GNUC__ | ||
217 | int u1, u2; | ||
218 | #endif | ||
219 | #endif /* USE_ASM_STRETCH */ | ||
220 | const int bpp = dst->format->BytesPerPixel; | ||
221 | |||
222 | if ( src->format->BitsPerPixel != dst->format->BitsPerPixel ) { | ||
223 | SDL_SetError("Only works with same format surfaces"); | ||
224 | return(-1); | ||
225 | } | ||
226 | |||
227 | /* Verify the blit rectangles */ | ||
228 | if ( srcrect ) { | ||
229 | if ( (srcrect->x < 0) || (srcrect->y < 0) || | ||
230 | ((srcrect->x+srcrect->w) > src->w) || | ||
231 | ((srcrect->y+srcrect->h) > src->h) ) { | ||
232 | SDL_SetError("Invalid source blit rectangle"); | ||
233 | return(-1); | ||
234 | } | ||
235 | } else { | ||
236 | full_src.x = 0; | ||
237 | full_src.y = 0; | ||
238 | full_src.w = src->w; | ||
239 | full_src.h = src->h; | ||
240 | srcrect = &full_src; | ||
241 | } | ||
242 | if ( dstrect ) { | ||
243 | if ( (dstrect->x < 0) || (dstrect->y < 0) || | ||
244 | ((dstrect->x+dstrect->w) > dst->w) || | ||
245 | ((dstrect->y+dstrect->h) > dst->h) ) { | ||
246 | SDL_SetError("Invalid destination blit rectangle"); | ||
247 | return(-1); | ||
248 | } | ||
249 | } else { | ||
250 | full_dst.x = 0; | ||
251 | full_dst.y = 0; | ||
252 | full_dst.w = dst->w; | ||
253 | full_dst.h = dst->h; | ||
254 | dstrect = &full_dst; | ||
255 | } | ||
256 | |||
257 | /* Lock the destination if it's in hardware */ | ||
258 | dst_locked = 0; | ||
259 | if ( SDL_MUSTLOCK(dst) ) { | ||
260 | if ( SDL_LockSurface(dst) < 0 ) { | ||
261 | SDL_SetError("Unable to lock destination surface"); | ||
262 | return(-1); | ||
263 | } | ||
264 | dst_locked = 1; | ||
265 | } | ||
266 | /* Lock the source if it's in hardware */ | ||
267 | src_locked = 0; | ||
268 | if ( SDL_MUSTLOCK(src) ) { | ||
269 | if ( SDL_LockSurface(src) < 0 ) { | ||
270 | if ( dst_locked ) { | ||
271 | SDL_UnlockSurface(dst); | ||
272 | } | ||
273 | SDL_SetError("Unable to lock source surface"); | ||
274 | return(-1); | ||
275 | } | ||
276 | src_locked = 1; | ||
277 | } | ||
278 | |||
279 | /* Set up the data... */ | ||
280 | pos = 0x10000; | ||
281 | inc = (srcrect->h << 16) / dstrect->h; | ||
282 | src_row = srcrect->y; | ||
283 | dst_row = dstrect->y; | ||
284 | |||
285 | #ifdef USE_ASM_STRETCH | ||
286 | /* Write the opcodes for this stretch */ | ||
287 | if ( (bpp == 3) || | ||
288 | (generate_rowbytes(srcrect->w, dstrect->w, bpp) < 0) ) { | ||
289 | use_asm = SDL_FALSE; | ||
290 | } | ||
291 | #endif | ||
292 | |||
293 | /* Perform the stretch blit */ | ||
294 | for ( dst_maxrow = dst_row+dstrect->h; dst_row<dst_maxrow; ++dst_row ) { | ||
295 | dstp = (Uint8 *)dst->pixels + (dst_row*dst->pitch) | ||
296 | + (dstrect->x*bpp); | ||
297 | while ( pos >= 0x10000L ) { | ||
298 | srcp = (Uint8 *)src->pixels + (src_row*src->pitch) | ||
299 | + (srcrect->x*bpp); | ||
300 | ++src_row; | ||
301 | pos -= 0x10000L; | ||
302 | } | ||
303 | #ifdef USE_ASM_STRETCH | ||
304 | if (use_asm) { | ||
305 | #ifdef __GNUC__ | ||
306 | __asm__ __volatile__ ( | ||
307 | "call *%4" | ||
308 | : "=&D" (u1), "=&S" (u2) | ||
309 | : "0" (dstp), "1" (srcp), "r" (copy_row) | ||
310 | : "memory" ); | ||
311 | #elif defined(_MSC_VER) || defined(__WATCOMC__) | ||
312 | { void *code = copy_row; | ||
313 | __asm { | ||
314 | push edi | ||
315 | push esi | ||
316 | |||
317 | mov edi, dstp | ||
318 | mov esi, srcp | ||
319 | call dword ptr code | ||
320 | |||
321 | pop esi | ||
322 | pop edi | ||
323 | } | ||
324 | } | ||
325 | #else | ||
326 | #error Need inline assembly for this compiler | ||
327 | #endif | ||
328 | } else | ||
329 | #endif | ||
330 | switch (bpp) { | ||
331 | case 1: | ||
332 | copy_row1(srcp, srcrect->w, dstp, dstrect->w); | ||
333 | break; | ||
334 | case 2: | ||
335 | copy_row2((Uint16 *)srcp, srcrect->w, | ||
336 | (Uint16 *)dstp, dstrect->w); | ||
337 | break; | ||
338 | case 3: | ||
339 | copy_row3(srcp, srcrect->w, dstp, dstrect->w); | ||
340 | break; | ||
341 | case 4: | ||
342 | copy_row4((Uint32 *)srcp, srcrect->w, | ||
343 | (Uint32 *)dstp, dstrect->w); | ||
344 | break; | ||
345 | } | ||
346 | pos += inc; | ||
347 | } | ||
348 | |||
349 | /* We need to unlock the surfaces if they're locked */ | ||
350 | if ( dst_locked ) { | ||
351 | SDL_UnlockSurface(dst); | ||
352 | } | ||
353 | if ( src_locked ) { | ||
354 | SDL_UnlockSurface(src); | ||
355 | } | ||
356 | return(0); | ||
357 | } | ||
358 | |||