Skip to content
This repository has been archived by the owner on Feb 11, 2021. It is now read-only.

Latest commit

 

History

History
353 lines (323 loc) · 9.79 KB

SDL_stretch.c

File metadata and controls

353 lines (323 loc) · 9.79 KB
 
1
2
/*
Simple DirectMedia Layer
Feb 15, 2013
Feb 15, 2013
3
Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_config.h"
/* This a stretch blit implementation based on ideas given to me by
Tomasz Cejner - thanks! :)
April 27, 2000 - Sam Lantinga
*/
#include "SDL_video.h"
#include "SDL_blit.h"
/* This isn't ready for general consumption yet - it should be folded
into the general blitting mechanism.
*/
#if ((defined(_MFC_VER) && defined(_M_IX86)) || \
defined(__WATCOMC__) || \
(defined(__GNUC__) && defined(__i386__))) && SDL_ASSEMBLY_ROUTINES
/* There's a bug with gcc 4.4.1 and -O2 where srcp doesn't get the correct
* value after the first scanline. FIXME? */
/*#define USE_ASM_STRETCH*/
#endif
#ifdef USE_ASM_STRETCH
#ifdef HAVE_MPROTECT
#include <sys/types.h>
#include <sys/mman.h>
#endif
#ifdef __GNUC__
#define PAGE_ALIGNED __attribute__((__aligned__(4096)))
#else
#define PAGE_ALIGNED
#endif
#if defined(_M_IX86) || defined(i386)
May 22, 2013
May 22, 2013
57
58
59
60
61
62
#define PREFIX16 0x66
#define STORE_BYTE 0xAA
#define STORE_WORD 0xAB
#define LOAD_BYTE 0xAC
#define LOAD_WORD 0xAD
#define RETURN 0xC3
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#else
#error Need assembly opcodes for this architecture
#endif
static unsigned char copy_row[4096] PAGE_ALIGNED;
static int
generate_rowbytes(int src_w, int dst_w, int bpp)
{
static struct
{
int bpp;
int src_w;
int dst_w;
int status;
} last;
int i;
int pos, inc;
unsigned char *eip, *fence;
unsigned char load, store;
/* See if we need to regenerate the copy buffer */
if ((src_w == last.src_w) && (dst_w == last.dst_w) && (bpp == last.bpp)) {
return (last.status);
}
last.bpp = bpp;
last.src_w = src_w;
last.dst_w = dst_w;
last.status = -1;
switch (bpp) {
case 1:
load = LOAD_BYTE;
store = STORE_BYTE;
break;
case 2:
case 4:
load = LOAD_WORD;
store = STORE_WORD;
break;
default:
Mar 31, 2013
Mar 31, 2013
105
return SDL_SetError("ASM stretch of %d bytes isn't supported\n", bpp);
106
107
108
109
}
#ifdef HAVE_MPROTECT
/* Make the code writeable */
if (mprotect(copy_row, sizeof(copy_row), PROT_READ | PROT_WRITE) < 0) {
Mar 31, 2013
Mar 31, 2013
110
return SDL_SetError("Couldn't make copy buffer writeable");
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
}
#endif
pos = 0x10000;
inc = (src_w << 16) / dst_w;
eip = copy_row;
fence = copy_row + sizeof(copy_row)-2;
for (i = 0; i < dst_w; ++i) {
while (pos >= 0x10000L) {
if (eip == fence) {
return -1;
}
if (bpp == 2) {
*eip++ = PREFIX16;
}
*eip++ = load;
pos -= 0x10000L;
}
if (eip == fence) {
return -1;
}
if (bpp == 2) {
*eip++ = PREFIX16;
}
*eip++ = store;
pos += inc;
}
*eip++ = RETURN;
#ifdef HAVE_MPROTECT
/* Make the code executable but not writeable */
if (mprotect(copy_row, sizeof(copy_row), PROT_READ | PROT_EXEC) < 0) {
Mar 31, 2013
Mar 31, 2013
142
return SDL_SetError("Couldn't make copy buffer executable");
143
144
145
146
147
148
149
150
}
#endif
last.status = 0;
return (0);
}
#endif /* USE_ASM_STRETCH */
May 22, 2013
May 22, 2013
151
152
#define DEFINE_COPY_ROW(name, type) \
static void name(type *src, int src_w, type *dst, int dst_w) \
May 22, 2013
May 22, 2013
153
154
155
156
157
158
{ \
int i; \
int pos, inc; \
type pixel = 0; \
\
pos = 0x10000; \
May 22, 2013
May 22, 2013
159
inc = (src_w << 16) / dst_w; \
May 22, 2013
May 22, 2013
160
161
162
163
164
165
166
167
for ( i=dst_w; i>0; --i ) { \
while ( pos >= 0x10000L ) { \
pixel = *src++; \
pos -= 0x10000L; \
} \
*dst++ = pixel; \
pos += inc; \
} \
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
}
/* *INDENT-OFF* */
DEFINE_COPY_ROW(copy_row1, Uint8)
DEFINE_COPY_ROW(copy_row2, Uint16)
DEFINE_COPY_ROW(copy_row4, Uint32)
/* *INDENT-ON* */
/* The ASM code doesn't handle 24-bpp stretch blits */
static void
copy_row3(Uint8 * src, int src_w, Uint8 * dst, int dst_w)
{
int i;
int pos, inc;
Uint8 pixel[3] = { 0, 0, 0 };
pos = 0x10000;
inc = (src_w << 16) / dst_w;
for (i = dst_w; i > 0; --i) {
while (pos >= 0x10000L) {
pixel[0] = *src++;
pixel[1] = *src++;
pixel[2] = *src++;
pos -= 0x10000L;
}
*dst++ = pixel[0];
*dst++ = pixel[1];
*dst++ = pixel[2];
pos += inc;
}
}
/* Perform a stretch blit between two surfaces of the same format.
NOTE: This function is not safe to call from multiple threads!
*/
int
SDL_SoftStretch(SDL_Surface * src, const SDL_Rect * srcrect,
SDL_Surface * dst, const SDL_Rect * dstrect)
{
int src_locked;
int dst_locked;
int pos, inc;
int dst_maxrow;
int src_row, dst_row;
Uint8 *srcp = NULL;
Uint8 *dstp;
SDL_Rect full_src;
SDL_Rect full_dst;
#ifdef USE_ASM_STRETCH
SDL_bool use_asm = SDL_TRUE;
#ifdef __GNUC__
int u1, u2;
#endif
#endif /* USE_ASM_STRETCH */
const int bpp = dst->format->BytesPerPixel;
May 22, 2013
May 22, 2013
223
if (src->format->format != dst->format->format) {
Mar 31, 2013
Mar 31, 2013
224
return SDL_SetError("Only works with same format surfaces");
225
226
227
228
229
230
231
}
/* Verify the blit rectangles */
if (srcrect) {
if ((srcrect->x < 0) || (srcrect->y < 0) ||
((srcrect->x + srcrect->w) > src->w) ||
((srcrect->y + srcrect->h) > src->h)) {
Mar 31, 2013
Mar 31, 2013
232
return SDL_SetError("Invalid source blit rectangle");
233
234
235
236
237
238
239
240
241
242
243
244
}
} else {
full_src.x = 0;
full_src.y = 0;
full_src.w = src->w;
full_src.h = src->h;
srcrect = &full_src;
}
if (dstrect) {
if ((dstrect->x < 0) || (dstrect->y < 0) ||
((dstrect->x + dstrect->w) > dst->w) ||
((dstrect->y + dstrect->h) > dst->h)) {
Mar 31, 2013
Mar 31, 2013
245
return SDL_SetError("Invalid destination blit rectangle");
246
247
248
249
250
251
252
253
254
255
256
257
258
}
} else {
full_dst.x = 0;
full_dst.y = 0;
full_dst.w = dst->w;
full_dst.h = dst->h;
dstrect = &full_dst;
}
/* Lock the destination if it's in hardware */
dst_locked = 0;
if (SDL_MUSTLOCK(dst)) {
if (SDL_LockSurface(dst) < 0) {
Mar 31, 2013
Mar 31, 2013
259
return SDL_SetError("Unable to lock destination surface");
260
261
262
263
264
265
266
267
268
269
}
dst_locked = 1;
}
/* Lock the source if it's in hardware */
src_locked = 0;
if (SDL_MUSTLOCK(src)) {
if (SDL_LockSurface(src) < 0) {
if (dst_locked) {
SDL_UnlockSurface(dst);
}
Mar 31, 2013
Mar 31, 2013
270
return SDL_SetError("Unable to lock source surface");
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
}
src_locked = 1;
}
/* Set up the data... */
pos = 0x10000;
inc = (srcrect->h << 16) / dstrect->h;
src_row = srcrect->y;
dst_row = dstrect->y;
#ifdef USE_ASM_STRETCH
/* Write the opcodes for this stretch */
if ((bpp == 3) || (generate_rowbytes(srcrect->w, dstrect->w, bpp) < 0)) {
use_asm = SDL_FALSE;
}
#endif
/* Perform the stretch blit */
for (dst_maxrow = dst_row + dstrect->h; dst_row < dst_maxrow; ++dst_row) {
dstp = (Uint8 *) dst->pixels + (dst_row * dst->pitch)
+ (dstrect->x * bpp);
while (pos >= 0x10000L) {
srcp = (Uint8 *) src->pixels + (src_row * src->pitch)
+ (srcrect->x * bpp);
++src_row;
pos -= 0x10000L;
}
#ifdef USE_ASM_STRETCH
if (use_asm) {
#ifdef __GNUC__
__asm__ __volatile__("call *%4":"=&D"(u1), "=&S"(u2)
:"0"(dstp), "1"(srcp), "r"(copy_row)
:"memory");
#elif defined(_MSC_VER) || defined(__WATCOMC__)
/* *INDENT-OFF* */
{
void *code = copy_row;
__asm {
push edi
push esi
mov edi, dstp
mov esi, srcp
call dword ptr code
pop esi
pop edi
}
}
/* *INDENT-ON* */
#else
#error Need inline assembly for this compiler
#endif
} else
#endif
switch (bpp) {
case 1:
copy_row1(srcp, srcrect->w, dstp, dstrect->w);
break;
case 2:
copy_row2((Uint16 *) srcp, srcrect->w,
(Uint16 *) dstp, dstrect->w);
break;
case 3:
copy_row3(srcp, srcrect->w, dstp, dstrect->w);
break;
case 4:
copy_row4((Uint32 *) srcp, srcrect->w,
(Uint32 *) dstp, dstrect->w);
break;
}
pos += inc;
}
/* We need to unlock the surfaces if they're locked */
if (dst_locked) {
SDL_UnlockSurface(dst);
}
if (src_locked) {
SDL_UnlockSurface(src);
}
return (0);
}
/* vi: set ts=4 sw=4 expandtab: */