cleanup tile cache 'limiting functions'
This commit is contained in:
parent
4763ea8989
commit
6357c2fa2a
@ -17,7 +17,7 @@ package org.mapsforge.android.glrenderer;
|
|||||||
import org.mapsforge.android.mapgenerator.MapTile;
|
import org.mapsforge.android.mapgenerator.MapTile;
|
||||||
|
|
||||||
class GLMapTile extends MapTile {
|
class GLMapTile extends MapTile {
|
||||||
long lastDraw = 0;
|
byte lastDraw = 0;
|
||||||
|
|
||||||
// VBO layout:
|
// VBO layout:
|
||||||
// 16 bytes fill coordinates
|
// 16 bytes fill coordinates
|
||||||
|
@ -114,7 +114,7 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
|||||||
private static TilesData newTiles, curTiles, drawTiles;
|
private static TilesData newTiles, curTiles, drawTiles;
|
||||||
|
|
||||||
// draw position is updated from current position in onDrawFrame
|
// draw position is updated from current position in onDrawFrame
|
||||||
// keeping the position consistent while drawing
|
// keeping the position and active tiles consistent while drawing
|
||||||
private static MapPosition mCurPosition, mDrawPosition;
|
private static MapPosition mCurPosition, mDrawPosition;
|
||||||
|
|
||||||
// flag set by updateVisibleList when current visible tiles
|
// flag set by updateVisibleList when current visible tiles
|
||||||
@ -122,10 +122,12 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
|||||||
private static boolean mUpdateTiles;
|
private static boolean mUpdateTiles;
|
||||||
|
|
||||||
private static boolean mInitial;
|
private static boolean mInitial;
|
||||||
private static short mDrawCount = 0;
|
|
||||||
|
|
||||||
private float[] mClearColor = null;
|
private float[] mClearColor = null;
|
||||||
private static long mRedrawCnt = 0;
|
|
||||||
|
// number of tiles drawn in one frame
|
||||||
|
private static short mDrawCount = 0;
|
||||||
|
|
||||||
private static boolean mUpdateColor = false;
|
private static boolean mUpdateColor = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -218,8 +220,8 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME still the chance that one jumped two zoomlevels between cur and draw...
|
// FIXME still the chance that one jumped two zoomlevels between
|
||||||
// and this is all a bit heavy in the first place
|
// cur and draw. should use reference counter instead
|
||||||
private static boolean tileInUse(GLMapTile t) {
|
private static boolean tileInUse(GLMapTile t) {
|
||||||
byte z = mPrevZoom;
|
byte z = mPrevZoom;
|
||||||
|
|
||||||
@ -267,35 +269,115 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void limitCache(int remove) {
|
private static void limitCache(MapPosition mapPosition, int remove) {
|
||||||
boolean printAll = false;
|
int removes = remove;
|
||||||
|
|
||||||
for (int j = mTiles.size() - 1, cnt = 0; cnt < remove && j > 0; j--, cnt++) {
|
int size = mTiles.size();
|
||||||
GLMapTile t = mTiles.remove(j);
|
|
||||||
|
// remove orphaned tiles
|
||||||
|
for (int i = 0; i < size;) {
|
||||||
|
GLMapTile cur = mTiles.get(i);
|
||||||
|
// make sure tile cannot be used by GL or MapWorker Thread
|
||||||
|
if ((!cur.isActive) && (!cur.isLoading) && (!cur.newData)
|
||||||
|
&& (!cur.isReady) && (!tileInUse(cur))) {
|
||||||
|
|
||||||
|
clearTile(cur);
|
||||||
|
mTiles.remove(i);
|
||||||
|
removes--;
|
||||||
|
size--;
|
||||||
|
// Log.d(TAG, "remove empty tile" + cur);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (removes <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
updateTileDistances(mTiles, mapPosition);
|
||||||
|
|
||||||
|
Log.d(TAG, "remove tiles: " + removes);
|
||||||
|
|
||||||
|
// boolean printAll = false;
|
||||||
|
|
||||||
|
for (int i = 1; i <= removes; i++) {
|
||||||
|
|
||||||
|
GLMapTile t = mTiles.get(0);
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
for (int j = 1; j < size; j++) {
|
||||||
|
GLMapTile t2 = mTiles.get(j);
|
||||||
|
if (t2.distance > t.distance) {
|
||||||
|
t = t2;
|
||||||
|
pos = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
synchronized (t) {
|
synchronized (t) {
|
||||||
|
|
||||||
if (t.isActive) {
|
if (t.isActive) {
|
||||||
// dont remove tile used by renderthread or mapgenerator
|
// dont remove tile used by renderthread or mapgenerator
|
||||||
Log.d(TAG, "X not removing active " + t + " " + t.distance);
|
Log.d(TAG, "X not removing active " + t + " " + t.distance);
|
||||||
mTiles.add(t);
|
|
||||||
|
|
||||||
if (printAll) {
|
// if (printAll) {
|
||||||
printAll = false;
|
// printAll = false;
|
||||||
for (GLMapTile tt : mTiles)
|
// for (GLMapTile tt : mTiles)
|
||||||
Log.d(TAG, ">>>" + tt + " " + tt.distance);
|
// Log.d(TAG, ">>>" + tt + " " + tt.distance);
|
||||||
}
|
// }
|
||||||
} else if ((t.isReady || t.newData) && tileInUse(t)) {
|
} else if ((t.isReady || t.newData) && tileInUse(t)) {
|
||||||
// check if this tile could be used as proxy
|
// check if this tile could be used as proxy
|
||||||
// for not yet drawn active tile
|
// for not yet drawn active tile
|
||||||
Log.d(TAG, "X not removing proxy: " + t + " " + t.distance);
|
Log.d(TAG, "X not removing proxy: " + t + " " + t.distance);
|
||||||
mTiles.add(t);
|
|
||||||
} else {
|
} else {
|
||||||
if (t.isLoading) {
|
if (t.isLoading) {
|
||||||
Log.d(TAG, ">>> cancel loading " + t + " " + t.distance);
|
Log.d(TAG, ">>> cancel loading " + t + " " + t.distance);
|
||||||
t.isCanceled = true;
|
t.isCanceled = true;
|
||||||
}
|
}
|
||||||
|
mTiles.remove(pos);
|
||||||
|
clearTile(t);
|
||||||
|
size--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void limitLoadQueue(int remove) {
|
||||||
|
int size = remove;
|
||||||
|
|
||||||
|
synchronized (mTilesLoaded) {
|
||||||
|
|
||||||
|
// remove uploaded tiles
|
||||||
|
for (int i = 0; i < size;) {
|
||||||
|
GLMapTile t = mTilesLoaded.get(i);
|
||||||
|
// rel == null means tile is already removed by limitCache
|
||||||
|
if (!t.newData || t.rel == null) {
|
||||||
|
mTilesLoaded.remove(i);
|
||||||
|
size--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear loaded but not used tiles
|
||||||
|
if (size < MAX_TILES_IN_QUEUE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (size-- > MAX_TILES_IN_QUEUE - 20) {
|
||||||
|
GLMapTile t = mTilesLoaded.get(size);
|
||||||
|
|
||||||
|
synchronized (t) {
|
||||||
|
if (t.rel == null) {
|
||||||
|
mTilesLoaded.remove(size);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tileInUse(t)) {
|
||||||
|
// Log.d(TAG, "keep unused tile data: " + t + " " + t.isActive);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
mTilesLoaded.remove(size);
|
||||||
|
mTiles.remove(t);
|
||||||
|
// Log.d(TAG, "remove unused tile data: " + t);
|
||||||
clearTile(t);
|
clearTile(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -409,51 +491,6 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
|||||||
mMapView.addJobs(mJobList);
|
mMapView.addJobs(mJobList);
|
||||||
}
|
}
|
||||||
|
|
||||||
int removes = mTiles.size() - CACHE_TILES;
|
|
||||||
|
|
||||||
if (removes > 10) {
|
|
||||||
// int size = mTiles.size();
|
|
||||||
// for (int i = 0; i < size;) {
|
|
||||||
// GLMapTile cur = mTiles.get(i);
|
|
||||||
// if (!cur.isActive && !cur.isLoading && !cur.newData && !cur.isReady) {
|
|
||||||
// // Log.d(TAG, "remove empty tile" + cur);
|
|
||||||
// mTiles.remove(i);
|
|
||||||
// TreeTile.remove(cur);
|
|
||||||
// removes--;
|
|
||||||
// size--;
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
// i++;
|
|
||||||
// }
|
|
||||||
|
|
||||||
int size = mTiles.size();
|
|
||||||
|
|
||||||
updateTileDistances(mTiles, mapPosition);
|
|
||||||
// Log.d(TAG, "remove tiles: " + removes);
|
|
||||||
|
|
||||||
// find 'removes' tiles with longest distance and
|
|
||||||
// move them at the end
|
|
||||||
for (int i = 1; i <= removes; i++) {
|
|
||||||
int pos = 0;
|
|
||||||
GLMapTile t = mTiles.get(0);
|
|
||||||
|
|
||||||
for (int j = 1; j <= size - i; j++) {
|
|
||||||
GLMapTile t2 = mTiles.get(j);
|
|
||||||
if (t2.distance > t.distance) {
|
|
||||||
t = t2;
|
|
||||||
pos = j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Log.d(TAG, "mark for removal" + cur);
|
|
||||||
|
|
||||||
mTiles.add(size - i, mTiles.remove(pos));
|
|
||||||
}
|
|
||||||
// Collections.sort(mTiles);
|
|
||||||
|
|
||||||
limitCache(removes);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -560,47 +597,16 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
|||||||
if (changedPos)
|
if (changedPos)
|
||||||
updateVisibleList(mapPosition, zdir);
|
updateVisibleList(mapPosition, zdir);
|
||||||
|
|
||||||
synchronized (mTilesLoaded) {
|
if (changedPos || changedZoom) {
|
||||||
int size = mTilesLoaded.size();
|
int remove = mTiles.size() - CACHE_TILES;
|
||||||
if (size < MAX_TILES_IN_QUEUE)
|
if (remove > 10)
|
||||||
return;
|
limitCache(mapPosition, remove);
|
||||||
|
|
||||||
// remove uploaded tiles
|
|
||||||
for (int i = 0; i < size;) {
|
|
||||||
GLMapTile t = mTilesLoaded.get(i);
|
|
||||||
// rel == null means tile is already removed by limitCache
|
|
||||||
if (!t.newData || t.rel == null) {
|
|
||||||
mTilesLoaded.remove(i);
|
|
||||||
size--;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// clear loaded but not used tiles
|
|
||||||
if (size > MAX_TILES_IN_QUEUE) {
|
|
||||||
while (size-- > MAX_TILES_IN_QUEUE - 20) {
|
|
||||||
GLMapTile t = mTilesLoaded.get(size);
|
|
||||||
|
|
||||||
synchronized (t) {
|
|
||||||
if (t.rel == null) {
|
|
||||||
mTilesLoaded.remove(size);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tileInUse(t)) {
|
|
||||||
// Log.d(TAG, "keep unused tile data: " + t + " " + t.isActive);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
mTilesLoaded.remove(size);
|
|
||||||
mTiles.remove(t);
|
|
||||||
// Log.d(TAG, "remove unused tile data: " + t);
|
|
||||||
clearTile(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int size = mTilesLoaded.size();
|
||||||
|
if (size > MAX_TILES_IN_QUEUE)
|
||||||
|
limitLoadQueue(size);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -646,9 +652,7 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// depthRange: -1 to 1, bits: 2^24 => 2/2^24 one step
|
// depthRange: -1 to 1, bits: 2^24 => 2/2^24 one step
|
||||||
// maybe one could avoid clearing the depth buffer for a few
|
// ... asus has just 16 bit?!
|
||||||
// iterations when modifying glDepthRange before clipper
|
|
||||||
// gl_less test so that it does not fail
|
|
||||||
// private static final float depthStep = 0.00000011920928955078125f;
|
// private static final float depthStep = 0.00000011920928955078125f;
|
||||||
|
|
||||||
private static void setMatrix(GLMapTile tile, float div, int offset) {
|
private static void setMatrix(GLMapTile tile, float div, int offset) {
|
||||||
@ -811,7 +815,7 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void checkBufferUsage() {
|
private static void checkBufferUsage() {
|
||||||
// not really tested, try to clear some vbo when exceding limit
|
// try to clear some unused vbo when exceding limit
|
||||||
if (mBufferMemoryUsage > LIMIT_BUFFERS) {
|
if (mBufferMemoryUsage > LIMIT_BUFFERS) {
|
||||||
Log.d(TAG, "buffer object usage: " + mBufferMemoryUsage / MB + "MB");
|
Log.d(TAG, "buffer object usage: " + mBufferMemoryUsage / MB + "MB");
|
||||||
|
|
||||||
@ -825,19 +829,19 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
mBufferMemoryUsage -= vbo.size;
|
mBufferMemoryUsage -= vbo.size;
|
||||||
GlUtils.checkGlError("before");
|
|
||||||
// this should free allocated memory but it does not. at least on HTC.
|
// this should free allocated memory but it does not.
|
||||||
|
// on HTC it causes oom exception?!
|
||||||
|
|
||||||
// glBindBuffer(GL_ARRAY_BUFFER, vbo.id);
|
// glBindBuffer(GL_ARRAY_BUFFER, vbo.id);
|
||||||
// glBufferData(GL_ARRAY_BUFFER, 0, null, GLES20.GL_STATIC_DRAW);
|
// glBufferData(GL_ARRAY_BUFFER, 0, null, GLES20.GL_STATIC_DRAW);
|
||||||
|
|
||||||
// recreate vbo
|
// recreate vbo instead
|
||||||
buf[0] = vbo.id;
|
buf[0] = vbo.id;
|
||||||
GLES20.glDeleteBuffers(1, buf, 0);
|
GLES20.glDeleteBuffers(1, buf, 0);
|
||||||
GLES20.glGenBuffers(1, buf, 0);
|
GLES20.glGenBuffers(1, buf, 0);
|
||||||
vbo.id = buf[0];
|
vbo.id = buf[0];
|
||||||
|
|
||||||
GlUtils.checkGlError("after");
|
|
||||||
|
|
||||||
vbo.size = 0;
|
vbo.size = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -861,8 +865,7 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
|||||||
start = SystemClock.uptimeMillis();
|
start = SystemClock.uptimeMillis();
|
||||||
|
|
||||||
if (mUpdateColor && mClearColor != null) {
|
if (mUpdateColor && mClearColor != null) {
|
||||||
glClearColor(mClearColor[0], mClearColor[1],
|
glClearColor(mClearColor[0], mClearColor[1], mClearColor[2], mClearColor[3]);
|
||||||
mClearColor[2], mClearColor[3]);
|
|
||||||
mUpdateColor = false;
|
mUpdateColor = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -937,7 +940,6 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
|||||||
TextRenderer.compileTextures();
|
TextRenderer.compileTextures();
|
||||||
|
|
||||||
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
|
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
|
||||||
// glEnable(GLES20.GL_POLYGON_OFFSET_FILL);
|
|
||||||
|
|
||||||
for (int i = 0; i < tileCnt; i++) {
|
for (int i = 0; i < tileCnt; i++) {
|
||||||
if (tiles[i].isVisible && tiles[i].isReady) {
|
if (tiles[i].isVisible && tiles[i].isReady) {
|
||||||
@ -954,11 +956,10 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
|||||||
}
|
}
|
||||||
// GlUtils.checkGlError("end draw");
|
// GlUtils.checkGlError("end draw");
|
||||||
|
|
||||||
// glDisable(GLES20.GL_POLYGON_OFFSET_FILL);
|
|
||||||
glDisable(GLES20.GL_DEPTH_TEST);
|
glDisable(GLES20.GL_DEPTH_TEST);
|
||||||
//
|
|
||||||
|
|
||||||
mDrawCount = 0;
|
mDrawCount = 0;
|
||||||
|
mDrawSerial++;
|
||||||
|
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
int z = mDrawPosition.zoomLevel;
|
int z = mDrawPosition.zoomLevel;
|
||||||
@ -987,16 +988,17 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
|||||||
GLES20.glFinish();
|
GLES20.glFinish();
|
||||||
Log.d(TAG, "draw took " + (SystemClock.uptimeMillis() - start));
|
Log.d(TAG, "draw took " + (SystemClock.uptimeMillis() - start));
|
||||||
}
|
}
|
||||||
|
|
||||||
mRedrawCnt++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// used to not draw a tile twice per frame...
|
||||||
|
private static byte mDrawSerial = 0;
|
||||||
|
|
||||||
private static void drawTile(GLMapTile tile, float div) {
|
private static void drawTile(GLMapTile tile, float div) {
|
||||||
// draw parents only once
|
// draw parents only once
|
||||||
if (tile.lastDraw == mRedrawCnt)
|
if (tile.lastDraw == mDrawSerial)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
tile.lastDraw = mRedrawCnt;
|
tile.lastDraw = mDrawSerial;
|
||||||
|
|
||||||
int z = mDrawPosition.zoomLevel;
|
int z = mDrawPosition.zoomLevel;
|
||||||
float s = mDrawPosition.scale;
|
float s = mDrawPosition.scale;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user