[android] Re-initialise renderer, backend and context when the android system destroyed the underlying gl resources

This commit is contained in:
Ivo van Dongen
2017-09-13 14:34:05 +03:00
committed by Ivo van Dongen
parent 6211db6968
commit 67285f3a95
7 changed files with 99 additions and 45 deletions

View File

@@ -13,29 +13,29 @@
namespace mbgl {
namespace android {
MapRenderer::MapRenderer(jni::JNIEnv& _env,
jni::Object<MapRenderer> obj,
jni::Object<FileSource> fileSource,
jni::jfloat pixelRatio,
jni::String programCacheDir)
: javaPeer(SeizeGenericWeakRef(_env, jni::Object<MapRenderer>(jni::NewWeakGlobalRef(_env, obj.Get()).release())))
, threadPool(sharedThreadPool())
, backend(std::make_unique<AndroidRendererBackend>())
, renderer(std::make_unique<Renderer>(*backend, pixelRatio, FileSource::getDefaultFileSource(_env, fileSource),
*threadPool, GLContextMode::Unique, jni::Make<std::string>(_env, programCacheDir)))
, mailbox(std::make_shared<Mailbox>(*this))
, rendererRef(*renderer, mailbox) {
MapRenderer::MapRenderer(jni::JNIEnv& _env, jni::Object<MapRenderer> obj,
jni::Object<FileSource> _fileSource, jni::jfloat pixelRatio_,
jni::String programCacheDir_)
: javaPeer(SeizeGenericWeakRef(_env, jni::Object<MapRenderer>(jni::NewWeakGlobalRef(_env, obj.Get()).release()))), pixelRatio(pixelRatio_)
, fileSource(FileSource::getDefaultFileSource(_env, _fileSource))
, programCacheDir(jni::Make<std::string>(_env, programCacheDir_))
, threadPool(sharedThreadPool())
, mailbox(std::make_shared<Mailbox>(*this)) {
}
MapRenderer::~MapRenderer() = default;
void MapRenderer::reset() {
void MapRenderer::reset() {
assert (renderer);
renderer.reset();
// Lock to make sure there is no concurrent initialisation on the gl thread
std::lock_guard<std::mutex> lock(initialisationMutex);
rendererObserver.reset();
}
ActorRef<Renderer> MapRenderer::actor() const {
return rendererRef;
return *rendererRef;
}
void MapRenderer::schedule(std::weak_ptr<Mailbox> scheduled) {
@@ -43,7 +43,8 @@ void MapRenderer::schedule(std::weak_ptr<Mailbox> scheduled) {
android::UniqueEnv _env = android::AttachEnv();
auto runnable = std::make_unique<MapRendererRunnable>(*_env, std::move(scheduled));
static auto queueEvent = javaClass.GetMethod<void (jni::Object<MapRendererRunnable>)>(*_env, "queueEvent");
static auto queueEvent = javaClass.GetMethod<void(
jni::Object<MapRendererRunnable>)>(*_env, "queueEvent");
javaPeer->Call(*_env, queueEvent, runnable->getPeer());
// Release the object as it will be destroyed on GC of the Java Peer
@@ -52,7 +53,7 @@ void MapRenderer::schedule(std::weak_ptr<Mailbox> scheduled) {
void MapRenderer::requestRender() {
android::UniqueEnv _env = android::AttachEnv();
static auto onInvalidate = javaClass.GetMethod<void ()>(*_env, "requestRender");
static auto onInvalidate = javaClass.GetMethod<void()>(*_env, "requestRender");
javaPeer->Call(*_env, onInvalidate);
}
@@ -62,6 +63,18 @@ void MapRenderer::update(std::shared_ptr<UpdateParameters> params) {
updateParameters = std::move(params);
}
void MapRenderer::setObserver(std::shared_ptr<RendererObserver> _rendererObserver) {
// Lock as the initialization can come from the main thread or the GL thread first
std::lock_guard<std::mutex> lock(initialisationMutex);
rendererObserver = std::move(_rendererObserver);
// Set the new observer on the Renderer implementation
if (renderer) {
renderer->setObserver(rendererObserver.get());
}
}
// Called on OpenGL thread //
void MapRenderer::render(JNIEnv&) {
@@ -93,7 +106,28 @@ void MapRenderer::render(JNIEnv&) {
}
void MapRenderer::onSurfaceCreated(JNIEnv&) {
// TODO (re-)create Context, Backend and Renderer
// Lock as the initialization can come from the main thread or the GL thread first
std::lock_guard<std::mutex> lock(initialisationMutex);
// The android system will have already destroyed the underlying
// GL resources if this is not the first intialization and an
// attempt to clean them up will fail
if (backend) backend->markContextLost();
// Reset in opposite order
renderer.reset();
backend.reset();
// Create the new backend and renderer
backend = std::make_unique<AndroidRendererBackend>();
renderer = std::make_unique<Renderer>(*backend, pixelRatio, fileSource, *threadPool,
GLContextMode::Unique, programCacheDir);
rendererRef = std::make_unique<ActorRef<Renderer>>(*renderer, mailbox);
// Set the observer on the new Renderer implementation
if (rendererObserver) {
renderer->setObserver(rendererObserver.get());
}
}
void MapRenderer::onSurfaceChanged(JNIEnv&, jint width, jint height) {
@@ -113,22 +147,19 @@ void MapRenderer::registerNative(jni::JNIEnv& env) {
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
// Register the peer
jni::RegisterNativePeer<MapRenderer>(
env,
MapRenderer::javaClass,
"nativePtr",
std::make_unique<MapRenderer, JNIEnv&, jni::Object<MapRenderer>, jni::Object<FileSource>, jni::jfloat, jni::String>,
"nativeInitialize",
"finalize",
METHOD(&MapRenderer::render, "nativeRender"),
METHOD(&MapRenderer::onSurfaceCreated, "nativeOnSurfaceCreated"),
METHOD(&MapRenderer::onSurfaceChanged, "nativeOnSurfaceChanged")
);
jni::RegisterNativePeer<MapRenderer>(env, MapRenderer::javaClass, "nativePtr",
std::make_unique<MapRenderer, JNIEnv&, jni::Object<MapRenderer>, jni::Object<FileSource>, jni::jfloat, jni::String>,
"nativeInitialize", "finalize",
METHOD(&MapRenderer::render, "nativeRender"),
METHOD(&MapRenderer::onSurfaceCreated,
"nativeOnSurfaceCreated"),
METHOD(&MapRenderer::onSurfaceChanged,
"nativeOnSurfaceChanged"));
}
MapRenderer& MapRenderer::getNativePeer(JNIEnv& env, jni::Object<MapRenderer> jObject) {
static auto field = MapRenderer::javaClass.GetField<jlong>(env, "nativePtr");
MapRenderer* mapRenderer = reinterpret_cast<MapRenderer *>(jObject.Get(env, field));
MapRenderer* mapRenderer = reinterpret_cast<MapRenderer*>(jObject.Get(env, field));
assert(mapRenderer != nullptr);
return *mapRenderer;
}