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) {