mirror of https://github.com/GNOME/gimp.git
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:
parent
ddc557c297
commit
27e90260db
11
ChangeLog
11
ChangeLog
|
@ -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.
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
615
app/base/tile.c
615
app/base/tile.c
|
@ -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,26 +65,362 @@ 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 defined (TILE_DEBUG)
|
||||
if (tile_is_mirrored (tile) && dirty)
|
||||
{
|
||||
g_print ("Dirtying a mirrored tile: %p.\n", tile);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/* 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
|
||||
|
@ -56,9 +429,6 @@ tile_ref (Tile *tile)
|
|||
if (tile->ref_count == 1)
|
||||
{
|
||||
tile_swap_in (tile);
|
||||
|
||||
/* the tile must be clean */
|
||||
tile->dirty = FALSE;
|
||||
}
|
||||
|
||||
/* Insert the tile into the cache. If the tile is already
|
||||
|
@ -66,19 +436,46 @@ tile_ref (Tile *tile)
|
|||
* the tile.
|
||||
*/
|
||||
tile_cache_insert (tile);
|
||||
}
|
||||
|
||||
/* Call 'tile_manager_validate' if the tile was invalid.
|
||||
|
||||
/* 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,16 +564,22 @@ 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
|
||||
*/
|
||||
else
|
||||
{
|
||||
if (! tile_is_mirroring (tile))
|
||||
g_free (tile->data);
|
||||
|
||||
tile->data = NULL;
|
||||
}
|
||||
}
|
||||
#if USE_PTHREADS
|
||||
pthread_mutex_unlock(&(tile->mutex));
|
||||
#endif
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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,19 +34,33 @@ struct _Tile
|
|||
guint dirty : 1; /* is the tile dirty? has it been modified? */
|
||||
guint valid : 1; /* is the tile valid? */
|
||||
|
||||
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 tiles effective width and height may be smaller
|
||||
/* 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 */
|
||||
|
||||
guchar *data; /* the data for the tile. this may be NULL in which
|
||||
* case the tile data is on disk.
|
||||
*/
|
||||
|
||||
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.
|
||||
*/
|
||||
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -166,16 +166,22 @@ invert_invoker (args)
|
|||
{
|
||||
int_value = args[0].value.pdb_int;
|
||||
if (! (gimage = gimage_get_ID (int_value)))
|
||||
{
|
||||
g_warning ("bleep1\n");
|
||||
success = FALSE;
|
||||
}
|
||||
}
|
||||
/* the drawable */
|
||||
if (success)
|
||||
{
|
||||
int_value = args[1].value.pdb_int;
|
||||
drawable = drawable_get_ID (int_value);
|
||||
if (drawable == NULL || gimage != drawable_gimage (drawable))
|
||||
{
|
||||
g_warning ("bleep2\n");
|
||||
success = FALSE;
|
||||
}
|
||||
}
|
||||
/* make sure the drawable is not indexed color */
|
||||
if (success)
|
||||
success = ! drawable_indexed (drawable);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -166,16 +166,22 @@ invert_invoker (args)
|
|||
{
|
||||
int_value = args[0].value.pdb_int;
|
||||
if (! (gimage = gimage_get_ID (int_value)))
|
||||
{
|
||||
g_warning ("bleep1\n");
|
||||
success = FALSE;
|
||||
}
|
||||
}
|
||||
/* the drawable */
|
||||
if (success)
|
||||
{
|
||||
int_value = args[1].value.pdb_int;
|
||||
drawable = drawable_get_ID (int_value);
|
||||
if (drawable == NULL || gimage != drawable_gimage (drawable))
|
||||
{
|
||||
g_warning ("bleep2\n");
|
||||
success = FALSE;
|
||||
}
|
||||
}
|
||||
/* make sure the drawable is not indexed color */
|
||||
if (success)
|
||||
success = ! drawable_indexed (drawable);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -166,16 +166,22 @@ invert_invoker (args)
|
|||
{
|
||||
int_value = args[0].value.pdb_int;
|
||||
if (! (gimage = gimage_get_ID (int_value)))
|
||||
{
|
||||
g_warning ("bleep1\n");
|
||||
success = FALSE;
|
||||
}
|
||||
}
|
||||
/* the drawable */
|
||||
if (success)
|
||||
{
|
||||
int_value = args[1].value.pdb_int;
|
||||
drawable = drawable_get_ID (int_value);
|
||||
if (drawable == NULL || gimage != drawable_gimage (drawable))
|
||||
{
|
||||
g_warning ("bleep2\n");
|
||||
success = FALSE;
|
||||
}
|
||||
}
|
||||
/* make sure the drawable is not indexed color */
|
||||
if (success)
|
||||
success = ! drawable_indexed (drawable);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
|
|
615
app/tile.c
615
app/tile.c
|
@ -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,26 +65,362 @@ 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 defined (TILE_DEBUG)
|
||||
if (tile_is_mirrored (tile) && dirty)
|
||||
{
|
||||
g_print ("Dirtying a mirrored tile: %p.\n", tile);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/* 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
|
||||
|
@ -56,9 +429,6 @@ tile_ref (Tile *tile)
|
|||
if (tile->ref_count == 1)
|
||||
{
|
||||
tile_swap_in (tile);
|
||||
|
||||
/* the tile must be clean */
|
||||
tile->dirty = FALSE;
|
||||
}
|
||||
|
||||
/* Insert the tile into the cache. If the tile is already
|
||||
|
@ -66,19 +436,46 @@ tile_ref (Tile *tile)
|
|||
* the tile.
|
||||
*/
|
||||
tile_cache_insert (tile);
|
||||
}
|
||||
|
||||
/* Call 'tile_manager_validate' if the tile was invalid.
|
||||
|
||||
/* 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,16 +564,22 @@ 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
|
||||
*/
|
||||
else
|
||||
{
|
||||
if (! tile_is_mirroring (tile))
|
||||
g_free (tile->data);
|
||||
|
||||
tile->data = NULL;
|
||||
}
|
||||
}
|
||||
#if USE_PTHREADS
|
||||
pthread_mutex_unlock(&(tile->mutex));
|
||||
#endif
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
|
43
app/tile.h
43
app/tile.h
|
@ -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,19 +34,33 @@ struct _Tile
|
|||
guint dirty : 1; /* is the tile dirty? has it been modified? */
|
||||
guint valid : 1; /* is the tile valid? */
|
||||
|
||||
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 tiles effective width and height may be smaller
|
||||
/* 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 */
|
||||
|
||||
guchar *data; /* the data for the tile. this may be NULL in which
|
||||
* case the tile data is on disk.
|
||||
*/
|
||||
|
||||
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.
|
||||
*/
|
||||
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
57
app/xcf.c
57
app/xcf.c
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue