diff --git a/src/main/java/org/dynmap/flat/FlatMap.java b/src/main/java/org/dynmap/flat/FlatMap.java index 49a27c3a..0cb51f43 100644 --- a/src/main/java/org/dynmap/flat/FlatMap.java +++ b/src/main/java/org/dynmap/flat/FlatMap.java @@ -19,6 +19,7 @@ import org.dynmap.MapManager; import org.dynmap.MapTile; import org.dynmap.MapType; import org.dynmap.debug.Debug; +import org.dynmap.kzedmap.KzedMap; import org.dynmap.MapChunkCache; public class FlatMap extends MapType { @@ -80,7 +81,7 @@ public class FlatMap extends MapType { boolean isnether = (w.getEnvironment() == Environment.NETHER) && (maximumHeight == 127); boolean rendered = false; - BufferedImage im = new BufferedImage(t.size, t.size, BufferedImage.TYPE_INT_RGB); + BufferedImage im = KzedMap.allocateBufferedImage(t.size, t.size); WritableRaster raster = im.getRaster(); int[] pixel = new int[4]; @@ -177,7 +178,7 @@ public class FlatMap extends MapType { } catch (java.lang.NullPointerException e) { Debug.error("Failed to save image (NullPointerException): " + fname.getPath(), e); } - img.flush(); + KzedMap.freeBufferedImage(img); MapManager.mapman.pushUpdate(mtile.getWorld(), new Client.Tile(mtile.getFilename())); } diff --git a/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java b/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java index abe97a29..c3526ccf 100644 --- a/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java +++ b/src/main/java/org/dynmap/kzedmap/DefaultTileRenderer.java @@ -1,7 +1,5 @@ package org.dynmap.kzedmap; -import java.awt.Graphics2D; -import java.awt.RenderingHints; import java.awt.image.BufferedImage; import java.awt.image.WritableRaster; import java.io.File; @@ -62,8 +60,8 @@ public class DefaultTileRenderer implements MapTileRenderer { public boolean render(MapChunkCache cache, KzedMapTile tile, File outputFile) { World world = tile.getWorld(); boolean isnether = (world.getEnvironment() == Environment.NETHER); - BufferedImage im = new BufferedImage(KzedMap.tileWidth, KzedMap.tileHeight, BufferedImage.TYPE_INT_RGB); - BufferedImage zim = new BufferedImage(KzedMap.tileWidth/2, KzedMap.tileHeight/2, BufferedImage.TYPE_INT_RGB); + BufferedImage im = KzedMap.allocateBufferedImage(KzedMap.tileWidth, KzedMap.tileHeight); + BufferedImage zim = KzedMap.allocateBufferedImage(KzedMap.tileWidth/2, KzedMap.tileHeight/2); WritableRaster r = im.getRaster(); WritableRaster zr = zim.getRaster(); boolean isempty = true; @@ -208,9 +206,11 @@ public class DefaultTileRenderer implements MapTileRenderer { } catch (IndexOutOfBoundsException e) { } + boolean zIm_allocated = false; if (zIm == null) { /* create new one */ - zIm = new BufferedImage(KzedMap.tileWidth, KzedMap.tileHeight, BufferedImage.TYPE_INT_RGB); + zIm = KzedMap.allocateBufferedImage(KzedMap.tileWidth, KzedMap.tileHeight); + zIm_allocated = true; Debug.debug("New zoom-out tile created " + zmtile.getFilename()); } else { Debug.debug("Loaded zoom-out tile from " + zmtile.getFilename()); @@ -219,7 +219,7 @@ public class DefaultTileRenderer implements MapTileRenderer { /* blit scaled rendered tile onto zoom-out tile */ WritableRaster zim = zIm.getRaster(); zim.setRect(ox, oy, zimg.getRaster()); - zimg.flush(); + KzedMap.freeBufferedImage(zimg); /* save zoom-out tile */ @@ -231,7 +231,10 @@ public class DefaultTileRenderer implements MapTileRenderer { } catch (java.lang.NullPointerException e) { Debug.error("Failed to save zoom-out tile (NullPointerException): " + zoomFile.getName(), e); } - zIm.flush(); + if(zIm_allocated) + KzedMap.freeBufferedImage(zIm); + else + zIm.flush(); /* Push updates for both files.*/ MapManager.mapman.pushUpdate(mtile.getWorld(), new Client.Tile(mtile.getFilename())); diff --git a/src/main/java/org/dynmap/kzedmap/KzedMap.java b/src/main/java/org/dynmap/kzedmap/KzedMap.java index 0b11697b..44b8f024 100644 --- a/src/main/java/org/dynmap/kzedmap/KzedMap.java +++ b/src/main/java/org/dynmap/kzedmap/KzedMap.java @@ -1,7 +1,10 @@ package org.dynmap.kzedmap; +import java.awt.image.BufferedImage; import java.io.File; import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; import java.util.List; import java.util.logging.Logger; @@ -33,10 +36,17 @@ public class KzedMap extends MapType { public static final int anchorx = 0; public static final int anchory = 127; public static final int anchorz = 0; - + MapTileRenderer[] renderers; ZoomedTileRenderer zoomrenderer; + /* BufferedImage cache - we use the same things a lot... */ + private static Object lock = new Object(); + private static HashMap> imgcache = + new HashMap>(); /* Indexed by resolution - X<<32+Y */ + private static int[] zerobuf = new int[128]; + private static final int CACHE_LIMIT = 10; + public KzedMap(ConfigurationNode configuration) { Log.info("Loading renderers for map '" + getClass().toString() + "'..."); List renderers = configuration.createInstances("renderers", new Class[0], new Object[0]); @@ -246,4 +256,48 @@ public class KzedMap extends MapType { else return y - (y % zTileHeight); } + + /** + * Allocate buffered image from pool, if possible + * @param x - x dimension + * @param y - y dimension + */ + public static BufferedImage allocateBufferedImage(int x, int y) { + BufferedImage img = null; + synchronized(lock) { + long k = (x<<16) + y; + LinkedList ll = imgcache.get(k); + if(ll != null) { + img = ll.poll(); + } + } + if(img != null) { /* Got it - reset it for use */ + if(zerobuf.length < x) + zerobuf = new int[x]; + img.setRGB(0, 0, x, y, zerobuf, 0, 0); + } + else { + img = new BufferedImage(x, y, BufferedImage.TYPE_INT_RGB); + } + return img; + } + + /** + * Return buffered image to pool + */ + public static void freeBufferedImage(BufferedImage img) { + img.flush(); + synchronized(lock) { + long k = (img.getWidth()<<16) + img.getHeight(); + LinkedList ll = imgcache.get(k); + if(ll == null) { + ll = new LinkedList(); + imgcache.put(k, ll); + } + if(ll.size() < CACHE_LIMIT) { + ll.add(img); + img = null; + } + } + } }