mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-15 07:56:22 +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
|
||||
|
||||
DependencyManager::destroy<OffscreenUi>();
|
||||
|
||||
// shutdown render engine
|
||||
_main3DScene = nullptr;
|
||||
_renderEngine = nullptr;
|
||||
|
||||
qCDebug(interfaceapp) << "Application::cleanupBeforeQuit() complete";
|
||||
}
|
||||
|
||||
Application::~Application() {
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "Application.h"
|
||||
#include "Avatar.h"
|
||||
#include "AvatarManager.h"
|
||||
#include "InterfaceLogging.h"
|
||||
#include "Menu.h"
|
||||
#include "MyAvatar.h"
|
||||
#include "SceneScriptingInterface.h"
|
||||
|
@ -208,11 +209,15 @@ AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWe
|
|||
auto rawRenderableAvatar = std::static_pointer_cast<Avatar>(newAvatar);
|
||||
|
||||
render::ScenePointer scene = qApp->getMain3DScene();
|
||||
render::PendingChanges pendingChanges;
|
||||
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderAvatars()) {
|
||||
rawRenderableAvatar->addToScene(rawRenderableAvatar, scene, pendingChanges);
|
||||
if (scene) {
|
||||
render::PendingChanges 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;
|
||||
}
|
||||
|
|
|
@ -128,11 +128,15 @@ void EntityTreeRenderer::clear() {
|
|||
|
||||
// remove all entities from the scene
|
||||
auto scene = _viewState->getMain3DScene();
|
||||
render::PendingChanges pendingChanges;
|
||||
foreach(auto entity, _entitiesInScene) {
|
||||
entity->removeFromScene(entity, scene, pendingChanges);
|
||||
if (scene) {
|
||||
render::PendingChanges 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();
|
||||
|
||||
// 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);
|
||||
render::PendingChanges pendingChanges;
|
||||
auto scene = _viewState->getMain3DScene();
|
||||
entity->removeFromScene(entity, scene, pendingChanges);
|
||||
scene->enqueuePendingChanges(pendingChanges);
|
||||
if (scene) {
|
||||
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
|
||||
render::PendingChanges pendingChanges;
|
||||
auto scene = _viewState->getMain3DScene();
|
||||
if (entity->addToScene(entity, scene, pendingChanges)) {
|
||||
_entitiesInScene.insert(entity->getEntityItemID(), entity);
|
||||
if (scene) {
|
||||
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 <EntityItem.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
|
||||
|
@ -79,10 +80,14 @@ public:
|
|||
render::PendingChanges pendingChanges;
|
||||
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:
|
||||
|
|
|
@ -248,9 +248,12 @@ void RenderableZoneEntityItem::notifyBoundChanged() {
|
|||
}
|
||||
render::PendingChanges pendingChanges;
|
||||
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
|
||||
if (scene) {
|
||||
pendingChanges.updateItem<RenderableZoneEntityItemMeta>(_myMetaItem, [](RenderableZoneEntityItemMeta& data) {
|
||||
});
|
||||
|
||||
pendingChanges.updateItem<RenderableZoneEntityItemMeta>(_myMetaItem, [](RenderableZoneEntityItemMeta& data) {
|
||||
});
|
||||
|
||||
scene->enqueuePendingChanges(pendingChanges);
|
||||
scene->enqueuePendingChanges(pendingChanges);
|
||||
} else {
|
||||
qCWarning(entitiesrenderer) << "RenderableZoneEntityItem::notifyBoundChanged(), Unexpected null scene, possibly during application shutdown";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -862,8 +862,12 @@ void Model::setURL(const QUrl& url) {
|
|||
{
|
||||
render::PendingChanges pendingChanges;
|
||||
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
|
||||
removeFromScene(scene, pendingChanges);
|
||||
scene->enqueuePendingChanges(pendingChanges);
|
||||
if (scene) {
|
||||
removeFromScene(scene, pendingChanges);
|
||||
scene->enqueuePendingChanges(pendingChanges);
|
||||
} else {
|
||||
qCWarning(renderutils) << "Model::setURL(), Unexpected null scene, possibly during application shutdown";
|
||||
}
|
||||
}
|
||||
|
||||
_needsReload = true;
|
||||
|
|
|
@ -48,6 +48,10 @@ Scene::Scene(glm::vec3 origin, float size) :
|
|||
_items.push_back(Item()); // add the itemID #0 to nothing
|
||||
}
|
||||
|
||||
Scene::~Scene() {
|
||||
qDebug() << "Scene::~Scene()";
|
||||
}
|
||||
|
||||
ItemID Scene::allocateID() {
|
||||
// Just increment and return the proevious value initialized at 0
|
||||
return _IDAllocator.fetch_add(1);
|
||||
|
|
|
@ -55,7 +55,7 @@ typedef std::queue<PendingChanges> PendingChangesQueue;
|
|||
class Scene {
|
||||
public:
|
||||
Scene(glm::vec3 origin, float size);
|
||||
~Scene() {}
|
||||
~Scene();
|
||||
|
||||
// This call is thread safe, can be called from anywhere to allocate a new ID
|
||||
ItemID allocateID();
|
||||
|
|
Loading…
Reference in a new issue