From 8d5fef5f9941c62ac49cd01af18e47e85927d8e9 Mon Sep 17 00:00:00 2001 From: Ivo van Dongen Date: Wed, 13 Sep 2017 14:34:05 +0300 Subject: [android] Re-initialise renderer, backend and context when the android system destroyed the underlying gl resources --- .../com/mapbox/mapboxsdk/maps/NativeMapView.java | 3 + platform/android/src/android_renderer_backend.cpp | 11 +++- platform/android/src/android_renderer_backend.hpp | 4 ++ platform/android/src/android_renderer_frontend.cpp | 69 ++++++++++++++++------ platform/android/src/android_renderer_frontend.hpp | 7 +++ platform/android/src/native_map_view.cpp | 5 ++ 6 files changed, 80 insertions(+), 19 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java index d1faa910bb..dece1a1dce 100755 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java @@ -903,6 +903,8 @@ final class NativeMapView implements GLSurfaceView.Renderer { float pixelRatio, String programCacheDir); + private native void nativeOnSurfaceCreated(); + private native void nativeDestroy(); private native void nativeInitializeDisplay(); @@ -1142,6 +1144,7 @@ final class NativeMapView implements GLSurfaceView.Renderer { @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { Timber.i("[%s] onSurfaceCreated", Thread.currentThread().getName()); + nativeOnSurfaceCreated(); //TODO: callback to map to re-create renderer? } diff --git a/platform/android/src/android_renderer_backend.cpp b/platform/android/src/android_renderer_backend.cpp index eac12177a5..536090ddec 100755 --- a/platform/android/src/android_renderer_backend.cpp +++ b/platform/android/src/android_renderer_backend.cpp @@ -1,5 +1,7 @@ #include "android_renderer_backend.hpp" +#include + #include #include @@ -51,5 +53,12 @@ void AndroidRendererBackend::updateAssumedState() { assumeViewport(0, 0, getFramebufferSize()); } + +void AndroidRendererBackend::abandonContext() { + if (context) { + context->setCleanupOnDestruction(false); + } } -} + +} // namespace android +} // namspace mbgl diff --git a/platform/android/src/android_renderer_backend.hpp b/platform/android/src/android_renderer_backend.hpp index 0cc9d1b682..16cc782132 100755 --- a/platform/android/src/android_renderer_backend.hpp +++ b/platform/android/src/android_renderer_backend.hpp @@ -12,6 +12,10 @@ public: void bind() override; void updateAssumedState() override; + // Ensures the current context is not + // cleaned up when destroyed + void abandonContext(); + void updateViewPort(); void resizeFramebuffer(int width, int height); diff --git a/platform/android/src/android_renderer_frontend.cpp b/platform/android/src/android_renderer_frontend.cpp index 6ad7872f89..11bb9ab3fc 100644 --- a/platform/android/src/android_renderer_frontend.cpp +++ b/platform/android/src/android_renderer_frontend.cpp @@ -62,22 +62,16 @@ private: RendererObserver& delegate; }; -AndroidRendererFrontend::AndroidRendererFrontend(float pixelRatio, - FileSource& fileSource, - Scheduler& scheduler, - std::string programCacheDir, - InvalidateCallback invalidate) - : backend(std::make_unique()) - , renderer(std::make_unique>( - "Orchestration Thread", - *backend, - pixelRatio, - fileSource, - scheduler, - GLContextMode::Unique, - programCacheDir - )) - , asyncInvalidate([=, invalidate=std::move(invalidate)]() { +AndroidRendererFrontend::AndroidRendererFrontend(float pixelRatio_, + FileSource& fileSource_, + Scheduler& scheduler_, + std::string programCacheDir_, + InvalidateCallback invalidate_) + : pixelRatio(pixelRatio_) + , fileSource(fileSource_) + , scheduler(scheduler_) + , programCacheDir(programCacheDir_) + , asyncInvalidate([=, invalidate=std::move(invalidate_)]() { invalidate(); }) , mapRunLoop(util::RunLoop::Get()) { @@ -90,11 +84,50 @@ void AndroidRendererFrontend::reset() { renderer.reset(); } +void AndroidRendererFrontend::initialise() { + // Lock as the initialization can come from the main thread or the GL thread first + std::lock_guard lock(intitialisationMutex); + + if (backend) { + // The android system will have already destroyed the underlying + // GL resources and an attempt to clean them up will fail + backend->abandonContext(); + } + + // Destroy in reverse order + renderer.reset(); + backend.reset(); + + // Re-create + backend = std::make_unique(); + renderer = std::make_unique>( + "Orchestration Thread", + *backend, + pixelRatio, + fileSource, + scheduler, + GLContextMode::Unique, + programCacheDir + ); + + // Set the observer on the new Renderer implementation + if (rendererObserver) { + renderer->actor().invoke(&Renderer::setObserver, rendererObserver.get()); + } +} + void AndroidRendererFrontend::setObserver(RendererObserver& observer) { - assert (renderer); assert (util::RunLoop::Get()); + + // Lock as the initialization can come from the main thread or the GL thread first + std::lock_guard lock(intitialisationMutex); + rendererObserver = std::make_unique(*mapRunLoop, observer); - renderer->actor().invoke(&Renderer::setObserver, rendererObserver.get()); + + // Set the new observer on the Renderer implementation + if (renderer) { + renderer->actor().invoke(&Renderer::setObserver, rendererObserver.get()); + } } void AndroidRendererFrontend::update(std::shared_ptr params) { diff --git a/platform/android/src/android_renderer_frontend.hpp b/platform/android/src/android_renderer_frontend.hpp index 36db705f2e..9c90e63c83 100644 --- a/platform/android/src/android_renderer_frontend.hpp +++ b/platform/android/src/android_renderer_frontend.hpp @@ -42,6 +42,7 @@ public: InvalidateCallback); ~AndroidRendererFrontend() override; + void initialise(); void reset() override; void setObserver(RendererObserver&) override; @@ -67,6 +68,11 @@ public: void requestSnapshot(SnapshotCallback); private: + float pixelRatio; + FileSource& fileSource; + Scheduler& scheduler; + std::string programCacheDir; + std::unique_ptr backend; std::unique_ptr> renderer; std::unique_ptr rendererObserver; @@ -74,6 +80,7 @@ private: std::mutex updateMutex; std::shared_ptr updateParameters; + std::mutex intitialisationMutex; util::AsyncTask asyncInvalidate; diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp index 1a0dc34bbc..e55628b202 100755 --- a/platform/android/src/native_map_view.cpp +++ b/platform/android/src/native_map_view.cpp @@ -187,6 +187,10 @@ void NativeMapView::onSourceChanged(mbgl::style::Source&) { // JNI Methods // +void NativeMapView::onSurfaceCreated(jni::JNIEnv&) { + rendererFrontend->initialise(); +} + // Called from the OpenGL renderer thread void NativeMapView::render(jni::JNIEnv& ) { rendererFrontend->render(); @@ -1003,6 +1007,7 @@ void NativeMapView::registerNative(jni::JNIEnv& env) { std::make_unique, jni::Object, jni::jfloat, jni::String>, "nativeInitialize", "nativeDestroy", + METHOD(&NativeMapView::onSurfaceCreated, "nativeOnSurfaceCreated"), METHOD(&NativeMapView::render, "nativeRender"), METHOD(&NativeMapView::update, "nativeUpdate"), METHOD(&NativeMapView::resizeView, "nativeResizeView"), -- cgit v1.2.1