Optimize Asset::GetPath in cooked build
This commit is contained in:
@@ -127,7 +127,7 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the path to the asset storage file. In Editor, it reflects the actual file, in cooked Game, it fakes the Editor path to be informative for developers.
|
||||
/// </summary>
|
||||
API_PROPERTY() virtual const String& GetPath() const = 0;
|
||||
API_PROPERTY() virtual StringView GetPath() const = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the asset type name.
|
||||
|
||||
@@ -619,7 +619,7 @@ Asset::LoadResult Model::load()
|
||||
{
|
||||
String name;
|
||||
#if !BUILD_RELEASE
|
||||
name = GetPath() + TEXT(".SDF");
|
||||
name = String(GetPath()) + TEXT(".SDF");
|
||||
#endif
|
||||
SDF.Texture = GPUDevice::Instance->CreateTexture(name);
|
||||
}
|
||||
|
||||
@@ -464,10 +464,10 @@ void BinaryAsset::OnDeleteObject()
|
||||
|
||||
#endif
|
||||
|
||||
const String& BinaryAsset::GetPath() const
|
||||
StringView BinaryAsset::GetPath() const
|
||||
{
|
||||
#if USE_EDITOR
|
||||
return Storage ? Storage->GetPath() : String::Empty;
|
||||
return Storage ? Storage->GetPath() : StringView::Empty;
|
||||
#else
|
||||
// In build all assets are packed into packages so use ID for original path lookup
|
||||
return Content::GetRegistry()->GetEditorAssetPath(_id);
|
||||
|
||||
@@ -292,7 +292,7 @@ public:
|
||||
#if USE_EDITOR
|
||||
void OnDeleteObject() override;
|
||||
#endif
|
||||
const String& GetPath() const final override;
|
||||
StringView GetPath() const final override;
|
||||
uint64 GetMemoryUsage() const override;
|
||||
|
||||
protected:
|
||||
|
||||
@@ -10,12 +10,24 @@
|
||||
#include "Engine/Serialization/FileWriteStream.h"
|
||||
#include "Engine/Serialization/FileReadStream.h"
|
||||
#include "Engine/Content/Content.h"
|
||||
#include "Engine/Content/Storage/ContentStorageManager.h"
|
||||
#include "Engine/Content/Storage/JsonStorageProxy.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Threading/Threading.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include "FlaxEngine.Gen.h"
|
||||
#if ASSETS_CACHE_EDITABLE
|
||||
#include "Engine/Content/Storage/ContentStorageManager.h"
|
||||
#include "Engine/Content/Storage/JsonStorageProxy.h"
|
||||
#include "Engine/Threading/Threading.h"
|
||||
#define ASSETS_CACHE_LOCK() ScopeLock lock(_locker)
|
||||
#else
|
||||
#define ASSETS_CACHE_LOCK()
|
||||
#endif
|
||||
|
||||
int32 AssetsCache::Size() const
|
||||
{
|
||||
ASSETS_CACHE_LOCK();
|
||||
const int32 result = _registry.Count();
|
||||
return result;
|
||||
}
|
||||
|
||||
void AssetsCache::Init()
|
||||
{
|
||||
@@ -72,7 +84,7 @@ void AssetsCache::Init()
|
||||
return;
|
||||
}
|
||||
|
||||
ScopeLock lock(_locker);
|
||||
ASSETS_CACHE_LOCK();
|
||||
_isDirty = false;
|
||||
|
||||
// Load elements count
|
||||
@@ -127,6 +139,16 @@ void AssetsCache::Init()
|
||||
_pathsMapping.Add(mappedPath, id);
|
||||
}
|
||||
|
||||
#if !USE_EDITOR && !BUILD_RELEASE
|
||||
// Build inverse path mapping in development builds for faster GetEditorAssetPath (eg. used by PROFILE_CPU_ASSET)
|
||||
_pathsMappingInv.Clear();
|
||||
_pathsMappingInv.EnsureCapacity(count);
|
||||
for (auto& mapping : _pathsMapping)
|
||||
{
|
||||
_pathsMappingInv.Add(mapping.Value, StringView(mapping.Key));
|
||||
}
|
||||
#endif
|
||||
|
||||
// Check errors
|
||||
const bool hasError = stream->HasError();
|
||||
deleteStream.Delete();
|
||||
@@ -154,7 +176,7 @@ bool AssetsCache::Save()
|
||||
if (!_isDirty && FileSystem::FileExists(_path))
|
||||
return false;
|
||||
|
||||
ScopeLock lock(_locker);
|
||||
ASSETS_CACHE_LOCK();
|
||||
|
||||
if (Save(_path, _registry, _pathsMapping))
|
||||
return true;
|
||||
@@ -223,12 +245,16 @@ bool AssetsCache::Save(const StringView& path, const Registry& entries, const Pa
|
||||
return false;
|
||||
}
|
||||
|
||||
const String& AssetsCache::GetEditorAssetPath(const Guid& id) const
|
||||
StringView AssetsCache::GetEditorAssetPath(const Guid& id) const
|
||||
{
|
||||
ScopeLock lock(_locker);
|
||||
ASSETS_CACHE_LOCK();
|
||||
#if USE_EDITOR
|
||||
auto e = _registry.TryGet(id);
|
||||
return e ? e->Info.Path : String::Empty;
|
||||
#elif !BUILD_RELEASE
|
||||
StringView result;
|
||||
_pathsMappingInv.TryGet(id, result);
|
||||
return result;
|
||||
#else
|
||||
for (auto& e : _pathsMapping)
|
||||
{
|
||||
@@ -242,10 +268,8 @@ const String& AssetsCache::GetEditorAssetPath(const Guid& id) const
|
||||
bool AssetsCache::FindAsset(const StringView& path, AssetInfo& info)
|
||||
{
|
||||
PROFILE_CPU();
|
||||
|
||||
bool result = false;
|
||||
|
||||
ScopeLock lock(_locker);
|
||||
ASSETS_CACHE_LOCK();
|
||||
|
||||
// Check if asset has direct mapping to id (used for some cooked assets)
|
||||
Guid id;
|
||||
@@ -294,7 +318,7 @@ bool AssetsCache::FindAsset(const Guid& id, AssetInfo& info)
|
||||
{
|
||||
PROFILE_CPU();
|
||||
bool result = false;
|
||||
ScopeLock lock(_locker);
|
||||
ASSETS_CACHE_LOCK();
|
||||
auto e = _registry.TryGet(id);
|
||||
if (e != nullptr)
|
||||
{
|
||||
@@ -316,14 +340,14 @@ bool AssetsCache::FindAsset(const Guid& id, AssetInfo& info)
|
||||
void AssetsCache::GetAll(Array<Guid>& result) const
|
||||
{
|
||||
PROFILE_CPU();
|
||||
ScopeLock lock(_locker);
|
||||
ASSETS_CACHE_LOCK();
|
||||
_registry.GetKeys(result);
|
||||
}
|
||||
|
||||
void AssetsCache::GetAllByTypeName(const StringView& typeName, Array<Guid>& result) const
|
||||
{
|
||||
PROFILE_CPU();
|
||||
ScopeLock lock(_locker);
|
||||
ASSETS_CACHE_LOCK();
|
||||
for (auto i = _registry.Begin(); i.IsNotEnd(); ++i)
|
||||
{
|
||||
if (i->Value.Info.TypeName == typeName)
|
||||
@@ -331,6 +355,8 @@ void AssetsCache::GetAllByTypeName(const StringView& typeName, Array<Guid>& resu
|
||||
}
|
||||
}
|
||||
|
||||
#if ASSETS_CACHE_EDITABLE
|
||||
|
||||
void AssetsCache::RegisterAssets(FlaxStorage* storage)
|
||||
{
|
||||
PROFILE_CPU();
|
||||
@@ -342,7 +368,7 @@ void AssetsCache::RegisterAssets(FlaxStorage* storage)
|
||||
storage->GetEntries(entries);
|
||||
ASSERT(entries.HasItems());
|
||||
|
||||
ScopeLock lock(_locker);
|
||||
ASSETS_CACHE_LOCK();
|
||||
auto storagePath = storage->GetPath();
|
||||
|
||||
// Remove all old entries from that location
|
||||
@@ -440,7 +466,7 @@ void AssetsCache::RegisterAssets(const FlaxStorageReference& storage)
|
||||
void AssetsCache::RegisterAsset(const Guid& id, const String& typeName, const StringView& path)
|
||||
{
|
||||
PROFILE_CPU();
|
||||
ScopeLock lock(_locker);
|
||||
ASSETS_CACHE_LOCK();
|
||||
|
||||
// Check if asset has been already added to the registry
|
||||
bool isMissing = true;
|
||||
@@ -492,8 +518,7 @@ void AssetsCache::RegisterAsset(const Guid& id, const String& typeName, const St
|
||||
bool AssetsCache::DeleteAsset(const StringView& path, AssetInfo* info)
|
||||
{
|
||||
bool result = false;
|
||||
_locker.Lock();
|
||||
|
||||
ASSETS_CACHE_LOCK();
|
||||
for (auto i = _registry.Begin(); i.IsNotEnd(); ++i)
|
||||
{
|
||||
if (i->Value.Info.Path == path)
|
||||
@@ -506,16 +531,13 @@ bool AssetsCache::DeleteAsset(const StringView& path, AssetInfo* info)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_locker.Unlock();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool AssetsCache::DeleteAsset(const Guid& id, AssetInfo* info)
|
||||
{
|
||||
bool result = false;
|
||||
_locker.Lock();
|
||||
|
||||
ASSETS_CACHE_LOCK();
|
||||
const auto e = _registry.TryGet(id);
|
||||
if (e != nullptr)
|
||||
{
|
||||
@@ -525,16 +547,13 @@ bool AssetsCache::DeleteAsset(const Guid& id, AssetInfo* info)
|
||||
_isDirty = true;
|
||||
result = true;
|
||||
}
|
||||
|
||||
_locker.Unlock();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool AssetsCache::RenameAsset(const StringView& oldPath, const StringView& newPath)
|
||||
{
|
||||
bool result = false;
|
||||
_locker.Lock();
|
||||
|
||||
ASSETS_CACHE_LOCK();
|
||||
for (auto i = _registry.Begin(); i.IsNotEnd(); ++i)
|
||||
{
|
||||
if (i->Value.Info.Path == oldPath)
|
||||
@@ -545,11 +564,11 @@ bool AssetsCache::RenameAsset(const StringView& oldPath, const StringView& newPa
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_locker.Unlock();
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool AssetsCache::IsEntryValid(Entry& e)
|
||||
{
|
||||
#if ENABLE_ASSETS_DISCOVERY
|
||||
|
||||
@@ -16,6 +16,9 @@ struct AssetHeader;
|
||||
struct FlaxStorageReference;
|
||||
class FlaxStorage;
|
||||
|
||||
// In cooked game all assets are there and all access to registry is read-only so can be multithreaded
|
||||
#define ASSETS_CACHE_EDITABLE (USE_EDITOR)
|
||||
|
||||
/// <summary>
|
||||
/// Assets cache flags.
|
||||
/// </summary>
|
||||
@@ -75,22 +78,21 @@ public:
|
||||
|
||||
private:
|
||||
bool _isDirty = false;
|
||||
#if ASSETS_CACHE_EDITABLE
|
||||
CriticalSection _locker;
|
||||
#endif
|
||||
Registry _registry;
|
||||
PathsMapping _pathsMapping;
|
||||
#if !USE_EDITOR && !BUILD_RELEASE
|
||||
Dictionary<Guid, StringView> _pathsMappingInv;
|
||||
#endif
|
||||
String _path;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Gets amount of registered assets.
|
||||
/// </summary>
|
||||
int32 Size() const
|
||||
{
|
||||
_locker.Lock();
|
||||
const int32 result = _registry.Count();
|
||||
_locker.Unlock();
|
||||
return result;
|
||||
}
|
||||
int32 Size() const;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
@@ -116,11 +118,11 @@ public:
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Finds the asset path by id. In editor it returns the actual asset path, at runtime it returns the mapped asset path.
|
||||
/// Finds the asset path by id. In editor, it returns the actual asset path, at runtime it returns the mapped asset path.
|
||||
/// </summary>
|
||||
/// <param name="id">The asset id.</param>
|
||||
/// <returns>The asset path, or empty if failed to find.</returns>
|
||||
const String& GetEditorAssetPath(const Guid& id) const;
|
||||
StringView GetEditorAssetPath(const Guid& id) const;
|
||||
|
||||
/// <summary>
|
||||
/// Finds the asset info by path.
|
||||
@@ -173,6 +175,7 @@ public:
|
||||
/// <param name="result">The result array.</param>
|
||||
void GetAllByTypeName(const StringView& typeName, Array<Guid, HeapAllocation>& result) const;
|
||||
|
||||
#if ASSETS_CACHE_EDITABLE
|
||||
/// <summary>
|
||||
/// Register assets in the cache
|
||||
/// </summary>
|
||||
@@ -223,6 +226,7 @@ public:
|
||||
/// <param name="newPath">New path</param>
|
||||
/// <returns>True if has been deleted, otherwise false</returns>
|
||||
bool RenameAsset(const StringView& oldPath, const StringView& newPath);
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether cached asset entry is valid.
|
||||
|
||||
@@ -521,7 +521,7 @@ bool Content::GetAssetInfo(const StringView& path, AssetInfo& info)
|
||||
#endif
|
||||
}
|
||||
|
||||
String Content::GetEditorAssetPath(const Guid& id)
|
||||
StringView Content::GetEditorAssetPath(const Guid& id)
|
||||
{
|
||||
return Cache.GetEditorAssetPath(id);
|
||||
}
|
||||
@@ -749,6 +749,7 @@ void Content::DeleteAsset(const StringView& path)
|
||||
return;
|
||||
}
|
||||
|
||||
#if USE_EDITOR
|
||||
ScopeLock locker(AssetsLocker);
|
||||
|
||||
// Remove from registry
|
||||
@@ -765,6 +766,7 @@ void Content::DeleteAsset(const StringView& path)
|
||||
|
||||
// Delete file
|
||||
deleteFileSafety(path, info.ID);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Content::deleteFileSafety(const StringView& path, const Guid& id)
|
||||
|
||||
@@ -75,7 +75,7 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="id">The asset id.</param>
|
||||
/// <returns>The asset path, or empty if failed to find.</returns>
|
||||
API_FUNCTION() static String GetEditorAssetPath(const Guid& id);
|
||||
API_FUNCTION() static StringView GetEditorAssetPath(const Guid& id);
|
||||
|
||||
/// <summary>
|
||||
/// Finds all the asset IDs. Uses asset registry.
|
||||
|
||||
@@ -91,7 +91,7 @@ void JsonAssetBase::OnGetData(rapidjson_flax::StringBuffer& buffer) const
|
||||
Data->Accept(writerObj.GetWriter());
|
||||
}
|
||||
|
||||
const String& JsonAssetBase::GetPath() const
|
||||
StringView JsonAssetBase::GetPath() const
|
||||
{
|
||||
#if USE_EDITOR
|
||||
return _path;
|
||||
|
||||
@@ -88,7 +88,7 @@ protected:
|
||||
|
||||
public:
|
||||
// [Asset]
|
||||
const String& GetPath() const override;
|
||||
StringView GetPath() const override;
|
||||
uint64 GetMemoryUsage() const override;
|
||||
#if USE_EDITOR
|
||||
void GetReferences(Array<Guid, HeapAllocation>& assets, Array<String, HeapAllocation>& files) const override;
|
||||
|
||||
@@ -36,7 +36,7 @@ public:
|
||||
// [ContentLoadTask]
|
||||
String ToString() const override
|
||||
{
|
||||
return String::Format(TEXT("Load Asset Data Task ({}, {}, {})"), (int32)GetState(), _chunks, _asset ? _asset->GetPath() : String::Empty);
|
||||
return String::Format(TEXT("Load Asset Data Task ({}, {}, {})"), (int32)GetState(), _chunks, _asset ? _asset->GetPath() : StringView::Empty);
|
||||
}
|
||||
bool HasReference(Object* obj) const override
|
||||
{
|
||||
|
||||
@@ -134,7 +134,7 @@ public:
|
||||
struct Args
|
||||
{
|
||||
rapidjson_flax::Value& Data;
|
||||
const String* AssetPath;
|
||||
StringView AssetPath;
|
||||
int32 EngineBuild;
|
||||
float TimeBudget;
|
||||
};
|
||||
@@ -222,7 +222,7 @@ namespace LevelImpl
|
||||
SceneResult loadScene(SceneLoader& loader, JsonAsset* sceneAsset, float* timeBudget = nullptr);
|
||||
SceneResult loadScene(SceneLoader& loader, const BytesContainer& sceneData, Scene** outScene = nullptr, float* timeBudget = nullptr);
|
||||
SceneResult loadScene(SceneLoader& loader, rapidjson_flax::Document& document, Scene** outScene = nullptr, float* timeBudget = nullptr);
|
||||
SceneResult loadScene(SceneLoader& loader, rapidjson_flax::Value& data, int32 engineBuild, Scene** outScene = nullptr, const String* assetPath = nullptr, float* timeBudget = nullptr);
|
||||
SceneResult loadScene(SceneLoader& loader, rapidjson_flax::Value& data, int32 engineBuild, Scene** outScene = nullptr, StringView assetPath = StringView(), float* timeBudget = nullptr);
|
||||
bool unloadScene(Scene* scene);
|
||||
bool unloadScenes();
|
||||
bool saveScene(Scene* scene);
|
||||
@@ -959,7 +959,7 @@ SceneResult LevelImpl::loadScene(SceneLoader& loader, JsonAsset* sceneAsset, flo
|
||||
return SceneResult::Failed;
|
||||
}
|
||||
|
||||
return loadScene(loader, *sceneAsset->Data, sceneAsset->DataEngineBuild, nullptr, &sceneAsset->GetPath(), timeBudget);
|
||||
return loadScene(loader, *sceneAsset->Data, sceneAsset->DataEngineBuild, nullptr, sceneAsset->GetPath(), timeBudget);
|
||||
}
|
||||
|
||||
SceneResult LevelImpl::loadScene(SceneLoader& loader, const BytesContainer& sceneData, Scene** outScene, float* timeBudget)
|
||||
@@ -999,7 +999,7 @@ SceneResult LevelImpl::loadScene(SceneLoader& loader, rapidjson_flax::Document&
|
||||
return loadScene(loader, data->value, saveEngineBuild, outScene, nullptr, timeBudget);
|
||||
}
|
||||
|
||||
SceneResult LevelImpl::loadScene(SceneLoader& loader, rapidjson_flax::Value& data, int32 engineBuild, Scene** outScene, const String* assetPath, float* timeBudget)
|
||||
SceneResult LevelImpl::loadScene(SceneLoader& loader, rapidjson_flax::Value& data, int32 engineBuild, Scene** outScene, StringView assetPath, float* timeBudget)
|
||||
{
|
||||
PROFILE_CPU_NAMED("Level.LoadScene");
|
||||
PROFILE_MEM(Level);
|
||||
@@ -1401,12 +1401,12 @@ SceneResult SceneLoader::OnEnd(Args& args)
|
||||
LOG(Error, "Failed to resave asset '{}'", prefab->GetPath());
|
||||
}
|
||||
}
|
||||
if (ContentDeprecated::Clear() && args.AssetPath)
|
||||
if (ContentDeprecated::Clear() && args.AssetPath != StringView())
|
||||
{
|
||||
LOG(Info, "Resaving asset '{}' that uses deprecated data format", *args.AssetPath);
|
||||
if (saveScene(Scene, *args.AssetPath))
|
||||
LOG(Info, "Resaving asset '{}' that uses deprecated data format", args.AssetPath);
|
||||
if (saveScene(Scene, args.AssetPath))
|
||||
{
|
||||
LOG(Error, "Failed to resave asset '{}'", *args.AssetPath);
|
||||
LOG(Error, "Failed to resave asset '{}'", args.AssetPath);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user