2 Simple DirectMedia Layer
3 Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
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.
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:
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.
21 #include "../SDL_internal.h"
23 /* This a stretch blit implementation based on ideas given to me by
24 Tomasz Cejner - thanks! :)
26 April 27, 2000 - Sam Lantinga
29 #include "SDL_video.h"
32 /* This isn't ready for general consumption yet - it should be folded
33 into the general blitting mechanism.
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 */
44 #ifdef USE_ASM_STRETCH
47 #include <sys/types.h>
51 #define PAGE_ALIGNED __attribute__((__aligned__(4096)))
56 #if defined(_M_IX86) || defined(i386)
58 #define STORE_BYTE 0xAA
59 #define STORE_WORD 0xAB
60 #define LOAD_BYTE 0xAC
61 #define LOAD_WORD 0xAD
64 #error Need assembly opcodes for this architecture
67 static unsigned char copy_row[4096] PAGE_ALIGNED;
70 generate_rowbytes(int src_w, int dst_w, int bpp)
82 unsigned char *eip, *fence;
83 unsigned char load, store;
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)) {
105 return SDL_SetError("ASM stretch of %d bytes isn't supported\n", bpp);
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");
114 inc = (src_w << 16) / dst_w;
116 fence = copy_row + sizeof(copy_row)-2;
117 for (i = 0; i < dst_w; ++i) {
118 while (pos >= 0x10000L) {
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");
149 #endif /* USE_ASM_STRETCH */
151 #define DEFINE_COPY_ROW(name, type) \
152 static void name(type *src, int src_w, type *dst, int dst_w) \
159 inc = (src_w << 16) / dst_w; \
160 for ( i=dst_w; i>0; --i ) { \
161 while ( pos >= 0x10000L ) { \
170 DEFINE_COPY_ROW(copy_row1, Uint8)
171 DEFINE_COPY_ROW(copy_row2, Uint16)
172 DEFINE_COPY_ROW(copy_row4, Uint32)
175 /* The ASM code doesn't handle 24-bpp stretch blits */
177 copy_row3(Uint8 * src, int src_w, Uint8 * dst, int dst_w)
181 Uint8 pixel[3] = { 0, 0, 0 };
184 inc = (src_w << 16) / dst_w;
185 for (i = dst_w; i > 0; --i) {
186 while (pos >= 0x10000L) {
199 /* Perform a stretch blit between two surfaces of the same format.
200 NOTE: This function is not safe to call from multiple threads!
203 SDL_SoftStretch(SDL_Surface * src, const SDL_Rect * srcrect,
204 SDL_Surface * dst, const SDL_Rect * dstrect)
210 int src_row, dst_row;
215 #ifdef USE_ASM_STRETCH
216 SDL_bool use_asm = SDL_TRUE;
220 #endif /* USE_ASM_STRETCH */
221 const int bpp = dst->format->BytesPerPixel;
223 if (src->format->format != dst->format->format) {
224 return SDL_SetError("Only works with same format surfaces");
227 /* Verify the blit rectangles */
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");
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");
255 /* Lock the destination if it's in hardware */
257 if (SDL_MUSTLOCK(dst)) {
258 if (SDL_LockSurface(dst) < 0) {
259 return SDL_SetError("Unable to lock destination surface");
263 /* Lock the source if it's in hardware */
265 if (SDL_MUSTLOCK(src)) {
266 if (SDL_LockSurface(src) < 0) {
268 SDL_UnlockSurface(dst);
270 return SDL_SetError("Unable to lock source surface");
275 /* Set up the data... */
277 inc = (srcrect->h << 16) / dstrect->h;
278 src_row = srcrect->y;
279 dst_row = dstrect->y;
281 #ifdef USE_ASM_STRETCH
282 /* Write the opcodes for this stretch */
283 if ((bpp == 3) || (generate_rowbytes(srcrect->w, dstrect->w, bpp) < 0)) {
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);
298 #ifdef USE_ASM_STRETCH
301 __asm__ __volatile__("call *%4":"=&D"(u1), "=&S"(u2)
302 :"0"(dstp), "1"(srcp), "r"(copy_row)
304 #elif defined(_MSC_VER) || defined(__WATCOMC__)
307 void *code = copy_row;
320 #error Need inline assembly for this compiler
326 copy_row1(srcp, srcrect->w, dstp, dstrect->w);
329 copy_row2((Uint16 *) srcp, srcrect->w,
330 (Uint16 *) dstp, dstrect->w);
333 copy_row3(srcp, srcrect->w, dstp, dstrect->w);
336 copy_row4((Uint32 *) srcp, srcrect->w,
337 (Uint32 *) dstp, dstrect->w);
343 /* We need to unlock the surfaces if they're locked */
345 SDL_UnlockSurface(dst);
348 SDL_UnlockSurface(src);
353 /* vi: set ts=4 sw=4 expandtab: */