fixing MapTile state logic
This commit is contained in:
parent
5f9a9cc909
commit
71715dccd9
@ -16,6 +16,7 @@
|
||||
*/
|
||||
package org.oscim.layers.tile;
|
||||
|
||||
import static org.oscim.layers.tile.MapTile.State.CANCEL;
|
||||
import static org.oscim.layers.tile.MapTile.State.LOADING;
|
||||
import static org.oscim.layers.tile.MapTile.State.NONE;
|
||||
|
||||
@ -37,9 +38,6 @@ public class JobQueue {
|
||||
* the jobs to be added to this queue.
|
||||
*/
|
||||
public synchronized void setJobs(MapTile[] tiles) {
|
||||
for (MapTile t : tiles)
|
||||
t.state = LOADING;
|
||||
|
||||
mJobs = tiles;
|
||||
mCurrentJob = 0;
|
||||
}
|
||||
@ -55,12 +53,12 @@ public class JobQueue {
|
||||
MapTile[] tiles = mJobs;
|
||||
|
||||
for (int i = mCurrentJob, n = mJobs.length; i < n; i++) {
|
||||
|
||||
if (tiles[i].state == LOADING)
|
||||
tiles[i].state = NONE;
|
||||
else
|
||||
log.debug("wrong tile in queue {} {}", tiles[i], tiles[i].state);
|
||||
|
||||
MapTile t = tiles[i];
|
||||
if (t.state(LOADING | CANCEL)) {
|
||||
t.setState(NONE);
|
||||
} else {
|
||||
log.error("Wrong tile in queue {} {}", t, t.state());
|
||||
}
|
||||
tiles[i] = null;
|
||||
}
|
||||
mCurrentJob = 0;
|
||||
|
@ -16,9 +16,13 @@
|
||||
*/
|
||||
package org.oscim.layers.tile;
|
||||
|
||||
import static org.oscim.layers.tile.MapTile.State.CANCEL;
|
||||
import static org.oscim.layers.tile.MapTile.State.DEADBEEF;
|
||||
import static org.oscim.layers.tile.MapTile.State.LOADING;
|
||||
import static org.oscim.layers.tile.MapTile.State.NEW_DATA;
|
||||
import static org.oscim.layers.tile.MapTile.State.NONE;
|
||||
import static org.oscim.layers.tile.MapTile.State.READY;
|
||||
import static org.oscim.layers.tile.MapTile.State.TIMEOUT;
|
||||
|
||||
import org.oscim.core.Tile;
|
||||
import org.oscim.layers.tile.vector.VectorTileLoader;
|
||||
@ -44,34 +48,38 @@ public class MapTile extends Tile {
|
||||
}
|
||||
|
||||
public static final class State {
|
||||
public final static byte NONE = 0;
|
||||
public final static byte NONE = (1 << 0);
|
||||
|
||||
/**
|
||||
* STATE_LOADING means the tile is about to be loaded / loading.
|
||||
* Tile belongs to TileLoader thread.
|
||||
*/
|
||||
public final static byte LOADING = (1 << 0);
|
||||
public final static byte LOADING = (1 << 1);
|
||||
|
||||
/**
|
||||
* STATE_NEW_DATA: tile data is prepared for rendering.
|
||||
* While 'locked' it belongs to GL Thread.
|
||||
*/
|
||||
public final static byte NEW_DATA = (1 << 1);
|
||||
public final static byte NEW_DATA = (1 << 2);
|
||||
|
||||
/**
|
||||
* STATE_READY: tile data is uploaded to GL.
|
||||
* While 'locked' it belongs to GL Thread.
|
||||
*/
|
||||
public final static byte READY = (1 << 2);
|
||||
public final static byte READY = (1 << 3);
|
||||
|
||||
/**
|
||||
* STATE_CANCEL: tile is removed from TileManager,
|
||||
* but may still be processed by TileLoader.
|
||||
*/
|
||||
public final static byte CANCEL = (1 << 3);
|
||||
public final static byte CANCEL = (1 << 4);
|
||||
|
||||
public final static byte DEADBEEF = (1 << 4);
|
||||
public final static byte TIMEOUT = (1 << 5);
|
||||
|
||||
/**
|
||||
* Dont touch if you find some.
|
||||
*/
|
||||
public final static byte DEADBEEF = (1 << 6);
|
||||
}
|
||||
|
||||
public final static int PROXY_CHILD00 = (1 << 0);
|
||||
@ -83,7 +91,7 @@ public class MapTile extends Tile {
|
||||
public final static int PROXY_HOLDER = (1 << 6);
|
||||
|
||||
/** Tile state */
|
||||
byte state;
|
||||
byte state = State.NONE;
|
||||
|
||||
/**
|
||||
* absolute tile coordinates: tileX,Y / Math.pow(2, zoomLevel)
|
||||
@ -176,6 +184,11 @@ public class MapTile extends Tile {
|
||||
* used. This function should only be called through {@link TileManager}
|
||||
*/
|
||||
void lock() {
|
||||
if (state == DEADBEEF) {
|
||||
log.debug("Locking dead tile {}", this);
|
||||
return;
|
||||
}
|
||||
|
||||
if (locked++ > 0)
|
||||
return;
|
||||
|
||||
@ -218,6 +231,12 @@ public class MapTile extends Tile {
|
||||
if (--locked > 0)
|
||||
return;
|
||||
|
||||
if (state == DEADBEEF) {
|
||||
log.debug("Unlock dead tile {}", this);
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
|
||||
TileNode parent = node.parent;
|
||||
if ((proxy & PROXY_PARENT) != 0)
|
||||
parent.item.refs--;
|
||||
@ -259,7 +278,7 @@ public class MapTile extends Tile {
|
||||
data.dispose();
|
||||
data = data.next;
|
||||
}
|
||||
state = DEADBEEF;
|
||||
state = NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -367,4 +386,75 @@ public class MapTile extends Tile {
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
public String state() {
|
||||
switch (state) {
|
||||
case State.NONE:
|
||||
return "None";
|
||||
case State.LOADING:
|
||||
return "Loading";
|
||||
case State.NEW_DATA:
|
||||
return "Data";
|
||||
case State.READY:
|
||||
return "Ready";
|
||||
case State.CANCEL:
|
||||
return "Cancel";
|
||||
case State.TIMEOUT:
|
||||
return "Timeout";
|
||||
case State.DEADBEEF:
|
||||
return "Dead";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void setState(byte newState) {
|
||||
if (state == newState)
|
||||
return;
|
||||
|
||||
switch (newState) {
|
||||
case NONE:
|
||||
if (state(LOADING | CANCEL)) {
|
||||
state = newState;
|
||||
return;
|
||||
}
|
||||
throw new IllegalStateException("None"
|
||||
+ " <= " + state() + " " + this);
|
||||
case LOADING:
|
||||
if (state == NONE) {
|
||||
state = newState;
|
||||
return;
|
||||
}
|
||||
throw new IllegalStateException("Loading"
|
||||
+ " <= " + state() + " " + this);
|
||||
case NEW_DATA:
|
||||
if (state == LOADING) {
|
||||
state = newState;
|
||||
return;
|
||||
}
|
||||
throw new IllegalStateException("NewData"
|
||||
+ " <= " + state() + " " + this);
|
||||
|
||||
case READY:
|
||||
if (state == NEW_DATA) {
|
||||
state = newState;
|
||||
return;
|
||||
}
|
||||
throw new IllegalStateException("Ready"
|
||||
+ " <= " + state() + " " + this);
|
||||
|
||||
case CANCEL:
|
||||
if (state == LOADING) {
|
||||
state = newState;
|
||||
return;
|
||||
}
|
||||
throw new IllegalStateException("Cancel" +
|
||||
" <= " + state() + " " + this);
|
||||
case TIMEOUT:
|
||||
// TODO
|
||||
break;
|
||||
case DEADBEEF:
|
||||
state = newState;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import static org.oscim.layers.tile.MapTile.State.CANCEL;
|
||||
import static org.oscim.layers.tile.MapTile.State.DEADBEEF;
|
||||
import static org.oscim.layers.tile.MapTile.State.LOADING;
|
||||
import static org.oscim.layers.tile.MapTile.State.NEW_DATA;
|
||||
import static org.oscim.layers.tile.MapTile.State.NONE;
|
||||
import static org.oscim.layers.tile.MapTile.State.READY;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -65,7 +66,6 @@ public class TileManager {
|
||||
/** cache limit threshold */
|
||||
private static final int CACHE_THRESHOLD = 25;
|
||||
private static final int CACHE_CLEAR_THRESHOLD = 10;
|
||||
private static final int QUEUE_CLEAR_THRESHOLD = 10;
|
||||
|
||||
private final Map mMap;
|
||||
private final Viewport mViewport;
|
||||
@ -77,10 +77,10 @@ public class TileManager {
|
||||
private int mTilesCount;
|
||||
|
||||
/** current end position in mTiles */
|
||||
private int mTilesSize;
|
||||
private int mTilesEnd;
|
||||
|
||||
/** counter for tiles with new data not yet loaded to GL */
|
||||
private int mTilesForUpload;
|
||||
private int mTilesToUpload;
|
||||
|
||||
/** new tile jobs for MapWorkers */
|
||||
private final ArrayList<MapTile> mJobs;
|
||||
@ -112,7 +112,7 @@ public class TileManager {
|
||||
@Override
|
||||
public void removeItem(MapTile t) {
|
||||
if (t.node == null)
|
||||
throw new IllegalStateException("already removed: " + t);
|
||||
throw new IllegalStateException("Already removed: " + t);
|
||||
|
||||
super.remove(t.node);
|
||||
t.node.item = null;
|
||||
@ -149,8 +149,8 @@ public class TileManager {
|
||||
mJobs = new ArrayList<MapTile>();
|
||||
mTiles = new MapTile[mCacheLimit];
|
||||
|
||||
mTilesSize = 0;
|
||||
mTilesForUpload = 0;
|
||||
mTilesEnd = 0;
|
||||
mTilesToUpload = 0;
|
||||
mUpdateSerial = 0;
|
||||
}
|
||||
|
||||
@ -165,17 +165,28 @@ public class TileManager {
|
||||
}
|
||||
|
||||
public void init() {
|
||||
if (mCurrentTiles != null)
|
||||
mCurrentTiles.releaseTiles();
|
||||
/* pass VBOs and VertexItems back to pools */
|
||||
for (int i = 0; i < mTilesSize; i++) {
|
||||
if (mTiles[i] == null)
|
||||
for (int i = 0; i < mTilesEnd; i++) {
|
||||
MapTile t = mTiles[i];
|
||||
if (t == null)
|
||||
continue;
|
||||
removeFromCache(mTiles[i]);
|
||||
mTiles[i].state = CANCEL;
|
||||
|
||||
if (!t.isLocked()) {
|
||||
//log.debug("init clear {} {}", t, t.state());
|
||||
t.clear();
|
||||
}
|
||||
mIndex.removeItem(t);
|
||||
|
||||
/* in case the tile is still loading:
|
||||
* clear when returned from loader */
|
||||
t.setState(DEADBEEF);
|
||||
}
|
||||
|
||||
/* clear references to cached MapTiles */
|
||||
Arrays.fill(mTiles, null);
|
||||
mTilesSize = 0;
|
||||
mTilesEnd = 0;
|
||||
mTilesCount = 0;
|
||||
|
||||
/* set up TileSet large enough to hold current tiles */
|
||||
@ -198,6 +209,7 @@ public class TileManager {
|
||||
public boolean update(MapPosition pos) {
|
||||
|
||||
// FIXME cant expect init to be called otherwise
|
||||
// Should use some onLayerAttached callback instead.
|
||||
if (mNewTiles == null || mNewTiles.tiles.length == 0) {
|
||||
mPrevZoomlevel = pos.zoomLevel;
|
||||
init();
|
||||
@ -319,17 +331,19 @@ public class TileManager {
|
||||
mCacheReduce += 10;
|
||||
if (dbg)
|
||||
log.debug("reduce cache {}", (mCacheLimit - mCacheReduce));
|
||||
} else
|
||||
} else {
|
||||
mCacheReduce = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* limit cache items */
|
||||
int remove = mTilesCount - (mCacheLimit - mCacheReduce);
|
||||
|
||||
if (remove > CACHE_THRESHOLD ||
|
||||
mTilesForUpload > MAX_TILES_IN_QUEUE)
|
||||
if (remove > CACHE_THRESHOLD || mTilesToUpload > MAX_TILES_IN_QUEUE) {
|
||||
synchronized (mTilelock) {
|
||||
limitCache(pos, remove);
|
||||
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -379,9 +393,11 @@ public class TileManager {
|
||||
if (tile == null) {
|
||||
TileNode n = mIndex.add(x, y, zoomLevel);
|
||||
tile = n.item = new MapTile(n, x, y, zoomLevel);
|
||||
tile.setState(LOADING);
|
||||
mJobs.add(tile);
|
||||
addToCache(tile);
|
||||
} else if (!tile.isActive()) {
|
||||
tile.setState(LOADING);
|
||||
mJobs.add(tile);
|
||||
}
|
||||
|
||||
@ -393,10 +409,10 @@ public class TileManager {
|
||||
p = n.item = new MapTile(n, x >> 1, y >> 1, zoomLevel - 1);
|
||||
addToCache(p);
|
||||
/* this prevents to add tile twice to queue */
|
||||
p.state = LOADING;
|
||||
p.setState(LOADING);
|
||||
mJobs.add(p);
|
||||
} else if (!p.isActive()) {
|
||||
p.state = LOADING;
|
||||
p.setState(LOADING);
|
||||
mJobs.add(p);
|
||||
}
|
||||
}
|
||||
@ -405,133 +421,139 @@ public class TileManager {
|
||||
|
||||
private void addToCache(MapTile tile) {
|
||||
|
||||
if (mTilesSize == mTiles.length) {
|
||||
if (mTilesSize > mTilesCount) {
|
||||
TileDistanceSort.sort(mTiles, 0, mTilesSize);
|
||||
if (mTilesEnd == mTiles.length) {
|
||||
if (mTilesEnd > mTilesCount) {
|
||||
TileDistanceSort.sort(mTiles, 0, mTilesEnd);
|
||||
/* sorting also repacks the 'sparse' filled array
|
||||
* so end of mTiles is at mTilesCount now */
|
||||
mTilesSize = mTilesCount;
|
||||
mTilesEnd = mTilesCount;
|
||||
}
|
||||
|
||||
if (mTilesSize == mTiles.length) {
|
||||
log.debug("realloc tiles {}", mTilesSize);
|
||||
if (mTilesEnd == mTiles.length) {
|
||||
log.debug("realloc tiles {}", mTilesEnd);
|
||||
MapTile[] tmp = new MapTile[mTiles.length + 20];
|
||||
System.arraycopy(mTiles, 0, tmp, 0, mTilesCount);
|
||||
mTiles = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
mTiles[mTilesSize++] = tile;
|
||||
mTiles[mTilesEnd++] = tile;
|
||||
mTilesCount++;
|
||||
}
|
||||
|
||||
private void removeFromCache(MapTile t) {
|
||||
private boolean removeFromCache(MapTile t) {
|
||||
/* TODO check valid states here:When in CANCEL state tile belongs to
|
||||
* TileLoader thread, defer clearing to jobCompleted() */
|
||||
|
||||
if (dbg)
|
||||
log.debug("remove from cache {} {} {}",
|
||||
t, t.state(), t.isLocked());
|
||||
|
||||
if (t.isLocked())
|
||||
return false;
|
||||
|
||||
if (t.state(NEW_DATA | READY))
|
||||
events.fire(TILE_REMOVED, t);
|
||||
|
||||
if (dbg)
|
||||
log.debug("remove from cache {} {} {}", t, t.state, t.isLocked());
|
||||
|
||||
/* When in CANCEL state tile belongs to TileLoader thread,
|
||||
* defer clearing to jobCompleted() */
|
||||
if (t.state != CANCEL)
|
||||
t.clear();
|
||||
|
||||
mIndex.removeItem(t);
|
||||
|
||||
mTilesCount--;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void limitCache(MapPosition pos, int remove) {
|
||||
MapTile[] tiles = mTiles;
|
||||
int size = mTilesSize;
|
||||
|
||||
/* count tiles that have new data */
|
||||
mTilesForUpload = 0;
|
||||
int newTileCnt = 0;
|
||||
|
||||
/* remove tiles that were never loaded */
|
||||
for (int i = 0; i < size; i++) {
|
||||
for (int i = 0; i < mTilesEnd; i++) {
|
||||
MapTile t = tiles[i];
|
||||
if (t == null)
|
||||
continue;
|
||||
|
||||
if (t.state == NEW_DATA)
|
||||
if (t.state(NEW_DATA))
|
||||
newTileCnt++;
|
||||
|
||||
if (t.state == DEADBEEF) {
|
||||
//log.debug("found DEADBEEF {}", t);
|
||||
if (t.state(DEADBEEF)) {
|
||||
log.debug("found DEADBEEF {}", t);
|
||||
t.clear();
|
||||
tiles[i] = null;
|
||||
mTilesCount--;
|
||||
continue;
|
||||
}
|
||||
/* make sure tile cannot be used by GL or MapWorker Thread */
|
||||
if ((t.state != 0) || t.isLocked()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* empty tile */
|
||||
removeFromCache(t);
|
||||
/* make sure tile cannot be used by GL or MapWorker Thread */
|
||||
if (t.state(NONE) && removeFromCache(t)) {
|
||||
tiles[i] = null;
|
||||
remove--;
|
||||
}
|
||||
}
|
||||
|
||||
if ((remove < CACHE_CLEAR_THRESHOLD) && (newTileCnt < MAX_TILES_IN_QUEUE))
|
||||
return;
|
||||
|
||||
updateDistances(tiles, size, pos);
|
||||
TileDistanceSort.sort(tiles, 0, size);
|
||||
updateDistances(tiles, mTilesEnd, pos);
|
||||
TileDistanceSort.sort(tiles, 0, mTilesEnd);
|
||||
|
||||
/* sorting also repacks the 'sparse' filled array
|
||||
* so end of mTiles is at mTilesCount now */
|
||||
size = mTilesSize = mTilesCount;
|
||||
|
||||
// log.debug("remove:" + remove + " new:" + newTileCnt);
|
||||
// log.debug("cur: " + mapPosition);
|
||||
mTilesEnd = mTilesCount;
|
||||
|
||||
/* start with farest away tile */
|
||||
for (int i = size - 1; i >= 0 && remove > 0; i--) {
|
||||
for (int i = mTilesCount - 1; i >= 0 && remove > 0; i--) {
|
||||
MapTile t = tiles[i];
|
||||
|
||||
/* dont remove tile used by TileRenderer, or somewhere else
|
||||
* try again in next run. */
|
||||
if (t.isLocked()) {
|
||||
if (dbg)
|
||||
log.debug("{} locked (state={}, d={})", t, t.state, t.distance);
|
||||
log.debug("{} locked (state={}, d={})",
|
||||
t, t.state(), t.distance);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (t.state(CANCEL)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* cancel loading of tiles that should not even be cached */
|
||||
if (t.state == LOADING) {
|
||||
t.state = CANCEL;
|
||||
if (t.state(LOADING)) {
|
||||
t.setState(CANCEL);
|
||||
if (dbg)
|
||||
log.debug("{} canceled (d={})", t, t.distance);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* clear new and unused tile */
|
||||
if (t.state == NEW_DATA) {
|
||||
if (t.state(NEW_DATA)) {
|
||||
newTileCnt--;
|
||||
if (dbg)
|
||||
log.debug("{} unused (d=({})", t, t.distance);
|
||||
}
|
||||
|
||||
removeFromCache(t);
|
||||
if (!t.state(READY | NEW_DATA)) {
|
||||
log.error("stuff that should be here! {} {}", t, t.state());
|
||||
}
|
||||
|
||||
if (removeFromCache(t)) {
|
||||
tiles[i] = null;
|
||||
remove--;
|
||||
}
|
||||
}
|
||||
|
||||
remove = (newTileCnt - MAX_TILES_IN_QUEUE) + QUEUE_CLEAR_THRESHOLD;
|
||||
for (int i = size - 1; i >= 0 && remove > 0; i--) {
|
||||
for (int i = mTilesCount - 1; i >= 0 && newTileCnt > MAX_TILES_IN_QUEUE; i--) {
|
||||
MapTile t = tiles[i];
|
||||
if ((t != null) && (t.state == NEW_DATA) && !t.isLocked()) {
|
||||
removeFromCache(t);
|
||||
if ((t != null) && (t.state(NEW_DATA))) {
|
||||
if (removeFromCache(t)) {
|
||||
tiles[i] = null;
|
||||
remove--;
|
||||
newTileCnt--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mTilesForUpload += newTileCnt;
|
||||
mTilesToUpload = newTileCnt;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -563,21 +585,23 @@ public class TileManager {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (success && tile.state != CANCEL) {
|
||||
tile.state = NEW_DATA;
|
||||
if (success && tile.state(LOADING)) {
|
||||
tile.setState(NEW_DATA);
|
||||
events.fire(TILE_LOADED, tile);
|
||||
|
||||
mTilesForUpload++;
|
||||
//log.debug("loading {}: ready", tile);
|
||||
mTilesToUpload++;
|
||||
return;
|
||||
}
|
||||
|
||||
log.debug("loading {}: {}", tile,
|
||||
success ? "canceled"
|
||||
: "failed");
|
||||
// TODO use mMap.update(true) to retry tile loading?
|
||||
log.debug("Load: {} {} state:{}",
|
||||
tile, success ? "success" : "failed",
|
||||
tile.state());
|
||||
|
||||
if (tile.state == LOADING)
|
||||
mIndex.removeItem(tile);
|
||||
/* got orphaned tile */
|
||||
if (tile.state(DEADBEEF)) {
|
||||
tile.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
tile.clear();
|
||||
}
|
||||
|
@ -20,7 +20,6 @@ import static org.oscim.layers.tile.MapTile.PROXY_PARENT;
|
||||
import static org.oscim.layers.tile.MapTile.State.NEW_DATA;
|
||||
import static org.oscim.layers.tile.MapTile.State.READY;
|
||||
|
||||
import org.oscim.core.MapPosition;
|
||||
import org.oscim.layers.tile.MapTile.TileNode;
|
||||
import org.oscim.renderer.BufferObject;
|
||||
import org.oscim.renderer.GLViewport;
|
||||
@ -79,50 +78,61 @@ public abstract class TileRenderer extends LayerRenderer {
|
||||
*/
|
||||
@Override
|
||||
public synchronized void update(GLViewport v) {
|
||||
/* count placeholder tiles */
|
||||
|
||||
if (mAlpha == 0) {
|
||||
mDrawTiles.releaseTiles();
|
||||
setReady(false);
|
||||
return;
|
||||
}
|
||||
|
||||
/* get current tiles to draw */
|
||||
boolean tilesChanged;
|
||||
synchronized (tilelock) {
|
||||
tilesChanged = mTileManager.getActiveTiles(mDrawTiles);
|
||||
}
|
||||
|
||||
if (mDrawTiles.cnt == 0)
|
||||
return;
|
||||
|
||||
/* keep constant while rendering frame */
|
||||
mLayerAlpha = mAlpha;
|
||||
mOverdrawColor = mOverdraw;
|
||||
|
||||
int tileCnt = mDrawTiles.cnt;
|
||||
MapTile[] tiles = mDrawTiles.tiles;
|
||||
/* get current tiles to draw */
|
||||
synchronized (tilelock) {
|
||||
boolean tilesChanged = mTileManager.getActiveTiles(mDrawTiles);
|
||||
|
||||
if (tilesChanged || v.changed()) {
|
||||
updateTileVisibility(v.pos, v.plane);
|
||||
if (mDrawTiles.cnt == 0) {
|
||||
setReady(false);
|
||||
mProxyTileCnt = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
tileCnt += mProxyTileCnt;
|
||||
/* update isVisible flag true for tiles that intersect view */
|
||||
if (tilesChanged || v.changed()) {
|
||||
|
||||
/* lock tiles while updating isVisible state */
|
||||
mProxyTileCnt = 0;
|
||||
|
||||
MapTile[] tiles = mDrawTiles.tiles;
|
||||
int tileZoom = tiles[0].zoomLevel;
|
||||
|
||||
for (int i = 0; i < mDrawTiles.cnt; i++)
|
||||
tiles[i].isVisible = false;
|
||||
|
||||
/* no renderable tile can be locked at this point */
|
||||
if (tileZoom > v.pos.zoomLevel + 2 || tileZoom < v.pos.zoomLevel - 4) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* check visibile tiles */
|
||||
mScanBox.scan(v.pos.x, v.pos.y, v.pos.scale, tileZoom, v.plane);
|
||||
}
|
||||
}
|
||||
/* prepare tiles for rendering */
|
||||
if (compileTileLayers(tiles, tileCnt) > 0) {
|
||||
if (compileTileLayers(mDrawTiles.tiles, mDrawTiles.cnt + mProxyTileCnt) > 0) {
|
||||
mUploadSerial++;
|
||||
BufferObject.checkBufferUsage(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(GLViewport v) {
|
||||
/* render in update() so that tiles cannot vanish in between. */
|
||||
setReady(true);
|
||||
}
|
||||
|
||||
public void clearTiles() {
|
||||
/* Clear all references to MapTiles as all current
|
||||
* tiles will also be removed from TileManager. */
|
||||
//mDrawTiles = new TileSet();
|
||||
mDrawTiles.releaseTiles();
|
||||
mDrawTiles.tiles = new MapTile[1];
|
||||
mDrawTiles.cnt = 0;
|
||||
}
|
||||
@ -137,17 +147,17 @@ public abstract class TileRenderer extends LayerRenderer {
|
||||
if (!tile.isVisible)
|
||||
continue;
|
||||
|
||||
if (tile.state == READY)
|
||||
if (tile.state(READY))
|
||||
continue;
|
||||
|
||||
if (tile.state == NEW_DATA) {
|
||||
if (tile.state(NEW_DATA)) {
|
||||
uploadCnt += uploadTileData(tile);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* load tile that is referenced by this holder */
|
||||
MapTile proxy = tile.holder;
|
||||
if (proxy != null && proxy.state == NEW_DATA) {
|
||||
if (proxy != null && proxy.state(NEW_DATA)) {
|
||||
uploadCnt += uploadTileData(proxy);
|
||||
tile.state = proxy.state;
|
||||
continue;
|
||||
@ -174,7 +184,7 @@ public abstract class TileRenderer extends LayerRenderer {
|
||||
}
|
||||
|
||||
private static int uploadTileData(MapTile tile) {
|
||||
tile.state = READY;
|
||||
tile.setState(READY);
|
||||
RenderBuckets buckets = tile.getBuckets();
|
||||
|
||||
/* tile might only contain label layers */
|
||||
@ -191,30 +201,6 @@ public abstract class TileRenderer extends LayerRenderer {
|
||||
|
||||
private final Object tilelock = new Object();
|
||||
|
||||
/** set tile isVisible flag true for tiles that intersect view */
|
||||
private void updateTileVisibility(MapPosition pos, float[] box) {
|
||||
|
||||
/* lock tiles while updating isVisible state */
|
||||
synchronized (tilelock) {
|
||||
MapTile[] tiles = mDrawTiles.tiles;
|
||||
|
||||
int tileZoom = tiles[0].zoomLevel;
|
||||
|
||||
for (int i = 0; i < mDrawTiles.cnt; i++)
|
||||
tiles[i].isVisible = false;
|
||||
|
||||
if (tileZoom > pos.zoomLevel + 2 || tileZoom < pos.zoomLevel - 4) {
|
||||
//log.debug("skip: zoomlevel diff " + (tileZoom - pos.zoomLevel));
|
||||
return;
|
||||
}
|
||||
/* count placeholder tiles */
|
||||
mProxyTileCnt = 0;
|
||||
|
||||
/* check visibile tiles */
|
||||
mScanBox.scan(pos.x, pos.y, pos.scale, tileZoom, box);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update tileSet with currently visible tiles get a TileSet of currently
|
||||
* visible tiles
|
||||
@ -248,7 +234,7 @@ public abstract class TileRenderer extends LayerRenderer {
|
||||
tileSet.cnt = 0;
|
||||
for (int i = 0; i < cnt; i++) {
|
||||
MapTile t = newTiles[i];
|
||||
if (t.isVisible && t.state == READY) {
|
||||
if (t.isVisible && t.state(READY)) {
|
||||
t.lock();
|
||||
tileSet.tiles[tileSet.cnt++] = t;
|
||||
}
|
||||
|
@ -45,8 +45,7 @@ public class VectorTileRenderer extends TileRenderer {
|
||||
protected int mDrawSerial;
|
||||
|
||||
@Override
|
||||
public synchronized void update(GLViewport v) {
|
||||
super.update(v);
|
||||
public synchronized void render(GLViewport v) {
|
||||
|
||||
/* discard depth projection from tilt, depth buffer
|
||||
* is used for clipping */
|
||||
@ -67,8 +66,8 @@ public class VectorTileRenderer extends TileRenderer {
|
||||
|
||||
for (int i = 0; i < tileCnt; i++) {
|
||||
MapTile t = tiles[i];
|
||||
// TODO check if proxies are actually available
|
||||
if (t.isVisible && t.state != READY) {
|
||||
|
||||
if (t.isVisible && !t.state(READY)) {
|
||||
GL.glDepthMask(true);
|
||||
GL.glClear(GL20.GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
@ -87,7 +86,7 @@ public class VectorTileRenderer extends TileRenderer {
|
||||
/* draw visible tiles */
|
||||
for (int i = 0; i < tileCnt; i++) {
|
||||
MapTile t = tiles[i];
|
||||
if (t.isVisible && t.state == READY)
|
||||
if (t.isVisible && t.state(READY))
|
||||
drawTile(t, v, 0);
|
||||
}
|
||||
|
||||
@ -155,8 +154,10 @@ public class VectorTileRenderer extends TileRenderer {
|
||||
? tile.getBuckets()
|
||||
: tile.holder.getBuckets();
|
||||
|
||||
if (buckets == null || buckets.vbo == null)
|
||||
if (buckets == null || buckets.vbo == null) {
|
||||
//log.debug("{} no buckets!", tile);
|
||||
return;
|
||||
}
|
||||
|
||||
MapPosition pos = v.pos;
|
||||
/* place tile relative to map position */
|
||||
|
@ -33,7 +33,7 @@ public class BitmapTileLayer extends TileLayer {
|
||||
|
||||
protected static final Logger log = LoggerFactory.getLogger(BitmapTileLayer.class);
|
||||
|
||||
private final static int CACHE_LIMIT = 20;
|
||||
private final static int CACHE_LIMIT = 40;
|
||||
|
||||
protected final TileSource mTileSource;
|
||||
|
||||
@ -110,7 +110,7 @@ public class BitmapTileLayer extends TileLayer {
|
||||
pool.clear();
|
||||
}
|
||||
|
||||
final static int POOL_FILL = 40;
|
||||
final static int POOL_FILL = 20;
|
||||
|
||||
/** pool shared by TextLayers */
|
||||
final TexturePool pool = new TexturePool(POOL_FILL) {
|
||||
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
package org.oscim.layers.tile.bitmap;
|
||||
|
||||
import static org.oscim.layers.tile.MapTile.State.CANCEL;
|
||||
import static org.oscim.layers.tile.MapTile.State.LOADING;
|
||||
|
||||
import org.oscim.backend.canvas.Bitmap;
|
||||
import org.oscim.core.Tile;
|
||||
@ -55,23 +55,26 @@ public class BitmapTileLoader extends TileLoader {
|
||||
|
||||
@Override
|
||||
public void setTileImage(Bitmap bitmap) {
|
||||
if (isCanceled() || mTile.state(CANCEL))
|
||||
if (isCanceled() || !mTile.state(LOADING)) {
|
||||
bitmap.recycle();
|
||||
return;
|
||||
}
|
||||
|
||||
BitmapBucket l = new BitmapBucket(false);
|
||||
l.setBitmap(bitmap, Tile.SIZE, Tile.SIZE, mLayer.pool);
|
||||
|
||||
RenderBuckets b = new RenderBuckets();
|
||||
b.set(l);
|
||||
mTile.data = b;
|
||||
RenderBuckets buckets = new RenderBuckets();
|
||||
buckets.set(l);
|
||||
mTile.data = buckets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
mTileDataSource.cancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
mTileDataSource.cancel();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
package org.oscim.layers.tile.vector;
|
||||
|
||||
import static org.oscim.layers.tile.MapTile.State.CANCEL;
|
||||
import static org.oscim.layers.tile.MapTile.State.LOADING;
|
||||
|
||||
import org.oscim.core.GeometryBuffer.GeometryType;
|
||||
import org.oscim.core.MapElement;
|
||||
@ -134,14 +134,15 @@ public class VectorTileLoader extends TileLoader implements IRenderTheme.Callbac
|
||||
|
||||
@Override
|
||||
public void completed(QueryResult result) {
|
||||
mTileLayer.callHooksComplete(mTile, result == QueryResult.SUCCESS);
|
||||
boolean ok = (result == QueryResult.SUCCESS);
|
||||
|
||||
mTileLayer.callHooksComplete(mTile, ok);
|
||||
|
||||
/* finish buckets- tessellate and cleanup on worker-thread */
|
||||
mBuckets.prepare();
|
||||
clearState();
|
||||
|
||||
super.completed(result);
|
||||
|
||||
clearState();
|
||||
}
|
||||
|
||||
protected static int getValidLayer(int layer) {
|
||||
@ -180,7 +181,7 @@ public class VectorTileLoader extends TileLoader implements IRenderTheme.Callbac
|
||||
|
||||
@Override
|
||||
public void process(MapElement element) {
|
||||
if (isCanceled() || mTile.state(CANCEL))
|
||||
if (isCanceled() || !mTile.state(LOADING))
|
||||
return;
|
||||
|
||||
if (mTileLayer.callProcessHooks(mTile, mBuckets, element))
|
||||
|
Loading…
x
Reference in New Issue
Block a user