Android: clean up Surface resources when it is destroyed
Clean up any resources using the Android Surface when it has been destroyed. Previously the resource clean up was done only after Qt app state changed to Hidden or below and we initiate the removal of the Surface. However, in the case of QtSurface which is a SurfaceView, it will destroy its Surface before we ever get to that part, leading to the resources holding a reference to a destroyed Surface. Task-number: QTBUG-118231 Change-Id: I282ddcc2813bf0a4e19cbb906376258dd2b4004f Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io> (cherry picked from commit 9343d1ab6e1a5df3166d211809f2eb0e5a3cd878) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
868324d1e4
commit
6eb29cab2a
@ -47,6 +47,8 @@ class QtSurface extends SurfaceView implements SurfaceHolder.Callback
|
||||
@Override
|
||||
public void surfaceDestroyed(SurfaceHolder holder)
|
||||
{
|
||||
// Once we return from this function, the Surface will be destroyed,
|
||||
// so everything holding a reference to it needs to clean it up before we do that
|
||||
if (m_surfaceCallback != null)
|
||||
m_surfaceCallback.onSurfaceChanged(null);
|
||||
}
|
||||
|
@ -50,6 +50,12 @@ bool QAndroidPlatformOpenGLContext::makeCurrent(QPlatformSurface *surface)
|
||||
|
||||
QAndroidPlatformOpenGLWindow *window = static_cast<QAndroidPlatformOpenGLWindow *>(surface);
|
||||
window->lockSurface();
|
||||
// Has the Surface been destroyed?
|
||||
if (window->eglSurface(eglConfig()) == EGL_NO_SURFACE) {
|
||||
qWarning() << "makeCurrent(): no EGLSurface, likely Surface destroyed by Android.";
|
||||
window->unlockSurface();
|
||||
return false;
|
||||
}
|
||||
const bool ok = QEGLPlatformContext::makeCurrent(surface);
|
||||
window->unlockSurface();
|
||||
return ok;
|
||||
|
@ -33,7 +33,7 @@ QAndroidPlatformOpenGLWindow::~QAndroidPlatformOpenGLWindow()
|
||||
m_surfaceWaitCondition.wakeOne();
|
||||
lockSurface();
|
||||
destroySurface();
|
||||
clearEgl();
|
||||
clearSurface();
|
||||
unlockSurface();
|
||||
}
|
||||
|
||||
@ -58,13 +58,15 @@ EGLSurface QAndroidPlatformOpenGLWindow::eglSurface(EGLConfig config)
|
||||
QGuiApplication::applicationState() == Qt::ApplicationSuspended) {
|
||||
return m_eglSurface;
|
||||
}
|
||||
|
||||
// If we haven't called createSurface() yet, call it and wait until Android has created
|
||||
// the Surface
|
||||
if (!m_surfaceCreated) {
|
||||
AndroidDeadlockProtector protector;
|
||||
if (!protector.acquire())
|
||||
return m_eglSurface;
|
||||
|
||||
createSurface();
|
||||
qCDebug(lcQpaWindow) << "called createSurface(), waiting for Surface to be ready...";
|
||||
m_surfaceWaitCondition.wait(&m_surfaceMutex);
|
||||
}
|
||||
|
||||
@ -79,7 +81,7 @@ EGLSurface QAndroidPlatformOpenGLWindow::eglSurface(EGLConfig config)
|
||||
bool QAndroidPlatformOpenGLWindow::checkNativeSurface(EGLConfig config)
|
||||
{
|
||||
// Either no surface created, or the m_eglSurface already wraps the active Surface
|
||||
// -> makeCurrent is NOT needed.
|
||||
// -> makeCurrent is NOT needed, and we should not create a new EGL surface
|
||||
if (!m_surfaceCreated || !m_androidSurfaceObject.isValid())
|
||||
return false;
|
||||
|
||||
@ -96,14 +98,14 @@ void QAndroidPlatformOpenGLWindow::applicationStateChanged(Qt::ApplicationState
|
||||
if (state <= Qt::ApplicationHidden) {
|
||||
lockSurface();
|
||||
destroySurface();
|
||||
clearEgl();
|
||||
clearSurface();
|
||||
unlockSurface();
|
||||
}
|
||||
}
|
||||
|
||||
void QAndroidPlatformOpenGLWindow::createEgl(EGLConfig config)
|
||||
{
|
||||
clearEgl();
|
||||
clearSurface();
|
||||
QJniEnvironment env;
|
||||
m_nativeWindow = ANativeWindow_fromSurface(env.jniEnv(), m_androidSurfaceObject.object());
|
||||
m_androidSurfaceObject = QJniObject();
|
||||
@ -124,7 +126,7 @@ QSurfaceFormat QAndroidPlatformOpenGLWindow::format() const
|
||||
return m_format;
|
||||
}
|
||||
|
||||
void QAndroidPlatformOpenGLWindow::clearEgl()
|
||||
void QAndroidPlatformOpenGLWindow::clearSurface()
|
||||
{
|
||||
if (m_eglSurface != EGL_NO_SURFACE) {
|
||||
eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
@ -134,7 +136,7 @@ void QAndroidPlatformOpenGLWindow::clearEgl()
|
||||
|
||||
if (m_nativeWindow) {
|
||||
ANativeWindow_release(m_nativeWindow);
|
||||
m_nativeWindow = 0;
|
||||
m_nativeWindow = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ public:
|
||||
|
||||
protected:
|
||||
void createEgl(EGLConfig config);
|
||||
void clearEgl();
|
||||
void clearSurface() override;
|
||||
|
||||
private:
|
||||
EGLDisplay m_eglDisplay = EGL_NO_DISPLAY;
|
||||
|
@ -31,8 +31,10 @@ public:
|
||||
|
||||
VkSurfaceKHR *vkSurface();
|
||||
|
||||
protected:
|
||||
void clearSurface() override;
|
||||
|
||||
private:
|
||||
void clearSurface();
|
||||
void destroyAndClearSurface();
|
||||
|
||||
ANativeWindow *m_nativeWindow;
|
||||
|
@ -303,10 +303,14 @@ void QAndroidPlatformWindow::destroySurface()
|
||||
void QAndroidPlatformWindow::onSurfaceChanged(QtJniTypes::Surface surface)
|
||||
{
|
||||
lockSurface();
|
||||
const bool surfaceIsValid = surface.isValid();
|
||||
qCDebug(lcQpaWindow) << "onSurfaceChanged():, valid Surface received" << surfaceIsValid;
|
||||
m_androidSurfaceObject = surface;
|
||||
if (m_androidSurfaceObject.isValid()) {
|
||||
if (surfaceIsValid) {
|
||||
// wait until we have a valid surface to draw into
|
||||
m_surfaceWaitCondition.wakeOne();
|
||||
} else {
|
||||
clearSurface();
|
||||
}
|
||||
|
||||
unlockSurface();
|
||||
|
@ -77,6 +77,7 @@ protected:
|
||||
void sendExpose() const;
|
||||
bool blockedByModal() const;
|
||||
bool isEmbeddingContainer() const;
|
||||
virtual void clearSurface() {}
|
||||
|
||||
Qt::WindowFlags m_windowFlags;
|
||||
Qt::WindowStates m_windowState;
|
||||
|
Loading…
x
Reference in New Issue
Block a user