diff --git a/src/org/mapsforge/android/glrenderer/GLMapTile.java b/src/org/mapsforge/android/glrenderer/GLMapTile.java index 4550e985..dd4f7c8e 100644 --- a/src/org/mapsforge/android/glrenderer/GLMapTile.java +++ b/src/org/mapsforge/android/glrenderer/GLMapTile.java @@ -17,7 +17,7 @@ package org.mapsforge.android.glrenderer; import org.mapsforge.android.mapgenerator.MapTile; class GLMapTile extends MapTile { - long lastDraw = 0; + byte lastDraw = 0; // VBO layout: // 16 bytes fill coordinates diff --git a/src/org/mapsforge/android/glrenderer/MapRenderer.java b/src/org/mapsforge/android/glrenderer/MapRenderer.java index 310a7379..e31497d1 100644 --- a/src/org/mapsforge/android/glrenderer/MapRenderer.java +++ b/src/org/mapsforge/android/glrenderer/MapRenderer.java @@ -114,7 +114,7 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer { private static TilesData newTiles, curTiles, drawTiles; // 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; // 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 mInitial; - private static short mDrawCount = 0; 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; /** @@ -218,8 +220,8 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer { return false; } - // FIXME still the chance that one jumped two zoomlevels between cur and draw... - // and this is all a bit heavy in the first place + // FIXME still the chance that one jumped two zoomlevels between + // cur and draw. should use reference counter instead private static boolean tileInUse(GLMapTile t) { byte z = mPrevZoom; @@ -267,35 +269,115 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer { return false; } - private static void limitCache(int remove) { - boolean printAll = false; + private static void limitCache(MapPosition mapPosition, int remove) { + int removes = remove; - for (int j = mTiles.size() - 1, cnt = 0; cnt < remove && j > 0; j--, cnt++) { - GLMapTile t = mTiles.remove(j); + int size = mTiles.size(); + + // 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) { - if (t.isActive) { // dont remove tile used by renderthread or mapgenerator Log.d(TAG, "X not removing active " + t + " " + t.distance); - mTiles.add(t); - if (printAll) { - printAll = false; - for (GLMapTile tt : mTiles) - Log.d(TAG, ">>>" + tt + " " + tt.distance); - } + // if (printAll) { + // printAll = false; + // for (GLMapTile tt : mTiles) + // Log.d(TAG, ">>>" + tt + " " + tt.distance); + // } } else if ((t.isReady || t.newData) && tileInUse(t)) { // check if this tile could be used as proxy // for not yet drawn active tile Log.d(TAG, "X not removing proxy: " + t + " " + t.distance); - mTiles.add(t); } else { if (t.isLoading) { Log.d(TAG, ">>> cancel loading " + t + " " + t.distance); 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); } } @@ -409,51 +491,6 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer { 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; } @@ -560,47 +597,16 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer { if (changedPos) updateVisibleList(mapPosition, zdir); - synchronized (mTilesLoaded) { - int size = mTilesLoaded.size(); - if (size < MAX_TILES_IN_QUEUE) - return; - - // 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); - } - } - } + if (changedPos || changedZoom) { + int remove = mTiles.size() - CACHE_TILES; + if (remove > 10) + limitCache(mapPosition, remove); } + + 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 - // maybe one could avoid clearing the depth buffer for a few - // iterations when modifying glDepthRange before clipper - // gl_less test so that it does not fail + // ... asus has just 16 bit?! // private static final float depthStep = 0.00000011920928955078125f; 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() { - // not really tested, try to clear some vbo when exceding limit + // try to clear some unused vbo when exceding limit if (mBufferMemoryUsage > LIMIT_BUFFERS) { Log.d(TAG, "buffer object usage: " + mBufferMemoryUsage / MB + "MB"); @@ -825,19 +829,19 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer { continue; 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); // glBufferData(GL_ARRAY_BUFFER, 0, null, GLES20.GL_STATIC_DRAW); - // recreate vbo + // recreate vbo instead buf[0] = vbo.id; GLES20.glDeleteBuffers(1, buf, 0); GLES20.glGenBuffers(1, buf, 0); vbo.id = buf[0]; - GlUtils.checkGlError("after"); - vbo.size = 0; } } @@ -861,8 +865,7 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer { start = SystemClock.uptimeMillis(); if (mUpdateColor && mClearColor != null) { - glClearColor(mClearColor[0], mClearColor[1], - mClearColor[2], mClearColor[3]); + glClearColor(mClearColor[0], mClearColor[1], mClearColor[2], mClearColor[3]); mUpdateColor = false; } @@ -937,7 +940,6 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer { TextRenderer.compileTextures(); GLES20.glEnable(GLES20.GL_DEPTH_TEST); - // glEnable(GLES20.GL_POLYGON_OFFSET_FILL); for (int i = 0; i < tileCnt; i++) { if (tiles[i].isVisible && tiles[i].isReady) { @@ -954,11 +956,10 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer { } // GlUtils.checkGlError("end draw"); - // glDisable(GLES20.GL_POLYGON_OFFSET_FILL); glDisable(GLES20.GL_DEPTH_TEST); - // mDrawCount = 0; + mDrawSerial++; glEnable(GL_BLEND); int z = mDrawPosition.zoomLevel; @@ -987,16 +988,17 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer { GLES20.glFinish(); 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) { // draw parents only once - if (tile.lastDraw == mRedrawCnt) + if (tile.lastDraw == mDrawSerial) return; - tile.lastDraw = mRedrawCnt; + tile.lastDraw = mDrawSerial; int z = mDrawPosition.zoomLevel; float s = mDrawPosition.scale;