src/video/SDL_blit.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 17 Aug 2007 06:21:58 +0000
changeset 2262 bee005ace1bf
parent 2260 202ddfd1cfb1
child 2263 900c35d8e8fd
permissions -rw-r--r--
Work in progress: merging new texture features into SDL blit system
     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@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_blit_copy.h"
    28 #include "SDL_RLEaccel_c.h"
    29 #include "SDL_pixels_c.h"
    30 
    31 /* The general purpose software blit routine */
    32 static int
    33 SDL_SoftBlit(SDL_Surface * src, SDL_Rect * srcrect,
    34              SDL_Surface * dst, SDL_Rect * dstrect)
    35 {
    36     int okay;
    37     int src_locked;
    38     int dst_locked;
    39 
    40     /* Everything is okay at the beginning...  */
    41     okay = 1;
    42 
    43     /* Lock the destination if it's in hardware */
    44     dst_locked = 0;
    45     if (SDL_MUSTLOCK(dst)) {
    46         if (SDL_LockSurface(dst) < 0) {
    47             okay = 0;
    48         } else {
    49             dst_locked = 1;
    50         }
    51     }
    52     /* Lock the source if it's in hardware */
    53     src_locked = 0;
    54     if (SDL_MUSTLOCK(src)) {
    55         if (SDL_LockSurface(src) < 0) {
    56             okay = 0;
    57         } else {
    58             src_locked = 1;
    59         }
    60     }
    61 
    62     /* Set up source and destination buffer pointers, and BLIT! */
    63     if (okay && srcrect->w && srcrect->h) {
    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->BytesPerPixel;
    70         info.src_w = srcrect->w;
    71         info.src_h = srcrect->h;
    72         info.dst = (Uint8 *) dst->pixels +
    73             (Uint16) dstrect->y * dst->pitch +
    74             (Uint16) dstrect->x * info->dst_fmt->BytesPerPixel;
    75         info.dst_w = dstrect->w;
    76         info.dst_h = dstrect->h;
    77         RunBlit = (SDL_BlitFunc) src->map->data;
    78 
    79         /* Run the actual software blit */
    80         RunBlit(info);
    81     }
    82 
    83     /* We need to unlock the surfaces if they're locked */
    84     if (dst_locked) {
    85         SDL_UnlockSurface(dst);
    86     }
    87     if (src_locked) {
    88         SDL_UnlockSurface(src);
    89     }
    90     /* Blit is done! */
    91     return (okay ? 0 : -1);
    92 }
    93 
    94 #ifdef __MACOSX__
    95 #include <sys/sysctl.h>
    96 
    97 static SDL_bool
    98 SDL_UseAltivecPrefetch()
    99 {
   100     const char key[] = "hw.l3cachesize";
   101     u_int64_t result = 0;
   102     size_t typeSize = sizeof(result);
   103 
   104     if (sysctlbyname(key, &result, &typeSize, NULL, 0) == 0 && result > 0) {
   105         return SDL_TRUE;
   106     } else {
   107         return SDL_FALSE;
   108     }
   109 }
   110 #else
   111 static SDL_bool
   112 SDL_UseAltivecPrefetch()
   113 {
   114     /* Just guess G4 */
   115     return SDL_TRUE;
   116 }
   117 #endif /* __MACOSX__ */
   118 
   119 static SDL_BlitFunc
   120 SDL_ChooseBlitFunc(Uint32 src_format, Uint32 dst_format, int flags, SDL_BlitEntry * entries)
   121 {
   122     int i;
   123     static Uint32 features = 0xffffffff;
   124 
   125     /* Get the available CPU features */
   126     if (features == 0xffffffff) {
   127         const char *override = SDL_getenv("SDL_BLIT_CPU_FEATURES");
   128 
   129         features = SDL_CPU_ANY;
   130 
   131         /* Allow an override for testing .. */
   132         if (override) {
   133             SDL_sscanf(override, "%u", &features);
   134         } else {
   135             if (SDL_HasMMX()) {
   136                 features |= SDL_CPU_MMX;
   137             }
   138             if (SDL_Has3DNow()) {
   139                 features |= SDL_CPU_3DNOW;
   140             }
   141             if (SDL_HasSSE()) {
   142                 features |= SDL_CPU_SSE;
   143             }
   144             if (SDL_HasSSE2()) {
   145                 features |= SDL_CPU_SSE2;
   146             }
   147             if (SDL_HasAltiVec()) {
   148                 if (SDL_UseAltivecPrefetch()) {
   149                     features |= SDL_CPU_ALTIVEC_PREFETCH;
   150                 } else {
   151                     features |= SDL_CPU_ALTIVEC_NOPREFETCH;
   152                 }
   153             }
   154         }
   155     }
   156 
   157     for (i = 0; entries[i].blit; ++i) {
   158         if (src_format != entries[i].src_format) {
   159             continue;
   160         }
   161         if (dst_format != entries[i].dst_format) {
   162             continue;
   163         }
   164         if ((flags & entries[i].flags) != flags) {
   165             continue;
   166         }
   167         if (!(features & entries[i].cpu)) {
   168             continue;
   169         }
   170         return entries[i].func;
   171     }
   172     return NULL;
   173 }
   174 
   175 /* Figure out which of many blit routines to set up on a surface */
   176 int
   177 SDL_CalculateBlit(SDL_Surface * surface)
   178 {
   179     SDL_BlitFunc blit = NULL;
   180     int blit_index;
   181 
   182     /* Clean everything out to start */
   183     if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
   184         SDL_UnRLESurface(surface, 1);
   185     }
   186     surface->map->blit = NULL;
   187 
   188     /* Get the blit function index, based on surface mode */
   189     /* { 0 = nothing, 1 = colorkey, 2 = alpha, 3 = colorkey+alpha } */
   190     blit_index = 0;
   191     blit_index |= (!!(surface->flags & SDL_SRCCOLORKEY)) << 0;
   192     if (surface->flags & SDL_SRCALPHA
   193         && ((surface->map->cmod >> 24) != SDL_ALPHA_OPAQUE
   194             || surface->format->Amask)) {
   195         blit_index |= 2;
   196     }
   197 
   198     /* Check for special "identity" case -- copy blit */
   199     if (surface->map->identity && blit_index == 0) {
   200         /* Handle overlapping blits on the same surface */
   201         if (surface == surface->map->dst) {
   202             blit = SDL_BlitCopyOverlap;
   203         } else {
   204             blit = SDL_BlitCopy;
   205         }
   206     } else {
   207         if (surface->format->BitsPerPixel < 8) {
   208             blit = SDL_CalculateBlit0(surface, blit_index);
   209         } else {
   210             switch (surface->format->BytesPerPixel) {
   211             case 1:
   212                 blit = SDL_CalculateBlit1(surface, blit_index);
   213                 break;
   214             case 2:
   215             case 3:
   216             case 4:
   217                 blit = SDL_CalculateBlitN(surface, blit_index);
   218                 break;
   219             }
   220         }
   221     }
   222     if (blit == NULL) {
   223         blit = SDL_ChooseBlitFunc(src_format, dst_format, surface->map->info.flags, SDL_GeneratedBlitFuncTable);
   224     }
   225 
   226     /* Make sure we have a blit function */
   227     if (blit == NULL) {
   228         SDL_InvalidateMap(surface->map);
   229         SDL_SetError("Blit combination not supported");
   230         return (-1);
   231     }
   232 
   233     /* Choose software blitting function */
   234     if (surface->flags & SDL_RLEACCELOK) {
   235         if (surface->map->identity
   236             && (blit_index == 1
   237                 || (blit_index == 3 && !surface->format->Amask))) {
   238             if (SDL_RLESurface(surface) == 0)
   239                 surface->map->blit = SDL_RLEBlit;
   240         } else if (blit_index == 2 && surface->format->Amask) {
   241             if (SDL_RLESurface(surface) == 0)
   242                 surface->map->blit = SDL_RLEAlphaBlit;
   243         }
   244     }
   245 
   246     if (surface->map->blit == NULL) {
   247         surface->map->blit = SDL_SoftBlit;
   248         surface->map->data = blit;
   249     }
   250     return (0);
   251 }
   252 
   253 /* vi: set ts=4 sw=4 expandtab: */