src/video/SDL_blit.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 18 Aug 2007 01:44:21 +0000
changeset 2266 e61ad15a205f
parent 2265 265bb136af92
child 2267 c785543d1843
permissions -rw-r--r--
More work in progress integrating SDL_Surface and the new SDL_Texture API
     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_auto.h"
    28 #include "SDL_blit_copy.h"
    29 #include "SDL_RLEaccel_c.h"
    30 #include "SDL_pixels_c.h"
    31 
    32 /* The general purpose software blit routine */
    33 static int
    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 && srcrect->w && srcrect->h) {
    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->dst = (Uint8 *) dst->pixels +
    75             (Uint16) dstrect->y * dst->pitch +
    76             (Uint16) dstrect->x * info->dst_fmt->BytesPerPixel;
    77         info->dst_w = dstrect->w;
    78         info->dst_h = dstrect->h;
    79         RunBlit = (SDL_BlitFunc) src->map->data;
    80 
    81         /* Run the actual software blit */
    82         RunBlit(info);
    83     }
    84 
    85     /* We need to unlock the surfaces if they're locked */
    86     if (dst_locked) {
    87         SDL_UnlockSurface(dst);
    88     }
    89     if (src_locked) {
    90         SDL_UnlockSurface(src);
    91     }
    92     /* Blit is done! */
    93     return (okay ? 0 : -1);
    94 }
    95 
    96 #ifdef __MACOSX__
    97 #include <sys/sysctl.h>
    98 
    99 static SDL_bool
   100 SDL_UseAltivecPrefetch()
   101 {
   102     const char key[] = "hw.l3cachesize";
   103     u_int64_t result = 0;
   104     size_t typeSize = sizeof(result);
   105 
   106     if (sysctlbyname(key, &result, &typeSize, NULL, 0) == 0 && result > 0) {
   107         return SDL_TRUE;
   108     } else {
   109         return SDL_FALSE;
   110     }
   111 }
   112 #else
   113 static SDL_bool
   114 SDL_UseAltivecPrefetch()
   115 {
   116     /* Just guess G4 */
   117     return SDL_TRUE;
   118 }
   119 #endif /* __MACOSX__ */
   120 
   121 static SDL_BlitFunc
   122 SDL_ChooseBlitFunc(Uint32 src_format, Uint32 dst_format, int flags, SDL_BlitFuncEntry * entries)
   123 {
   124     int i, flagcheck;
   125     static Uint32 features = 0xffffffff;
   126 
   127     /* Get the available CPU features */
   128     if (features == 0xffffffff) {
   129         const char *override = SDL_getenv("SDL_BLIT_CPU_FEATURES");
   130 
   131         features = SDL_CPU_ANY;
   132 
   133         /* Allow an override for testing .. */
   134         if (override) {
   135             SDL_sscanf(override, "%u", &features);
   136         } else {
   137             if (SDL_HasMMX()) {
   138                 features |= SDL_CPU_MMX;
   139             }
   140             if (SDL_Has3DNow()) {
   141                 features |= SDL_CPU_3DNOW;
   142             }
   143             if (SDL_HasSSE()) {
   144                 features |= SDL_CPU_SSE;
   145             }
   146             if (SDL_HasSSE2()) {
   147                 features |= SDL_CPU_SSE2;
   148             }
   149             if (SDL_HasAltiVec()) {
   150                 if (SDL_UseAltivecPrefetch()) {
   151                     features |= SDL_CPU_ALTIVEC_PREFETCH;
   152                 } else {
   153                     features |= SDL_CPU_ALTIVEC_NOPREFETCH;
   154                 }
   155             }
   156         }
   157     }
   158 
   159     for (i = 0; entries[i].func; ++i) {
   160         /* Check for matching pixel formats */
   161         if (src_format != entries[i].src_format) {
   162             continue;
   163         }
   164         if (dst_format != entries[i].dst_format) {
   165             continue;
   166         }
   167 
   168         /* Check modulation flags */
   169         flagcheck = (flags & (SDL_COPY_MODULATE_COLOR|SDL_COPY_MODULATE_COLOR));
   170         if ((flagcheck & entries[i].flags) != flagcheck) {
   171             continue;
   172         }
   173 
   174         /* Check blend flags */
   175         flagcheck = (flags & (SDL_COPY_MASK|SDL_COPY_BLEND|SDL_COPY_ADD|SDL_COPY_MOD));
   176         if ((flagcheck & entries[i].flags) != flagcheck) {
   177             continue;
   178         }
   179 
   180         /* Check colorkey flag */
   181         flagcheck = (flags & SDL_COPY_COLORKEY);
   182         if ((flagcheck & entries[i].flags) != flagcheck) {
   183             continue;
   184         }
   185 
   186         /* Check scaling flags */
   187         flagcheck = (flags & SDL_COPY_NEAREST);
   188         if ((flagcheck & entries[i].flags) != flagcheck) {
   189             continue;
   190         }
   191 
   192         /* Check CPU features */
   193         flagcheck = entries[i].cpu;
   194         if ((flagcheck & features) != flagcheck) {
   195             continue;
   196         }
   197 
   198         /* We found the best one! */
   199         return entries[i].func;
   200     }
   201     return NULL;
   202 }
   203 
   204 /* Figure out which of many blit routines to set up on a surface */
   205 int
   206 SDL_CalculateBlit(SDL_Surface * surface)
   207 {
   208     SDL_BlitFunc blit = NULL;
   209     SDL_BlitMap *map = surface->map;
   210     SDL_Surface *dst = map->dst;
   211     Uint32 src_format;
   212     Uint32 dst_format;
   213 
   214     /* Clean everything out to start */
   215     if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
   216         SDL_UnRLESurface(surface, 1);
   217     }
   218     map->blit = SDL_SoftBlit;
   219     map->info.src_fmt = surface->format;
   220     map->info.src_pitch = surface->pitch;
   221     map->info.dst_fmt = dst->format;
   222     map->info.dst_pitch = dst->pitch;
   223 
   224     /* See if we can do RLE acceleration */
   225     if (surface->flags & SDL_RLEACCELOK) {
   226         if (SDL_RLESurface(surface) == 0) {
   227             return 0;
   228         }
   229     }
   230 
   231     /* Choose a standard blit function */
   232     src_format = SDL_MasksToPixelFormatEnum(surface->format->BitsPerPixel, surface->format->Rmask, surface->format->Gmask, surface->format->Bmask, surface->format->Amask);
   233     dst_format = SDL_MasksToPixelFormatEnum(dst->format->BitsPerPixel, dst->format->Rmask, dst->format->Gmask, dst->format->Bmask, dst->format->Amask);
   234 
   235     if (map->identity && !map->info.flags) {
   236         /* Handle overlapping blits on the same surface */
   237         if (surface == dst) {
   238             blit = SDL_BlitCopyOverlap;
   239         } else {
   240             blit = SDL_BlitCopy;
   241         }
   242     } else if (surface->format->BitsPerPixel < 8) {
   243         blit = SDL_ChooseBlitFunc(src_format, dst_format, map->info.flags, SDL_BlitFuncTable0);
   244     } else if (surface->format->BytesPerPixel == 1) {
   245         blit = SDL_ChooseBlitFunc(src_format, dst_format, map->info.flags, SDL_BlitFuncTable1);
   246     } else {
   247         blit = SDL_ChooseBlitFunc(src_format, dst_format, map->info.flags, SDL_BlitFuncTableN);
   248     }
   249     if (blit == NULL) {
   250         blit = SDL_ChooseBlitFunc(src_format, dst_format, map->info.flags, SDL_GeneratedBlitFuncTable);
   251     }
   252 
   253     /* Make sure we have a blit function */
   254     if (blit == NULL) {
   255         SDL_InvalidateMap(map);
   256         SDL_SetError("Blit combination not supported");
   257         return (-1);
   258     }
   259 
   260     return (0);
   261 }
   262 
   263 /* vi: set ts=4 sw=4 expandtab: */