| 1 | /* | 
|---|
| 2 | Simple DirectMedia Layer | 
|---|
| 3 | Copyright (C) 1997-2025 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_sysvideo.h" | 
|---|
| 24 | #include "SDL_surface_c.h" | 
|---|
| 25 | #include "SDL_blit_auto.h" | 
|---|
| 26 | #include "SDL_blit_copy.h" | 
|---|
| 27 | #include "SDL_blit_slow.h" | 
|---|
| 28 | #include "SDL_RLEaccel_c.h" | 
|---|
| 29 | #include "SDL_pixels_c.h" | 
|---|
| 30 |  | 
|---|
| 31 | // The general purpose software blit routine | 
|---|
| 32 | static bool SDLCALL SDL_SoftBlit(SDL_Surface *src, const SDL_Rect *srcrect, | 
|---|
| 33 | SDL_Surface *dst, const SDL_Rect *dstrect) | 
|---|
| 34 | { | 
|---|
| 35 | bool okay; | 
|---|
| 36 | int src_locked; | 
|---|
| 37 | int dst_locked; | 
|---|
| 38 |  | 
|---|
| 39 | // Everything is okay at the beginning... | 
|---|
| 40 | okay = true; | 
|---|
| 41 |  | 
|---|
| 42 | // Lock the destination if it's in hardware | 
|---|
| 43 | dst_locked = 0; | 
|---|
| 44 | if (SDL_MUSTLOCK(dst)) { | 
|---|
| 45 | if (!SDL_LockSurface(dst)) { | 
|---|
| 46 | okay = false; | 
|---|
| 47 | } else { | 
|---|
| 48 | dst_locked = 1; | 
|---|
| 49 | } | 
|---|
| 50 | } | 
|---|
| 51 | // Lock the source if it's in hardware | 
|---|
| 52 | src_locked = 0; | 
|---|
| 53 | if (SDL_MUSTLOCK(src)) { | 
|---|
| 54 | if (!SDL_LockSurface(src)) { | 
|---|
| 55 | okay = false; | 
|---|
| 56 | } else { | 
|---|
| 57 | src_locked = 1; | 
|---|
| 58 | } | 
|---|
| 59 | } | 
|---|
| 60 |  | 
|---|
| 61 | // Set up source and destination buffer pointers, and BLIT! | 
|---|
| 62 | if (okay) { | 
|---|
| 63 | SDL_BlitFunc RunBlit; | 
|---|
| 64 | SDL_BlitInfo *info = &src->map.info; | 
|---|
| 65 |  | 
|---|
| 66 | // Set up the blit information | 
|---|
| 67 | info->src = (Uint8 *)src->pixels + | 
|---|
| 68 | (Uint16)srcrect->y * src->pitch + | 
|---|
| 69 | (Uint16)srcrect->x * info->src_fmt->bytes_per_pixel; | 
|---|
| 70 | info->src_w = srcrect->w; | 
|---|
| 71 | info->src_h = srcrect->h; | 
|---|
| 72 | info->src_pitch = src->pitch; | 
|---|
| 73 | info->src_skip = | 
|---|
| 74 | info->src_pitch - info->src_w * info->src_fmt->bytes_per_pixel; | 
|---|
| 75 | info->dst = | 
|---|
| 76 | (Uint8 *)dst->pixels + (Uint16)dstrect->y * dst->pitch + | 
|---|
| 77 | (Uint16)dstrect->x * info->dst_fmt->bytes_per_pixel; | 
|---|
| 78 | info->dst_w = dstrect->w; | 
|---|
| 79 | info->dst_h = dstrect->h; | 
|---|
| 80 | info->dst_pitch = dst->pitch; | 
|---|
| 81 | info->dst_skip = | 
|---|
| 82 | info->dst_pitch - info->dst_w * info->dst_fmt->bytes_per_pixel; | 
|---|
| 83 | RunBlit = (SDL_BlitFunc)src->map.data; | 
|---|
| 84 |  | 
|---|
| 85 | // Run the actual software blit | 
|---|
| 86 | RunBlit(info); | 
|---|
| 87 | } | 
|---|
| 88 |  | 
|---|
| 89 | // We need to unlock the surfaces if they're locked | 
|---|
| 90 | if (dst_locked) { | 
|---|
| 91 | SDL_UnlockSurface(dst); | 
|---|
| 92 | } | 
|---|
| 93 | if (src_locked) { | 
|---|
| 94 | SDL_UnlockSurface(src); | 
|---|
| 95 | } | 
|---|
| 96 | // Blit is done! | 
|---|
| 97 | return okay; | 
|---|
| 98 | } | 
|---|
| 99 |  | 
|---|
| 100 | #ifdef SDL_HAVE_BLIT_AUTO | 
|---|
| 101 |  | 
|---|
| 102 | #ifdef SDL_PLATFORM_MACOS | 
|---|
| 103 | #include <sys/sysctl.h> | 
|---|
| 104 |  | 
|---|
| 105 | static bool SDL_UseAltivecPrefetch(void) | 
|---|
| 106 | { | 
|---|
| 107 | const char key[] = "hw.l3cachesize"; | 
|---|
| 108 | u_int64_t result = 0; | 
|---|
| 109 | size_t typeSize = sizeof(result); | 
|---|
| 110 |  | 
|---|
| 111 | if (sysctlbyname(key, &result, &typeSize, NULL, 0) == 0 && result > 0) { | 
|---|
| 112 | return true; | 
|---|
| 113 | } else { | 
|---|
| 114 | return false; | 
|---|
| 115 | } | 
|---|
| 116 | } | 
|---|
| 117 | #else | 
|---|
| 118 | static bool SDL_UseAltivecPrefetch(void) | 
|---|
| 119 | { | 
|---|
| 120 | // Just guess G4 | 
|---|
| 121 | return true; | 
|---|
| 122 | } | 
|---|
| 123 | #endif // SDL_PLATFORM_MACOS | 
|---|
| 124 |  | 
|---|
| 125 | static SDL_BlitFunc SDL_ChooseBlitFunc(SDL_PixelFormat src_format, SDL_PixelFormat dst_format, int flags, | 
|---|
| 126 | SDL_BlitFuncEntry *entries) | 
|---|
| 127 | { | 
|---|
| 128 | int i, flagcheck = (flags & (SDL_COPY_MODULATE_MASK | SDL_COPY_BLEND_MASK | SDL_COPY_COLORKEY | SDL_COPY_NEAREST)); | 
|---|
| 129 | static unsigned int features = 0x7fffffff; | 
|---|
| 130 |  | 
|---|
| 131 | // Get the available CPU features | 
|---|
| 132 | if (features == 0x7fffffff) { | 
|---|
| 133 | features = SDL_CPU_ANY; | 
|---|
| 134 | if (SDL_HasMMX()) { | 
|---|
| 135 | features |= SDL_CPU_MMX; | 
|---|
| 136 | } | 
|---|
| 137 | if (SDL_HasSSE()) { | 
|---|
| 138 | features |= SDL_CPU_SSE; | 
|---|
| 139 | } | 
|---|
| 140 | if (SDL_HasSSE2()) { | 
|---|
| 141 | features |= SDL_CPU_SSE2; | 
|---|
| 142 | } | 
|---|
| 143 | if (SDL_HasAltiVec()) { | 
|---|
| 144 | if (SDL_UseAltivecPrefetch()) { | 
|---|
| 145 | features |= SDL_CPU_ALTIVEC_PREFETCH; | 
|---|
| 146 | } else { | 
|---|
| 147 | features |= SDL_CPU_ALTIVEC_NOPREFETCH; | 
|---|
| 148 | } | 
|---|
| 149 | } | 
|---|
| 150 | } | 
|---|
| 151 |  | 
|---|
| 152 | for (i = 0; entries[i].func; ++i) { | 
|---|
| 153 | // Check for matching pixel formats | 
|---|
| 154 | if (src_format != entries[i].src_format) { | 
|---|
| 155 | continue; | 
|---|
| 156 | } | 
|---|
| 157 | if (dst_format != entries[i].dst_format) { | 
|---|
| 158 | continue; | 
|---|
| 159 | } | 
|---|
| 160 |  | 
|---|
| 161 | // Check flags | 
|---|
| 162 | if ((flagcheck & entries[i].flags) != flagcheck) { | 
|---|
| 163 | continue; | 
|---|
| 164 | } | 
|---|
| 165 |  | 
|---|
| 166 | // Check CPU features | 
|---|
| 167 | if ((entries[i].cpu & features) != entries[i].cpu) { | 
|---|
| 168 | continue; | 
|---|
| 169 | } | 
|---|
| 170 |  | 
|---|
| 171 | // We found the best one! | 
|---|
| 172 | return entries[i].func; | 
|---|
| 173 | } | 
|---|
| 174 | return NULL; | 
|---|
| 175 | } | 
|---|
| 176 | #endif // SDL_HAVE_BLIT_AUTO | 
|---|
| 177 |  | 
|---|
| 178 | // Figure out which of many blit routines to set up on a surface | 
|---|
| 179 | bool SDL_CalculateBlit(SDL_Surface *surface, SDL_Surface *dst) | 
|---|
| 180 | { | 
|---|
| 181 | SDL_BlitFunc blit = NULL; | 
|---|
| 182 | SDL_BlitMap *map = &surface->map; | 
|---|
| 183 | SDL_Colorspace src_colorspace = surface->colorspace; | 
|---|
| 184 | SDL_Colorspace dst_colorspace = dst->colorspace; | 
|---|
| 185 |  | 
|---|
| 186 | // We don't currently support blitting to < 8 bpp surfaces | 
|---|
| 187 | if (SDL_BITSPERPIXEL(dst->format) < 8) { | 
|---|
| 188 | SDL_InvalidateMap(map); | 
|---|
| 189 | return SDL_SetError( "Blit combination not supported"); | 
|---|
| 190 | } | 
|---|
| 191 |  | 
|---|
| 192 | #ifdef SDL_HAVE_RLE | 
|---|
| 193 | // Clean everything out to start | 
|---|
| 194 | if (surface->flags & SDL_INTERNAL_SURFACE_RLEACCEL) { | 
|---|
| 195 | SDL_UnRLESurface(surface, true); | 
|---|
| 196 | } | 
|---|
| 197 | #endif | 
|---|
| 198 |  | 
|---|
| 199 | map->blit = SDL_SoftBlit; | 
|---|
| 200 | map->info.src_surface = surface; | 
|---|
| 201 | map->info.src_fmt = surface->fmt; | 
|---|
| 202 | map->info.src_pal = surface->palette; | 
|---|
| 203 | map->info.dst_surface = dst; | 
|---|
| 204 | map->info.dst_fmt = dst->fmt; | 
|---|
| 205 | map->info.dst_pal = dst->palette; | 
|---|
| 206 |  | 
|---|
| 207 | #ifdef SDL_HAVE_RLE | 
|---|
| 208 | // See if we can do RLE acceleration | 
|---|
| 209 | if (map->info.flags & SDL_COPY_RLE_DESIRED) { | 
|---|
| 210 | if (SDL_RLESurface(surface)) { | 
|---|
| 211 | return true; | 
|---|
| 212 | } | 
|---|
| 213 | } | 
|---|
| 214 | #endif | 
|---|
| 215 |  | 
|---|
| 216 | // Choose a standard blit function | 
|---|
| 217 | if (!blit) { | 
|---|
| 218 | if (src_colorspace != dst_colorspace || | 
|---|
| 219 | SDL_BYTESPERPIXEL(surface->format) > 4 || | 
|---|
| 220 | SDL_BYTESPERPIXEL(dst->format) > 4) { | 
|---|
| 221 | blit = SDL_Blit_Slow_Float; | 
|---|
| 222 | } | 
|---|
| 223 | } | 
|---|
| 224 | if (!blit) { | 
|---|
| 225 | if (map->identity && !(map->info.flags & ~SDL_COPY_RLE_DESIRED)) { | 
|---|
| 226 | blit = SDL_BlitCopy; | 
|---|
| 227 | } else if (SDL_ISPIXELFORMAT_10BIT(surface->format) || | 
|---|
| 228 | SDL_ISPIXELFORMAT_10BIT(dst->format)) { | 
|---|
| 229 | blit = SDL_Blit_Slow; | 
|---|
| 230 | } | 
|---|
| 231 | #ifdef SDL_HAVE_BLIT_0 | 
|---|
| 232 | else if (SDL_BITSPERPIXEL(surface->format) < 8 && | 
|---|
| 233 | SDL_ISPIXELFORMAT_INDEXED(surface->format)) { | 
|---|
| 234 | blit = SDL_CalculateBlit0(surface); | 
|---|
| 235 | } | 
|---|
| 236 | #endif | 
|---|
| 237 | #ifdef SDL_HAVE_BLIT_1 | 
|---|
| 238 | else if (SDL_BYTESPERPIXEL(surface->format) == 1 && | 
|---|
| 239 | SDL_ISPIXELFORMAT_INDEXED(surface->format)) { | 
|---|
| 240 | blit = SDL_CalculateBlit1(surface); | 
|---|
| 241 | } | 
|---|
| 242 | #endif | 
|---|
| 243 | #ifdef SDL_HAVE_BLIT_A | 
|---|
| 244 | else if (map->info.flags & SDL_COPY_BLEND) { | 
|---|
| 245 | blit = SDL_CalculateBlitA(surface); | 
|---|
| 246 | } | 
|---|
| 247 | #endif | 
|---|
| 248 | #ifdef SDL_HAVE_BLIT_N | 
|---|
| 249 | else { | 
|---|
| 250 | blit = SDL_CalculateBlitN(surface); | 
|---|
| 251 | } | 
|---|
| 252 | #endif | 
|---|
| 253 | } | 
|---|
| 254 | #ifdef SDL_HAVE_BLIT_AUTO | 
|---|
| 255 | if (!blit) { | 
|---|
| 256 | SDL_PixelFormat src_format = surface->format; | 
|---|
| 257 | SDL_PixelFormat dst_format = dst->format; | 
|---|
| 258 |  | 
|---|
| 259 | blit = | 
|---|
| 260 | SDL_ChooseBlitFunc(src_format, dst_format, map->info.flags, | 
|---|
| 261 | SDL_GeneratedBlitFuncTable); | 
|---|
| 262 | } | 
|---|
| 263 | #endif | 
|---|
| 264 |  | 
|---|
| 265 | #ifndef TEST_SLOW_BLIT | 
|---|
| 266 | if (!blit) | 
|---|
| 267 | #endif | 
|---|
| 268 | { | 
|---|
| 269 | SDL_PixelFormat src_format = surface->format; | 
|---|
| 270 | SDL_PixelFormat dst_format = dst->format; | 
|---|
| 271 |  | 
|---|
| 272 | if ((!SDL_ISPIXELFORMAT_INDEXED(src_format) || | 
|---|
| 273 | (src_format == SDL_PIXELFORMAT_INDEX8 && surface->palette)) && | 
|---|
| 274 | !SDL_ISPIXELFORMAT_FOURCC(src_format) && | 
|---|
| 275 | (!SDL_ISPIXELFORMAT_INDEXED(dst_format) || | 
|---|
| 276 | (dst_format == SDL_PIXELFORMAT_INDEX8 && dst->palette)) && | 
|---|
| 277 | !SDL_ISPIXELFORMAT_FOURCC(dst_format)) { | 
|---|
| 278 | blit = SDL_Blit_Slow; | 
|---|
| 279 | } | 
|---|
| 280 | } | 
|---|
| 281 | map->data = (void *)blit; | 
|---|
| 282 |  | 
|---|
| 283 | // Make sure we have a blit function | 
|---|
| 284 | if (!blit) { | 
|---|
| 285 | SDL_InvalidateMap(map); | 
|---|
| 286 | return SDL_SetError( "Blit combination not supported"); | 
|---|
| 287 | } | 
|---|
| 288 |  | 
|---|
| 289 | return true; | 
|---|
| 290 | } | 
|---|
| 291 |  | 
|---|