src/video/SDL_blit.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 11 Feb 2011 14:51:04 -0800
changeset 5259 6a65c1fc07af
parent 5184 d976b67150c5
child 5262 b530ef003506
permissions -rw-r--r--
Updated CPU detection code for SSE3 and SSE4 and removed obsolete 3DNow! and Altivec support.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2010 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_blit_slow.h"
    30 #include "SDL_RLEaccel_c.h"
    31 #include "SDL_pixels_c.h"
    32 
    33 /* The general purpose software blit routine */
    34 static int
    35 SDL_SoftBlit(SDL_Surface * src, SDL_Rect * srcrect,
    36              SDL_Surface * dst, SDL_Rect * dstrect)
    37 {
    38     int okay;
    39     int src_locked;
    40     int dst_locked;
    41 
    42     /* Everything is okay at the beginning...  */
    43     okay = 1;
    44 
    45     /* Lock the destination if it's in hardware */
    46     dst_locked = 0;
    47     if (SDL_MUSTLOCK(dst)) {
    48         if (SDL_LockSurface(dst) < 0) {
    49             okay = 0;
    50         } else {
    51             dst_locked = 1;
    52         }
    53     }
    54     /* Lock the source if it's in hardware */
    55     src_locked = 0;
    56     if (SDL_MUSTLOCK(src)) {
    57         if (SDL_LockSurface(src) < 0) {
    58             okay = 0;
    59         } else {
    60             src_locked = 1;
    61         }
    62     }
    63 
    64     /* Set up source and destination buffer pointers, and BLIT! */
    65     if (okay && srcrect->w && srcrect->h) {
    66         SDL_BlitFunc RunBlit;
    67         SDL_BlitInfo *info = &src->map->info;
    68 
    69         /* Set up the blit information */
    70         info->src = (Uint8 *) src->pixels +
    71             (Uint16) srcrect->y * src->pitch +
    72             (Uint16) srcrect->x * info->src_fmt->BytesPerPixel;
    73         info->src_w = srcrect->w;
    74         info->src_h = srcrect->h;
    75         info->src_pitch = src->pitch;
    76         info->src_skip =
    77             info->src_pitch - info->src_w * info->src_fmt->BytesPerPixel;
    78         info->dst =
    79             (Uint8 *) dst->pixels + (Uint16) dstrect->y * dst->pitch +
    80             (Uint16) dstrect->x * info->dst_fmt->BytesPerPixel;
    81         info->dst_w = dstrect->w;
    82         info->dst_h = dstrect->h;
    83         info->dst_pitch = dst->pitch;
    84         info->dst_skip =
    85             info->dst_pitch - info->dst_w * info->dst_fmt->BytesPerPixel;
    86         RunBlit = (SDL_BlitFunc) src->map->data;
    87 
    88         /* Run the actual software blit */
    89         RunBlit(info);
    90     }
    91 
    92     /* We need to unlock the surfaces if they're locked */
    93     if (dst_locked) {
    94         SDL_UnlockSurface(dst);
    95     }
    96     if (src_locked) {
    97         SDL_UnlockSurface(src);
    98     }
    99     /* Blit is done! */
   100     return (okay ? 0 : -1);
   101 }
   102 
   103 
   104 static SDL_BlitFunc
   105 SDL_ChooseBlitFunc(Uint32 src_format, Uint32 dst_format, int flags,
   106                    SDL_BlitFuncEntry * entries)
   107 {
   108     int i, flagcheck;
   109     static Uint32 features = 0xffffffff;
   110 
   111     /* Get the available CPU features */
   112     if (features == 0xffffffff) {
   113         const char *override = SDL_getenv("SDL_BLIT_CPU_FEATURES");
   114 
   115         features = SDL_CPU_ANY;
   116 
   117         /* Allow an override for testing .. */
   118         if (override) {
   119             SDL_sscanf(override, "%u", &features);
   120         } else {
   121             if (SDL_HasMMX()) {
   122                 features |= SDL_CPU_MMX;
   123             }
   124             if (SDL_HasSSE()) {
   125                 features |= SDL_CPU_SSE;
   126             }
   127             if (SDL_HasSSE2()) {
   128                 features |= SDL_CPU_SSE2;
   129             }
   130         }
   131     }
   132 
   133     for (i = 0; entries[i].func; ++i) {
   134         /* Check for matching pixel formats */
   135         if (src_format != entries[i].src_format) {
   136             continue;
   137         }
   138         if (dst_format != entries[i].dst_format) {
   139             continue;
   140         }
   141 
   142         /* Check modulation flags */
   143         flagcheck =
   144             (flags & (SDL_COPY_MODULATE_COLOR | SDL_COPY_MODULATE_ALPHA));
   145         if ((flagcheck & entries[i].flags) != flagcheck) {
   146             continue;
   147         }
   148 
   149         /* Check blend flags */
   150         flagcheck =
   151             (flags &
   152              (SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD));
   153         if ((flagcheck & entries[i].flags) != flagcheck) {
   154             continue;
   155         }
   156 
   157         /* Check colorkey flag */
   158         flagcheck = (flags & SDL_COPY_COLORKEY);
   159         if ((flagcheck & entries[i].flags) != flagcheck) {
   160             continue;
   161         }
   162 
   163         /* Check scaling flags */
   164         flagcheck = (flags & SDL_COPY_NEAREST);
   165         if ((flagcheck & entries[i].flags) != flagcheck) {
   166             continue;
   167         }
   168 
   169         /* Check CPU features */
   170         flagcheck = entries[i].cpu;
   171         if ((flagcheck & features) != flagcheck) {
   172             continue;
   173         }
   174 
   175         /* We found the best one! */
   176         return entries[i].func;
   177     }
   178     return NULL;
   179 }
   180 
   181 /* Figure out which of many blit routines to set up on a surface */
   182 int
   183 SDL_CalculateBlit(SDL_Surface * surface)
   184 {
   185     SDL_BlitFunc blit = NULL;
   186     SDL_BlitMap *map = surface->map;
   187     SDL_Surface *dst = map->dst;
   188 
   189     /* Clean everything out to start */
   190     if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
   191         SDL_UnRLESurface(surface, 1);
   192     }
   193     map->blit = SDL_SoftBlit;
   194     map->info.src_fmt = surface->format;
   195     map->info.src_pitch = surface->pitch;
   196     map->info.dst_fmt = dst->format;
   197     map->info.dst_pitch = dst->pitch;
   198 
   199     /* See if we can do RLE acceleration */
   200     if (map->info.flags & SDL_COPY_RLE_DESIRED) {
   201         if (SDL_RLESurface(surface) == 0) {
   202             return 0;
   203         }
   204     }
   205 
   206     /* Choose a standard blit function */
   207     if (map->identity && !(map->info.flags & ~SDL_COPY_RLE_DESIRED)) {
   208         /* Handle overlapping blits on the same surface */
   209         if (surface == dst) {
   210             blit = SDL_BlitCopyOverlap;
   211         } else {
   212             blit = SDL_BlitCopy;
   213         }
   214     } else if (surface->format->BitsPerPixel < 8) {
   215         blit = SDL_CalculateBlit0(surface);
   216     } else if (surface->format->BytesPerPixel == 1) {
   217         blit = SDL_CalculateBlit1(surface);
   218     } else if (map->info.flags & SDL_COPY_BLEND) {
   219         blit = SDL_CalculateBlitA(surface);
   220     } else {
   221         blit = SDL_CalculateBlitN(surface);
   222     }
   223     if (blit == NULL) {
   224         Uint32 src_format =
   225             SDL_MasksToPixelFormatEnum(surface->format->BitsPerPixel,
   226                                        surface->format->Rmask,
   227                                        surface->format->Gmask,
   228                                        surface->format->Bmask,
   229                                        surface->format->Amask);
   230         Uint32 dst_format =
   231             SDL_MasksToPixelFormatEnum(dst->format->BitsPerPixel,
   232                                        dst->format->Rmask,
   233                                        dst->format->Gmask,
   234                                        dst->format->Bmask,
   235                                        dst->format->Amask);
   236 
   237         blit =
   238             SDL_ChooseBlitFunc(src_format, dst_format, map->info.flags,
   239                                SDL_GeneratedBlitFuncTable);
   240     }
   241 #ifndef TEST_SLOW_BLIT
   242     if (blit == NULL)
   243 #endif
   244     {
   245         if (surface->format->BytesPerPixel > 1
   246             && dst->format->BytesPerPixel > 1) {
   247             blit = SDL_Blit_Slow;
   248         }
   249     }
   250     map->data = blit;
   251 
   252     /* Make sure we have a blit function */
   253     if (blit == NULL) {
   254         SDL_InvalidateMap(map);
   255         SDL_SetError("Blit combination not supported");
   256         return (-1);
   257     }
   258 
   259     return (0);
   260 }
   261 
   262 /* vi: set ts=4 sw=4 expandtab: */