src/video/SDL_stretch.c
changeset 1895 c121d94672cb
parent 1849 b5a4ac87b98c
child 1985 8055185ae4ed
equal deleted inserted replaced
1894:c69cee13dd76 1895:c121d94672cb
    53 #error Need assembly opcodes for this architecture
    53 #error Need assembly opcodes for this architecture
    54 #endif
    54 #endif
    55 
    55 
    56 static unsigned char copy_row[4096];
    56 static unsigned char copy_row[4096];
    57 
    57 
    58 static int generate_rowbytes(int src_w, int dst_w, int bpp)
    58 static int
       
    59 generate_rowbytes(int src_w, int dst_w, int bpp)
    59 {
    60 {
    60 	static struct {
    61     static struct
    61 		int bpp;
    62     {
    62 		int src_w;
    63         int bpp;
    63 		int dst_w;
    64         int src_w;
    64 	} last;
    65         int dst_w;
    65 
    66     } last;
    66 	int i;
    67 
    67 	int pos, inc;
    68     int i;
    68 	unsigned char *eip;
    69     int pos, inc;
    69 	unsigned char load, store;
    70     unsigned char *eip;
    70 
    71     unsigned char load, store;
    71 	/* See if we need to regenerate the copy buffer */
    72 
    72 	if ( (src_w == last.src_w) &&
    73     /* See if we need to regenerate the copy buffer */
    73 	     (dst_w == last.dst_w) && (bpp == last.bpp) ) {
    74     if ((src_w == last.src_w) && (dst_w == last.dst_w) && (bpp == last.bpp)) {
    74 		return(0);
    75         return (0);
    75 	}
    76     }
    76 	last.bpp = bpp;
    77     last.bpp = bpp;
    77 	last.src_w = src_w;
    78     last.src_w = src_w;
    78 	last.dst_w = dst_w;
    79     last.dst_w = dst_w;
    79 
    80 
    80 	switch (bpp) {
    81     switch (bpp) {
    81 	    case 1:
    82     case 1:
    82 		load = LOAD_BYTE;
    83         load = LOAD_BYTE;
    83 		store = STORE_BYTE;
    84         store = STORE_BYTE;
    84 		break;
    85         break;
    85 	    case 2:
    86     case 2:
    86 	    case 4:
    87     case 4:
    87 		load = LOAD_WORD;
    88         load = LOAD_WORD;
    88 		store = STORE_WORD;
    89         store = STORE_WORD;
    89 		break;
    90         break;
    90 	    default:
    91     default:
    91 		SDL_SetError("ASM stretch of %d bytes isn't supported\n", bpp);
    92         SDL_SetError("ASM stretch of %d bytes isn't supported\n", bpp);
    92 		return(-1);
    93         return (-1);
    93 	}
    94     }
    94 	pos = 0x10000;
    95     pos = 0x10000;
    95 	inc = (src_w << 16) / dst_w;
    96     inc = (src_w << 16) / dst_w;
    96 	eip = copy_row;
    97     eip = copy_row;
    97 	for ( i=0; i<dst_w; ++i ) {
    98     for (i = 0; i < dst_w; ++i) {
    98 		while ( pos >= 0x10000L ) {
    99         while (pos >= 0x10000L) {
    99 			if ( bpp == 2 ) {
   100             if (bpp == 2) {
   100 				*eip++ = PREFIX16;
   101                 *eip++ = PREFIX16;
   101 			}
   102             }
   102 			*eip++ = load;
   103             *eip++ = load;
   103 			pos -= 0x10000L;
   104             pos -= 0x10000L;
   104 		}
   105         }
   105 		if ( bpp == 2 ) {
   106         if (bpp == 2) {
   106 			*eip++ = PREFIX16;
   107             *eip++ = PREFIX16;
   107 		}
   108         }
   108 		*eip++ = store;
   109         *eip++ = store;
   109 		pos += inc;
   110         pos += inc;
   110 	}
   111     }
   111 	*eip++ = RETURN;
   112     *eip++ = RETURN;
   112 
   113 
   113 	/* Verify that we didn't overflow (too late) */
   114     /* Verify that we didn't overflow (too late) */
   114 	if ( eip > (copy_row+sizeof(copy_row)) ) {
   115     if (eip > (copy_row + sizeof(copy_row))) {
   115 		SDL_SetError("Copy buffer overflow");
   116         SDL_SetError("Copy buffer overflow");
   116 		return(-1);
   117         return (-1);
   117 	}
   118     }
   118 	return(0);
   119     return (0);
   119 }
   120 }
   120 
   121 
   121 #else
   122 #else
   122 
   123 
   123 #define DEFINE_COPY_ROW(name, type)			\
   124 #define DEFINE_COPY_ROW(name, type)			\
   137 		*dst++ = pixel;				\
   138 		*dst++ = pixel;				\
   138 		pos += inc;				\
   139 		pos += inc;				\
   139 	}						\
   140 	}						\
   140 }
   141 }
   141 DEFINE_COPY_ROW(copy_row1, Uint8)
   142 DEFINE_COPY_ROW(copy_row1, Uint8)
   142 DEFINE_COPY_ROW(copy_row2, Uint16)
   143     DEFINE_COPY_ROW(copy_row2, Uint16) DEFINE_COPY_ROW(copy_row4, Uint32)
   143 DEFINE_COPY_ROW(copy_row4, Uint32)
       
   144 
       
   145 #endif /* USE_ASM_STRETCH */
   144 #endif /* USE_ASM_STRETCH */
   146 
       
   147 /* The ASM code doesn't handle 24-bpp stretch blits */
   145 /* The ASM code doesn't handle 24-bpp stretch blits */
   148 void copy_row3(Uint8 *src, int src_w, Uint8 *dst, int dst_w)
   146      void
       
   147      copy_row3(Uint8 * src, int src_w, Uint8 * dst, int dst_w)
   149 {
   148 {
   150 	int i;
   149     int i;
   151 	int pos, inc;
   150     int pos, inc;
   152 	Uint8 pixel[3] = { 0, 0, 0 };
   151     Uint8 pixel[3];
   153 
   152 
   154 	pos = 0x10000;
   153     pos = 0x10000;
   155 	inc = (src_w << 16) / dst_w;
   154     inc = (src_w << 16) / dst_w;
   156 	for ( i=dst_w; i>0; --i ) {
   155     for (i = dst_w; i > 0; --i) {
   157 		while ( pos >= 0x10000L ) {
   156         while (pos >= 0x10000L) {
   158 			pixel[0] = *src++;
   157             pixel[0] = *src++;
   159 			pixel[1] = *src++;
   158             pixel[1] = *src++;
   160 			pixel[2] = *src++;
   159             pixel[2] = *src++;
   161 			pos -= 0x10000L;
   160             pos -= 0x10000L;
   162 		}
   161         }
   163 		*dst++ = pixel[0];
   162         *dst++ = pixel[0];
   164 		*dst++ = pixel[1];
   163         *dst++ = pixel[1];
   165 		*dst++ = pixel[2];
   164         *dst++ = pixel[2];
   166 		pos += inc;
   165         pos += inc;
   167 	}
   166     }
   168 }
   167 }
   169 
   168 
   170 /* Perform a stretch blit between two surfaces of the same format.
   169 /* Perform a stretch blit between two surfaces of the same format.
   171    NOTE:  This function is not safe to call from multiple threads!
   170    NOTE:  This function is not safe to call from multiple threads!
   172 */
   171 */
   173 int SDL_SoftStretch(SDL_Surface *src, SDL_Rect *srcrect,
   172 int
   174                     SDL_Surface *dst, SDL_Rect *dstrect)
   173 SDL_SoftStretch(SDL_Surface * src, SDL_Rect * srcrect,
       
   174                 SDL_Surface * dst, SDL_Rect * dstrect)
   175 {
   175 {
   176 	int src_locked;
   176     int src_locked;
   177 	int dst_locked;
   177     int dst_locked;
   178 	int pos, inc;
   178     int pos, inc;
   179 	int dst_width;
   179     int dst_width;
   180 	int dst_maxrow;
   180     int dst_maxrow;
   181 	int src_row, dst_row;
   181     int src_row, dst_row;
   182 	Uint8 *srcp = NULL;
   182     Uint8 *srcp = NULL;
   183 	Uint8 *dstp;
   183     Uint8 *dstp;
   184 	SDL_Rect full_src;
   184     SDL_Rect full_src;
   185 	SDL_Rect full_dst;
   185     SDL_Rect full_dst;
   186 #if defined(USE_ASM_STRETCH) && defined(__GNUC__)
   186 #if defined(USE_ASM_STRETCH) && defined(__GNUC__)
   187 	int u1, u2;
   187     int u1, u2;
   188 #endif
   188 #endif
   189 	const int bpp = dst->format->BytesPerPixel;
   189     const int bpp = dst->format->BytesPerPixel;
   190 
   190 
   191 	if ( src->format->BitsPerPixel != dst->format->BitsPerPixel ) {
   191     if (src->format->BitsPerPixel != dst->format->BitsPerPixel) {
   192 		SDL_SetError("Only works with same format surfaces");
   192         SDL_SetError("Only works with same format surfaces");
   193 		return(-1);
   193         return (-1);
   194 	}
   194     }
   195 
   195 
   196 	/* Verify the blit rectangles */
   196     /* Verify the blit rectangles */
   197 	if ( srcrect ) {
   197     if (srcrect) {
   198 		if ( (srcrect->x < 0) || (srcrect->y < 0) ||
   198         if ((srcrect->x < 0) || (srcrect->y < 0) ||
   199 		     ((srcrect->x+srcrect->w) > src->w) ||
   199             ((srcrect->x + srcrect->w) > src->w) ||
   200 		     ((srcrect->y+srcrect->h) > src->h) ) {
   200             ((srcrect->y + srcrect->h) > src->h)) {
   201 			SDL_SetError("Invalid source blit rectangle");
   201             SDL_SetError("Invalid source blit rectangle");
   202 			return(-1);
   202             return (-1);
   203 		}
   203         }
   204 	} else {
   204     } else {
   205 		full_src.x = 0;
   205         full_src.x = 0;
   206 		full_src.y = 0;
   206         full_src.y = 0;
   207 		full_src.w = src->w;
   207         full_src.w = src->w;
   208 		full_src.h = src->h;
   208         full_src.h = src->h;
   209 		srcrect = &full_src;
   209         srcrect = &full_src;
   210 	}
   210     }
   211 	if ( dstrect ) {
   211     if (dstrect) {
   212 		if ( (dstrect->x < 0) || (dstrect->y < 0) ||
   212         if ((dstrect->x < 0) || (dstrect->y < 0) ||
   213 		     ((dstrect->x+dstrect->w) > dst->w) ||
   213             ((dstrect->x + dstrect->w) > dst->w) ||
   214 		     ((dstrect->y+dstrect->h) > dst->h) ) {
   214             ((dstrect->y + dstrect->h) > dst->h)) {
   215 			SDL_SetError("Invalid destination blit rectangle");
   215             SDL_SetError("Invalid destination blit rectangle");
   216 			return(-1);
   216             return (-1);
   217 		}
   217         }
   218 	} else {
   218     } else {
   219 		full_dst.x = 0;
   219         full_dst.x = 0;
   220 		full_dst.y = 0;
   220         full_dst.y = 0;
   221 		full_dst.w = dst->w;
   221         full_dst.w = dst->w;
   222 		full_dst.h = dst->h;
   222         full_dst.h = dst->h;
   223 		dstrect = &full_dst;
   223         dstrect = &full_dst;
   224 	}
   224     }
   225 
   225 
   226 	/* Lock the destination if it's in hardware */
   226     /* Lock the destination if it's in hardware */
   227 	dst_locked = 0;
   227     dst_locked = 0;
   228 	if ( SDL_MUSTLOCK(dst) ) {
   228     if (SDL_MUSTLOCK(dst)) {
   229 		if ( SDL_LockSurface(dst) < 0 ) {
   229         if (SDL_LockSurface(dst) < 0) {
   230 			SDL_SetError("Unable to lock destination surface");
   230             SDL_SetError("Unable to lock destination surface");
   231 			return(-1);
   231             return (-1);
   232 		}
   232         }
   233 		dst_locked = 1;
   233         dst_locked = 1;
   234 	}
   234     }
   235 	/* Lock the source if it's in hardware */
   235     /* Lock the source if it's in hardware */
   236 	src_locked = 0;
   236     src_locked = 0;
   237 	if ( SDL_MUSTLOCK(src) ) {
   237     if (SDL_MUSTLOCK(src)) {
   238 		if ( SDL_LockSurface(src) < 0 ) {
   238         if (SDL_LockSurface(src) < 0) {
   239 			if ( dst_locked ) {
   239             if (dst_locked) {
   240 				SDL_UnlockSurface(dst);
   240                 SDL_UnlockSurface(dst);
   241 			}
   241             }
   242 			SDL_SetError("Unable to lock source surface");
   242             SDL_SetError("Unable to lock source surface");
   243 			return(-1);
   243             return (-1);
   244 		}
   244         }
   245 		src_locked = 1;
   245         src_locked = 1;
   246 	}
   246     }
   247 
   247 
   248 	/* Set up the data... */
   248     /* Set up the data... */
   249 	pos = 0x10000;
   249     pos = 0x10000;
   250 	inc = (srcrect->h << 16) / dstrect->h;
   250     inc = (srcrect->h << 16) / dstrect->h;
   251 	src_row = srcrect->y;
   251     src_row = srcrect->y;
   252 	dst_row = dstrect->y;
   252     dst_row = dstrect->y;
   253 	dst_width = dstrect->w*bpp;
   253     dst_width = dstrect->w * bpp;
   254 
   254 
   255 #ifdef USE_ASM_STRETCH
   255 #ifdef USE_ASM_STRETCH
   256 	/* Write the opcodes for this stretch */
   256     /* Write the opcodes for this stretch */
   257 	if ( (bpp != 3) &&
   257     if ((bpp != 3) && (generate_rowbytes(srcrect->w, dstrect->w, bpp) < 0)) {
   258 	     (generate_rowbytes(srcrect->w, dstrect->w, bpp) < 0) ) {
   258         return (-1);
   259 		return(-1);
   259     }
   260 	}
   260 #endif
   261 #endif
   261 
   262 
   262     /* Perform the stretch blit */
   263 	/* Perform the stretch blit */
   263     for (dst_maxrow = dst_row + dstrect->h; dst_row < dst_maxrow; ++dst_row) {
   264 	for ( dst_maxrow = dst_row+dstrect->h; dst_row<dst_maxrow; ++dst_row ) {
   264         dstp = (Uint8 *) dst->pixels + (dst_row * dst->pitch)
   265 		dstp = (Uint8 *)dst->pixels + (dst_row*dst->pitch)
   265             + (dstrect->x * bpp);
   266 		                            + (dstrect->x*bpp);
   266         while (pos >= 0x10000L) {
   267 		while ( pos >= 0x10000L ) {
   267             srcp = (Uint8 *) src->pixels + (src_row * src->pitch)
   268 			srcp = (Uint8 *)src->pixels + (src_row*src->pitch)
   268                 + (srcrect->x * bpp);
   269 			                            + (srcrect->x*bpp);
   269             ++src_row;
   270 			++src_row;
   270             pos -= 0x10000L;
   271 			pos -= 0x10000L;
   271         }
   272 		}
       
   273 #ifdef USE_ASM_STRETCH
   272 #ifdef USE_ASM_STRETCH
   274 		switch (bpp) {
   273         switch (bpp) {
   275 		    case 3:
   274         case 3:
   276 			copy_row3(srcp, srcrect->w, dstp, dstrect->w);
   275             copy_row3(srcp, srcrect->w, dstp, dstrect->w);
   277 			break;
   276             break;
   278 		    default:
   277         default:
   279 #ifdef __GNUC__
   278 #ifdef __GNUC__
   280 			__asm__ __volatile__ (
   279           __asm__ __volatile__("call *%4": "=&D"(u1), "=&S"(u2): "0"(dstp), "1"(srcp), "r"(copy_row):"memory");
   281 			"call *%4"
       
   282 			: "=&D" (u1), "=&S" (u2)
       
   283 			: "0" (dstp), "1" (srcp), "r" (copy_row)
       
   284 			: "memory" );
       
   285 #elif defined(_MSC_VER) || defined(__WATCOMC__)
   280 #elif defined(_MSC_VER) || defined(__WATCOMC__)
   286 		{ void *code = copy_row;
   281             {
   287 			__asm {
   282                 void *code = copy_row;
   288 				push edi
   283                 __asm {
   289 				push esi
   284                 push edi
   290 	
   285                         push esi
   291 				mov edi, dstp
   286                         mov edi, dstp
   292 				mov esi, srcp
   287                         mov esi, srcp call dword ptr code pop esi pop edi}
   293 				call dword ptr code
   288             }
   294 
       
   295 				pop esi
       
   296 				pop edi
       
   297 			}
       
   298 		}
       
   299 #else
   289 #else
   300 #error Need inline assembly for this compiler
   290 #error Need inline assembly for this compiler
   301 #endif
   291 #endif
   302 			break;
   292             break;
   303 		}
   293         }
   304 #else
   294 #else
   305 		switch (bpp) {
   295         switch (bpp) {
   306 		    case 1:
   296         case 1:
   307 			copy_row1(srcp, srcrect->w, dstp, dstrect->w);
   297             copy_row1(srcp, srcrect->w, dstp, dstrect->w);
   308 			break;
   298             break;
   309 		    case 2:
   299         case 2:
   310 			copy_row2((Uint16 *)srcp, srcrect->w,
   300             copy_row2((Uint16 *) srcp, srcrect->w,
   311 			          (Uint16 *)dstp, dstrect->w);
   301                       (Uint16 *) dstp, dstrect->w);
   312 			break;
   302             break;
   313 		    case 3:
   303         case 3:
   314 			copy_row3(srcp, srcrect->w, dstp, dstrect->w);
   304             copy_row3(srcp, srcrect->w, dstp, dstrect->w);
   315 			break;
   305             break;
   316 		    case 4:
   306         case 4:
   317 			copy_row4((Uint32 *)srcp, srcrect->w,
   307             copy_row4((Uint32 *) srcp, srcrect->w,
   318 			          (Uint32 *)dstp, dstrect->w);
   308                       (Uint32 *) dstp, dstrect->w);
   319 			break;
   309             break;
   320 		}
   310         }
   321 #endif
   311 #endif
   322 		pos += inc;
   312         pos += inc;
   323 	}
   313     }
   324 
   314 
   325 	/* We need to unlock the surfaces if they're locked */
   315     /* We need to unlock the surfaces if they're locked */
   326 	if ( dst_locked ) {
   316     if (dst_locked) {
   327 		SDL_UnlockSurface(dst);
   317         SDL_UnlockSurface(dst);
   328 	}
   318     }
   329 	if ( src_locked ) {
   319     if (src_locked) {
   330 		SDL_UnlockSurface(src);
   320         SDL_UnlockSurface(src);
   331 	}
   321     }
   332 	return(0);
   322     return (0);
   333 }
   323 }
   334 
   324 
       
   325 /* vi: set ts=4 sw=4 expandtab: */