Re: [AD] stretch_blit bug

[ Thread Index | Date Index | More lists.liballeg.org/allegro-developers Archives ]


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;
}


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/