Fix deadlock in scene loading

#1761 #1773
This commit is contained in:
Wojtek Figat
2023-10-24 14:08:34 +02:00
parent ba374a27db
commit 806590d1c3
4 changed files with 9 additions and 45 deletions

View File

@@ -416,7 +416,7 @@ public:
}
// Load scene
if (Level::loadScene(SceneAsset.Get()))
if (Level::loadScene(SceneAsset))
{
LOG(Error, "Failed to deserialize scene {0}", SceneId);
CallSceneEvent(SceneEventType::OnSceneLoadError, nullptr, SceneId);
@@ -816,40 +816,10 @@ bool LevelImpl::unloadScenes()
return false;
}
bool Level::loadScene(const Guid& sceneId)
{
const auto sceneAsset = Content::LoadAsync<JsonAsset>(sceneId);
return loadScene(sceneAsset);
}
bool Level::loadScene(const String& scenePath)
{
LOG(Info, "Loading scene from file. Path: \'{0}\'", scenePath);
// Check for missing file
if (!FileSystem::FileExists(scenePath))
{
LOG(Error, "Missing scene file.");
return true;
}
// Load file
BytesContainer sceneData;
if (File::ReadAllBytes(scenePath, sceneData))
{
LOG(Error, "Cannot load data from file.");
return true;
}
return loadScene(sceneData);
}
bool Level::loadScene(JsonAsset* sceneAsset)
{
// Keep reference to the asset (prevent unloading during action)
AssetReference<JsonAsset> ref = sceneAsset;
// Wait for loaded
if (sceneAsset == nullptr || sceneAsset->WaitForLoaded())
{
LOG(Error, "Cannot load scene asset.");
@@ -879,6 +849,7 @@ bool Level::loadScene(const BytesContainer& sceneData, Scene** outScene)
return true;
}
ScopeLock lock(ScenesLock);
return loadScene(document, outScene);
}
@@ -1332,6 +1303,7 @@ bool Level::LoadScene(const Guid& id)
}
// Load scene
ScopeLock lock(ScenesLock);
if (loadScene(sceneAsset))
{
LOG(Error, "Failed to deserialize scene {0}", id);

View File

@@ -541,8 +541,8 @@ private:
};
static void callActorEvent(ActorEventType eventType, Actor* a, Actor* b);
static bool loadScene(const Guid& sceneId);
static bool loadScene(const String& scenePath);
// All loadScene assume that ScenesLock has been taken by the calling thread
static bool loadScene(JsonAsset* sceneAsset);
static bool loadScene(const BytesContainer& sceneData, Scene** outScene = nullptr);
static bool loadScene(rapidjson_flax::Document& document, Scene** outScene = nullptr);

View File

@@ -280,9 +280,9 @@ void SceneObjectsFactory::HandleObjectDeserializationError(const ISerializable::
#if USE_EDITOR
// Add dummy script
auto* dummyScript = parent->AddScript<MissingScript>();
const auto parentIdMember = value.FindMember("TypeName");
if (parentIdMember != value.MemberEnd() && parentIdMember->value.IsString())
dummyScript->MissingTypeName = parentIdMember->value.GetString();
const auto typeNameMember = value.FindMember("TypeName");
if (typeNameMember != value.MemberEnd() && typeNameMember->value.IsString())
dummyScript->MissingTypeName = typeNameMember->value.GetString();
dummyScript->Data = MoveTemp(bufferStr);
#endif
LOG(Warning, "Parent actor of the missing object: {0}", parent->GetName());

View File

@@ -16,16 +16,13 @@ class FLAXENGINE_API Win32CriticalSection
friend Win32ConditionVariable;
private:
mutable Windows::CRITICAL_SECTION _criticalSection;
private:
Win32CriticalSection(const Win32CriticalSection&);
Win32CriticalSection& operator=(const Win32CriticalSection&);
public:
/// <summary>
/// Initializes a new instance of the <see cref="Win32CriticalSection"/> class.
/// </summary>
@@ -43,17 +40,12 @@ public:
}
public:
/// <summary>
/// Locks the critical section.
/// </summary>
void Lock() const
{
// Spin first before entering critical section, causing ring-0 transition and context switch
if (Windows::TryEnterCriticalSection(&_criticalSection) == 0)
{
Windows::EnterCriticalSection(&_criticalSection);
}
Windows::EnterCriticalSection(&_criticalSection);
}
/// <summary>