SDL_blit.c (8589B)
1 /* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20 */ 21 #include "../SDL_internal.h" 22 23 #include "SDL_video.h" 24 #include "SDL_sysvideo.h" 25 #include "SDL_blit.h" 26 #include "SDL_blit_auto.h" 27 #include "SDL_blit_copy.h" 28 #include "SDL_blit_slow.h" 29 #include "SDL_RLEaccel_c.h" 30 #include "SDL_pixels_c.h" 31 32 /* The general purpose software blit routine */ 33 static int SDLCALL 34 SDL_SoftBlit(SDL_Surface * src, SDL_Rect * srcrect, 35 SDL_Surface * dst, SDL_Rect * dstrect) 36 { 37 int okay; 38 int src_locked; 39 int dst_locked; 40 41 /* Everything is okay at the beginning... */ 42 okay = 1; 43 44 /* Lock the destination if it's in hardware */ 45 dst_locked = 0; 46 if (SDL_MUSTLOCK(dst)) { 47 if (SDL_LockSurface(dst) < 0) { 48 okay = 0; 49 } else { 50 dst_locked = 1; 51 } 52 } 53 /* Lock the source if it's in hardware */ 54 src_locked = 0; 55 if (SDL_MUSTLOCK(src)) { 56 if (SDL_LockSurface(src) < 0) { 57 okay = 0; 58 } else { 59 src_locked = 1; 60 } 61 } 62 63 /* Set up source and destination buffer pointers, and BLIT! */ 64 if (okay && !SDL_RectEmpty(srcrect)) { 65 SDL_BlitFunc RunBlit; 66 SDL_BlitInfo *info = &src->map->info; 67 68 /* Set up the blit information */ 69 info->src = (Uint8 *) src->pixels + 70 (Uint16) srcrect->y * src->pitch + 71 (Uint16) srcrect->x * info->src_fmt->BytesPerPixel; 72 info->src_w = srcrect->w; 73 info->src_h = srcrect->h; 74 info->src_pitch = src->pitch; 75 info->src_skip = 76 info->src_pitch - info->src_w * info->src_fmt->BytesPerPixel; 77 info->dst = 78 (Uint8 *) dst->pixels + (Uint16) dstrect->y * dst->pitch + 79 (Uint16) dstrect->x * info->dst_fmt->BytesPerPixel; 80 info->dst_w = dstrect->w; 81 info->dst_h = dstrect->h; 82 info->dst_pitch = dst->pitch; 83 info->dst_skip = 84 info->dst_pitch - info->dst_w * info->dst_fmt->BytesPerPixel; 85 RunBlit = (SDL_BlitFunc) src->map->data; 86 87 /* Run the actual software blit */ 88 RunBlit(info); 89 } 90 91 /* We need to unlock the surfaces if they're locked */ 92 if (dst_locked) { 93 SDL_UnlockSurface(dst); 94 } 95 if (src_locked) { 96 SDL_UnlockSurface(src); 97 } 98 /* Blit is done! */ 99 return (okay ? 0 : -1); 100 } 101 102 #if SDL_HAVE_BLIT_AUTO 103 104 #ifdef __MACOSX__ 105 #include <sys/sysctl.h> 106 107 static SDL_bool 108 SDL_UseAltivecPrefetch() 109 { 110 const char key[] = "hw.l3cachesize"; 111 u_int64_t result = 0; 112 size_t typeSize = sizeof(result); 113 114 if (sysctlbyname(key, &result, &typeSize, NULL, 0) == 0 && result > 0) { 115 return SDL_TRUE; 116 } else { 117 return SDL_FALSE; 118 } 119 } 120 #else 121 static SDL_bool 122 SDL_UseAltivecPrefetch() 123 { 124 /* Just guess G4 */ 125 return SDL_TRUE; 126 } 127 #endif /* __MACOSX__ */ 128 129 static SDL_BlitFunc 130 SDL_ChooseBlitFunc(Uint32 src_format, Uint32 dst_format, int flags, 131 SDL_BlitFuncEntry * entries) 132 { 133 int i, flagcheck = (flags & (SDL_COPY_MODULATE_COLOR | SDL_COPY_MODULATE_ALPHA | SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | SDL_COPY_MUL | SDL_COPY_COLORKEY | SDL_COPY_NEAREST)); 134 static int features = 0x7fffffff; 135 136 /* Get the available CPU features */ 137 if (features == 0x7fffffff) { 138 const char *override = SDL_getenv("SDL_BLIT_CPU_FEATURES"); 139 140 features = SDL_CPU_ANY; 141 142 /* Allow an override for testing .. */ 143 if (override) { 144 SDL_sscanf(override, "%u", &features); 145 } else { 146 if (SDL_HasMMX()) { 147 features |= SDL_CPU_MMX; 148 } 149 if (SDL_Has3DNow()) { 150 features |= SDL_CPU_3DNOW; 151 } 152 if (SDL_HasSSE()) { 153 features |= SDL_CPU_SSE; 154 } 155 if (SDL_HasSSE2()) { 156 features |= SDL_CPU_SSE2; 157 } 158 if (SDL_HasAltiVec()) { 159 if (SDL_UseAltivecPrefetch()) { 160 features |= SDL_CPU_ALTIVEC_PREFETCH; 161 } else { 162 features |= SDL_CPU_ALTIVEC_NOPREFETCH; 163 } 164 } 165 } 166 } 167 168 for (i = 0; entries[i].func; ++i) { 169 /* Check for matching pixel formats */ 170 if (src_format != entries[i].src_format) { 171 continue; 172 } 173 if (dst_format != entries[i].dst_format) { 174 continue; 175 } 176 177 /* Check flags */ 178 if ((flagcheck & entries[i].flags) != flagcheck) { 179 continue; 180 } 181 182 /* Check CPU features */ 183 if ((entries[i].cpu & features) != entries[i].cpu) { 184 continue; 185 } 186 187 /* We found the best one! */ 188 return entries[i].func; 189 } 190 return NULL; 191 } 192 #endif /* SDL_HAVE_BLIT_AUTO */ 193 194 /* Figure out which of many blit routines to set up on a surface */ 195 int 196 SDL_CalculateBlit(SDL_Surface * surface) 197 { 198 SDL_BlitFunc blit = NULL; 199 SDL_BlitMap *map = surface->map; 200 SDL_Surface *dst = map->dst; 201 202 /* We don't currently support blitting to < 8 bpp surfaces */ 203 if (dst->format->BitsPerPixel < 8) { 204 SDL_InvalidateMap(map); 205 return SDL_SetError("Blit combination not supported"); 206 } 207 208 #if SDL_HAVE_RLE 209 /* Clean everything out to start */ 210 if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) { 211 SDL_UnRLESurface(surface, 1); 212 } 213 #endif 214 215 map->blit = SDL_SoftBlit; 216 map->info.src_fmt = surface->format; 217 map->info.src_pitch = surface->pitch; 218 map->info.dst_fmt = dst->format; 219 map->info.dst_pitch = dst->pitch; 220 221 #if SDL_HAVE_RLE 222 /* See if we can do RLE acceleration */ 223 if (map->info.flags & SDL_COPY_RLE_DESIRED) { 224 if (SDL_RLESurface(surface) == 0) { 225 return 0; 226 } 227 } 228 #endif 229 230 /* Choose a standard blit function */ 231 if (map->identity && !(map->info.flags & ~SDL_COPY_RLE_DESIRED)) { 232 blit = SDL_BlitCopy; 233 } else if (surface->format->Rloss > 8 || dst->format->Rloss > 8) { 234 /* Greater than 8 bits per channel not supported yet */ 235 SDL_InvalidateMap(map); 236 return SDL_SetError("Blit combination not supported"); 237 } 238 #if SDL_HAVE_BLIT_0 239 else if (surface->format->BitsPerPixel < 8 && 240 SDL_ISPIXELFORMAT_INDEXED(surface->format->format)) { 241 blit = SDL_CalculateBlit0(surface); 242 } 243 #endif 244 #if SDL_HAVE_BLIT_1 245 else if (surface->format->BytesPerPixel == 1 && 246 SDL_ISPIXELFORMAT_INDEXED(surface->format->format)) { 247 blit = SDL_CalculateBlit1(surface); 248 } 249 #endif 250 #if SDL_HAVE_BLIT_A 251 else if (map->info.flags & SDL_COPY_BLEND) { 252 blit = SDL_CalculateBlitA(surface); 253 } 254 #endif 255 #if SDL_HAVE_BLIT_N 256 else { 257 blit = SDL_CalculateBlitN(surface); 258 } 259 #endif 260 #if SDL_HAVE_BLIT_AUTO 261 if (blit == NULL) { 262 Uint32 src_format = surface->format->format; 263 Uint32 dst_format = dst->format->format; 264 265 blit = 266 SDL_ChooseBlitFunc(src_format, dst_format, map->info.flags, 267 SDL_GeneratedBlitFuncTable); 268 } 269 #endif 270 271 #ifndef TEST_SLOW_BLIT 272 if (blit == NULL) 273 #endif 274 { 275 Uint32 src_format = surface->format->format; 276 Uint32 dst_format = dst->format->format; 277 278 if (!SDL_ISPIXELFORMAT_INDEXED(src_format) && 279 !SDL_ISPIXELFORMAT_FOURCC(src_format) && 280 !SDL_ISPIXELFORMAT_INDEXED(dst_format) && 281 !SDL_ISPIXELFORMAT_FOURCC(dst_format)) { 282 blit = SDL_Blit_Slow; 283 } 284 } 285 map->data = blit; 286 287 /* Make sure we have a blit function */ 288 if (blit == NULL) { 289 SDL_InvalidateMap(map); 290 return SDL_SetError("Blit combination not supported"); 291 } 292 293 return 0; 294 } 295 296 /* vi: set ts=4 sw=4 expandtab: */