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 17:30:01 -0600
OK, I've managed to get it as fast if not a little faster than the
Allegro version. These are the results after compiling with
-mtune=pentium -O2 -funroll-loops -ffast-math -fomit-frame-pointer.
mm stretch_blit took 658 millis
mm my_stretch took 652 millis
mv stretch_blit took 5724 millis
mv my_stretch took 5688 millis
vm stretch_blit took 682 millis
vm my_stretch took 655 millis
It is also a lot simpler. If this would be committed to svn I could add
masked and 8 bit support. New version attached.
On Wed, 2007-04-25 at 10:44 -0600, Trent Gamblin wrote:
> Attached is an improved version of Elias' stretching routines, with a
> benchmark program. It's not as fast as stretch_blit, but it's more
> accurate and can blit between bitmaps of different color depths.
#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
}
#if 0
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 i1; /* amount to increment sx every iteration */
int i2; /* when this reaches dw increase a pixel */
} _al_stretch;
#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 */
#if 0
int i1; /* amount to increment sx every iteration */
int i2; /* when this reaches dw increase a pixel */
#endif
int sinc;
} _al_stretch;
/*
#define DECLARE_STRETCHER(type, size, put, get) \
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.i1)) { \
put(dptr, get(s)); \
dptr += size; \
xc += _al_stretch.i2; \
if (xc <= 0) { \
s = (type *) ((unsigned char*)s + (size)); \
xc += _al_stretch.dw; \
} \
}
*/
#define DECLARE_STRETCHER(type, size, put, get) \
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)) { \
put(dptr, get(s)); \
dptr += size; \
xc += _al_stretch.sw; \
if (xc >= _al_stretch.dw) { \
s = (type *) ((unsigned char*)s + (size)); \
xc -= _al_stretch.dw; \
} \
}
static void stretch_line15_or_16(uintptr_t dptr, unsigned char* sptr)
{
DECLARE_STRETCHER(unsigned short, _al_stretch.size, bmp_write16, *);
}
static void stretch_line24(uintptr_t dptr, unsigned char* sptr)
{
DECLARE_STRETCHER(unsigned char, _al_stretch.size, bmp_write24, READ3BYTES);
}
static void stretch_line32(uintptr_t dptr, unsigned char* sptr)
{
DECLARE_STRETCHER(uint32_t, _al_stretch.size, bmp_write32, *);
}
void my_stretch(BITMAP *source, BITMAP *destination,
int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh)
{
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);
switch (bitmap_color_depth(source)) {
case 15:
case 16:
stretch_line = stretch_line15_or_16;
_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.i1 = sw / dw;
_al_stretch.i2 = sw % dw;
*/
_al_stretch.sinc = sw / dw;
//_al_stretch.xcstart = _al_stretch.i2/2;
_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);
}
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(24);
set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);
buffer = create_bitmap(640, 480);
sprite = load_bitmap("test.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;
}