A few substantial changes:
- Tiles are initialized after being constructed which makes life simpler for custom tiles which no longer have to have their own constructor that passes Tile's stuff down to it. - Tiles are no longer LRU cached (because we blow through that cache instantly on all but the smallest of scenes), and are now tracked by weak references so that we guarantee that only one instance of a tile is ever in memory. - Added code to track and report memory usage of weak cached tiles as well as "stray" tiles which are created through other means than asking a TileSet for a tile (fringe tiles being the most prolific example). git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@2628 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: ObjectTile.java,v 1.16 2003/02/12 05:33:18 mdb Exp $
|
||||
// $Id: ObjectTile.java,v 1.17 2003/05/31 00:56:38 mdb Exp $
|
||||
|
||||
package com.threerings.media.tile;
|
||||
|
||||
@@ -8,7 +8,6 @@ import java.awt.Point;
|
||||
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
import com.threerings.media.image.Mirage;
|
||||
import com.threerings.util.DirectionUtil;
|
||||
|
||||
/**
|
||||
@@ -28,15 +27,6 @@ import com.threerings.util.DirectionUtil;
|
||||
*/
|
||||
public class ObjectTile extends Tile
|
||||
{
|
||||
/**
|
||||
* Constructs a new object tile with the specified image. The base
|
||||
* width and height should be set before using this tile.
|
||||
*/
|
||||
public ObjectTile (Mirage image)
|
||||
{
|
||||
super(image);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object footprint width in tile units.
|
||||
*/
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
//
|
||||
// $Id: ObjectTileSet.java,v 1.16 2003/05/13 02:16:21 mdb Exp $
|
||||
// $Id: ObjectTileSet.java,v 1.17 2003/05/31 00:56:38 mdb Exp $
|
||||
|
||||
package com.threerings.media.tile;
|
||||
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
import com.threerings.media.image.Mirage;
|
||||
import com.threerings.media.image.Colorization;
|
||||
|
||||
/**
|
||||
@@ -159,27 +158,31 @@ public class ObjectTileSet extends SwissArmyTileSet
|
||||
return zations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates instances of {@link ObjectTile}, which can span more than a
|
||||
* single tile's space in a display.
|
||||
*/
|
||||
protected Tile createTile (int tileIndex, Mirage image)
|
||||
// documentation inherited
|
||||
protected Tile createTile ()
|
||||
{
|
||||
ObjectTile tile = new ObjectTile(image);
|
||||
return new ObjectTile();
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected void initTile (Tile tile, int tileIndex, Colorization[] zations)
|
||||
{
|
||||
super.initTile(tile, tileIndex, zations);
|
||||
|
||||
ObjectTile otile = (ObjectTile)tile;
|
||||
if (_owidths != null) {
|
||||
tile.setBase(_owidths[tileIndex], _oheights[tileIndex]);
|
||||
otile.setBase(_owidths[tileIndex], _oheights[tileIndex]);
|
||||
}
|
||||
if (_xorigins != null) {
|
||||
tile.setOrigin(_xorigins[tileIndex], _yorigins[tileIndex]);
|
||||
otile.setOrigin(_xorigins[tileIndex], _yorigins[tileIndex]);
|
||||
}
|
||||
if (_priorities != null) {
|
||||
tile.setPriority(_priorities[tileIndex]);
|
||||
otile.setPriority(_priorities[tileIndex]);
|
||||
}
|
||||
if (_xspots != null) {
|
||||
tile.setSpot(_xspots[tileIndex], _yspots[tileIndex],
|
||||
_sorients[tileIndex]);
|
||||
otile.setSpot(_xspots[tileIndex], _yspots[tileIndex],
|
||||
_sorients[tileIndex]);
|
||||
}
|
||||
return tile;
|
||||
}
|
||||
|
||||
/** The width (in tile units) of our object tiles. */
|
||||
|
||||
@@ -1,26 +1,71 @@
|
||||
//
|
||||
// $Id: Tile.java,v 1.27 2003/01/17 02:30:50 mdb Exp $
|
||||
// $Id: Tile.java,v 1.28 2003/05/31 00:56:38 mdb Exp $
|
||||
|
||||
package com.threerings.media.tile;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.threerings.media.image.Colorization;
|
||||
import com.threerings.media.image.Mirage;
|
||||
|
||||
/**
|
||||
* A tile represents a single square in a single layer in a scene.
|
||||
*/
|
||||
public class Tile implements Cloneable
|
||||
public class Tile // implements Cloneable
|
||||
{
|
||||
/**
|
||||
* Constructs a tile with the specified image.
|
||||
*
|
||||
* @param image our tile image in mirage form (which is optimized for
|
||||
* screen rendering).
|
||||
*/
|
||||
public Tile (Mirage image)
|
||||
/** Used when caching tiles. */
|
||||
public static class Key
|
||||
{
|
||||
public TileSet tileSet;
|
||||
public int tileIndex;
|
||||
public Colorization[] zations;
|
||||
|
||||
public Key (TileSet tileSet, int tileIndex, Colorization[] zations) {
|
||||
this.tileSet = tileSet;
|
||||
this.tileIndex = tileIndex;
|
||||
this.zations = zations;
|
||||
}
|
||||
|
||||
public boolean equals (Object other) {
|
||||
if (other instanceof Key) {
|
||||
Key okey = (Key)other;
|
||||
return (tileSet == okey.tileSet &&
|
||||
tileIndex == okey.tileIndex &&
|
||||
Arrays.equals(zations, okey.zations));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public int hashCode () {
|
||||
int code = (tileSet == null) ? tileIndex :
|
||||
(tileSet.hashCode() ^ tileIndex);
|
||||
int zcount = (zations == null) ? 0 : zations.length;
|
||||
for (int ii = 0; ii < zcount; ii++) {
|
||||
if (zations[ii] != null) {
|
||||
code ^= zations[ii].hashCode();
|
||||
}
|
||||
}
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
||||
/** The key associated with this tile. */
|
||||
public Key key;
|
||||
|
||||
/**
|
||||
* Configures this tile with its tile image.
|
||||
*/
|
||||
public void setImage (Mirage image)
|
||||
{
|
||||
if (_mirage != null) {
|
||||
_totalTileMemory -= _mirage.getEstimatedMemoryUsage();
|
||||
}
|
||||
_mirage = image;
|
||||
if (_mirage != null) {
|
||||
_totalTileMemory += _mirage.getEstimatedMemoryUsage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,18 +110,18 @@ public class Tile implements Cloneable
|
||||
return _mirage.hitTest(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a shallow copy of this tile object.
|
||||
*/
|
||||
public Object clone ()
|
||||
{
|
||||
try {
|
||||
return (Tile)super.clone();
|
||||
} catch (CloneNotSupportedException cnse) {
|
||||
String errmsg = "All is wrong with the universe: " + cnse;
|
||||
throw new RuntimeException(errmsg);
|
||||
}
|
||||
}
|
||||
// /**
|
||||
// * Creates a shallow copy of this tile object.
|
||||
// */
|
||||
// public Object clone ()
|
||||
// {
|
||||
// try {
|
||||
// return (Tile)super.clone();
|
||||
// } catch (CloneNotSupportedException cnse) {
|
||||
// String errmsg = "All is wrong with the universe: " + cnse;
|
||||
// throw new RuntimeException(errmsg);
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* Return a string representation of this tile.
|
||||
@@ -99,6 +144,17 @@ public class Tile implements Cloneable
|
||||
buf.append(_mirage.getHeight());
|
||||
}
|
||||
|
||||
/** Decrement total tile memory by our value. */
|
||||
protected void finalize ()
|
||||
{
|
||||
if (_mirage != null) {
|
||||
_totalTileMemory -= _mirage.getEstimatedMemoryUsage();
|
||||
}
|
||||
}
|
||||
|
||||
/** Our tileset image. */
|
||||
protected Mirage _mirage;
|
||||
|
||||
/** Used to track total (estimated) memory in use by tiles. */
|
||||
protected static long _totalTileMemory = 0L;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: TileSet.java,v 1.53 2003/05/17 18:39:26 mdb Exp $
|
||||
// $Id: TileSet.java,v 1.54 2003/05/31 00:56:38 mdb Exp $
|
||||
|
||||
package com.threerings.media.tile;
|
||||
|
||||
@@ -8,11 +8,11 @@ import java.awt.Rectangle;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.Serializable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.samskivert.util.LRUHashMap;
|
||||
import com.samskivert.util.RuntimeAdjust;
|
||||
import com.samskivert.util.StringUtil;
|
||||
import com.samskivert.util.Throttle;
|
||||
@@ -191,21 +191,25 @@ public abstract class TileSet
|
||||
*/
|
||||
public Tile getTile (int tileIndex, Colorization[] zations)
|
||||
{
|
||||
TileKey key = new TileKey(this, tileIndex, zations);
|
||||
Tile.Key key = new Tile.Key(this, tileIndex, zations);
|
||||
Tile tile = null;
|
||||
synchronized (_tiles) {
|
||||
tile = (Tile)_tiles.get(key);
|
||||
|
||||
// first look in the active set; if it's in use by anyone or in
|
||||
// the cache, it will be in the active set
|
||||
synchronized (_atiles) {
|
||||
WeakReference wref = (WeakReference)_atiles.get(key);
|
||||
if (wref != null) {
|
||||
tile = (Tile)wref.get();
|
||||
}
|
||||
}
|
||||
|
||||
// if it's not in the active set, it's not in memory; so load it
|
||||
if (tile == null) {
|
||||
tile = createTile(tileIndex, getTileMirage(tileIndex, zations));
|
||||
initTile(tile);
|
||||
synchronized (_tiles) {
|
||||
_tiles.put(key, tile);
|
||||
if (_keySet != null) {
|
||||
_keySet.add(key);
|
||||
} else {
|
||||
Log.warning("What in the fuck is going on?");
|
||||
}
|
||||
tile = createTile();
|
||||
tile.key = key;
|
||||
initTile(tile, tileIndex, zations);
|
||||
synchronized (_atiles) {
|
||||
_atiles.put(key, new WeakReference(tile));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,16 +318,14 @@ public abstract class TileSet
|
||||
protected abstract Rectangle computeTileBounds (int tileIndex);
|
||||
|
||||
/**
|
||||
* Creates a tile for the specified tile index.
|
||||
* Creates a blank tile of the appropriate type for this tileset.
|
||||
*
|
||||
* @param tileIndex the index of the tile to be created.
|
||||
* @param image the tile image in the form of a {@link Mirage}.
|
||||
*
|
||||
* @return a configured tile.
|
||||
* @return a blank tile ready to be populated with its image and
|
||||
* metadata.
|
||||
*/
|
||||
protected Tile createTile (int tileIndex, Mirage image)
|
||||
protected Tile createTile ()
|
||||
{
|
||||
return new Tile(image);
|
||||
return new Tile();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -332,10 +334,13 @@ public abstract class TileSet
|
||||
* call <code>super.initTile()</code>.
|
||||
*
|
||||
* @param tile the tile to initialize.
|
||||
* @param tileIndex the index of the tile.
|
||||
* @param zations the colorizations to be used when generating the
|
||||
* tile image.
|
||||
*/
|
||||
protected void initTile (Tile tile)
|
||||
protected void initTile (Tile tile, int tileIndex, Colorization[] zations)
|
||||
{
|
||||
// nothing for now
|
||||
tile.setImage(getTileMirage(tileIndex, zations));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -348,21 +353,6 @@ public abstract class TileSet
|
||||
return buf.append("]").toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to disable the flushing of cached tiles temporarily. If one
|
||||
* wishes to avoid garbage collection for a short period of time, they
|
||||
* may disable tile flushing during that period. A call to {@link
|
||||
* System#gc} is probably a good idea once flushing is reenabled.
|
||||
*/
|
||||
public static void setCanFlushCache (boolean enabled)
|
||||
{
|
||||
if (_tiles != null) {
|
||||
synchronized (_tiles) {
|
||||
_tiles.setCanFlush(enabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports statistics detailing the image manager cache performance
|
||||
* and the current size of the cached images.
|
||||
@@ -374,20 +364,26 @@ public abstract class TileSet
|
||||
return;
|
||||
}
|
||||
|
||||
// compute our estimated memory usage
|
||||
long size = 0;
|
||||
System.gc();
|
||||
|
||||
int[] eff = null;
|
||||
synchronized (_tiles) {
|
||||
Iterator iter = _tiles.values().iterator();
|
||||
// compute our estimated memory usage
|
||||
long amem = 0;
|
||||
int asize = 0;
|
||||
synchronized (_atiles) {
|
||||
// first total up the active tiles
|
||||
Iterator iter = _atiles.values().iterator();
|
||||
while (iter.hasNext()) {
|
||||
size += ((Tile)iter.next()).getEstimatedMemoryUsage();
|
||||
WeakReference wref = (WeakReference)iter.next();
|
||||
Tile tile = (Tile)wref.get();
|
||||
if (tile != null) {
|
||||
asize++;
|
||||
amem += tile.getEstimatedMemoryUsage();
|
||||
}
|
||||
}
|
||||
eff = _tiles.getTrackedEffectiveness();
|
||||
}
|
||||
Log.info("TileSet LRU [mem=" + (size / 1024) + "k" +
|
||||
", size=" + _tiles.size() + ", hits=" + eff[0] +
|
||||
", misses=" + eff[1] + ", totalKeys=" + _keySet.size() + "].");
|
||||
Log.info("Tile caches [amem=" + (amem / 1024) + "k" +
|
||||
", tmem=" + (Tile._totalTileMemory / 1024) + "k" +
|
||||
", seen=" + _atiles.size() + ", asize=" + asize + "].");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -402,49 +398,6 @@ public abstract class TileSet
|
||||
buf.append(", tileCount=").append(getTileCount());
|
||||
}
|
||||
|
||||
/** Used when caching tiles. */
|
||||
protected static class TileKey
|
||||
{
|
||||
/**
|
||||
* Creates a new tile key.
|
||||
*/
|
||||
public TileKey (TileSet tileSet, int tileIndex, Colorization[] zations)
|
||||
{
|
||||
_tset = tileSet;
|
||||
_tidx = tileIndex;
|
||||
_zations = zations;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public boolean equals (Object other)
|
||||
{
|
||||
if (other instanceof TileKey) {
|
||||
TileKey okey = (TileKey)other;
|
||||
return (_tset == okey._tset && _tidx == okey._tidx &&
|
||||
Arrays.equals(_zations, okey._zations));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public int hashCode ()
|
||||
{
|
||||
int code = _tset.hashCode() ^ _tidx;
|
||||
int zcount = (_zations == null) ? 0 : _zations.length;
|
||||
for (int ii = 0; ii < zcount; ii++) {
|
||||
if (_zations[ii] != null) {
|
||||
code ^= _zations[ii].hashCode();
|
||||
}
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
protected TileSet _tset;
|
||||
protected int _tidx;
|
||||
protected Colorization[] _zations;
|
||||
}
|
||||
|
||||
/** The path to the file containing the tile images. */
|
||||
protected String _imagePath;
|
||||
|
||||
@@ -461,31 +414,9 @@ public abstract class TileSet
|
||||
* a class change (modification of fields, inheritance). */
|
||||
private static final long serialVersionUID = 1;
|
||||
|
||||
/** A weak cache of our tiles. */
|
||||
protected static LRUHashMap _tiles;
|
||||
|
||||
/** The set of all keys we've ever seen. */
|
||||
protected static HashSet _keySet = new HashSet();
|
||||
/** A map containing weak references to all "active" tiles. */
|
||||
protected static HashMap _atiles = new HashMap();
|
||||
|
||||
/** Throttle our cache status logging to once every 30 seconds. */
|
||||
protected static Throttle _cacheStatThrottle = new Throttle(1, 30000L);
|
||||
|
||||
/** Register our tile cache size with the runtime adjustments
|
||||
* framework. */
|
||||
protected static RuntimeAdjust.IntAdjust _cacheSize =
|
||||
new RuntimeAdjust.IntAdjust(
|
||||
"Size (in kb of memory used) of the tile LRU cache " +
|
||||
"[requires restart]", "narya.media.tile.cache_size",
|
||||
MediaPrefs.config, 2048);
|
||||
|
||||
static {
|
||||
int tcsize = _cacheSize.getValue();
|
||||
Log.debug("Creating tile cache [size=" + tcsize + "k].");
|
||||
_tiles = new LRUHashMap(tcsize*1024, new LRUHashMap.ItemSizer() {
|
||||
public int computeSize (Object value) {
|
||||
return (int)((Tile)value).getEstimatedMemoryUsage();
|
||||
}
|
||||
});
|
||||
_tiles.setTracking(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: TrimmedObjectTileSet.java,v 1.12 2003/05/27 18:25:04 mdb Exp $
|
||||
// $Id: TrimmedObjectTileSet.java,v 1.13 2003/05/31 00:56:38 mdb Exp $
|
||||
|
||||
package com.threerings.media.tile;
|
||||
|
||||
@@ -104,19 +104,26 @@ public class TrimmedObjectTileSet extends TileSet
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected Tile createTile (int tileIndex, Mirage tileImage)
|
||||
protected Tile createTile ()
|
||||
{
|
||||
ObjectTile tile = new ObjectTile(tileImage);
|
||||
tile.setBase(_ometrics[tileIndex].width, _ometrics[tileIndex].height);
|
||||
tile.setOrigin(_ometrics[tileIndex].x, _ometrics[tileIndex].y);
|
||||
return new ObjectTile();
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected void initTile (Tile tile, int tileIndex, Colorization[] zations)
|
||||
{
|
||||
super.initTile(tile, tileIndex, zations);
|
||||
|
||||
ObjectTile otile = (ObjectTile)tile;
|
||||
otile.setBase(_ometrics[tileIndex].width, _ometrics[tileIndex].height);
|
||||
otile.setOrigin(_ometrics[tileIndex].x, _ometrics[tileIndex].y);
|
||||
if (_bits != null) {
|
||||
Bits bits = _bits[tileIndex];
|
||||
tile.setPriority(bits.priority);
|
||||
otile.setPriority(bits.priority);
|
||||
if (bits.sorient != -1) {
|
||||
tile.setSpot(bits.xspot, bits.yspot, bits.sorient);
|
||||
otile.setSpot(bits.xspot, bits.yspot, bits.sorient);
|
||||
}
|
||||
}
|
||||
return tile;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: TrimmedTile.java,v 1.5 2003/01/13 22:49:46 mdb Exp $
|
||||
// $Id: TrimmedTile.java,v 1.6 2003/05/31 00:56:38 mdb Exp $
|
||||
|
||||
package com.threerings.media.tile;
|
||||
|
||||
@@ -8,8 +8,6 @@ import java.awt.Rectangle;
|
||||
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
import com.threerings.media.image.Mirage;
|
||||
|
||||
/**
|
||||
* Behaves just like a regular tile, but contains a "trimmed" image which
|
||||
* is one where the source image has been trimmed to the smallest
|
||||
@@ -19,18 +17,14 @@ import com.threerings.media.image.Mirage;
|
||||
public class TrimmedTile extends Tile
|
||||
{
|
||||
/**
|
||||
* Creates a trimmed tile using the supplied tileset image with the
|
||||
* specified bounds and coordinates.
|
||||
* Sets the trimmed bounds of this tile.
|
||||
*
|
||||
* @param tilesetSource the tileset image that contains our trimmed
|
||||
* tile image.
|
||||
* @param tbounds contains the width and height of the
|
||||
* <em>untrimmed</em> tile, but the x and y offset of the
|
||||
* <em>trimmed</em> tile image in the original untrimmed tile image.
|
||||
*/
|
||||
public TrimmedTile (Mirage image, Rectangle tbounds)
|
||||
public void setTrimmedBounds (Rectangle tbounds)
|
||||
{
|
||||
super(image);
|
||||
_tbounds = tbounds;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: TrimmedTileSet.java,v 1.6 2003/01/13 22:49:46 mdb Exp $
|
||||
// $Id: TrimmedTileSet.java,v 1.7 2003/05/31 00:56:38 mdb Exp $
|
||||
|
||||
package com.threerings.media.tile;
|
||||
|
||||
@@ -8,7 +8,7 @@ import java.awt.Rectangle;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import com.threerings.media.image.Mirage;
|
||||
import com.threerings.media.image.Colorization;
|
||||
import com.threerings.media.tile.util.TileSetTrimmer;
|
||||
|
||||
/**
|
||||
@@ -30,9 +30,16 @@ public class TrimmedTileSet extends TileSet
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected Tile createTile (int tileIndex, Mirage image)
|
||||
protected Tile createTile ()
|
||||
{
|
||||
return new TrimmedTile(image, _tbounds[tileIndex]);
|
||||
return new TrimmedTile();
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected void initTile (Tile tile, int tileIndex, Colorization[] zations)
|
||||
{
|
||||
super.initTile(tile, tileIndex, zations);
|
||||
((TrimmedTile)tile).setTrimmedBounds(_tbounds[tileIndex]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user