Fix crash when closing handles to asset file while any asset streaming task is active for asset from that file
This commit is contained in:
@@ -481,6 +481,10 @@ void Asset::InitAsVirtual()
|
||||
_isLoaded = true;
|
||||
}
|
||||
|
||||
void Asset::CancelStreaming()
|
||||
{
|
||||
}
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
void Asset::GetReferences(Array<Guid>& output) const
|
||||
|
||||
@@ -154,6 +154,11 @@ public:
|
||||
/// </summary>
|
||||
virtual void InitAsVirtual();
|
||||
|
||||
/// <summary>
|
||||
/// Cancels any asynchronous content streaming by this asset (eg. mesh data streaming into GPU memory). Will release any locks for asset storage container.
|
||||
/// </summary>
|
||||
virtual void CancelStreaming();
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -769,6 +769,11 @@ void Model::InitAsVirtual()
|
||||
BinaryAsset::InitAsVirtual();
|
||||
}
|
||||
|
||||
void Model::CancelStreaming()
|
||||
{
|
||||
CancelStreamingTasks();
|
||||
}
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
void Model::GetReferences(Array<Guid>& output) const
|
||||
@@ -849,6 +854,15 @@ Task* Model::CreateStreamingTask(int32 residency)
|
||||
return result;
|
||||
}
|
||||
|
||||
void Model::CancelStreamingTasks()
|
||||
{
|
||||
if (_streamingTask)
|
||||
{
|
||||
_streamingTask->Cancel();
|
||||
ASSERT_LOW_LAYER(_streamingTask == nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
Asset::LoadResult Model::load()
|
||||
{
|
||||
// Get header chunk
|
||||
|
||||
@@ -251,6 +251,7 @@ public:
|
||||
int32 GetLODsCount() const override;
|
||||
void GetMeshes(Array<MeshBase*>& meshes, int32 lodIndex = 0) override;
|
||||
void InitAsVirtual() override;
|
||||
void CancelStreaming() override;
|
||||
#if USE_EDITOR
|
||||
void GetReferences(Array<Guid>& output) const override;
|
||||
#endif
|
||||
@@ -262,6 +263,7 @@ public:
|
||||
bool CanBeUpdated() const override;
|
||||
Task* UpdateAllocation(int32 residency) override;
|
||||
Task* CreateStreamingTask(int32 residency) override;
|
||||
void CancelStreamingTasks() override;
|
||||
|
||||
protected:
|
||||
// [ModelBase]
|
||||
|
||||
@@ -760,6 +760,11 @@ void SkinnedModel::InitAsVirtual()
|
||||
BinaryAsset::InitAsVirtual();
|
||||
}
|
||||
|
||||
void SkinnedModel::CancelStreaming()
|
||||
{
|
||||
CancelStreamingTasks();
|
||||
}
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
void SkinnedModel::GetReferences(Array<Guid>& output) const
|
||||
@@ -840,6 +845,15 @@ Task* SkinnedModel::CreateStreamingTask(int32 residency)
|
||||
return result;
|
||||
}
|
||||
|
||||
void SkinnedModel::CancelStreamingTasks()
|
||||
{
|
||||
if (_streamingTask)
|
||||
{
|
||||
_streamingTask->Cancel();
|
||||
ASSERT_LOW_LAYER(_streamingTask == nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
Asset::LoadResult SkinnedModel::load()
|
||||
{
|
||||
// Get header chunk
|
||||
|
||||
@@ -273,6 +273,7 @@ public:
|
||||
int32 GetLODsCount() const override;
|
||||
void GetMeshes(Array<MeshBase*>& meshes, int32 lodIndex = 0) override;
|
||||
void InitAsVirtual() override;
|
||||
void CancelStreaming() override;
|
||||
#if USE_EDITOR
|
||||
void GetReferences(Array<Guid>& output) const override;
|
||||
#endif
|
||||
@@ -284,6 +285,7 @@ public:
|
||||
bool CanBeUpdated() const override;
|
||||
Task* UpdateAllocation(int32 residency) override;
|
||||
Task* CreateStreamingTask(int32 residency) override;
|
||||
void CancelStreamingTasks() override;
|
||||
|
||||
protected:
|
||||
// [ModelBase]
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include "Engine/Platform/File.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Serialization/FileWriteStream.h"
|
||||
#include "Engine/Content/Asset.h"
|
||||
#include "Engine/Content/Content.h"
|
||||
#include "Engine/Threading/Threading.h"
|
||||
#if USE_EDITOR
|
||||
#include "Engine/Serialization/JsonWriter.h"
|
||||
@@ -1289,9 +1291,24 @@ void FlaxStorage::CloseFileHandles()
|
||||
// In those situations all the async tasks using this storage should be cancelled externally
|
||||
|
||||
// Ensure that no one is using this resource
|
||||
int32 waitTime = 500;
|
||||
int32 waitTime = 10;
|
||||
while (Platform::AtomicRead(&_chunksLock) != 0 && waitTime-- > 0)
|
||||
Platform::Sleep(10);
|
||||
if (Platform::AtomicRead(&_chunksLock) != 0)
|
||||
{
|
||||
// File can be locked by some streaming tasks (eg. AudioClip::StreamingTask or StreamModelLODTask)
|
||||
for (int32 i = 0; i < GetEntriesCount(); i++)
|
||||
{
|
||||
Entry e;
|
||||
GetEntry(i, e);
|
||||
Asset* asset = Content::GetAsset(e.ID);
|
||||
if (asset)
|
||||
{
|
||||
LOG(Info, "Canceling streaming for asset {0}", asset->ToString());
|
||||
asset->CancelStreaming();
|
||||
}
|
||||
}
|
||||
}
|
||||
ASSERT(_chunksLock == 0);
|
||||
|
||||
_file.DeleteAll();
|
||||
|
||||
Reference in New Issue
Block a user