Asynchronous GeometryTile deletion (#2051)
Co-authored-by: Tim Sylvester <tim@wetdogweather.com>
This commit is contained in:
@@ -60,7 +60,7 @@ ActorRef<Renderer> MapRenderer::actor() const {
|
||||
return *rendererRef;
|
||||
}
|
||||
|
||||
void MapRenderer::schedule(std::function<void()> scheduled) {
|
||||
void MapRenderer::schedule(std::function<void()>&& scheduled) {
|
||||
try {
|
||||
// Create a runnable
|
||||
android::UniqueEnv _env = android::AttachEnv();
|
||||
@@ -84,6 +84,23 @@ void MapRenderer::schedule(std::function<void()> scheduled) {
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t MapRenderer::waitForEmpty(Milliseconds timeout) {
|
||||
try {
|
||||
android::UniqueEnv _env = android::AttachEnv();
|
||||
static auto& javaClass = jni::Class<MapRenderer>::Singleton(*_env);
|
||||
static auto waitForEmpty = javaClass.GetMethod<jni::jint(jni::jlong)>(*_env, "waitForEmpty");
|
||||
if (auto weakReference = javaPeer.get(*_env)) {
|
||||
return weakReference.Call(*_env, waitForEmpty, static_cast<int64_t>(timeout.count()));
|
||||
}
|
||||
// If the peer is already cleaned up, there's nothing to wait for
|
||||
return 0;
|
||||
} catch (...) {
|
||||
Log::Error(Event::Android, "MapRenderer::waitForEmpty failed");
|
||||
jni::ThrowJavaError(*android::AttachEnv(), std::current_exception());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void MapRenderer::requestRender() {
|
||||
try {
|
||||
android::UniqueEnv _env = android::AttachEnv();
|
||||
|
||||
@@ -66,9 +66,13 @@ public:
|
||||
|
||||
// From Scheduler. Schedules by using callbacks to the
|
||||
// JVM to process the mailbox on the right thread.
|
||||
void schedule(std::function<void()> scheduled) override;
|
||||
void schedule(std::function<void()>&& scheduled) override;
|
||||
mapbox::base::WeakPtr<Scheduler> makeWeakPtr() override { return weakFactory.makeWeakPtr(); }
|
||||
|
||||
// Wait for the queue to be empty
|
||||
// A timeout of zero results in an unbounded wait
|
||||
std::size_t waitForEmpty(Milliseconds timeout) override;
|
||||
|
||||
void requestRender();
|
||||
|
||||
// Snapshot - requires a RunLoop on the calling thread
|
||||
|
||||
@@ -120,6 +120,11 @@ public abstract class MapRenderer implements MapRendererScheduler {
|
||||
this.queueEvent((Runnable) runnable);
|
||||
}
|
||||
|
||||
/// Wait indefinitely for the queue to become empty
|
||||
public void waitForEmpty() {
|
||||
waitForEmpty(0);
|
||||
}
|
||||
|
||||
private native void nativeInitialize(MapRenderer self,
|
||||
float pixelRatio,
|
||||
String localIdeographFontFamily);
|
||||
|
||||
@@ -14,4 +14,9 @@ public interface MapRendererScheduler {
|
||||
@Keep
|
||||
void queueEvent(Runnable runnable);
|
||||
|
||||
@Keep
|
||||
void waitForEmpty();
|
||||
|
||||
@Keep
|
||||
long waitForEmpty(long timeoutMillis);
|
||||
}
|
||||
|
||||
@@ -116,4 +116,11 @@ public class GLSurfaceViewMapRenderer extends MapRenderer implements GLSurfaceVi
|
||||
glSurfaceView.queueEvent(runnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public long waitForEmpty(long timeoutMillis) {
|
||||
return glSurfaceView.waitForEmpty(timeoutMillis);
|
||||
}
|
||||
}
|
||||
@@ -317,6 +317,16 @@ public class MapLibreGLSurfaceView extends SurfaceView implements SurfaceHolder.
|
||||
glThread.queueEvent(r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the queue to become empty
|
||||
* @param timeoutMillis Timeout in milliseconds
|
||||
* @return Number of queue items remaining
|
||||
*/
|
||||
public long waitForEmpty(long timeoutMillis) {
|
||||
return glThread.waitForEmpty(timeoutMillis);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method is used as part of the View class and is not normally
|
||||
* called or subclassed by clients of GLSurfaceView.
|
||||
@@ -1023,6 +1033,39 @@ public class MapLibreGLSurfaceView extends SurfaceView implements SurfaceHolder.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the queue to become empty
|
||||
* @param timeoutMillis Timeout in milliseconds, zero for indefinite wait
|
||||
* @return Number of queue items remaining
|
||||
*/
|
||||
public int waitForEmpty(long timeoutMillis) {
|
||||
final long startTime = System.nanoTime();
|
||||
synchronized (glThreadManager) {
|
||||
// Wait for the queue to be empty
|
||||
while (!this.eventQueue.isEmpty()) {
|
||||
if (timeoutMillis > 0) {
|
||||
final long elapsedMillis = (System.nanoTime() - startTime) / 1000 / 1000;
|
||||
if (elapsedMillis < timeoutMillis) {
|
||||
try {
|
||||
glThreadManager.wait(timeoutMillis - elapsedMillis);
|
||||
} catch (InterruptedException ex) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
glThreadManager.wait();
|
||||
} catch (InterruptedException ex) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.eventQueue.size();
|
||||
}
|
||||
}
|
||||
|
||||
// Once the thread is started, all accesses to the following member
|
||||
// variables are protected by the sGLThreadManager monitor
|
||||
private boolean shouldExit;
|
||||
|
||||
@@ -35,6 +35,7 @@ public class TextureViewMapRenderer extends MapRenderer {
|
||||
super(context, localIdeographFontFamily);
|
||||
this.translucentSurface = translucentSurface;
|
||||
renderThread = new TextureViewRenderThread(textureView, this);
|
||||
renderThread.setName("TextureViewRenderer");
|
||||
renderThread.start();
|
||||
}
|
||||
|
||||
@@ -86,6 +87,14 @@ public class TextureViewMapRenderer extends MapRenderer {
|
||||
renderThread.queueEvent(runnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public long waitForEmpty(long timeoutMillis) {
|
||||
return renderThread.waitForEmpty(timeoutMillis);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
|
||||
@@ -135,6 +135,39 @@ class TextureViewRenderThread extends Thread implements TextureView.SurfaceTextu
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the queue to be empty.
|
||||
* @param timeoutMillis Maximum time to wait, in milliseconds
|
||||
* @return The number of items remaining in the queue
|
||||
*/
|
||||
@UiThread
|
||||
int waitForEmpty(long timeoutMillis) {
|
||||
final long startTime = System.nanoTime();
|
||||
synchronized (lock) {
|
||||
// Wait for the queue to be empty
|
||||
while (!this.eventQueue.isEmpty()) {
|
||||
if (timeoutMillis > 0) {
|
||||
final long elapsedMillis = (System.nanoTime() - startTime) / 1000 / 1000;
|
||||
if (elapsedMillis < timeoutMillis) {
|
||||
try {
|
||||
lock.wait(timeoutMillis - elapsedMillis);
|
||||
} catch (InterruptedException ex) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
lock.wait(0);
|
||||
} catch (InterruptedException ex) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.eventQueue.size();
|
||||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
void onPause() {
|
||||
|
||||
Reference in New Issue
Block a user