src/video/SDL_blit.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 15 Aug 2007 08:21:10 +0000
changeset 2247 93994f65c74c
parent 1895 c121d94672cb
child 2249 5a58b57b6724
permissions -rw-r--r--
Removed hermes since it's LGPL and not compatible with a commercial license.

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