Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.     SDL - Simple DirectMedia Layer
  3.     Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
  4.  
  5.     This library is free software; you can redistribute it and/or
  6.     modify it under the terms of the GNU Library General Public
  7.     License as published by the Free Software Foundation; either
  8.     version 2 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.     Library General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU Library General Public
  16.     License along with this library; if not, write to the Free
  17.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  
  19.     Sam Lantinga
  20.     slouken@devolution.com
  21. */
  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_error.h"
  30. #include "SDL_video.h"
  31. #include "SDL_blit.h"
  32.  
  33. /* This isn't ready for general consumption yet - it should be folded
  34.    into the general blitting mechanism.
  35. */
  36.  
  37. #if (defined(WIN32) && !defined(_M_ALPHA) && !defined(_WIN32_WCE)) || \
  38.     defined(i386) && defined(__GNUC__) && defined(USE_ASMBLIT)
  39. #define USE_ASM_STRETCH
  40. #endif
  41.  
  42. #ifdef USE_ASM_STRETCH
  43.  
  44. #if defined(WIN32) || defined(i386)
  45. #define PREFIX16        0x66
  46. #define STORE_BYTE      0xAA
  47. #define STORE_WORD      0xAB
  48. #define LOAD_BYTE       0xAC
  49. #define LOAD_WORD       0xAD
  50. #define RETURN          0xC3
  51. #else
  52. #error Need assembly opcodes for this architecture
  53. #endif
  54.  
  55. #if defined(__ELF__) && defined(__GNUC__)
  56. extern unsigned char _copy_row[4096] __attribute__ ((alias ("copy_row")));
  57. #endif
  58. static unsigned char copy_row[4096];
  59.  
  60. static int generate_rowbytes(int src_w, int dst_w, int bpp)
  61. {
  62.         static struct {
  63.                 int bpp;
  64.                 int src_w;
  65.                 int dst_w;
  66.         } last;
  67.  
  68.         int i;
  69.         int pos, inc;
  70.         unsigned char *eip;
  71.         unsigned char load, store;
  72.  
  73.         /* See if we need to regenerate the copy buffer */
  74.         if ( (src_w == last.src_w) &&
  75.              (dst_w == last.src_w) && (bpp == last.bpp) ) {
  76.                 return(0);
  77.         }
  78.         last.bpp = bpp;
  79.         last.src_w = src_w;
  80.         last.dst_w = dst_w;
  81.  
  82.         switch (bpp) {
  83.             case 1:
  84.                 load = LOAD_BYTE;
  85.                 store = STORE_BYTE;
  86.                 break;
  87.             case 2:
  88.             case 4:
  89.                 load = LOAD_WORD;
  90.                 store = STORE_WORD;
  91.                 break;
  92.             default:
  93.                 SDL_SetError("ASM stretch of %d bytes isn't supported\n", bpp);
  94.                 return(-1);
  95.         }
  96.         pos = 0x10000;
  97.         inc = (src_w << 16) / dst_w;
  98.         eip = copy_row;
  99.         for ( i=0; i<dst_w; ++i ) {
  100.                 while ( pos >= 0x10000L ) {
  101.                         if ( bpp == 2 ) {
  102.                                 *eip++ = PREFIX16;
  103.                         }
  104.                         *eip++ = load;
  105.                         pos -= 0x10000L;
  106.                 }
  107.                 if ( bpp == 2 ) {
  108.                         *eip++ = PREFIX16;
  109.                 }
  110.                 *eip++ = store;
  111.                 pos += inc;
  112.         }
  113.         *eip++ = RETURN;
  114.  
  115.         /* Verify that we didn't overflow (too late) */
  116.         if ( eip > (copy_row+sizeof(copy_row)) ) {
  117.                 SDL_SetError("Copy buffer overflow");
  118.                 return(-1);
  119.         }
  120.         return(0);
  121. }
  122.  
  123. #else
  124.  
  125. #define DEFINE_COPY_ROW(name, type)                     \
  126. void name(type *src, int src_w, type *dst, int dst_w)   \
  127. {                                                       \
  128.         int i;                                          \
  129.         int pos, inc;                                   \
  130.         type pixel = 0;                                 \
  131.                                                         \
  132.         pos = 0x10000;                                  \
  133.         inc = (src_w << 16) / dst_w;                    \
  134.         for ( i=dst_w; i>0; --i ) {                     \
  135.                 while ( pos >= 0x10000L ) {             \
  136.                         pixel = *src++;                 \
  137.                         pos -= 0x10000L;                \
  138.                 }                                       \
  139.                 *dst++ = pixel;                         \
  140.                 pos += inc;                             \
  141.         }                                               \
  142. }
  143. DEFINE_COPY_ROW(copy_row1, Uint8)
  144. DEFINE_COPY_ROW(copy_row2, Uint16)
  145. DEFINE_COPY_ROW(copy_row4, Uint32)
  146.  
  147. #endif /* USE_ASM_STRETCH */
  148.  
  149. /* The ASM code doesn't handle 24-bpp stretch blits */
  150. void copy_row3(Uint8 *src, int src_w, Uint8 *dst, int dst_w)
  151. {
  152.         int i;
  153.         int pos, inc;
  154.         Uint8 pixel[3];
  155.  
  156.         pos = 0x10000;
  157.         inc = (src_w << 16) / dst_w;
  158.         for ( i=dst_w; i>0; --i ) {
  159.                 while ( pos >= 0x10000L ) {
  160.                         pixel[0] = *src++;
  161.                         pixel[1] = *src++;
  162.                         pixel[2] = *src++;
  163.                         pos -= 0x10000L;
  164.                 }
  165.                 *dst++ = pixel[0];
  166.                 *dst++ = pixel[1];
  167.                 *dst++ = pixel[2];
  168.                 pos += inc;
  169.         }
  170. }
  171.  
  172. /* Perform a stretch blit between two surfaces of the same format.
  173.    NOTE:  This function is not safe to call from multiple threads!
  174. */
  175. int SDL_SoftStretch(SDL_Surface *src, SDL_Rect *srcrect,
  176.                     SDL_Surface *dst, SDL_Rect *dstrect)
  177. {
  178.         int pos, inc;
  179.         int dst_width;
  180.         int dst_maxrow;
  181.         int src_row, dst_row;
  182.         Uint8 *srcp = NULL;
  183.         Uint8 *dstp;
  184.         SDL_Rect full_src;
  185.         SDL_Rect full_dst;
  186. #if defined(USE_ASM_STRETCH) && defined(__GNUC__)
  187.         int u1, u2;
  188. #endif
  189.         const int bpp = dst->format->BytesPerPixel;
  190.  
  191.         if ( src->format->BitsPerPixel != dst->format->BitsPerPixel ) {
  192.                 SDL_SetError("Only works with same format surfaces");
  193.                 return(-1);
  194.         }
  195.  
  196.         /* Verify the blit rectangles */
  197.         if ( srcrect ) {
  198.                 if ( (srcrect->x < 0) || (srcrect->y < 0) ||
  199.                      ((srcrect->x+srcrect->w) > src->w) ||
  200.                      ((srcrect->y+srcrect->h) > src->h) ) {
  201.                         SDL_SetError("Invalid source blit rectangle");
  202.                         return(-1);
  203.                 }
  204.         } else {
  205.                 full_src.x = 0;
  206.                 full_src.y = 0;
  207.                 full_src.w = src->w;
  208.                 full_src.h = src->h;
  209.                 srcrect = &full_src;
  210.         }
  211.         if ( dstrect ) {
  212.                 if ( (dstrect->x < 0) || (dstrect->y < 0) ||
  213.                      ((dstrect->x+dstrect->w) > dst->w) ||
  214.                      ((dstrect->y+dstrect->h) > dst->h) ) {
  215.                         SDL_SetError("Invalid destination blit rectangle");
  216.                         return(-1);
  217.                 }
  218.         } else {
  219.                 full_dst.x = 0;
  220.                 full_dst.y = 0;
  221.                 full_dst.w = dst->w;
  222.                 full_dst.h = dst->h;
  223.                 dstrect = &full_dst;
  224.         }
  225.  
  226.         /* Set up the data... */
  227.         pos = 0x10000;
  228.         inc = (srcrect->h << 16) / dstrect->h;
  229.         src_row = srcrect->y;
  230.         dst_row = dstrect->y;
  231.         dst_width = dstrect->w*bpp;
  232.  
  233. #ifdef USE_ASM_STRETCH
  234.         /* Write the opcodes for this stretch */
  235.         if ( (bpp != 3) &&
  236.              (generate_rowbytes(srcrect->w, dstrect->w, bpp) < 0) ) {
  237.                 return(-1);
  238.         }
  239. #endif
  240.  
  241.         /* Perform the stretch blit */
  242.         for ( dst_maxrow = dst_row+dstrect->h; dst_row<dst_maxrow; ++dst_row ) {
  243.                 dstp = (Uint8 *)dst->pixels + (dst_row*dst->pitch)
  244.                                             + (dstrect->x*bpp);
  245.                 while ( pos >= 0x10000L ) {
  246.                         srcp = (Uint8 *)src->pixels + (src_row*src->pitch)
  247.                                                     + (srcrect->x*bpp);
  248.                         ++src_row;
  249.                         pos -= 0x10000L;
  250.                 }
  251. #ifdef USE_ASM_STRETCH
  252.                 switch (bpp) {
  253.                     case 3:
  254.                         copy_row3(srcp, srcrect->w, dstp, dstrect->w);
  255.                         break;
  256.                     default:
  257. #ifdef __GNUC__
  258.                         __asm__ __volatile__ ("call _copy_row"
  259.                         : "=&D" (u1), "=&S" (u2)
  260.                         : "0" (dstp), "1" (srcp)
  261.                         : "memory" );
  262. #else
  263. #ifdef WIN32
  264.                 { void *code = &copy_row;
  265.                         __asm {
  266.                                 push edi
  267.                                 push esi
  268.        
  269.                                 mov edi, dstp
  270.                                 mov esi, srcp
  271.                                 call dword ptr code
  272.  
  273.                                 pop esi
  274.                                 pop edi
  275.                         }
  276.                 }
  277. #else
  278. #error Need inline assembly for this compiler
  279. #endif
  280. #endif /* __GNUC__ */
  281.                         break;
  282.                 }
  283. #else
  284.                 switch (bpp) {
  285.                     case 1:
  286.                         copy_row1(srcp, srcrect->w, dstp, dstrect->w);
  287.                         break;
  288.                     case 2:
  289.                         copy_row2((Uint16 *)srcp, srcrect->w,
  290.                                   (Uint16 *)dstp, dstrect->w);
  291.                         break;
  292.                     case 3:
  293.                         copy_row3(srcp, srcrect->w, dstp, dstrect->w);
  294.                         break;
  295.                     case 4:
  296.                         copy_row4((Uint32 *)srcp, srcrect->w,
  297.                                   (Uint32 *)dstp, dstrect->w);
  298.                         break;
  299.                 }
  300. #endif
  301.                 pos += inc;
  302.         }
  303.         return(0);
  304. }
  305.  
  306.