Add deferred async scene asset loading

This commit is contained in:
2026-04-02 18:50:41 +08:00
parent dd08d8969e
commit 86144416af
18 changed files with 1806 additions and 97 deletions

View File

@@ -5,6 +5,7 @@
#include <XCEngine/Core/Asset/ResourceHandle.h>
#include <XCEngine/Resources/Mesh/Mesh.h>
#include <memory>
#include <string>
namespace XCEngine {
@@ -14,8 +15,8 @@ class MeshFilterComponent : public Component {
public:
std::string GetName() const override { return "MeshFilter"; }
Resources::Mesh* GetMesh() const { return m_mesh.Get(); }
const Resources::ResourceHandle<Resources::Mesh>& GetMeshHandle() const { return m_mesh; }
Resources::Mesh* GetMesh() const;
const Resources::ResourceHandle<Resources::Mesh>& GetMeshHandle() const;
const std::string& GetMeshPath() const { return m_meshPath; }
const Resources::AssetRef& GetMeshAssetRef() const { return m_meshRef; }
@@ -28,9 +29,15 @@ public:
void Deserialize(std::istream& is) override;
private:
struct PendingMeshLoadState;
void BeginAsyncMeshLoad(const std::string& meshPath);
void ResolvePendingMesh();
Resources::ResourceHandle<Resources::Mesh> m_mesh;
std::string m_meshPath;
Resources::AssetRef m_meshRef;
std::shared_ptr<PendingMeshLoadState> m_pendingMeshLoad;
};
} // namespace Components

View File

@@ -6,6 +6,7 @@
#include <XCEngine/Resources/Material/Material.h>
#include <cstdint>
#include <memory>
#include <string>
#include <vector>
@@ -42,12 +43,17 @@ public:
void Deserialize(std::istream& is) override;
private:
struct PendingMaterialLoadState;
void BeginAsyncMaterialLoad(size_t index, const std::string& materialPath);
void ResolvePendingMaterials();
void EnsureMaterialSlot(size_t index);
static std::string MaterialPathFromHandle(const Resources::ResourceHandle<Resources::Material>& material);
std::vector<Resources::ResourceHandle<Resources::Material>> m_materials;
std::vector<std::string> m_materialPaths;
std::vector<Resources::AssetRef> m_materialRefs;
std::vector<std::shared_ptr<PendingMaterialLoadState>> m_pendingMaterialLoads;
bool m_castShadows = true;
bool m_receiveShadows = true;
uint32_t m_renderLayer = 0;

View File

@@ -2,10 +2,13 @@
#include <XCEngine/Core/IO/IResourceLoader.h>
#include <XCEngine/Core/Asset/ImportSettings.h>
#include <XCEngine/Core/Containers/Array.h>
#include <XCEngine/Threading/Mutex.h>
#include <atomic>
#include <condition_variable>
#include <deque>
#include <functional>
#include <mutex>
#include <thread>
#include <vector>
namespace XCEngine {
namespace Resources {
@@ -50,6 +53,14 @@ private:
static Core::uint64 GenerateRequestId();
};
struct CompletedLoadRequest {
LoadRequest request;
LoadResult result;
CompletedLoadRequest(LoadRequest inRequest, LoadResult inResult)
: request(std::move(inRequest)), result(std::move(inResult)) {}
};
class AsyncLoader {
public:
static AsyncLoader& Get();
@@ -76,18 +87,21 @@ public:
private:
void SubmitInternal(LoadRequest request);
IResourceLoader* FindLoader(ResourceType type) const;
void WorkerThread();
void QueueCompleted(LoadRequest request, LoadResult result);
Threading::Mutex m_queueMutex;
Containers::Array<LoadRequest> m_pendingQueue;
Threading::Mutex m_completedMutex;
Containers::Array<LoadRequest> m_completedQueue;
std::mutex m_queueMutex;
std::condition_variable m_pendingCondition;
std::deque<LoadRequest> m_pendingQueue;
std::mutex m_completedMutex;
std::deque<CompletedLoadRequest> m_completedQueue;
std::vector<std::thread> m_workerThreads;
std::atomic<bool> m_running{false};
std::atomic<Core::uint32> m_pendingCount{0};
std::atomic<Core::uint32> m_completedCount{0};
Core::uint32 m_totalRequested = 0;
std::atomic<Core::uint64> m_totalRequested{0};
};
} // namespace Resources

View File

@@ -11,6 +11,11 @@
#include <XCEngine/Core/Containers/HashMap.h>
#include <XCEngine/Threading/Mutex.h>
#include <XCEngine/Debug/Logger.h>
#include <atomic>
#include <condition_variable>
#include <memory>
#include <mutex>
#include <unordered_map>
#include <type_traits>
namespace XCEngine {
@@ -18,6 +23,17 @@ namespace Resources {
class ResourceManager {
public:
class ScopedDeferredSceneLoad {
public:
explicit ScopedDeferredSceneLoad(ResourceManager& manager = ResourceManager::Get());
ScopedDeferredSceneLoad(const ScopedDeferredSceneLoad&) = delete;
ScopedDeferredSceneLoad& operator=(const ScopedDeferredSceneLoad&) = delete;
~ScopedDeferredSceneLoad();
private:
ResourceManager* m_manager = nullptr;
};
static ResourceManager& Get();
void Initialize();
@@ -43,7 +59,7 @@ public:
static_assert(std::is_base_of_v<IResource, T>, "T must derive from IResource");
Containers::String path;
if (!assetRef.IsValid() || !m_assetDatabase.TryGetPrimaryAssetPath(assetRef.assetGuid, path)) {
if (!TryResolveAssetPath(assetRef, path)) {
return ResourceHandle<T>();
}
@@ -54,6 +70,9 @@ public:
std::function<void(LoadResult)> callback);
void LoadAsync(const Containers::String& path, ResourceType type, ImportSettings* settings,
std::function<void(LoadResult)> callback);
void UpdateAsyncLoads();
bool IsAsyncLoading() const;
Core::uint32 GetAsyncPendingCount() const;
void Unload(const Containers::String& path);
void Unload(ResourceGUID guid);
@@ -98,8 +117,35 @@ public:
void UnloadGroup(const Containers::Array<ResourceGUID>& guids);
void RefreshAssetDatabase();
bool TryGetAssetRef(const Containers::String& path, ResourceType resourceType, AssetRef& outRef) const;
bool TryResolveAssetPath(const AssetRef& assetRef, Containers::String& outPath) const;
void BeginDeferredSceneLoad();
void EndDeferredSceneLoad();
bool IsDeferredSceneLoadEnabled() const;
private:
struct InFlightLoadKey {
ResourceGUID guid;
ResourceType type = ResourceType::Unknown;
bool operator==(const InFlightLoadKey& other) const {
return guid == other.guid && type == other.type;
}
};
struct InFlightLoadKeyHasher {
size_t operator()(const InFlightLoadKey& key) const noexcept {
return std::hash<ResourceGUID>{}(key.guid) ^
(static_cast<size_t>(key.type) << 1);
}
};
struct InFlightLoadState {
bool completed = false;
bool success = false;
Containers::String errorMessage;
std::condition_variable condition;
};
ResourceManager() = default;
~ResourceManager() = default;
@@ -122,8 +168,13 @@ private:
ResourceCache m_cache;
Core::UniqueRef<AsyncLoader> m_asyncLoader;
Threading::Mutex m_mutex;
mutable std::recursive_mutex m_ioMutex;
std::mutex m_inFlightLoadsMutex;
std::unordered_map<InFlightLoadKey, std::shared_ptr<InFlightLoadState>, InFlightLoadKeyHasher> m_inFlightLoads;
std::atomic<Core::uint32> m_deferredSceneLoadDepth{0};
friend class ResourceHandleBase;
friend class AsyncLoader;
};
} // namespace Resources