
=====================================================================
                        Image Buffers
=====================================================================

the image buffer code uses a small and specialized inheritance
mechanism.  it's basically a stripped down version of the one
used by the gtkobject system.

image buffers manage a three dimensional block of memory.  the block
is measured in (pixels x pixels x bytes).

the z dimension is described by a Tag.  every image buffer has a Tag
assigned at creation which never changes.  this tag will eventually
be replaced by a mix of hollywood tags and jay's colormodel work.

the x and y dimensions are each described by a pair of integers,
'period' and 'offset'.  these numbers describe the tiling of the memory
in the image.  period is the tile size in that dimension, and offset is
the offset into the first tile where the image begins (ie: partial
left/top tiles).  there may also be partial right/bottom tiles, do the
math on width and height to find out.  partial tiles are always fully
allocated.  ie: all tiles in a buffer have memory chunks which are
identical in size.

since the image tiling structure is fairly arbitrary, a method called
'focus' is used.  this takes a region-of-interest on the image and
focusses on it.  ie: it calculates the actual contiguous area in the
upper left corner of the ROI and returns the boundaries.  the lower
right parts of the roi may be clipped if they rest on another chunk of
memory.  the info is passed back in a GimpPortion structure which is
the primary means of communication with the other routines.

the memory in each tile has the lifecycle of the underlying GimpMemPtr.
see the memmgmt docs for more details.

an addition is the concept of a 'valid' state.  this is introduced
between the alloc and use of the memory.  by default, memory is
validated by memsetting it to zero.  interfaces will exist in the
subclasses to register a custom validator.

the alloc/validate/use cycle is chained together internally so that
using an unallocated tile will automatically alloc and validate it.
these automatic actions can be suppressed if required.



=====================================================================
                         Copy On Write
=====================================================================

there are two basic tasks you want to accomplish with COW.  first, you
might have two images that are the same.  it would be efficient to
share as much of their underlying data as possible.  second, you might
have a tiled image of some sort (even a solid color fill is a tile
size of 1...) and would like to have internal sharing.

there are several things the mapping routines need:

  - the src buffer (with the original tiles)
  - the dst buffer (which will share those tiles if possible)
  - the area on each buffer

src and dst are both GimpBuffers.  they must be of the same subtype
and have the same tiling structure.  currently, identical tiling
structure is sufficient.  however, when i do shm buffers the subtype
rule will be required so it is stated from the beginning.

the areas are both GimpAreas.  the area corners must coincide with
tile corners.  the sizes of the areas do not have to be the same
however.  a smaller dst area will share just the upper left corner of
a larger src area.  a smaller src area will be tiled inside a larger
dst area.  you can color a large area by just sharing a single src
tile filled with that color.

it is not good to map over tiles with outstanding refs.  if you do, it
will complain.  also, the people holding the refs will be most upset
because they have just lost.  it's no problem to map over allocated
memory, just make sure no one is holding refs to it.



=====================================================================
                Comparison to Existing Image Buffers
=====================================================================

this section describes the existing (Dec 14 1998) gimp 1.1 image
memory management as i see it.  the existing interfaces are grouped
and described according to the design principles of the new package.
therefore, the various tile_* header files are thoroughly mixed
together.



Public Interfaces
-----------------

these routines are used throughout gimp.  the new design must provide
public interfaces with equivalent functionality.



  System Initialization
  ---------------------

int
tile_swap_add (char     *filename,
	       SwapFunc  swap_func,
	       gpointer  user_data)

void
tile_swap_exit (void)

      these are only used in app_procs.c (the default swapper) the one
      in xcf.c is commented out.  swapping has been started in the new
      implementation and requires a call to gimp_memory_init().



  Image Creation/Destruction/Attributes
  -------------------------------------

TileManager*
tile_manager_new (int toplevel_width,
		  int toplevel_height,
		  int bpp)
void tile_manager_destroy      (TileManager *tm)
int  tile_manager_level_width  (TileManager *tm) 
int  tile_manager_level_height (TileManager *tm)
int  tile_manager_level_bpp    (TileManager *tm)



      a tile_manager_new equivalent is provided by each buffer
      subclass.  the others routines apply to all buffers and are
      present in buffer.h as gimp_buffer_{delete,width,height,depth}.

      all calls to tile_manager_new will need to be retrofitted
      with a tag in place of bpp.


#define TileManager GimpBuffer

#define tile_manager_new(w,h,t)     gimp_tile_buffer_new ((t),(w),(h),64,64)
#define tile_manager_destroy        gimp_buffer_delete
#define tile_manager_level_width    gimp_buffer_width
#define tile_manager_level_height   gimp_buffer_height
#define tile_manager_level_bpp      gimp_buffer_depth




  Image Data Allocation/Initialization/Accessing
  ----------------------------------------------

      all these routines relate to the image memory lifecycle.  see
      the section on that for a description of the new functionality.

      we'll start by introducing a temporary struct to replace the
      regular Tile.  this holds the same info, but in terms of the
      new system.

typedef struct
{
        GimpBuffer * b;
        GimpPortion p;
        GimpPixelArray a;
        GimpMemStatus s;
} Tile;





Tile*
tile_manager_get_tile (TileManager *tm,
		       int          xpixel,
		       int          ypixel,
		       int          wantread,
		       int          wantwrite);

      this is the gimp_buffer_use method with the associated autoalloc
      and autovalidate.  after the use succeeds, do a gimp_buffer_data
      to get the dimensions of the tile you just used.
      
      each call returns a newly alloced Tile which is freed in 
      tile_release.  the exception is when 'wantread' is false.  here
      we may want to return a static or just fix up callers manually.

Tile *
tile_manager_get_tile (TileManager *tm,
		       int          xpixel,
		       int          ypixel,
		       int          wantread,
		       int          wantwrite)
{
        GimpArea roi;
        Tile * t;

        t = g_new (Tile, 1);
        t->b = tm;

        roi.a.x = xpixel;
        roi.a.y = ypixel;
        roi.b.x = b->width;
        roi.b.y = b->height;
        gimp_buffer_focus (t->b, &t->p, &roi);

        if (wantwrite == TRUE)
                gimp_buffer_use (t->b, &t->p, USE_WRITE);
        else if (wantread == TRUE)
                gimp_buffer_use (t->b, &t->p, USE_READ);
        else
                g_message ("fix me");

        gimp_buffer_data (t->b, &t->p, &t->a);

        return t;
}






void
tile_release (Tile *tile, int dirty)

      this is a combination of release, invalidate and unalloc.  the
      idea of a separate refcount on the tile which destroys the tile
      when it reaches zero now lives in the bowels of the MemMgr.
      image data is freed by the MemMgr when no MemPtr (and hence no
      Tile or anyone else for that matter) refers to it.  the tile
      itself is never shared by anyone, just the image data.  therefore
      we only drop the ref and don't have to worry about the deallocation
      of memory.

      the Tile object is freed here.  dirty is ignored.

void
tile_release (Tile *t, int dirty)
{
        gimp_buffer_use (t->b, &t->p, USE_RELEASE);
        g_free (t);
}







int 
tile_is_valid (Tile *tile)

      replaced by gimp_buffer_query.  this is fairly special purpose
      anyway, used only in gimp_image_invalidate and places that do
      mapping

gint
tile_is_valid (Tile *tile)
{
  if (gimp_buffer_query (tile->b, &tile->p, &tile->s) == FALSE)
    return FALSE;

  return tile->s.valid;
}





void   tile_manager_set_validate_proc (TileManager      *tm,
                                       TileValidateProc  proc)
void   tile_manager_set_user_data     (TileManager *tm,
                                       void        *user_data)
void * tile_manager_get_user_data     (TileManager *tm)

      GimpBuffer has two fields in the base class, vfunc and vdata.  these
      can be manually set and examined.  if there is a vfunc it will be
      invoked in the subclass validate handler.  the vfunc routine will
      be passed the GimpBuffer, so it can look at the vdata field if
      it wants to.

#define tile_manager_set_validate_proc(t,p)   (t)->vfunc = (p)
#define tile_manager_set_user_data(t,d)       (t)->vdata = (d)
#define tile_manager_get_user_data(t)         (t)->vdata




void
tile_manager_map_tile (TileManager *tm,
		       int          xpixel,
		       int          ypixel,
		       Tile        *srctile)

void
tile_manager_map_over_tile (TileManager *tm, Tile *tile, Tile *srctile)

  to be defined.




  Image Data Usage
  ----------------

void * tile_data_pointer (Tile *tile, int xoff, int yoff)
int    tile_ewidth       (Tile *tile)
int    tile_eheight      (Tile *tile)
int    tile_bpp          (Tile *tile)
int    tile_size         (Tile *tile)

       these routines are replaced by the GimpPixelArray structure and
       the gimp_buffer_data() routine.

void *
tile_data_pointer(Tile *t, int x, int y)
{
        guchar * d;

        d = guchar_d (gpa_data (&t->a))
          + gpa_offset (&t->a) \
          + (y * gpa_rowstride (&t->a)) \
          + (x * gpa_pixstride (&t->a));

        return (void*) d;
}

#define tile_bpp(t)      (t)->b->depth;

// technically this is not correct, but the idea of ewidth and eheight
// is broken anyway and i think this will work for all current uses
#define tile_ewidth(t)   (t)->b->x.period
#define tile_eheight(t)  (t)->b->y.period
#define tile_size(t)     ((t)->b->x.period * (t)->b->y.period * (t)->b->depth)



  Unneeded Interfaces
  -------------------

    tile_manager_get_tile_coordinates
      this exists because the initialization interface for
      tilemanagers uses tiles, not coordinates.  image buffers do
      everything in terms of GimpPortion which is in pixels already
      so it's not needed.

    tile_mark_valid
    tile_invalidate_tile
      what good are this routines?  fix gimp_image_invalidate instead.

    tile_manager_get_async
      i haven't thought about this yet.  it doesn;t do anything anyway
      so this can probably be dropped for now.



Protected Interfaces
--------------------

these routines are used internally and shared with xcf.c and plugin.c.
both xcf and plugins arguably require privileged access to the
internal image structure.

    tile_lock
    tile_alloc
    tile_manager_map
    tile_manager_get  (plugins too)
    tile_swap_remove



Private Interfaces
------------------

these routines are used only inside tile*.c.  since they are not
exported to the world, no attempt is made to relate them to public
methods of the new design.  rather, they are listed to complete the
catalog of existing functionality.  the new design should somehow
provide these services as well.

    tile_init
    tile_attach
    tile_detach
    tile_manager_validate
    tile_invalidate
    tile_manager_invalidate_tiles


    tile_swap_in
    tile_swap_in_async
    tile_swap_out
    tile_swap_delete
    tile_swap_compress
    tile_cache_insert
    tile_cache_flush
    tile_cache_set_size
      these will all be internal to MemMgr since memory is now shared,
      not tiles.  they'll be triggered by d_read, d_write, d_release
      primarily.











