Fix crash on destroying web entities and overlays

This commit is contained in:
Brad Davis 2016-10-03 16:42:50 -07:00
parent ca3572f991
commit 8c5028158f
5 changed files with 35 additions and 21 deletions

View file

@ -73,7 +73,12 @@ void Web3DOverlay::render(RenderArgs* args) {
QOpenGLContext * currentContext = QOpenGLContext::currentContext(); QOpenGLContext * currentContext = QOpenGLContext::currentContext();
QSurface * currentSurface = currentContext->surface(); QSurface * currentSurface = currentContext->surface();
if (!_webSurface) { if (!_webSurface) {
_webSurface = new OffscreenQmlSurface(); auto deleter = [](OffscreenQmlSurface* webSurface) {
AbstractViewStateInterface::instance()->postLambdaEvent([webSurface] {
webSurface->deleteLater();
});
};
_webSurface = QSharedPointer<OffscreenQmlSurface>(new OffscreenQmlSurface(), deleter);
_webSurface->create(currentContext); _webSurface->create(currentContext);
_webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/controls/")); _webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/controls/"));
_webSurface->load("WebView.qml"); _webSurface->load("WebView.qml");
@ -95,8 +100,9 @@ void Web3DOverlay::render(RenderArgs* args) {
} }
if (!_texture) { if (!_texture) {
_texture = gpu::TexturePointer(gpu::Texture::createExternal2D([this](uint32_t recycleTexture, void* recycleFence) { auto webSurface = _webSurface;
_webSurface->releaseTexture({ recycleTexture, recycleFence }); _texture = gpu::TexturePointer(gpu::Texture::createExternal2D([webSurface](uint32_t recycleTexture, void* recycleFence) {
webSurface->releaseTexture({ recycleTexture, recycleFence });
})); }));
_texture->setSource(__FUNCTION__); _texture->setSource(__FUNCTION__);
} }

View file

@ -41,7 +41,7 @@ public:
virtual Web3DOverlay* createClone() const override; virtual Web3DOverlay* createClone() const override;
private: private:
OffscreenQmlSurface* _webSurface{ nullptr }; QSharedPointer<OffscreenQmlSurface> _webSurface;
QMetaObject::Connection _connection; QMetaObject::Connection _connection;
gpu::TexturePointer _texture; gpu::TexturePointer _texture;
QString _url; QString _url;

View file

@ -129,7 +129,19 @@ bool RenderableWebEntityItem::buildWebSurface(EntityTreeRenderer* renderer) {
// Save the original GL context, because creating a QML surface will create a new context // Save the original GL context, because creating a QML surface will create a new context
QOpenGLContext * currentContext = QOpenGLContext::currentContext(); QOpenGLContext * currentContext = QOpenGLContext::currentContext();
QSurface * currentSurface = currentContext->surface(); QSurface * currentSurface = currentContext->surface();
_webSurface = new OffscreenQmlSurface();
auto deleter = [](OffscreenQmlSurface* webSurface) {
AbstractViewStateInterface::instance()->postLambdaEvent([webSurface] {
webSurface->deleteLater();
});
};
_webSurface = QSharedPointer<OffscreenQmlSurface>(new OffscreenQmlSurface(), deleter);
// The lifetime of the QML surface MUST be managed by the main thread
// Additionally, we MUST use local variables copied by value, rather than
// member variables, since they would implicitly refer to a this that
// is no longer valid
_webSurface->create(currentContext); _webSurface->create(currentContext);
_webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/controls/")); _webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/controls/"));
_webSurface->load("WebView.qml", [&](QQmlContext* context, QObject* obj) { _webSurface->load("WebView.qml", [&](QQmlContext* context, QObject* obj) {
@ -215,9 +227,11 @@ void RenderableWebEntityItem::render(RenderArgs* args) {
_webSurface->resize(QSize(windowSize.x, windowSize.y)); _webSurface->resize(QSize(windowSize.x, windowSize.y));
if (!_texture) { if (!_texture) {
_texture = gpu::TexturePointer(gpu::Texture::createExternal2D([this](uint32_t recycleTexture, void* recycleFence) { auto webSurface = _webSurface;
_webSurface->releaseTexture({ recycleTexture, recycleFence }); auto recycler = [webSurface] (uint32_t recycleTexture, void* recycleFence) {
})); webSurface->releaseTexture({ recycleTexture, recycleFence });
};
_texture = gpu::TexturePointer(gpu::Texture::createExternal2D(recycler));
_texture->setSource(__FUNCTION__); _texture->setSource(__FUNCTION__);
} }
OffscreenQmlSurface::TextureAndFence newTextureAndFence; OffscreenQmlSurface::TextureAndFence newTextureAndFence;
@ -352,16 +366,7 @@ void RenderableWebEntityItem::destroyWebSurface() {
_mouseMoveConnection = QMetaObject::Connection(); _mouseMoveConnection = QMetaObject::Connection();
QObject::disconnect(_hoverLeaveConnection); QObject::disconnect(_hoverLeaveConnection);
_hoverLeaveConnection = QMetaObject::Connection(); _hoverLeaveConnection = QMetaObject::Connection();
_webSurface.reset();
// The lifetime of the QML surface MUST be managed by the main thread
// Additionally, we MUST use local variables copied by value, rather than
// member variables, since they would implicitly refer to a this that
// is no longer valid
auto webSurface = _webSurface;
AbstractViewStateInterface::instance()->postLambdaEvent([webSurface] {
webSurface->deleteLater();
});
_webSurface = nullptr;
} }
} }

View file

@ -78,7 +78,7 @@ private:
void destroyWebSurface(); void destroyWebSurface();
glm::vec2 getWindowSize() const; glm::vec2 getWindowSize() const;
OffscreenQmlSurface* _webSurface{ nullptr }; QSharedPointer<OffscreenQmlSurface> _webSurface;
QMetaObject::Connection _connection; QMetaObject::Connection _connection;
gpu::TexturePointer _texture; gpu::TexturePointer _texture;
ivec2 _lastPress { INT_MIN }; ivec2 _lastPress { INT_MIN };

View file

@ -182,8 +182,11 @@ GLTexture::~GLTexture() {
if (backend) { if (backend) {
if (_external) { if (_external) {
auto recycler = _gpuObject.getExternalRecycler(); auto recycler = _gpuObject.getExternalRecycler();
assert(recycler); if (recycler) {
backend->releaseExternalTexture(_id, recycler); backend->releaseExternalTexture(_id, recycler);
} else {
qWarning() << "No recycler available for texture " << _id << " possible leak";
}
} else if (_id) { } else if (_id) {
backend->releaseTexture(_id, _size); backend->releaseTexture(_id, _size);
} }