diff --git a/docs/RHI抽象层设计与实现.md b/docs/RHI抽象层设计与实现.md index a72757ff..be73e582 100644 --- a/docs/RHI抽象层设计与实现.md +++ b/docs/RHI抽象层设计与实现.md @@ -489,9 +489,57 @@ public: 4. **绑定方式** - D3D12:通过 CommandList->SetPipelineState - OpenGL:glUseProgram - - 解决:基类提供 Bind/Unbind 接口 + - 解决:基类提供 Bind/Unbind 接口 -### 5.8 根签名 vs OpenGL 资源绑定 +### 5.8 采样器(RHISampler)抽象设计 + +#### 5.8.1 设计理念对应 + +| 差异点 | 设计理念 | 处理方案 | +|--------|---------|---------| +| 初始化参数差异 | 求同存异 | 后端各自实现初始化 | +| 句柄类型差异 | 底层逃逸 | 统一返回 void* | +| 绑定方式 | 求同存异 | 基类提供 Bind/Unbind | + +#### 5.8.2 现有实现对比 + +| 功能 | D3D12Sampler | OpenGLSampler | +|------|--------------|---------------| +| 初始化 | Initialize(device, desc) | Initialize(desc) | +| 销毁 | Shutdown() | Shutdown() | +| 绑定 | 通过 DescriptorHeap | Bind(unit) | +| 句柄 | GetNativeHandle() | GetID() | + +#### 5.8.3 抽象接口定义 + +```cpp +class RHISampler { +public: + virtual ~RHISampler() = default; + + virtual void Shutdown() = 0; + + virtual void Bind(unsigned int unit) = 0; + virtual void Unbind(unsigned int unit) = 0; + + virtual void* GetNativeHandle() = 0; + virtual unsigned int GetID() = 0; +}; +``` + +#### 5.8.4 差异处理策略 + +1. **初始化参数差异(求同存异)** + - D3D12:需要 device 参数 + - OpenGL:不需要 device + - 解决:Device 的 CreateSampler() 统一接收 SamplerDesc,后端各自实现 Initialize() + +2. **句柄类型差异(底层逃逸)** + - D3D12:通过 DescriptorHeap 管理 + - OpenGL:GLuint + - 解决:GetNativeHandle() 返回 void* + +### 5.9 根签名 vs OpenGL 资源绑定 - **D3D12**:显式 `RootSignature` 定义资源绑定规则 - **OpenGL**:隐式通过 `glUniformLocation`、`glBindTextureUnit` 绑定 - **解决方案**: diff --git a/docs/plan/第四阶段计划_资源系统.md b/docs/plan/第四阶段计划_资源系统.md index a6f919b5..65b4fc7b 100644 --- a/docs/plan/第四阶段计划_资源系统.md +++ b/docs/plan/第四阶段计划_资源系统.md @@ -2110,9 +2110,1552 @@ private: --- -## 11. 关键技术点 +## 11. 详细执行计划 -### 11.1 引用计数与缓存淘汰的交互 +> 本节详细说明如何逐步实现资源系统,包括每个文件的具体内容、实现步骤、测试方法和集成要点。 + +### 11.1 文件创建清单 + +首先,需要创建以下目录结构和文件: + +``` +engine/include/XCEngine/Resources/ +├── Resources.h # 主头文件 +├── ResourceTypes.h # 资源类型枚举 +├── ImportSettings.h # 导入设置基类 +├── IResource.h # 资源基类接口 +├── ResourceHandle.h # 资源句柄 +├── ResourceManager.h # 资源管理器 +├── IResourceLoader.h # 加载器基类 +├── ResourceCache.h # 资源缓存 +├── AsyncLoader.h # 异步加载器 +├── Texture.h # 纹理资源 +├── TextureLoader.h # 纹理加载器 +├── TextureImportSettings.h # 纹理导入设置 +├── Mesh.h # 网格资源 +├── MeshLoader.h # 网格加载器 +├── MeshImportSettings.h # 网格导入设置 +├── Material.h # 材质资源 +├── MaterialLoader.h # 材质加载器 +├── Shader.h # 着色器资源 +├── ShaderLoader.h # 着色器加载器 +├── AudioClip.h # 音频资源 +├── AudioLoader.h # 音频加载器 +└── BinaryResource.h # 二进制资源 + +engine/src/Resources/ +├── Resources.cpp # 资源系统初始化 +├── ResourceManager.cpp # 资源管理器实现 +├── ResourceCache.cpp # 缓存实现 +├── AsyncLoader.cpp # 异步加载实现 +├── TextureLoader.cpp # 纹理加载实现 +├── MeshLoader.cpp # 网格加载实现 +├── MaterialLoader.cpp # 材质加载实现 +├── ShaderLoader.cpp # 着色器加载实现 +└── AudioLoader.cpp # 音频加载实现 +``` + +### 11.2 第一阶段:基础框架(天1-3) + +#### 步骤 11.2.1 创建主头文件 Resources.h + +```cpp +// Resources.h +#pragma once + +#include "ResourceTypes.h" +#include "ImportSettings.h" +#include "IResource.h" +#include "ResourceHandle.h" +#include "ResourceManager.h" +#include "IResourceLoader.h" +#include "ResourceCache.h" +#include "AsyncLoader.h" + +// 具体资源类型 +#include "Texture.h" +#include "TextureLoader.h" +#include "TextureImportSettings.h" +#include "Mesh.h" +#include "MeshLoader.h" +#include "MeshImportSettings.h" +#include "Material.h" +#include "MaterialLoader.h" +#include "Shader.h" +#include "ShaderLoader.h" +#include "AudioClip.h" +#include "AudioLoader.h" +#include "BinaryResource.h" +``` + +#### 步骤 11.2.2 实现 ResourceTypes.h + +**文件**: `engine/include/XCEngine/Resources/ResourceTypes.h` + +```cpp +#pragma once +#include "../Core/Types.h" +#include "../Containers/String.h" +#include "../Containers/Array.h" +#include + +namespace XCEngine { +namespace Resources { + +// 资源类型枚举 +enum class ResourceType : Core::uint8 { + Unknown = 0, + Texture, + Mesh, + Material, + Shader, + AudioClip, + Binary, + AnimationClip, + Skeleton, + Font, + ParticleSystem, + Scene, + Prefab +}; + +constexpr const char* GetResourceTypeName(ResourceType type) { + switch (type) { + case ResourceType::Texture: return "Texture"; + case ResourceType::Mesh: return "Mesh"; + case ResourceType::Material: return "Material"; + case ResourceType::Shader: return "Shader"; + case ResourceType::AudioClip: return "AudioClip"; + case ResourceType::Binary: return "Binary"; + case ResourceType::AnimationClip: return "AnimationClip"; + case ResourceType::Skeleton: return "Skeleton"; + case ResourceType::Font: return "Font"; + case ResourceType::ParticleSystem:return "ParticleSystem"; + case ResourceType::Scene: return "Scene"; + case ResourceType::Prefab: return "Prefab"; + default: return "Unknown"; + } +} + +// ResourceGUID - 64位唯一标识符 +struct ResourceGUID { + Core::uint64 value; + + ResourceGUID() : value(0) {} + explicit ResourceGUID(Core::uint64 v) : value(v) {} + + bool IsValid() const { return value != 0; } + + bool operator==(const ResourceGUID& other) const { return value == other.value; } + bool operator!=(const ResourceGUID& other) const { return value != other.value; } + + static ResourceGUID Generate(const char* path); + static ResourceGUID Generate(const Containers::String& path); + + Containers::String ToString() const; +}; + +inline ResourceGUID MakeResourceGUID(const char* path) { + return ResourceGUID::Generate(path); +} + +// 模板特化获取ResourceType +template +ResourceType GetResourceType(); + +template<> inline ResourceType GetResourceType() { return ResourceType::Texture; } +template<> inline ResourceType GetResourceType() { return ResourceType::Mesh; } +template<> inline ResourceType GetResourceType() { return ResourceType::Material; } +template<> inline ResourceType GetResourceType() { return ResourceType::Shader; } +template<> inline ResourceType GetResourceType() { return ResourceType::AudioClip; } +template<> inline ResourceType GetResourceType() { return ResourceType::Binary; } + +// 导入设置基类 +class ImportSettings { +public: + virtual ~ImportSettings() = default; + + virtual UniquePtr Clone() const = 0; + virtual bool LoadFromJSON(const Containers::String& json) { return false; } + virtual Containers::String SaveToJSON() const { return Containers::String(); } +}; + +} // namespace Resources +} // namespace XCEngine +``` + +**实现文件** `engine/src/Resources/ResourceTypes.cpp`: +```cpp +#include "Resources/ResourceTypes.h" +#include + +namespace XCEngine { +namespace Resources { + +// 简单哈希实现(实际项目中可使用MD5) +ResourceGUID ResourceGUID::Generate(const char* path) { + Core::uint64 hash = 14695981039346656037ULL; // FNV offset basis + + while (*path) { + hash ^= static_cast(*path); + hash *= 1099511628211ULL; // FNV prime + 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 +``` + +#### 步骤 11.2.3 实现 IResource.h + +**文件**: `engine/include/XCEngine/Resources/IResource.h` + +```cpp +#pragma once +#include "ResourceTypes.h" +#include "../Containers/String.h" + +namespace XCEngine { +namespace Resources { + +class IResource { +public: + virtual ~IResource() = default; + + virtual ResourceType GetType() const = 0; + virtual const Containers::String& GetName() const = 0; + virtual const Containers::String& GetPath() const = 0; + virtual ResourceGUID GetGUID() const = 0; + virtual bool IsValid() const = 0; + virtual size_t GetMemorySize() const = 0; + virtual void Release() = 0; + +protected: + struct ConstructParams { + Containers::String name; + Containers::String path; + ResourceGUID guid; + size_t memorySize = 0; + }; + + void Initialize(const ConstructParams& params) { + m_name = params.name; + m_path = params.path; + m_guid = params.guid; + m_memorySize = params.memorySize; + m_isValid = true; + } + + void SetInvalid() { m_isValid = false; } + + Containers::String m_name; + Containers::String m_path; + ResourceGUID m_guid; + bool m_isValid = false; + size_t m_memorySize = 0; +}; + +} // namespace Resources +} // namespace XCEngine +``` + +#### 步骤 11.2.4 实现 ResourceHandle.h + +**文件**: `engine/include/XCEngine/Resources/ResourceHandle.h` + +```cpp +#pragma once +#include "IResource.h" +#include +#include + +namespace XCEngine { +namespace Resources { + +template +class ResourceHandle { + static_assert(std::is_base_of_v, "T must derive from IResource"); + +public: + ResourceHandle() = default; + + explicit ResourceHandle(T* resource) + : m_resource(resource) { + if (m_resource) { + ResourceManager::Get().AddRef(m_resource->GetGUID()); + } + } + + ResourceHandle(const ResourceHandle& other) + : m_resource(other.m_resource) { + if (m_resource) { + ResourceManager::Get().AddRef(m_resource->GetGUID()); + } + } + + ResourceHandle(ResourceHandle&& other) noexcept + : m_resource(other.m_resource) { + other.m_resource = nullptr; + } + + ~ResourceHandle() { + Reset(); + } + + ResourceHandle& operator=(const ResourceHandle& other) { + if (this != &other) { + Reset(); + m_resource = other.m_resource; + if (m_resource) { + ResourceManager::Get().AddRef(m_resource->GetGUID()); + } + } + return *this; + } + + ResourceHandle& operator=(ResourceHandle&& other) noexcept { + if (this != &other) { + Reset(); + m_resource = other.m_resource; + other.m_resource = nullptr; + } + return *this; + } + + T* Get() const { return m_resource; } + T* operator->() const { return m_resource; } + T& operator*() const { return *m_resource; } + + bool IsValid() const { return m_resource != nullptr && m_resource->IsValid(); } + explicit operator bool() const { return IsValid(); } + + ResourceGUID GetGUID() const { + return m_resource ? m_resource->GetGUID() : ResourceGUID(0); + } + + ResourceType GetResourceType() const { + return m_resource ? m_resource->GetType() : ResourceType::Unknown; + } + + void Reset() { + if (m_resource) { + ResourceManager::Get().Release(m_resource->GetGUID()); + m_resource = nullptr; + } + } + + void Swap(ResourceHandle& other) { + std::swap(m_resource, other.m_resource); + } + +private: + T* m_resource = nullptr; +}; + +template +bool operator==(const ResourceHandle& lhs, const ResourceHandle& rhs) { + return lhs.GetGUID() == rhs.GetGUID(); +} + +template +bool operator!=(const ResourceHandle& lhs, const ResourceHandle& rhs) { + return !(lhs == rhs); +} + +} // namespace Resources +} // namespace XCEngine +``` + +#### 步骤 11.2.5 实现 IResourceLoader.h + +**文件**: `engine/include/XCEngine/Resources/IResourceLoader.h` + +```cpp +#pragma once +#include "IResource.h" +#include "ResourceTypes.h" +#include "../Containers/String.h" +#include "../Containers/Array.h" +#include + +namespace XCEngine { +namespace Resources { + +struct LoadResult { + IResource* resource = nullptr; + bool success = false; + Containers::String errorMessage; + + LoadResult() = default; + explicit LoadResult(IResource* res) : resource(res), success(res != nullptr) {} + explicit LoadResult(const Containers::String& error) : success(false), errorMessage(error) {} + explicit LoadResult(bool success, const Containers::String& error = "") + : success(success), errorMessage(error) {} + + operator bool() const { return success && resource != nullptr; } +}; + +class IResourceLoader { +public: + virtual ~IResourceLoader() = default; + + virtual ResourceType GetResourceType() const = 0; + virtual Containers::Array GetSupportedExtensions() const = 0; + virtual bool CanLoad(const Containers::String& path) const = 0; + virtual LoadResult Load(const Containers::String& path, const ImportSettings* settings = nullptr) = 0; + + virtual void LoadAsync(const Containers::String& path, + const ImportSettings* settings, + std::function callback) { + LoadResult result = Load(path, settings); + if (callback) { + callback(result); + } + } + + virtual ImportSettings* GetDefaultSettings() const = 0; + +protected: + static Containers::Array ReadFileData(const Containers::String& path); + static Containers::String GetExtension(const Containers::String& path); +}; + +#define REGISTER_RESOURCE_LOADER(loaderType) \ + namespace { \ + struct loaderType##Registrar { \ + loaderType##Registrar() { \ + ResourceManager::Get().RegisterLoader(new loaderType()); \ + } \ + } g_##loaderType##Registrar; \ + } + +} // namespace Resources +} // namespace XCEngine +``` + +#### 步骤 11.2.6 实现 ResourceManager.h + +**文件**: `engine/include/XCEngine/Resources/ResourceManager.h` + +```cpp +#pragma once +#include "IResourceLoader.h" +#include "ResourceCache.h" +#include "AsyncLoader.h" +#include "../Containers/String.h" +#include "../Containers/Array.h" +#include "../Containers/HashMap.h" +#include "../Threading/Mutex.h" +#include "../Debug/Logger.h" + +namespace XCEngine { +namespace Resources { + +class ResourceManager { +public: + static ResourceManager& Get(); + + void Initialize(); + void Shutdown(); + + void SetResourceRoot(const Containers::String& rootPath); + const Containers::String& GetResourceRoot() const; + + template + ResourceHandle Load(const Containers::String& path, ImportSettings* settings = nullptr) { + static_assert(std::is_base_of_v, "T must derive from IResource"); + + // 实现见文档Section 5.4 + } + + void LoadAsync(const Containers::String& path, ResourceType type, + std::function callback); + void LoadAsync(const Containers::String& path, ResourceType type, ImportSettings* settings, + std::function callback); + + void Unload(const Containers::String& path); + void Unload(ResourceGUID guid); + void UnloadUnused(); + void UnloadAll(); + + void AddRef(ResourceGUID guid); + void Release(ResourceGUID guid); + Core::uint32 GetRefCount(ResourceGUID guid) const; + + void RegisterLoader(IResourceLoader* loader); + void UnregisterLoader(ResourceType type); + IResourceLoader* GetLoader(ResourceType type) const; + + void SetMemoryBudget(size_t bytes); + size_t GetMemoryUsage() const; + size_t GetMemoryBudget() const; + void FlushCache(); + + IResource* Find(const Containers::String& path); + IResource* Find(ResourceGUID guid); + bool Exists(const Containers::String& path) const; + bool Exists(ResourceGUID guid) const; + + Containers::String ResolvePath(const Containers::String& relativePath) const; + +private: + ResourceManager() = default; + ~ResourceManager() = default; + + IResource* FindInCache(ResourceGUID guid); + void AddToCache(ResourceGUID guid, IResource* resource); + IResourceLoader* FindLoader(ResourceType type); + void ReloadResource(ResourceGUID guid); + + Containers::String m_resourceRoot; + Containers::HashMap m_resourceCache; + Containers::HashMap m_refCounts; + Containers::HashMap m_guidToPath; + Containers::HashMap> m_loaders; + + size_t m_memoryUsage = 0; + size_t m_memoryBudget = 512 * 1024 * 1024; + + UniquePtr m_asyncLoader; + Threading::Mutex m_mutex; + + friend class ResourceHandleBase; +}; + +} // namespace Resources +} // namespace XCEngine +``` + +#### 步骤 11.2.7 实现 ResourceManager.cpp + +**文件**: `engine/src/Resources/ResourceManager.cpp` + +```cpp +#include "Resources/ResourceManager.h" +#include "Resources/ResourceHandle.h" + +namespace XCEngine { +namespace Resources { + +ResourceManager& ResourceManager::Get() { + static ResourceManager instance; + return instance; +} + +void ResourceManager::Initialize() { + m_asyncLoader = UniquePtr(new AsyncLoader()); + m_asyncLoader->Initialize(2); // 默认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 == m_refCounts.End()) { + m_refCounts.Insert(guid, 1); + } else { + it->second++; + } + + 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 != m_refCounts.End()) { + it->second--; + + if (it->second == 0) { + m_refCounts.Erase(guid); + m_cache.OnZeroRefCount(guid); + } + } +} + +Core::uint32 ResourceManager::GetRefCount(ResourceGUID guid) const { + std::lock_guard lock(m_mutex); + + auto it = m_refCounts.Find(guid); + return it != m_refCounts.End() ? it->second : 0; +} + +void ResourceManager::RegisterLoader(IResourceLoader* loader) { + std::lock_guard lock(m_mutex); + m_loaders.Insert(loader->GetResourceType(), UniquePtr(loader)); +} + +IResourceLoader* ResourceManager::GetLoader(ResourceType type) const { + std::lock_guard lock(m_mutex); + + auto it = m_loaders.Find(type); + return it != m_loaders.End() ? it->second.Get() : 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 != m_resourceCache.End() ? it->second : 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 != m_resourceCache.End()) { + IResource* resource = it->second; + m_resourceCache.Erase(guid); + m_memoryUsage -= resource->GetMemorySize(); + resource->Release(); + } +} + +void ResourceManager::UnloadAll() { + std::lock_guard lock(m_mutex); + + for (auto& pair : m_resourceCache) { + pair.second->Release(); + } + 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) { + ResourceGUID guid = MakeResourceGUID(path.CStr()); + return Find(guid); +} + +IResource* ResourceManager::Find(ResourceGUID guid) { + return FindInCache(guid); +} + +bool ResourceManager::Exists(const Containers::String& path) const { + return Find(MakeResourceGUID(path.CStr())) != nullptr; +} + +bool ResourceManager::Exists(ResourceGUID guid) const { + return false; // 需要实现 +} + +Containers::String ResourceManager::ResolvePath(const Containers::String& relativePath) const { + return m_resourceRoot + "/" + relativePath; +} + +void ResourceManager::LoadAsync(const Containers::String& path, ResourceType type, + std::function callback) { + LoadAsync(path, type, nullptr, callback); +} + +void ResourceManager::LoadAsync(const Containers::String& path, ResourceType type, + ImportSettings* settings, + std::function)> callback) { + m_asyncLoader->Submit(path, type, settings, callback); +} + +void ResourceManager::Unload(const Containers::String& path) { + Unload(MakeResourceGUID(path.CStr())); +} + +void ResourceManager::UnloadUnused() { + // 实现清理未使用资源 +} + +void ResourceManager::UnregisterLoader(ResourceType type) { + m_loaders.Erase(type); +} + +void ResourceManager::ReloadResource(ResourceGUID guid) { + // 实现重新加载逻辑 +} + +} // namespace Resources +} // namespace XCEngine +``` + +### 11.3 第二阶段:缓存系统(天4-5) + +#### 步骤 11.3.1 实现 ResourceCache.h + +**文件**: `engine/include/XCEngine/Resources/ResourceCache.h` + +```cpp +#pragma once +#include "ResourceTypes.h" +#include "../Containers/HashMap.h" +#include "../Containers/Array.h" +#include "../Threading/Mutex.h" +#include + +namespace XCEngine { +namespace Resources { + +struct CacheEntry { + IResource* resource; + ResourceGUID guid; + size_t memorySize; + Core::uint64 lastAccessTime; + Core::uint32 accessCount; + + CacheEntry() : resource(nullptr), memorySize(0), lastAccessTime(0), accessCount(0) {} + CacheEntry(IResource* res, size_t size) + : resource(res), guid(res->GetGUID()), memorySize(size), + lastAccessTime(GetCurrentTick()), accessCount(1) {} + +private: + static Core::uint64 GetCurrentTick(); +}; + +class ResourceCache { +public: + ResourceCache(); + ~ResourceCache(); + + void Add(ResourceGUID guid, IResource* resource); + void Remove(ResourceGUID guid); + IResource* Find(ResourceGUID guid) const; + void Touch(ResourceGUID guid); + + size_t GetSize() const { return m_cache.Size(); } + size_t GetMemoryUsage() const { return m_memoryUsage; } + + void SetMemoryBudget(size_t bytes); + size_t GetMemoryBudget() const { return m_memoryBudget; } + + void OnMemoryPressure(size_t requiredBytes); + void OnZeroRefCount(ResourceGUID guid); + void Flush(); + void Clear(); + + Containers::Array GetLRUList(size_t count) const; + +private: + void Evict(size_t requiredBytes); + void UpdateMemoryStats(); + + Containers::HashMap m_cache; + Containers::Array m_lruOrder; + size_t m_memoryUsage = 0; + size_t m_memoryBudget = 512 * 1024 * 1024; + + Threading::Mutex m_mutex; +}; + +} // namespace Resources +} // namespace XCEngine +``` + +#### 步骤 11.3.2 实现 ResourceCache.cpp + +**文件**: `engine/src/Resources/ResourceCache.cpp` + +```cpp +#include "Resources/ResourceCache.h" + +namespace XCEngine { +namespace Resources { + +// 简单的时间戳实现,实际可使用Profiler::Get().GetTickCount() +static Core::uint64 g_currentTick = 0; +Core::uint64 CacheEntry::GetCurrentTick() { + return ++g_currentTick; +} + +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.Add(guid); + m_memoryUsage += entry.memorySize; +} + +void ResourceCache::Remove(ResourceGUID guid) { + std::lock_guard lock(m_mutex); + + auto it = m_cache.Find(guid); + if (it != m_cache.End()) { + m_memoryUsage -= it->second.memorySize; + m_cache.Erase(guid); + + for (auto lit = m_lruOrder.Begin(); lit != m_lruOrder.End(); ++lit) { + if (*lit == guid) { + m_lruOrder.Erase(lit); + break; + } + } + } +} + +IResource* ResourceCache::Find(ResourceGUID guid) const { + std::lock_guard lock(m_mutex); + + auto it = m_cache.Find(guid); + return it != m_cache.End() ? it->second.resource : nullptr; +} + +void ResourceCache::Touch(ResourceGUID guid) { + std::lock_guard lock(m_mutex); + + auto it = m_cache.Find(guid); + if (it != m_cache.End()) { + it->second.lastAccessTime = CacheEntry::GetCurrentTick(); + it->second.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) { + // 引用计数为0时,标记资源可以被淘汰 + // 实际淘汰由LRU策略决定 +} + +void ResourceCache::Evict(size_t requiredBytes) { + size_t released = 0; + + for (auto it = m_lruOrder.Begin(); it != m_lruOrder.End() && released < requiredBytes; ) { + ResourceGUID guid = *it; + auto cacheIt = m_cache.Find(guid); + + if (cacheIt != m_cache.End()) { + CacheEntry& entry = cacheIt->second; + + if (ResourceManager::Get().GetRefCount(guid) == 0) { + size_t entrySize = entry.memorySize; + + m_cache.Erase(guid); + m_memoryUsage -= entrySize; + released += entrySize; + + entry.resource->Release(); + it = m_lruOrder.Erase(it); + } else { + ++it; + } + } else { + ++it; + } + } +} + +void ResourceCache::Flush() { + std::lock_guard lock(m_mutex); + + for (auto& pair : m_cache) { + if (ResourceManager::Get().GetRefCount(pair.first) == 0) { + pair.second.resource->Release(); + } + } + + 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 ResourceCache::GetLRUList(size_t count) const { + std::lock_guard lock(m_mutex); + + Containers::Array result; + size_t n = std::min(count, static_cast(m_lruOrder.Size())); + + for (size_t i = 0; i < n; i++) { + result.Add(m_lruOrder[i]); + } + + return result; +} + +} // namespace Resources +} // namespace XCEngine +``` + +### 11.4 第三阶段:异步加载(天6-7) + +#### 步骤 11.4.1 实现 AsyncLoader.h + +**文件**: `engine/include/XCEngine/Resources/AsyncLoader.h` + +```cpp +#pragma once +#include "IResourceLoader.h" +#include "../Containers/Array.h" +#include "../Threading/Mutex.h" +#include +#include + +namespace XCEngine { +namespace Resources { + +struct LoadRequest { + Containers::String path; + ResourceType type; + std::function callback; + UniquePtr settings; + Core::uint64 requestId; + + LoadRequest() : requestId(0) {} + + LoadRequest(const Containers::String& p, ResourceType t, + std::function cb, ImportSettings* s = nullptr) + : path(p), type(t), callback(std::move(cb)), + settings(s), requestId(GenerateRequestId()) {} + +private: + static Core::uint64 GenerateRequestId(); +}; + +class LoadTask : public Threading::ITask { +public: + LoadTask(LoadRequest request, IResourceLoader* loader); + + void Execute() override; + LoadResult& GetResult() { return m_result; } + +private: + LoadRequest m_request; + IResourceLoader* m_loader; + LoadResult m_result; +}; + +class AsyncLoader { +public: + static AsyncLoader& Get(); + + void Initialize(Core::uint32 workerThreadCount = 2); + void Shutdown(); + + void Submit(const Containers::String& path, ResourceType type, + std::function callback); + void Submit(const Containers::String& path, ResourceType type, ImportSettings* settings, + std::function callback); + + void Update(); + bool IsLoading() const { return m_pendingCount > 0; } + Core::uint32 GetPendingCount() const { return m_pendingCount; } + float GetProgress() const; + void CancelAll(); + void Cancel(Core::uint64 requestId); + +private: + AsyncLoader() = default; + ~AsyncLoader() = default; + + void SubmitInternal(LoadRequest& request); + IResourceLoader* FindLoader(ResourceType type) const; + + Threading::Mutex m_queueMutex; + Containers::Array m_pendingQueue; + + Threading::Mutex m_completedMutex; + Containers::Array m_completedQueue; + + std::atomic m_pendingCount{0}; + std::atomic m_completedCount{0}; + Core::uint32 m_totalRequested = 0; +}; + +} // namespace Resources +} // namespace XCEngine +``` + +#### 步骤 11.4.2 实现 AsyncLoader.cpp + +**文件**: `engine/src/Resources/AsyncLoader.cpp` + +```cpp +#include "Resources/AsyncLoader.h" +#include "Resources/ResourceManager.h" +#include "../Threading/TaskSystem.h" + +namespace XCEngine { +namespace Resources { + +Core::uint64 LoadRequest::GenerateRequestId() { + static std::atomic s_requestId{0}; + return ++s_requestId; +} + +LoadTask::LoadTask(LoadRequest request, IResourceLoader* loader) + : m_request(std::move(request)), m_loader(loader) {} + +void LoadTask::Execute() { + m_result = m_loader->Load(m_request.path, m_request.settings.Get()); + + // 放入完成队列 + AsyncLoader::Get().QueueCompleted(std::move(m_request), std::move(m_result)); +} + +AsyncLoader& AsyncLoader::Get() { + static AsyncLoader instance; + return instance; +} + +void AsyncLoader::Initialize(Core::uint32 workerThreadCount) { + // TaskSystem已初始化,此处不需要额外操作 +} + +void AsyncLoader::Shutdown() { + CancelAll(); +} + +void AsyncLoader::Submit(const Containers::String& path, ResourceType type, + std::function callback) { + Submit(path, type, nullptr, callback); +} + +void AsyncLoader::Submit(const Containers::String& path, ResourceType type, + ImportSettings* settings, std::function callback) { + LoadRequest request(path, type, callback, settings); + SubmitInternal(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.Add(request); + m_pendingCount++; + m_totalRequested++; + } + + // 提交到任务系统 + auto task = new LoadTask(request, loader); + Threading::TaskSystem::Get().Submit(UniquePtr(task)); +} + +void AsyncLoader::Update() { + Containers::Array completed; + + { + std::lock_guard lock(m_completedMutex); + completed = std::move(m_completedQueue); + m_completedQueue.Clear(); + } + + for (auto& request : completed) { + m_pendingCount--; + + if (request.callback) { + request.callback(m_completedResults[request.requestId]); + } + } + + m_completedResults.Clear(); +} + +float AsyncLoader::GetProgress() const { + if (m_totalRequested == 0) return 1.0f; + return static_cast(m_totalRequested - m_pendingCount) / 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); + + for (auto it = m_pendingQueue.Begin(); it != m_pendingQueue.End(); ++it) { + if (it->requestId == requestId) { + m_pendingQueue.Erase(it); + m_pendingCount--; + return; + } + } +} + +IResourceLoader* AsyncLoader::FindLoader(ResourceType type) const { + return ResourceManager::Get().GetLoader(type); +} + +} // namespace Resources +} // namespace XCEngine +``` + +### 11.5 第四阶段:具体资源类型(天8-11) + +#### 步骤 11.5.1 实现 Texture 及其加载器 + +**文件**: `engine/include/XCEngine/Resources/Texture.h` + +```cpp +#pragma once +#include "IResource.h" +#include "../Core/Types.h" + +namespace XCEngine { +namespace Resources { + +enum class TextureType { + Texture2D, Texture3D, TextureCube, Texture2DArray, TextureCubeArray +}; + +enum class TextureFormat { + Unknown, R8_UNORM, RG8_UNORM, RGBA8_UNORM, RGBA8_SRGB, + R16_FLOAT, RG16_FLOAT, RGBA16_FLOAT, + R32_FLOAT, RG32_FLOAT, RGBA32_FLOAT, + D16_UNORM, D24_UNORM_S8_UINT, D32_FLOAT, D32_FLOAT_S8_X24_UINT, + BC1_UNORM, BC1_UNORM_SRGB, BC2_UNORM, BC2_UNORM_SRGB, + BC3_UNORM, BC3_UNORM_SRGB, BC4_UNORM, BC5_UNORM, BC6H_UF16, + BC7_UNORM, BC7_UNORM_SRGB +}; + +enum class TextureUsage : Core::uint8 { + None = 0, ShaderResource = 1 << 0, RenderTarget = 1 << 1, + DepthStencil = 1 << 2, UnorderedAccess = 1 << 3, + TransferSrc = 1 << 4, TransferDst = 1 << 5 +}; + +class Texture : public IResource { +public: + Texture(); + virtual ~Texture() override; + + ResourceType GetType() const override { return ResourceType::Texture; } + const Containers::String& GetName() const override { return m_name; } + const Containers::String& GetPath() const override { return m_path; } + ResourceGUID GetGUID() const override { return m_guid; } + bool IsValid() const override { return m_isValid; } + size_t GetMemorySize() const override { return m_memorySize; } + void Release() override; + + Core::uint32 GetWidth() const { return m_width; } + Core::uint32 GetHeight() const { return m_height; } + Core::uint32 GetDepth() const { return m_depth; } + Core::uint32 GetMipLevels() const { return m_mipLevels; } + Core::uint32 GetArraySize() const { return m_arraySize; } + TextureType GetTextureType() const { return m_textureType; } + TextureFormat GetFormat() const { return m_format; } + TextureUsage GetUsage() const { return m_usage; } + + class IRHIResource* GetRHIResource() const { return m_rhiResource; } + void SetRHIResource(class IRHIResource* resource); + + bool Create(Core::uint32 width, Core::uint32 height, Core::uint32 depth, + Core::uint32 mipLevels, TextureType type, TextureFormat format, + const void* data, size_t dataSize); + bool GenerateMipmaps(); + +private: + Core::uint32 m_width = 0; + Core::uint32 m_height = 0; + Core::uint32 m_depth = 1; + Core::uint32 m_mipLevels = 1; + Core::uint32 m_arraySize = 1; + TextureType m_textureType = TextureType::Texture2D; + TextureFormat m_format = TextureFormat::RGBA8_UNORM; + TextureUsage m_usage = TextureUsage::ShaderResource; + + class IRHIResource* m_rhiResource = nullptr; +}; + +} // namespace Resources +} // namespace XCEngine +``` + +**实现要点**: +1. 使用stb_image库加载PNG/JPG/TGA +2. 支持生成Mipmap +3. 完成后创建RHI资源 + +#### 步骤 11.5.2 实现 Mesh 及其加载器 + +**文件**: `engine/include/XCEngine/Resources/Mesh.h` + +```cpp +#pragma once +#include "IResource.h" +#include "../Containers/Array.h" +#include "../Math/AABB.h" + +namespace XCEngine { +namespace Resources { + +enum class VertexAttribute : Core::uint32 { + Position = 1 << 0, Normal = 1 << 1, Tangent = 1 << 2, + Color = 1 << 3, UV0 = 1 << 4, UV1 = 1 << 5, + UV2 = 1 << 6, UV3 = 1 << 7, BoneWeights = 1 << 8, BoneIndices = 1 << 9 +}; + +struct MeshSection { + Core::uint32 baseVertex; + Core::uint32 vertexCount; + Core::uint32 startIndex; + Core::uint32 indexCount; + Core::uint32 materialID; + Math::AABB boundingBox; +}; + +class Mesh : public IResource { +public: + Mesh(); + virtual ~Mesh() override; + + ResourceType GetType() const override { return ResourceType::Mesh; } + const Containers::String& GetName() const override { return m_name; } + const Containers::String& GetPath() const override { return m_path; } + ResourceGUID GetGUID() const override { return m_guid; } + bool IsValid() const override { return m_isValid; } + size_t GetMemorySize() const override { return m_memorySize; } + void Release() override; + + void SetVertexData(const void* data, size_t size, Core::uint32 vertexCount, + Core::uint32 vertexStride, VertexAttribute attributes); + const void* GetVertexData() const { return m_vertexData.Data(); } + size_t GetVertexDataSize() const { return m_vertexData.Size(); } + Core::uint32 GetVertexCount() const { return m_vertexCount; } + Core::uint32 GetVertexStride() const { return m_vertexStride; } + VertexAttribute GetVertexAttributes() const { return m_attributes; } + + void SetIndexData(const void* data, size_t size, Core::uint32 indexCount, bool use32Bit); + const void* GetIndexData() const { return m_indexData.Data(); } + size_t GetIndexDataSize() const { return m_indexData.Size(); } + Core::uint32 GetIndexCount() const { return m_indexCount; } + bool IsUse32BitIndex() const { return m_use32BitIndex; } + + void AddSection(const MeshSection& section); + const Containers::Array& GetSections() const { return m_sections; } + + void SetBoundingBox(const Math::AABB& box); + const Math::AABB& GetBoundingBox() const { return m_boundingBox; } + + class IRHIBuffer* GetVertexBuffer() const { return m_vertexBuffer; } + class IRHIBuffer* GetIndexBuffer() const { return m_indexBuffer; } + void SetRHIBuffers(class IRHIBuffer* vb, class IRHIBuffer* ib); + +private: + Containers::Array m_vertexData; + Core::uint32 m_vertexCount = 0; + Core::uint32 m_vertexStride = 0; + VertexAttribute m_attributes = VertexAttribute::Position; + + Containers::Array m_indexData; + Core::uint32 m_indexCount = 0; + bool m_use32BitIndex = false; + + Containers::Array m_sections; + Math::AABB m_boundingBox; + + class IRHIBuffer* m_vertexBuffer = nullptr; + class IRHIBuffer* m_indexBuffer = nullptr; +}; + +} // namespace Resources +} // namespace XCEngine +``` + +#### 步骤 11.5.3 实现 Material 及其加载器 + +**文件**: `engine/include/XCEngine/Resources/Material.h` + +```cpp +#pragma once +#include "IResource.h" +#include "ResourceHandle.h" +#include "Texture.h" +#include "../Containers/HashMap.h" +#include "../Math/Vector2.h" +#include "../Math/Vector3.h" +#include "../Math/Vector4.h" + +namespace XCEngine { +namespace Resources { + +enum class MaterialPropertyType { + Float, Float2, Float3, Float4, + Int, Int2, Int3, Int4, + Bool, Texture, Cubemap +}; + +struct MaterialProperty { + Containers::String name; + MaterialPropertyType type; + + union Value { + float floatValue[4]; + Core::int32 intValue[4]; + bool boolValue; + ResourceHandle textureValue; + + Value() { memset(this, 0, sizeof(Value)); } + } value; + + Core::uint32 refCount; +}; + +class Material : public IResource { +public: + Material(); + virtual ~Material() override; + + ResourceType GetType() const override { return ResourceType::Material; } + const Containers::String& GetName() const override { return m_name; } + const Containers::String& GetPath() const override { return m_path; } + ResourceGUID GetGUID() const override { return m_guid; } + bool IsValid() const override { return m_isValid; } + size_t GetMemorySize() const override { return m_memorySize; } + void Release() override; + + void SetShader(const ResourceHandle& shader); + class Shader* GetShader() const { return m_shader.Get(); } + + void SetFloat(const Containers::String& name, float value); + void SetFloat2(const Containers::String& name, const Math::Vector2& value); + void SetFloat3(const Containers::String& name, const Math::Vector3& value); + void SetFloat4(const Containers::String& name, const Math::Vector4& value); + void SetInt(const Containers::String& name, int32 value); + void SetBool(const Containers::String& name, bool value); + void SetTexture(const Containers::String& name, const ResourceHandle& texture); + + float GetFloat(const Containers::String& name) const; + ResourceHandle GetTexture(const Containers::String& name) const; + + const Containers::Array& GetConstantBufferData() const { return m_constantBufferData; } + void UpdateConstantBuffer(); + +private: + ResourceHandle m_shader; + Containers::HashMap m_properties; + Containers::Array m_constantBufferData; + + struct TextureBinding { + Containers::String name; + Core::uint32 slot; + ResourceHandle texture; + }; + Containers::Array m_textureBindings; +}; + +} // namespace Resources +} // namespace XCEngine +``` + +#### 步骤 11.5.4 实现 AudioClip 及其加载器 + +类似实现,支持WAV格式加载。 + +### 11.6 第五阶段:文件系统集成(天12-13) + +#### 步骤 11.6.1 实现 ResourceFileSystem + +**文件**: `engine/include/XCEngine/Resources/ResourceFileSystem.h` + +```cpp +#pragma once +#include "ResourceTypes.h" +#include "../Containers/String.h" +#include "../Containers/Array.h" +#include "../Containers/HashMap.h" + +namespace XCEngine { +namespace Resources { + +class ResourceFileSystem { +public: + ResourceFileSystem(); + ~ResourceFileSystem(); + + void Initialize(const Containers::String& rootPath); + void Shutdown(); + + bool AddArchive(const Containers::String& archivePath); + bool AddDirectory(const Containers::String& directoryPath); + void RemoveArchive(const Containers::String& archivePath); + + bool FindResource(const Containers::String& relativePath, + Containers::String& outAbsolutePath) const; + Containers::Array ReadResource(const Containers::String& relativePath) const; + bool Exists(const Containers::String& relativePath) const; + + struct ResourceInfo { + Containers::String path; + size_t size; + Core::uint64 modifiedTime; + bool inArchive; + Containers::String archivePath; + }; + + bool GetResourceInfo(const Containers::String& relativePath, ResourceInfo& outInfo) const; + void EnumerateResources(const Containers::String& pattern, + Containers::Array& outResources) const; + +private: + class IArchive { + public: + virtual ~IArchive() = default; + virtual bool Open(const Containers::String& path) = 0; + virtual void Close() = 0; + virtual bool Read(const Containers::String& fileName, void* buffer, + size_t size, size_t offset) const = 0; + virtual size_t GetSize(const Containers::String& fileName) const = 0; + virtual bool Exists(const Containers::String& fileName) const = 0; + virtual void Enumerate(const Containers::String& pattern, + Containers::Array& outFiles) const = 0; + }; + + Containers::String m_rootPath; + Containers::Array> m_archives; + Containers::Array m_directories; + mutable Containers::HashMap m_infoCache; +}; + +} // namespace Resources +} // namespace XCEngine +``` + +### 11.7 第六阶段:依赖管理(天14-15) + +#### 步骤 11.7.1 实现 ResourceDependencyGraph + +```cpp +// 见文档Section 9 +``` + +### 11.8 第七阶段:测试与集成(天16-17) + +#### 步骤 11.8.1 单元测试 + +创建测试用例: +1. 资源加载/卸载 +2. 引用计数 +3. 缓存淘汰 +4. 异步加载 +5. 多线程安全 + +#### 步骤 11.8.2 集成到现有mvs项目 + +在示例应用中使用资源系统加载纹理和模型。 + +### 11.9 每日任务清单 + +| 天数 | 任务 | 完成标准 | +|------|------|----------| +| 1 | 创建目录结构 + Resources.h + ResourceTypes.h | 编译通过 | +| 2 | IResource.h + ResourceHandle.h | 智能指针正常工作 | +| 3 | IResourceLoader.h + ResourceManager.h框架 | 加载器接口完成 | +| 4 | ResourceCache.h/cpp | LRU淘汰正常 | +| 5 | ResourceManager与Cache集成 | 引用计数正常 | +| 6 | AsyncLoader.h/cpp框架 | 任务提交正常 | +| 7 | 异步回调机制 | 主线程回调正常 | +| 8 | Texture.h + 基础加载 | PNG加载成功 | +| 9 | Texture RHI资源创建 | 渲染器能使用 | +| 10 | Mesh.h + 加载器 | OBJ加载成功 | +| 11 | Material.h + 加载器 | JSON材质加载 | +| 12 | ResourceFileSystem | 目录/归档支持 | +| 13 | 资源打包Builder | 打包成功 | +| 14 | DependencyGraph | 依赖关系正确 | +| 15 | 资源组加载 | 批量加载正常 | +| 16 | 单元测试 | 测试通过 | +| 17 | 集成测试 | 示例运行正常 | + +--- + +## 13. 关键技术点 + +### 13.1 引用计数与缓存淘汰的交互 ```cpp // 引用计数管理 @@ -2152,7 +3695,7 @@ void ResourceManager::Release(ResourceGUID guid) { } ``` -### 11.2 异步加载线程安全 +### 13.2 异步加载线程安全 ```cpp // AsyncLoader::Update() 在主线程调用 @@ -2184,7 +3727,7 @@ void LoadTask::Execute() { } ``` -### 11.3 内存压力响应 +### 13.3 内存压力响应 ```cpp void ResourceCache::OnMemoryPressure(size_t requiredBytes) { @@ -2231,9 +3774,9 @@ void ResourceCache::OnMemoryPressure(size_t requiredBytes) { --- -## 12. 使用示例 +## 14. 使用示例 -### 12.1 基本使用 +### 14.1 基本使用 ```cpp // 初始化资源系统 @@ -2292,7 +3835,7 @@ void LoadMeshAsyncExample() { } ``` -### 12.2 资源组加载 +### 14.2 资源组加载 ```cpp // 加载场景所需的所有资源 @@ -2330,7 +3873,7 @@ void LoadSceneResources(const String& scenePath) { } ``` -### 12.3 自定义导入设置 +### 14.3 自定义导入设置 ```cpp void LoadTextureWithSettings() { @@ -2351,7 +3894,7 @@ void LoadTextureWithSettings() { --- -## 13. 验收标准 +## 15. 验收标准 ### 13.1 功能验收 @@ -2380,7 +3923,7 @@ void LoadTextureWithSettings() { --- -## 14. 后续扩展 +## 16. 后续扩展 ### 14.1 可选的扩展功能 @@ -2404,7 +3947,7 @@ void LoadTextureWithSettings() { --- -## 15. 依赖关系 +## 17. 依赖关系 ``` 资源系统依赖关系图: diff --git a/engine/include/XCEngine/RHI/D3D12/D3D12Sampler.h b/engine/include/XCEngine/RHI/D3D12/D3D12Sampler.h index e480fd8e..80ad7557 100644 --- a/engine/include/XCEngine/RHI/D3D12/D3D12Sampler.h +++ b/engine/include/XCEngine/RHI/D3D12/D3D12Sampler.h @@ -3,6 +3,7 @@ #include #include +#include "../RHISampler.h" #include "D3D12Enum.h" using Microsoft::WRL::ComPtr; @@ -10,17 +11,21 @@ using Microsoft::WRL::ComPtr; namespace XCEngine { namespace RHI { -class D3D12Sampler { +class D3D12Sampler : public RHISampler { public: D3D12Sampler(); - ~D3D12Sampler(); + ~D3D12Sampler() override; bool Initialize(ID3D12Device* device, const D3D12_SAMPLER_DESC& desc); - void Shutdown(); + void Shutdown() override; D3D12_SAMPLER_DESC GetDesc() const { return m_desc; } - void* GetNativeHandle() const { return nullptr; } + void* GetNativeHandle() override { return nullptr; } + unsigned int GetID() override { return 0; } + + void Bind(unsigned int unit) override { } + void Unbind(unsigned int unit) override { } private: D3D12_SAMPLER_DESC m_desc; diff --git a/engine/include/XCEngine/RHI/OpenGL/OpenGLSampler.h b/engine/include/XCEngine/RHI/OpenGL/OpenGLSampler.h index 8dee4e9e..006cd85b 100644 --- a/engine/include/XCEngine/RHI/OpenGL/OpenGLSampler.h +++ b/engine/include/XCEngine/RHI/OpenGL/OpenGLSampler.h @@ -2,6 +2,9 @@ #include +#include "../RHISampler.h" +#include "../RHITypes.h" + namespace XCEngine { namespace RHI { @@ -26,7 +29,7 @@ enum class SamplerCompareMode { CompareToRef }; -struct SamplerDesc { +struct OpenGLSamplerDesc { SamplerFilter minFilter = SamplerFilter::LinearMipmapLinear; SamplerFilter magFilter = SamplerFilter::Linear; SamplerWrapMode wrapS = SamplerWrapMode::Repeat; @@ -39,22 +42,24 @@ struct SamplerDesc { float maxLod = 1000.0f; }; -class OpenGLSampler { +class OpenGLSampler : public RHISampler { public: OpenGLSampler(); - ~OpenGLSampler(); + ~OpenGLSampler() override; - bool Initialize(const SamplerDesc& desc); - void Shutdown(); + bool Initialize(const OpenGLSamplerDesc& desc); + void Shutdown() override; - void Bind(unsigned int unit); - void Unbind(unsigned int unit); + void Bind(unsigned int unit) override; + void Unbind(unsigned int unit) override; unsigned int GetID() const { return m_sampler; } + unsigned int GetID() override { return m_sampler; } + void* GetNativeHandle() override { return reinterpret_cast(static_cast(m_sampler)); } private: unsigned int m_sampler; - SamplerDesc m_desc; + OpenGLSamplerDesc m_desc; }; } // namespace RHI diff --git a/engine/include/XCEngine/RHI/RHISampler.h b/engine/include/XCEngine/RHI/RHISampler.h new file mode 100644 index 00000000..bc816635 --- /dev/null +++ b/engine/include/XCEngine/RHI/RHISampler.h @@ -0,0 +1,23 @@ +#pragma once + +#include "RHITypes.h" +#include "RHIEnums.h" + +namespace XCEngine { +namespace RHI { + +class RHISampler { +public: + virtual ~RHISampler() = default; + + virtual void Shutdown() = 0; + + virtual void Bind(unsigned int unit) = 0; + virtual void Unbind(unsigned int unit) = 0; + + virtual void* GetNativeHandle() = 0; + virtual unsigned int GetID() = 0; +}; + +} // namespace RHI +} // namespace XCEngine diff --git a/engine/src/RHI/OpenGL/OpenGLSampler.cpp b/engine/src/RHI/OpenGL/OpenGLSampler.cpp index 3596a0ca..5c761e7d 100644 --- a/engine/src/RHI/OpenGL/OpenGLSampler.cpp +++ b/engine/src/RHI/OpenGL/OpenGLSampler.cpp @@ -34,7 +34,7 @@ OpenGLSampler::OpenGLSampler() : m_sampler(0) { OpenGLSampler::~OpenGLSampler() { } -bool OpenGLSampler::Initialize(const SamplerDesc& desc) { +bool OpenGLSampler::Initialize(const OpenGLSamplerDesc& desc) { m_desc = desc; glGenSamplers(1, &m_sampler);