Mercurial > sdl-ios-xcode
comparison src/video/SDL_stretch.c @ 3405:d5f2dd33f4eb
Merged improvements to SDL_SoftStretch() from SDL 1.2
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Sun, 18 Oct 2009 17:49:40 +0000 |
parents | 99210400e8b9 |
children | 8ae607392409 |
comparison
equal
deleted
inserted
replaced
3404:c9dcc73f6a36 | 3405:d5f2dd33f4eb |
---|---|
39 (defined(__GNUC__) && defined(__i386__))) && SDL_ASSEMBLY_ROUTINES | 39 (defined(__GNUC__) && defined(__i386__))) && SDL_ASSEMBLY_ROUTINES |
40 #define USE_ASM_STRETCH | 40 #define USE_ASM_STRETCH |
41 #endif | 41 #endif |
42 | 42 |
43 #ifdef USE_ASM_STRETCH | 43 #ifdef USE_ASM_STRETCH |
44 | |
45 #ifdef HAVE_MPROTECT | |
46 #include <sys/types.h> | |
47 #include <sys/mman.h> | |
48 #endif | |
49 #ifdef __GNUC__ | |
50 #define PAGE_ALIGNED __attribute__((__aligned__(4096))) | |
51 #else | |
52 #define PAGE_ALIGNED | |
53 #endif | |
44 | 54 |
45 #if defined(_M_IX86) || defined(i386) | 55 #if defined(_M_IX86) || defined(i386) |
46 #define PREFIX16 0x66 | 56 #define PREFIX16 0x66 |
47 #define STORE_BYTE 0xAA | 57 #define STORE_BYTE 0xAA |
48 #define STORE_WORD 0xAB | 58 #define STORE_WORD 0xAB |
51 #define RETURN 0xC3 | 61 #define RETURN 0xC3 |
52 #else | 62 #else |
53 #error Need assembly opcodes for this architecture | 63 #error Need assembly opcodes for this architecture |
54 #endif | 64 #endif |
55 | 65 |
56 static unsigned char copy_row[4096]; | 66 static unsigned char copy_row[4096] PAGE_ALIGNED; |
57 | 67 |
58 static int | 68 static int |
59 generate_rowbytes(int src_w, int dst_w, int bpp) | 69 generate_rowbytes(int src_w, int dst_w, int bpp) |
60 { | 70 { |
61 static struct | 71 static struct |
62 { | 72 { |
63 int bpp; | 73 int bpp; |
64 int src_w; | 74 int src_w; |
65 int dst_w; | 75 int dst_w; |
76 int status; | |
66 } last; | 77 } last; |
67 | 78 |
68 int i; | 79 int i; |
69 int pos, inc; | 80 int pos, inc; |
70 unsigned char *eip; | 81 unsigned char *eip; |
71 unsigned char load, store; | 82 unsigned char load, store; |
72 | 83 |
73 /* See if we need to regenerate the copy buffer */ | 84 /* See if we need to regenerate the copy buffer */ |
74 if ((src_w == last.src_w) && (dst_w == last.dst_w) && (bpp == last.bpp)) { | 85 if ((src_w == last.src_w) && (dst_w == last.dst_w) && (bpp == last.bpp)) { |
75 return (0); | 86 return (last.status); |
76 } | 87 } |
77 last.bpp = bpp; | 88 last.bpp = bpp; |
78 last.src_w = src_w; | 89 last.src_w = src_w; |
79 last.dst_w = dst_w; | 90 last.dst_w = dst_w; |
91 last.status = -1; | |
80 | 92 |
81 switch (bpp) { | 93 switch (bpp) { |
82 case 1: | 94 case 1: |
83 load = LOAD_BYTE; | 95 load = LOAD_BYTE; |
84 store = STORE_BYTE; | 96 store = STORE_BYTE; |
90 break; | 102 break; |
91 default: | 103 default: |
92 SDL_SetError("ASM stretch of %d bytes isn't supported\n", bpp); | 104 SDL_SetError("ASM stretch of %d bytes isn't supported\n", bpp); |
93 return (-1); | 105 return (-1); |
94 } | 106 } |
107 #ifdef HAVE_MPROTECT | |
108 /* Make the code writeable */ | |
109 if (mprotect(copy_row, sizeof(copy_row), PROT_READ | PROT_WRITE) < 0) { | |
110 SDL_SetError("Couldn't make copy buffer writeable"); | |
111 return (-1); | |
112 } | |
113 #endif | |
95 pos = 0x10000; | 114 pos = 0x10000; |
96 inc = (src_w << 16) / dst_w; | 115 inc = (src_w << 16) / dst_w; |
97 eip = copy_row; | 116 eip = copy_row; |
98 for (i = 0; i < dst_w; ++i) { | 117 for (i = 0; i < dst_w; ++i) { |
99 while (pos >= 0x10000L) { | 118 while (pos >= 0x10000L) { |
109 *eip++ = store; | 128 *eip++ = store; |
110 pos += inc; | 129 pos += inc; |
111 } | 130 } |
112 *eip++ = RETURN; | 131 *eip++ = RETURN; |
113 | 132 |
114 /* Verify that we didn't overflow (too late) */ | 133 /* Verify that we didn't overflow (too late!!!) */ |
115 if (eip > (copy_row + sizeof(copy_row))) { | 134 if (eip > (copy_row + sizeof(copy_row))) { |
116 SDL_SetError("Copy buffer overflow"); | 135 SDL_SetError("Copy buffer overflow"); |
117 return (-1); | 136 return (-1); |
118 } | 137 } |
138 #ifdef HAVE_MPROTECT | |
139 /* Make the code executable but not writeable */ | |
140 if (mprotect(copy_row, sizeof(copy_row), PROT_READ | PROT_EXEC) < 0) { | |
141 SDL_SetError("Couldn't make copy buffer executable"); | |
142 return (-1); | |
143 } | |
144 #endif | |
145 last.status = 0; | |
119 return (0); | 146 return (0); |
120 } | 147 } |
121 | 148 |
122 #else | 149 #endif /* USE_ASM_STRETCH */ |
123 | 150 |
124 #define DEFINE_COPY_ROW(name, type) \ | 151 #define DEFINE_COPY_ROW(name, type) \ |
125 void name(type *src, int src_w, type *dst, int dst_w) \ | 152 void name(type *src, int src_w, type *dst, int dst_w) \ |
126 { \ | 153 { \ |
127 int i; \ | 154 int i; \ |
128 int pos, inc; \ | 155 int pos, inc; \ |
129 type pixel = 0; \ | 156 type pixel = 0; \ |
130 \ | 157 \ |
131 pos = 0x10000; \ | 158 pos = 0x10000; \ |
132 inc = (src_w << 16) / dst_w; \ | 159 inc = (src_w << 16) / dst_w; \ |
133 for ( i=dst_w; i>0; --i ) { \ | 160 for ( i=dst_w; i>0; --i ) { \ |
134 while ( pos >= 0x10000L ) { \ | 161 while ( pos >= 0x10000L ) { \ |
135 pixel = *src++; \ | 162 pixel = *src++; \ |
136 pos -= 0x10000L; \ | 163 pos -= 0x10000L; \ |
137 } \ | 164 } \ |
138 *dst++ = pixel; \ | 165 *dst++ = pixel; \ |
139 pos += inc; \ | 166 pos += inc; \ |
140 } \ | 167 } \ |
141 } | 168 } |
142 /* *INDENT-OFF* */ | 169 /* *INDENT-OFF* */ |
143 DEFINE_COPY_ROW(copy_row1, Uint8) | 170 DEFINE_COPY_ROW(copy_row1, Uint8) |
144 DEFINE_COPY_ROW(copy_row2, Uint16) | 171 DEFINE_COPY_ROW(copy_row2, Uint16) |
145 DEFINE_COPY_ROW(copy_row4, Uint32) | 172 DEFINE_COPY_ROW(copy_row4, Uint32) |
146 /* *INDENT-ON* */ | 173 /* *INDENT-ON* */ |
147 #endif /* USE_ASM_STRETCH */ | 174 |
148 /* The ASM code doesn't handle 24-bpp stretch blits */ | 175 /* The ASM code doesn't handle 24-bpp stretch blits */ |
149 void | 176 void |
150 copy_row3(Uint8 * src, int src_w, Uint8 * dst, int dst_w) | 177 copy_row3(Uint8 * src, int src_w, Uint8 * dst, int dst_w) |
151 { | 178 { |
152 int i; | 179 int i; |
153 int pos, inc; | 180 int pos, inc; |
154 Uint8 pixel[3]; | 181 Uint8 pixel[3] = { 0, 0, 0 }; |
155 | 182 |
156 pos = 0x10000; | 183 pos = 0x10000; |
157 inc = (src_w << 16) / dst_w; | 184 inc = (src_w << 16) / dst_w; |
158 for (i = dst_w; i > 0; --i) { | 185 for (i = dst_w; i > 0; --i) { |
159 while (pos >= 0x10000L) { | 186 while (pos >= 0x10000L) { |
184 int src_row, dst_row; | 211 int src_row, dst_row; |
185 Uint8 *srcp = NULL; | 212 Uint8 *srcp = NULL; |
186 Uint8 *dstp; | 213 Uint8 *dstp; |
187 SDL_Rect full_src; | 214 SDL_Rect full_src; |
188 SDL_Rect full_dst; | 215 SDL_Rect full_dst; |
189 #if defined(USE_ASM_STRETCH) && defined(__GNUC__) | 216 #ifdef USE_ASM_STRETCH |
217 SDL_bool use_asm = SDL_TRUE; | |
218 #ifdef __GNUC__ | |
190 int u1, u2; | 219 int u1, u2; |
191 #endif | 220 #endif |
221 #endif /* USE_ASM_STRETCH */ | |
192 const int bpp = dst->format->BytesPerPixel; | 222 const int bpp = dst->format->BytesPerPixel; |
193 | 223 |
194 if (src->format->BitsPerPixel != dst->format->BitsPerPixel) { | 224 if (src->format->BitsPerPixel != dst->format->BitsPerPixel) { |
195 SDL_SetError("Only works with same format surfaces"); | 225 SDL_SetError("Only works with same format surfaces"); |
196 return (-1); | 226 return (-1); |
255 dst_row = dstrect->y; | 285 dst_row = dstrect->y; |
256 dst_width = dstrect->w * bpp; | 286 dst_width = dstrect->w * bpp; |
257 | 287 |
258 #ifdef USE_ASM_STRETCH | 288 #ifdef USE_ASM_STRETCH |
259 /* Write the opcodes for this stretch */ | 289 /* Write the opcodes for this stretch */ |
260 if ((bpp != 3) && (generate_rowbytes(srcrect->w, dstrect->w, bpp) < 0)) { | 290 if ((bpp == 3) || (generate_rowbytes(srcrect->w, dstrect->w, bpp) < 0)) { |
261 return (-1); | 291 use_asm = SDL_FALSE; |
262 } | 292 } |
263 #endif | 293 #endif |
264 | 294 |
265 /* Perform the stretch blit */ | 295 /* Perform the stretch blit */ |
266 for (dst_maxrow = dst_row + dstrect->h; dst_row < dst_maxrow; ++dst_row) { | 296 for (dst_maxrow = dst_row + dstrect->h; dst_row < dst_maxrow; ++dst_row) { |
271 + (srcrect->x * bpp); | 301 + (srcrect->x * bpp); |
272 ++src_row; | 302 ++src_row; |
273 pos -= 0x10000L; | 303 pos -= 0x10000L; |
274 } | 304 } |
275 #ifdef USE_ASM_STRETCH | 305 #ifdef USE_ASM_STRETCH |
276 switch (bpp) { | 306 if (use_asm) { |
277 case 3: | |
278 copy_row3(srcp, srcrect->w, dstp, dstrect->w); | |
279 break; | |
280 default: | |
281 #ifdef __GNUC__ | 307 #ifdef __GNUC__ |
282 __asm__ __volatile__("call *%4": "=&D"(u1), "=&S"(u2): "0"(dstp), "1"(srcp), "r"(copy_row):"memory"); | 308 __asm__ __volatile__("call *%4":"=&D"(u1), "=&S"(u2) |
309 :"0"(dstp), "1"(srcp), "r"(copy_row) | |
310 :"memory"); | |
283 #elif defined(_MSC_VER) || defined(__WATCOMC__) | 311 #elif defined(_MSC_VER) || defined(__WATCOMC__) |
284 /* *INDENT-OFF* */ | 312 /* *INDENT-OFF* */ |
285 { | 313 { |
286 void *code = copy_row; | 314 void *code = copy_row; |
287 __asm { | 315 __asm { |
296 } | 324 } |
297 /* *INDENT-ON* */ | 325 /* *INDENT-ON* */ |
298 #else | 326 #else |
299 #error Need inline assembly for this compiler | 327 #error Need inline assembly for this compiler |
300 #endif | 328 #endif |
301 break; | 329 } else |
302 } | 330 #endif |
303 #else | 331 switch (bpp) { |
304 switch (bpp) { | 332 case 1: |
305 case 1: | 333 copy_row1(srcp, srcrect->w, dstp, dstrect->w); |
306 copy_row1(srcp, srcrect->w, dstp, dstrect->w); | 334 break; |
307 break; | 335 case 2: |
308 case 2: | 336 copy_row2((Uint16 *) srcp, srcrect->w, |
309 copy_row2((Uint16 *) srcp, srcrect->w, | 337 (Uint16 *) dstp, dstrect->w); |
310 (Uint16 *) dstp, dstrect->w); | 338 break; |
311 break; | 339 case 3: |
312 case 3: | 340 copy_row3(srcp, srcrect->w, dstp, dstrect->w); |
313 copy_row3(srcp, srcrect->w, dstp, dstrect->w); | 341 break; |
314 break; | 342 case 4: |
315 case 4: | 343 copy_row4((Uint32 *) srcp, srcrect->w, |
316 copy_row4((Uint32 *) srcp, srcrect->w, | 344 (Uint32 *) dstp, dstrect->w); |
317 (Uint32 *) dstp, dstrect->w); | 345 break; |
318 break; | 346 } |
319 } | |
320 #endif | |
321 pos += inc; | 347 pos += inc; |
322 } | 348 } |
323 | 349 |
324 /* We need to unlock the surfaces if they're locked */ | 350 /* We need to unlock the surfaces if they're locked */ |
325 if (dst_locked) { | 351 if (dst_locked) { |