Re: [AD] stretch_blit bug |
[ Thread Index |
Date Index
| More lists.liballeg.org/allegro-developers Archives
]
- To: Coordination of admins/developers of the game programming library Allegro <alleg-developers@xxxxxxxxxx>
- Subject: Re: [AD] stretch_blit bug
- From: Trent Gamblin <trent@xxxxxxxxxx>
- Date: Wed, 25 Apr 2007 19:30:13 -0600
On Thu, 2007-04-26 at 09:28 +1000, Peter Wang wrote:
> Would either of the new stretch_blit implementations be faster if they
> didn't use indirect function calls? I didn't think C compilers were
> generally smart enough to specialise them.
>
> Peter
Yes. The last one I posted had everything in a macro. I'm attaching
another one now that fixes a bug where stretching to smaller sizes
doesn't work. It's still a little slower than the current one in
Allegro. If anyone can see how to speed it up that would be good.
This one also does 8 bit and masked blits.
#include <allegro.h>
#include <stdio.h>
#ifdef __linux__
#include <sys/time.h>
#else
#include <allegro.h>
#include <winalleg.h>
#endif
long currentTimeMillis()
{
#ifdef __linux__
struct timeval tv;
gettimeofday(&tv, 0);
return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
#else
return timeGetTime();
#endif
}
static struct {
int dx, dend; /* destination x, destination end */
int size; /* pixel size */
int xcstart; /* x counter start */
int sw, dw; /* source and destination width */
int sinc;
int xcinc;
} _al_stretch;
#define DECLARE_STRETCHER(type, size, put, get) \
ASSERT(dptr); \
ASSERT(sptr); \
int x; \
int xc = _al_stretch.xcstart; \
type* s = (type*)sptr; \
for (x = _al_stretch.dx; x < _al_stretch.dend; x++, \
s = (type*)((unsigned char*)s + _al_stretch.sinc*size)) { \
put(dptr, get(s)); \
dptr += size; \
xc += _al_stretch.xcinc; \
if (xc >= _al_stretch.dw) { \
s = (type *) ((unsigned char*)s + (size)); \
xc -= _al_stretch.dw; \
} \
}
#define DECLARE_MASKED_STRETCHER(type, size, put, get, mask) \
ASSERT(dptr); \
ASSERT(sptr); \
int x; \
int xc = _al_stretch.xcstart; \
type* s = (type*)sptr; \
for (x = _al_stretch.dx; x < _al_stretch.dend; x++, \
s = (type*)((unsigned char*)s + _al_stretch.sinc*size)) { \
int color = get(s); \
if (color != mask) \
put(dptr, get(s)); \
dptr += size; \
xc += _al_stretch.xcinc; \
if (xc >= _al_stretch.dw) { \
s = (type *) ((unsigned char*)s + (size)); \
xc -= _al_stretch.dw; \
} \
}
#ifdef ALLEGRO_COLOR8
static void stretch_line8(uintptr_t dptr, unsigned char *sptr)
{
DECLARE_STRETCHER(unsigned char, 1, bmp_write8, *);
}
static void masked_stretch_line8(uintptr_t dptr, unsigned char *sptr)
{
DECLARE_MASKED_STRETCHER(unsigned char, 1, bmp_write8, *, 0);
}
#endif
#ifdef ALLEGRO_COLOR16
static void stretch_line15(uintptr_t dptr, unsigned char* sptr)
{
DECLARE_STRETCHER(unsigned short, _al_stretch.size, bmp_write16, *);
}
static void stretch_line16(uintptr_t dptr, unsigned char* sptr)
{
DECLARE_STRETCHER(unsigned short, _al_stretch.size, bmp_write16, *);
}
static void masked_stretch_line15(uintptr_t dptr, unsigned char* sptr)
{
DECLARE_MASKED_STRETCHER(unsigned short, _al_stretch.size, bmp_write16, *, MASK_COLOR_15);
}
static void masked_stretch_line16(uintptr_t dptr, unsigned char* sptr)
{
DECLARE_MASKED_STRETCHER(unsigned short, _al_stretch.size, bmp_write16, *, MASK_COLOR_16);
}
#endif
#ifdef ALLEGRO_COLOR24
static void stretch_line24(uintptr_t dptr, unsigned char* sptr)
{
DECLARE_STRETCHER(unsigned char, _al_stretch.size, bmp_write24, READ3BYTES);
}
static void masked_stretch_line24(uintptr_t dptr, unsigned char* sptr)
{
DECLARE_MASKED_STRETCHER(unsigned char, _al_stretch.size, bmp_write24, READ3BYTES, MASK_COLOR_24);
}
#endif
#ifdef ALLEGRO_COLOR32
static void stretch_line32(uintptr_t dptr, unsigned char* sptr)
{
DECLARE_STRETCHER(uint32_t, _al_stretch.size, bmp_write32, *);
}
static void masked_stretch_line32(uintptr_t dptr, unsigned char* sptr)
{
DECLARE_MASKED_STRETCHER(uint32_t, _al_stretch.size, bmp_write32, *, MASK_COLOR_32);
}
#endif
void _al_stretch_blit(BITMAP *source, BITMAP *destination,
int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh,
int masked)
{
int y; /* current destination y */
int yc; /* y counter */
int sxofs, dxofs; /* start offsets */
void (*stretch_line)(uintptr_t, unsigned char*);
ASSERT(bitmap_color_depth(source) == bitmap_color_depth(destination));
ASSERT(source != destination);
if (masked) {
switch (bitmap_color_depth(source)) {
case 8:
stretch_line = masked_stretch_line8;
_al_stretch.size = 1;
break;
case 15:
stretch_line = masked_stretch_line15;
_al_stretch.size = 2;
break;
case 16:
stretch_line = masked_stretch_line16;
_al_stretch.size = 2;
break;
case 24:
stretch_line = masked_stretch_line24;
_al_stretch.size = 3;
break;
default:
stretch_line = masked_stretch_line32;
_al_stretch.size = 4;
break;
}
}
else {
switch (bitmap_color_depth(source)) {
case 8:
stretch_line = masked_stretch_line8;
_al_stretch.size = 1;
break;
case 15:
stretch_line = stretch_line15;
_al_stretch.size = 2;
break;
case 16:
stretch_line = stretch_line16;
_al_stretch.size = 2;
break;
case 24:
stretch_line = stretch_line24;
_al_stretch.size = 3;
break;
default:
stretch_line = stretch_line32;
_al_stretch.size = 4;
break;
}
}
yc = sh/2;
sxofs = sx * _al_stretch.size;
dxofs = dx * _al_stretch.size;
_al_stretch.dx = dx;
_al_stretch.dend = dx + dw;
_al_stretch.sw = sw;
_al_stretch.dw = dw;
_al_stretch.sinc = sw / dw;
_al_stretch.xcinc = sw % dw;
_al_stretch.xcstart = 0;
bmp_select(destination);
for (y = dy; y < dy + dh; y++) {
(*stretch_line)(bmp_write_line(destination, y) + dxofs, source->line[sy] + sxofs);
yc += sh;
while (yc > dh) {
sy++;
yc -= dh;
}
}
bmp_unwrite_line(destination);
}
void my_stretch(BITMAP *source, BITMAP *destination,
int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh)
{
_al_stretch_blit(source, destination, sx, sy, sw, sh, dx, dy, dw, dh, 0);
}
void my_masked_stretch(BITMAP *source, BITMAP *destination,
int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh)
{
_al_stretch_blit(source, destination, sx, sy, sw, sh, dx, dy, dw, dh, 1);
}
int main()
{
const int count = 2500;
const int w = 200;
const int h = 200;
BITMAP* buffer, *sprite;
long start, end;
int i;
allegro_init();
install_keyboard();
set_color_depth(32);
set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);
buffer = create_bitmap(640, 480);
sprite = load_bitmap("sprite.pcx", 0);
if (!buffer || !sprite) return 1;
start = currentTimeMillis();
for (i = 0; i < count; i++) {
int x = rand() % 640;
int y = rand() % 480;
x = MAX(0, MIN(640-w, x));
y = MAX(0, MIN(480-h, y));
stretch_blit(sprite, buffer, 0, 0, sprite->w, sprite->h,
x, y, w, h);
}
end = currentTimeMillis();
printf("mm stretch_blit took %d millis\n", end - start);
start = currentTimeMillis();
for (i = 0; i < count; i++) {
int x = rand() % 640;
int y = rand() % 480;
x = MAX(0, MIN(640-w, x));
y = MAX(0, MIN(480-h, y));
my_stretch(sprite, buffer, 0, 0, sprite->w, sprite->h,
x, y, w, h);
}
end = currentTimeMillis();
printf("mm my_stretch took %d millis\n", end - start);
start = currentTimeMillis();
for (i = 0; i < count; i++) {
int x = rand() % 640;
int y = rand() % 480;
x = MAX(0, MIN(640-w, x));
y = MAX(0, MIN(480-h, y));
stretch_blit(sprite, screen, 0, 0, sprite->w, sprite->h,
x, y, w, h);
}
end = currentTimeMillis();
printf("mv stretch_blit took %d millis\n", end - start);
start = currentTimeMillis();
for (i = 0; i < count; i++) {
int x = rand() % 640;
int y = rand() % 480;
x = MAX(0, MIN(640-w, x));
y = MAX(0, MIN(480-h, y));
my_stretch(sprite, screen, 0, 0, sprite->w, sprite->h,
x, y, w, h);
}
end = currentTimeMillis();
printf("mv my_stretch took %d millis\n", end - start);
start = currentTimeMillis();
for (i = 0; i < count; i++) {
int x = rand() % 640;
int y = rand() % 480;
x = MAX(0, MIN(640-w, x));
y = MAX(0, MIN(480-h, y));
stretch_blit(screen, buffer, 0, 0, sprite->w, sprite->h,
x, y, w, h);
}
end = currentTimeMillis();
printf("vm stretch_blit took %d millis\n", end - start);
start = currentTimeMillis();
for (i = 0; i < count; i++) {
int x = rand() % 640;
int y = rand() % 480;
x = MAX(0, MIN(640-w, x));
y = MAX(0, MIN(480-h, y));
my_stretch(screen, buffer, 0, 0, sprite->w, sprite->h,
x, y, w, h);
}
end = currentTimeMillis();
printf("vm my_stretch took %d millis\n", end - start);
return 0;
}