mirror of
https://github.com/overte-org/overte.git
synced 2025-08-06 19:59:28 +02:00
Destroy render scene & engine before Application is destroyed
Many render items/payloads contain smart pointers back to the objects that added them to the scene, including entity and avatar objects. Currently, those render items are destroyed when the scene is destroyed very late in the application life-cycle. There are rare crashes that can occur when these render items are destroyed. Possibly, due to them referencing objects that have already been destroyed via raw pointers. In an effort to eliminate these crashes, we now destroy the scene earlier, within Application::aboutToQuit() which is connected to the QCoreApplication::aboutToQuit signal. Also, we guard against null scene pointer dereferences. Any location that accesses the scene off the main thread, now checks the validity of the scene pointer.
This commit is contained in:
parent
2b2b55aab0
commit
23aa626755
8 changed files with 62 additions and 23 deletions
|
@ -1576,6 +1576,12 @@ void Application::cleanupBeforeQuit() {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
DependencyManager::destroy<OffscreenUi>();
|
DependencyManager::destroy<OffscreenUi>();
|
||||||
|
|
||||||
|
// shutdown render engine
|
||||||
|
_main3DScene = nullptr;
|
||||||
|
_renderEngine = nullptr;
|
||||||
|
|
||||||
|
qCDebug(interfaceapp) << "Application::cleanupBeforeQuit() complete";
|
||||||
}
|
}
|
||||||
|
|
||||||
Application::~Application() {
|
Application::~Application() {
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include "Avatar.h"
|
#include "Avatar.h"
|
||||||
#include "AvatarManager.h"
|
#include "AvatarManager.h"
|
||||||
|
#include "InterfaceLogging.h"
|
||||||
#include "Menu.h"
|
#include "Menu.h"
|
||||||
#include "MyAvatar.h"
|
#include "MyAvatar.h"
|
||||||
#include "SceneScriptingInterface.h"
|
#include "SceneScriptingInterface.h"
|
||||||
|
@ -208,11 +209,15 @@ AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWe
|
||||||
auto rawRenderableAvatar = std::static_pointer_cast<Avatar>(newAvatar);
|
auto rawRenderableAvatar = std::static_pointer_cast<Avatar>(newAvatar);
|
||||||
|
|
||||||
render::ScenePointer scene = qApp->getMain3DScene();
|
render::ScenePointer scene = qApp->getMain3DScene();
|
||||||
render::PendingChanges pendingChanges;
|
if (scene) {
|
||||||
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderAvatars()) {
|
render::PendingChanges pendingChanges;
|
||||||
rawRenderableAvatar->addToScene(rawRenderableAvatar, scene, pendingChanges);
|
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderAvatars()) {
|
||||||
|
rawRenderableAvatar->addToScene(rawRenderableAvatar, scene, pendingChanges);
|
||||||
|
}
|
||||||
|
scene->enqueuePendingChanges(pendingChanges);
|
||||||
|
} else {
|
||||||
|
qCWarning(interfaceapp) << "AvatarManager::addAvatar() : Unexpected null scene, possibly during application shutdown";
|
||||||
}
|
}
|
||||||
scene->enqueuePendingChanges(pendingChanges);
|
|
||||||
|
|
||||||
return newAvatar;
|
return newAvatar;
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,11 +128,15 @@ void EntityTreeRenderer::clear() {
|
||||||
|
|
||||||
// remove all entities from the scene
|
// remove all entities from the scene
|
||||||
auto scene = _viewState->getMain3DScene();
|
auto scene = _viewState->getMain3DScene();
|
||||||
render::PendingChanges pendingChanges;
|
if (scene) {
|
||||||
foreach(auto entity, _entitiesInScene) {
|
render::PendingChanges pendingChanges;
|
||||||
entity->removeFromScene(entity, scene, pendingChanges);
|
foreach(auto entity, _entitiesInScene) {
|
||||||
|
entity->removeFromScene(entity, scene, pendingChanges);
|
||||||
|
}
|
||||||
|
scene->enqueuePendingChanges(pendingChanges);
|
||||||
|
} else {
|
||||||
|
qCWarning(entitiesrenderer) << "EntitityTreeRenderer::clear(), Unexpected null scene, possibly during application shutdown";
|
||||||
}
|
}
|
||||||
scene->enqueuePendingChanges(pendingChanges);
|
|
||||||
_entitiesInScene.clear();
|
_entitiesInScene.clear();
|
||||||
|
|
||||||
// reset the zone to the default (while we load the next scene)
|
// reset the zone to the default (while we load the next scene)
|
||||||
|
@ -901,8 +905,12 @@ void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) {
|
||||||
auto entity = _entitiesInScene.take(entityID);
|
auto entity = _entitiesInScene.take(entityID);
|
||||||
render::PendingChanges pendingChanges;
|
render::PendingChanges pendingChanges;
|
||||||
auto scene = _viewState->getMain3DScene();
|
auto scene = _viewState->getMain3DScene();
|
||||||
entity->removeFromScene(entity, scene, pendingChanges);
|
if (scene) {
|
||||||
scene->enqueuePendingChanges(pendingChanges);
|
entity->removeFromScene(entity, scene, pendingChanges);
|
||||||
|
scene->enqueuePendingChanges(pendingChanges);
|
||||||
|
} else {
|
||||||
|
qCWarning(entitiesrenderer) << "EntityTreeRenderer::deletingEntity(), Unexpected null scene, possibly during application shutdown";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -919,10 +927,14 @@ void EntityTreeRenderer::addEntityToScene(EntityItemPointer entity) {
|
||||||
// here's where we add the entity payload to the scene
|
// here's where we add the entity payload to the scene
|
||||||
render::PendingChanges pendingChanges;
|
render::PendingChanges pendingChanges;
|
||||||
auto scene = _viewState->getMain3DScene();
|
auto scene = _viewState->getMain3DScene();
|
||||||
if (entity->addToScene(entity, scene, pendingChanges)) {
|
if (scene) {
|
||||||
_entitiesInScene.insert(entity->getEntityItemID(), entity);
|
if (entity->addToScene(entity, scene, pendingChanges)) {
|
||||||
|
_entitiesInScene.insert(entity->getEntityItemID(), entity);
|
||||||
|
}
|
||||||
|
scene->enqueuePendingChanges(pendingChanges);
|
||||||
|
} else {
|
||||||
|
qCWarning(entitiesrenderer) << "EntityTreeRenderer::addEntityToScene(), Unexpected null scene, possibly during application shutdown";
|
||||||
}
|
}
|
||||||
scene->enqueuePendingChanges(pendingChanges);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <render/Scene.h>
|
#include <render/Scene.h>
|
||||||
#include <EntityItem.h>
|
#include <EntityItem.h>
|
||||||
#include "AbstractViewStateInterface.h"
|
#include "AbstractViewStateInterface.h"
|
||||||
|
#include "EntitiesRendererLogging.h"
|
||||||
|
|
||||||
|
|
||||||
// These or the icon "name" used by the render item status value, they correspond to the atlas texture used by the DrawItemStatus
|
// These or the icon "name" used by the render item status value, they correspond to the atlas texture used by the DrawItemStatus
|
||||||
|
@ -79,10 +80,14 @@ public:
|
||||||
render::PendingChanges pendingChanges;
|
render::PendingChanges pendingChanges;
|
||||||
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
|
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
|
||||||
|
|
||||||
pendingChanges.updateItem<RenderableEntityItemProxy>(_myItem, [](RenderableEntityItemProxy& data) {
|
if (scene) {
|
||||||
});
|
pendingChanges.updateItem<RenderableEntityItemProxy>(_myItem, [](RenderableEntityItemProxy& data) {
|
||||||
|
});
|
||||||
|
|
||||||
scene->enqueuePendingChanges(pendingChanges);
|
scene->enqueuePendingChanges(pendingChanges);
|
||||||
|
} else {
|
||||||
|
qCWarning(entitiesrenderer) << "SimpleRenderableEntityItem::notifyChanged(), Unexpected null scene, possibly during application shutdown";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -248,9 +248,12 @@ void RenderableZoneEntityItem::notifyBoundChanged() {
|
||||||
}
|
}
|
||||||
render::PendingChanges pendingChanges;
|
render::PendingChanges pendingChanges;
|
||||||
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
|
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
|
||||||
|
if (scene) {
|
||||||
|
pendingChanges.updateItem<RenderableZoneEntityItemMeta>(_myMetaItem, [](RenderableZoneEntityItemMeta& data) {
|
||||||
|
});
|
||||||
|
|
||||||
pendingChanges.updateItem<RenderableZoneEntityItemMeta>(_myMetaItem, [](RenderableZoneEntityItemMeta& data) {
|
scene->enqueuePendingChanges(pendingChanges);
|
||||||
});
|
} else {
|
||||||
|
qCWarning(entitiesrenderer) << "RenderableZoneEntityItem::notifyBoundChanged(), Unexpected null scene, possibly during application shutdown";
|
||||||
scene->enqueuePendingChanges(pendingChanges);
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -862,8 +862,12 @@ void Model::setURL(const QUrl& url) {
|
||||||
{
|
{
|
||||||
render::PendingChanges pendingChanges;
|
render::PendingChanges pendingChanges;
|
||||||
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
|
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
|
||||||
removeFromScene(scene, pendingChanges);
|
if (scene) {
|
||||||
scene->enqueuePendingChanges(pendingChanges);
|
removeFromScene(scene, pendingChanges);
|
||||||
|
scene->enqueuePendingChanges(pendingChanges);
|
||||||
|
} else {
|
||||||
|
qCWarning(renderutils) << "Model::setURL(), Unexpected null scene, possibly during application shutdown";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_needsReload = true;
|
_needsReload = true;
|
||||||
|
|
|
@ -48,6 +48,10 @@ Scene::Scene(glm::vec3 origin, float size) :
|
||||||
_items.push_back(Item()); // add the itemID #0 to nothing
|
_items.push_back(Item()); // add the itemID #0 to nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Scene::~Scene() {
|
||||||
|
qDebug() << "Scene::~Scene()";
|
||||||
|
}
|
||||||
|
|
||||||
ItemID Scene::allocateID() {
|
ItemID Scene::allocateID() {
|
||||||
// Just increment and return the proevious value initialized at 0
|
// Just increment and return the proevious value initialized at 0
|
||||||
return _IDAllocator.fetch_add(1);
|
return _IDAllocator.fetch_add(1);
|
||||||
|
|
|
@ -55,7 +55,7 @@ typedef std::queue<PendingChanges> PendingChangesQueue;
|
||||||
class Scene {
|
class Scene {
|
||||||
public:
|
public:
|
||||||
Scene(glm::vec3 origin, float size);
|
Scene(glm::vec3 origin, float size);
|
||||||
~Scene() {}
|
~Scene();
|
||||||
|
|
||||||
// This call is thread safe, can be called from anywhere to allocate a new ID
|
// This call is thread safe, can be called from anywhere to allocate a new ID
|
||||||
ItemID allocateID();
|
ItemID allocateID();
|
||||||
|
|
Loading…
Reference in a new issue