SDL  2.0
SDL_stretch.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2020 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(_MSC_VER) && defined(_M_IX86)) || \
37  (defined(__WATCOMC__) && defined(__386__)) || \
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__) || defined(__386__)
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", 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) {
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) {
346  }
347  if (src_locked) {
349  }
350  return (0);
351 }
352 
353 /* vi: set ts=4 sw=4 expandtab: */
SDL_UnlockSurface
#define SDL_UnlockSurface
Definition: SDL_dynapi_overrides.h:449
Uint32
uint32_t Uint32
Definition: SDL_stdinc.h:203
SDL_Surface
A collection of pixels used in software blitting.
Definition: SDL_surface.h:70
if
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro pixld1_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl else error unsupported endif endm macro pixld2_s mem_operand if mov asr add asl add asl mov asr sub UNIT_X add asl mov asr add asl add asl mov asr add UNIT_X add asl else pixld1_s mem_operand pixld1_s mem_operand endif endm macro pixld0_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl endif endm macro pixld_s_internal mem_operand if mem_operand pixld2_s mem_operand pixdeinterleave basereg elseif mem_operand elseif mem_operand elseif mem_operand elseif mem_operand pixld0_s mem_operand else pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else error unsupported mem_operand if bpp mem_operand endif endm macro vuzp8 reg2 vuzp d d &reg2 endm macro vzip8 reg2 vzip d d &reg2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld[DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld if[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro fetch_mask_pixblock pixld mask_basereg pixblock_size MASK endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp skip1(dst_w_bpp<=(lowbit *8)) &&((lowbit *8)<(pixblock_size *dst_w_bpp)) .if lowbit< 16 tst DST_R
Definition: pixman-arm-neon-asm.h:469
copy_row3
static void copy_row3(Uint8 *src, int src_w, Uint8 *dst, int dst_w)
Definition: SDL_stretch.c:177
NULL
#define NULL
Definition: begin_code.h:167
SDL_MUSTLOCK
#define SDL_MUSTLOCK(S)
Definition: SDL_surface.h:62
SDL_Rect::x
int x
Definition: SDL_rect.h:79
SDL_Rect::w
int w
Definition: SDL_rect.h:80
dst
GLenum GLenum dst
Definition: SDL_opengl_glext.h:1740
u2
GLfixed GLfixed u2
Definition: SDL_opengl_glext.h:4561
SDL_FALSE
@ SDL_FALSE
Definition: SDL_stdinc.h:163
SDL_Rect::y
int y
Definition: SDL_rect.h:79
SDL_Rect::h
int h
Definition: SDL_rect.h:80
SDL_blit.h
mov
set set set set set set set set set set set set set set set set set set set set *set set set macro pixldst op &r &cond WK op &r &cond WK op &r &cond WK else op &m &cond &ia op &r &cond WK else op &m &cond &ia elseif elseif else error unsupported base if elseif elseif else error unsupported unaligned pixldst unaligned endm macro pixst base base else pixldst base endif endm macro PF base if bpp PF set rept prefetch_distance PF set OFFSET endr endif endm macro preload_leading_step2 base if bpp ifc DST PF PF else if bpp lsl PF PF lsl PF PF lsl PF PF PF else PF mov
Definition: pixman-arm-simd-asm.h:214
Uint16
uint16_t Uint16
Definition: SDL_stdinc.h:191
pop
#define pop
Definition: SDL_qsort.c:196
bpp
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp
Definition: pixman-arm-neon-asm.h:146
SDL_LockSurface
#define SDL_LockSurface
Definition: SDL_dynapi_overrides.h:448
src
GLenum src
Definition: SDL_opengl_glext.h:1740
SDL_TRUE
@ SDL_TRUE
Definition: SDL_stdinc.h:164
SDL_SetError
#define SDL_SetError
Definition: SDL_dynapi_overrides.h:30
SDL_Rect
A rectangle, with the origin at the upper left (integer).
Definition: SDL_rect.h:77
DEFINE_COPY_ROW
#define DEFINE_COPY_ROW(name, type)
Definition: SDL_stretch.c:151
u1
GLfixed u1
Definition: SDL_opengl_glext.h:4561
SDL_video.h
ptr
set set set set set set set set set set set set set set set set set set set set *set set set macro pixldst op &r &cond WK op &r &cond WK op &r &cond WK else op &m &cond &ia op &r &cond WK else op &m &cond &ia elseif elseif else error unsupported base if elseif elseif else error unsupported unaligned pixldst unaligned endm macro pixst base base else pixldst base endif endm macro PF ptr
Definition: pixman-arm-simd-asm.h:171
SDL_SoftStretch
int 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
i
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
SDL_bool
SDL_bool
Definition: SDL_stdinc.h:161
Uint8
uint8_t Uint8
Definition: SDL_stdinc.h:179