Rectangle clipping timing results

Tests using 1000000 iterations on a Pentium 133 processor under zero load.

Clipping DISABLED:
Clipping calculations using { minx, miny, maxx, maxx }
No optimization: ~2.0 seconds
O2 optimization: ~1.4 seconds

Clipping calculations using { x, y, w, h }
With Uint16 (w, h)
No optimization: ~1.4 seconds
O2 optimization: ~1.0 seconds
With int (w, h)
No optimization: ~1.3 seconds (consistently ~0.1 seconds faster)
O2 optimization: ~0.95 seconds (consistently ~0.05 seconds faster)

Clipping ENABLED:
Clipping calculations using { minx, miny, maxx, maxx }
No optimization: ~2.0 seconds
O2 optimization: ~1.4 seconds

Clipping calculations using { x, y, w, h }
No optimization: ~1.8 seconds
O2 optimization: ~1.4 seconds

Clipping WORST CASE:
Clipping calculations using { minx, miny, maxx, maxx }
No optimization: ~31.5 seconds
O2 optimization: ~31.0 seconds

Clipping calculations using { x, y, w, h }
No optimization: ~32.5 seconds
O2 optimization: ~30.0 seconds-------------------------------------------------

I think I’ll stick with the original clipping code. :slight_smile:

The source to the test code is included as an attachment.

See ya!
-Sam Lantinga (slouken at devolution.com)


Author of Simple DirectMedia Layer -
http://www.devolution.com/~slouken/SDL/

-------------- next part --------------

#include <stdio.h>
#include “SDL.h”

int SDL_UpperBlit1 (SDL_Surface *src, SDL_Rect *srcrect,
SDL_Surface *dst, SDL_Rect *dstrect)
{
SDL_Area srcarea, dstarea;
int clip_diff;

/* Set source and destination blit area rectangles */
if ( dstrect == NULL ) {
	SDL_SetAreaWH(&dstarea, 0, 0, dst->w, dst->h);
} else {
	SDL_SetAreaWH(&dstarea, dstrect->x, dstrect->y,
				dstrect->w, dstrect->h);
}
if ( srcrect == NULL ) {
	SDL_SetAreaWH(&srcarea, 0, 0, src->w, src->h);
} else {
	SDL_SetAreaWH(&srcarea, srcrect->x, srcrect->y,
				srcrect->w, srcrect->h);
}

/* Perform destination clipping */
clip_diff = dst->clip.minx-dstarea.minx;
if ( clip_diff > 0 ) {
	dstarea.minx += clip_diff;
	srcarea.minx += clip_diff;
}
clip_diff = dst->clip.miny-dstarea.miny;
if ( clip_diff > 0 ) {
	dstarea.miny += clip_diff;
	srcarea.miny += clip_diff;
}
clip_diff = dstarea.maxx-dst->clip.maxx;
if ( clip_diff > 0 ) {
	dstarea.maxx -= clip_diff;
	srcarea.maxx -= clip_diff;
}
clip_diff = dstarea.maxy-dst->clip.maxy;
if ( clip_diff > 0 ) {
	dstarea.maxy -= clip_diff;
	srcarea.maxy -= clip_diff;
}

/* Perform source clipping */
if ( srcarea.minx < 0 ) {
	dstarea.minx -= srcarea.minx;
	srcarea.minx = 0;
}
if ( srcarea.miny < 0 ) {
	dstarea.miny -= srcarea.miny;
	srcarea.miny = 0;
}
clip_diff = srcarea.maxx-src->w+1;
if ( clip_diff > 0 ) {
	dstarea.maxx -= clip_diff;
	srcarea.maxx -= clip_diff;
}
clip_diff = srcarea.maxy-src->h+1;
if ( clip_diff > 0 ) {
	dstarea.maxy -= clip_diff;
	srcarea.maxy -= clip_diff;
}

/* Verify blit areas */
if ( (srcarea.minx > srcarea.maxx) ) {
	SDL_SetError("src rectangle minx > maxx after clipping");
	return(-1);
}
if ( (srcarea.miny > srcarea.maxy) ) {
	SDL_SetError("src rectangle miny > maxy after clipping");
	return(-1);
}
if ( (dstarea.minx > dstarea.maxx) ) {
	SDL_SetError("dst rectangle minx > maxx after clipping");
	return(-1);
}
if ( (dstarea.miny > dstarea.maxy) ) {
	SDL_SetError("dst rectangle miny > maxy after clipping");
	return(-1);
}
if ( ((srcarea.maxx-srcarea.minx) != (dstarea.maxx-dstarea.minx)) ||
     ((srcarea.maxy-srcarea.miny) != (dstarea.maxy-dstarea.miny)) ) {
	SDL_SetError("src and dst rectangles have different size");
	return(-1);
}

/* Update the destination rectangle with clipped area */
if ( dstrect != NULL ) {
	SDL_AreaToRect(&dstarea, dstrect);
}

/* Do the blit */
return(0);

}

int SDL_UpperBlit2 (SDL_Surface *src, SDL_Rect *srcrect,
SDL_Surface *dst, SDL_Rect *dstrect)
{
SDL_Rect fullsrc, fulldst;
int clip_diff;

/* Set default rectangles */
if ( dstrect == NULL ) {
	fulldst.x = 0;
	fulldst.y = 0;
	fulldst.w = dst->w;
	fulldst.h = dst->h;
	dstrect = &fulldst;
}
if ( srcrect == NULL ) {
	fullsrc.x = 0;
	fullsrc.y = 0;
	fullsrc.w = src->w;
	fullsrc.h = src->h;
	srcrect = &fullsrc;
}

/* Verify the destination coordinates */
if ( dstrect != &fulldst ) {

	/* Check for negative destination coordinates */
	if ( dstrect->x < 0 ) {
		if ( -dstrect->x >= dstrect->w ) {
			srcrect->w = 0;
			dstrect->w = 0;
			return(0);
		}
		srcrect->x -= dstrect->x;
		srcrect->w += dstrect->x;
		dstrect->w += dstrect->x;
		dstrect->x = 0;
	}
	if ( dstrect->y < 0 ) {
		if ( -dstrect->y >= dstrect->h ) {
			srcrect->h = 0;
			dstrect->h = 0;
			return(0);
		}
		srcrect->y -= dstrect->y;
		srcrect->h += dstrect->y;
		dstrect->h += dstrect->y;
		dstrect->y = 0;
	}

	/* Check for overlarge destination rectangle */
	clip_diff = (dstrect->x+dstrect->w)-(dst->w);
	if ( clip_diff > 0 ) {
		if ( clip_diff >= dstrect->w ) {
			srcrect->w = 0;
			dstrect->w = 0;
			return(0);
		}
		dstrect->w -= clip_diff;
		srcrect->w -= clip_diff;
	}
	clip_diff = (dstrect->y+dstrect->h)-(dst->h);
	if ( clip_diff > 0 ) {
		if ( clip_diff >= dstrect->h ) {
			srcrect->h = 0;
			dstrect->h = 0;
			return(0);
		}
		dstrect->h -= clip_diff;
		srcrect->h -= clip_diff;
	}
}

/* Verify the source coordinates */
if ( srcrect != &fullsrc ) {

	/* Check for negative destination coordinates */
	if ( srcrect->x < 0 ) {
		if ( -srcrect->x >= srcrect->w ) {
			srcrect->w = 0;
			dstrect->w = 0;
			return(0);
		}
		srcrect->w += srcrect->x;
		dstrect->w += srcrect->x;
		srcrect->x = 0;
	}
	if ( srcrect->y < 0 ) {
		if ( -srcrect->y >= srcrect->h ) {
			srcrect->h = 0;
			dstrect->h = 0;
			return(0);
		}
		srcrect->h += srcrect->y;
		dstrect->h += srcrect->y;
		srcrect->y = 0;
	}

	/* Check for overlarge source rectangle */
	clip_diff = (srcrect->x+srcrect->w)-(src->w);
	if ( clip_diff > 0 ) {
		if ( clip_diff >= dstrect->w ) {
			srcrect->w = 0;
			dstrect->w = 0;
			return(0);
		}
		dstrect->w -= clip_diff;
		srcrect->w -= clip_diff;
	}
	clip_diff = (srcrect->y+srcrect->h)-(src->h);
	if ( clip_diff > 0 ) {
		if ( clip_diff >= dstrect->h ) {
			srcrect->h = 0;
			dstrect->h = 0;
			return(0);
		}
		dstrect->h -= clip_diff;
		srcrect->h -= clip_diff;
	}
}

/* Check for clipping */
if ( 0 ) {

	/* Check for clipping and adjust rectangles */
	clip_diff = src->clip.minx-dstrect->x;
	if ( clip_diff > 0 ) {
		if ( clip_diff >= dstrect->w ) {
			srcrect->w = 0;
			dstrect->w = 0;
			return(0);
		}

#ifdef BLIT_DEBUG
fprintf(stderr,
“Blit of %dx%d at (%d,%d) extends %d pixels beyond left edge\n”,
dstrect->w, dstrect->h, dstrect->x, dstrect->y, clip_diff);
#endif
dstrect->x += clip_diff;
dstrect->w -= clip_diff;
srcrect->x += clip_diff;
srcrect->w -= clip_diff;
}
clip_diff = (dstrect->x+dstrect->w)-src->clip.maxx;
if ( clip_diff > 0 ) {
if ( clip_diff >= dstrect->w ) {
srcrect->w = 0;
dstrect->w = 0;
return(0);
}
#ifdef BLIT_DEBUG
fprintf(stderr,
“Blit of %dx%d at (%d,%d) extends %d pixels beyond right edge (%d)\n”,
dstrect->w, dstrect->h, dstrect->x, dstrect->y, clip_diff,
src->clip_maxx);
#endif
dstrect->w -= clip_diff;
srcrect->w -= clip_diff;
}
clip_diff = src->clip.miny-dstrect->y;
if ( clip_diff > 0 ) {
if ( clip_diff >= dstrect->h ) {
srcrect->h = 0;
dstrect->h = 0;
return(0);
}
#ifdef BLIT_DEBUG
fprintf(stderr,
“Blit of %dx%d at (%d,%d) extends %d pixels beyond top edge\n”,
dstrect->w, dstrect->h, dstrect->x, dstrect->y, clip_diff);
#endif
dstrect->y += clip_diff;
dstrect->h -= clip_diff;
srcrect->y += clip_diff;
srcrect->h -= clip_diff;
}
clip_diff = (dstrect->y+dstrect->h)-src->clip.maxy;
if ( clip_diff > 0 ) {
if ( clip_diff >= dstrect->h ) {
srcrect->h = 0;
dstrect->h = 0;
return(0);
}
#ifdef BLIT_DEBUG
fprintf(stderr,
“Blit of %dx%d at (%d,%d) extends %d pixels beyond bottom edge\n”,
dstrect->w, dstrect->h, dstrect->x, dstrect->y, clip.diff);
#endif
dstrect->h -= clip_diff;
srcrect->h -= clip_diff;
}
}
/* Check to make sure the blit rectangles are valid */
if ( (srcrect->w != dstrect->w) || (srcrect->h != dstrect->h) ) {
SDL_SetError(“SDL_UpperBlit: Passed mismatched rectangles”);
return(-1);
}

return(0);

}

main()
{
SDL_Surface src, dst;
SDL_Rect srect, drect;
int i;
Uint32 then, now;

if ( SDL_Init(0) < 0 )
	exit(1);

/* Initialize the surfaces */
srect.x = srect.y = 0;
srect.w = src.w = 100;
srect.h = src.h = 100;
drect.x = drect.y = 0;
drect.w = dst.w = 100;
drect.h = dst.h = 100;

#if 0
SDL_SetClipping(&src, 1, 1, src.w-1, src.h-1);
SDL_SetClipping(&dst, 1, 1, dst.w-1, dst.h-1);
#else
SDL_SetClipping(&src, 0, 0, 0, 0);
SDL_SetClipping(&dst, 0, 0, 0, 0);
#endif

printf("Performing 1000000 iterations of Blit #1\n");
then = SDL_GetTicks();
for ( i=0; i<1000000; ++i ) {
	SDL_UpperBlit1(&src, &srect, &dst, &drect);
}
now = SDL_GetTicks();
printf("Test took %d ms\n", now-then);

printf("Performing 1000000 iterations of Blit #2\n");
then = SDL_GetTicks();
for ( i=0; i<1000000; ++i ) {
	SDL_UpperBlit2(&src, &srect, &dst, &drect);
}
now = SDL_GetTicks();
printf("Test took %d ms\n", now-then);

exit(0);

}

Just a note, this message just uncovered (another) security hole in
pine… (It tried to execute a program as a result of it, and gave me some
shell errors as a result!!)

Does MMR support IMAP?

– Michael Samuel