src/video/SDL_blit.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 29 May 2006 04:04:35 +0000
branchSDL-1.3
changeset 1668 4da1ee79c9af
parent 1662 782fd950bd46
child 1670 eef792d31de8
permissions -rw-r--r--
more tweaking indent options
     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_RLEaccel_c.h"
    28 #include "SDL_pixels_c.h"
    29 
    30 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && SDL_ASSEMBLY_ROUTINES
    31 #define MMX_ASMBLIT
    32 #endif
    33 
    34 #if defined(MMX_ASMBLIT)
    35 #include "SDL_cpuinfo.h"
    36 #include "mmx.h"
    37 #endif
    38 
    39 /* The general purpose software blit routine */
    40 static int
    41 SDL_SoftBlit(SDL_Surface * src, SDL_Rect * srcrect,
    42              SDL_Surface * dst, SDL_Rect * dstrect)
    43 {
    44     int okay;
    45     int src_locked;
    46     int dst_locked;
    47 
    48     /* Everything is okay at the beginning...  */
    49     okay = 1;
    50 
    51     /* Lock the destination if it's in hardware */
    52     dst_locked = 0;
    53     if (SDL_MUSTLOCK(dst)) {
    54         if (SDL_LockSurface(dst) < 0) {
    55             okay = 0;
    56         } else {
    57             dst_locked = 1;
    58         }
    59     }
    60     /* Lock the source if it's in hardware */
    61     src_locked = 0;
    62     if (SDL_MUSTLOCK(src)) {
    63         if (SDL_LockSurface(src) < 0) {
    64             okay = 0;
    65         } else {
    66             src_locked = 1;
    67         }
    68     }
    69 
    70     /* Set up source and destination buffer pointers, and BLIT! */
    71     if (okay && srcrect->w && srcrect->h) {
    72         SDL_BlitInfo info;
    73         SDL_loblit RunBlit;
    74 
    75         /* Set up the blit information */
    76         info.s_pixels = (Uint8 *) src->pixels +
    77             (Uint16) srcrect->y * src->pitch +
    78             (Uint16) srcrect->x * src->format->BytesPerPixel;
    79         info.s_width = srcrect->w;
    80         info.s_height = srcrect->h;
    81         info.s_skip = src->pitch - info.s_width * src->format->BytesPerPixel;
    82         info.d_pixels = (Uint8 *) dst->pixels +
    83             (Uint16) dstrect->y * dst->pitch +
    84             (Uint16) dstrect->x * dst->format->BytesPerPixel;
    85         info.d_width = dstrect->w;
    86         info.d_height = dstrect->h;
    87         info.d_skip = dst->pitch - info.d_width * dst->format->BytesPerPixel;
    88         info.aux_data = src->map->sw_data->aux_data;
    89         info.src = src->format;
    90         info.table = src->map->table;
    91         info.dst = dst->format;
    92         RunBlit = src->map->sw_data->blit;
    93 
    94         /* Run the actual software blit */
    95         RunBlit(&info);
    96     }
    97 
    98     /* We need to unlock the surfaces if they're locked */
    99     if (dst_locked) {
   100         SDL_UnlockSurface(dst);
   101     }
   102     if (src_locked) {
   103         SDL_UnlockSurface(src);
   104     }
   105     /* Blit is done! */
   106     return (okay ? 0 : -1);
   107 }
   108 
   109 #ifdef MMX_ASMBLIT
   110 static __inline__ void
   111 SDL_memcpyMMX(Uint8 * to, const Uint8 * from, int len)
   112 {
   113     int i;
   114 
   115     for (i = 0; i < len / 8; i++) {
   116         __asm__ __volatile__("	movq (%0), %%mm0\n"
   117                              "	movq %%mm0, (%1)\n"::"r"(from),
   118                              "r"(to):"memory");
   119         from += 8;
   120         to += 8;
   121     }
   122     if (len & 7)
   123         SDL_memcpy(to, from, len & 7);
   124 }
   125 
   126 static __inline__ void
   127 SDL_memcpySSE(Uint8 * to, const Uint8 * from, int len)
   128 {
   129     int i;
   130 
   131     __asm__ __volatile__("	prefetchnta (%0)\n"
   132                          "	prefetchnta 64(%0)\n"
   133                          "	prefetchnta 128(%0)\n"
   134                          "	prefetchnta 192(%0)\n"::"r"(from));
   135 
   136     for (i = 0; i < len / 8; i++) {
   137         __asm__ __volatile__("	prefetchnta 256(%0)\n"
   138                              "	movq (%0), %%mm0\n"
   139                              "	movntq %%mm0, (%1)\n"::"r"(from),
   140                              "r"(to):"memory");
   141         from += 8;
   142         to += 8;
   143     }
   144     if (len & 7)
   145         SDL_memcpy(to, from, len & 7);
   146 }
   147 #endif
   148 
   149 static void
   150 SDL_BlitCopy(SDL_BlitInfo * info)
   151 {
   152     Uint8 *src, *dst;
   153     int w, h;
   154     int srcskip, dstskip;
   155 
   156     w = info->d_width * info->dst->BytesPerPixel;
   157     h = info->d_height;
   158     src = info->s_pixels;
   159     dst = info->d_pixels;
   160     srcskip = w + info->s_skip;
   161     dstskip = w + info->d_skip;
   162 #ifdef MMX_ASMBLIT
   163     if (SDL_HasSSE()) {
   164         while (h--) {
   165             SDL_memcpySSE(dst, src, w);
   166             src += srcskip;
   167             dst += dstskip;
   168         }
   169         __asm__ __volatile__("	emms\n"::);
   170     } else if (SDL_HasMMX()) {
   171         while (h--) {
   172             SDL_memcpyMMX(dst, src, w);
   173             src += srcskip;
   174             dst += dstskip;
   175         }
   176         __asm__ __volatile__("	emms\n"::);
   177     } else
   178 #endif
   179         while (h--) {
   180             SDL_memcpy(dst, src, w);
   181             src += srcskip;
   182             dst += dstskip;
   183         }
   184 }
   185 
   186 static void
   187 SDL_BlitCopyOverlap(SDL_BlitInfo * info)
   188 {
   189     Uint8 *src, *dst;
   190     int w, h;
   191     int srcskip, dstskip;
   192 
   193     w = info->d_width * info->dst->BytesPerPixel;
   194     h = info->d_height;
   195     src = info->s_pixels;
   196     dst = info->d_pixels;
   197     srcskip = w + info->s_skip;
   198     dstskip = w + info->d_skip;
   199     if (dst < src) {
   200         while (h--) {
   201             SDL_memcpy(dst, src, w);
   202             src += srcskip;
   203             dst += dstskip;
   204         }
   205     } else {
   206         src += ((h - 1) * srcskip);
   207         dst += ((h - 1) * dstskip);
   208         while (h--) {
   209             SDL_revcpy(dst, src, w);
   210             src -= srcskip;
   211             dst -= dstskip;
   212         }
   213     }
   214 }
   215 
   216 /* Figure out which of many blit routines to set up on a surface */
   217 int
   218 SDL_CalculateBlit(SDL_Surface * surface)
   219 {
   220     SDL_VideoDevice *_this = SDL_GetVideoDevice();
   221     const SDL_VideoInfo *info = SDL_GetVideoInfo();
   222     int blit_index;
   223 
   224     /* Clean everything out to start */
   225     if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
   226         SDL_UnRLESurface(surface, 1);
   227     }
   228     surface->map->sw_blit = NULL;
   229 
   230     /* Figure out if an accelerated hardware blit is possible */
   231     surface->flags &= ~SDL_HWACCEL;
   232     if (surface->map->identity) {
   233         int hw_blit_ok;
   234 
   235         if ((surface->flags & SDL_HWSURFACE) == SDL_HWSURFACE) {
   236             /* We only support accelerated blitting to hardware */
   237             if (surface->map->dst->flags & SDL_HWSURFACE) {
   238                 hw_blit_ok = info->blit_hw;
   239             } else {
   240                 hw_blit_ok = 0;
   241             }
   242             if (hw_blit_ok && (surface->flags & SDL_SRCCOLORKEY)) {
   243                 hw_blit_ok = info->blit_hw_CC;
   244             }
   245             if (hw_blit_ok && (surface->flags & SDL_SRCALPHA)) {
   246                 hw_blit_ok = info->blit_hw_A;
   247             }
   248         } else {
   249             /* We only support accelerated blitting to hardware */
   250             if (surface->map->dst->flags & SDL_HWSURFACE) {
   251                 hw_blit_ok = info->blit_sw;
   252             } else {
   253                 hw_blit_ok = 0;
   254             }
   255             if (hw_blit_ok && (surface->flags & SDL_SRCCOLORKEY)) {
   256                 hw_blit_ok = info->blit_sw_CC;
   257             }
   258             if (hw_blit_ok && (surface->flags & SDL_SRCALPHA)) {
   259                 hw_blit_ok = info->blit_sw_A;
   260             }
   261         }
   262         if (hw_blit_ok) {
   263             _this->CheckHWBlit(_this, surface, surface->map->dst);
   264         }
   265     }
   266 
   267     /* if an alpha pixel format is specified, we can accelerate alpha blits */
   268     if (((surface->flags & SDL_HWSURFACE) == SDL_HWSURFACE)
   269         && (_this->displayformatalphapixel)) {
   270         if ((surface->flags & SDL_SRCALPHA))
   271             if (info->blit_hw_A) {
   272                 _this->CheckHWBlit(_this, surface, surface->map->dst);
   273             }
   274     }
   275 
   276     /* Get the blit function index, based on surface mode */
   277     /* { 0 = nothing, 1 = colorkey, 2 = alpha, 3 = colorkey+alpha } */
   278     blit_index = 0;
   279     blit_index |= (!!(surface->flags & SDL_SRCCOLORKEY)) << 0;
   280     if (surface->flags & SDL_SRCALPHA
   281         && (surface->format->alpha != SDL_ALPHA_OPAQUE
   282             || surface->format->Amask)) {
   283         blit_index |= 2;
   284     }
   285 
   286     /* Check for special "identity" case -- copy blit */
   287     if (surface->map->identity && blit_index == 0) {
   288         surface->map->sw_data->blit = SDL_BlitCopy;
   289 
   290         /* Handle overlapping blits on the same surface */
   291         if (surface == surface->map->dst) {
   292             surface->map->sw_data->blit = SDL_BlitCopyOverlap;
   293         }
   294     } else {
   295         if (surface->format->BitsPerPixel < 8) {
   296             surface->map->sw_data->blit =
   297                 SDL_CalculateBlit0(surface, blit_index);
   298         } else {
   299             switch (surface->format->BytesPerPixel) {
   300             case 1:
   301                 surface->map->sw_data->blit =
   302                     SDL_CalculateBlit1(surface, blit_index);
   303                 break;
   304             case 2:
   305             case 3:
   306             case 4:
   307                 surface->map->sw_data->blit =
   308                     SDL_CalculateBlitN(surface, blit_index);
   309                 break;
   310             default:
   311                 surface->map->sw_data->blit = NULL;
   312                 break;
   313             }
   314         }
   315     }
   316     /* Make sure we have a blit function */
   317     if (surface->map->sw_data->blit == NULL) {
   318         SDL_InvalidateMap(surface->map);
   319         SDL_SetError("Blit combination not supported");
   320         return (-1);
   321     }
   322 
   323     /* Choose software blitting function */
   324     if (surface->flags & SDL_RLEACCELOK
   325         && (surface->flags & SDL_HWACCEL) != SDL_HWACCEL) {
   326 
   327         if (surface->map->identity
   328             && (blit_index == 1
   329                 || (blit_index == 3 && !surface->format->Amask))) {
   330             if (SDL_RLESurface(surface) == 0)
   331                 surface->map->sw_blit = SDL_RLEBlit;
   332         } else if (blit_index == 2 && surface->format->Amask) {
   333             if (SDL_RLESurface(surface) == 0)
   334                 surface->map->sw_blit = SDL_RLEAlphaBlit;
   335         }
   336     }
   337 
   338     if (surface->map->sw_blit == NULL) {
   339         surface->map->sw_blit = SDL_SoftBlit;
   340     }
   341     return (0);
   342 }
   343 
   344 /* vi: set ts=4 sw=4 expandtab: */