winrt: Move EGL surface to window.

Fixes GPU memory leak when window is created/deleted dynamically and
repeatedly. EGL context used to own EGL surface, but the context
outlives the surface if window is created/deleted dynamically. The
EGL surface is now owned by the window and destroyed with it.

Change-Id: Ib949261ef6e77217018e60aad3e36e4a6d2eaba0
Reviewed-by: Andrew Knight <andrew.knight@intopalo.com>
bb10
Samuel Nevala 2015-09-10 13:14:57 +03:00 committed by Andrew Knight
parent fe1ba87961
commit f3fd7b3d96
3 changed files with 44 additions and 21 deletions

View File

@ -56,7 +56,6 @@ public:
EGLDisplay eglDisplay;
EGLConfig eglConfig;
EGLContext eglContext;
QHash<QPlatformSurface *, EGLSurface> surfaceForWindow;
};
QWinRTEGLContext::QWinRTEGLContext(QOpenGLContext *context)
@ -70,8 +69,6 @@ QWinRTEGLContext::QWinRTEGLContext(QOpenGLContext *context)
QWinRTEGLContext::~QWinRTEGLContext()
{
Q_D(QWinRTEGLContext);
foreach (const EGLSurface &surface, d->surfaceForWindow)
eglDestroySurface(d->eglDisplay, surface);
if (d->eglContext != EGL_NO_CONTEXT)
eglDestroyContext(d->eglDisplay, d->eglContext);
if (d->eglDisplay != EGL_NO_DISPLAY)
@ -112,23 +109,13 @@ bool QWinRTEGLContext::makeCurrent(QPlatformSurface *windowSurface)
Q_D(QWinRTEGLContext);
Q_ASSERT(windowSurface->surface()->surfaceType() == QSurface::OpenGLSurface);
EGLSurface surface = d->surfaceForWindow.value(windowSurface);
if (surface == EGL_NO_SURFACE) {
QWinRTWindow *window = static_cast<QWinRTWindow *>(windowSurface);
HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([this, d, window, &surface]() {
surface = eglCreateWindowSurface(d->eglDisplay, d->eglConfig,
reinterpret_cast<EGLNativeWindowType>(window->winId()),
nullptr);
if (surface == EGL_NO_SURFACE) {
qCritical("Failed to create EGL window surface: 0x%x", eglGetError());
return E_FAIL;
}
return S_OK;
});
if (FAILED(hr))
return false;
d->surfaceForWindow.insert(windowSurface, surface);
}
QWinRTWindow *window = static_cast<QWinRTWindow *>(windowSurface);
if (window->eglSurface() == EGL_NO_SURFACE)
window->createEglSurface(d->eglDisplay, d->eglConfig);
EGLSurface surface = window->eglSurface();
if (surface == EGL_NO_SURFACE)
return false;
const bool ok = eglMakeCurrent(d->eglDisplay, surface, surface, d->eglContext);
if (!ok) {
@ -153,7 +140,8 @@ void QWinRTEGLContext::swapBuffers(QPlatformSurface *windowSurface)
Q_D(QWinRTEGLContext);
Q_ASSERT(windowSurface->surface()->surfaceType() == QSurface::OpenGLSurface);
eglSwapBuffers(d->eglDisplay, d->surfaceForWindow.value(windowSurface));
const QWinRTWindow *window = static_cast<QWinRTWindow *>(windowSurface);
eglSwapBuffers(d->eglDisplay, window->eglSurface());
}
QSurfaceFormat QWinRTEGLContext::format() const

View File

@ -88,6 +88,8 @@ public:
QSurfaceFormat surfaceFormat;
QString windowTitle;
Qt::WindowState state;
EGLDisplay display;
EGLSurface surface;
ComPtr<ISwapChainPanel> swapChainPanel;
ComPtr<ICanvasStatics> canvas;
@ -100,6 +102,8 @@ QWinRTWindow::QWinRTWindow(QWindow *window)
{
Q_D(QWinRTWindow);
d->surface = EGL_NO_SURFACE;
d->display = EGL_NO_DISPLAY;
d->screen = static_cast<QWinRTScreen *>(screen());
setWindowFlags(window->flags());
setWindowState(window->windowState());
@ -170,6 +174,11 @@ QWinRTWindow::~QWinRTWindow()
return S_OK;
});
RETURN_VOID_IF_FAILED("Failed to completely destroy window resources, likely because the application is shutting down");
EGLBoolean value = eglDestroySurface(d->display, d->surface);
d->surface = EGL_NO_SURFACE;
if (value == EGL_FALSE)
qCritical("Failed to destroy EGL window surface: 0x%x", eglGetError());
}
QSurfaceFormat QWinRTWindow::format() const
@ -293,4 +302,26 @@ void QWinRTWindow::setWindowState(Qt::WindowState state)
d->state = state;
}
EGLSurface QWinRTWindow::eglSurface() const
{
Q_D(const QWinRTWindow);
return d->surface;
}
void QWinRTWindow::createEglSurface(EGLDisplay display, EGLConfig config)
{
Q_D(QWinRTWindow);
if (d->surface == EGL_NO_SURFACE) {
d->display = display;
QEventDispatcherWinRT::runOnXamlThread([this, d, display, config]() {
d->surface = eglCreateWindowSurface(display, config,
reinterpret_cast<EGLNativeWindowType>(winId()),
nullptr);
if (d->surface == EGL_NO_SURFACE)
qCritical("Failed to create EGL window surface: 0x%x", eglGetError());
return S_OK;
});
}
}
QT_END_NAMESPACE

View File

@ -39,6 +39,7 @@
#include <qpa/qplatformwindow.h>
#include <qpa/qwindowsysteminterface.h>
#include <EGL/egl.h>
QT_BEGIN_NAMESPACE
@ -63,6 +64,9 @@ public:
qreal devicePixelRatio() const Q_DECL_OVERRIDE;
void setWindowState(Qt::WindowState state) Q_DECL_OVERRIDE;
EGLSurface eglSurface() const;
void createEglSurface(EGLDisplay display, EGLConfig config);
private:
QScopedPointer<QWinRTWindowPrivate> d_ptr;
Q_DECLARE_PRIVATE(QWinRTWindow)