[android] Re-initialise renderer, backend and context when the android system destroyed the underlying gl resources
This commit is contained in:
committed by
Ivo van Dongen
parent
6211db6968
commit
67285f3a95
@@ -1,5 +1,7 @@
|
||||
#include "android_renderer_backend.hpp"
|
||||
|
||||
#include <mbgl/gl/context.hpp>
|
||||
|
||||
#include <EGL/egl.h>
|
||||
|
||||
#include <cassert>
|
||||
@@ -51,5 +53,11 @@ void AndroidRendererBackend::updateAssumedState() {
|
||||
assumeViewport(0, 0, getFramebufferSize());
|
||||
}
|
||||
|
||||
void AndroidRendererBackend::markContextLost() {
|
||||
if (context) {
|
||||
context->setCleanupOnDestruction(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
} // namspace mbgl
|
||||
|
||||
@@ -13,6 +13,10 @@ public:
|
||||
void updateAssumedState() override;
|
||||
mbgl::Size getFramebufferSize() const override;
|
||||
|
||||
// Ensures the current context is not
|
||||
// cleaned up when destroyed
|
||||
void markContextLost();
|
||||
|
||||
void updateViewPort();
|
||||
|
||||
void resizeFramebuffer(int width, int height);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "android_renderer_frontend.hpp"
|
||||
|
||||
#include <mbgl/actor/scheduler.hpp>
|
||||
#include <mbgl/renderer/renderer.hpp>
|
||||
#include <mbgl/renderer/renderer_observer.hpp>
|
||||
#include <mbgl/storage/file_source.hpp>
|
||||
#include <mbgl/util/thread.hpp>
|
||||
@@ -63,13 +64,13 @@ AndroidRendererFrontend::~AndroidRendererFrontend() = default;
|
||||
|
||||
void AndroidRendererFrontend::reset() {
|
||||
mapRenderer.reset();
|
||||
rendererObserver.reset();
|
||||
}
|
||||
|
||||
void AndroidRendererFrontend::setObserver(RendererObserver& observer) {
|
||||
assert (util::RunLoop::Get());
|
||||
rendererObserver = std::make_unique<ForwardingRendererObserver>(*mapRunLoop, observer);
|
||||
mapRenderer.actor().invoke(&Renderer::setObserver, rendererObserver.get());
|
||||
// Don't call the Renderer directly, but use MapRenderer#setObserver to make sure
|
||||
// the Renderer may be re-initialised without losing the RendererObserver reference.
|
||||
mapRenderer.setObserver(std::make_unique<ForwardingRendererObserver>(*mapRunLoop, observer));
|
||||
}
|
||||
|
||||
void AndroidRendererFrontend::update(std::shared_ptr<UpdateParameters> params) {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#include <mbgl/actor/actor.hpp>
|
||||
#include <mbgl/annotation/annotation.hpp>
|
||||
#include <mbgl/renderer/renderer_backend.hpp>
|
||||
#include <mbgl/renderer/renderer_frontend.hpp>
|
||||
#include <mbgl/util/geo.hpp>
|
||||
#include <mbgl/util/image.hpp>
|
||||
@@ -17,15 +16,11 @@
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class FileSource;
|
||||
class Scheduler;
|
||||
class RenderedQueryOptions;
|
||||
class SourceQueryOptions;
|
||||
|
||||
namespace android {
|
||||
|
||||
class AndroidRendererBackend;
|
||||
|
||||
class AndroidRendererFrontend : public RendererFrontend {
|
||||
public:
|
||||
|
||||
@@ -51,9 +46,7 @@ public:
|
||||
void requestSnapshot(SnapshotCallback);
|
||||
|
||||
private:
|
||||
std::unique_ptr<RendererObserver> rendererObserver;
|
||||
MapRenderer& mapRenderer;
|
||||
|
||||
util::RunLoop* mapRunLoop;
|
||||
|
||||
// TODO
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/actor/actor_ref.hpp>
|
||||
#include <mbgl/actor/mailbox.hpp>
|
||||
#include <mbgl/actor/scheduler.hpp>
|
||||
#include <mbgl/renderer/renderer.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include <jni/jni.hpp>
|
||||
#include <mbgl/storage/default_file_source.hpp>
|
||||
|
||||
#include "jni/generic_global_ref_deleter.hpp"
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
template <class>
|
||||
class ActorRef;
|
||||
class Mailbox;
|
||||
class Renderer;
|
||||
class RendererBackend;
|
||||
class RendererObserver;
|
||||
class ThreadPool;
|
||||
class UpdateParameters;
|
||||
|
||||
@@ -52,6 +54,11 @@ public:
|
||||
// Resets the renderer to clean up on the calling thread
|
||||
void reset();
|
||||
|
||||
// Takes the RendererObserver by shared_ptr so we
|
||||
// don't have to make the header public. Use
|
||||
// this instead of Renderer#setObserver directly
|
||||
void setObserver(std::shared_ptr<RendererObserver>);
|
||||
|
||||
// Sets the new update parameters to use on subsequent
|
||||
// renders. Be sure to trigger a render with
|
||||
// requestRender().
|
||||
@@ -79,11 +86,20 @@ private:
|
||||
|
||||
private:
|
||||
GenericUniqueWeakObject<MapRenderer> javaPeer;
|
||||
|
||||
float pixelRatio;
|
||||
DefaultFileSource& fileSource;
|
||||
std::string programCacheDir;
|
||||
|
||||
std::shared_ptr<ThreadPool> threadPool;
|
||||
std::shared_ptr<Mailbox> mailbox;
|
||||
|
||||
std::mutex initialisationMutex;
|
||||
std::shared_ptr<RendererObserver> rendererObserver;
|
||||
|
||||
std::unique_ptr<AndroidRendererBackend> backend;
|
||||
std::unique_ptr<Renderer> renderer;
|
||||
std::shared_ptr<Mailbox> mailbox;
|
||||
ActorRef<Renderer> rendererRef;
|
||||
std::unique_ptr<ActorRef<Renderer>> rendererRef;
|
||||
|
||||
std::shared_ptr<UpdateParameters> updateParameters;
|
||||
std::mutex updateMutex;
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <mbgl/style/style.hpp>
|
||||
#include <mbgl/style/image.hpp>
|
||||
#include <mbgl/style/filter.hpp>
|
||||
#include <mbgl/renderer/query.hpp>
|
||||
|
||||
// Java -> C++ conversion
|
||||
#include "style/android_conversion.hpp"
|
||||
|
||||
Reference in New Issue
Block a user