Incorporated Adam's copy-on-write patches. Seems to not break anything,

Incorporated Adam's copy-on-write patches.  Seems to not break
anything, but I'm sure they do somewhere. --sg
This commit is contained in:
scott 1998-07-02 23:29:44 +00:00
parent ddc557c297
commit 27e90260db
71 changed files with 1789 additions and 232 deletions

View File

@ -1,3 +1,12 @@
Thu Jul 2 18:10:43 1998 Scott Goehring <scott@poverty.bloomington.in.us>
* blend.c boundary.c by_color_select.c channel.c color_picker.c
drawable_cmds.c frac.c fuzzy_select.c image_render.c invert.c
layer.c paint_core.c paint_funcs.c pixel_region.c plug_in.c tile.c
tile.h tile_cache.c tile_manager.c transform_core.c undo.c xcf.c:
incorporated Adam's copy-on-write patches. Tested briefly:
nothing seems to be broken, but I guarantee nothing.
Thu Jul 2 11:03:12 PDT 1998 Manish Singh <yosh@gimp.org>
* updated blur, randomize, and exchange plugins (not sure if
@ -358,7 +367,6 @@ Sat Jun 20 11:36:16 PDT 1998 Manish Singh <yosh@gimp.org>
* configure.in
* app/Makefile.am: really add thread support
>>>>>>> 1.454
Sat Jun 20 12:04:41 1998 Scott Goehring <scott@poverty.bloomington.in.us>
* app/tile.h: #include config.h so we can tell if we're doing
@ -393,7 +401,6 @@ Fri Jun 19 12:34:29 PDT 1998 Manish Singh <yosh@gimp.org>
* changes libgimp versioning to gtk-style. Bunch o' Makefile.am
changes for that
>>>>>>> 1.430
Thu Jun 18 23:11:36 1998 Owen Taylor <otaylor@gtk.org>
* app/ink.c: Shift the range to smaller brushes.

View File

@ -1360,7 +1360,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
return;
}
tile_ref (tile);
tile_ref2 (tile, TRUE);
if (tile_data.use_shm)
memcpy (tile->data, shm_addr, tile_size (tile));
@ -1407,7 +1407,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
tile_data.height = tile->eheight;
tile_data.use_shm = (shm_ID == -1) ? FALSE : TRUE;
tile_ref (tile);
tile_ref2 (tile, FALSE);
if (tile_data.use_shm)
memcpy (shm_addr, tile->data, tile_size (tile));

View File

@ -124,7 +124,7 @@ find_empty_segs (PixelRegion *maskPR,
if (tile)
tile_unref (tile, FALSE);
tile = tile_manager_get_tile (maskPR->tiles, x, scanline, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
data = tile->data + tile->bpp *
((scanline % TILE_HEIGHT) * tile->ewidth + (x % TILE_WIDTH)) + (tile->bpp - 1);
tilex = x / TILE_WIDTH;

View File

@ -124,7 +124,7 @@ pixel_region_get_row (PR, x, y, w, data, subsample)
while (x < end)
{
tile = tile_manager_get_tile (PR->tiles, x, y, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
tile_data = tile->data + tile->bpp * (tile->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH));
boundary = x + (tile->ewidth - (x % TILE_WIDTH));
inc = subsample * tile->bpp;
@ -159,7 +159,7 @@ pixel_region_set_row (PR, x, y, w, data)
while (x < end)
{
tile = tile_manager_get_tile (PR->tiles, x, y, 0);
tile_ref (tile);
tile_ref2 (tile, TRUE);
tile_data = tile->data + tile->bpp * (tile->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH));
boundary = x + (tile->ewidth - (x % TILE_WIDTH));
@ -194,7 +194,7 @@ pixel_region_get_col (PR, x, y, h, data, subsample)
while (y < end)
{
tile = tile_manager_get_tile (PR->tiles, x, y, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
tile_data = tile->data + tile->bpp * (tile->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH));
boundary = y + (tile->eheight - (y % TILE_HEIGHT));
inc = subsample * tile->bpp * tile->ewidth;
@ -230,7 +230,7 @@ pixel_region_set_col (PR, x, y, h, data)
while (y < end)
{
tile = tile_manager_get_tile (PR->tiles, x, y, 0);
tile_ref (tile);
tile_ref2 (tile, TRUE);
tile_data = tile->data + tile->bpp * (tile->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH));
boundary = y + (tile->eheight - (y % TILE_HEIGHT));
inc = tile->bpp * tile->ewidth;
@ -550,7 +550,7 @@ pixel_region_configure (PRH, PRI)
int offx, offy;
tile = tile_manager_get_tile (PRH->PR->tiles, PRH->PR->x, PRH->PR->y, 0);
tile_ref (tile);
tile_ref2 (tile, PRH->PR->dirty);
offx = PRH->PR->x % TILE_WIDTH;
offy = PRH->PR->y % TILE_HEIGHT;

View File

@ -1,6 +1,7 @@
#include <gtk/gtkmain.h>
#include <glib.h>
#include "gimprc.h"
#include "tile.h"
#include "tile_cache.h"
#include "tile_swap.h"
#ifdef USE_PTHREADS

View File

@ -339,8 +339,8 @@ tile_manager_update_tile (TileManager *tm,
tile = tile_manager_get (tm, num, level);
tile_ref (tile);
tile_ref (toplevel_tile);
tile_ref2 (tile, TRUE);
tile_ref2 (toplevel_tile, FALSE);
tilew += tilex;
tileh += tiley;

View File

@ -1,8 +1,43 @@
#include <stdio.h>
#include "tile.h"
#include "tile_cache.h"
#include "tile_manager.h"
#include "tile_swap.h"
/* EXPERIMENTAL Copy-On-Write goodies
* by Adam D. Moss
* adam@gimp.org
* adam@foxbox.org
*
*
* C.O.W. Revisions:
*
* 97.10.05 - Initial release
* 97.10.06 - Much faster tile invalidation +
* Better swap interaction (should no longer
* crash GIMP when GIMP swapfile is full).
* 97.10.18 - Very stable now, and even more efficient.
* 98.06.16 - Revised from GIMP 0.99.14 for 1.[01].0 - no
* longer so sure about stability until
* more comprehensive testing is done.
*
*
* MISC TODO:
*
* tile_invalidate: (tile_manager) - don't let a tile become
* invalidated if its ref-count >1, but move it to a delete-on-last-unref
* list instead...
*/
/*
* Define MUCH_TILE_DEBUG in addition to TILE_DEBUG to get
* debugging for every single tile_ref2 and tile_unref (that's
* a lot).
#define MUCH_TILE_DEBUG heckyeah
*/
void
tile_init (Tile *tile,
@ -11,11 +46,13 @@ tile_init (Tile *tile,
tile->ref_count = 0;
tile->dirty = FALSE;
tile->valid = FALSE;
tile->data = NULL;
tile->real_tile_ptr = NULL;
tile->mirrored_by = NULL;
tile->ewidth = TILE_WIDTH;
tile->eheight = TILE_HEIGHT;
tile->bpp = bpp;
tile->tile_num = -1;
tile->data = NULL;
tile->swap_num = 1;
tile->swap_offset = -1;
tile->tm = NULL;
@ -28,57 +65,417 @@ tile_init (Tile *tile,
#endif
}
int tile_ref_count = 0;
void
#if defined (TILE_DEBUG) && defined (__GNUC__)
_tile_ref (Tile *tile, char *func_name)
#else
tile_ref (Tile *tile)
#endif
{
/* While things get moved over to the new tile_ref2
* interface, tile_ref is a wrapper which just says
* 'yes, we'll be dirtying the tile'
*/
#if defined (TILE_DEBUG) && defined (__GNUC__)
printf("COW-Warning: function %s is using obsolete tile_ref interface\n",
func_name);
#endif
#if defined (TILE_DEBUG) && defined (__GNUC__)
_tile_ref2 (tile, TRUE, func_name);
#else
tile_ref2 (tile, TRUE);
#endif
}
gboolean
tile_is_mirroring (Tile *tile)
{
return (tile->real_tile_ptr != NULL);
}
gboolean
tile_is_mirrored (Tile *tile)
{
return (tile->mirrored_by != NULL);
}
gboolean
tile_is_real (Tile *tile)
{
return (tile->real_tile_ptr == NULL);
}
/* Follow the real_tile_ptr links back to the tile which provides
* the real source data for the given tile
*/
Tile *
tile_find_nonmirroring (Tile *tile)
{
if (! tile_is_mirroring (tile))
{
return tile;
}
else
{
return tile_find_nonmirroring (tile->real_tile_ptr);
}
}
/*
*/
Tile *
tile_find_finalmirroring (Tile *tile)
{
if (! tile_is_mirrored (tile))
{
return tile;
}
else
{
return tile_find_finalmirroring (tile->mirrored_by);
}
}
/* Take a mirroring-tile and turn it into a bona fide self-contained
* tile.
*/
void
tile_devirtualize (Tile *tile)
{
Tile *real_tile;
/* Sanity */
if (tile_is_real (tile))
g_error ("Tried to devirtualize a real tile");
#if defined (TILE_DEBUG)
if (tile->ref_count == 0)
g_warning ("Trying to devirtualize a mirroring-tile with no ref_count");
#endif
/* Go find the tile ('real_tile') which owns the real data
*/
real_tile = tile_find_nonmirroring (tile);
/* Sanity */
#if defined (TILE_DEBUG)
if (real_tile->ref_count == 0)
g_warning ("Trying to devirtualize a mirroring-tile whose real_tile has no ref_count");
#endif
if (!real_tile->valid)
g_warning ("Trying to devirtualize a mirroring-tile whose real_tile is !valid");
/* Copy the actual tile data from the real_tile to this tile
*/
tile->data = NULL;
tile_alloc (tile);
/* printf ("{ %dx%d : %d - %p[%p]->%p[%p] }", real_tile->ewidth, real_tile->eheight,
real_tile->bpp, real_tile, real_tile->data, tile, tile->data);
fflush(stdout);*/
memcpy (tile->data, real_tile->data, tile_size(real_tile));
/* 'tile' is now a real tile. */
tile->real_tile_ptr = NULL;
tile->valid = TRUE;
tile_cache_insert(tile);
#if defined (TILE_DEBUG)
g_print ("Tile at %p is now devirtualized.\n", tile);
#endif
}
/* Make this tile self-contained.
*
* The next tile in the linked-list of tiles which are mirroring 'tile'
* is promoted to a real physical tile and unlinked from 'tile'. This
* renders 'tile' safe for dirtying (or destruction).
*/
void
tile_isolate (Tile *tile)
{
Tile *temp_tileptr;
/* Sanity
*/
if (! (tile_is_mirrored (tile) || tile_is_mirroring (tile)))
{
g_warning ("Tried to isolate a tile which is neither a mirror source "
"nor destination");
return;
}
/* This tile is both linked to and linked from? */
if (tile_is_mirrored (tile) && tile_is_mirroring (tile))
{
temp_tileptr = tile->real_tile_ptr;
#if defined (TILE_DEBUG)
g_print ("tile %p: was middle of chain - relinking %p and %p\n",
tile,
temp_tileptr,
tile->mirrored_by);
#endif
tile->mirrored_by->real_tile_ptr = temp_tileptr;
temp_tileptr->mirrored_by = tile->mirrored_by;
tile_ref2 (temp_tileptr, FALSE);
tile_devirtualize (tile);
tile_unref (temp_tileptr, FALSE);
tile->mirrored_by = NULL;
return;
}
/* This tile is mirroring another, but is not mirrored itself? */
if (tile_is_mirroring (tile))
{
temp_tileptr = tile->real_tile_ptr;
#if defined (TILE_DEBUG)
g_print ("tile %p: was end of chain - cauterizing %p\n",
tile,
temp_tileptr);
#endif
/* We stop mirroring the tile which we previously were -
* so reset that tile's mirrored_by pointer.
*/
temp_tileptr->mirrored_by = NULL;
tile_ref2 (temp_tileptr, FALSE);
tile_devirtualize (tile);
tile_unref (temp_tileptr, FALSE);
return;
}
/* This tile is mirrored by another, but is not itself a mirror. */
if (tile_is_mirrored (tile))
{
#if defined (TILE_DEBUG)
g_print ("tile %p: was source of chain - devirtualizing %p\n",
tile,
tile->mirrored_by);
#endif
temp_tileptr = tile->mirrored_by;
tile_ref2 (temp_tileptr, FALSE);
tile_devirtualize (temp_tileptr);
tile_unref (temp_tileptr, FALSE);
/* The tile which was dependant on this one no longer is -
* so we can unref once.
*/
tile_unref (tile, FALSE);
tile->mirrored_by = NULL;
return;
}
}
/* Turns dest_tile into a mirroring-tile which mirrors the given
* src_tile using copy-on-write.
*/
void
tile_mirror (Tile *dest_tile, Tile *src_tile)
{
Tile *finalmirroring;
if (dest_tile == src_tile)
{
g_warning ("TRIED TO MIRROR TILE TO ITSELF");
return;
}
#if defined (TILE_DEBUG)
g_print ("mirroring ");
#endif
if (tile_is_real (dest_tile))
{
#if defined (TILE_DEBUG)
g_print ("TO REAL ");
#endif
tile_invalidate (dest_tile);
}
else
{
tile_invalidate (dest_tile);
}
/* dest_tile->ref_count = 0; */
dest_tile->dirty = FALSE;
dest_tile->valid = FALSE;
dest_tile->data = NULL;
dest_tile->ewidth = src_tile->ewidth;
dest_tile->eheight = src_tile->eheight;
dest_tile->bpp = src_tile->bpp;
dest_tile->tile_num = -1; /* ! */
/*
*/
finalmirroring = tile_find_finalmirroring (src_tile);
dest_tile->real_tile_ptr = finalmirroring;
finalmirroring->mirrored_by = dest_tile;
#if defined (TILE_DEBUG)
g_print ("%p -> %p\n", finalmirroring, dest_tile);
#endif
/* The following should be irrelevant in a mirroring tile - mirroring
* tiles by definition don't have real data of their own, so they can't
* be swapped. They don't have associated TileManagers either, since they
* rely on their mirrored source tile to contain validated data.
*/
dest_tile->swap_num = 1;
dest_tile->swap_offset = -1;
dest_tile->tm = NULL;
}
void
#if defined (TILE_DEBUG) && defined (__GNUC__)
_tile_ref2 (Tile *tile, int dirty, char *func_name)
#else
tile_ref2 (Tile *tile, int dirty)
#endif
{
#ifdef USE_PTHREADS
pthread_mutex_lock(&(tile->mutex));
#endif
/* g_print ("tile_ref: 0x%08x %s\n", tile, func_name); */
#if defined (TILE_DEBUG) && defined (__GNUC__) && defined (MUCH_TILE_DEBUG)
g_print ("tile_ref2: %02d %c %p %s\n", tile->ref_count,
dirty?'d':' ',
tile,
func_name);
#endif
/*g_print ("tile_ref2: %02d %c %p\n", tile->ref_count,
dirty?'d':' ',
tile);*/
/* Increment the global reference count.
*/
tile_ref_count += 1;
/* Increment the reference count.
/* Increment this tile's reference count.
*/
tile->ref_count += 1;
/* If this is the first reference to the tile then
* swap the tile data in from disk. Note: this will
* properly handle the case where the tile data isn't
* on disk.
*/
if (tile->ref_count == 1)
#if defined (TILE_DEBUG)
if (tile_is_mirrored (tile) && dirty)
{
tile_swap_in (tile);
g_print ("Dirtying a mirrored tile: %p.\n", tile);
}
#endif
/* the tile must be clean */
tile->dirty = FALSE;
/*
if (dirty && tile->dirty)
{
g_print ("Not good: Dirtying a write-locked tile: %p.\n", tile);
} */
/* if this is a read-only attachment to a mirroring tile,
* then ref the chain, update the data pointer, and return.
*/
if ((!dirty) && (tile_is_mirroring (tile)))
{
/* ref each of the tiles in the chain, back to the
* 'real' tile which sits at the start.
*/
#if USE_PTHREADS
pthread_mutex_unlock(&(tile->mutex));
#endif
tile_ref2 (tile->real_tile_ptr, FALSE);
tile->data = tile->real_tile_ptr->data;
return;
}
/* Insert the tile into the cache. If the tile is already
* in the cache this will have the affect of "touching"
* the tile.
*/
tile_cache_insert (tile);
/* Call 'tile_manager_validate' if the tile was invalid.
/* dirty, or clean-and-real */
/* Real tile - first reference. */
if (!tile_is_mirroring (tile))
{
/* If this is the first reference to the tile then
* swap the tile data in from disk. Note: this will
* properly handle the case where the tile data isn't
* on disk.
*/
if (tile->ref_count == 1)
{
tile_swap_in (tile);
}
/* Insert the tile into the cache. If the tile is already
* in the cache this will have the affect of "touching"
* the tile.
*/
tile_cache_insert (tile);
}
/* Read/write attachment to a mirrored/ing tile - must be
* thoughtful.
*/
if (dirty)
{
/* Doing a read/write reference to a mirroring/ed tile -
* we'll have to turn the tile into a 'real' tile.
* Then return - we're done.
*/
{
if (tile_is_mirroring (tile) | tile_is_mirrored (tile))
{
#if defined (TILE_DEBUG)
g_print ("r/w to mir'd/ing - isolating: ");
#endif
tile_isolate (tile);
}
}
}
/* Mark the tile as dirty if it's being ref'd as dirtyable.
*/
tile->dirty |= dirty;
#if USE_PTHREADS
pthread_mutex_unlock(&(tile->mutex));
#endif
/* Call 'tile_manager_validate' if the tile was invalid.
*/
if (!tile->valid)
tile_manager_validate ((TileManager*) tile->tm, tile);
}
void
#if defined (TILE_DEBUG) && defined (__GNUC__)
_tile_unref (Tile *tile, int dirty, char *func_name)
@ -89,20 +486,76 @@ tile_unref (Tile *tile, int dirty)
#ifdef USE_PTHREADS
pthread_mutex_lock(&(tile->mutex));
#endif
/* g_print ("tile_unref: 0x%08x %s\n", tile, func_name); */
#if defined (TILE_DEBUG) && defined (__GNUC__) && defined (MUCH_TILE_DEBUG)
g_print ("tile_unref: %02d %c %p %s\n", tile->ref_count,
dirty?'d':' ',
tile, func_name);
#endif
/* g_print ("tile_unref: %02d %c %p\n", tile->ref_count,
dirty?'d':' ',
tile);*/
/* Decrement the global reference count.
*/
tile_ref_count -= 1;
/* Decrement the reference count.
/* Decrement this tile's reference count.
*/
tile->ref_count -= 1;
/* Mark the tile dirty if indicated
*
* commented out - we now dirty on ref, not unref
*/
if (dirty && !tile->dirty)
/*
tile->dirty |= dirty;
*/
#if defined (TILE_DEBUG)
if (tile_is_mirroring (tile))
{
tile->dirty = TRUE;
tile_cache_insert (tile);
/* Mirroring tiles aren't allowed to be submitted as dirty -
* they should have been isolated at ref time.
*/
if (dirty)
g_warning ("Mirroring tile unref'd as dirty.");
}
if (tile_is_mirrored (tile))
{
/* Mirrored tiles aren't allowed to be submitted as dirty -
* they should have been isolated at ref time.
*/
fflush(stdout);
if (dirty)
g_warning ("Mirrored tile unref'd as dirty.");
}
#endif
/* When we unref a mirroring tile, also unref the tile which
* was being mirrored.
*/
if (tile_is_mirroring (tile))
{
/* Mirroring tiles aren't allowed to be submitted as dirty -
* they should have been ref'd as dirty in the first place so we
* could turn them into 'real' tiles.
*/
if (dirty)
{
g_warning ("Bleh, tried to unref a mirroring tile as dirty.");
}
/* Go find the mirrored tile and unref that too. */
#if USE_PTHREADS
pthread_mutex_unlock(&(tile->mutex));
#endif
tile_unref (tile->real_tile_ptr, FALSE);
return;
}
/* If this was the last reference to the tile, then
@ -111,15 +564,21 @@ tile_unref (Tile *tile, int dirty)
if (tile->ref_count == 0)
{
/* Only need to swap out in two cases:
* 1) The tile is dirty
* 2) The tile has never been swapped
* 1) The tile is dirty }
* 2) The tile has never been swapped } and is not mirroring
*/
if (tile->dirty || tile->swap_offset == -1)
if ((tile->dirty || tile->swap_offset == -1)
&& !tile_is_mirroring (tile))
tile_swap_out (tile);
/* Otherwise, just throw out the data--the same stuff is in swap
*/
g_free (tile->data);
tile->data = NULL;
else
{
if (! tile_is_mirroring (tile))
g_free (tile->data);
tile->data = NULL;
}
}
#if USE_PTHREADS
pthread_mutex_unlock(&(tile->mutex));
@ -155,6 +614,128 @@ tile_invalidate (Tile *tile)
#ifdef USE_PTHREADS
pthread_mutex_lock(&(tile->mutex));
#endif
#if defined (TILE_DEBUG)
if (tile->ref_count > 1)
{
g_print (" (inv%p:ref%d) ", tile, tile->ref_count);
}
else
{
g_print (" (inv%p) ", tile);
}
#endif
/* If this tile is mirrored/ing, then maybe isolate it before we
* invalidate it, so that we don't accidentally delete a tile
* whose data is still in use by a mirror.
*/
if (tile_is_mirrored (tile))
{
if (tile_is_mirroring (tile))
{
/* tile is in the middle of a chain. just relink its
* successor and predecessor. that's all we need to do for
* a cleanup.
*/
#if defined (TILE_DEBUG)
g_print ("tile %p: was middle of chain - relinking %p and %p, "
"no isolation\n",
tile,
tile->real_tile_ptr,
tile->mirrored_by);
#endif
tile->mirrored_by->real_tile_ptr = tile->real_tile_ptr;
tile->real_tile_ptr->mirrored_by = tile->mirrored_by;
}
else
{
/* tile is real, and mirrored. Copy its vital statistics to
* its successor in the tile chain, so it can be safely deleted.
*/
#if defined (TILE_DEBUG)
g_print ("tile %p: was source of chain - successor %p swallows soul"
", no isolation\n",
tile,
tile->mirrored_by);
#endif
/* remove 'tile' from cache - but keep the ref_count up
* so that the tile_unref() which tile_cache_flush() calls
* won't invalidate the tile (we'll be doing that ourselves).
*/
tile->ref_count++;
tile_cache_flush (tile);
tile->ref_count--;
/* imbue our successor with our data pointer, validity,
* tile manager, swap_num, swap_offset, and dirty
* flag
*/
tile->mirrored_by->data = tile->data;
tile->data = NULL;
tile->mirrored_by->dirty = tile->dirty;
tile->dirty = FALSE;
tile->mirrored_by->valid = tile->valid;
tile->valid = FALSE;
tile->mirrored_by->swap_num = tile->swap_num;
tile->swap_num = 0;
tile->mirrored_by->swap_offset = tile->swap_offset;
tile->swap_num = -1;
tile->mirrored_by->tm = tile->tm;
tile->tm = NULL;
/* sever links with our successor in both directions.
* our successor is now the new chain source.
*
* also register this newly-born 'real' tile with the tile cache.
*/
tile->mirrored_by->real_tile_ptr = NULL;
tile_cache_insert (tile->mirrored_by);
tile->mirrored_by = NULL;
/* This tile is as clean and invalid as it's going to get.
* Return.
*/
return;
}
}
else /* not mirrored, maybe mirroring */
{
/* for a non-real tile at the end of a chain, the only cleanup
* we have to do for its safe destruction is cauterize the
* flapping mirrored_by pointer of its predecessor on the chain.
*/
if (tile_is_mirroring (tile))
{
#if defined (TILE_DEBUG)
g_print ("tile %p: was end of chain - cauterizing %p, no "
"isolation\n",
tile,
tile->real_tile_ptr);
#endif
tile->real_tile_ptr->mirrored_by = NULL;
}
}
/* If this isn't a 'real' tile then it doesn't need invalidating,
* since it doesn't have any unique data associated with it.
*/
if (!tile_is_real (tile))
{
if (tile->valid)
{
g_warning ("tried to invalidate a mirroring tile which was valid.");
tile->valid = FALSE;
}
return;
}
/* Only 'real' tiles permitted past this point.
*/
/* Invalidate the tile. (Must be valid first).
*/
if (tile->valid)
@ -189,3 +770,5 @@ tile_invalidate (Tile *tile)
pthread_mutex_unlock(&(tile->mutex));
#endif
}

View File

@ -4,7 +4,11 @@
#define TILE_WIDTH 64
#define TILE_HEIGHT 64
/* Uncomment for verbose debugging on copy-on-write logic
#define TILE_DEBUG
*/
#include <sys/types.h>
@ -30,24 +34,38 @@ struct _Tile
guint dirty : 1; /* is the tile dirty? has it been modified? */
guint valid : 1; /* is the tile valid? */
int ewidth; /* the effective width of the tile */
int eheight; /* the effective height of the tile */
/* a tiles effective width and height may be smaller
* (but not larger) than TILE_WIDTH and TILE_HEIGHT.
* this is to handle edge tiles of a drawable.
*/
int bpp; /* the bytes per pixel (1, 2, 3 or 4) */
int tile_num; /* the number of this tile within the drawable */
guchar *data; /* the data for the tile. this may be NULL in which
* case the tile data is on disk.
*/
Tile *real_tile_ptr;/* if this tile's 'data' pointer is just a copy-on-write
* mirror of another's, this is that source tile.
* (real_tile itself can actually be a virtual tile
* too.) This is NULL if this tile is not a virtual
* tile.
*/
Tile *mirrored_by; /* If another tile is mirroring this one, this is
* a pointer to that tile, otherwise this is NULL.
* Note that only one tile may be _directly_ mirroring
* another given tile. This ensures that the graph
* of mirrorings is no more complex than a linked
* list.
*/
int ewidth; /* the effective width of the tile */
int eheight; /* the effective height of the tile */
/* a tile's effective width and height may be smaller
* (but not larger) than TILE_WIDTH and TILE_HEIGHT.
* this is to handle edge tiles of a drawable.
*/
int bpp; /* the bytes per pixel (1, 2, 3 or 4) */
int tile_num; /* the number of this tile within the drawable */
int swap_num; /* the index into the file table of the file to be used
* for swapping. swap_num 1 is always the global swap file.
*/
off_t swap_offset; /* the offset within the swap file of the tile data.
* if the tile data is in memory this will be set to -1.
* if the tile data is in memory this will be set to -1.
*/
void *tm; /* A pointer to the tile manager for this tile.
@ -68,24 +86,37 @@ struct _Tile
void tile_init (Tile *tile,
int bpp);
/*
* c-o-w
*/
void tile_mirror (Tile *dest_tile, Tile *src_tile);
/* Referencing a tile causes the reference count to be incremented.
* If the reference count was previously 0 the tile will will be
* swapped into memory from disk.
*
* tile_ref2 is a new tile-referencing interface through which you
* should register your intent to dirty the tile. This will facilitate
* copy-on-write tile semantics.
*/
#if defined (TILE_DEBUG) && defined (__GNUC__)
#define tile_ref(t) _tile_ref (t, __PRETTY_FUNCTION__)
void _tile_ref (Tile *tile, char *func_name);
#define tile_ref2(t,d) _tile_ref2 (t, d, __PRETTY_FUNCTION__)
void _tile_ref2 (Tile *tile, int dirty, char *func_name);
#else
void tile_ref (Tile *tile);
void tile_ref2 (Tile *tile, int dirty);
#endif
/* Unrefercing a tile causes the reference count to be decremented.
/* Unreferencing a tile causes the reference count to be decremented.
* When the reference count reaches 0 the tile data will be swapped
* out to disk. Note that the tile may be in the tile cache which
* also references the tile causing the reference count not to

View File

@ -1013,7 +1013,7 @@ gradient_calc_shapeburst_angular_factor (double x,
ix = (int) BOUNDS (x, 0, distR.w);
iy = (int) BOUNDS (y, 0, distR.h);
tile = tile_manager_get_tile (distR.tiles, ix, iy, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
value = 1.0 - *(((float *) tile->data) + ((iy % TILE_HEIGHT) * tile->ewidth + (ix % TILE_WIDTH)));
tile_unref (tile, FALSE);
@ -1032,7 +1032,7 @@ gradient_calc_shapeburst_spherical_factor (double x,
ix = (int) BOUNDS (x, 0, distR.w);
iy = (int) BOUNDS (y, 0, distR.h);
tile = tile_manager_get_tile (distR.tiles, ix, iy, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
value = *(((float *) tile->data) + ((iy % TILE_HEIGHT) * tile->ewidth + (ix % TILE_WIDTH)));
value = 1.0 - sin (0.5 * M_PI * value);
tile_unref (tile, FALSE);
@ -1052,7 +1052,7 @@ gradient_calc_shapeburst_dimpled_factor (double x,
ix = (int) BOUNDS (x, 0, distR.w);
iy = (int) BOUNDS (y, 0, distR.h);
tile = tile_manager_get_tile (distR.tiles, ix, iy, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
value = *(((float *) tile->data) + ((iy % TILE_HEIGHT) * tile->ewidth + (ix % TILE_WIDTH)));
value = cos (0.5 * M_PI * value);
tile_unref (tile, FALSE);

View File

@ -124,7 +124,7 @@ find_empty_segs (PixelRegion *maskPR,
if (tile)
tile_unref (tile, FALSE);
tile = tile_manager_get_tile (maskPR->tiles, x, scanline, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
data = tile->data + tile->bpp *
((scanline % TILE_HEIGHT) * tile->ewidth + (x % TILE_WIDTH)) + (tile->bpp - 1);
tilex = x / TILE_WIDTH;

View File

@ -359,7 +359,7 @@ by_color_select_button_release (Tool *tool,
if (x < 0 || y < 0 || x >= gdisp->gimage->width || y >= gdisp->gimage->height)
return;
tile = tile_manager_get_tile (gimage_composite (gdisp->gimage), x, y, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
data = tile->data + tile->bpp * (tile->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH));
gimage_get_color (gdisp->gimage, gimage_composite_type(gdisp->gimage), col, data);
tile_unref (tile, FALSE);
@ -369,7 +369,7 @@ by_color_select_button_release (Tool *tool,
if (x < 0 || y < 0 || x >= drawable_width (drawable) || y >= drawable_height (drawable))
return;
tile = tile_manager_get_tile (drawable_data (drawable), x, y, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
data = tile->data + tile->bpp * (tile->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH));
gimage_get_color (gdisp->gimage, drawable_type(drawable), col, data);
tile_unref (tile, FALSE);
@ -932,7 +932,7 @@ by_color_select_preview_button_press (ByColorDialog *bcd,
if (x < 0 || y < 0 || x >= bcd->gimage->width || y >= bcd->gimage->height)
return;
tile = tile_manager_get_tile (gimage_composite (bcd->gimage), x, y, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
col = tile->data + tile->bpp * (tile->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH));
}
else
@ -945,7 +945,7 @@ by_color_select_preview_button_press (ByColorDialog *bcd,
if (x < 0 || y < 0 || x >= drawable_width (drawable) || y >= drawable_height (drawable))
return;
tile = tile_manager_get_tile (drawable_data (drawable), x, y, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
col = tile->data + tile->bpp * (tile->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH));
}

View File

@ -548,7 +548,7 @@ channel_value (Channel *mask, int x, int y)
}
tile = tile_manager_get_tile (GIMP_DRAWABLE(mask)->tiles, x, y, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
val = tile->data[(y % TILE_HEIGHT) * TILE_WIDTH + (x % TILE_WIDTH)];
tile_unref (tile, FALSE);

View File

@ -327,7 +327,7 @@ get_color (GImage *gimage,
if (x >= 0 && y >= 0 && x < width && y < height)
{
tile = tile_manager_get_tile (tiles, x, y, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
src = tile->data + tile->bpp * (tile->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH));
}

View File

@ -548,7 +548,7 @@ channel_value (Channel *mask, int x, int y)
}
tile = tile_manager_get_tile (GIMP_DRAWABLE(mask)->tiles, x, y, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
val = tile->data[(y % TILE_HEIGHT) * TILE_WIDTH + (x % TILE_WIDTH)];
tile_unref (tile, FALSE);

View File

@ -548,7 +548,7 @@ channel_value (Channel *mask, int x, int y)
}
tile = tile_manager_get_tile (GIMP_DRAWABLE(mask)->tiles, x, y, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
val = tile->data[(y % TILE_HEIGHT) * TILE_WIDTH + (x % TILE_WIDTH)];
tile_unref (tile, FALSE);

View File

@ -1013,7 +1013,7 @@ gradient_calc_shapeburst_angular_factor (double x,
ix = (int) BOUNDS (x, 0, distR.w);
iy = (int) BOUNDS (y, 0, distR.h);
tile = tile_manager_get_tile (distR.tiles, ix, iy, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
value = 1.0 - *(((float *) tile->data) + ((iy % TILE_HEIGHT) * tile->ewidth + (ix % TILE_WIDTH)));
tile_unref (tile, FALSE);
@ -1032,7 +1032,7 @@ gradient_calc_shapeburst_spherical_factor (double x,
ix = (int) BOUNDS (x, 0, distR.w);
iy = (int) BOUNDS (y, 0, distR.h);
tile = tile_manager_get_tile (distR.tiles, ix, iy, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
value = *(((float *) tile->data) + ((iy % TILE_HEIGHT) * tile->ewidth + (ix % TILE_WIDTH)));
value = 1.0 - sin (0.5 * M_PI * value);
tile_unref (tile, FALSE);
@ -1052,7 +1052,7 @@ gradient_calc_shapeburst_dimpled_factor (double x,
ix = (int) BOUNDS (x, 0, distR.w);
iy = (int) BOUNDS (y, 0, distR.h);
tile = tile_manager_get_tile (distR.tiles, ix, iy, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
value = *(((float *) tile->data) + ((iy % TILE_HEIGHT) * tile->ewidth + (ix % TILE_WIDTH)));
value = cos (0.5 * M_PI * value);
tile_unref (tile, FALSE);

View File

@ -166,7 +166,10 @@ invert_invoker (args)
{
int_value = args[0].value.pdb_int;
if (! (gimage = gimage_get_ID (int_value)))
success = FALSE;
{
g_warning ("bleep1\n");
success = FALSE;
}
}
/* the drawable */
if (success)
@ -174,7 +177,10 @@ invert_invoker (args)
int_value = args[1].value.pdb_int;
drawable = drawable_get_ID (int_value);
if (drawable == NULL || gimage != drawable_gimage (drawable))
success = FALSE;
{
g_warning ("bleep2\n");
success = FALSE;
}
}
/* make sure the drawable is not indexed color */
if (success)

View File

@ -615,8 +615,8 @@ undo_pop_image (GImage *gimage,
if (src_tile->valid == TRUE)
{
dest_tile = tile_manager_get_tile (drawable_data (image_undo->drawable), j, i, 0);
tile_ref (src_tile);
tile_ref (dest_tile);
tile_ref2 (src_tile, TRUE);
tile_ref2 (dest_tile, TRUE);
swap_pixels (src_tile->data, dest_tile->data,
(src_tile->ewidth * src_tile->eheight * src_tile->bpp));
tile_unref (src_tile, TRUE);

View File

@ -940,13 +940,13 @@ layer_pick_correlate (layer, x, y)
* the given point is non-zero
*/
tile = tile_manager_get_tile (GIMP_DRAWABLE(layer)->tiles, x, y, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
val = tile->data[tile->bpp * (tile->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH) + 1) - 1];
if (layer->mask)
{
mask_tile = tile_manager_get_tile (GIMP_DRAWABLE(layer->mask)->tiles, x, y, 0);
tile_ref (mask_tile);
tile_ref2 (mask_tile, FALSE);
val = (val * mask_tile->data[mask_tile->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH)]) / 255;
tile_unref (mask_tile, FALSE);
}

View File

@ -2437,7 +2437,7 @@ render_image_tile_fault (RenderInfo *info)
if (!tile)
return NULL;
tile_ref (tile);
tile_ref2 (tile, FALSE);
data = (tile->data +
((info->src_y % TILE_HEIGHT) * tile->ewidth +
(info->src_x % TILE_WIDTH)) * tile->bpp);
@ -2468,7 +2468,7 @@ render_image_tile_fault (RenderInfo *info)
if (!tile)
return tile_buf;
tile_ref (tile);
tile_ref2 (tile, FALSE);
data = (tile->data +
((info->src_y % TILE_HEIGHT) * tile->ewidth +
(x % TILE_WIDTH)) * tile->bpp);

View File

@ -2437,7 +2437,7 @@ render_image_tile_fault (RenderInfo *info)
if (!tile)
return NULL;
tile_ref (tile);
tile_ref2 (tile, FALSE);
data = (tile->data +
((info->src_y % TILE_HEIGHT) * tile->ewidth +
(info->src_x % TILE_WIDTH)) * tile->bpp);
@ -2468,7 +2468,7 @@ render_image_tile_fault (RenderInfo *info)
if (!tile)
return tile_buf;
tile_ref (tile);
tile_ref2 (tile, FALSE);
data = (tile->data +
((info->src_y % TILE_HEIGHT) * tile->ewidth +
(x % TILE_WIDTH)) * tile->bpp);

View File

@ -1263,7 +1263,7 @@ drawable_set_pixel_invoker (Argument *args)
if (success)
{
tile = tile_manager_get_tile (drawable_data (drawable), x, y, 0);
tile_ref (tile);
tile_ref2 (tile, TRUE);
x %= TILE_WIDTH;
y %= TILE_HEIGHT;
@ -1368,7 +1368,7 @@ drawable_get_pixel_invoker (Argument *args)
{
pixel = (unsigned char *) g_new (unsigned char, num_channels);
tile = tile_manager_get_tile (drawable_data (drawable), x, y, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
x %= TILE_WIDTH;
y %= TILE_HEIGHT;

View File

@ -250,7 +250,7 @@ xcf_load_frac_compressed_tile (XcfInfo *info, Tile *tile)
XCFFileInfo = info;
tile_ref (tile);
tile_ref2 (tile, TRUE);
frac_file = OpenInputBitFile (info->fp, &info->cp);
if (frac_file == NULL )
@ -393,7 +393,7 @@ xcf_save_frac_compressed_tile (XcfInfo *info, Tile *tile)
guchar *channelTilesData[MAX_CHANNELS];
gint i, num_channels;
tile_ref (tile);
tile_ref2 (tile, FALSE);
if (!save_initted)
pete_warn ("Using default values for save variables");

View File

@ -128,8 +128,8 @@ ref_tiles (TileManager *src, TileManager *mask, Tile **s_tile, Tile **m_tile,
*s_tile = tile_manager_get_tile (src, x, y, 0);
*m_tile = tile_manager_get_tile (mask, x, y, 0);
tile_ref (*s_tile);
tile_ref (*m_tile);
tile_ref2 (*s_tile, FALSE);
tile_ref2 (*m_tile, TRUE);
*s = (*s_tile)->data + (*s_tile)->bpp * ((*s_tile)->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH));
*m = (*m_tile)->data + (*m_tile)->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH);
@ -215,7 +215,7 @@ find_contiguous_region_helper (PixelRegion *mask, PixelRegion *src,
if (y < 0 || y >= src->h) return;
tile = tile_manager_get_tile (mask->tiles, x, y, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
val = tile->data[tile->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH)];
tile_unref (tile, FALSE);
if (val != 0)
@ -284,7 +284,7 @@ find_contiguous_region (GImage *gimage, GimpDrawable *drawable, int antialias,
tile = tile_manager_get_tile (srcPR.tiles, x, y, 0);
if (tile)
{
tile_ref (tile);
tile_ref2 (tile, FALSE);
start = tile->data + tile->ewidth * tile->bpp * (y % TILE_HEIGHT) +
tile->bpp * (x % TILE_WIDTH);

View File

@ -548,7 +548,7 @@ channel_value (Channel *mask, int x, int y)
}
tile = tile_manager_get_tile (GIMP_DRAWABLE(mask)->tiles, x, y, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
val = tile->data[(y % TILE_HEIGHT) * TILE_WIDTH + (x % TILE_WIDTH)];
tile_unref (tile, FALSE);

View File

@ -166,7 +166,10 @@ invert_invoker (args)
{
int_value = args[0].value.pdb_int;
if (! (gimage = gimage_get_ID (int_value)))
success = FALSE;
{
g_warning ("bleep1\n");
success = FALSE;
}
}
/* the drawable */
if (success)
@ -174,7 +177,10 @@ invert_invoker (args)
int_value = args[1].value.pdb_int;
drawable = drawable_get_ID (int_value);
if (drawable == NULL || gimage != drawable_gimage (drawable))
success = FALSE;
{
g_warning ("bleep2\n");
success = FALSE;
}
}
/* make sure the drawable is not indexed color */
if (success)

View File

@ -940,13 +940,13 @@ layer_pick_correlate (layer, x, y)
* the given point is non-zero
*/
tile = tile_manager_get_tile (GIMP_DRAWABLE(layer)->tiles, x, y, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
val = tile->data[tile->bpp * (tile->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH) + 1) - 1];
if (layer->mask)
{
mask_tile = tile_manager_get_tile (GIMP_DRAWABLE(layer->mask)->tiles, x, y, 0);
tile_ref (mask_tile);
tile_ref2 (mask_tile, FALSE);
val = (val * mask_tile->data[mask_tile->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH)]) / 255;
tile_unref (mask_tile, FALSE);
}

View File

@ -1360,7 +1360,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
return;
}
tile_ref (tile);
tile_ref2 (tile, TRUE);
if (tile_data.use_shm)
memcpy (tile->data, shm_addr, tile_size (tile));
@ -1407,7 +1407,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
tile_data.height = tile->eheight;
tile_data.use_shm = (shm_ID == -1) ? FALSE : TRUE;
tile_ref (tile);
tile_ref2 (tile, FALSE);
if (tile_data.use_shm)
memcpy (shm_addr, tile->data, tile_size (tile));

View File

@ -1360,7 +1360,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
return;
}
tile_ref (tile);
tile_ref2 (tile, TRUE);
if (tile_data.use_shm)
memcpy (tile->data, shm_addr, tile_size (tile));
@ -1407,7 +1407,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
tile_data.height = tile->eheight;
tile_data.use_shm = (shm_ID == -1) ? FALSE : TRUE;
tile_ref (tile);
tile_ref2 (tile, FALSE);
if (tile_data.use_shm)
memcpy (shm_addr, tile->data, tile_size (tile));

View File

@ -2437,7 +2437,7 @@ render_image_tile_fault (RenderInfo *info)
if (!tile)
return NULL;
tile_ref (tile);
tile_ref2 (tile, FALSE);
data = (tile->data +
((info->src_y % TILE_HEIGHT) * tile->ewidth +
(info->src_x % TILE_WIDTH)) * tile->bpp);
@ -2468,7 +2468,7 @@ render_image_tile_fault (RenderInfo *info)
if (!tile)
return tile_buf;
tile_ref (tile);
tile_ref2 (tile, FALSE);
data = (tile->data +
((info->src_y % TILE_HEIGHT) * tile->ewidth +
(x % TILE_WIDTH)) * tile->bpp);

View File

@ -166,7 +166,10 @@ invert_invoker (args)
{
int_value = args[0].value.pdb_int;
if (! (gimage = gimage_get_ID (int_value)))
success = FALSE;
{
g_warning ("bleep1\n");
success = FALSE;
}
}
/* the drawable */
if (success)
@ -174,7 +177,10 @@ invert_invoker (args)
int_value = args[1].value.pdb_int;
drawable = drawable_get_ID (int_value);
if (drawable == NULL || gimage != drawable_gimage (drawable))
success = FALSE;
{
g_warning ("bleep2\n");
success = FALSE;
}
}
/* make sure the drawable is not indexed color */
if (success)

View File

@ -940,13 +940,13 @@ layer_pick_correlate (layer, x, y)
* the given point is non-zero
*/
tile = tile_manager_get_tile (GIMP_DRAWABLE(layer)->tiles, x, y, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
val = tile->data[tile->bpp * (tile->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH) + 1) - 1];
if (layer->mask)
{
mask_tile = tile_manager_get_tile (GIMP_DRAWABLE(layer->mask)->tiles, x, y, 0);
tile_ref (mask_tile);
tile_ref2 (mask_tile, FALSE);
val = (val * mask_tile->data[mask_tile->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH)]) / 255;
tile_unref (mask_tile, FALSE);
}

View File

@ -1360,7 +1360,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
return;
}
tile_ref (tile);
tile_ref2 (tile, TRUE);
if (tile_data.use_shm)
memcpy (tile->data, shm_addr, tile_size (tile));
@ -1407,7 +1407,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
tile_data.height = tile->eheight;
tile_data.use_shm = (shm_ID == -1) ? FALSE : TRUE;
tile_ref (tile);
tile_ref2 (tile, FALSE);
if (tile_data.use_shm)
memcpy (shm_addr, tile->data, tile_size (tile));

View File

@ -22,6 +22,8 @@
#include "gimprc.h"
#include "paint_funcs.h"
#include "boundary.h"
#include "tile_manager.h"
#include "tile_manager_pvt.h" /* For copy-on-write */
#define STD_BUF_SIZE 1021
#define MAXDIFF 195076
@ -2367,6 +2369,7 @@ shade_region (PixelRegion *src,
}
void
copy_region (PixelRegion *src,
PixelRegion *dest)
@ -2376,7 +2379,106 @@ copy_region (PixelRegion *src,
unsigned char * s, * d;
void * pr;
for (pr = pixel_regions_register (2, src, dest); pr != NULL; pr = pixel_regions_process (pr))
/* g_print ("CR: %d,%d (%dx%d) -> %d,%d (%dx%d) :: [%d] [%d]\n",
src->x,
src->y,
src->w,
src->h,
dest->x,
dest->y,
dest->w,
dest->h,
src->tiles->levels->width,
dest->tiles->levels->width);fflush(stdout);*/
/* If we're copying from the same offset in each drawable,
* and the PixelRegions are the same size, and the drawables are
* the same size, we can do a quick'n'cheap Copy-On-Write. Otherwise
* we have to do the copy the old fashioned way.
*
* For COW the PixelRegions must also be of the same dimensions as the
* tilemanager level, for reasons of simplicity. Future work
* may remove this restriction.
*/
#if 0
printf("SPR[ D%p T%p R%d O%d,%d S%d,%d B%d d%d P%d ]\n",
src->data, src->tiles, src->rowstride, src->x,
src->y, src->w, src->h, src->bytes, src->dirty,
src->process_count);
printf("DPR[ D%p T%p R%d O%d,%d S%d,%d B%d d%d P%d ]\n",
dest->data, dest->tiles, dest->rowstride, dest->x,
dest->y, dest->w, dest->h, dest->bytes, dest->dirty,
dest->process_count);
fflush(stdout);
#endif
if ((src->x == dest->x) &&
(src->y == dest->y) &&
(src->w == dest->w) &&
(src->h == dest->h)
&&
(src->tiles) &&
(dest->tiles)
&&
(src->tiles->levels) &&
(dest->tiles->levels) &&
(dest->tiles->levels->width == src->tiles->levels->width) &&
(dest->tiles->levels->height == src->tiles->levels->height)
&&
(src->w == src->tiles->levels->width) &&
(src->h == src->tiles->levels->height)
)
{
Tile *src_tile;
Tile *dest_tile;
gint xstepper,ystepper;
#if defined (TILE_DEBUG)
g_print ("CR: c.o.w. \n");
#endif
/* c.o.w. */
for (ystepper = src->y;
ystepper < (src->y + src->h);
ystepper += TILE_HEIGHT)
{
for (xstepper = src->x;
xstepper < (src->x + src->w);
xstepper += TILE_WIDTH)
{
src_tile = tile_manager_get_tile (src->tiles,
xstepper, ystepper,
0);
dest_tile = tile_manager_get_tile (dest->tiles,
xstepper, ystepper,
0);
if (src_tile && dest_tile)
{
/* printf(" @%p/%p@ ",
tile_find_nonmirroring (src_tile),
tile_find_nonmirroring (dest_tile));*/
tile_mirror (dest_tile, src_tile);
}
}
}
#if defined (TILE_DEBUG)
g_print (src_tile ? "dest " : "src ");
g_print ("CR: END c.o.w. \n");
#endif
return;
}
/* else 'The old-fashioned way.'
*/
for (pr = pixel_regions_register (2, src, dest);
pr != NULL;
pr = pixel_regions_process (pr))
{
pixelwidth = src->w * src->bytes;
s = src->data;
@ -3403,7 +3505,7 @@ shapeburst_region (PixelRegion *srcPR,
while (y >= end)
{
tile = tile_manager_get_tile (srcPR->tiles, x, y, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
tile_data = tile->data + (tile->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH));
boundary = MINIMUM ((y % TILE_HEIGHT), (tile->ewidth - (x % TILE_WIDTH) - 1));
boundary = MINIMUM (boundary, (y - end)) + 1;

View File

@ -640,7 +640,7 @@ paint_core_get_orig_image (paint_core, drawable, x1, y1, x2, y2)
undo_tile = tile_manager_get_tile (undo_tiles, srcPR.x, srcPR.y, 0);
if (undo_tile->valid == TRUE)
{
tile_ref (undo_tile);
tile_ref2 (undo_tile, FALSE);
s = undo_tile->data + srcPR.rowstride * (srcPR.y % TILE_HEIGHT) +
srcPR.bytes * (srcPR.x % TILE_WIDTH);
refd = TRUE;
@ -1193,8 +1193,8 @@ set_undo_tiles (drawable, x, y, w, h)
if (dest_tile->valid == FALSE)
{
src_tile = tile_manager_get_tile (drawable_data (drawable), j, i, 0);
tile_ref (src_tile);
tile_ref (dest_tile);
tile_ref2 (src_tile, FALSE);
tile_ref2 (dest_tile, TRUE);
memcpy (dest_tile->data, src_tile->data,
(src_tile->ewidth * src_tile->eheight * src_tile->bpp));
tile_unref (src_tile, FALSE);
@ -1219,7 +1219,7 @@ set_canvas_tiles (x, y, w, h)
tile = tile_manager_get_tile (canvas_tiles, j, i, 0);
if (tile->valid == FALSE)
{
tile_ref (tile);
tile_ref2 (tile, TRUE);
memset (tile->data, 0, (tile->ewidth * tile->eheight * tile->bpp));
tile_unref (tile, TRUE);
}

View File

@ -22,6 +22,8 @@
#include "gimprc.h"
#include "paint_funcs.h"
#include "boundary.h"
#include "tile_manager.h"
#include "tile_manager_pvt.h" /* For copy-on-write */
#define STD_BUF_SIZE 1021
#define MAXDIFF 195076
@ -2367,6 +2369,7 @@ shade_region (PixelRegion *src,
}
void
copy_region (PixelRegion *src,
PixelRegion *dest)
@ -2376,7 +2379,106 @@ copy_region (PixelRegion *src,
unsigned char * s, * d;
void * pr;
for (pr = pixel_regions_register (2, src, dest); pr != NULL; pr = pixel_regions_process (pr))
/* g_print ("CR: %d,%d (%dx%d) -> %d,%d (%dx%d) :: [%d] [%d]\n",
src->x,
src->y,
src->w,
src->h,
dest->x,
dest->y,
dest->w,
dest->h,
src->tiles->levels->width,
dest->tiles->levels->width);fflush(stdout);*/
/* If we're copying from the same offset in each drawable,
* and the PixelRegions are the same size, and the drawables are
* the same size, we can do a quick'n'cheap Copy-On-Write. Otherwise
* we have to do the copy the old fashioned way.
*
* For COW the PixelRegions must also be of the same dimensions as the
* tilemanager level, for reasons of simplicity. Future work
* may remove this restriction.
*/
#if 0
printf("SPR[ D%p T%p R%d O%d,%d S%d,%d B%d d%d P%d ]\n",
src->data, src->tiles, src->rowstride, src->x,
src->y, src->w, src->h, src->bytes, src->dirty,
src->process_count);
printf("DPR[ D%p T%p R%d O%d,%d S%d,%d B%d d%d P%d ]\n",
dest->data, dest->tiles, dest->rowstride, dest->x,
dest->y, dest->w, dest->h, dest->bytes, dest->dirty,
dest->process_count);
fflush(stdout);
#endif
if ((src->x == dest->x) &&
(src->y == dest->y) &&
(src->w == dest->w) &&
(src->h == dest->h)
&&
(src->tiles) &&
(dest->tiles)
&&
(src->tiles->levels) &&
(dest->tiles->levels) &&
(dest->tiles->levels->width == src->tiles->levels->width) &&
(dest->tiles->levels->height == src->tiles->levels->height)
&&
(src->w == src->tiles->levels->width) &&
(src->h == src->tiles->levels->height)
)
{
Tile *src_tile;
Tile *dest_tile;
gint xstepper,ystepper;
#if defined (TILE_DEBUG)
g_print ("CR: c.o.w. \n");
#endif
/* c.o.w. */
for (ystepper = src->y;
ystepper < (src->y + src->h);
ystepper += TILE_HEIGHT)
{
for (xstepper = src->x;
xstepper < (src->x + src->w);
xstepper += TILE_WIDTH)
{
src_tile = tile_manager_get_tile (src->tiles,
xstepper, ystepper,
0);
dest_tile = tile_manager_get_tile (dest->tiles,
xstepper, ystepper,
0);
if (src_tile && dest_tile)
{
/* printf(" @%p/%p@ ",
tile_find_nonmirroring (src_tile),
tile_find_nonmirroring (dest_tile));*/
tile_mirror (dest_tile, src_tile);
}
}
}
#if defined (TILE_DEBUG)
g_print (src_tile ? "dest " : "src ");
g_print ("CR: END c.o.w. \n");
#endif
return;
}
/* else 'The old-fashioned way.'
*/
for (pr = pixel_regions_register (2, src, dest);
pr != NULL;
pr = pixel_regions_process (pr))
{
pixelwidth = src->w * src->bytes;
s = src->data;
@ -3403,7 +3505,7 @@ shapeburst_region (PixelRegion *srcPR,
while (y >= end)
{
tile = tile_manager_get_tile (srcPR->tiles, x, y, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
tile_data = tile->data + (tile->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH));
boundary = MINIMUM ((y % TILE_HEIGHT), (tile->ewidth - (x % TILE_WIDTH) - 1));
boundary = MINIMUM (boundary, (y - end)) + 1;

View File

@ -124,7 +124,7 @@ pixel_region_get_row (PR, x, y, w, data, subsample)
while (x < end)
{
tile = tile_manager_get_tile (PR->tiles, x, y, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
tile_data = tile->data + tile->bpp * (tile->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH));
boundary = x + (tile->ewidth - (x % TILE_WIDTH));
inc = subsample * tile->bpp;
@ -159,7 +159,7 @@ pixel_region_set_row (PR, x, y, w, data)
while (x < end)
{
tile = tile_manager_get_tile (PR->tiles, x, y, 0);
tile_ref (tile);
tile_ref2 (tile, TRUE);
tile_data = tile->data + tile->bpp * (tile->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH));
boundary = x + (tile->ewidth - (x % TILE_WIDTH));
@ -194,7 +194,7 @@ pixel_region_get_col (PR, x, y, h, data, subsample)
while (y < end)
{
tile = tile_manager_get_tile (PR->tiles, x, y, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
tile_data = tile->data + tile->bpp * (tile->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH));
boundary = y + (tile->eheight - (y % TILE_HEIGHT));
inc = subsample * tile->bpp * tile->ewidth;
@ -230,7 +230,7 @@ pixel_region_set_col (PR, x, y, h, data)
while (y < end)
{
tile = tile_manager_get_tile (PR->tiles, x, y, 0);
tile_ref (tile);
tile_ref2 (tile, TRUE);
tile_data = tile->data + tile->bpp * (tile->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH));
boundary = y + (tile->eheight - (y % TILE_HEIGHT));
inc = tile->bpp * tile->ewidth;
@ -550,7 +550,7 @@ pixel_region_configure (PRH, PRI)
int offx, offy;
tile = tile_manager_get_tile (PRH->PR->tiles, PRH->PR->x, PRH->PR->y, 0);
tile_ref (tile);
tile_ref2 (tile, PRH->PR->dirty);
offx = PRH->PR->x % TILE_WIDTH;
offy = PRH->PR->y % TILE_HEIGHT;

View File

@ -1360,7 +1360,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
return;
}
tile_ref (tile);
tile_ref2 (tile, TRUE);
if (tile_data.use_shm)
memcpy (tile->data, shm_addr, tile_size (tile));
@ -1407,7 +1407,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
tile_data.height = tile->eheight;
tile_data.use_shm = (shm_ID == -1) ? FALSE : TRUE;
tile_ref (tile);
tile_ref2 (tile, FALSE);
if (tile_data.use_shm)
memcpy (shm_addr, tile->data, tile_size (tile));

View File

@ -1360,7 +1360,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
return;
}
tile_ref (tile);
tile_ref2 (tile, TRUE);
if (tile_data.use_shm)
memcpy (tile->data, shm_addr, tile_size (tile));
@ -1407,7 +1407,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
tile_data.height = tile->eheight;
tile_data.use_shm = (shm_ID == -1) ? FALSE : TRUE;
tile_ref (tile);
tile_ref2 (tile, FALSE);
if (tile_data.use_shm)
memcpy (shm_addr, tile->data, tile_size (tile));

View File

@ -1360,7 +1360,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
return;
}
tile_ref (tile);
tile_ref2 (tile, TRUE);
if (tile_data.use_shm)
memcpy (tile->data, shm_addr, tile_size (tile));
@ -1407,7 +1407,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
tile_data.height = tile->eheight;
tile_data.use_shm = (shm_ID == -1) ? FALSE : TRUE;
tile_ref (tile);
tile_ref2 (tile, FALSE);
if (tile_data.use_shm)
memcpy (shm_addr, tile->data, tile_size (tile));

View File

@ -1360,7 +1360,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
return;
}
tile_ref (tile);
tile_ref2 (tile, TRUE);
if (tile_data.use_shm)
memcpy (tile->data, shm_addr, tile_size (tile));
@ -1407,7 +1407,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
tile_data.height = tile->eheight;
tile_data.use_shm = (shm_ID == -1) ? FALSE : TRUE;
tile_ref (tile);
tile_ref2 (tile, FALSE);
if (tile_data.use_shm)
memcpy (shm_addr, tile->data, tile_size (tile));

View File

@ -1360,7 +1360,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
return;
}
tile_ref (tile);
tile_ref2 (tile, TRUE);
if (tile_data.use_shm)
memcpy (tile->data, shm_addr, tile_size (tile));
@ -1407,7 +1407,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
tile_data.height = tile->eheight;
tile_data.use_shm = (shm_ID == -1) ? FALSE : TRUE;
tile_ref (tile);
tile_ref2 (tile, FALSE);
if (tile_data.use_shm)
memcpy (shm_addr, tile->data, tile_size (tile));

View File

@ -1360,7 +1360,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
return;
}
tile_ref (tile);
tile_ref2 (tile, TRUE);
if (tile_data.use_shm)
memcpy (tile->data, shm_addr, tile_size (tile));
@ -1407,7 +1407,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
tile_data.height = tile->eheight;
tile_data.use_shm = (shm_ID == -1) ? FALSE : TRUE;
tile_ref (tile);
tile_ref2 (tile, FALSE);
if (tile_data.use_shm)
memcpy (shm_addr, tile->data, tile_size (tile));

View File

@ -1360,7 +1360,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
return;
}
tile_ref (tile);
tile_ref2 (tile, TRUE);
if (tile_data.use_shm)
memcpy (tile->data, shm_addr, tile_size (tile));
@ -1407,7 +1407,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
tile_data.height = tile->eheight;
tile_data.use_shm = (shm_ID == -1) ? FALSE : TRUE;
tile_ref (tile);
tile_ref2 (tile, FALSE);
if (tile_data.use_shm)
memcpy (shm_addr, tile->data, tile_size (tile));

View File

@ -1360,7 +1360,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
return;
}
tile_ref (tile);
tile_ref2 (tile, TRUE);
if (tile_data.use_shm)
memcpy (tile->data, shm_addr, tile_size (tile));
@ -1407,7 +1407,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
tile_data.height = tile->eheight;
tile_data.use_shm = (shm_ID == -1) ? FALSE : TRUE;
tile_ref (tile);
tile_ref2 (tile, FALSE);
if (tile_data.use_shm)
memcpy (shm_addr, tile->data, tile_size (tile));

View File

@ -1360,7 +1360,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
return;
}
tile_ref (tile);
tile_ref2 (tile, TRUE);
if (tile_data.use_shm)
memcpy (tile->data, shm_addr, tile_size (tile));
@ -1407,7 +1407,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
tile_data.height = tile->eheight;
tile_data.use_shm = (shm_ID == -1) ? FALSE : TRUE;
tile_ref (tile);
tile_ref2 (tile, FALSE);
if (tile_data.use_shm)
memcpy (shm_addr, tile->data, tile_size (tile));

View File

@ -1360,7 +1360,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
return;
}
tile_ref (tile);
tile_ref2 (tile, TRUE);
if (tile_data.use_shm)
memcpy (tile->data, shm_addr, tile_size (tile));
@ -1407,7 +1407,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
tile_data.height = tile->eheight;
tile_data.use_shm = (shm_ID == -1) ? FALSE : TRUE;
tile_ref (tile);
tile_ref2 (tile, FALSE);
if (tile_data.use_shm)
memcpy (shm_addr, tile->data, tile_size (tile));

View File

@ -1360,7 +1360,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
return;
}
tile_ref (tile);
tile_ref2 (tile, TRUE);
if (tile_data.use_shm)
memcpy (tile->data, shm_addr, tile_size (tile));
@ -1407,7 +1407,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
tile_data.height = tile->eheight;
tile_data.use_shm = (shm_ID == -1) ? FALSE : TRUE;
tile_ref (tile);
tile_ref2 (tile, FALSE);
if (tile_data.use_shm)
memcpy (shm_addr, tile->data, tile_size (tile));

View File

@ -1360,7 +1360,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
return;
}
tile_ref (tile);
tile_ref2 (tile, TRUE);
if (tile_data.use_shm)
memcpy (tile->data, shm_addr, tile_size (tile));
@ -1407,7 +1407,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
tile_data.height = tile->eheight;
tile_data.use_shm = (shm_ID == -1) ? FALSE : TRUE;
tile_ref (tile);
tile_ref2 (tile, FALSE);
if (tile_data.use_shm)
memcpy (shm_addr, tile->data, tile_size (tile));

View File

@ -1360,7 +1360,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
return;
}
tile_ref (tile);
tile_ref2 (tile, TRUE);
if (tile_data.use_shm)
memcpy (tile->data, shm_addr, tile_size (tile));
@ -1407,7 +1407,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
tile_data.height = tile->eheight;
tile_data.use_shm = (shm_ID == -1) ? FALSE : TRUE;
tile_ref (tile);
tile_ref2 (tile, FALSE);
if (tile_data.use_shm)
memcpy (shm_addr, tile->data, tile_size (tile));

View File

@ -1360,7 +1360,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
return;
}
tile_ref (tile);
tile_ref2 (tile, TRUE);
if (tile_data.use_shm)
memcpy (tile->data, shm_addr, tile_size (tile));
@ -1407,7 +1407,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
tile_data.height = tile->eheight;
tile_data.use_shm = (shm_ID == -1) ? FALSE : TRUE;
tile_ref (tile);
tile_ref2 (tile, FALSE);
if (tile_data.use_shm)
memcpy (shm_addr, tile->data, tile_size (tile));

View File

@ -1360,7 +1360,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
return;
}
tile_ref (tile);
tile_ref2 (tile, TRUE);
if (tile_data.use_shm)
memcpy (tile->data, shm_addr, tile_size (tile));
@ -1407,7 +1407,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
tile_data.height = tile->eheight;
tile_data.use_shm = (shm_ID == -1) ? FALSE : TRUE;
tile_ref (tile);
tile_ref2 (tile, FALSE);
if (tile_data.use_shm)
memcpy (shm_addr, tile->data, tile_size (tile));

View File

@ -1360,7 +1360,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
return;
}
tile_ref (tile);
tile_ref2 (tile, TRUE);
if (tile_data.use_shm)
memcpy (tile->data, shm_addr, tile_size (tile));
@ -1407,7 +1407,7 @@ plug_in_handle_tile_req (GPTileReq *tile_req)
tile_data.height = tile->eheight;
tile_data.use_shm = (shm_ID == -1) ? FALSE : TRUE;
tile_ref (tile);
tile_ref2 (tile, FALSE);
if (tile_data.use_shm)
memcpy (shm_addr, tile->data, tile_size (tile));

View File

@ -1,8 +1,43 @@
#include <stdio.h>
#include "tile.h"
#include "tile_cache.h"
#include "tile_manager.h"
#include "tile_swap.h"
/* EXPERIMENTAL Copy-On-Write goodies
* by Adam D. Moss
* adam@gimp.org
* adam@foxbox.org
*
*
* C.O.W. Revisions:
*
* 97.10.05 - Initial release
* 97.10.06 - Much faster tile invalidation +
* Better swap interaction (should no longer
* crash GIMP when GIMP swapfile is full).
* 97.10.18 - Very stable now, and even more efficient.
* 98.06.16 - Revised from GIMP 0.99.14 for 1.[01].0 - no
* longer so sure about stability until
* more comprehensive testing is done.
*
*
* MISC TODO:
*
* tile_invalidate: (tile_manager) - don't let a tile become
* invalidated if its ref-count >1, but move it to a delete-on-last-unref
* list instead...
*/
/*
* Define MUCH_TILE_DEBUG in addition to TILE_DEBUG to get
* debugging for every single tile_ref2 and tile_unref (that's
* a lot).
#define MUCH_TILE_DEBUG heckyeah
*/
void
tile_init (Tile *tile,
@ -11,11 +46,13 @@ tile_init (Tile *tile,
tile->ref_count = 0;
tile->dirty = FALSE;
tile->valid = FALSE;
tile->data = NULL;
tile->real_tile_ptr = NULL;
tile->mirrored_by = NULL;
tile->ewidth = TILE_WIDTH;
tile->eheight = TILE_HEIGHT;
tile->bpp = bpp;
tile->tile_num = -1;
tile->data = NULL;
tile->swap_num = 1;
tile->swap_offset = -1;
tile->tm = NULL;
@ -28,57 +65,417 @@ tile_init (Tile *tile,
#endif
}
int tile_ref_count = 0;
void
#if defined (TILE_DEBUG) && defined (__GNUC__)
_tile_ref (Tile *tile, char *func_name)
#else
tile_ref (Tile *tile)
#endif
{
/* While things get moved over to the new tile_ref2
* interface, tile_ref is a wrapper which just says
* 'yes, we'll be dirtying the tile'
*/
#if defined (TILE_DEBUG) && defined (__GNUC__)
printf("COW-Warning: function %s is using obsolete tile_ref interface\n",
func_name);
#endif
#if defined (TILE_DEBUG) && defined (__GNUC__)
_tile_ref2 (tile, TRUE, func_name);
#else
tile_ref2 (tile, TRUE);
#endif
}
gboolean
tile_is_mirroring (Tile *tile)
{
return (tile->real_tile_ptr != NULL);
}
gboolean
tile_is_mirrored (Tile *tile)
{
return (tile->mirrored_by != NULL);
}
gboolean
tile_is_real (Tile *tile)
{
return (tile->real_tile_ptr == NULL);
}
/* Follow the real_tile_ptr links back to the tile which provides
* the real source data for the given tile
*/
Tile *
tile_find_nonmirroring (Tile *tile)
{
if (! tile_is_mirroring (tile))
{
return tile;
}
else
{
return tile_find_nonmirroring (tile->real_tile_ptr);
}
}
/*
*/
Tile *
tile_find_finalmirroring (Tile *tile)
{
if (! tile_is_mirrored (tile))
{
return tile;
}
else
{
return tile_find_finalmirroring (tile->mirrored_by);
}
}
/* Take a mirroring-tile and turn it into a bona fide self-contained
* tile.
*/
void
tile_devirtualize (Tile *tile)
{
Tile *real_tile;
/* Sanity */
if (tile_is_real (tile))
g_error ("Tried to devirtualize a real tile");
#if defined (TILE_DEBUG)
if (tile->ref_count == 0)
g_warning ("Trying to devirtualize a mirroring-tile with no ref_count");
#endif
/* Go find the tile ('real_tile') which owns the real data
*/
real_tile = tile_find_nonmirroring (tile);
/* Sanity */
#if defined (TILE_DEBUG)
if (real_tile->ref_count == 0)
g_warning ("Trying to devirtualize a mirroring-tile whose real_tile has no ref_count");
#endif
if (!real_tile->valid)
g_warning ("Trying to devirtualize a mirroring-tile whose real_tile is !valid");
/* Copy the actual tile data from the real_tile to this tile
*/
tile->data = NULL;
tile_alloc (tile);
/* printf ("{ %dx%d : %d - %p[%p]->%p[%p] }", real_tile->ewidth, real_tile->eheight,
real_tile->bpp, real_tile, real_tile->data, tile, tile->data);
fflush(stdout);*/
memcpy (tile->data, real_tile->data, tile_size(real_tile));
/* 'tile' is now a real tile. */
tile->real_tile_ptr = NULL;
tile->valid = TRUE;
tile_cache_insert(tile);
#if defined (TILE_DEBUG)
g_print ("Tile at %p is now devirtualized.\n", tile);
#endif
}
/* Make this tile self-contained.
*
* The next tile in the linked-list of tiles which are mirroring 'tile'
* is promoted to a real physical tile and unlinked from 'tile'. This
* renders 'tile' safe for dirtying (or destruction).
*/
void
tile_isolate (Tile *tile)
{
Tile *temp_tileptr;
/* Sanity
*/
if (! (tile_is_mirrored (tile) || tile_is_mirroring (tile)))
{
g_warning ("Tried to isolate a tile which is neither a mirror source "
"nor destination");
return;
}
/* This tile is both linked to and linked from? */
if (tile_is_mirrored (tile) && tile_is_mirroring (tile))
{
temp_tileptr = tile->real_tile_ptr;
#if defined (TILE_DEBUG)
g_print ("tile %p: was middle of chain - relinking %p and %p\n",
tile,
temp_tileptr,
tile->mirrored_by);
#endif
tile->mirrored_by->real_tile_ptr = temp_tileptr;
temp_tileptr->mirrored_by = tile->mirrored_by;
tile_ref2 (temp_tileptr, FALSE);
tile_devirtualize (tile);
tile_unref (temp_tileptr, FALSE);
tile->mirrored_by = NULL;
return;
}
/* This tile is mirroring another, but is not mirrored itself? */
if (tile_is_mirroring (tile))
{
temp_tileptr = tile->real_tile_ptr;
#if defined (TILE_DEBUG)
g_print ("tile %p: was end of chain - cauterizing %p\n",
tile,
temp_tileptr);
#endif
/* We stop mirroring the tile which we previously were -
* so reset that tile's mirrored_by pointer.
*/
temp_tileptr->mirrored_by = NULL;
tile_ref2 (temp_tileptr, FALSE);
tile_devirtualize (tile);
tile_unref (temp_tileptr, FALSE);
return;
}
/* This tile is mirrored by another, but is not itself a mirror. */
if (tile_is_mirrored (tile))
{
#if defined (TILE_DEBUG)
g_print ("tile %p: was source of chain - devirtualizing %p\n",
tile,
tile->mirrored_by);
#endif
temp_tileptr = tile->mirrored_by;
tile_ref2 (temp_tileptr, FALSE);
tile_devirtualize (temp_tileptr);
tile_unref (temp_tileptr, FALSE);
/* The tile which was dependant on this one no longer is -
* so we can unref once.
*/
tile_unref (tile, FALSE);
tile->mirrored_by = NULL;
return;
}
}
/* Turns dest_tile into a mirroring-tile which mirrors the given
* src_tile using copy-on-write.
*/
void
tile_mirror (Tile *dest_tile, Tile *src_tile)
{
Tile *finalmirroring;
if (dest_tile == src_tile)
{
g_warning ("TRIED TO MIRROR TILE TO ITSELF");
return;
}
#if defined (TILE_DEBUG)
g_print ("mirroring ");
#endif
if (tile_is_real (dest_tile))
{
#if defined (TILE_DEBUG)
g_print ("TO REAL ");
#endif
tile_invalidate (dest_tile);
}
else
{
tile_invalidate (dest_tile);
}
/* dest_tile->ref_count = 0; */
dest_tile->dirty = FALSE;
dest_tile->valid = FALSE;
dest_tile->data = NULL;
dest_tile->ewidth = src_tile->ewidth;
dest_tile->eheight = src_tile->eheight;
dest_tile->bpp = src_tile->bpp;
dest_tile->tile_num = -1; /* ! */
/*
*/
finalmirroring = tile_find_finalmirroring (src_tile);
dest_tile->real_tile_ptr = finalmirroring;
finalmirroring->mirrored_by = dest_tile;
#if defined (TILE_DEBUG)
g_print ("%p -> %p\n", finalmirroring, dest_tile);
#endif
/* The following should be irrelevant in a mirroring tile - mirroring
* tiles by definition don't have real data of their own, so they can't
* be swapped. They don't have associated TileManagers either, since they
* rely on their mirrored source tile to contain validated data.
*/
dest_tile->swap_num = 1;
dest_tile->swap_offset = -1;
dest_tile->tm = NULL;
}
void
#if defined (TILE_DEBUG) && defined (__GNUC__)
_tile_ref2 (Tile *tile, int dirty, char *func_name)
#else
tile_ref2 (Tile *tile, int dirty)
#endif
{
#ifdef USE_PTHREADS
pthread_mutex_lock(&(tile->mutex));
#endif
/* g_print ("tile_ref: 0x%08x %s\n", tile, func_name); */
#if defined (TILE_DEBUG) && defined (__GNUC__) && defined (MUCH_TILE_DEBUG)
g_print ("tile_ref2: %02d %c %p %s\n", tile->ref_count,
dirty?'d':' ',
tile,
func_name);
#endif
/*g_print ("tile_ref2: %02d %c %p\n", tile->ref_count,
dirty?'d':' ',
tile);*/
/* Increment the global reference count.
*/
tile_ref_count += 1;
/* Increment the reference count.
/* Increment this tile's reference count.
*/
tile->ref_count += 1;
/* If this is the first reference to the tile then
* swap the tile data in from disk. Note: this will
* properly handle the case where the tile data isn't
* on disk.
*/
if (tile->ref_count == 1)
#if defined (TILE_DEBUG)
if (tile_is_mirrored (tile) && dirty)
{
tile_swap_in (tile);
g_print ("Dirtying a mirrored tile: %p.\n", tile);
}
#endif
/* the tile must be clean */
tile->dirty = FALSE;
/*
if (dirty && tile->dirty)
{
g_print ("Not good: Dirtying a write-locked tile: %p.\n", tile);
} */
/* if this is a read-only attachment to a mirroring tile,
* then ref the chain, update the data pointer, and return.
*/
if ((!dirty) && (tile_is_mirroring (tile)))
{
/* ref each of the tiles in the chain, back to the
* 'real' tile which sits at the start.
*/
#if USE_PTHREADS
pthread_mutex_unlock(&(tile->mutex));
#endif
tile_ref2 (tile->real_tile_ptr, FALSE);
tile->data = tile->real_tile_ptr->data;
return;
}
/* Insert the tile into the cache. If the tile is already
* in the cache this will have the affect of "touching"
* the tile.
*/
tile_cache_insert (tile);
/* Call 'tile_manager_validate' if the tile was invalid.
/* dirty, or clean-and-real */
/* Real tile - first reference. */
if (!tile_is_mirroring (tile))
{
/* If this is the first reference to the tile then
* swap the tile data in from disk. Note: this will
* properly handle the case where the tile data isn't
* on disk.
*/
if (tile->ref_count == 1)
{
tile_swap_in (tile);
}
/* Insert the tile into the cache. If the tile is already
* in the cache this will have the affect of "touching"
* the tile.
*/
tile_cache_insert (tile);
}
/* Read/write attachment to a mirrored/ing tile - must be
* thoughtful.
*/
if (dirty)
{
/* Doing a read/write reference to a mirroring/ed tile -
* we'll have to turn the tile into a 'real' tile.
* Then return - we're done.
*/
{
if (tile_is_mirroring (tile) | tile_is_mirrored (tile))
{
#if defined (TILE_DEBUG)
g_print ("r/w to mir'd/ing - isolating: ");
#endif
tile_isolate (tile);
}
}
}
/* Mark the tile as dirty if it's being ref'd as dirtyable.
*/
tile->dirty |= dirty;
#if USE_PTHREADS
pthread_mutex_unlock(&(tile->mutex));
#endif
/* Call 'tile_manager_validate' if the tile was invalid.
*/
if (!tile->valid)
tile_manager_validate ((TileManager*) tile->tm, tile);
}
void
#if defined (TILE_DEBUG) && defined (__GNUC__)
_tile_unref (Tile *tile, int dirty, char *func_name)
@ -89,20 +486,76 @@ tile_unref (Tile *tile, int dirty)
#ifdef USE_PTHREADS
pthread_mutex_lock(&(tile->mutex));
#endif
/* g_print ("tile_unref: 0x%08x %s\n", tile, func_name); */
#if defined (TILE_DEBUG) && defined (__GNUC__) && defined (MUCH_TILE_DEBUG)
g_print ("tile_unref: %02d %c %p %s\n", tile->ref_count,
dirty?'d':' ',
tile, func_name);
#endif
/* g_print ("tile_unref: %02d %c %p\n", tile->ref_count,
dirty?'d':' ',
tile);*/
/* Decrement the global reference count.
*/
tile_ref_count -= 1;
/* Decrement the reference count.
/* Decrement this tile's reference count.
*/
tile->ref_count -= 1;
/* Mark the tile dirty if indicated
*
* commented out - we now dirty on ref, not unref
*/
if (dirty && !tile->dirty)
/*
tile->dirty |= dirty;
*/
#if defined (TILE_DEBUG)
if (tile_is_mirroring (tile))
{
tile->dirty = TRUE;
tile_cache_insert (tile);
/* Mirroring tiles aren't allowed to be submitted as dirty -
* they should have been isolated at ref time.
*/
if (dirty)
g_warning ("Mirroring tile unref'd as dirty.");
}
if (tile_is_mirrored (tile))
{
/* Mirrored tiles aren't allowed to be submitted as dirty -
* they should have been isolated at ref time.
*/
fflush(stdout);
if (dirty)
g_warning ("Mirrored tile unref'd as dirty.");
}
#endif
/* When we unref a mirroring tile, also unref the tile which
* was being mirrored.
*/
if (tile_is_mirroring (tile))
{
/* Mirroring tiles aren't allowed to be submitted as dirty -
* they should have been ref'd as dirty in the first place so we
* could turn them into 'real' tiles.
*/
if (dirty)
{
g_warning ("Bleh, tried to unref a mirroring tile as dirty.");
}
/* Go find the mirrored tile and unref that too. */
#if USE_PTHREADS
pthread_mutex_unlock(&(tile->mutex));
#endif
tile_unref (tile->real_tile_ptr, FALSE);
return;
}
/* If this was the last reference to the tile, then
@ -111,15 +564,21 @@ tile_unref (Tile *tile, int dirty)
if (tile->ref_count == 0)
{
/* Only need to swap out in two cases:
* 1) The tile is dirty
* 2) The tile has never been swapped
* 1) The tile is dirty }
* 2) The tile has never been swapped } and is not mirroring
*/
if (tile->dirty || tile->swap_offset == -1)
if ((tile->dirty || tile->swap_offset == -1)
&& !tile_is_mirroring (tile))
tile_swap_out (tile);
/* Otherwise, just throw out the data--the same stuff is in swap
*/
g_free (tile->data);
tile->data = NULL;
else
{
if (! tile_is_mirroring (tile))
g_free (tile->data);
tile->data = NULL;
}
}
#if USE_PTHREADS
pthread_mutex_unlock(&(tile->mutex));
@ -155,6 +614,128 @@ tile_invalidate (Tile *tile)
#ifdef USE_PTHREADS
pthread_mutex_lock(&(tile->mutex));
#endif
#if defined (TILE_DEBUG)
if (tile->ref_count > 1)
{
g_print (" (inv%p:ref%d) ", tile, tile->ref_count);
}
else
{
g_print (" (inv%p) ", tile);
}
#endif
/* If this tile is mirrored/ing, then maybe isolate it before we
* invalidate it, so that we don't accidentally delete a tile
* whose data is still in use by a mirror.
*/
if (tile_is_mirrored (tile))
{
if (tile_is_mirroring (tile))
{
/* tile is in the middle of a chain. just relink its
* successor and predecessor. that's all we need to do for
* a cleanup.
*/
#if defined (TILE_DEBUG)
g_print ("tile %p: was middle of chain - relinking %p and %p, "
"no isolation\n",
tile,
tile->real_tile_ptr,
tile->mirrored_by);
#endif
tile->mirrored_by->real_tile_ptr = tile->real_tile_ptr;
tile->real_tile_ptr->mirrored_by = tile->mirrored_by;
}
else
{
/* tile is real, and mirrored. Copy its vital statistics to
* its successor in the tile chain, so it can be safely deleted.
*/
#if defined (TILE_DEBUG)
g_print ("tile %p: was source of chain - successor %p swallows soul"
", no isolation\n",
tile,
tile->mirrored_by);
#endif
/* remove 'tile' from cache - but keep the ref_count up
* so that the tile_unref() which tile_cache_flush() calls
* won't invalidate the tile (we'll be doing that ourselves).
*/
tile->ref_count++;
tile_cache_flush (tile);
tile->ref_count--;
/* imbue our successor with our data pointer, validity,
* tile manager, swap_num, swap_offset, and dirty
* flag
*/
tile->mirrored_by->data = tile->data;
tile->data = NULL;
tile->mirrored_by->dirty = tile->dirty;
tile->dirty = FALSE;
tile->mirrored_by->valid = tile->valid;
tile->valid = FALSE;
tile->mirrored_by->swap_num = tile->swap_num;
tile->swap_num = 0;
tile->mirrored_by->swap_offset = tile->swap_offset;
tile->swap_num = -1;
tile->mirrored_by->tm = tile->tm;
tile->tm = NULL;
/* sever links with our successor in both directions.
* our successor is now the new chain source.
*
* also register this newly-born 'real' tile with the tile cache.
*/
tile->mirrored_by->real_tile_ptr = NULL;
tile_cache_insert (tile->mirrored_by);
tile->mirrored_by = NULL;
/* This tile is as clean and invalid as it's going to get.
* Return.
*/
return;
}
}
else /* not mirrored, maybe mirroring */
{
/* for a non-real tile at the end of a chain, the only cleanup
* we have to do for its safe destruction is cauterize the
* flapping mirrored_by pointer of its predecessor on the chain.
*/
if (tile_is_mirroring (tile))
{
#if defined (TILE_DEBUG)
g_print ("tile %p: was end of chain - cauterizing %p, no "
"isolation\n",
tile,
tile->real_tile_ptr);
#endif
tile->real_tile_ptr->mirrored_by = NULL;
}
}
/* If this isn't a 'real' tile then it doesn't need invalidating,
* since it doesn't have any unique data associated with it.
*/
if (!tile_is_real (tile))
{
if (tile->valid)
{
g_warning ("tried to invalidate a mirroring tile which was valid.");
tile->valid = FALSE;
}
return;
}
/* Only 'real' tiles permitted past this point.
*/
/* Invalidate the tile. (Must be valid first).
*/
if (tile->valid)
@ -189,3 +770,5 @@ tile_invalidate (Tile *tile)
pthread_mutex_unlock(&(tile->mutex));
#endif
}

View File

@ -4,7 +4,11 @@
#define TILE_WIDTH 64
#define TILE_HEIGHT 64
/* Uncomment for verbose debugging on copy-on-write logic
#define TILE_DEBUG
*/
#include <sys/types.h>
@ -30,24 +34,38 @@ struct _Tile
guint dirty : 1; /* is the tile dirty? has it been modified? */
guint valid : 1; /* is the tile valid? */
int ewidth; /* the effective width of the tile */
int eheight; /* the effective height of the tile */
/* a tiles effective width and height may be smaller
* (but not larger) than TILE_WIDTH and TILE_HEIGHT.
* this is to handle edge tiles of a drawable.
*/
int bpp; /* the bytes per pixel (1, 2, 3 or 4) */
int tile_num; /* the number of this tile within the drawable */
guchar *data; /* the data for the tile. this may be NULL in which
* case the tile data is on disk.
*/
Tile *real_tile_ptr;/* if this tile's 'data' pointer is just a copy-on-write
* mirror of another's, this is that source tile.
* (real_tile itself can actually be a virtual tile
* too.) This is NULL if this tile is not a virtual
* tile.
*/
Tile *mirrored_by; /* If another tile is mirroring this one, this is
* a pointer to that tile, otherwise this is NULL.
* Note that only one tile may be _directly_ mirroring
* another given tile. This ensures that the graph
* of mirrorings is no more complex than a linked
* list.
*/
int ewidth; /* the effective width of the tile */
int eheight; /* the effective height of the tile */
/* a tile's effective width and height may be smaller
* (but not larger) than TILE_WIDTH and TILE_HEIGHT.
* this is to handle edge tiles of a drawable.
*/
int bpp; /* the bytes per pixel (1, 2, 3 or 4) */
int tile_num; /* the number of this tile within the drawable */
int swap_num; /* the index into the file table of the file to be used
* for swapping. swap_num 1 is always the global swap file.
*/
off_t swap_offset; /* the offset within the swap file of the tile data.
* if the tile data is in memory this will be set to -1.
* if the tile data is in memory this will be set to -1.
*/
void *tm; /* A pointer to the tile manager for this tile.
@ -68,24 +86,37 @@ struct _Tile
void tile_init (Tile *tile,
int bpp);
/*
* c-o-w
*/
void tile_mirror (Tile *dest_tile, Tile *src_tile);
/* Referencing a tile causes the reference count to be incremented.
* If the reference count was previously 0 the tile will will be
* swapped into memory from disk.
*
* tile_ref2 is a new tile-referencing interface through which you
* should register your intent to dirty the tile. This will facilitate
* copy-on-write tile semantics.
*/
#if defined (TILE_DEBUG) && defined (__GNUC__)
#define tile_ref(t) _tile_ref (t, __PRETTY_FUNCTION__)
void _tile_ref (Tile *tile, char *func_name);
#define tile_ref2(t,d) _tile_ref2 (t, d, __PRETTY_FUNCTION__)
void _tile_ref2 (Tile *tile, int dirty, char *func_name);
#else
void tile_ref (Tile *tile);
void tile_ref2 (Tile *tile, int dirty);
#endif
/* Unrefercing a tile causes the reference count to be decremented.
/* Unreferencing a tile causes the reference count to be decremented.
* When the reference count reaches 0 the tile data will be swapped
* out to disk. Note that the tile may be in the tile cache which
* also references the tile causing the reference count not to

View File

@ -1,6 +1,7 @@
#include <gtk/gtkmain.h>
#include <glib.h>
#include "gimprc.h"
#include "tile.h"
#include "tile_cache.h"
#include "tile_swap.h"
#ifdef USE_PTHREADS

View File

@ -339,8 +339,8 @@ tile_manager_update_tile (TileManager *tm,
tile = tile_manager_get (tm, num, level);
tile_ref (tile);
tile_ref (toplevel_tile);
tile_ref2 (tile, TRUE);
tile_ref2 (toplevel_tile, FALSE);
tilew += tilex;
tileh += tiley;

View File

@ -1013,7 +1013,7 @@ gradient_calc_shapeburst_angular_factor (double x,
ix = (int) BOUNDS (x, 0, distR.w);
iy = (int) BOUNDS (y, 0, distR.h);
tile = tile_manager_get_tile (distR.tiles, ix, iy, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
value = 1.0 - *(((float *) tile->data) + ((iy % TILE_HEIGHT) * tile->ewidth + (ix % TILE_WIDTH)));
tile_unref (tile, FALSE);
@ -1032,7 +1032,7 @@ gradient_calc_shapeburst_spherical_factor (double x,
ix = (int) BOUNDS (x, 0, distR.w);
iy = (int) BOUNDS (y, 0, distR.h);
tile = tile_manager_get_tile (distR.tiles, ix, iy, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
value = *(((float *) tile->data) + ((iy % TILE_HEIGHT) * tile->ewidth + (ix % TILE_WIDTH)));
value = 1.0 - sin (0.5 * M_PI * value);
tile_unref (tile, FALSE);
@ -1052,7 +1052,7 @@ gradient_calc_shapeburst_dimpled_factor (double x,
ix = (int) BOUNDS (x, 0, distR.w);
iy = (int) BOUNDS (y, 0, distR.h);
tile = tile_manager_get_tile (distR.tiles, ix, iy, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
value = *(((float *) tile->data) + ((iy % TILE_HEIGHT) * tile->ewidth + (ix % TILE_WIDTH)));
value = cos (0.5 * M_PI * value);
tile_unref (tile, FALSE);

View File

@ -359,7 +359,7 @@ by_color_select_button_release (Tool *tool,
if (x < 0 || y < 0 || x >= gdisp->gimage->width || y >= gdisp->gimage->height)
return;
tile = tile_manager_get_tile (gimage_composite (gdisp->gimage), x, y, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
data = tile->data + tile->bpp * (tile->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH));
gimage_get_color (gdisp->gimage, gimage_composite_type(gdisp->gimage), col, data);
tile_unref (tile, FALSE);
@ -369,7 +369,7 @@ by_color_select_button_release (Tool *tool,
if (x < 0 || y < 0 || x >= drawable_width (drawable) || y >= drawable_height (drawable))
return;
tile = tile_manager_get_tile (drawable_data (drawable), x, y, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
data = tile->data + tile->bpp * (tile->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH));
gimage_get_color (gdisp->gimage, drawable_type(drawable), col, data);
tile_unref (tile, FALSE);
@ -932,7 +932,7 @@ by_color_select_preview_button_press (ByColorDialog *bcd,
if (x < 0 || y < 0 || x >= bcd->gimage->width || y >= bcd->gimage->height)
return;
tile = tile_manager_get_tile (gimage_composite (bcd->gimage), x, y, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
col = tile->data + tile->bpp * (tile->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH));
}
else
@ -945,7 +945,7 @@ by_color_select_preview_button_press (ByColorDialog *bcd,
if (x < 0 || y < 0 || x >= drawable_width (drawable) || y >= drawable_height (drawable))
return;
tile = tile_manager_get_tile (drawable_data (drawable), x, y, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
col = tile->data + tile->bpp * (tile->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH));
}

View File

@ -327,7 +327,7 @@ get_color (GImage *gimage,
if (x >= 0 && y >= 0 && x < width && y < height)
{
tile = tile_manager_get_tile (tiles, x, y, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
src = tile->data + tile->bpp * (tile->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH));
}

View File

@ -128,8 +128,8 @@ ref_tiles (TileManager *src, TileManager *mask, Tile **s_tile, Tile **m_tile,
*s_tile = tile_manager_get_tile (src, x, y, 0);
*m_tile = tile_manager_get_tile (mask, x, y, 0);
tile_ref (*s_tile);
tile_ref (*m_tile);
tile_ref2 (*s_tile, FALSE);
tile_ref2 (*m_tile, TRUE);
*s = (*s_tile)->data + (*s_tile)->bpp * ((*s_tile)->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH));
*m = (*m_tile)->data + (*m_tile)->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH);
@ -215,7 +215,7 @@ find_contiguous_region_helper (PixelRegion *mask, PixelRegion *src,
if (y < 0 || y >= src->h) return;
tile = tile_manager_get_tile (mask->tiles, x, y, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
val = tile->data[tile->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH)];
tile_unref (tile, FALSE);
if (val != 0)
@ -284,7 +284,7 @@ find_contiguous_region (GImage *gimage, GimpDrawable *drawable, int antialias,
tile = tile_manager_get_tile (srcPR.tiles, x, y, 0);
if (tile)
{
tile_ref (tile);
tile_ref2 (tile, FALSE);
start = tile->data + tile->ewidth * tile->bpp * (y % TILE_HEIGHT) +
tile->bpp * (x % TILE_WIDTH);

View File

@ -1013,7 +1013,7 @@ gradient_calc_shapeburst_angular_factor (double x,
ix = (int) BOUNDS (x, 0, distR.w);
iy = (int) BOUNDS (y, 0, distR.h);
tile = tile_manager_get_tile (distR.tiles, ix, iy, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
value = 1.0 - *(((float *) tile->data) + ((iy % TILE_HEIGHT) * tile->ewidth + (ix % TILE_WIDTH)));
tile_unref (tile, FALSE);
@ -1032,7 +1032,7 @@ gradient_calc_shapeburst_spherical_factor (double x,
ix = (int) BOUNDS (x, 0, distR.w);
iy = (int) BOUNDS (y, 0, distR.h);
tile = tile_manager_get_tile (distR.tiles, ix, iy, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
value = *(((float *) tile->data) + ((iy % TILE_HEIGHT) * tile->ewidth + (ix % TILE_WIDTH)));
value = 1.0 - sin (0.5 * M_PI * value);
tile_unref (tile, FALSE);
@ -1052,7 +1052,7 @@ gradient_calc_shapeburst_dimpled_factor (double x,
ix = (int) BOUNDS (x, 0, distR.w);
iy = (int) BOUNDS (y, 0, distR.h);
tile = tile_manager_get_tile (distR.tiles, ix, iy, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
value = *(((float *) tile->data) + ((iy % TILE_HEIGHT) * tile->ewidth + (ix % TILE_WIDTH)));
value = cos (0.5 * M_PI * value);
tile_unref (tile, FALSE);

View File

@ -359,7 +359,7 @@ by_color_select_button_release (Tool *tool,
if (x < 0 || y < 0 || x >= gdisp->gimage->width || y >= gdisp->gimage->height)
return;
tile = tile_manager_get_tile (gimage_composite (gdisp->gimage), x, y, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
data = tile->data + tile->bpp * (tile->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH));
gimage_get_color (gdisp->gimage, gimage_composite_type(gdisp->gimage), col, data);
tile_unref (tile, FALSE);
@ -369,7 +369,7 @@ by_color_select_button_release (Tool *tool,
if (x < 0 || y < 0 || x >= drawable_width (drawable) || y >= drawable_height (drawable))
return;
tile = tile_manager_get_tile (drawable_data (drawable), x, y, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
data = tile->data + tile->bpp * (tile->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH));
gimage_get_color (gdisp->gimage, drawable_type(drawable), col, data);
tile_unref (tile, FALSE);
@ -932,7 +932,7 @@ by_color_select_preview_button_press (ByColorDialog *bcd,
if (x < 0 || y < 0 || x >= bcd->gimage->width || y >= bcd->gimage->height)
return;
tile = tile_manager_get_tile (gimage_composite (bcd->gimage), x, y, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
col = tile->data + tile->bpp * (tile->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH));
}
else
@ -945,7 +945,7 @@ by_color_select_preview_button_press (ByColorDialog *bcd,
if (x < 0 || y < 0 || x >= drawable_width (drawable) || y >= drawable_height (drawable))
return;
tile = tile_manager_get_tile (drawable_data (drawable), x, y, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
col = tile->data + tile->bpp * (tile->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH));
}

View File

@ -128,8 +128,8 @@ ref_tiles (TileManager *src, TileManager *mask, Tile **s_tile, Tile **m_tile,
*s_tile = tile_manager_get_tile (src, x, y, 0);
*m_tile = tile_manager_get_tile (mask, x, y, 0);
tile_ref (*s_tile);
tile_ref (*m_tile);
tile_ref2 (*s_tile, FALSE);
tile_ref2 (*m_tile, TRUE);
*s = (*s_tile)->data + (*s_tile)->bpp * ((*s_tile)->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH));
*m = (*m_tile)->data + (*m_tile)->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH);
@ -215,7 +215,7 @@ find_contiguous_region_helper (PixelRegion *mask, PixelRegion *src,
if (y < 0 || y >= src->h) return;
tile = tile_manager_get_tile (mask->tiles, x, y, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
val = tile->data[tile->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH)];
tile_unref (tile, FALSE);
if (val != 0)
@ -284,7 +284,7 @@ find_contiguous_region (GImage *gimage, GimpDrawable *drawable, int antialias,
tile = tile_manager_get_tile (srcPR.tiles, x, y, 0);
if (tile)
{
tile_ref (tile);
tile_ref2 (tile, FALSE);
start = tile->data + tile->ewidth * tile->bpp * (y % TILE_HEIGHT) +
tile->bpp * (x % TILE_WIDTH);

View File

@ -128,8 +128,8 @@ ref_tiles (TileManager *src, TileManager *mask, Tile **s_tile, Tile **m_tile,
*s_tile = tile_manager_get_tile (src, x, y, 0);
*m_tile = tile_manager_get_tile (mask, x, y, 0);
tile_ref (*s_tile);
tile_ref (*m_tile);
tile_ref2 (*s_tile, FALSE);
tile_ref2 (*m_tile, TRUE);
*s = (*s_tile)->data + (*s_tile)->bpp * ((*s_tile)->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH));
*m = (*m_tile)->data + (*m_tile)->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH);
@ -215,7 +215,7 @@ find_contiguous_region_helper (PixelRegion *mask, PixelRegion *src,
if (y < 0 || y >= src->h) return;
tile = tile_manager_get_tile (mask->tiles, x, y, 0);
tile_ref (tile);
tile_ref2 (tile, FALSE);
val = tile->data[tile->ewidth * (y % TILE_HEIGHT) + (x % TILE_WIDTH)];
tile_unref (tile, FALSE);
if (val != 0)
@ -284,7 +284,7 @@ find_contiguous_region (GImage *gimage, GimpDrawable *drawable, int antialias,
tile = tile_manager_get_tile (srcPR.tiles, x, y, 0);
if (tile)
{
tile_ref (tile);
tile_ref2 (tile, FALSE);
start = tile->data + tile->ewidth * tile->bpp * (y % TILE_HEIGHT) +
tile->bpp * (x % TILE_WIDTH);

View File

@ -640,7 +640,7 @@ paint_core_get_orig_image (paint_core, drawable, x1, y1, x2, y2)
undo_tile = tile_manager_get_tile (undo_tiles, srcPR.x, srcPR.y, 0);
if (undo_tile->valid == TRUE)
{
tile_ref (undo_tile);
tile_ref2 (undo_tile, FALSE);
s = undo_tile->data + srcPR.rowstride * (srcPR.y % TILE_HEIGHT) +
srcPR.bytes * (srcPR.x % TILE_WIDTH);
refd = TRUE;
@ -1193,8 +1193,8 @@ set_undo_tiles (drawable, x, y, w, h)
if (dest_tile->valid == FALSE)
{
src_tile = tile_manager_get_tile (drawable_data (drawable), j, i, 0);
tile_ref (src_tile);
tile_ref (dest_tile);
tile_ref2 (src_tile, FALSE);
tile_ref2 (dest_tile, TRUE);
memcpy (dest_tile->data, src_tile->data,
(src_tile->ewidth * src_tile->eheight * src_tile->bpp));
tile_unref (src_tile, FALSE);
@ -1219,7 +1219,7 @@ set_canvas_tiles (x, y, w, h)
tile = tile_manager_get_tile (canvas_tiles, j, i, 0);
if (tile->valid == FALSE)
{
tile_ref (tile);
tile_ref2 (tile, TRUE);
memset (tile->data, 0, (tile->ewidth * tile->eheight * tile->bpp));
tile_unref (tile, TRUE);
}

View File

@ -61,7 +61,7 @@ static double cubic (double, int, int, int, int);
#define REF_TILE(i,x,y) \
tile[i] = tile_manager_get_tile (float_tiles, x, y, 0); \
tile_ref (tile[i]); \
tile_ref2 (tile[i], FALSE); \
src[i] = tile[i]->data + tile[i]->bpp * (tile[i]->ewidth * ((y) % TILE_HEIGHT) + ((x) % TILE_WIDTH));

View File

@ -61,7 +61,7 @@ static double cubic (double, int, int, int, int);
#define REF_TILE(i,x,y) \
tile[i] = tile_manager_get_tile (float_tiles, x, y, 0); \
tile_ref (tile[i]); \
tile_ref2 (tile[i], FALSE); \
src[i] = tile[i]->data + tile[i]->bpp * (tile[i]->ewidth * ((y) % TILE_HEIGHT) + ((x) % TILE_WIDTH));

View File

@ -615,8 +615,8 @@ undo_pop_image (GImage *gimage,
if (src_tile->valid == TRUE)
{
dest_tile = tile_manager_get_tile (drawable_data (image_undo->drawable), j, i, 0);
tile_ref (src_tile);
tile_ref (dest_tile);
tile_ref2 (src_tile, TRUE);
tile_ref2 (dest_tile, TRUE);
swap_pixels (src_tile->data, dest_tile->data,
(src_tile->ewidth * src_tile->eheight * src_tile->bpp));
tile_unref (src_tile, TRUE);

View File

@ -1088,7 +1088,7 @@ static void
xcf_save_tile (XcfInfo *info,
Tile *tile)
{
tile_ref (tile);
tile_ref2 (tile, FALSE);
info->cp += xcf_write_int8 (info->fp, tile->data, tile_size (tile));
tile_unref (tile, FALSE);
}
@ -1107,7 +1107,7 @@ xcf_save_tile_rle (XcfInfo *info,
int bpp;
int i, j, k;
tile_ref (tile);
tile_ref2 (tile, FALSE);
bpp = tile->bpp;
@ -1850,6 +1850,40 @@ xcf_load_hierarchy (XcfInfo *info,
return TRUE;
}
static void
tile_compare_and_maybe_mirror (Tile *new, Tile *old)
{
if (
(old->ewidth == new->ewidth) &&
(old->eheight == new->eheight) &&
(old->bpp == new->bpp)
)
{
tile_ref2 (new, FALSE);
tile_ref2 (old, FALSE);
if (memcmp (new->data, old->data,
old->ewidth * old->eheight * old->bpp) == 0)
{
#if defined (TILE_DEBUG)
g_print ("M");
#endif
tile_unref (new, FALSE);
tile_unref (old, FALSE);
tile_mirror (new, old);
}
else
{
#if defined (TILE_DEBUG)
g_print (".");
#endif
tile_unref (new, FALSE);
tile_unref (old, FALSE);
}
}
}
static gint
xcf_load_level (XcfInfo *info,
TileManager *tiles,
@ -1862,6 +1896,7 @@ xcf_load_level (XcfInfo *info,
int width;
int height;
int i;
Tile *previous;
info->cp += xcf_read_int32 (info->fp, (guint32*) &width, 1);
info->cp += xcf_read_int32 (info->fp, (guint32*) &height, 1);
@ -1884,6 +1919,10 @@ xcf_load_level (XcfInfo *info,
*/
tile_manager_get (tiles, 0, level_num);
/* Initialise the reference for the in-memory tile-compression
*/
previous = NULL;
ntiles = level->ntile_rows * level->ntile_cols;
for (i = 0; i < ntiles; i++)
{
@ -1920,6 +1959,16 @@ xcf_load_level (XcfInfo *info,
break;
}
/* To potentially save memory, we compare the
* newly-fetched tile against the last one, and
* if they're the same we copy-on-write mirror one against
* the other.
*/
if (previous != NULL)
tile_compare_and_maybe_mirror (&level->tiles[i], previous);
previous = &level->tiles[i];
/* restore the saved position so we'll be ready to
* read the next offset.
*/
@ -1956,7 +2005,7 @@ xcf_load_tile (XcfInfo *info,
#else
tile_ref (tile);
tile_ref2 (tile, TRUE);
info->cp += xcf_read_int8 (info->fp, tile->data, tile_size (tile));
tile_unref (tile, TRUE);
@ -1979,7 +2028,7 @@ xcf_load_tile_rle (XcfInfo *info,
int bpp;
int i, j;
tile_ref (tile);
tile_ref2 (tile, TRUE);
data = tile->data;
bpp = tile->bpp;

View File

@ -1088,7 +1088,7 @@ static void
xcf_save_tile (XcfInfo *info,
Tile *tile)
{
tile_ref (tile);
tile_ref2 (tile, FALSE);
info->cp += xcf_write_int8 (info->fp, tile->data, tile_size (tile));
tile_unref (tile, FALSE);
}
@ -1107,7 +1107,7 @@ xcf_save_tile_rle (XcfInfo *info,
int bpp;
int i, j, k;
tile_ref (tile);
tile_ref2 (tile, FALSE);
bpp = tile->bpp;
@ -1850,6 +1850,40 @@ xcf_load_hierarchy (XcfInfo *info,
return TRUE;
}
static void
tile_compare_and_maybe_mirror (Tile *new, Tile *old)
{
if (
(old->ewidth == new->ewidth) &&
(old->eheight == new->eheight) &&
(old->bpp == new->bpp)
)
{
tile_ref2 (new, FALSE);
tile_ref2 (old, FALSE);
if (memcmp (new->data, old->data,
old->ewidth * old->eheight * old->bpp) == 0)
{
#if defined (TILE_DEBUG)
g_print ("M");
#endif
tile_unref (new, FALSE);
tile_unref (old, FALSE);
tile_mirror (new, old);
}
else
{
#if defined (TILE_DEBUG)
g_print (".");
#endif
tile_unref (new, FALSE);
tile_unref (old, FALSE);
}
}
}
static gint
xcf_load_level (XcfInfo *info,
TileManager *tiles,
@ -1862,6 +1896,7 @@ xcf_load_level (XcfInfo *info,
int width;
int height;
int i;
Tile *previous;
info->cp += xcf_read_int32 (info->fp, (guint32*) &width, 1);
info->cp += xcf_read_int32 (info->fp, (guint32*) &height, 1);
@ -1884,6 +1919,10 @@ xcf_load_level (XcfInfo *info,
*/
tile_manager_get (tiles, 0, level_num);
/* Initialise the reference for the in-memory tile-compression
*/
previous = NULL;
ntiles = level->ntile_rows * level->ntile_cols;
for (i = 0; i < ntiles; i++)
{
@ -1920,6 +1959,16 @@ xcf_load_level (XcfInfo *info,
break;
}
/* To potentially save memory, we compare the
* newly-fetched tile against the last one, and
* if they're the same we copy-on-write mirror one against
* the other.
*/
if (previous != NULL)
tile_compare_and_maybe_mirror (&level->tiles[i], previous);
previous = &level->tiles[i];
/* restore the saved position so we'll be ready to
* read the next offset.
*/
@ -1956,7 +2005,7 @@ xcf_load_tile (XcfInfo *info,
#else
tile_ref (tile);
tile_ref2 (tile, TRUE);
info->cp += xcf_read_int8 (info->fp, tile->data, tile_size (tile));
tile_unref (tile, TRUE);
@ -1979,7 +2028,7 @@ xcf_load_tile_rle (XcfInfo *info,
int bpp;
int i, j;
tile_ref (tile);
tile_ref2 (tile, TRUE);
data = tile->data;
bpp = tile->bpp;