Improve Vulkan Android surface lifecycle (#4323)
This commit is contained in:
@@ -27,6 +27,9 @@ public:
|
||||
// Ensures the current context is not cleaned up when destroyed
|
||||
virtual void markContextLost();
|
||||
|
||||
virtual bool createSurface(ANativeWindow*) { return false; }
|
||||
virtual void destroySurface() {}
|
||||
|
||||
virtual void resizeFramebuffer(int width, int height);
|
||||
virtual PremultipliedImage readFramebuffer();
|
||||
|
||||
|
||||
@@ -55,6 +55,21 @@ AndroidVulkanRendererBackend::AndroidVulkanRendererBackend(ANativeWindow* window
|
||||
|
||||
AndroidVulkanRendererBackend::~AndroidVulkanRendererBackend() = default;
|
||||
|
||||
bool AndroidVulkanRendererBackend::createSurface(ANativeWindow* window_) {
|
||||
window = window_;
|
||||
setResource(std::make_unique<AndroidVulkanRenderableResource>(*this));
|
||||
|
||||
initSurface();
|
||||
initSwapchain();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AndroidVulkanRendererBackend::destroySurface() {
|
||||
window = nullptr;
|
||||
setResource(nullptr);
|
||||
}
|
||||
|
||||
std::vector<const char*> AndroidVulkanRendererBackend::getInstanceExtensions() {
|
||||
auto extensions = mbgl::vulkan::RendererBackend::getInstanceExtensions();
|
||||
extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
|
||||
|
||||
@@ -16,6 +16,9 @@ public:
|
||||
~AndroidVulkanRendererBackend() override;
|
||||
|
||||
ANativeWindow* getWindow() { return window; }
|
||||
bool createSurface(ANativeWindow* window) override;
|
||||
void destroySurface() override;
|
||||
|
||||
mbgl::gfx::RendererBackend& getImpl() override { return *this; }
|
||||
|
||||
std::vector<const char*> getInstanceExtensions() override;
|
||||
|
||||
@@ -249,10 +249,23 @@ void MapRenderer::onSurfaceCreated(JNIEnv& env, const jni::Object<AndroidSurface
|
||||
// Lock as the initialization can come from the main thread or the GL thread first
|
||||
std::scoped_lock lock(initialisationMutex);
|
||||
|
||||
// The android system will have already destroyed the underlying
|
||||
// GL resources if this is not the first initialization and an
|
||||
// attempt to clean them up will fail
|
||||
UniqueANativeWindow window_ = nullptr;
|
||||
|
||||
if (surface) {
|
||||
window_ = std::unique_ptr<ANativeWindow, std::function<void(ANativeWindow*)>>(
|
||||
ANativeWindow_fromSurface(&env, reinterpret_cast<jobject>(surface.get())),
|
||||
[](ANativeWindow* window_) { ANativeWindow_release(window_); });
|
||||
}
|
||||
|
||||
if (backend) {
|
||||
if (backend->createSurface(window_.get())) {
|
||||
window = std::move(window_);
|
||||
return;
|
||||
}
|
||||
|
||||
// The android system will have already destroyed the underlying
|
||||
// GL resources if this is not the first initialization and an
|
||||
// attempt to clean them up will fail
|
||||
gfx::BackendScope backendGuard{backend->getImpl()};
|
||||
backend->markContextLost();
|
||||
}
|
||||
@@ -264,13 +277,7 @@ void MapRenderer::onSurfaceCreated(JNIEnv& env, const jni::Object<AndroidSurface
|
||||
// Reset in opposite order
|
||||
renderer.reset();
|
||||
backend.reset();
|
||||
window.reset();
|
||||
|
||||
if (surface) {
|
||||
window = std::unique_ptr<ANativeWindow, std::function<void(ANativeWindow*)>>(
|
||||
ANativeWindow_fromSurface(&env, reinterpret_cast<jobject>(surface.get())),
|
||||
[](ANativeWindow* window_) { ANativeWindow_release(window_); });
|
||||
}
|
||||
window = std::move(window_);
|
||||
|
||||
// Create the new backend and renderer
|
||||
backend = AndroidRendererBackend::Create(window.get());
|
||||
@@ -316,7 +323,11 @@ void MapRenderer::onRendererReset(JNIEnv&) {
|
||||
|
||||
// needs to be called on GL thread
|
||||
void MapRenderer::onSurfaceDestroyed(JNIEnv&) {
|
||||
resetRenderer();
|
||||
if (backend) {
|
||||
backend->destroySurface();
|
||||
}
|
||||
|
||||
window.reset();
|
||||
}
|
||||
|
||||
void MapRenderer::setSwapBehaviorFlush(JNIEnv&, jboolean flush) {
|
||||
|
||||
@@ -147,7 +147,9 @@ private:
|
||||
std::unique_ptr<AndroidRendererBackend> backend;
|
||||
std::unique_ptr<Renderer> renderer;
|
||||
std::unique_ptr<ActorRef<Renderer>> rendererRef;
|
||||
std::unique_ptr<ANativeWindow, std::function<void(ANativeWindow*)>> window;
|
||||
|
||||
using UniqueANativeWindow = std::unique_ptr<ANativeWindow, std::function<void(ANativeWindow*)>>;
|
||||
UniqueANativeWindow window;
|
||||
|
||||
std::shared_ptr<UpdateParameters> updateParameters;
|
||||
std::mutex updateMutex;
|
||||
|
||||
@@ -35,7 +35,6 @@ public class MapLibreVulkanSurfaceView extends MapLibreSurfaceView {
|
||||
|
||||
boolean sizeChanged = false;
|
||||
boolean initSurface = false;
|
||||
boolean destroySurface = false;
|
||||
boolean wantRenderNotification = false;
|
||||
boolean doRenderNotification = false;
|
||||
int w = 0;
|
||||
@@ -64,10 +63,10 @@ public class MapLibreVulkanSurfaceView extends MapLibreSurfaceView {
|
||||
// lost surface
|
||||
if (!hasSurface && !waitingForSurface) {
|
||||
MapLibreVulkanSurfaceView view = mSurfaceViewWeakRef.get();
|
||||
if (view != null) {
|
||||
destroySurface = true;
|
||||
graphicsSurfaceCreated = false;
|
||||
if (view != null && graphicsSurfaceCreated) {
|
||||
view.renderer.onSurfaceDestroyed();
|
||||
}
|
||||
graphicsSurfaceCreated = false;
|
||||
waitingForSurface = true;
|
||||
renderThreadManager.notifyAll();
|
||||
}
|
||||
@@ -129,15 +128,6 @@ public class MapLibreVulkanSurfaceView extends MapLibreSurfaceView {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (destroySurface) {
|
||||
MapLibreVulkanSurfaceView view = mSurfaceViewWeakRef.get();
|
||||
if (view != null) {
|
||||
view.renderer.onSurfaceDestroyed();
|
||||
destroySurface = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (initSurface) {
|
||||
MapLibreVulkanSurfaceView view = mSurfaceViewWeakRef.get();
|
||||
if (view != null) {
|
||||
|
||||
@@ -34,7 +34,6 @@ public class VulkanTextureViewRenderThread extends TextureViewRenderThread {
|
||||
while (true) {
|
||||
Runnable event = null;
|
||||
boolean createSurface = false;
|
||||
boolean destroySurface = false;
|
||||
boolean sizeChanged = false;
|
||||
int w = -1;
|
||||
int h = -1;
|
||||
@@ -54,13 +53,15 @@ public class VulkanTextureViewRenderThread extends TextureViewRenderThread {
|
||||
}
|
||||
|
||||
if (this.destroySurface) {
|
||||
destroySurface = true;
|
||||
if (surface != null) {
|
||||
mapRenderer.onSurfaceDestroyed();
|
||||
surface.release();
|
||||
surface = null;
|
||||
}
|
||||
|
||||
this.hasNativeSurface = false;
|
||||
this.destroySurface = false;
|
||||
lock.notifyAll();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -108,16 +109,6 @@ public class VulkanTextureViewRenderThread extends TextureViewRenderThread {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (destroySurface) {
|
||||
mapRenderer.onSurfaceDestroyed();
|
||||
synchronized (lock) {
|
||||
this.hasNativeSurface = false;
|
||||
lock.notifyAll();
|
||||
}
|
||||
destroySurface = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the surface size has changed inform the map renderer.
|
||||
if (sizeChanged) {
|
||||
mapRenderer.onSurfaceChanged(w, h);
|
||||
|
||||
Reference in New Issue
Block a user