implement managing of tasks instances in ContinuousTask

This commit is contained in:
Hannes Janetzek 2014-01-22 22:42:50 +01:00
parent c8d79ee6fc
commit 401b0bf2dc
3 changed files with 149 additions and 102 deletions

View File

@ -68,6 +68,8 @@ public class LabelLayer extends Layer implements Map.InputListener, Map.UpdateLi
public void onMapUpdate(MapPosition mapPosition, boolean changed, boolean clear) { public void onMapUpdate(MapPosition mapPosition, boolean changed, boolean clear) {
if (clear) if (clear)
mTextRenderer.clearLabels(); mTextRenderer.clearLabels();
mTextRenderer.update();
} }
// @Override // @Override

View File

@ -53,9 +53,11 @@ import org.oscim.utils.FastMath;
import org.oscim.utils.OBB2D; import org.oscim.utils.OBB2D;
import org.oscim.utils.async.ContinuousTask; import org.oscim.utils.async.ContinuousTask;
import org.oscim.utils.pool.Pool; import org.oscim.utils.pool.Pool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class TextRenderer extends ElementRenderer { class TextRenderer extends ElementRenderer {
//static final Logger log = LoggerFactory.getLogger(TextRenderLayer.class); static final Logger log = LoggerFactory.getLogger(TextRenderer.class);
private final static float MIN_CAPTION_DIST = 5; private final static float MIN_CAPTION_DIST = 5;
private final static float MIN_WAY_DIST = 3; private final static float MIN_WAY_DIST = 3;
@ -65,10 +67,10 @@ class TextRenderer extends ElementRenderer {
private final Viewport mViewport; private final Viewport mViewport;
private final TileSet mTileSet; private final TileSet mTileSet;
class TextureLayers { //private ElementLayers mDebugLayer;
boolean ready;
final TextureLayer l; class TextureLayers {
final TextureLayer layers;
final TextLayer textLayer; final TextLayer textLayer;
final SymbolLayer symbolLayer; final SymbolLayer symbolLayer;
@ -80,17 +82,12 @@ class TextRenderer extends ElementRenderer {
symbolLayer = new SymbolLayer(); symbolLayer = new SymbolLayer();
textLayer = new TextLayer(); textLayer = new TextLayer();
l = symbolLayer; layers = symbolLayer;
l.next = textLayer; symbolLayer.next = textLayer;
} }
} }
// used by GL thread
private TextureLayers mCurLayer;
// used by labeling thread
private TextureLayers mNextLayer;
// thread local pool (labeling) // thread local pool (labeling)
class LabelPool extends Pool<TextItem> { class LabelPool extends Pool<TextItem> {
Label releaseAndGetNext(Label l) { Label releaseAndGetNext(Label l) {
@ -139,9 +136,6 @@ class TextRenderer extends ElementRenderer {
layers.textureLayers = new TextLayer(); layers.textureLayers = new TextLayer();
layers.textureLayers.next = new SymbolLayer(); layers.textureLayers.next = new SymbolLayer();
mCurLayer = new TextureLayers();
mNextLayer = new TextureLayers();
//mActiveTiles = new HashMap<MapTile, LabelTile>(); //mActiveTiles = new HashMap<MapTile, LabelTile>();
mRelabelCnt = 0; mRelabelCnt = 0;
@ -241,6 +235,15 @@ class TextRenderer extends ElementRenderer {
return true; return true;
} }
private boolean iconIsVisible(int x, int y) {
// rough filter
float dist = x * x + y * y;
if (dist > mSquareRadius)
return false;
return true;
}
private boolean wayIsVisible(TextItem ti) { private boolean wayIsVisible(TextItem ti) {
// rough filter // rough filter
float dist = ti.x * ti.x + ti.y * ti.y; float dist = ti.x * ti.x + ti.y * ti.y;
@ -258,8 +261,6 @@ class TextRenderer extends ElementRenderer {
return false; return false;
} }
private ElementLayers mDebugLayer;
private Label getLabel() { private Label getLabel() {
Label l = (Label) mPool.get(); Label l = (Label) mPool.get();
l.active = Integer.MAX_VALUE; l.active = Integer.MAX_VALUE;
@ -379,10 +380,10 @@ class TextRenderer extends ElementRenderer {
return l; return l;
} }
boolean updateLabels() { boolean updateLabels(TextureLayers work) {
// nextLayer is not loaded yet // nextLayer is not loaded yet
if (mNextLayer.ready) //if (mNextLayer.ready)
return false; // return false;
// get current tiles // get current tiles
boolean changedTiles = mTileLayer.getVisibleTiles(mTileSet); boolean changedTiles = mTileLayer.getVisibleTiles(mTileSet);
@ -393,7 +394,7 @@ class TextRenderer extends ElementRenderer {
return false; return false;
} }
MapPosition pos = mNextLayer.pos; MapPosition pos = work.pos;
synchronized (mViewport) { synchronized (mViewport) {
changedPos = mViewport.getMapPosition(pos); changedPos = mViewport.getMapPosition(pos);
@ -428,7 +429,7 @@ class TextRenderer extends ElementRenderer {
//if (dbg != null) //if (dbg != null)
// Debug.addDebugLayers(dbg); // Debug.addDebugLayers(dbg);
SymbolLayer sl = mNextLayer.symbolLayer; SymbolLayer sl = work.symbolLayer;
sl.clearItems(); sl.clearItems();
mRelabelCnt++; mRelabelCnt++;
@ -570,13 +571,17 @@ class TextRenderer extends ElementRenderer {
if (ti.texRegion == null) if (ti.texRegion == null)
continue; continue;
int x = (int) ((dx + ti.x) * scale);
int y = (int) ((dy + ti.y) * scale);
if (!iconIsVisible(x, y))
continue;
SymbolItem s = SymbolItem.pool.get(); SymbolItem s = SymbolItem.pool.get();
s.texRegion = ti.texRegion; s.texRegion = ti.texRegion;
s.x = (float) ((dx + ti.x) * scale); s.x = x;
s.y = (float) ((dy + ti.y) * scale); s.y = y;
s.billboard = true; s.billboard = true;
sl.addSymbol(s); sl.addSymbol(s);
} }
} }
@ -585,18 +590,16 @@ class TextRenderer extends ElementRenderer {
// temporary used Label // temporary used Label
l = (Label) mPool.release(l); l = (Label) mPool.release(l);
TextLayer tl = mNextLayer.textLayer;
tl.labels = mLabels;
// draw text to bitmaps and create vertices // draw text to bitmaps and create vertices
tl.prepare(); work.textLayer.labels = mLabels;
tl.labels = null; work.textLayer.prepare();
work.textLayer.labels = null;
// remove tile locks // remove tile locks
mTileLayer.releaseTiles(mTileSet); mTileLayer.releaseTiles(mTileSet);
mDebugLayer = dbg; //mDebugLayer = dbg;
mNextLayer.ready = true; //mNextLayer.ready = true;
return true; return true;
} }
@ -607,90 +610,87 @@ class TextRenderer extends ElementRenderer {
public synchronized void update(MapPosition pos, boolean changed, public synchronized void update(MapPosition pos, boolean changed,
Matrices matrices) { Matrices matrices) {
if (mNextLayer.ready) { TextureLayers t;
// exchange current with next layers synchronized (mLabelTask) {
TextureLayers tmp = mCurLayer;
mCurLayer = mNextLayer; t = mLabelTask.poll();
mNextLayer = tmp;
mNextLayer.ready = false; if (t == null)
return;
// clear textures and text items from previous layer
layers.clear(); layers.clear();
if (mDebugLayer != null) {
layers.baseLayers = mDebugLayer.baseLayers;
mDebugLayer = null;
}
// set new TextLayer to be uploaded and rendered
layers.textureLayers = mCurLayer.l;
mMapPosition = mCurLayer.pos;
compile();
} }
mLabelTask.submit((mLastRun + MAX_RELABEL_DELAY) - System.currentTimeMillis()); // set new TextLayer to be uploaded and rendered
layers.textureLayers = t.layers;
mMapPosition = t.pos;
compile();
update();
} }
@Override @Override
public synchronized void render(MapPosition pos, Matrices m) { public synchronized void render(MapPosition pos, Matrices m) {
GLState.test(false, false); GLState.test(false, false);
layers.vbo.bind();
float scale = (float) (mMapPosition.scale / pos.scale); float scale = (float) (mMapPosition.scale / pos.scale);
setMatrix(pos, m, true); if (layers.baseLayers != null) {
setMatrix(pos, m, true);
synchronized (layers) { for (RenderElement l = layers.baseLayers; l != null;) {
layers.vbo.bind(); if (l.type == RenderElement.POLYGON) {
if (layers.baseLayers != null) { l = PolygonLayer.Renderer.draw(pos, l, m, true, 1, false);
for (RenderElement l = layers.baseLayers; l != null;) { } else {
if (l.type == RenderElement.POLYGON) { float div = (float) (mMapPosition.scale / (1 << pos.zoomLevel));
l = PolygonLayer.Renderer.draw(pos, l, m, true, 1, false); l = LineLayer.Renderer.draw(layers, l, pos, m, div);
} else {
float div = scale * (float) (pos.scale / (1 << pos.zoomLevel));
l = LineLayer.Renderer.draw(layers, l, pos, m, div);
}
} }
} }
setMatrix(pos, m, false);
for (RenderElement l = layers.textureLayers; l != null;)
l = TextureLayer.Renderer.draw(l, scale, m);
} }
setMatrix(pos, m, false);
for (RenderElement l = layers.textureLayers; l != null;)
l = TextureLayer.Renderer.draw(l, scale, m);
} }
final class LabelTask extends ContinuousTask { final class LabelTask extends ContinuousTask<TextureLayers> {
public LabelTask(Map map) { public LabelTask(Map map) {
super(map, 10); super(map, 10, new TextureLayers(), new TextureLayers());
} }
@Override @Override
public void doWork() { public boolean doWork(TextureLayers t) {
if (updateLabels()) if (updateLabels(t)) {
mMap.render(); mMap.render();
return true;
}
mLastRun = System.currentTimeMillis(); return false;
} }
@Override @Override
public void cleanup() { public void cleanup(TextureLayers t) {
clearLabelsInternal(); }
@Override
public void finish() {
mLabels = (Label) mPool.releaseAll(mLabels);
mTileSet.releaseTiles();
} }
} }
private final LabelTask mLabelTask; private final LabelTask mLabelTask;
/* private */long mLastRun; public void clearLabels() {
mLabelTask.cancel(true);
/* private */void clearLabelsInternal() {
mLabels = (Label) mPool.releaseAll(mLabels);
mTileSet.releaseTiles();
} }
public void clearLabels() { public void update() {
mLabelTask.cancel(); mLabelTask.submit(MAX_RELABEL_DELAY);
} }
} }

View File

@ -2,7 +2,12 @@ package org.oscim.utils.async;
import org.oscim.map.Map; import org.oscim.map.Map;
public abstract class ContinuousTask implements Runnable { /**
* Simple 'Double Buffering' worker for running Tasks on AsyncExecutor
* thread.
*/
public abstract class ContinuousTask<T> implements Runnable {
private final Map mMap; private final Map mMap;
protected boolean mRunning; protected boolean mRunning;
@ -12,30 +17,40 @@ public abstract class ContinuousTask implements Runnable {
protected long mMinDelay; protected long mMinDelay;
public ContinuousTask(Map map, long minDelay) { /** Stuff which can be processed on the worker thread. */
protected T mTaskTodo;
/** Stuff that is done an ready for being fetched by poll(). */
protected T mTaskDone;
/** Stuff that is ready - will not be modified in the worker. */
protected T mTaskLocked;
public ContinuousTask(Map map, long minDelay, T t1, T t2) {
mMap = map; mMap = map;
mMinDelay = minDelay; mMinDelay = minDelay;
mTaskTodo = t1;
mTaskLocked = t2;
} }
@Override @Override
public void run() { public void run() {
synchronized (this) { synchronized (this) {
//System.out.println("run " + mRunning + " "
// + mCancel + " " + mDelayed + " " + mWait);
if (mCancel) { if (mCancel) {
mCancel = false; mCancel = false;
mRunning = false; mRunning = false;
mDelayed = false; mDelayed = false;
mWait = false; mWait = false;
cleanup(); cleanup(mTaskTodo);
finish();
return; return;
} }
if (mDelayed) {
if (mDelayed || mTaskTodo == null) {
// entered on main-loop // entered on main-loop
mDelayed = false; mDelayed = false;
mWait = false;
// unset running temporarily // unset running temporarily
mRunning = false; mRunning = false;
submit(0); submit(0);
@ -43,32 +58,43 @@ public abstract class ContinuousTask implements Runnable {
} }
} }
doWork(); boolean done = doWork(mTaskTodo);
synchronized (this) { synchronized (this) {
mRunning = false; mRunning = false;
if (mCancel) if (mCancel) {
cleanup(); cleanup(mTaskTodo);
else if (mWait) finish();
mCancel = false;
} else if (done) {
mTaskDone = mTaskTodo;
mTaskTodo = null;
} else if (mWait) {
// only submit if not 'done'
// as otherwise there is no
// mStuffTodo
submit(mMinDelay); submit(mMinDelay);
mWait = false;
mCancel = false; }
mWait = false;
} }
} }
public abstract void doWork(); public abstract boolean doWork(T task);
public abstract void cleanup(); public abstract void cleanup(T task);
public void finish() {
}
public synchronized void submit(long delay) { public synchronized void submit(long delay) {
//System.out.println("submit " + mRunning + " " + mCancel + " " + delay);
if (mRunning) { if (mRunning) {
mWait = true; mWait = true;
return; return;
} }
mRunning = true; mRunning = true;
if (delay <= 0) { if (delay <= 0) {
mMap.addTask(this); mMap.addTask(this);
@ -80,12 +106,31 @@ public abstract class ContinuousTask implements Runnable {
} }
public synchronized void cancel() { public synchronized T poll() {
if (mTaskDone == null)
return null;
cleanup(mTaskLocked);
mTaskTodo = mTaskLocked;
mTaskLocked = mTaskDone;
mTaskDone = null;
if (mWait) {
submit(mMinDelay);
mWait = false;
}
return mTaskLocked;
}
public synchronized void cancel(boolean clear) {
if (mRunning) { if (mRunning) {
mCancel = true; mCancel = true;
return; return;
} }
cleanup(); cleanup(mTaskTodo);
finish();
} }
} }