home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / libgimp / gimptile.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-06  |  9.6 KB  |  382 lines

  1. /* LIBGIMP - The GIMP Library
  2.  * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
  3.  *
  4.  * gimptile.c
  5.  *
  6.  * This library is free software; you can redistribute it and/or
  7.  * modify it under the terms of the GNU Lesser General Public
  8.  * License as published by the Free Software Foundation; either
  9.  * version 2 of the License, or (at your option) any later version.
  10.  *
  11.  * This library is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14.  * Library General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU Lesser General Public
  17.  * License along with this library; if not, write to the
  18.  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  19.  * Boston, MA 02111-1307, USA.
  20.  */
  21.  
  22. #include <string.h>
  23.  
  24. #include "gimp.h"
  25. #include "gimpprotocol.h"
  26. #include "gimpwire.h"
  27.  
  28.  
  29. /*  This is the percentage of the maximum cache size that 
  30.  *  should be cleared from the cache when an eviction is 
  31.  *  necessary.
  32.  */
  33. #define FREE_QUANTUM 0.1
  34.  
  35. void         gimp_read_expect_msg   (WireMessage *msg,
  36.                      gint         type);
  37.  
  38. static void  gimp_tile_get          (GimpTile    *tile);
  39. static void  gimp_tile_put          (GimpTile    *tile);
  40. static void  gimp_tile_cache_insert (GimpTile    *tile);
  41. static void  gimp_tile_cache_flush  (GimpTile    *tile);
  42. static void  gimp_tile_cache_zorch  (void);
  43. static guint gimp_tile_hash         (GimpTile    *tile);
  44.  
  45.  
  46. gint _gimp_tile_width  = -1;
  47. gint _gimp_tile_height = -1;
  48.  
  49. static GHashTable *tile_hash_table = NULL;
  50. static GList      *tile_list_head  = NULL;
  51. static GList      *tile_list_tail  = NULL;
  52. static gulong      max_tile_size   = 0;
  53. static gulong      cur_cache_size  = 0;
  54. static gulong      max_cache_size  = 0;
  55.  
  56.  
  57. void
  58. gimp_tile_ref (GimpTile *tile)
  59. {
  60.   if (tile)
  61.     {
  62.       tile->ref_count += 1;
  63.  
  64.       if (tile->ref_count == 1)
  65.     {
  66.       gimp_tile_get (tile);
  67.       tile->dirty = FALSE;
  68.     }
  69.  
  70.       gimp_tile_cache_insert (tile);
  71.     }
  72. }
  73.  
  74. void
  75. gimp_tile_ref_zero (GimpTile *tile)
  76. {
  77.   if (tile)
  78.     {
  79.       tile->ref_count += 1;
  80.  
  81.       if (tile->ref_count == 1)
  82.     {
  83.       tile->data = g_new (guchar, tile->ewidth * tile->eheight * tile->bpp);
  84.       memset (tile->data, 0, tile->ewidth * tile->eheight * tile->bpp);
  85.     }
  86.  
  87.       gimp_tile_cache_insert (tile);
  88.     }
  89. }
  90.  
  91. void
  92. gimp_tile_unref (GimpTile *tile,
  93.          gboolean  dirty)
  94. {
  95.   if (tile)
  96.     {
  97.       tile->ref_count -= 1;
  98.       tile->dirty |= dirty;
  99.  
  100.       if (tile->ref_count == 0)
  101.     {
  102.       gimp_tile_flush (tile);
  103.       g_free (tile->data);
  104.       tile->data = NULL;
  105.     }
  106.     }
  107. }
  108.  
  109. void
  110. gimp_tile_flush (GimpTile *tile)
  111. {
  112.   if (tile && tile->data && tile->dirty)
  113.     {
  114.       gimp_tile_put (tile);
  115.       tile->dirty = FALSE;
  116.     }
  117. }
  118.  
  119. void
  120. gimp_tile_cache_size (gulong kilobytes)
  121. {
  122.   max_cache_size = kilobytes * 1024;
  123. }
  124.  
  125. void
  126. gimp_tile_cache_ntiles (gulong ntiles)
  127. {
  128.   gimp_tile_cache_size ((gulong)(ntiles * _gimp_tile_width * _gimp_tile_height * 4 + 1023) / 1024);
  129. }
  130.  
  131. guint
  132. gimp_tile_width (void)
  133. {
  134.   return _gimp_tile_width;
  135. }
  136.  
  137. guint
  138. gimp_tile_height (void)
  139. {
  140.   return _gimp_tile_height;
  141. }
  142.  
  143.  
  144. static void
  145. gimp_tile_get (GimpTile *tile)
  146. {
  147.   extern GIOChannel *_writechannel;
  148.   extern guchar* _shm_addr;
  149.  
  150.   GPTileReq tile_req;
  151.   GPTileData *tile_data;
  152.   WireMessage msg;
  153.  
  154.   tile_req.drawable_ID = tile->drawable->id;
  155.   tile_req.tile_num = tile->tile_num;
  156.   tile_req.shadow = tile->shadow;
  157.   if (!gp_tile_req_write (_writechannel, &tile_req))
  158.     gimp_quit ();
  159.  
  160.   gimp_read_expect_msg(&msg,GP_TILE_DATA);
  161.  
  162.   tile_data = msg.data;
  163.   if ((tile_data->drawable_ID != tile->drawable->id) ||
  164.       (tile_data->tile_num != tile->tile_num) ||
  165.       (tile_data->shadow != tile->shadow) ||
  166.       (tile_data->width != tile->ewidth) ||
  167.       (tile_data->height != tile->eheight) ||
  168.       (tile_data->bpp != tile->bpp))
  169.     {
  170.       g_message ("received tile info did not match computed tile info\n");
  171.       gimp_quit ();
  172.     }
  173.  
  174.   if (tile_data->use_shm)
  175.     {
  176.       tile->data = g_new (guchar, tile->ewidth * tile->eheight * tile->bpp);
  177.       memcpy (tile->data, _shm_addr, tile->ewidth * tile->eheight * tile->bpp);
  178.     }
  179.   else
  180.     {
  181.       tile->data = tile_data->data;
  182.       tile_data->data = NULL;
  183.     }
  184.  
  185.   if (!gp_tile_ack_write (_writechannel))
  186.     gimp_quit ();
  187.  
  188.   wire_destroy (&msg);
  189. }
  190.  
  191. static void
  192. gimp_tile_put (GimpTile *tile)
  193. {
  194.   extern GIOChannel *_writechannel;
  195.   extern guchar *_shm_addr;
  196.  
  197.   GPTileReq tile_req;
  198.   GPTileData tile_data;
  199.   GPTileData *tile_info;
  200.   WireMessage msg;
  201.  
  202.   tile_req.drawable_ID = -1;
  203.   tile_req.tile_num = 0;
  204.   tile_req.shadow = 0;
  205.   if (!gp_tile_req_write (_writechannel, &tile_req))
  206.     gimp_quit ();
  207.  
  208.   gimp_read_expect_msg(&msg,GP_TILE_DATA);
  209.  
  210.   tile_info = msg.data;
  211.  
  212.   tile_data.drawable_ID = tile->drawable->id;
  213.   tile_data.tile_num = tile->tile_num;
  214.   tile_data.shadow = tile->shadow;
  215.   tile_data.bpp = tile->bpp;
  216.   tile_data.width = tile->ewidth;
  217.   tile_data.height = tile->eheight;
  218.   tile_data.use_shm = tile_info->use_shm;
  219.   tile_data.data = NULL;
  220.  
  221.   if (tile_info->use_shm)
  222.     memcpy (_shm_addr, tile->data, tile->ewidth * tile->eheight * tile->bpp);
  223.   else
  224.     tile_data.data = tile->data;
  225.  
  226.   if (!gp_tile_data_write (_writechannel, &tile_data))
  227.     gimp_quit ();
  228.  
  229.   gimp_read_expect_msg(&msg,GP_TILE_ACK);
  230.  
  231.   wire_destroy (&msg);
  232. }
  233.  
  234. /* This function is nearly identical to the function 'tile_cache_insert'
  235.  *  in the file 'tile_cache.c' which is part of the main gimp application.
  236.  */
  237. static void
  238. gimp_tile_cache_insert (GimpTile *tile)
  239. {
  240.   GList *tmp;
  241.  
  242.   if (!tile_hash_table)
  243.     {
  244.       tile_hash_table = g_hash_table_new ((GHashFunc) gimp_tile_hash, NULL);
  245.       max_tile_size = gimp_tile_width () * gimp_tile_height () * 4;
  246.     }
  247.  
  248.   /* First check and see if the tile is already
  249.    *  in the cache. In that case we will simply place
  250.    *  it at the end of the tile list to indicate that
  251.    *  it was the most recently accessed tile.
  252.    */
  253.   tmp = g_hash_table_lookup (tile_hash_table, tile);
  254.  
  255.   if (tmp)
  256.     {
  257.       /* The tile was already in the cache. Place it at
  258.        *  the end of the tile list.
  259.        */
  260.       if (tmp == tile_list_tail)
  261.     tile_list_tail = tile_list_tail->prev;
  262.       tile_list_head = g_list_remove_link (tile_list_head, tmp);
  263.       if (!tile_list_head)
  264.     tile_list_tail = NULL;
  265.       g_list_free (tmp);
  266.  
  267.       /* Remove the old reference to the tiles list node
  268.        *  in the tile hash table.
  269.        */
  270.       g_hash_table_remove (tile_hash_table, tile);
  271.  
  272.       tile_list_tail = g_list_append (tile_list_tail, tile);
  273.       if (!tile_list_head)
  274.     tile_list_head = tile_list_tail;
  275.       tile_list_tail = g_list_last (tile_list_tail);
  276.  
  277.       /* Add the tiles list node to the tile hash table. The
  278.        *  list node is indexed by the tile itself. This makes
  279.        *  for a quick lookup of which list node the tile is in.
  280.        */
  281.       g_hash_table_insert (tile_hash_table, tile, tile_list_tail);
  282.     }
  283.   else
  284.     {
  285.       /* The tile was not in the cache. First check and see
  286.        *  if there is room in the cache. If not then we'll have
  287.        *  to make room first. Note: it might be the case that the
  288.        *  cache is smaller than the size of a tile in which case
  289.        *  it won't be possible to put it in the cache.
  290.        */
  291.       if ((cur_cache_size + max_tile_size) > max_cache_size)
  292.     {
  293.       while (tile_list_head && (cur_cache_size + max_cache_size * FREE_QUANTUM) > max_cache_size)
  294.         gimp_tile_cache_zorch ();
  295.  
  296.       if ((cur_cache_size + max_tile_size) > max_cache_size)
  297.         return;
  298.     }
  299.  
  300.       /* Place the tile at the end of the tile list.
  301.        */
  302.       tile_list_tail = g_list_append (tile_list_tail, tile);
  303.       if (!tile_list_head)
  304.     tile_list_head = tile_list_tail;
  305.       tile_list_tail = g_list_last (tile_list_tail);
  306.  
  307.       /* Add the tiles list node to the tile hash table.
  308.        */
  309.       g_hash_table_insert (tile_hash_table, tile, tile_list_tail);
  310.  
  311.       /* Note the increase in the number of bytes the cache
  312.        *  is referencing.
  313.        */
  314.       cur_cache_size += max_tile_size;
  315.  
  316.       /* Reference the tile so that it won't be returned to
  317.        *  the main gimp application immediately.
  318.        */
  319.       tile->ref_count += 1;
  320.       if (tile->ref_count == 1)
  321.     {
  322.       gimp_tile_get (tile);
  323.       tile->dirty = FALSE;
  324.     }
  325.     }
  326. }
  327.  
  328. static void
  329. gimp_tile_cache_flush (GimpTile *tile)
  330. {
  331.   GList *tmp;
  332.  
  333.   if (!tile_hash_table)
  334.     {
  335.       tile_hash_table = g_hash_table_new ((GHashFunc) gimp_tile_hash, NULL);
  336.       max_tile_size = gimp_tile_width () * gimp_tile_height () * 4;
  337.     }
  338.  
  339.   /* Find where the tile is in the cache.
  340.    */
  341.   tmp = g_hash_table_lookup (tile_hash_table, tile);
  342.  
  343.   if (tmp)
  344.     {
  345.       /* If the tile is in the cache, then remove it from the
  346.        *  tile list.
  347.        */
  348.       if (tmp == tile_list_tail)
  349.         tile_list_tail = tile_list_tail->prev;
  350.       tile_list_head = g_list_remove_link (tile_list_head, tmp);
  351.       if (!tile_list_head)
  352.         tile_list_tail = NULL;
  353.       g_list_free (tmp);
  354.  
  355.       /* Remove the tile from the tile hash table.
  356.        */
  357.       g_hash_table_remove (tile_hash_table, tile);
  358.  
  359.       /* Note the decrease in the number of bytes the cache
  360.        *  is referencing.
  361.        */
  362.       cur_cache_size -= max_tile_size;
  363.  
  364.       /* Unreference the tile.
  365.        */
  366.       gimp_tile_unref (tile, FALSE);
  367.     }
  368. }
  369.  
  370. static void
  371. gimp_tile_cache_zorch (void)
  372. {
  373.   if (tile_list_head)
  374.     gimp_tile_cache_flush ((GimpTile*) tile_list_head->data);
  375. }
  376.  
  377. static guint
  378. gimp_tile_hash (GimpTile *tile)
  379. {
  380.   return (gulong) tile;
  381. }
  382.