Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5131 | clevermous | 1 | /* |
2 | SDL - Simple DirectMedia Layer |
||
3 | Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga |
||
4 | |||
5 | This library is free software; you can redistribute it and/or |
||
6 | modify it under the terms of the GNU Library General Public |
||
7 | License as published by the Free Software Foundation; either |
||
8 | version 2 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 | Library General Public License for more details. |
||
14 | |||
15 | You should have received a copy of the GNU Library General Public |
||
16 | License along with this library; if not, write to the Free |
||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||
18 | |||
19 | Sam Lantinga |
||
20 | slouken@devolution.com |
||
21 | */ |
||
22 | |||
23 | /* This a stretch blit implementation based on ideas given to me by |
||
24 | Tomasz Cejner - thanks! :) |
||
25 | |||
26 | April 27, 2000 - Sam Lantinga |
||
27 | */ |
||
28 | |||
29 | #include "SDL_error.h" |
||
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(WIN32UNDEFINED) && !defined(_M_ALPHA) && !defined(_WIN32_WCE)) || \ |
||
38 | defined(i386) && defined(__GNUC__) && defined(USE_ASMBLIT) |
||
39 | #define USE_ASM_STRETCH |
||
40 | #endif |
||
41 | |||
42 | #ifdef USE_ASM_STRETCH |
||
43 | |||
44 | #if defined(WIN32UNDEFINED) || defined(i386) |
||
45 | #define PREFIX16 0x66 |
||
46 | #define STORE_BYTE 0xAA |
||
47 | #define STORE_WORD 0xAB |
||
48 | #define LOAD_BYTE 0xAC |
||
49 | #define LOAD_WORD 0xAD |
||
50 | #define RETURN 0xC3 |
||
51 | #else |
||
52 | #error Need assembly opcodes for this architecture |
||
53 | #endif |
||
54 | |||
55 | #if defined(__ELF__) && defined(__GNUC__) |
||
56 | extern unsigned char _copy_row[4096] __attribute__ ((alias ("copy_row"))); |
||
57 | #endif |
||
58 | static unsigned char copy_row[4096]; |
||
59 | |||
60 | static int generate_rowbytes(int src_w, int dst_w, int bpp) |
||
61 | { |
||
62 | static struct { |
||
63 | int bpp; |
||
64 | int src_w; |
||
65 | int dst_w; |
||
66 | } last; |
||
67 | |||
68 | int i; |
||
69 | int pos, inc; |
||
70 | unsigned char *eip; |
||
71 | unsigned char load, store; |
||
72 | |||
73 | /* See if we need to regenerate the copy buffer */ |
||
74 | if ( (src_w == last.src_w) && |
||
75 | (dst_w == last.src_w) && (bpp == last.bpp) ) { |
||
76 | return(0); |
||
77 | } |
||
78 | last.bpp = bpp; |
||
79 | last.src_w = src_w; |
||
80 | last.dst_w = dst_w; |
||
81 | |||
82 | switch (bpp) { |
||
83 | case 1: |
||
84 | load = LOAD_BYTE; |
||
85 | store = STORE_BYTE; |
||
86 | break; |
||
87 | case 2: |
||
88 | case 4: |
||
89 | load = LOAD_WORD; |
||
90 | store = STORE_WORD; |
||
91 | break; |
||
92 | default: |
||
93 | SDL_SetError("ASM stretch of %d bytes isn't supported\n", bpp); |
||
94 | return(-1); |
||
95 | } |
||
96 | pos = 0x10000; |
||
97 | inc = (src_w << 16) / dst_w; |
||
98 | eip = copy_row; |
||
99 | for ( i=0; i |
||
100 | while ( pos >= 0x10000L ) { |
||
101 | if ( bpp == 2 ) { |
||
102 | *eip++ = PREFIX16; |
||
103 | } |
||
104 | *eip++ = load; |
||
105 | pos -= 0x10000L; |
||
106 | } |
||
107 | if ( bpp == 2 ) { |
||
108 | *eip++ = PREFIX16; |
||
109 | } |
||
110 | *eip++ = store; |
||
111 | pos += inc; |
||
112 | } |
||
113 | *eip++ = RETURN; |
||
114 | |||
115 | /* Verify that we didn't overflow (too late) */ |
||
116 | if ( eip > (copy_row+sizeof(copy_row)) ) { |
||
117 | SDL_SetError("Copy buffer overflow"); |
||
118 | return(-1); |
||
119 | } |
||
120 | return(0); |
||
121 | } |
||
122 | |||
123 | #else |
||
124 | |||
125 | #define DEFINE_COPY_ROW(name, type) \ |
||
126 | void name(type *src, int src_w, type *dst, int dst_w) \ |
||
127 | { \ |
||
128 | int i; \ |
||
129 | int pos, inc; \ |
||
130 | type pixel = 0; \ |
||
131 | \ |
||
132 | pos = 0x10000; \ |
||
133 | inc = (src_w << 16) / dst_w; \ |
||
134 | for ( i=dst_w; i>0; --i ) { \ |
||
135 | while ( pos >= 0x10000L ) { \ |
||
136 | pixel = *src++; \ |
||
137 | pos -= 0x10000L; \ |
||
138 | } \ |
||
139 | *dst++ = pixel; \ |
||
140 | pos += inc; \ |
||
141 | } \ |
||
142 | } |
||
143 | DEFINE_COPY_ROW(copy_row1, Uint8) |
||
144 | DEFINE_COPY_ROW(copy_row2, Uint16) |
||
145 | DEFINE_COPY_ROW(copy_row4, Uint32) |
||
146 | |||
147 | #endif /* USE_ASM_STRETCH */ |
||
148 | |||
149 | /* The ASM code doesn't handle 24-bpp stretch blits */ |
||
150 | void copy_row3(Uint8 *src, int src_w, Uint8 *dst, int dst_w) |
||
151 | { |
||
152 | int i; |
||
153 | int pos, inc; |
||
154 | Uint8 pixel[3]; |
||
155 | |||
156 | pos = 0x10000; |
||
157 | inc = (src_w << 16) / dst_w; |
||
158 | for ( i=dst_w; i>0; --i ) { |
||
159 | while ( pos >= 0x10000L ) { |
||
160 | pixel[0] = *src++; |
||
161 | pixel[1] = *src++; |
||
162 | pixel[2] = *src++; |
||
163 | pos -= 0x10000L; |
||
164 | } |
||
165 | *dst++ = pixel[0]; |
||
166 | *dst++ = pixel[1]; |
||
167 | *dst++ = pixel[2]; |
||
168 | pos += inc; |
||
169 | } |
||
170 | } |
||
171 | |||
172 | /* Perform a stretch blit between two surfaces of the same format. |
||
173 | NOTE: This function is not safe to call from multiple threads! |
||
174 | */ |
||
175 | int SDL_SoftStretch(SDL_Surface *src, SDL_Rect *srcrect, |
||
176 | SDL_Surface *dst, SDL_Rect *dstrect) |
||
177 | { |
||
178 | int pos, inc; |
||
179 | int dst_width; |
||
180 | int dst_maxrow; |
||
181 | int src_row, dst_row; |
||
182 | Uint8 *srcp = NULL; |
||
183 | Uint8 *dstp; |
||
184 | SDL_Rect full_src; |
||
185 | SDL_Rect full_dst; |
||
186 | #if defined(USE_ASM_STRETCH) && defined(__GNUC__) |
||
187 | int u1, u2; |
||
188 | #endif |
||
189 | const int bpp = dst->format->BytesPerPixel; |
||
190 | |||
191 | if ( src->format->BitsPerPixel != dst->format->BitsPerPixel ) { |
||
192 | SDL_SetError("Only works with same format surfaces"); |
||
193 | return(-1); |
||
194 | } |
||
195 | |||
196 | /* Verify the blit rectangles */ |
||
197 | if ( srcrect ) { |
||
198 | if ( (srcrect->x < 0) || (srcrect->y < 0) || |
||
199 | ((srcrect->x+srcrect->w) > src->w) || |
||
200 | ((srcrect->y+srcrect->h) > src->h) ) { |
||
201 | SDL_SetError("Invalid source blit rectangle"); |
||
202 | return(-1); |
||
203 | } |
||
204 | } else { |
||
205 | full_src.x = 0; |
||
206 | full_src.y = 0; |
||
207 | full_src.w = src->w; |
||
208 | full_src.h = src->h; |
||
209 | srcrect = &full_src; |
||
210 | } |
||
211 | if ( dstrect ) { |
||
212 | if ( (dstrect->x < 0) || (dstrect->y < 0) || |
||
213 | ((dstrect->x+dstrect->w) > dst->w) || |
||
214 | ((dstrect->y+dstrect->h) > dst->h) ) { |
||
215 | SDL_SetError("Invalid destination blit rectangle"); |
||
216 | return(-1); |
||
217 | } |
||
218 | } else { |
||
219 | full_dst.x = 0; |
||
220 | full_dst.y = 0; |
||
221 | full_dst.w = dst->w; |
||
222 | full_dst.h = dst->h; |
||
223 | dstrect = &full_dst; |
||
224 | } |
||
225 | |||
226 | /* Set up the data... */ |
||
227 | pos = 0x10000; |
||
228 | inc = (srcrect->h << 16) / dstrect->h; |
||
229 | src_row = srcrect->y; |
||
230 | dst_row = dstrect->y; |
||
231 | dst_width = dstrect->w*bpp; |
||
232 | |||
233 | #ifdef USE_ASM_STRETCH |
||
234 | /* Write the opcodes for this stretch */ |
||
235 | if ( (bpp != 3) && |
||
236 | (generate_rowbytes(srcrect->w, dstrect->w, bpp) < 0) ) { |
||
237 | return(-1); |
||
238 | } |
||
239 | #endif |
||
240 | |||
241 | /* Perform the stretch blit */ |
||
242 | for ( dst_maxrow = dst_row+dstrect->h; dst_row |
||
243 | dstp = (Uint8 *)dst->pixels + (dst_row*dst->pitch) |
||
244 | + (dstrect->x*bpp); |
||
245 | while ( pos >= 0x10000L ) { |
||
246 | srcp = (Uint8 *)src->pixels + (src_row*src->pitch) |
||
247 | + (srcrect->x*bpp); |
||
248 | ++src_row; |
||
249 | pos -= 0x10000L; |
||
250 | } |
||
251 | #ifdef USE_ASM_STRETCH |
||
252 | switch (bpp) { |
||
253 | case 3: |
||
254 | copy_row3(srcp, srcrect->w, dstp, dstrect->w); |
||
255 | break; |
||
256 | default: |
||
257 | #ifdef __GNUC__ |
||
258 | __asm__ __volatile__ ("call _copy_row" |
||
259 | : "=&D" (u1), "=&S" (u2) |
||
260 | : "0" (dstp), "1" (srcp) |
||
261 | : "memory" ); |
||
262 | #else |
||
263 | #ifdef WIN32UNDEFINED |
||
264 | { void *code = ©_row; |
||
265 | __asm { |
||
266 | push edi |
||
267 | push esi |
||
268 | |||
269 | mov edi, dstp |
||
270 | mov esi, srcp |
||
271 | call dword ptr code |
||
272 | |||
273 | pop esi |
||
274 | pop edi |
||
275 | } |
||
276 | } |
||
277 | #else |
||
278 | #error Need inline assembly for this compiler |
||
279 | #endif |
||
280 | #endif /* __GNUC__ */ |
||
281 | break; |
||
282 | } |
||
283 | #else |
||
284 | switch (bpp) { |
||
285 | case 1: |
||
286 | copy_row1(srcp, srcrect->w, dstp, dstrect->w); |
||
287 | break; |
||
288 | case 2: |
||
289 | copy_row2((Uint16 *)srcp, srcrect->w, |
||
290 | (Uint16 *)dstp, dstrect->w); |
||
291 | break; |
||
292 | case 3: |
||
293 | copy_row3(srcp, srcrect->w, dstp, dstrect->w); |
||
294 | break; |
||
295 | case 4: |
||
296 | copy_row4((Uint32 *)srcp, srcrect->w, |
||
297 | (Uint32 *)dstp, dstrect->w); |
||
298 | break; |
||
299 | } |
||
300 | #endif |
||
301 | pos += inc; |
||
302 | } |
||
303 | return(0); |
||
304 | }>><>>>>>><>><>><> |
||
305 |