e14743d1 |
1 | /* |
2 | SDL - Simple DirectMedia Layer |
3 | Copyright (C) 1997-2009 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 | #include "SDL_video.h" |
25 | #include "SDL_sysvideo.h" |
26 | #include "SDL_blit.h" |
27 | #include "SDL_RLEaccel_c.h" |
28 | #include "SDL_pixels_c.h" |
29 | |
30 | #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && SDL_ASSEMBLY_ROUTINES |
31 | #define MMX_ASMBLIT |
32 | #if (__GNUC__ > 2) /* SSE instructions aren't in GCC 2. */ |
33 | #define SSE_ASMBLIT |
34 | #endif |
35 | #endif |
36 | |
37 | #if defined(MMX_ASMBLIT) |
38 | #include "SDL_cpuinfo.h" |
39 | #include "mmx.h" |
40 | #endif |
41 | |
42 | /* The general purpose software blit routine */ |
43 | static int SDL_SoftBlit(SDL_Surface *src, SDL_Rect *srcrect, |
44 | SDL_Surface *dst, SDL_Rect *dstrect) |
45 | { |
46 | int okay; |
47 | int src_locked; |
48 | int dst_locked; |
49 | |
50 | /* Everything is okay at the beginning... */ |
51 | okay = 1; |
52 | |
53 | /* Lock the destination if it's in hardware */ |
54 | dst_locked = 0; |
55 | if ( SDL_MUSTLOCK(dst) ) { |
56 | if ( SDL_LockSurface(dst) < 0 ) { |
57 | okay = 0; |
58 | } else { |
59 | dst_locked = 1; |
60 | } |
61 | } |
62 | /* Lock the source if it's in hardware */ |
63 | src_locked = 0; |
64 | if ( SDL_MUSTLOCK(src) ) { |
65 | if ( SDL_LockSurface(src) < 0 ) { |
66 | okay = 0; |
67 | } else { |
68 | src_locked = 1; |
69 | } |
70 | } |
71 | |
72 | /* Set up source and destination buffer pointers, and BLIT! */ |
73 | if ( okay && srcrect->w && srcrect->h ) { |
74 | SDL_BlitInfo info; |
75 | SDL_loblit RunBlit; |
76 | |
77 | /* Set up the blit information */ |
78 | info.s_pixels = (Uint8 *)src->pixels + |
79 | (Uint16)srcrect->y*src->pitch + |
80 | (Uint16)srcrect->x*src->format->BytesPerPixel; |
81 | info.s_width = srcrect->w; |
82 | info.s_height = srcrect->h; |
83 | info.s_skip=src->pitch-info.s_width*src->format->BytesPerPixel; |
84 | info.d_pixels = (Uint8 *)dst->pixels + |
85 | (Uint16)dstrect->y*dst->pitch + |
86 | (Uint16)dstrect->x*dst->format->BytesPerPixel; |
87 | info.d_width = dstrect->w; |
88 | info.d_height = dstrect->h; |
89 | info.d_skip=dst->pitch-info.d_width*dst->format->BytesPerPixel; |
90 | info.aux_data = src->map->sw_data->aux_data; |
91 | info.src = src->format; |
92 | info.table = src->map->table; |
93 | info.dst = dst->format; |
94 | RunBlit = src->map->sw_data->blit; |
95 | |
96 | /* Run the actual software blit */ |
97 | RunBlit(&info); |
98 | } |
99 | |
100 | /* We need to unlock the surfaces if they're locked */ |
101 | if ( dst_locked ) { |
102 | SDL_UnlockSurface(dst); |
103 | } |
104 | if ( src_locked ) { |
105 | SDL_UnlockSurface(src); |
106 | } |
107 | /* Blit is done! */ |
108 | return(okay ? 0 : -1); |
109 | } |
110 | |
111 | #ifdef MMX_ASMBLIT |
112 | static __inline__ void SDL_memcpyMMX(Uint8 *to, const Uint8 *from, int len) |
113 | { |
114 | int i; |
115 | |
116 | for(i=0; i<len/8; i++) { |
117 | __asm__ __volatile__ ( |
118 | " movq (%0), %%mm0\n" |
119 | " movq %%mm0, (%1)\n" |
120 | : : "r" (from), "r" (to) : "memory"); |
121 | from+=8; |
122 | to+=8; |
123 | } |
124 | if (len&7) |
125 | SDL_memcpy(to, from, len&7); |
126 | } |
127 | |
128 | #ifdef SSE_ASMBLIT |
129 | static __inline__ void SDL_memcpySSE(Uint8 *to, const Uint8 *from, int len) |
130 | { |
131 | int i; |
132 | |
133 | __asm__ __volatile__ ( |
134 | " prefetchnta (%0)\n" |
135 | " prefetchnta 64(%0)\n" |
136 | " prefetchnta 128(%0)\n" |
137 | " prefetchnta 192(%0)\n" |
138 | : : "r" (from) ); |
139 | |
140 | for(i=0; i<len/8; i++) { |
141 | __asm__ __volatile__ ( |
142 | " prefetchnta 256(%0)\n" |
143 | " movq (%0), %%mm0\n" |
144 | " movntq %%mm0, (%1)\n" |
145 | : : "r" (from), "r" (to) : "memory"); |
146 | from+=8; |
147 | to+=8; |
148 | } |
149 | if (len&7) |
150 | SDL_memcpy(to, from, len&7); |
151 | } |
152 | #endif |
153 | #endif |
154 | |
155 | static void SDL_BlitCopy(SDL_BlitInfo *info) |
156 | { |
157 | Uint8 *src, *dst; |
158 | int w, h; |
159 | int srcskip, dstskip; |
160 | |
161 | w = info->d_width*info->dst->BytesPerPixel; |
162 | h = info->d_height; |
163 | src = info->s_pixels; |
164 | dst = info->d_pixels; |
165 | srcskip = w+info->s_skip; |
166 | dstskip = w+info->d_skip; |
167 | |
168 | #ifdef SSE_ASMBLIT |
169 | if(SDL_HasSSE()) |
170 | { |
171 | while ( h-- ) { |
172 | SDL_memcpySSE(dst, src, w); |
173 | src += srcskip; |
174 | dst += dstskip; |
175 | } |
176 | __asm__ __volatile__ ( |
177 | " emms\n" |
178 | ::); |
179 | } |
180 | else |
181 | #endif |
182 | #ifdef MMX_ASMBLIT |
183 | if(SDL_HasMMX()) |
184 | { |
185 | while ( h-- ) { |
186 | SDL_memcpyMMX(dst, src, w); |
187 | src += srcskip; |
188 | dst += dstskip; |
189 | } |
190 | __asm__ __volatile__ ( |
191 | " emms\n" |
192 | ::); |
193 | } |
194 | else |
195 | #endif |
196 | while ( h-- ) { |
197 | SDL_memcpy(dst, src, w); |
198 | src += srcskip; |
199 | dst += dstskip; |
200 | } |
201 | } |
202 | |
203 | static void SDL_BlitCopyOverlap(SDL_BlitInfo *info) |
204 | { |
205 | Uint8 *src, *dst; |
206 | int w, h; |
207 | int srcskip, dstskip; |
208 | |
209 | w = info->d_width*info->dst->BytesPerPixel; |
210 | h = info->d_height; |
211 | src = info->s_pixels; |
212 | dst = info->d_pixels; |
213 | srcskip = w+info->s_skip; |
214 | dstskip = w+info->d_skip; |
215 | if ( dst < src ) { |
216 | while ( h-- ) { |
217 | SDL_memcpy(dst, src, w); |
218 | src += srcskip; |
219 | dst += dstskip; |
220 | } |
221 | } else { |
222 | src += ((h-1) * srcskip); |
223 | dst += ((h-1) * dstskip); |
224 | while ( h-- ) { |
225 | SDL_revcpy(dst, src, w); |
226 | src -= srcskip; |
227 | dst -= dstskip; |
228 | } |
229 | } |
230 | } |
231 | |
232 | /* Figure out which of many blit routines to set up on a surface */ |
233 | int SDL_CalculateBlit(SDL_Surface *surface) |
234 | { |
235 | int blit_index; |
236 | |
237 | /* Clean everything out to start */ |
238 | if ( (surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL ) { |
239 | SDL_UnRLESurface(surface, 1); |
240 | } |
241 | surface->map->sw_blit = NULL; |
242 | |
243 | /* Figure out if an accelerated hardware blit is possible */ |
244 | surface->flags &= ~SDL_HWACCEL; |
245 | if ( surface->map->identity ) { |
246 | int hw_blit_ok; |
247 | |
248 | if ( (surface->flags & SDL_HWSURFACE) == SDL_HWSURFACE ) { |
249 | /* We only support accelerated blitting to hardware */ |
250 | if ( surface->map->dst->flags & SDL_HWSURFACE ) { |
251 | hw_blit_ok = current_video->info.blit_hw; |
252 | } else { |
253 | hw_blit_ok = 0; |
254 | } |
255 | if (hw_blit_ok && (surface->flags & SDL_SRCCOLORKEY)) { |
256 | hw_blit_ok = current_video->info.blit_hw_CC; |
257 | } |
258 | if ( hw_blit_ok && (surface->flags & SDL_SRCALPHA) ) { |
259 | hw_blit_ok = current_video->info.blit_hw_A; |
260 | } |
261 | } else { |
262 | /* We only support accelerated blitting to hardware */ |
263 | if ( surface->map->dst->flags & SDL_HWSURFACE ) { |
264 | hw_blit_ok = current_video->info.blit_sw; |
265 | } else { |
266 | hw_blit_ok = 0; |
267 | } |
268 | if (hw_blit_ok && (surface->flags & SDL_SRCCOLORKEY)) { |
269 | hw_blit_ok = current_video->info.blit_sw_CC; |
270 | } |
271 | if ( hw_blit_ok && (surface->flags & SDL_SRCALPHA) ) { |
272 | hw_blit_ok = current_video->info.blit_sw_A; |
273 | } |
274 | } |
275 | if ( hw_blit_ok ) { |
276 | SDL_VideoDevice *video = current_video; |
277 | SDL_VideoDevice *this = current_video; |
278 | video->CheckHWBlit(this, surface, surface->map->dst); |
279 | } |
280 | } |
281 | |
282 | /* if an alpha pixel format is specified, we can accelerate alpha blits */ |
283 | if (((surface->flags & SDL_HWSURFACE) == SDL_HWSURFACE )&&(current_video->displayformatalphapixel)) |
284 | { |
285 | if ( (surface->flags & SDL_SRCALPHA) ) |
286 | if ( current_video->info.blit_hw_A ) { |
287 | SDL_VideoDevice *video = current_video; |
288 | SDL_VideoDevice *this = current_video; |
289 | video->CheckHWBlit(this, surface, surface->map->dst); |
290 | } |
291 | } |
292 | |
293 | /* Get the blit function index, based on surface mode */ |
294 | /* { 0 = nothing, 1 = colorkey, 2 = alpha, 3 = colorkey+alpha } */ |
295 | blit_index = 0; |
296 | blit_index |= (!!(surface->flags & SDL_SRCCOLORKEY)) << 0; |
297 | if ( surface->flags & SDL_SRCALPHA |
298 | && (surface->format->alpha != SDL_ALPHA_OPAQUE |
299 | || surface->format->Amask) ) { |
300 | blit_index |= 2; |
301 | } |
302 | |
303 | /* Check for special "identity" case -- copy blit */ |
304 | if ( surface->map->identity && blit_index == 0 ) { |
305 | surface->map->sw_data->blit = SDL_BlitCopy; |
306 | |
307 | /* Handle overlapping blits on the same surface */ |
308 | if ( surface == surface->map->dst ) { |
309 | surface->map->sw_data->blit = SDL_BlitCopyOverlap; |
310 | } |
311 | } else { |
312 | if ( surface->format->BitsPerPixel < 8 ) { |
313 | surface->map->sw_data->blit = |
314 | SDL_CalculateBlit0(surface, blit_index); |
315 | } else { |
316 | switch ( surface->format->BytesPerPixel ) { |
317 | case 1: |
318 | surface->map->sw_data->blit = |
319 | SDL_CalculateBlit1(surface, blit_index); |
320 | break; |
321 | case 2: |
322 | case 3: |
323 | case 4: |
324 | surface->map->sw_data->blit = |
325 | SDL_CalculateBlitN(surface, blit_index); |
326 | break; |
327 | default: |
328 | surface->map->sw_data->blit = NULL; |
329 | break; |
330 | } |
331 | } |
332 | } |
333 | /* Make sure we have a blit function */ |
334 | if ( surface->map->sw_data->blit == NULL ) { |
335 | SDL_InvalidateMap(surface->map); |
336 | SDL_SetError("Blit combination not supported"); |
337 | return(-1); |
338 | } |
339 | |
340 | /* Choose software blitting function */ |
341 | if(surface->flags & SDL_RLEACCELOK |
342 | && (surface->flags & SDL_HWACCEL) != SDL_HWACCEL) { |
343 | |
344 | if(surface->map->identity |
345 | && (blit_index == 1 |
346 | || (blit_index == 3 && !surface->format->Amask))) { |
347 | if ( SDL_RLESurface(surface) == 0 ) |
348 | surface->map->sw_blit = SDL_RLEBlit; |
349 | } else if(blit_index == 2 && surface->format->Amask) { |
350 | if ( SDL_RLESurface(surface) == 0 ) |
351 | surface->map->sw_blit = SDL_RLEAlphaBlit; |
352 | } |
353 | } |
354 | |
355 | if ( surface->map->sw_blit == NULL ) { |
356 | surface->map->sw_blit = SDL_SoftBlit; |
357 | } |
358 | return(0); |
359 | } |
360 | |