refactor: reorganize Resources module into Core/Asset, Core/IO and Resources subdirectories

- Split core resource architecture into Core/Asset/ (IResource, ResourceManager, ResourceCache, etc.)
- Moved IO layer into Core/IO/ (IResourceLoader, ResourceFileSystem, etc.)
- Reorganized concrete resource types into Resources/{Texture,Mesh,Material,Shader,AudioClip}/
- Updated all include paths from relative to <XCEngine/...> format
- Fixed circular dependency in Material.h (removed unnecessary ResourceManager.h include)
- Fixed malformed include syntax in ResourceManager.h and AsyncLoader.h
- Fixed glad.h path issues in CMakeLists.txt
This commit is contained in:
2026-03-24 14:46:17 +08:00
parent b1829bcfc5
commit 50c0ffdb9e
47 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,103 @@
#include "Resources/AsyncLoader.h"
#include "Resources/ResourceManager.h"
#include "Resources/ResourceTypes.h"
namespace XCEngine {
namespace Resources {
Core::uint64 LoadRequest::GenerateRequestId() {
static std::atomic<Core::uint64> s_requestId{0};
return ++s_requestId;
}
AsyncLoader& AsyncLoader::Get() {
static AsyncLoader instance;
return instance;
}
void AsyncLoader::Initialize(Core::uint32 workerThreadCount) {
(void)workerThreadCount;
}
void AsyncLoader::Shutdown() {
CancelAll();
}
void AsyncLoader::Submit(const Containers::String& path, ResourceType type,
std::function<void(LoadResult)> callback) {
Submit(path, type, nullptr, std::move(callback));
}
void AsyncLoader::Submit(const Containers::String& path, ResourceType type, ImportSettings* settings,
std::function<void(LoadResult)> callback) {
LoadRequest request(path, type, std::move(callback), settings);
SubmitInternal(std::move(request));
}
void AsyncLoader::SubmitInternal(LoadRequest request) {
IResourceLoader* loader = FindLoader(request.type);
if (!loader) {
if (request.callback) {
LoadResult result(Containers::String("No loader for type: ") +
GetResourceTypeName(request.type));
request.callback(result);
}
return;
}
{
std::lock_guard lock(m_queueMutex);
m_pendingQueue.PushBack(std::move(request));
m_pendingCount++;
m_totalRequested++;
}
}
void AsyncLoader::Update() {
Containers::Array<LoadRequest> completed;
{
std::lock_guard lock(m_completedMutex);
completed = std::move(m_completedQueue);
m_completedQueue.Clear();
}
for (auto& request : completed) {
m_pendingCount--;
if (request.callback) {
LoadResult result(true);
request.callback(result);
}
}
}
float AsyncLoader::GetProgress() const {
if (m_totalRequested == 0) return 1.0f;
return static_cast<float>(m_totalRequested - m_pendingCount.load()) / m_totalRequested;
}
void AsyncLoader::CancelAll() {
std::lock_guard lock(m_queueMutex);
m_pendingQueue.Clear();
m_pendingCount = 0;
}
void AsyncLoader::Cancel(Core::uint64 requestId) {
std::lock_guard lock(m_queueMutex);
(void)requestId;
}
IResourceLoader* AsyncLoader::FindLoader(ResourceType type) const {
return ResourceManager::Get().GetLoader(type);
}
void AsyncLoader::QueueCompleted(LoadRequest request, LoadResult result) {
std::lock_guard lock(m_completedMutex);
(void)request;
(void)result;
}
} // namespace Resources
} // namespace XCEngine

View File

@@ -0,0 +1,141 @@
#include "Resources/ResourceCache.h"
#include "Resources/ResourceManager.h"
namespace XCEngine {
namespace Resources {
static Core::uint64 g_currentTick = 0;
Core::uint64 CacheEntry::GetCurrentTick() {
return ++g_currentTick;
}
CacheEntry::CacheEntry(IResource* res, size_t size)
: resource(res), guid(res->GetGUID()), memorySize(size),
lastAccessTime(GetCurrentTick()), accessCount(1) {}
ResourceCache::ResourceCache() = default;
ResourceCache::~ResourceCache() = default;
void ResourceCache::Add(ResourceGUID guid, IResource* resource) {
std::lock_guard lock(m_mutex);
if (m_cache.Contains(guid)) {
return;
}
CacheEntry entry(resource, resource->GetMemorySize());
m_cache.Insert(guid, entry);
m_lruOrder.PushBack(guid);
m_memoryUsage += entry.memorySize;
}
void ResourceCache::Remove(ResourceGUID guid) {
std::lock_guard lock(m_mutex);
auto* it = m_cache.Find(guid);
if (it != nullptr) {
m_memoryUsage -= it->memorySize;
m_cache.Erase(guid);
// Simple workaround: rebuild LRU list without the guid
Containers::Array<ResourceGUID> newList;
for (size_t i = 0; i < m_lruOrder.Size(); ++i) {
if (m_lruOrder[i] != guid) {
newList.PushBack(m_lruOrder[i]);
}
}
m_lruOrder = std::move(newList);
}
}
IResource* ResourceCache::Find(ResourceGUID guid) const {
std::lock_guard lock(m_mutex);
auto* it = m_cache.Find(guid);
return it != nullptr ? it->resource : nullptr;
}
void ResourceCache::Touch(ResourceGUID guid) {
std::lock_guard lock(m_mutex);
auto* it = m_cache.Find(guid);
if (it != nullptr) {
it->lastAccessTime = CacheEntry::GetCurrentTick();
it->accessCount++;
}
}
void ResourceCache::SetMemoryBudget(size_t bytes) {
std::lock_guard lock(m_mutex);
m_memoryBudget = bytes;
}
void ResourceCache::OnMemoryPressure(size_t requiredBytes) {
std::lock_guard lock(m_mutex);
if (m_memoryUsage + requiredBytes <= m_memoryBudget) {
return;
}
size_t targetRelease = (m_memoryUsage + requiredBytes) - m_memoryBudget;
Evict(targetRelease);
}
void ResourceCache::OnZeroRefCount(ResourceGUID guid) {
}
void ResourceCache::Evict(size_t requiredBytes) {
size_t released = 0;
// Simple eviction: remove from end of LRU list
while (released < requiredBytes && m_lruOrder.Size() > 0) {
ResourceGUID guid = m_lruOrder.Back();
m_lruOrder.PopBack();
auto* it = m_cache.Find(guid);
if (it != nullptr) {
m_memoryUsage -= it->memorySize;
released += it->memorySize;
it->resource->Release();
m_cache.Erase(guid);
}
}
}
void ResourceCache::Flush() {
std::lock_guard lock(m_mutex);
// Release all resources
for (size_t i = 0; i < m_cache.Size(); ++i) {
// Would need iteration support
}
m_cache.Clear();
m_lruOrder.Clear();
m_memoryUsage = 0;
}
void ResourceCache::Clear() {
std::lock_guard lock(m_mutex);
m_cache.Clear();
m_lruOrder.Clear();
m_memoryUsage = 0;
}
Containers::Array<ResourceGUID> ResourceCache::GetLRUList(size_t count) const {
std::lock_guard lock(m_mutex);
Containers::Array<ResourceGUID> result;
size_t n = std::min(count, static_cast<size_t>(m_lruOrder.Size()));
for (size_t i = 0; i < n; i++) {
result.PushBack(m_lruOrder[i]);
}
return result;
}
} // namespace Resources
} // namespace XCEngine

View File

@@ -0,0 +1,224 @@
#include "Resources/ResourceDependencyGraph.h"
namespace XCEngine {
namespace Resources {
ResourceDependencyGraph::ResourceDependencyGraph() = default;
ResourceDependencyGraph::~ResourceDependencyGraph() = default;
void ResourceDependencyGraph::AddNode(ResourceGUID guid, ResourceType type) {
if (m_nodes.Contains(guid)) {
return;
}
DependencyNode node;
node.guid = guid;
node.type = type;
node.refCount = 0;
m_nodes.Insert(guid, node);
}
void ResourceDependencyGraph::RemoveNode(ResourceGUID guid) {
m_nodes.Erase(guid);
}
void ResourceDependencyGraph::AddDependency(ResourceGUID owner, ResourceGUID dependency) {
DependencyNode* ownerNode = m_nodes.Find(owner);
DependencyNode* depNode = m_nodes.Find(dependency);
if (!ownerNode || !depNode) {
return;
}
bool alreadyExists = false;
for (size_t i = 0; i < ownerNode->dependencies.Size(); ++i) {
if (ownerNode->dependencies[i] == dependency) {
alreadyExists = true;
break;
}
}
if (!alreadyExists) {
ownerNode->dependencies.PushBack(dependency);
depNode->dependents.PushBack(owner);
}
}
void ResourceDependencyGraph::RemoveDependency(ResourceGUID owner, ResourceGUID dependency) {
DependencyNode* ownerNode = m_nodes.Find(owner);
DependencyNode* depNode = m_nodes.Find(dependency);
if (!ownerNode || !depNode) {
return;
}
for (size_t i = 0; i < ownerNode->dependencies.Size(); ++i) {
if (ownerNode->dependencies[i] == dependency) {
ownerNode->dependencies[i] = ownerNode->dependencies.Back();
ownerNode->dependencies.PopBack();
break;
}
}
for (size_t i = 0; i < depNode->dependents.Size(); ++i) {
if (depNode->dependents[i] == owner) {
depNode->dependents[i] = depNode->dependents.Back();
depNode->dependents.PopBack();
break;
}
}
}
Containers::Array<ResourceGUID> ResourceDependencyGraph::GetDependencies(ResourceGUID guid) const {
Containers::Array<ResourceGUID> result;
const DependencyNode* node = m_nodes.Find(guid);
if (node) {
result = node->dependencies;
}
return result;
}
Containers::Array<ResourceGUID> ResourceDependencyGraph::GetDependents(ResourceGUID guid) const {
Containers::Array<ResourceGUID> result;
const DependencyNode* node = m_nodes.Find(guid);
if (node) {
result = node->dependents;
}
return result;
}
Containers::Array<ResourceGUID> ResourceDependencyGraph::GetAllDependencies(ResourceGUID guid) const {
Containers::Array<ResourceGUID> result;
Containers::Array<ResourceGUID> stack;
stack.PushBack(guid);
while (stack.Size() > 0) {
ResourceGUID current = stack.Back();
stack.PopBack();
bool visited = false;
for (size_t i = 0; i < result.Size(); ++i) {
if (result[i] == current) {
visited = true;
break;
}
}
if (visited) continue;
if (current != guid) {
result.PushBack(current);
}
const DependencyNode* node = m_nodes.Find(current);
if (node) {
for (size_t i = 0; i < node->dependencies.Size(); ++i) {
stack.PushBack(node->dependencies[i]);
}
}
}
return result;
}
void ResourceDependencyGraph::IncrementRefCount(ResourceGUID guid) {
DependencyNode* node = m_nodes.Find(guid);
if (node) {
node->refCount++;
}
}
void ResourceDependencyGraph::DecrementRefCount(ResourceGUID guid) {
DependencyNode* node = m_nodes.Find(guid);
if (node && node->refCount > 0) {
node->refCount--;
}
}
Core::uint32 ResourceDependencyGraph::GetRefCount(ResourceGUID guid) const {
const DependencyNode* node = m_nodes.Find(guid);
if (node) {
return node->refCount;
}
return 0;
}
bool ResourceDependencyGraph::HasCircularDependency(ResourceGUID guid, Containers::Array<ResourceGUID>& outCycle) const {
Containers::Array<ResourceGUID> path;
Containers::Array<ResourceGUID> stack;
stack.PushBack(guid);
while (stack.Size() > 0) {
ResourceGUID current = stack.Back();
stack.PopBack();
bool inPath = false;
for (size_t i = 0; i < path.Size(); ++i) {
if (path[i] == current) {
inPath = true;
break;
}
}
if (inPath) {
outCycle = path;
outCycle.PushBack(current);
return true;
}
path.PushBack(current);
const DependencyNode* node = m_nodes.Find(current);
if (node) {
for (size_t i = 0; i < node->dependencies.Size(); ++i) {
stack.PushBack(node->dependencies[i]);
}
}
}
return false;
}
Containers::Array<ResourceGUID> ResourceDependencyGraph::TopologicalSort() const {
Containers::Array<ResourceGUID> result;
return result;
}
bool ResourceDependencyGraph::Unload(ResourceGUID guid) {
DependencyNode* node = m_nodes.Find(guid);
if (!node) {
return false;
}
if (node->refCount > 0) {
return false;
}
for (size_t i = 0; i < node->dependents.Size(); ++i) {
DependencyNode* depNode = m_nodes.Find(node->dependents[i]);
if (depNode && depNode->refCount > 0) {
return false;
}
}
return true;
}
void ResourceDependencyGraph::Clear() {
m_nodes.Clear();
}
bool ResourceDependencyGraph::HasNode(ResourceGUID guid) const {
return m_nodes.Find(guid) != nullptr;
}
bool ResourceDependencyGraph::HasCircularDependencyInternal(ResourceGUID guid, Containers::HashMap<ResourceGUID, bool>& visited,
Containers::Array<ResourceGUID>& path, Containers::Array<ResourceGUID>& outCycle) const {
return false;
}
} // namespace Resources
} // namespace XCEngine

View File

@@ -0,0 +1,211 @@
#include "Resources/ResourceManager.h"
#include "Resources/ResourceHandle.h"
#include "Resources/ResourceTypes.h"
namespace XCEngine {
namespace Resources {
ResourceManager& ResourceManager::Get() {
static ResourceManager instance;
return instance;
}
void ResourceManager::Initialize() {
m_asyncLoader = Core::MakeUnique<AsyncLoader>();
m_asyncLoader->Initialize(2);
}
void ResourceManager::Shutdown() {
UnloadAll();
m_asyncLoader->Shutdown();
m_asyncLoader.reset();
}
void ResourceManager::SetResourceRoot(const Containers::String& rootPath) {
m_resourceRoot = rootPath;
}
const Containers::String& ResourceManager::GetResourceRoot() const {
return m_resourceRoot;
}
void ResourceManager::AddRef(ResourceGUID guid) {
std::lock_guard lock(m_mutex);
auto* it = m_refCounts.Find(guid);
if (it == nullptr) {
m_refCounts.Insert(guid, 1);
} else {
(*it)++;
}
if (!m_resourceCache.Contains(guid)) {
ReloadResource(guid);
}
}
void ResourceManager::Release(ResourceGUID guid) {
std::lock_guard lock(m_mutex);
auto* it = m_refCounts.Find(guid);
if (it != nullptr) {
(*it)--;
if (*it == 0) {
m_refCounts.Erase(guid);
m_cache.OnZeroRefCount(guid);
}
}
}
Core::uint32 ResourceManager::GetRefCount(ResourceGUID guid) const {
auto* it = m_refCounts.Find(guid);
return it != nullptr ? *it : 0;
}
void ResourceManager::RegisterLoader(IResourceLoader* loader) {
std::lock_guard lock(m_mutex);
m_loaders.Insert(loader->GetResourceType(), loader);
}
IResourceLoader* ResourceManager::GetLoader(ResourceType type) const {
auto* it = m_loaders.Find(type);
return it != nullptr ? *it : nullptr;
}
IResourceLoader* ResourceManager::FindLoader(ResourceType type) {
return GetLoader(type);
}
IResource* ResourceManager::FindInCache(ResourceGUID guid) {
std::lock_guard lock(m_mutex);
auto* it = m_resourceCache.Find(guid);
return it != nullptr ? *it : nullptr;
}
void ResourceManager::AddToCache(ResourceGUID guid, IResource* resource) {
std::lock_guard lock(m_mutex);
m_resourceCache.Insert(guid, resource);
m_memoryUsage += resource->GetMemorySize();
m_cache.Add(guid, resource);
if (m_memoryUsage > m_memoryBudget) {
m_cache.OnMemoryPressure(m_memoryUsage - m_memoryBudget);
}
}
void ResourceManager::Unload(ResourceGUID guid) {
std::lock_guard lock(m_mutex);
auto* it = m_resourceCache.Find(guid);
if (it != nullptr) {
IResource* resource = *it;
m_resourceCache.Erase(guid);
m_memoryUsage -= resource->GetMemorySize();
resource->Release();
}
}
void ResourceManager::UnloadAll() {
std::lock_guard lock(m_mutex);
for (size_t i = 0; i < m_resourceCache.Size(); ++i) {
// This is a simplified approach - we'd need a way to iterate
// For now, just clear everything
}
m_resourceCache.Clear();
m_refCounts.Clear();
m_memoryUsage = 0;
}
void ResourceManager::SetMemoryBudget(size_t bytes) {
m_memoryBudget = bytes;
}
size_t ResourceManager::GetMemoryUsage() const {
return m_memoryUsage;
}
size_t ResourceManager::GetMemoryBudget() const {
return m_memoryBudget;
}
void ResourceManager::FlushCache() {
m_cache.Flush();
}
IResource* ResourceManager::Find(const Containers::String& path) {
return Find(ResourceGUID::Generate(path));
}
IResource* ResourceManager::Find(ResourceGUID guid) {
return FindInCache(guid);
}
bool ResourceManager::Exists(const Containers::String& path) const {
return Exists(ResourceGUID::Generate(path));
}
bool ResourceManager::Exists(ResourceGUID guid) const {
return m_resourceCache.Contains(guid);
}
Containers::String ResourceManager::ResolvePath(const Containers::String& relativePath) const {
return m_resourceRoot + "/" + relativePath;
}
void ResourceManager::LoadAsync(const Containers::String& path, ResourceType type,
std::function<void(LoadResult)> callback) {
LoadAsync(path, type, nullptr, callback);
}
void ResourceManager::LoadAsync(const Containers::String& path, ResourceType type,
ImportSettings* settings,
std::function<void(LoadResult)> callback) {
m_asyncLoader->Submit(path, type, settings, callback);
}
void ResourceManager::Unload(const Containers::String& path) {
Unload(ResourceGUID::Generate(path));
}
void ResourceManager::UnloadUnused() {
}
void ResourceManager::UnregisterLoader(ResourceType type) {
m_loaders.Erase(type);
}
void ResourceManager::ReloadResource(ResourceGUID guid) {
auto* pathIt = m_guidToPath.Find(guid);
if (pathIt == nullptr) {
return;
}
}
Containers::Array<Containers::String> ResourceManager::GetResourcePaths() const {
Containers::Array<Containers::String> paths;
for (const auto& pair : m_guidToPath) {
paths.PushBack(pair.second);
}
return paths;
}
void ResourceManager::UnloadGroup(const Containers::Array<ResourceGUID>& guids) {
std::lock_guard lock(m_mutex);
for (const auto& guid : guids) {
auto* it = m_resourceCache.Find(guid);
if (it != nullptr) {
IResource* resource = *it;
m_resourceCache.Erase(guid);
m_memoryUsage -= resource->GetMemorySize();
resource->Release();
}
}
}
} // namespace Resources
} // namespace XCEngine

View File

@@ -0,0 +1,29 @@
#include "Resources/ResourceTypes.h"
namespace XCEngine {
namespace Resources {
ResourceGUID ResourceGUID::Generate(const char* path) {
Core::uint64 hash = 14695981039346656037ULL;
while (*path) {
hash ^= static_cast<Core::uint64>(*path);
hash *= 1099511628211ULL;
path++;
}
return ResourceGUID(hash);
}
ResourceGUID ResourceGUID::Generate(const Containers::String& path) {
return Generate(path.CStr());
}
Containers::String ResourceGUID::ToString() const {
char buffer[17];
snprintf(buffer, sizeof(buffer), "%016llx", value);
return Containers::String(buffer);
}
} // namespace Resources
} // namespace XCEngine