- handle limiting of unused loaded tiles in limitCache

- remove unused tiles based on distance to map center
This commit is contained in:
Hannes Janetzek 2013-02-04 17:56:47 +01:00
parent 10381ae4ea
commit 7df1ceeff1
2 changed files with 43 additions and 86 deletions

View File

@ -255,6 +255,8 @@ public class GLRenderer implements GLSurfaceView.Renderer {
} }
private static void uploadTileData(MapTile tile) { private static void uploadTileData(MapTile tile) {
TileManager.tilesForUpload--;
if (tile.layers == null) { if (tile.layers == null) {
BufferObject.release(tile.vbo); BufferObject.release(tile.vbo);
tile.vbo = null; tile.vbo = null;

View File

@ -18,7 +18,6 @@ package org.oscim.renderer;
import static org.oscim.generator.JobTile.STATE_LOADING; import static org.oscim.generator.JobTile.STATE_LOADING;
import static org.oscim.generator.JobTile.STATE_NEW_DATA; import static org.oscim.generator.JobTile.STATE_NEW_DATA;
import static org.oscim.generator.JobTile.STATE_NONE; import static org.oscim.generator.JobTile.STATE_NONE;
import static org.oscim.generator.JobTile.STATE_READY;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@ -37,13 +36,17 @@ import android.util.Log;
/** /**
* @author Hannes Janetzek * @author Hannes Janetzek
* @TODO * @TODO
* - prefetching to cache file
* - this class should probably not be in 'renderer' -> tilemap? * - this class should probably not be in 'renderer' -> tilemap?
* - make it general for reuse in tile-overlays * - make it general for reuse in tile-overlays
*/ */
public class TileManager { public class TileManager {
static final String TAG = TileManager.class.getSimpleName(); static final String TAG = TileManager.class.getSimpleName();
private static final int MAX_TILES_IN_QUEUE = 40; // TODO this should depend on the number of
// tiles that could be displayed
private static final int MAX_TILES_IN_QUEUE = 50;
private static final int CACHE_THRESHOLD = 30; private static final int CACHE_THRESHOLD = 30;
private final MapView mMapView; private final MapView mMapView;
@ -63,9 +66,6 @@ public class TileManager {
// new jobs for MapWorkers // new jobs for MapWorkers
private ArrayList<JobTile> mJobs; private ArrayList<JobTile> mJobs;
// tiles that have new data to upload, see passTile()
private ArrayList<MapTile> mTilesLoaded;
private boolean mInitialized; private boolean mInitialized;
// private static MapPosition mCurPosition, mDrawPosition; // private static MapPosition mCurPosition, mDrawPosition;
@ -75,6 +75,8 @@ public class TileManager {
private static int mUpdateCnt; private static int mUpdateCnt;
static Object tilelock = new Object(); static Object tilelock = new Object();
static volatile int tilesForUpload;
private static TileSet mCurrentTiles; private static TileSet mCurrentTiles;
/* package */static TileSet mNewTiles; /* package */static TileSet mNewTiles;
@ -138,10 +140,11 @@ public class TileManager {
mJobs = new ArrayList<JobTile>(); mJobs = new ArrayList<JobTile>();
mTiles = new MapTile[GLRenderer.CACHE_TILES]; mTiles = new MapTile[GLRenderer.CACHE_TILES];
mTilesLoaded = new ArrayList<MapTile>(30);
mTilesSize = 0; mTilesSize = 0;
mUpdateCnt = 0; mUpdateCnt = 0;
tilesForUpload = 0;
mInitialized = false; mInitialized = false;
} }
@ -182,8 +185,6 @@ public class TileManager {
mTilesSize = 0; mTilesSize = 0;
mTilesCount = 0; mTilesCount = 0;
mTilesLoaded.clear();
for (TileSet td : mTileSets) { for (TileSet td : mTileSets) {
Arrays.fill(td.tiles, null); Arrays.fill(td.tiles, null);
td.cnt = 0; td.cnt = 0;
@ -233,10 +234,9 @@ public class TileManager {
mMapView.render(); mMapView.render();
int remove = mTilesCount - GLRenderer.CACHE_TILES; int remove = mTilesCount - GLRenderer.CACHE_TILES;
if (remove > CACHE_THRESHOLD) if (remove > CACHE_THRESHOLD ||
tilesForUpload > (MAX_TILES_IN_QUEUE + 10))
limitCache(mapPosition, remove); limitCache(mapPosition, remove);
limitLoadQueue();
} }
} }
@ -282,9 +282,12 @@ public class TileManager {
return td; return td;
} }
// public void releaseTiles(TileSet tiles) { /**
// * @param tiles ...
// } */
public void releaseTiles(TileSet tiles) {
}
/** /**
* set mNewTiles for the visible tiles and pass it to GLRenderer, add jobs * set mNewTiles for the visible tiles and pass it to GLRenderer, add jobs
@ -403,12 +406,10 @@ public class TileManager {
if (p == null) { if (p == null) {
p = new MapTile(x >> 1, y >> 1, (byte) (zoomLevel - 1)); p = new MapTile(x >> 1, y >> 1, (byte) (zoomLevel - 1));
QuadTree.add(p); QuadTree.add(p);
p.state = STATE_LOADING; p.state = STATE_LOADING;
mJobs.add(p); mJobs.add(p);
} else if (!p.isActive()) { } else if (!p.isActive()) {
//Log.d(TAG, "prefetch parent " + p);
p.state = STATE_LOADING; p.state = STATE_LOADING;
mJobs.add(p); mJobs.add(p);
} }
@ -505,18 +506,11 @@ public class TileManager {
remove--; remove--;
} }
if (remove > 10) { if (remove > 10 || tilesForUpload > MAX_TILES_IN_QUEUE) {
updateTileDistances(tiles, size, mapPosition); updateTileDistances(tiles, size, mapPosition);
// double start, end;
// start = SystemClock.uptimeMillis();
TileDistanceSort.sort(tiles, 0, size); TileDistanceSort.sort(tiles, 0, size);
//end = SystemClock.uptimeMillis();
//Log.d(TAG, "sort took " + (end - start) +
// "limitCache: repacked: " + mTilesSize + " to: " + mTilesCount);
// sorting also repacks the 'sparse' filled array // sorting also repacks the 'sparse' filled array
// so end of mTiles is at mTilesCount now // so end of mTiles is at mTilesCount now
mTilesSize = size = mTilesCount; mTilesSize = size = mTilesCount;
@ -528,66 +522,33 @@ public class TileManager {
Log.d(TAG, "limitCache: tile still locked " + t + " " + t.distance); Log.d(TAG, "limitCache: tile still locked " + t + " " + t.distance);
//mTiles.add(t); //mTiles.add(t);
} else if (t.state == STATE_LOADING) { } else if (t.state == STATE_LOADING) {
// NOTE: if we add tile back and set loading=false, on next // NOTE: when set loading to false the tile could be
// limitCache the tile will be removed. clearTile could // added to load queue again while still processed in
// interfere with TileGenerator. so clear in passTile() // TileGenerator => need tile.cancel flag.
// instead.
// ... no, this does not work either: when set loading to
// false tile could be added to load queue while still
// processed in TileGenerator => need tile.cancel flag.
// t.isLoading = false; // t.isLoading = false;
//mTiles.add(t); //mTiles.add(t);
Log.d(TAG, "limitCache: cancel loading " + t + " " + t.distance); Log.d(TAG, "limitCache: cancel loading " + t + " " + t.distance);
} else { } else {
if (t.state == STATE_NEW_DATA)
tilesForUpload--;
clearTile(t); clearTile(t);
tiles[size - i] = null; tiles[size - i] = null;
} }
} }
}
}
private void limitLoadQueue() { remove = (tilesForUpload - MAX_TILES_IN_QUEUE);
int size = mTilesLoaded.size(); //Log.d(TAG, "cleanup load queue " + tilesForUpload + "/" + remove);
if (size < MAX_TILES_IN_QUEUE) for (int i = 1; i < size && remove > 0; i++) {
return; MapTile t = tiles[size - i];
if (t != null && t.state == STATE_NEW_DATA && !t.isLocked()) {
synchronized (mTilesLoaded) { //Log.d(TAG, "remove from load queue " + t);
// remove tiles already uploaded to vbo clearTile(t);
for (int i = 0; i < size;) { tiles[size - i] = null;
MapTile t = mTilesLoaded.get(i); remove--;
if (t.state == STATE_READY || t.state == STATE_NONE) { tilesForUpload--;
mTilesLoaded.remove(i);
size--;
continue;
} }
i++;
}
if (size < MAX_TILES_IN_QUEUE)
return;
// clear loaded but not used tiles
for (int i = 0, n = size - MAX_TILES_IN_QUEUE / 2; i < n; n--) {
MapTile t = mTilesLoaded.get(i);
if (t.isLocked()) {
i++;
continue;
}
mTilesLoaded.remove(i);
// remove reference from mTiles
MapTile[] tiles = mTiles;
for (int j = 0, m = mTilesSize; j < m; j++) {
if (t == tiles[j]) {
mTiles[j] = null;
break;
}
}
clearTile(t);
} }
} }
} }
@ -595,8 +556,8 @@ public class TileManager {
/** /**
* called from MapWorker Thread when tile is loaded by TileGenerator * called from MapWorker Thread when tile is loaded by TileGenerator
* @param jobTile * @param jobTile
* ... * Tile ready for upload to GL
* @return ... * @return ... caller does not care
*/ */
public synchronized boolean passTile(JobTile jobTile) { public synchronized boolean passTile(JobTile jobTile) {
MapTile tile = (MapTile) jobTile; MapTile tile = (MapTile) jobTile;
@ -617,13 +578,12 @@ public class TileManager {
tile.state = STATE_NEW_DATA; tile.state = STATE_NEW_DATA;
//if (tile.isVisible) // locked means the tile is visible or referenced by
mMapView.render(); // a tile that might be visible.
if (tile.isLocked())
mMapView.render();
synchronized (mTilesLoaded) { tilesForUpload++;
//if (!mTilesLoaded.contains(tile))
mTilesLoaded.add(tile);
}
return true; return true;
} }
@ -633,10 +593,5 @@ public class TileManager {
mWidth = w; mWidth = w;
mHeight = h; mHeight = h;
// size changed does not mean gl surface was recreated
// FIXME iirc this was the case before honeycomb
//if (mWidth > 0 && mHeight > 0)
// mInitialized = true;
} }
} }