zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
SDL_stretch.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2013 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_config.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 
67 static unsigned char copy_row[4096] PAGE_ALIGNED;
68 
69 static int
70 generate_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) \
152 static 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* */
170 DEFINE_COPY_ROW(copy_row1, Uint8)
171 DEFINE_COPY_ROW(copy_row2, Uint16)
172 DEFINE_COPY_ROW(copy_row4, Uint32)
173 /* *INDENT-ON* */
174 
175 /* The ASM code doesn't handle 24-bpp stretch blits */
176 static void
177 copy_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 */
202 int
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: */
GLuint GLdouble u1
Definition: glew.h:3337
#define NULL
Definition: ftobjs.h:61
Uint8 BytesPerPixel
Definition: SDL_pixels.h:277
SDL_bool
Definition: SDL_stdinc.h:116
A collection of pixels used in software blitting.
Definition: SDL_surface.h:69
GLuint GLdouble GLdouble u2
Definition: glew.h:3337
if(!yyg->yy_init)
static void copy_row3(Uint8 *src, int src_w, Uint8 *dst, int dst_w)
Definition: SDL_stretch.c:177
#define DEFINE_COPY_ROW(name, type)
Definition: SDL_stretch.c:151
uint32_t Uint32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:145
DECLSPEC void SDLCALL SDL_UnlockSurface(SDL_Surface *surface)
Definition: SDL_surface.c:786
GLenum GLenum dst
Definition: glew.h:2396
void * pixels
Definition: SDL_surface.h:75
#define pop
Definition: SDL_qsort.c:125
DECLSPEC int SDLCALL SDL_SetError(const char *fmt,...)
Definition: SDL_error.c:53
int x
Definition: SDL_rect.h:65
int w
Definition: SDL_rect.h:66
Definition: inftrees.h:24
SDL_PixelFormat * format
Definition: SDL_surface.h:72
#define SDL_MUSTLOCK(S)
Definition: SDL_surface.h:61
int h
Definition: SDL_rect.h:66
uint8_t Uint8
An unsigned 8-bit integer type.
Definition: SDL_stdinc.h:129
uint16_t Uint16
An unsigned 16-bit integer type.
Definition: SDL_stdinc.h:137
GLenum src
Definition: glew.h:2396
int i
Definition: pngrutil.c:1377
DECLSPEC int SDLCALL SDL_LockSurface(SDL_Surface *surface)
Sets up a surface for directly accessing the pixels.
Definition: SDL_surface.c:765
int y
Definition: SDL_rect.h:65
A rectangle, with the origin at the upper left.
Definition: SDL_rect.h:63
DECLSPEC int SDLCALL SDL_SoftStretch(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, const SDL_Rect *dstrect)
Perform a fast, low quality, stretch blit between two surfaces of the same pixel format.
Definition: SDL_stretch.c:203