src/video/SDL_blit.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 02 Dec 2008 17:14:04 +0000
changeset 2824 4dba7aa7ea77
parent 2805 2ed5ff5373d8
child 2837 ff8db79a3cc9
permissions -rw-r--r--
Added slow but complete blit fallback
Don't try to RLE encode surfaces that have alpha channel and alpha modulation
Don't turn on blending when converting an RGB surface to RGBA format
Do turn on blending when converting colorkey to alpha channel
slouken@0
     1
/*
slouken@0
     2
    SDL - Simple DirectMedia Layer
slouken@1312
     3
    Copyright (C) 1997-2006 Sam Lantinga
slouken@0
     4
slouken@0
     5
    This library is free software; you can redistribute it and/or
slouken@1312
     6
    modify it under the terms of the GNU Lesser General Public
slouken@0
     7
    License as published by the Free Software Foundation; either
slouken@1312
     8
    version 2.1 of the License, or (at your option) any later version.
slouken@0
     9
slouken@0
    10
    This library is distributed in the hope that it will be useful,
slouken@0
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@0
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@1312
    13
    Lesser General Public License for more details.
slouken@0
    14
slouken@1312
    15
    You should have received a copy of the GNU Lesser General Public
slouken@1312
    16
    License along with this library; if not, write to the Free Software
slouken@1312
    17
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
slouken@0
    18
slouken@0
    19
    Sam Lantinga
slouken@252
    20
    slouken@libsdl.org
slouken@0
    21
*/
slouken@1402
    22
#include "SDL_config.h"
slouken@0
    23
slouken@0
    24
#include "SDL_video.h"
slouken@0
    25
#include "SDL_sysvideo.h"
slouken@0
    26
#include "SDL_blit.h"
slouken@2263
    27
#include "SDL_blit_auto.h"
slouken@2254
    28
#include "SDL_blit_copy.h"
slouken@2824
    29
#include "SDL_blit_slow.h"
slouken@0
    30
#include "SDL_RLEaccel_c.h"
slouken@0
    31
#include "SDL_pixels_c.h"
slouken@0
    32
slouken@0
    33
/* The general purpose software blit routine */
slouken@1895
    34
static int
slouken@1895
    35
SDL_SoftBlit(SDL_Surface * src, SDL_Rect * srcrect,
slouken@1895
    36
             SDL_Surface * dst, SDL_Rect * dstrect)
slouken@0
    37
{
slouken@1895
    38
    int okay;
slouken@1895
    39
    int src_locked;
slouken@1895
    40
    int dst_locked;
slouken@0
    41
slouken@1895
    42
    /* Everything is okay at the beginning...  */
slouken@1895
    43
    okay = 1;
slouken@0
    44
slouken@1895
    45
    /* Lock the destination if it's in hardware */
slouken@1895
    46
    dst_locked = 0;
slouken@1895
    47
    if (SDL_MUSTLOCK(dst)) {
slouken@1895
    48
        if (SDL_LockSurface(dst) < 0) {
slouken@1895
    49
            okay = 0;
slouken@1895
    50
        } else {
slouken@1895
    51
            dst_locked = 1;
slouken@1895
    52
        }
slouken@1895
    53
    }
slouken@1895
    54
    /* Lock the source if it's in hardware */
slouken@1895
    55
    src_locked = 0;
slouken@1895
    56
    if (SDL_MUSTLOCK(src)) {
slouken@1895
    57
        if (SDL_LockSurface(src) < 0) {
slouken@1895
    58
            okay = 0;
slouken@1895
    59
        } else {
slouken@1895
    60
            src_locked = 1;
slouken@1895
    61
        }
slouken@1895
    62
    }
slouken@0
    63
slouken@1895
    64
    /* Set up source and destination buffer pointers, and BLIT! */
slouken@1895
    65
    if (okay && srcrect->w && srcrect->h) {
slouken@2263
    66
        SDL_BlitFunc RunBlit;
slouken@2262
    67
        SDL_BlitInfo *info = &src->map->info;
slouken@0
    68
slouken@1895
    69
        /* Set up the blit information */
slouken@2262
    70
        info->src = (Uint8 *) src->pixels +
slouken@1895
    71
            (Uint16) srcrect->y * src->pitch +
slouken@2262
    72
            (Uint16) srcrect->x * info->src_fmt->BytesPerPixel;
slouken@2263
    73
        info->src_w = srcrect->w;
slouken@2263
    74
        info->src_h = srcrect->h;
slouken@2267
    75
        info->src_skip =
slouken@2267
    76
            info->src_pitch - info->src_w * info->src_fmt->BytesPerPixel;
slouken@2267
    77
        info->dst =
slouken@2267
    78
            (Uint8 *) dst->pixels + (Uint16) dstrect->y * dst->pitch +
slouken@2262
    79
            (Uint16) dstrect->x * info->dst_fmt->BytesPerPixel;
slouken@2263
    80
        info->dst_w = dstrect->w;
slouken@2263
    81
        info->dst_h = dstrect->h;
slouken@2267
    82
        info->dst_skip =
slouken@2267
    83
            info->dst_pitch - info->dst_w * info->dst_fmt->BytesPerPixel;
slouken@2262
    84
        RunBlit = (SDL_BlitFunc) src->map->data;
slouken@0
    85
slouken@1895
    86
        /* Run the actual software blit */
slouken@2262
    87
        RunBlit(info);
slouken@1895
    88
    }
slouken@0
    89
slouken@1895
    90
    /* We need to unlock the surfaces if they're locked */
slouken@1895
    91
    if (dst_locked) {
slouken@1895
    92
        SDL_UnlockSurface(dst);
slouken@1895
    93
    }
slouken@1895
    94
    if (src_locked) {
slouken@1895
    95
        SDL_UnlockSurface(src);
slouken@1895
    96
    }
slouken@1895
    97
    /* Blit is done! */
slouken@1895
    98
    return (okay ? 0 : -1);
slouken@0
    99
}
slouken@0
   100
slouken@2247
   101
#ifdef __MACOSX__
slouken@2247
   102
#include <sys/sysctl.h>
slouken@2247
   103
slouken@2249
   104
static SDL_bool
slouken@2249
   105
SDL_UseAltivecPrefetch()
slouken@2247
   106
{
slouken@2247
   107
    const char key[] = "hw.l3cachesize";
slouken@2247
   108
    u_int64_t result = 0;
slouken@2247
   109
    size_t typeSize = sizeof(result);
slouken@2247
   110
slouken@2247
   111
    if (sysctlbyname(key, &result, &typeSize, NULL, 0) == 0 && result > 0) {
slouken@2247
   112
        return SDL_TRUE;
slouken@2247
   113
    } else {
slouken@2247
   114
        return SDL_FALSE;
slouken@2247
   115
    }
slouken@2247
   116
}
slouken@2247
   117
#else
slouken@2249
   118
static SDL_bool
slouken@2249
   119
SDL_UseAltivecPrefetch()
slouken@2247
   120
{
slouken@2247
   121
    /* Just guess G4 */
slouken@2247
   122
    return SDL_TRUE;
slouken@2247
   123
}
slouken@2247
   124
#endif /* __MACOSX__ */
slouken@2247
   125
slouken@2262
   126
static SDL_BlitFunc
slouken@2267
   127
SDL_ChooseBlitFunc(Uint32 src_format, Uint32 dst_format, int flags,
slouken@2267
   128
                   SDL_BlitFuncEntry * entries)
slouken@689
   129
{
slouken@2265
   130
    int i, flagcheck;
slouken@2247
   131
    static Uint32 features = 0xffffffff;
slouken@689
   132
slouken@2262
   133
    /* Get the available CPU features */
slouken@2247
   134
    if (features == 0xffffffff) {
slouken@2262
   135
        const char *override = SDL_getenv("SDL_BLIT_CPU_FEATURES");
slouken@2250
   136
slouken@2262
   137
        features = SDL_CPU_ANY;
slouken@689
   138
slouken@2250
   139
        /* Allow an override for testing .. */
slouken@2247
   140
        if (override) {
slouken@2247
   141
            SDL_sscanf(override, "%u", &features);
slouken@2247
   142
        } else {
slouken@2247
   143
            if (SDL_HasMMX()) {
slouken@2262
   144
                features |= SDL_CPU_MMX;
slouken@2262
   145
            }
slouken@2262
   146
            if (SDL_Has3DNow()) {
slouken@2262
   147
                features |= SDL_CPU_3DNOW;
slouken@2247
   148
            }
slouken@2247
   149
            if (SDL_HasSSE()) {
slouken@2262
   150
                features |= SDL_CPU_SSE;
slouken@2262
   151
            }
slouken@2262
   152
            if (SDL_HasSSE2()) {
slouken@2262
   153
                features |= SDL_CPU_SSE2;
slouken@2247
   154
            }
slouken@2250
   155
            if (SDL_HasAltiVec()) {
slouken@2247
   156
                if (SDL_UseAltivecPrefetch()) {
slouken@2262
   157
                    features |= SDL_CPU_ALTIVEC_PREFETCH;
slouken@2247
   158
                } else {
slouken@2262
   159
                    features |= SDL_CPU_ALTIVEC_NOPREFETCH;
slouken@2247
   160
                }
slouken@2247
   161
            }
slouken@1895
   162
        }
slouken@1895
   163
    }
slouken@2247
   164
slouken@2263
   165
    for (i = 0; entries[i].func; ++i) {
slouken@2265
   166
        /* Check for matching pixel formats */
slouken@2262
   167
        if (src_format != entries[i].src_format) {
slouken@2262
   168
            continue;
slouken@2247
   169
        }
slouken@2262
   170
        if (dst_format != entries[i].dst_format) {
slouken@2262
   171
            continue;
slouken@2262
   172
        }
slouken@2265
   173
slouken@2265
   174
        /* Check modulation flags */
slouken@2267
   175
        flagcheck =
slouken@2267
   176
            (flags & (SDL_COPY_MODULATE_COLOR | SDL_COPY_MODULATE_COLOR));
slouken@2265
   177
        if ((flagcheck & entries[i].flags) != flagcheck) {
slouken@2262
   178
            continue;
slouken@2262
   179
        }
slouken@2265
   180
slouken@2265
   181
        /* Check blend flags */
slouken@2267
   182
        flagcheck =
slouken@2267
   183
            (flags &
slouken@2267
   184
             (SDL_COPY_MASK | SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD));
slouken@2265
   185
        if ((flagcheck & entries[i].flags) != flagcheck) {
slouken@2262
   186
            continue;
slouken@2262
   187
        }
slouken@2265
   188
slouken@2265
   189
        /* Check colorkey flag */
slouken@2265
   190
        flagcheck = (flags & SDL_COPY_COLORKEY);
slouken@2265
   191
        if ((flagcheck & entries[i].flags) != flagcheck) {
slouken@2265
   192
            continue;
slouken@2265
   193
        }
slouken@2265
   194
slouken@2265
   195
        /* Check scaling flags */
slouken@2265
   196
        flagcheck = (flags & SDL_COPY_NEAREST);
slouken@2265
   197
        if ((flagcheck & entries[i].flags) != flagcheck) {
slouken@2265
   198
            continue;
slouken@2265
   199
        }
slouken@2265
   200
slouken@2265
   201
        /* Check CPU features */
slouken@2265
   202
        flagcheck = entries[i].cpu;
slouken@2265
   203
        if ((flagcheck & features) != flagcheck) {
slouken@2265
   204
            continue;
slouken@2265
   205
        }
slouken@2265
   206
slouken@2265
   207
        /* We found the best one! */
slouken@2262
   208
        return entries[i].func;
slouken@2247
   209
    }
slouken@2262
   210
    return NULL;
slouken@0
   211
}
slouken@0
   212
slouken@0
   213
/* Figure out which of many blit routines to set up on a surface */
slouken@1895
   214
int
slouken@1895
   215
SDL_CalculateBlit(SDL_Surface * surface)
slouken@0
   216
{
slouken@2262
   217
    SDL_BlitFunc blit = NULL;
slouken@2266
   218
    SDL_BlitMap *map = surface->map;
slouken@2266
   219
    SDL_Surface *dst = map->dst;
slouken@0
   220
slouken@1895
   221
    /* Clean everything out to start */
slouken@1895
   222
    if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
slouken@1895
   223
        SDL_UnRLESurface(surface, 1);
slouken@1895
   224
    }
slouken@2266
   225
    map->blit = SDL_SoftBlit;
slouken@2266
   226
    map->info.src_fmt = surface->format;
slouken@2266
   227
    map->info.src_pitch = surface->pitch;
slouken@2266
   228
    map->info.dst_fmt = dst->format;
slouken@2266
   229
    map->info.dst_pitch = dst->pitch;
slouken@0
   230
slouken@2266
   231
    /* See if we can do RLE acceleration */
slouken@2805
   232
    if (map->info.flags & SDL_COPY_RLE_DESIRED) {
slouken@2266
   233
        if (SDL_RLESurface(surface) == 0) {
slouken@2266
   234
            return 0;
slouken@2266
   235
        }
slouken@2266
   236
    }
slouken@2266
   237
slouken@2266
   238
    /* Choose a standard blit function */
slouken@2801
   239
    if (map->identity && !(map->info.flags & ~SDL_COPY_RLE_DESIRED)) {
slouken@1895
   240
        /* Handle overlapping blits on the same surface */
slouken@2263
   241
        if (surface == dst) {
slouken@2257
   242
            blit = SDL_BlitCopyOverlap;
slouken@2247
   243
        } else {
slouken@2257
   244
            blit = SDL_BlitCopy;
slouken@1895
   245
        }
slouken@2266
   246
    } else if (surface->format->BitsPerPixel < 8) {
slouken@2267
   247
        blit = SDL_CalculateBlit0(surface);
slouken@2266
   248
    } else if (surface->format->BytesPerPixel == 1) {
slouken@2267
   249
        blit = SDL_CalculateBlit1(surface);
slouken@2267
   250
    } else if (map->info.flags & SDL_COPY_BLEND) {
slouken@2267
   251
        blit = SDL_CalculateBlitA(surface);
slouken@1895
   252
    } else {
slouken@2267
   253
        blit = SDL_CalculateBlitN(surface);
slouken@1895
   254
    }
slouken@2262
   255
    if (blit == NULL) {
slouken@2267
   256
        Uint32 src_format =
slouken@2267
   257
            SDL_MasksToPixelFormatEnum(surface->format->BitsPerPixel,
slouken@2267
   258
                                       surface->format->Rmask,
slouken@2267
   259
                                       surface->format->Gmask,
slouken@2267
   260
                                       surface->format->Bmask,
slouken@2267
   261
                                       surface->format->Amask);
slouken@2267
   262
        Uint32 dst_format =
slouken@2267
   263
            SDL_MasksToPixelFormatEnum(dst->format->BitsPerPixel,
bob@2329
   264
                                       dst->format->Rmask,
bob@2328
   265
                                       dst->format->Gmask,
slouken@2267
   266
                                       dst->format->Bmask,
slouken@2267
   267
                                       dst->format->Amask);
slouken@2267
   268
slouken@2267
   269
        blit =
slouken@2267
   270
            SDL_ChooseBlitFunc(src_format, dst_format, map->info.flags,
slouken@2267
   271
                               SDL_GeneratedBlitFuncTable);
slouken@2262
   272
    }
slouken@2824
   273
#ifndef TEST_SLOW_BLIT
slouken@2824
   274
    if (blit == NULL)
slouken@2824
   275
#endif
slouken@2824
   276
    {
slouken@2824
   277
        if (surface->format->BytesPerPixel > 1
slouken@2824
   278
            && dst->format->BytesPerPixel > 1) {
slouken@2824
   279
            blit = SDL_Blit_Slow;
slouken@2824
   280
        }
slouken@2824
   281
    }
slouken@2267
   282
    map->data = blit;
slouken@2262
   283
slouken@1895
   284
    /* Make sure we have a blit function */
slouken@2257
   285
    if (blit == NULL) {
slouken@2266
   286
        SDL_InvalidateMap(map);
slouken@1895
   287
        SDL_SetError("Blit combination not supported");
slouken@1895
   288
        return (-1);
slouken@1895
   289
    }
slouken@0
   290
slouken@1895
   291
    return (0);
slouken@0
   292
}
slouken@0
   293
slouken@1895
   294
/* vi: set ts=4 sw=4 expandtab: */