src/video/SDL_blit.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 16 Aug 2007 06:20:51 +0000
changeset 2250 e1d228456537
parent 2249 5a58b57b6724
child 2253 6d99edd791bf
permissions -rw-r--r--
Fixed a few compiler warnings.
Added SDL_blit_copy.c to the Visual C++ project

The SSE and MMX intrinsics don't compile on Visual Studio yet...
     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 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && SDL_ASSEMBLY_ROUTINES
    32 #define MMX_ASMBLIT
    33 #endif
    34 
    35 #if defined(MMX_ASMBLIT)
    36 #include "SDL_cpuinfo.h"
    37 #include "mmx.h"
    38 #endif
    39 
    40 /* The general purpose software blit routine */
    41 static int
    42 SDL_SoftBlit(SDL_Surface * src, SDL_Rect * srcrect,
    43              SDL_Surface * dst, SDL_Rect * dstrect)
    44 {
    45     int okay;
    46     int src_locked;
    47     int dst_locked;
    48 
    49     /* Everything is okay at the beginning...  */
    50     okay = 1;
    51 
    52     /* Lock the destination if it's in hardware */
    53     dst_locked = 0;
    54     if (SDL_MUSTLOCK(dst)) {
    55         if (SDL_LockSurface(dst) < 0) {
    56             okay = 0;
    57         } else {
    58             dst_locked = 1;
    59         }
    60     }
    61     /* Lock the source if it's in hardware */
    62     src_locked = 0;
    63     if (SDL_MUSTLOCK(src)) {
    64         if (SDL_LockSurface(src) < 0) {
    65             okay = 0;
    66         } else {
    67             src_locked = 1;
    68         }
    69     }
    70 
    71     /* Set up source and destination buffer pointers, and BLIT! */
    72     if (okay && srcrect->w && srcrect->h) {
    73         SDL_BlitInfo info;
    74         SDL_loblit RunBlit;
    75 
    76         /* Set up the blit information */
    77         info.s_pixels = (Uint8 *) src->pixels +
    78             (Uint16) srcrect->y * src->pitch +
    79             (Uint16) srcrect->x * src->format->BytesPerPixel;
    80         info.s_width = srcrect->w;
    81         info.s_height = srcrect->h;
    82         info.s_skip = src->pitch - info.s_width * src->format->BytesPerPixel;
    83         info.d_pixels = (Uint8 *) dst->pixels +
    84             (Uint16) dstrect->y * dst->pitch +
    85             (Uint16) dstrect->x * dst->format->BytesPerPixel;
    86         info.d_width = dstrect->w;
    87         info.d_height = dstrect->h;
    88         info.d_skip = dst->pitch - info.d_width * dst->format->BytesPerPixel;
    89         info.aux_data = src->map->sw_data->aux_data;
    90         info.src = src->format;
    91         info.table = src->map->table;
    92         info.dst = dst->format;
    93         RunBlit = src->map->sw_data->blit;
    94 
    95         /* Run the actual software blit */
    96         RunBlit(&info);
    97     }
    98 
    99     /* We need to unlock the surfaces if they're locked */
   100     if (dst_locked) {
   101         SDL_UnlockSurface(dst);
   102     }
   103     if (src_locked) {
   104         SDL_UnlockSurface(src);
   105     }
   106     /* Blit is done! */
   107     return (okay ? 0 : -1);
   108 }
   109 
   110 #ifdef __MACOSX__
   111 #include <sys/sysctl.h>
   112 
   113 static SDL_bool
   114 SDL_UseAltivecPrefetch()
   115 {
   116     const char key[] = "hw.l3cachesize";
   117     u_int64_t result = 0;
   118     size_t typeSize = sizeof(result);
   119 
   120     if (sysctlbyname(key, &result, &typeSize, NULL, 0) == 0 && result > 0) {
   121         return SDL_TRUE;
   122     } else {
   123         return SDL_FALSE;
   124     }
   125 }
   126 #else
   127 static SDL_bool
   128 SDL_UseAltivecPrefetch()
   129 {
   130     /* Just guess G4 */
   131     return SDL_TRUE;
   132 }
   133 #endif /* __MACOSX__ */
   134 
   135 static SDL_loblit
   136 SDL_ChooseBlitFunc(SDL_BlitEntry * entries, int count)
   137 {
   138     int i;
   139     static Uint32 features = 0xffffffff;
   140 
   141     if (features == 0xffffffff) {
   142         const char *override = SDL_getenv("SDL_BLIT_FEATURES");
   143 
   144         features = SDL_BLIT_ANY;
   145 
   146         /* Allow an override for testing .. */
   147         if (override) {
   148             SDL_sscanf(override, "%u", &features);
   149         } else {
   150             if (SDL_HasMMX()) {
   151                 features |= SDL_BLIT_MMX;
   152             }
   153             if (SDL_HasSSE()) {
   154                 features |= SDL_BLIT_SSE;
   155             }
   156             if (SDL_HasAltiVec()) {
   157                 if (SDL_UseAltivecPrefetch()) {
   158                     features |= SDL_BLIT_ALTIVEC_PREFETCH;
   159                 } else {
   160                     features |= SDL_BLIT_ALTIVEC_NOPREFETCH;
   161                 }
   162             }
   163         }
   164     }
   165 
   166     for (i = count; i > 0; --i) {
   167         if (features & entries[i].features) {
   168             return entries[i].blit;
   169         }
   170     }
   171     return entries[0].blit;
   172 }
   173 
   174 /* Figure out which of many blit routines to set up on a surface */
   175 int
   176 SDL_CalculateBlit(SDL_Surface * surface)
   177 {
   178     int blit_index;
   179 
   180     /* Clean everything out to start */
   181     if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
   182         SDL_UnRLESurface(surface, 1);
   183     }
   184     surface->map->sw_blit = NULL;
   185 
   186     /* Get the blit function index, based on surface mode */
   187     /* { 0 = nothing, 1 = colorkey, 2 = alpha, 3 = colorkey+alpha } */
   188     blit_index = 0;
   189     blit_index |= (!!(surface->flags & SDL_SRCCOLORKEY)) << 0;
   190     if (surface->flags & SDL_SRCALPHA
   191         && (surface->format->alpha != SDL_ALPHA_OPAQUE
   192             || surface->format->Amask)) {
   193         blit_index |= 2;
   194     }
   195 
   196     /* Check for special "identity" case -- copy blit */
   197     if (surface->map->identity && blit_index == 0) {
   198         /* Handle overlapping blits on the same surface */
   199         if (surface == surface->map->dst) {
   200             surface->map->sw_data->blit = SDL_BlitCopyOverlap;
   201         } else {
   202             surface->map->sw_data->blit = SDL_BlitCopy;
   203         }
   204     } else {
   205         if (surface->format->BitsPerPixel < 8) {
   206             surface->map->sw_data->blit =
   207                 SDL_CalculateBlit0(surface, blit_index);
   208         } else {
   209             switch (surface->format->BytesPerPixel) {
   210             case 1:
   211                 surface->map->sw_data->blit =
   212                     SDL_CalculateBlit1(surface, blit_index);
   213                 break;
   214             case 2:
   215             case 3:
   216             case 4:
   217                 surface->map->sw_data->blit =
   218                     SDL_CalculateBlitN(surface, blit_index);
   219                 break;
   220             default:
   221                 surface->map->sw_data->blit = NULL;
   222                 break;
   223             }
   224         }
   225     }
   226     /* Make sure we have a blit function */
   227     if (surface->map->sw_data->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->sw_blit = SDL_RLEBlit;
   240         } else if (blit_index == 2 && surface->format->Amask) {
   241             if (SDL_RLESurface(surface) == 0)
   242                 surface->map->sw_blit = SDL_RLEAlphaBlit;
   243         }
   244     }
   245 
   246     if (surface->map->sw_blit == NULL) {
   247         surface->map->sw_blit = SDL_SoftBlit;
   248     }
   249     return (0);
   250 }
   251 
   252 /* vi: set ts=4 sw=4 expandtab: */