keep an internal buffer filled with the background color and use it for

2007-03-07  Sven Neumann  <sven@gimp.org>

	* app/base/pixel-surround.c: keep an internal buffer filled with
	the background color and use it for out of bounds requests. 
Speed
	up filling the internal buffer by copying data row-by-row.


svn path=/trunk/; revision=22062
This commit is contained in:
Sven Neumann 2007-03-06 23:32:25 +00:00 committed by Sven Neumann
parent c5c17d737d
commit 4d76165127
2 changed files with 82 additions and 54 deletions

View file

@ -1,3 +1,9 @@
2007-03-07 Sven Neumann <sven@gimp.org>
* app/base/pixel-surround.c: keep an internal buffer filled with
the background color and use it for out of bounds requests. Speed
up filling the internal buffer by copying data row-by-row.
2007-03-06 Sven Neumann <sven@gimp.org>
Patch by Martin Nordholts. Fixes bug #328001.

View file

@ -34,21 +34,25 @@ struct _PixelSurround
gint bpp; /* bytes per pixel in tile manager */
gint w; /* width of pixel surround area */
gint h; /* height of pixel surround area */
guchar bg[MAX_CHANNELS]; /* color to use for uncovered regions */
Tile *tile; /* locked tile (may be NULL) */
gint tile_x; /* origin of locked tile */
gint tile_y; /* origin of locked tile */
gint tile_w; /* width of locked tile */
gint tile_h; /* height of locked tile */
guchar buf[0];
gint rowstride;
guchar *bg;
guchar *buf;
};
/* inlining this function gives a few percent speedup */
static inline gboolean
pixel_surround_get_tile (PixelSurround *surround,
static inline const guchar *
pixel_surround_get_data (PixelSurround *surround,
gint x,
gint y)
gint y,
gint *w,
gint *h,
gint *rowstride)
{
/* do we still have a tile lock that we can use? */
if (surround->tile)
@ -63,19 +67,32 @@ pixel_surround_get_tile (PixelSurround *surround,
/* if not, try to get one for the target pixel */
if (! surround->tile)
surround->tile = tile_manager_get_tile (surround->mgr, x, y, TRUE, FALSE);
if (surround->tile)
{
surround->tile = tile_manager_get_tile (surround->mgr, x, y, TRUE, FALSE);
/* store offset and size of the locked tile */
surround->tile_x = x & ~(TILE_WIDTH - 1);
surround->tile_y = y & ~(TILE_HEIGHT - 1);
surround->tile_w = tile_ewidth (surround->tile);
surround->tile_h = tile_eheight (surround->tile);
if (surround->tile)
{
surround->tile_x = x & ~(TILE_WIDTH - 1);
surround->tile_y = y & ~(TILE_HEIGHT - 1);
surround->tile_w = tile_ewidth (surround->tile);
surround->tile_h = tile_eheight (surround->tile);
}
*w = surround->tile_x + surround->tile_w - x;
*h = surround->tile_y + surround->tile_h - y;
*rowstride = surround->tile_w * surround->bpp;
return tile_data_pointer (surround->tile, x % TILE_WIDTH, y % TILE_WIDTH);
}
else
{
/* return a pointer to the buffer that's filled with the bg color */
*w = surround->w;
*h = surround->h;
*rowstride = surround->rowstride;
return (surround->tile != NULL);
return surround->bg;
}
}
/**
@ -94,22 +111,31 @@ pixel_surround_new (TileManager *tiles,
const guchar bg[MAX_CHANNELS])
{
PixelSurround *surround;
gint i;
guchar *dest;
gint pixels;
g_return_val_if_fail (tiles != NULL, NULL);
surround = g_malloc (sizeof (PixelSurround) +
width * height * tile_manager_bpp (tiles));
surround = g_new0 (PixelSurround, 1);
surround->mgr = tiles;
surround->bpp = tile_manager_bpp (tiles);
surround->w = width;
surround->h = height;
surround->mgr = tiles;
surround->bpp = tile_manager_bpp (tiles);
surround->w = width;
surround->h = height;
surround->rowstride = width * surround->bpp;
surround->bg = g_new (guchar, surround->rowstride * height);
surround->buf = g_new (guchar, surround->rowstride * height);
for (i = 0; i < surround->bpp; ++i)
surround->bg[i] = bg[i];
dest = surround->bg;
pixels = width * height;
surround->tile = NULL;
while (pixels--)
{
gint i;
for (i = 0; i < surround->bpp; i++)
*dest++ = bg[i];
}
return surround;
}
@ -137,46 +163,39 @@ pixel_surround_lock (PixelSurround *surround,
gint y,
gint *rowstride)
{
guchar *dest;
gint i = x % TILE_WIDTH;
gint j = y % TILE_HEIGHT;
const guchar *src;
guchar *dest;
gint i, j;
gint w, h;
/* return a pointer to the tile data if the tile covers the whole region */
if (pixel_surround_get_tile (surround, x, y) &&
i + surround->w <= surround->tile_w &&
j + surround->h <= surround->tile_h)
{
*rowstride = surround->tile_w * surround->bpp;
/* return a pointer to the data if it covers the whole region */
src = pixel_surround_get_data (surround, x, y, &w, &h, rowstride);
return tile_data_pointer (surround->tile, i, j);
}
if (w >= surround->w && h >= surround->h)
return src;
/* otherwise, copy region to our internal buffer */
dest = surround->buf;
for (j = y; j < y + surround->h; j++)
for (j = 0; j < surround->h; j++)
{
for (i = x; i < x + surround->w; i++)
gint yy = y + j;
for (i = 0; i < surround->w;)
{
const guchar *src;
gint xx = x + i;
gint bytes;
if (pixel_surround_get_tile (surround, i, j))
{
src = tile_data_pointer (surround->tile,
i % TILE_WIDTH, j % TILE_HEIGHT);
}
else
{
src = surround->bg;
}
src = pixel_surround_get_data (surround, xx, yy, &w, &h, rowstride);
switch (surround->bpp)
{
case 4: *dest++ = *src++;
case 3: *dest++ = *src++;
case 2: *dest++ = *src++;
case 1: *dest++ = *src++;
}
w = MIN (w, surround->w - i);
bytes = w * surround->bpp;
while (bytes--)
*dest++ = *src++;
i += w;
}
}
@ -214,5 +233,8 @@ pixel_surround_destroy (PixelSurround *surround)
g_return_if_fail (surround != NULL);
pixel_surround_release (surround);
g_free (surround->buf);
g_free (surround->bg);
g_free (surround);
}