wasm: controlled screen destruction

Freeing OpenGL resources requires a current context,
which (on wasm) requires a screen.

Add a destroy() functions to QWasmScreen, QWasmCompositor, QWasmWindow,
and QWasmBackingStore which facilitates OpenGL cleanup before we start
deleting screen objects.

Task-number: QTBUG-75463
Change-Id: I9954b536416b9147965c74459ccad838d1578778
Reviewed-by: Lorn Potter <lorn.potter@gmail.com>
This commit is contained in:
Morten Johan Sørvig 2019-04-29 00:35:42 +02:00 committed by Jani Heikkinen
parent 4e0f262892
commit c8c4819b7b
9 changed files with 51 additions and 3 deletions

View File

@ -55,6 +55,12 @@ QWasmBackingStore::~QWasmBackingStore()
{ {
} }
void QWasmBackingStore::destroy()
{
if (m_texture->isCreated())
m_texture->destroy();
}
QPaintDevice *QWasmBackingStore::paintDevice() QPaintDevice *QWasmBackingStore::paintDevice()
{ {
return &m_image; return &m_image;

View File

@ -44,6 +44,7 @@ class QWasmBackingStore : public QPlatformBackingStore
public: public:
QWasmBackingStore(QWasmCompositor *compositor, QWindow *window); QWasmBackingStore(QWasmCompositor *compositor, QWindow *window);
~QWasmBackingStore(); ~QWasmBackingStore();
void destroy();
QPaintDevice *paintDevice() override; QPaintDevice *paintDevice() override;

View File

@ -37,6 +37,7 @@
#include <QtGui/qopenglcontext.h> #include <QtGui/qopenglcontext.h>
#include <QtGui/qopenglfunctions.h> #include <QtGui/qopenglfunctions.h>
#include <QtGui/qopengltextureblitter.h> #include <QtGui/qopengltextureblitter.h>
#include <QtGui/qoffscreensurface.h>
#include <QtGui/qpainter.h> #include <QtGui/qpainter.h>
#include <private/qpixmapcache_p.h> #include <private/qpixmapcache_p.h>
@ -71,6 +72,28 @@ QWasmCompositor::QWasmCompositor(QWasmScreen *screen)
QWasmCompositor::~QWasmCompositor() QWasmCompositor::~QWasmCompositor()
{ {
delete m_frameBuffer; delete m_frameBuffer;
destroy();
}
void QWasmCompositor::destroy()
{
// Destroy OpenGL resources. This is done here in a separate function
// which can be called while screen() still returns a valid screen
// (which it might not, during destruction). A valid QScreen is
// a requirement for QOffscreenSurface on Wasm since the native
// context is tied to a single canvas.
if (m_context) {
QOffscreenSurface offScreenSurface(screen()->screen());
offScreenSurface.setFormat(m_context->format());
offScreenSurface.create();
m_context->makeCurrent(&offScreenSurface);
for (QWasmWindow *window : m_windowStack)
window->destroy();
m_blitter.reset(nullptr);
m_context.reset(nullptr);
}
m_isEnabled = false; // prevent frame() from creating a new m_context
} }
void QWasmCompositor::setEnabled(bool enabled) void QWasmCompositor::setEnabled(bool enabled)
@ -653,7 +676,7 @@ void QWasmCompositor::frame()
m_needComposit = false; m_needComposit = false;
if (m_windowStack.empty() || !screen()) if (!m_isEnabled || m_windowStack.empty() || !screen())
return; return;
QWasmWindow *someWindow = nullptr; QWasmWindow *someWindow = nullptr;
@ -676,7 +699,9 @@ void QWasmCompositor::frame()
m_context->create(); m_context->create();
} }
m_context->makeCurrent(someWindow->window()); bool ok = m_context->makeCurrent(someWindow->window());
if (!ok)
return;
if (!m_blitter->isCreated()) if (!m_blitter->isCreated())
m_blitter->create(); m_blitter->create();

View File

@ -64,6 +64,7 @@ class QWasmCompositor : public QObject
public: public:
QWasmCompositor(QWasmScreen *screen); QWasmCompositor(QWasmScreen *screen);
~QWasmCompositor(); ~QWasmCompositor();
void destroy();
enum QWasmSubControl { enum QWasmSubControl {
SC_None = 0x00000000, SC_None = 0x00000000,

View File

@ -258,7 +258,9 @@ void QWasmIntegration::addScreen(const QString &canvasId)
void QWasmIntegration::removeScreen(const QString &canvasId) void QWasmIntegration::removeScreen(const QString &canvasId)
{ {
QWindowSystemInterface::handleScreenRemoved(m_screens.take(canvasId)); QWasmScreen *exScreen = m_screens.take(canvasId);
exScreen->destroy(); // clean up before deleting the screen
QWindowSystemInterface::handleScreenRemoved(exScreen);
} }
void QWasmIntegration::resizeScreen(const QString &canvasId) void QWasmIntegration::resizeScreen(const QString &canvasId)

View File

@ -57,7 +57,12 @@ QWasmScreen::QWasmScreen(const QString &canvasId)
QWasmScreen::~QWasmScreen() QWasmScreen::~QWasmScreen()
{ {
destroy();
}
void QWasmScreen::destroy()
{
m_compositor->destroy();
} }
QWasmScreen *QWasmScreen::get(QPlatformScreen *screen) QWasmScreen *QWasmScreen::get(QPlatformScreen *screen)

View File

@ -52,6 +52,7 @@ class QWasmScreen : public QObject, public QPlatformScreen
public: public:
QWasmScreen(const QString &canvasId); QWasmScreen(const QString &canvasId);
~QWasmScreen(); ~QWasmScreen();
void destroy();
static QWasmScreen *get(QPlatformScreen *screen); static QWasmScreen *get(QPlatformScreen *screen);
static QWasmScreen *get(QScreen *screen); static QWasmScreen *get(QScreen *screen);

View File

@ -65,6 +65,12 @@ QWasmWindow::~QWasmWindow()
m_compositor->removeWindow(this); m_compositor->removeWindow(this);
} }
void QWasmWindow::destroy()
{
if (m_backingStore)
m_backingStore->destroy();
}
void QWasmWindow::initialize() void QWasmWindow::initialize()
{ {
QRect rect = windowGeometry(); QRect rect = windowGeometry();

View File

@ -58,6 +58,7 @@ public:
QWasmWindow(QWindow *w, QWasmCompositor *compositor, QWasmBackingStore *backingStore); QWasmWindow(QWindow *w, QWasmCompositor *compositor, QWasmBackingStore *backingStore);
~QWasmWindow(); ~QWasmWindow();
void destroy();
void initialize() override; void initialize() override;