1 /* 2 SDL - Simple DirectMedia Layer 3 Copyright (C) 1997-2006 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 (at) 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 361