src/video/SDL_blit.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 16 Aug 2007 22:18:53 +0000
changeset 2255 17b2369756be
parent 2254 79e00f5561f4
child 2257 340942cfda48
permissions -rw-r--r--
Use MMX intrinsics over GCC inline assembly
     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;
    65         SDL_loblit RunBlit;
    66 
    67         /* Set up the blit information */
    68         info.s_pixels = (Uint8 *) src->pixels +
    69             (Uint16) srcrect->y * src->pitch +
    70             (Uint16) srcrect->x * src->format->BytesPerPixel;
    71         info.s_width = srcrect->w;
    72         info.s_height = srcrect->h;
    73         info.s_skip = src->pitch - info.s_width * src->format->BytesPerPixel;
    74         info.d_pixels = (Uint8 *) dst->pixels +
    75             (Uint16) dstrect->y * dst->pitch +
    76             (Uint16) dstrect->x * dst->format->BytesPerPixel;
    77         info.d_width = dstrect->w;
    78         info.d_height = dstrect->h;
    79         info.d_skip = dst->pitch - info.d_width * dst->format->BytesPerPixel;
    80         info.aux_data = src->map->sw_data->aux_data;
    81         info.src = src->format;
    82         info.table = src->map->table;
    83         info.dst = dst->format;
    84         RunBlit = src->map->sw_data->blit;
    85 
    86         /* Run the actual software blit */
    87         RunBlit(&info);
    88     }
    89 
    90     /* We need to unlock the surfaces if they're locked */
    91     if (dst_locked) {
    92         SDL_UnlockSurface(dst);
    93     }
    94     if (src_locked) {
    95         SDL_UnlockSurface(src);
    96     }
    97     /* Blit is done! */
    98     return (okay ? 0 : -1);
    99 }
   100 
   101 #ifdef __MACOSX__
   102 #include <sys/sysctl.h>
   103 
   104 static SDL_bool
   105 SDL_UseAltivecPrefetch()
   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 SDL_TRUE;
   113     } else {
   114         return SDL_FALSE;
   115     }
   116 }
   117 #else
   118 static SDL_bool
   119 SDL_UseAltivecPrefetch()
   120 {
   121     /* Just guess G4 */
   122     return SDL_TRUE;
   123 }
   124 #endif /* __MACOSX__ */
   125 
   126 static SDL_loblit
   127 SDL_ChooseBlitFunc(SDL_BlitEntry * entries, int count)
   128 {
   129     int i;
   130     static Uint32 features = 0xffffffff;
   131 
   132     if (features == 0xffffffff) {
   133         const char *override = SDL_getenv("SDL_BLIT_FEATURES");
   134 
   135         features = SDL_BLIT_ANY;
   136 
   137         /* Allow an override for testing .. */
   138         if (override) {
   139             SDL_sscanf(override, "%u", &features);
   140         } else {
   141             if (SDL_HasMMX()) {
   142                 features |= SDL_BLIT_MMX;
   143             }
   144             if (SDL_HasSSE()) {
   145                 features |= SDL_BLIT_SSE;
   146             }
   147             if (SDL_HasAltiVec()) {
   148                 if (SDL_UseAltivecPrefetch()) {
   149                     features |= SDL_BLIT_ALTIVEC_PREFETCH;
   150                 } else {
   151                     features |= SDL_BLIT_ALTIVEC_NOPREFETCH;
   152                 }
   153             }
   154         }
   155     }
   156 
   157     for (i = count; i > 0; --i) {
   158         if (features & entries[i].features) {
   159             return entries[i].blit;
   160         }
   161     }
   162     return entries[0].blit;
   163 }
   164 
   165 /* Figure out which of many blit routines to set up on a surface */
   166 int
   167 SDL_CalculateBlit(SDL_Surface * surface)
   168 {
   169     int blit_index;
   170 
   171     /* Clean everything out to start */
   172     if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
   173         SDL_UnRLESurface(surface, 1);
   174     }
   175     surface->map->sw_blit = NULL;
   176 
   177     /* Get the blit function index, based on surface mode */
   178     /* { 0 = nothing, 1 = colorkey, 2 = alpha, 3 = colorkey+alpha } */
   179     blit_index = 0;
   180     blit_index |= (!!(surface->flags & SDL_SRCCOLORKEY)) << 0;
   181     if (surface->flags & SDL_SRCALPHA
   182         && (surface->format->alpha != SDL_ALPHA_OPAQUE
   183             || surface->format->Amask)) {
   184         blit_index |= 2;
   185     }
   186 
   187     /* Check for special "identity" case -- copy blit */
   188     if (surface->map->identity && blit_index == 0) {
   189         /* Handle overlapping blits on the same surface */
   190         if (surface == surface->map->dst) {
   191             surface->map->sw_data->blit = SDL_BlitCopyOverlap;
   192         } else {
   193             surface->map->sw_data->blit = SDL_BlitCopy;
   194         }
   195     } else {
   196         if (surface->format->BitsPerPixel < 8) {
   197             surface->map->sw_data->blit =
   198                 SDL_CalculateBlit0(surface, blit_index);
   199         } else {
   200             switch (surface->format->BytesPerPixel) {
   201             case 1:
   202                 surface->map->sw_data->blit =
   203                     SDL_CalculateBlit1(surface, blit_index);
   204                 break;
   205             case 2:
   206             case 3:
   207             case 4:
   208                 surface->map->sw_data->blit =
   209                     SDL_CalculateBlitN(surface, blit_index);
   210                 break;
   211             default:
   212                 surface->map->sw_data->blit = NULL;
   213                 break;
   214             }
   215         }
   216     }
   217     /* Make sure we have a blit function */
   218     if (surface->map->sw_data->blit == NULL) {
   219         SDL_InvalidateMap(surface->map);
   220         SDL_SetError("Blit combination not supported");
   221         return (-1);
   222     }
   223 
   224     /* Choose software blitting function */
   225     if (surface->flags & SDL_RLEACCELOK) {
   226         if (surface->map->identity
   227             && (blit_index == 1
   228                 || (blit_index == 3 && !surface->format->Amask))) {
   229             if (SDL_RLESurface(surface) == 0)
   230                 surface->map->sw_blit = SDL_RLEBlit;
   231         } else if (blit_index == 2 && surface->format->Amask) {
   232             if (SDL_RLESurface(surface) == 0)
   233                 surface->map->sw_blit = SDL_RLEAlphaBlit;
   234         }
   235     }
   236 
   237     if (surface->map->sw_blit == NULL) {
   238         surface->map->sw_blit = SDL_SoftBlit;
   239     }
   240     return (0);
   241 }
   242 
   243 /* vi: set ts=4 sw=4 expandtab: */