Commit 85393964 authored by scott's avatar scott
Browse files

Another tile tweak. This one eliminates tile levels (which add

bookkeeping without being used).  Made copy_region more intelligent on
when to use tile sharing; some changes made to pixel_regions to
facilitate this.  Fixed a refcount problem with xcf load and probably
a few other bugs that I've forgotten about.  Added a sanity check in
set_undo_tiles to help with a problem larry is reporting with airbrush
and xinput.  --sg
parent 8e5e63d7
Sat Aug 15 14:09:12 1998 Scott Goehring <scott@poverty.bloomington.in.us>
* blend.c boundary.c by_color_select.c channel.c color_picker.c
convert.c drawable_cmds.c file_new_dialog.c flip_tool.c
floating_sel.c fuzzy_select.c gimage_mask.c gimpimage.c
gimpimage.h global_edit.c image_map.c image_render.c ink.c
layer.c paint_core.c paint_funcs.c perspective_tool.c
pixel_region.c pixel_region.h plug_in.c rotate_tool.c
scale_tool.c shear_tool.c text_tool.c tile_manager.c
tile_manager.h tile_manager_pvt.h transform_core.c undo.c xcf.c:
Another tile tweak. This one eliminates tile levels (which add
bookkeeping without being used). Made copy_region more
intelligent on when to use tile sharing; some changes made to
pixel_regions to facilitate this. Fixed a refcount problem with
xcf load and probably a few other bugs that I've forgotten
about. Added a sanity check in set_undo_tiles to help with a
problem larry is reporting with airbrush and xinput.
Sat Aug 15 16:11:07 MEST 1998 Sven Neumann <sven@gimp.org>
* TODO: updated the TODO file
......
......@@ -1358,7 +1358,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
return;
}
tile = tile_manager_get (tm, tile_info->tile_num, 0, TRUE, TRUE);
tile = tile_manager_get (tm, tile_info->tile_num, TRUE, TRUE);
if (!tile)
{
g_message ("plug-in requested invalid tile (killing)\n");
......@@ -1395,7 +1395,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
return;
}
tile = tile_manager_get (tm, tile_req->tile_num, 0, TRUE, FALSE);
tile = tile_manager_get (tm, tile_req->tile_num, TRUE, FALSE);
if (!tile)
{
g_message ("plug-in requested invalid tile (killing)\n");
......
......@@ -125,7 +125,7 @@ find_empty_segs (PixelRegion *maskPR,
{
if (tile)
tile_release (tile, FALSE);
tile = tile_manager_get_tile (maskPR->tiles, x, scanline, 0, TRUE, FALSE);
tile = tile_manager_get_tile (maskPR->tiles, x, scanline, TRUE, FALSE);
data = tile_data_pointer (tile, x % TILE_WIDTH, scanline % TILE_HEIGHT) + (tile_bpp(tile) - 1);
tilex = x / TILE_WIDTH;
......
......@@ -74,8 +74,9 @@ pixel_region_init (PR, tiles, x, y, w, h, dirty)
int dirty;
{
PR->tiles = tiles;
PR->curtile = NULL;
PR->data = NULL;
PR->bytes = tiles->levels[0].bpp;
PR->bytes = tiles->bpp;
PR->rowstride = PR->bytes * TILE_WIDTH;
PR->x = x;
PR->y = y;
......@@ -118,7 +119,7 @@ pixel_region_get_async (PR, ulx, uly, lrx, lry)
for (y = uly; y < lry; y += TILE_HEIGHT)
for (x = ulx; x < lrx; x += TILE_WIDTH)
tile_manager_get_async (PR->tiles, x, y, 0);
tile_manager_get_async (PR->tiles, x, y);
}
void
......@@ -143,7 +144,7 @@ pixel_region_get_row (PR, x, y, w, data, subsample)
while (x < end)
{
tile = tile_manager_get_tile (PR->tiles, x, y, 0, TRUE, FALSE);
tile = tile_manager_get_tile (PR->tiles, x, y, TRUE, FALSE);
tile_data = tile_data_pointer (tile, x % TILE_WIDTH, y % TILE_HEIGHT);
npixels = tile_ewidth (tile) - (x % TILE_WIDTH);
......@@ -190,7 +191,7 @@ pixel_region_set_row (PR, x, y, w, data)
while (x < end)
{
tile = tile_manager_get_tile (PR->tiles, x, y, 0, TRUE, TRUE);
tile = tile_manager_get_tile (PR->tiles, x, y, TRUE, TRUE);
tile_data = tile_data_pointer (tile, x % TILE_WIDTH, y % TILE_HEIGHT);
npixels = tile_ewidth(tile) - (x % TILE_WIDTH);
......@@ -229,7 +230,7 @@ pixel_region_get_col (PR, x, y, h, data, subsample)
while (y < end)
{
tile = tile_manager_get_tile (PR->tiles, x, y, 0, TRUE, FALSE);
tile = tile_manager_get_tile (PR->tiles, x, y, TRUE, FALSE);
tile_data = tile_data_pointer (tile, x % TILE_WIDTH, y % TILE_HEIGHT);
boundary = y + (tile_eheight(tile) - (y % TILE_HEIGHT));
if (boundary > end) /* make sure we don't write past the end */
......@@ -269,7 +270,7 @@ pixel_region_set_col (PR, x, y, h, data)
while (y < end)
{
tile = tile_manager_get_tile (PR->tiles, x, y, 0, TRUE, TRUE);
tile = tile_manager_get_tile (PR->tiles, x, y, TRUE, TRUE);
tile_data = tile_data_pointer (tile, x % TILE_WIDTH, y % TILE_HEIGHT);
boundary = y + (tile_eheight(tile) - (y % TILE_HEIGHT));
inc = tile_bpp(tile) * tile_ewidth(tile);
......@@ -370,8 +371,8 @@ pixel_regions_process (PRI_ptr)
/* Unref the last referenced tile if the underlying region is a tile manager */
if (PRH->PR->tiles)
{
Tile *tile = tile_manager_get_tile (PRH->PR->tiles, PRH->PR->x, PRH->PR->y, 0, FALSE, FALSE);
tile_release (tile, PRH->PR->dirty);
tile_release (PRH->PR->curtile, PRH->PR->dirty);
PRH->PR->curtile = NULL;
}
PRH->PR->x += PRI->portion_width;
......@@ -417,8 +418,8 @@ pixel_regions_process_stop (PRI_ptr)
/* Unref the last referenced tile if the underlying region is a tile manager */
if (PRH->PR->tiles)
{
Tile *tile = tile_manager_get_tile (PRH->PR->tiles, PRH->PR->x, PRH->PR->y, 0, FALSE, FALSE);
tile_release (tile, PRH->PR->dirty);
tile_release (PRH->PR->curtile, PRH->PR->dirty);
PRH->PR->curtile = NULL;
}
}
......@@ -588,16 +589,14 @@ pixel_region_configure (PRH, PRI)
*/
if (PRH->PR->tiles)
{
Tile *tile;
int offx, offy;
PRH->PR->curtile = tile_manager_get_tile (PRH->PR->tiles, PRH->PR->x, PRH->PR->y, TRUE, PRH->PR->dirty);
tile = tile_manager_get_tile (PRH->PR->tiles, PRH->PR->x, PRH->PR->y, 0, TRUE, PRH->PR->dirty);
PRH->PR->offx = PRH->PR->x % TILE_WIDTH;
PRH->PR->offy = PRH->PR->y % TILE_HEIGHT;
offx = PRH->PR->x % TILE_WIDTH;
offy = PRH->PR->y % TILE_HEIGHT;
PRH->PR->rowstride = tile_ewidth(tile) * PRH->PR->bytes;
PRH->PR->data = tile_data_pointer(tile, offx, offy);
PRH->PR->rowstride = tile_ewidth(PRH->PR->curtile) * PRH->PR->bytes;
PRH->PR->data = tile_data_pointer(PRH->PR->curtile,
PRH->PR->offx, PRH->PR->offy);
}
else
{
......
......@@ -26,6 +26,8 @@ struct _PixelRegion
{
unsigned char * data; /* pointer to region data */
TileManager * tiles; /* pointer to tiles */
Tile * curtile; /* current tile */
int offx, offy; /* tile offsets */
int rowstride; /* bytes per pixel row */
int x, y; /* origin */
int w, h; /* width and height of region */
......
......@@ -20,8 +20,10 @@
#include "tile.h"
struct _TileLevel
struct _TileManager
{
int x, y; /* tile manager offsets */
int width; /* the width of the tiled area */
int height; /* the height of the tiled area */
int bpp; /* the bpp of each tile */
......@@ -30,13 +32,6 @@ struct _TileLevel
int ntile_cols; /* the number of tiles in each columns */
Tile **tiles; /* the tiles for this level */
};
struct _TileManager
{
int x, y; /* tile manager offsets */
int nlevels; /* the number of tile levels in the hierarchy */
TileLevel *levels; /* the hierarchy */
TileValidateProc validate_proc; /* this proc is called when an attempt to get an
* invalid tile is made.
*/
......
......@@ -23,12 +23,9 @@
#include "tile_manager_pvt.h"
#include "tile_pvt.h" /* ick. */
static void tile_manager_destroy_level (TileManager *tm,
TileLevel *level);
static int tile_manager_get_tile_num (TileManager *tm,
int xpixel,
int ypixel,
int level);
int ypixel);
TileManager*
......@@ -37,121 +34,49 @@ tile_manager_new (int toplevel_width,
int bpp)
{
TileManager *tm;
int tmp1, tmp2;
int width, height;
int i;
tm = g_new (TileManager, 1);
tmp1 = tile_manager_calc_levels (toplevel_width, TILE_WIDTH);
tmp2 = tile_manager_calc_levels (toplevel_height, TILE_HEIGHT);
tm->nlevels = MAX (tmp1, tmp2);
tm->levels = g_new (TileLevel, tm->nlevels);
tm->user_data = NULL;
tm->validate_proc = NULL;
width = toplevel_width;
height = toplevel_height;
for (i = 0; i < tm->nlevels; i++)
{
tm->levels[i].width = width;
tm->levels[i].height = height;
tm->levels[i].bpp = bpp;
tm->levels[i].ntile_rows = (height + TILE_HEIGHT - 1) / TILE_HEIGHT;
tm->levels[i].ntile_cols = (width + TILE_WIDTH - 1) / TILE_WIDTH;
tm->levels[i].tiles = NULL;
width /= 2;
height /= 2;
}
tm->width = width;
tm->height = height;
tm->bpp = bpp;
tm->ntile_rows = (height + TILE_HEIGHT - 1) / TILE_HEIGHT;
tm->ntile_cols = (width + TILE_WIDTH - 1) / TILE_WIDTH;
tm->tiles = NULL;
return tm;
}
void
tile_manager_destroy (TileManager *tm)
{
int ntiles;
int i;
for (i = 0; i < tm->nlevels; i++)
tile_manager_destroy_level (tm, &tm->levels[i]);
g_free (tm->levels);
g_free (tm);
}
int
tile_manager_calc_levels (int size,
int tile_size)
{
int levels;
levels = 1;
while (size > tile_size)
{
size /= 2;
levels += 1;
}
return levels;
}
void
tile_manager_set_nlevels (TileManager *tm,
int nlevels)
{
TileLevel *levels;
int width, height;
int i;
if ((nlevels < 1) || (nlevels == tm->nlevels))
return;
levels = g_new (TileLevel, nlevels);
if (nlevels > tm->nlevels)
if (tm->tiles)
{
for (i = 0; i < tm->nlevels; i++)
levels[i] = tm->levels[i];
ntiles = tm->ntile_rows * tm->ntile_cols;
width = tm->levels[tm->nlevels - 1].width;
height = tm->levels[tm->nlevels - 1].height;
for (; i < nlevels; i++)
for (i = 0; i < ntiles; i++)
{
levels[i].width = width;
levels[i].height = height;
levels[i].bpp = tm->levels[0].bpp;
levels[i].ntile_rows = (height + TILE_HEIGHT - 1) / TILE_HEIGHT;
levels[i].ntile_cols = (width + TILE_WIDTH - 1) / TILE_WIDTH;
levels[i].tiles = NULL;
width /= 2;
height /= 2;
if (width < 1)
width = 1;
if (height < 1)
height = 1;
TILE_MUTEX_LOCK (tm->tiles[i]);
tile_detach (tm->tiles[i], tm, i);
}
}
else
{
for (i = 0; i < nlevels; i++)
levels[i] = tm->levels[i];
for (; i < tm->nlevels; i++)
tile_manager_destroy_level (tm, &tm->levels[i]);
g_free (tm->tiles);
}
g_free (tm->levels);
tm->nlevels = nlevels;
tm->levels = levels;
g_free (tm);
}
void
tile_manager_set_validate_proc (TileManager *tm,
TileValidateProc proc)
......@@ -159,31 +84,29 @@ tile_manager_set_validate_proc (TileManager *tm,
tm->validate_proc = proc;
}
Tile*
tile_manager_get_tile (TileManager *tm,
int xpixel,
int ypixel,
int level,
int wantread,
int wantwrite)
{
int tile_num;
tile_num = tile_manager_get_tile_num (tm, xpixel, ypixel, level);
tile_num = tile_manager_get_tile_num (tm, xpixel, ypixel);
if (tile_num < 0)
return NULL;
return tile_manager_get (tm, tile_num, level, wantread, wantwrite);
return tile_manager_get (tm, tile_num, wantread, wantwrite);
}
Tile*
tile_manager_get (TileManager *tm,
int tile_num,
int level,
int wantread,
int wantwrite)
{
TileLevel *tile_level;
Tile **tiles;
Tile **tile_ptr;
int ntiles;
......@@ -192,32 +115,28 @@ tile_manager_get (TileManager *tm,
int bottom_tile;
int i, j, k;
if ((level < 0) || (level >= tm->nlevels))
return NULL;
tile_level = &tm->levels[level];
ntiles = tile_level->ntile_rows * tile_level->ntile_cols;
ntiles = tm->ntile_rows * tm->ntile_cols;
if ((tile_num < 0) || (tile_num >= ntiles))
return NULL;
if (!tile_level->tiles)
if (!tm->tiles)
{
tile_level->tiles = g_new (Tile*, ntiles);
tiles = tile_level->tiles;
tm->tiles = g_new (Tile*, ntiles);
tiles = tm->tiles;
nrows = tile_level->ntile_rows;
ncols = tile_level->ntile_cols;
nrows = tm->ntile_rows;
ncols = tm->ntile_cols;
right_tile = tile_level->width - ((ncols - 1) * TILE_WIDTH);
bottom_tile = tile_level->height - ((nrows - 1) * TILE_HEIGHT);
right_tile = tm->width - ((ncols - 1) * TILE_WIDTH);
bottom_tile = tm->height - ((nrows - 1) * TILE_HEIGHT);
for (i = 0, k = 0; i < nrows; i++)
{
for (j = 0; j < ncols; j++, k++)
{
tiles[k] = g_new (Tile, 1);
tile_init (tiles[k], tile_level->bpp);
tile_init (tiles[k], tm->bpp);
tile_attach (tiles[k], tm, k);
if (j == (ncols - 1))
......@@ -229,7 +148,7 @@ tile_manager_get (TileManager *tm,
}
}
tile_ptr = &tile_level->tiles[tile_num];
tile_ptr = &tm->tiles[tile_num];
if (wantread)
{
......@@ -268,19 +187,16 @@ tile_manager_get (TileManager *tm,
void
tile_manager_get_async (TileManager *tm,
int xpixel,
int ypixel,
int level)
int ypixel)
{
Tile *tile_ptr;
TileLevel *tile_level;
int tile_num;
tile_num = tile_manager_get_tile_num (tm, xpixel, ypixel, level);
tile_num = tile_manager_get_tile_num (tm, xpixel, ypixel);
if (tile_num < 0)
return;
tile_level = &tm->levels[level];
tile_ptr = tile_level->tiles[tile_num];
tile_ptr = tm->tiles[tile_num];
tile_swap_in_async (tile_ptr);
}
......@@ -292,164 +208,40 @@ tile_manager_validate (TileManager *tm,
tile->valid = TRUE;
if (tm->validate_proc)
(* tm->validate_proc) (tm, tile, -1);
(* tm->validate_proc) (tm, tile);
}
void
tile_manager_invalidate_tiles (TileManager *tm,
Tile *toplevel_tile)
{
TileLevel *level;
double x, y;
int row, col;
int num;
int i;
col = toplevel_tile->tlink->tile_num % tm->levels[0].ntile_cols;
row = toplevel_tile->tlink->tile_num / tm->levels[0].ntile_cols;
x = (col * TILE_WIDTH + toplevel_tile->ewidth / 2.0) / (double) tm->levels[0].width;
y = (row * TILE_HEIGHT + toplevel_tile->eheight / 2.0) / (double) tm->levels[0].height;
for (i = 1; i < tm->nlevels; i++)
{
level = &tm->levels[i];
if (level->tiles)
{
col = x * level->width / TILE_WIDTH;
row = y * level->height / TILE_HEIGHT;
num = row * level->ntile_cols + col;
tile_invalidate (&level->tiles[num], tm, num);
}
}
}
void
tile_manager_invalidate_sublevels (TileManager *tm)
{
int ntiles;
int i, j;
for (i = 1; i < tm->nlevels; i++)
{
if (tm->levels[i].tiles)
{
ntiles = tm->levels[i].ntile_rows * tm->levels[i].ntile_cols;
for (j = 0; j < ntiles; j++)
tile_invalidate (&tm->levels[i].tiles[j], tm, j);
}
}
}
void
tile_manager_update_tile (TileManager *tm,
Tile *toplevel_tile,
int level)
{
TileLevel *tile_level;
Tile *tile;
guchar *src, *dest;
double x, y;
int srcx, srcy;
int tilex, tiley;
int tilew, tileh;
int bpp;
int row, col;
int num;
int i, j, k;
if ((level < 1) || (level >= tm->nlevels))
return;
col = toplevel_tile->tlink->tile_num % tm->levels[0].ntile_cols;
row = toplevel_tile->tlink->tile_num / tm->levels[0].ntile_cols;
x = (col * TILE_WIDTH + toplevel_tile->ewidth / 2.0) / (double) tm->levels[0].width;
y = (row * TILE_HEIGHT + toplevel_tile->eheight / 2.0) / (double) tm->levels[0].height;
tilex = ((col * TILE_WIDTH) >> level) % 64;
tiley = ((row * TILE_HEIGHT) >> level) % 64;
if (level > 6)
{
if (((col % (level - 6)) != 0) ||
((row % (level - 6)) != 0))
return;
tilew = 1;
tileh = 1;
}
else
{
tilew = (toplevel_tile->ewidth) >> level;
tileh = (toplevel_tile->eheight) >> level;
}
tile_level = &tm->levels[level];
col = (x * tile_level->width) / TILE_WIDTH;
row = (y * tile_level->height) / TILE_HEIGHT;
num = row * tile_level->ntile_cols + col;
tile = tile_manager_get (tm, num, level, TRUE, TRUE);
tile_lock (toplevel_tile);
col = toplevel_tile->tlink->tile_num % tm->ntile_cols;
row = toplevel_tile->tlink->tile_num / tm->ntile_cols;
tilew += tilex;
tileh += tiley;
x = (col * TILE_WIDTH + toplevel_tile->ewidth / 2.0) / (double) tm->width;
y = (row * TILE_HEIGHT + toplevel_tile->eheight / 2.0) / (double) tm->height;
bpp = tile->bpp;
for (i = tiley; i < tileh; i++)
if (tm->tiles)
{
srcx = tilex << level;
srcy = tiley << level;
src = toplevel_tile->data + (srcy * toplevel_tile->ewidth + srcx) * bpp;
dest = tile->data + (tiley * tile->ewidth + tilex) * bpp;
for (j = tilex; j < tilew; j++)
{
for (k = 0; k < bpp; k++)
dest[k] = src[k];
dest += bpp;
src += (bpp << level);
}
}
tile_release (tile, TRUE);
tile_release (toplevel_tile, FALSE);
}
static void
tile_manager_destroy_level (TileManager *tm, TileLevel *level)
{
int ntiles;
int i;
if (level->tiles)
{
ntiles = level->ntile_rows * level->ntile_cols;
for (i = 0; i < ntiles; i++)
{
TILE_MUTEX_LOCK (level->tiles[i]);
tile_detach (level->tiles[i], tm, i);
}
g_free (level->tiles);
col = x * tm->width / TILE_WIDTH;
row = y * tm->height / TILE_HEIGHT;
num = row * tm->ntile_cols + col;
tile_invalidate (&tm->tiles[num], tm, num);
}
}