cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_stretch.c (10029B)


      1/*
      2  Simple DirectMedia Layer
      3  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
      4
      5  This software is provided 'as-is', without any express or implied
      6  warranty.  In no event will the authors be held liable for any damages
      7  arising from the use of this software.
      8
      9  Permission is granted to anyone to use this software for any purpose,
     10  including commercial applications, and to alter it and redistribute it
     11  freely, subject to the following restrictions:
     12
     13  1. The origin of this software must not be misrepresented; you must not
     14     claim that you wrote the original software. If you use this software
     15     in a product, an acknowledgment in the product documentation would be
     16     appreciated but is not required.
     17  2. Altered source versions must be plainly marked as such, and must not be
     18     misrepresented as being the original software.
     19  3. This notice may not be removed or altered from any source distribution.
     20*/
     21#include "../SDL_internal.h"
     22
     23/* This a stretch blit implementation based on ideas given to me by
     24   Tomasz Cejner - thanks! :)
     25
     26   April 27, 2000 - Sam Lantinga
     27*/
     28
     29#include "SDL_video.h"
     30#include "SDL_blit.h"
     31
     32/* This isn't ready for general consumption yet - it should be folded
     33   into the general blitting mechanism.
     34*/
     35
     36#if ((defined(_MFC_VER) && defined(_M_IX86)) || \
     37     defined(__WATCOMC__) || \
     38     (defined(__GNUC__) && defined(__i386__))) && SDL_ASSEMBLY_ROUTINES
     39/* There's a bug with gcc 4.4.1 and -O2 where srcp doesn't get the correct
     40 * value after the first scanline.  FIXME? */
     41/* #define USE_ASM_STRETCH */
     42#endif
     43
     44#ifdef USE_ASM_STRETCH
     45
     46#ifdef HAVE_MPROTECT
     47#include <sys/types.h>
     48#include <sys/mman.h>
     49#endif
     50#ifdef __GNUC__
     51#define PAGE_ALIGNED __attribute__((__aligned__(4096)))
     52#else
     53#define PAGE_ALIGNED
     54#endif
     55
     56#if defined(_M_IX86) || defined(i386)
     57#define PREFIX16    0x66
     58#define STORE_BYTE  0xAA
     59#define STORE_WORD  0xAB
     60#define LOAD_BYTE   0xAC
     61#define LOAD_WORD   0xAD
     62#define RETURN      0xC3
     63#else
     64#error Need assembly opcodes for this architecture
     65#endif
     66
     67static unsigned char copy_row[4096] PAGE_ALIGNED;
     68
     69static int
     70generate_rowbytes(int src_w, int dst_w, int bpp)
     71{
     72    static struct
     73    {
     74        int bpp;
     75        int src_w;
     76        int dst_w;
     77        int status;
     78    } last;
     79
     80    int i;
     81    int pos, inc;
     82    unsigned char *eip, *fence;
     83    unsigned char load, store;
     84
     85    /* See if we need to regenerate the copy buffer */
     86    if ((src_w == last.src_w) && (dst_w == last.dst_w) && (bpp == last.bpp)) {
     87        return (last.status);
     88    }
     89    last.bpp = bpp;
     90    last.src_w = src_w;
     91    last.dst_w = dst_w;
     92    last.status = -1;
     93
     94    switch (bpp) {
     95    case 1:
     96        load = LOAD_BYTE;
     97        store = STORE_BYTE;
     98        break;
     99    case 2:
    100    case 4:
    101        load = LOAD_WORD;
    102        store = STORE_WORD;
    103        break;
    104    default:
    105        return SDL_SetError("ASM stretch of %d bytes isn't supported\n", bpp);
    106    }
    107#ifdef HAVE_MPROTECT
    108    /* Make the code writeable */
    109    if (mprotect(copy_row, sizeof(copy_row), PROT_READ | PROT_WRITE) < 0) {
    110        return SDL_SetError("Couldn't make copy buffer writeable");
    111    }
    112#endif
    113    pos = 0x10000;
    114    inc = (src_w << 16) / dst_w;
    115    eip = copy_row;
    116    fence = copy_row + sizeof(copy_row)-2;
    117    for (i = 0; i < dst_w; ++i) {
    118        while (pos >= 0x10000L) {
    119            if (eip == fence) {
    120                return -1;
    121            }
    122            if (bpp == 2) {
    123                *eip++ = PREFIX16;
    124            }
    125            *eip++ = load;
    126            pos -= 0x10000L;
    127        }
    128        if (eip == fence) {
    129            return -1;
    130        }
    131        if (bpp == 2) {
    132            *eip++ = PREFIX16;
    133        }
    134        *eip++ = store;
    135        pos += inc;
    136    }
    137    *eip++ = RETURN;
    138
    139#ifdef HAVE_MPROTECT
    140    /* Make the code executable but not writeable */
    141    if (mprotect(copy_row, sizeof(copy_row), PROT_READ | PROT_EXEC) < 0) {
    142        return SDL_SetError("Couldn't make copy buffer executable");
    143    }
    144#endif
    145    last.status = 0;
    146    return (0);
    147}
    148
    149#endif /* USE_ASM_STRETCH */
    150
    151#define DEFINE_COPY_ROW(name, type)         \
    152static void name(type *src, int src_w, type *dst, int dst_w)    \
    153{                                           \
    154    int i;                                  \
    155    int pos, inc;                           \
    156    type pixel = 0;                         \
    157                                            \
    158    pos = 0x10000;                          \
    159    inc = (src_w << 16) / dst_w;            \
    160    for ( i=dst_w; i>0; --i ) {             \
    161        while ( pos >= 0x10000L ) {         \
    162            pixel = *src++;                 \
    163            pos -= 0x10000L;                \
    164        }                                   \
    165        *dst++ = pixel;                     \
    166        pos += inc;                         \
    167    }                                       \
    168}
    169/* *INDENT-OFF* */
    170DEFINE_COPY_ROW(copy_row1, Uint8)
    171DEFINE_COPY_ROW(copy_row2, Uint16)
    172DEFINE_COPY_ROW(copy_row4, Uint32)
    173/* *INDENT-ON* */
    174
    175/* The ASM code doesn't handle 24-bpp stretch blits */
    176static void
    177copy_row3(Uint8 * src, int src_w, Uint8 * dst, int dst_w)
    178{
    179    int i;
    180    int pos, inc;
    181    Uint8 pixel[3] = { 0, 0, 0 };
    182
    183    pos = 0x10000;
    184    inc = (src_w << 16) / dst_w;
    185    for (i = dst_w; i > 0; --i) {
    186        while (pos >= 0x10000L) {
    187            pixel[0] = *src++;
    188            pixel[1] = *src++;
    189            pixel[2] = *src++;
    190            pos -= 0x10000L;
    191        }
    192        *dst++ = pixel[0];
    193        *dst++ = pixel[1];
    194        *dst++ = pixel[2];
    195        pos += inc;
    196    }
    197}
    198
    199/* Perform a stretch blit between two surfaces of the same format.
    200   NOTE:  This function is not safe to call from multiple threads!
    201*/
    202int
    203SDL_SoftStretch(SDL_Surface * src, const SDL_Rect * srcrect,
    204                SDL_Surface * dst, const SDL_Rect * dstrect)
    205{
    206    int src_locked;
    207    int dst_locked;
    208    int pos, inc;
    209    int dst_maxrow;
    210    int src_row, dst_row;
    211    Uint8 *srcp = NULL;
    212    Uint8 *dstp;
    213    SDL_Rect full_src;
    214    SDL_Rect full_dst;
    215#ifdef USE_ASM_STRETCH
    216    SDL_bool use_asm = SDL_TRUE;
    217#ifdef __GNUC__
    218    int u1, u2;
    219#endif
    220#endif /* USE_ASM_STRETCH */
    221    const int bpp = dst->format->BytesPerPixel;
    222
    223    if (src->format->format != dst->format->format) {
    224        return SDL_SetError("Only works with same format surfaces");
    225    }
    226
    227    /* Verify the blit rectangles */
    228    if (srcrect) {
    229        if ((srcrect->x < 0) || (srcrect->y < 0) ||
    230            ((srcrect->x + srcrect->w) > src->w) ||
    231            ((srcrect->y + srcrect->h) > src->h)) {
    232            return SDL_SetError("Invalid source blit rectangle");
    233        }
    234    } else {
    235        full_src.x = 0;
    236        full_src.y = 0;
    237        full_src.w = src->w;
    238        full_src.h = src->h;
    239        srcrect = &full_src;
    240    }
    241    if (dstrect) {
    242        if ((dstrect->x < 0) || (dstrect->y < 0) ||
    243            ((dstrect->x + dstrect->w) > dst->w) ||
    244            ((dstrect->y + dstrect->h) > dst->h)) {
    245            return SDL_SetError("Invalid destination blit rectangle");
    246        }
    247    } else {
    248        full_dst.x = 0;
    249        full_dst.y = 0;
    250        full_dst.w = dst->w;
    251        full_dst.h = dst->h;
    252        dstrect = &full_dst;
    253    }
    254
    255    /* Lock the destination if it's in hardware */
    256    dst_locked = 0;
    257    if (SDL_MUSTLOCK(dst)) {
    258        if (SDL_LockSurface(dst) < 0) {
    259            return SDL_SetError("Unable to lock destination surface");
    260        }
    261        dst_locked = 1;
    262    }
    263    /* Lock the source if it's in hardware */
    264    src_locked = 0;
    265    if (SDL_MUSTLOCK(src)) {
    266        if (SDL_LockSurface(src) < 0) {
    267            if (dst_locked) {
    268                SDL_UnlockSurface(dst);
    269            }
    270            return SDL_SetError("Unable to lock source surface");
    271        }
    272        src_locked = 1;
    273    }
    274
    275    /* Set up the data... */
    276    pos = 0x10000;
    277    inc = (srcrect->h << 16) / dstrect->h;
    278    src_row = srcrect->y;
    279    dst_row = dstrect->y;
    280
    281#ifdef USE_ASM_STRETCH
    282    /* Write the opcodes for this stretch */
    283    if ((bpp == 3) || (generate_rowbytes(srcrect->w, dstrect->w, bpp) < 0)) {
    284        use_asm = SDL_FALSE;
    285    }
    286#endif
    287
    288    /* Perform the stretch blit */
    289    for (dst_maxrow = dst_row + dstrect->h; dst_row < dst_maxrow; ++dst_row) {
    290        dstp = (Uint8 *) dst->pixels + (dst_row * dst->pitch)
    291            + (dstrect->x * bpp);
    292        while (pos >= 0x10000L) {
    293            srcp = (Uint8 *) src->pixels + (src_row * src->pitch)
    294                + (srcrect->x * bpp);
    295            ++src_row;
    296            pos -= 0x10000L;
    297        }
    298#ifdef USE_ASM_STRETCH
    299        if (use_asm) {
    300#ifdef __GNUC__
    301            __asm__ __volatile__("call *%4":"=&D"(u1), "=&S"(u2)
    302                                 :"0"(dstp), "1"(srcp), "r"(copy_row)
    303                                 :"memory");
    304#elif defined(_MSC_VER) || defined(__WATCOMC__)
    305            /* *INDENT-OFF* */
    306            {
    307                void *code = copy_row;
    308                __asm {
    309                    push edi
    310                    push esi
    311                    mov edi, dstp
    312                    mov esi, srcp
    313                    call dword ptr code
    314                    pop esi
    315                    pop edi
    316                }
    317            }
    318            /* *INDENT-ON* */
    319#else
    320#error Need inline assembly for this compiler
    321#endif
    322        } else
    323#endif
    324            switch (bpp) {
    325            case 1:
    326                copy_row1(srcp, srcrect->w, dstp, dstrect->w);
    327                break;
    328            case 2:
    329                copy_row2((Uint16 *) srcp, srcrect->w,
    330                          (Uint16 *) dstp, dstrect->w);
    331                break;
    332            case 3:
    333                copy_row3(srcp, srcrect->w, dstp, dstrect->w);
    334                break;
    335            case 4:
    336                copy_row4((Uint32 *) srcp, srcrect->w,
    337                          (Uint32 *) dstp, dstrect->w);
    338                break;
    339            }
    340        pos += inc;
    341    }
    342
    343    /* We need to unlock the surfaces if they're locked */
    344    if (dst_locked) {
    345        SDL_UnlockSurface(dst);
    346    }
    347    if (src_locked) {
    348        SDL_UnlockSurface(src);
    349    }
    350    return (0);
    351}
    352
    353/* vi: set ts=4 sw=4 expandtab: */