diff --git a/docs/RHI抽象层设计与实现.md b/docs/RHI抽象层设计与实现.md index ae79c291..a72757ff 100644 --- a/docs/RHI抽象层设计与实现.md +++ b/docs/RHI抽象层设计与实现.md @@ -253,7 +253,245 @@ public: ## 5. 核心差异处理方案 -### 5.1 根签名 vs OpenGL 资源绑定 + +### 5.1 缓冲区(RHIBuffer)抽象设计 + +#### 5.1.1 现有实现对比 + +| 功能 | D3D12Buffer | OpenGLBuffer | 处理方案 | +|------|-------------|--------------|----------| +| 初始化参数 | 需要 device + heapType | 不需要 | 后端各自实现初始化逻辑 | +| 句柄类型 | `ID3D12Resource*` | `GLuint` | 统一返回 `void*`,底层逃逸 | +| Map/Unmap | `Map()` / `Unmap()` | `glMapBuffer` | 后端各自实现 | +| 上传数据 | `UpdateData()` | `SetData()` | 统一为 `SetData()` | +| 获取大小 | `GetSize()` | `GetSize()` | 通用 | +| Vertex Stride | 显式存储 `m_stride` | VAO 管理 | 基类提供接口 | +| 资源状态 | `ResourceStates` 显式管理 | 无 | D3D12 维护,OpenGL 透明 | + +#### 5.1.2 抽象接口定义 + +```cpp +// engine/include/XCEngine/RHI/RHIBuffer.h +class RHIBuffer { +public: + virtual ~RHIBuffer() = default; + + // 数据操作 + virtual void* Map() = 0; + virtual void Unmap() = 0; + virtual void SetData(const void* data, size_t size, size_t offset = 0) = 0; + + // 属性查询 + virtual uint64_t GetSize() const = 0; + virtual BufferType GetBufferType() const = 0; + virtual void SetBufferType(BufferType type) = 0; + virtual uint32_t GetStride() const = 0; + virtual void SetStride(uint32_t stride) = 0; + + // 底层逃逸 + virtual void* GetNativeHandle() = 0; + + // 调试 + virtual const std::string& GetName() const = 0; + virtual void SetName(const std::string& name) = 0; + + // 生命周期 + virtual void Shutdown() = 0; +}; +``` + +#### 5.1.3 差异处理策略 + +1. **初始化参数差异** + - D3D12:在 `CreateBuffer()` 时由 Device 传入 device 参数,内部调用 `Initialize(device, size, ...)` + - OpenGL:直接调用 `Initialize(type, size, data, dynamic)`,不需要 device + +2. **句柄类型差异** + - `GetNativeHandle()` 返回 `void*` + - D3D12 后端:`return m_resource.Get();` + - OpenGL 后端:`return (void*)(uintptr_t)m_buffer;` + +3. **Vertex Stride** + - D3D12:显式存储在 `m_stride` + - OpenGL:在 VertexArray 中管理,可在基类中提供接口 + +4. **Device 创建接口** + ```cpp + // RHIDevice 中 + virtual RHIBuffer* CreateBuffer(const BufferDesc& desc) = 0; + + // D3D12Device 实现 + RHIBuffer* CreateBuffer(const BufferDesc& desc) override { + auto* buffer = new D3D12Buffer(); + buffer->Initialize(m_device.Get(), desc.size, ...); + return buffer; + } + + // OpenGLDevice 实现 + RHIBuffer* CreateBuffer(const BufferDesc& desc) override { + auto* buffer = new OpenGLBuffer(); + buffer->Initialize(glType, desc.size, ...); + return buffer; + } + ``` + +### 5.2 纹理(RHITexture)抽象设计 + +#### 5.2.1 设计理念对应 + +| 差异点 | 设计理念 | 处理方案 | +|--------|---------|---------| +| 初始化参数差异 | 求同存异 | 后端各自实现初始化,基类定义统一创建接口 | +| 句柄类型差异 | 底层逃逸 | 统一返回 void*,通过 GetNativeHandle() 获取原生类型 | +| 资源状态管理 | 特性降级 | D3D12 显式管理 ResourceStates,OpenGL 无需管理(透明) | +| 格式枚举差异 | 求同存异 | 基类统一 Format 枚举,后端映射到各自格式 | + +#### 5.2.2 现有实现对比 + +| 功能 | D3D12Texture | OpenGLTexture | 处理方案 | +|------|--------------|---------------|----------| +| 初始化参数 | device + resource desc | type + dimensions + format | 后端各自实现 | +| 句柄类型 | `ID3D12Resource*` | `GLuint` | 统一返回 `void*` | +| 尺寸获取 | GetWidth/Height/Depth | 同上 | 统一接口 | +| Mip Levels | GetMipLevels() | GetMipLevels() | 通用 | +| 格式 | DXGI_FORMAT | OpenGLFormat | 基类统一 Format | +| 纹理类型 | TextureType enum | OpenGLTextureType enum | 基类统一 TextureType | +| 绑定 | 通过 DescriptorHeap | glBindTexture | 后端实现 Bind() | +| Mipmap 生成 | 需手动计算 | glGenerateMipmap | 后端实现 | +| 资源状态 | ResourceStates | 无 | D3D12 维护,OpenGL 透明 | +| 深度纹理 | InitializeDepthStencil() | 普通纹理 | 后端实现 | + +#### 5.2.3 抽象接口定义 + +```cpp +class RHITexture { +public: + virtual ~RHITexture() = default; + + // 属性(求同存异) + virtual uint32_t GetWidth() const = 0; + virtual uint32_t GetHeight() const = 0; + virtual uint32_t GetDepth() const = 0; + virtual uint32_t GetMipLevels() const = 0; + virtual Format GetFormat() const = 0; + virtual TextureType GetTextureType() const = 0; + + // 资源状态(特性降级) + virtual ResourceStates GetState() const = 0; + virtual void SetState(ResourceStates state) = 0; + + // 底层逃逸 + virtual void* GetNativeHandle() = 0; + + // 调试 + virtual const std::string& GetName() const = 0; + virtual void SetName(const std::string& name) = 0; + + // 生命周期 + virtual void Shutdown() = 0; +}; +``` + +#### 5.2.4 差异处理策略 + +1. **初始化参数差异(求同存异)** + - D3D12:需要 device + resource desc + - OpenGL:需要 type + dimensions + format + - 解决:Device 的 CreateTexture() 统一接收 TextureDesc,后端各自实现 Initialize() + +2. **句柄类型差异(底层逃逸)** + - `GetNativeHandle()` 返回 `void*` + - D3D12:`return m_resource.Get();` + - OpenGL:`return reinterpret_cast(static_cast(m_texture));` + +3. **资源状态管理(特性降级)** + - D3D12:显式 ResourceStates 管理,需要转换 barrier + - OpenGL:无资源状态概念 + - 解决:基类提供 GetState/SetState,D3D12 实现具体逻辑,OpenGL 空实现 + +4. **格式枚举差异(求同存异)** + - D3D12:DXGI_FORMAT + - OpenGL:OpenGLFormat + - 解决:基类统一使用 Format 枚举,后端内部映射 + +### 5.7 着色器(RHIShader)抽象设计 + +#### 5.7.1 设计理念对应 + +| 差异点 | 设计理念 | 处理方案 | +|--------|---------|---------| +| 编译方式差异 | 求同存异 | 统一 Compile 接口,后端各自实现 | +| 句柄类型差异 | 底层逃逸 | 统一返回 void* | +| Uniform 设置 | 特性降级 | OpenGL 实现,D3D12 空实现 | +| 绑定方式 | 求同存异 | 基类提供 Bind/Unbind,后端实现 | + +#### 5.7.2 现有实现对比 + +| 功能 | D3D12Shader | OpenGLShader | 处理方案 | +|------|-------------|--------------|----------| +| 编译 | CompileFromFile/Compile | 同上 | 统一接口 | +| 字节码/Program | ID3DBlob | GLuint | 统一 void* | +| 类型 | ShaderType | 自有 enum | 基类统一 | +| Uniform 设置 | 无 | SetInt/SetFloat... | OpenGL 实现,D3D12 空 | +| 绑定 | 通过 CommandList | Use()/Bind() | 基类提供 Bind/Unbind | + +#### 5.7.3 抽象接口定义 + +```cpp +class RHIShader { +public: + virtual ~RHIShader() = default; + + // 编译(求同存异) + virtual bool CompileFromFile(const wchar_t* filePath, const char* entryPoint, const char* target) = 0; + virtual bool Compile(const void* sourceData, size_t sourceSize, const char* entryPoint, const char* target) = 0; + + // 属性 + virtual ShaderType GetType() const = 0; + virtual bool IsValid() const = 0; + + // 绑定(求同存异) + virtual void Bind() = 0; + virtual void Unbind() = 0; + + // 底层逃逸 + virtual void* GetNativeHandle() = 0; + + // Uniform 设置(特性降级) + virtual void SetInt(const char* name, int value) = 0; + virtual void SetFloat(const char* name, float value) = 0; + virtual void SetVec3(const char* name, float x, float y, float z) = 0; + virtual void SetVec4(const char* name, float x, float y, float z, float w) = 0; + virtual void SetMat4(const char* name, const float* value) = 0; + + // 生命周期 + virtual void Shutdown() = 0; +}; +``` + +#### 5.7.4 差异处理策略 + +1. **编译方式差异(求同存异)** + - D3D12:需要 entry point + target(如 "vs_6_0") + - OpenGL:根据 source 类型自动判断 + - 解决:统一 Compile 接口,后端各自处理 + +2. **句柄类型差异(底层逃逸)** + - D3D12:ID3DBlob + - OpenGL:GLuint (program) + - 解决:GetNativeHandle() 返回 void* + +3. **Uniform 设置(特性降级)** + - D3D12:通过 RootSignature/CBV 设置,不在 Shader 类 + - OpenGL:通过 glUniform* 设置 + - 解决:D3D12 实现为空,OpenGL 实现具体逻辑 + +4. **绑定方式** + - D3D12:通过 CommandList->SetPipelineState + - OpenGL:glUseProgram + - 解决:基类提供 Bind/Unbind 接口 + +### 5.8 根签名 vs OpenGL 资源绑定 - **D3D12**:显式 `RootSignature` 定义资源绑定规则 - **OpenGL**:隐式通过 `glUniformLocation`、`glBindTextureUnit` 绑定 - **解决方案**: @@ -261,7 +499,7 @@ public: - D3D12 后端:内部创建 `ID3D12RootSignature` - OpenGL 后端:存储绑定点数量,绘制时自动调用 `glBind*` -### 5.2 描述符堆 vs OpenGL 纹理单元 +### 5.4 描述符堆 vs OpenGL 纹理单元 - **D3D12**:显式 `DescriptorHeap` 管理资源视图 - **OpenGL**:隐式通过 `glActiveTexture` 绑定 - **解决方案**: @@ -270,7 +508,7 @@ public: - D3D12 后端:从堆分配槽位,更新描述符 - OpenGL 后端:维护绑定点计数器,绘制时自动绑定 -### 5.3 多线程命令录制 +### 5.5 多线程命令录制 - **D3D12**:原生支持多线程录制不同 `CommandList` - **OpenGL**:状态机模型,单线程上下文 - **解决方案**: @@ -278,7 +516,7 @@ public: - D3D12 后端:真·并行提交 - OpenGL 后端:命令缓冲队列,单线程回放 -### 5.4 高级特性(光线追踪等) +### 5.6 高级特性(光线追踪等) - **解决方案**: 1. **特性检测**:通过 `RHICapabilities` 查询支持情况 2. **降级方案**:不支持时用传统路径替代 diff --git a/docs/plan/第四阶段计划_资源系统.md b/docs/plan/第四阶段计划_资源系统.md new file mode 100644 index 00000000..a6f919b5 --- /dev/null +++ b/docs/plan/第四阶段计划_资源系统.md @@ -0,0 +1,2448 @@ +# 资源系统设计与实现 + +> **目标**:构建游戏引擎资源管理系统,支持多种资源类型的加载、缓存、异步加载 +> **阶段**:第四阶段(与RHI并行开发) +> **前置依赖**:第一阶段核心基础层(容器、内存管理、线程系统) + +--- + +## 0. 类型声明(文档内统一使用) + +本文档中使用的类型说明: +- `String` = `XCEngine::Containers::String` +- `Array` = `XCEngine::Containers::Array` +- `HashMap` = `XCEngine::Containers::HashMap` +- `uint8/uint32/uint64` = `XCEngine::Core::uint8/uint32/uint64` +- `UniquePtr` = `XCEngine::Core::UniqueRef` 或 `std::unique_ptr` +- `SharedPtr` = `XCEngine::Core::Ref` 或 `std::shared_ptr` +- `Mutex` = `XCEngine::Threading::Mutex` +- `ITask` = `XCEngine::Threading::ITask` + +--- + +## 1. 概述 + +### 1.1 设计目标 + +资源系统是游戏引擎的核心基础设施之一,负责管理游戏运行时所需的所有数据资产。一个优秀的资源系统需要满足以下目标: + +#### 1.1.1 功能性目标 + +- **统一资源管理**:提供统一的接口来管理不同类型的资源(纹理、网格、材质、音频等) +- **异步加载支持**:支持后台线程异步加载资源,避免阻塞主线程 +- **资源缓存机制**:实现智能的资源缓存和淘汰策略,优化内存使用 +- **引用计数管理**:通过引用计数自动管理资源生命周期 +- **资源依赖管理**:跟踪资源之间的依赖关系,支持资源组加载和批量卸载 +- **可扩展架构**:易于添加新的资源类型和加载器 + +#### 1.1.2 性能目标 + +- **低内存占用**:通过LRU缓存和按需加载控制内存使用 +- **快速加载**:异步加载 + 缓存命中 = 零加载时间 +- **线程安全**:多线程环境下安全访问资源 +- **零拷贝优化**:尽可能减少不必要的数据拷贝 + +#### 1.1.3 开发效率目标 + +- **简单易用的API**:提供清晰的同步/异步加载接口 +- **灵活的配置**:支持自定义导入设置和加载选项 +- **完善的错误处理**:清晰的错误信息和调试支持 + +--- + +## 2. 系统架构 + +### 2.1 整体架构图 + +``` +┌─────────────────────────────────────────────────────────────────────────────────┐ +│ ResourceSystem │ +├─────────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────────────────────────────────────────────────────────────────────┐ │ +│ │ 应用层 (Application) │ │ +│ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────────────┐ │ │ +│ │ │ Game Code │ │ Renderer │ │ Scene │ │ Editor │ │ │ +│ │ └─────┬──────┘ └─────┬──────┘ └─────┬──────┘ └─────────┬──────────┘ │ │ +│ └────────┼────────────────┼────────────────┼───────────────────┼────────────┘ │ +│ │ │ │ │ │ +│ ┌────────▼────────────────▼────────────────▼───────────────────▼────────────┐ │ +│ │ ResourceManager (资源管理器) │ │ +│ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ +│ │ │ • Load(path) - 同步加载 │ │ │ +│ │ │ • LoadAsync(path, callback) - 异步加载 │ │ │ +│ │ │ • Unload(path/guid) - 卸载资源 │ │ │ +│ │ │ • RegisterLoader() - 注册加载器 │ │ │ +│ │ │ • AddRef/Release - 引用计数管理 │ │ │ +│ │ └─────────────────────────────────────────────────────────────────────┘ │ │ +│ └────────┬───────────────────────────────────────────────────────────────────┘ │ +│ │ │ +│ ┌────────▼───────────────────────────────────────────────────────────────────┐ │ +│ │ ResourceLoader (加载器层) │ │ +│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌─────────────┐ │ │ +│ │ │TextureLoader │ │ MeshLoader │ │ AudioLoader │ │ShaderLoader │ │ │ +│ │ │ (纹理加载) │ │ (模型加载) │ │ (音频加载) │ │ (着色器加载) │ │ │ +│ │ └──────────────┘ └──────────────┘ └──────────────┘ └─────────────┘ │ │ +│ └────────┬───────────────────────────────────────────────────────────────────┘ │ +│ │ │ +│ ┌────────▼───────────────────────────────────────────────────────────────────┐ │ +│ │ ResourceCache (缓存层) │ │ +│ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ +│ │ │ • LRU淘汰策略 │ │ │ +│ │ │ • 内存压力响应 │ │ │ +│ │ │ • 手动刷新接口 │ │ │ +│ │ └─────────────────────────────────────────────────────────────────────┘ │ │ +│ └────────┬───────────────────────────────────────────────────────────────────┘ │ +│ │ │ +│ ┌────────▼───────────────────────────────────────────────────────────────────┐ │ +│ │ AsyncLoader (异步加载层) │ │ +│ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ +│ │ │ • 后台工作线程 │ │ │ +│ │ │ • 任务队列管理 │ │ │ +│ │ │ • 完成回调分发 │ │ │ +│ │ └─────────────────────────────────────────────────────────────────────┘ │ │ +│ └────────┬───────────────────────────────────────────────────────────────────┘ │ +│ │ │ +│ ┌────────▼───────────────────────────────────────────────────────────────────┐ │ +│ │ FileSystem (文件系统层) │ │ +│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ +│ │ │ Stream │ │ Path.h │ │ Archive │ │ Compression │ │ │ +│ │ └──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘ │ │ +│ └────────────────────────────────────────────────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────────────────────┘ +``` + +### 2.2 模块职责 + +| 模块 | 职责 | 关键类 | +|------|------|--------| +| **ResourceManager** | 资源总入口,引用计数管理 | ResourceManager | +| **ResourceLoader** | 具体资源类型的加载逻辑 | IResourceLoader, TextureLoader, MeshLoader | +| **ResourceCache** | 内存缓存,LRU淘汰 | ResourceCache, CacheEntry | +| **AsyncLoader** | 异步任务调度 | AsyncLoader, LoadRequest | +| **FileSystem** | 文件读写,路径管理 | FileSystem, Path, FileReader | + +### 2.3 数据流 + +``` +同步加载流程: + Load(path) → CheckCache → Found? → Return Handle + ↓ + Not Found + ↓ + GetLoader(type) → LoadResource → Create Handle → Add to Cache → Return + +异步加载流程: + LoadAsync(path, callback) → Create Request → Submit to Queue + ↓ + Worker Thread: Get Request → GetLoader → LoadResource + ↓ + Main Thread: Update() → Process Completed → Invoke Callback → Create Handle +``` + +--- + +## 3. 目录结构 + +### 3.1 设计目录结构 + +``` +engine/include/XCEngine/Resources/ +├── Resources.h # 主头文件,导出所有资源系统类 +├── IResource.h # 资源基类接口 +├── ResourceHandle.h # 资源句柄(模板智能指针) +├── ResourceManager.h # 资源管理器 +├── IResourceLoader.h # 加载器基类接口 +├── ResourceCache.h # 资源缓存 +├── AsyncLoader.h # 异步加载器 +├── ImportSettings.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 # 二进制资源 +└── ResourceTypes.h # 资源类型枚举 + +engine/src/Resources/ +├── Resources.cpp # 资源系统初始化 +├── ResourceManager.cpp +├── ResourceCache.cpp +├── AsyncLoader.cpp +├── TextureLoader.cpp +├── MeshLoader.cpp +├── MaterialLoader.cpp +├── ShaderLoader.cpp +└── AudioLoader.cpp +``` + +### 3.2 与现有项目整合 + +资源系统需要整合到现有项目中,需要创建或更新的文件: + +``` +engine/ +├── include/XCEngine/ +│ └── XCEngine.h # 添加 #include "Resources/Resources.h" +│ +└── src/ + └── Resources/ # 新建目录 + └── (上述实现文件) +``` + +--- + +## 4. 核心类型定义 + +### 4.1 资源类型枚举 + +```cpp +// ResourceTypes.h +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"; + } +} + +// 资源使用64位GUID作为唯一标识符 +// GUID生成规则:MD5(path) 的前64位 +// 这样可以保证相同路径生成相同的GUID +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; } + + // 从路径生成GUID + static ResourceGUID Generate(const char* path); + static ResourceGUID Generate(const String& path); + + 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; + + // 从JSON加载 + virtual bool LoadFromJSON(const String& json) { return false; } + + // 保存为JSON + virtual String SaveToJSON() const { return String(); } +}; + +} // namespace Resources +} // namespace XCEngine +} + +} // namespace Resources +} // namespace XCEngine +``` + +### 4.2 资源GUID + +```cpp +// 资源使用64位GUID作为唯一标识符 +// GUID生成规则:MD5(path) 的前64位 +// 这样可以保证相同路径生成相同的GUID + +struct ResourceGUID { + uint64 value; + + ResourceGUID() : value(0) {} + explicit ResourceGUID(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; } + + // 从路径生成GUID + static ResourceGUID Generate(const char* path); + static ResourceGUID Generate(const String& path); + + String ToString() const; +}; + +// 全局函数 +inline ResourceGUID MakeResourceGUID(const char* path) { + return ResourceGUID::Generate(path); +} +``` + +### 4.3 资源路径 + +```cpp +// 资源路径使用相对于资源根目录的路径 +// 例如:textures/player.png, models/player.fbx +// 资源系统会自动添加资源根目录前缀 + +class ResourcePath { +public: + ResourcePath() = default; + ResourcePath(const char* path); + ResourcePath(const String& path); + + // 获取扩展名 + String GetExtension() const; + + // 获取文件名(不含扩展名) + String GetStem() const; + + // 获取完整路径 + String GetFullPath() const; + + // 获取相对于资源根的路径 + String GetRelativePath() const; + + // 转换为资源GUID + ResourceGUID ToGUID() const; + + // 检查扩展名 + bool HasExtension(const char* ext) const; + bool HasAnyExtension(const char* const* extensions, Core::uint32 count) const; + +private: + String m_path; +}; +``` + +--- + +## 5. 核心接口设计 + +### 5.1 资源基类接口 (IResource) + +```cpp +// IResource.h +namespace XCEngine { +namespace Resources { + +class IResource { +public: + virtual ~IResource() = default; + + // 获取资源类型 + virtual ResourceType GetType() const = 0; + + // 获取资源名称 + virtual const String& GetName() const = 0; + + // 获取资源路径 + virtual const String& GetPath() const = 0; + + // 获取资源GUID + virtual ResourceGUID GetGUID() const = 0; + + // 资源是否有效 + virtual bool IsValid() const = 0; + + // 获取资源内存大小(用于缓存统计) + virtual size_t GetMemorySize() const = 0; + + // 释放资源(返回到对象池或真正删除) + virtual void Release() = 0; + +protected: + // 资源初始化(供子类调用) + struct ConstructParams { + String name; + 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; } + + String m_name; + String m_path; + ResourceGUID m_guid; + bool m_isValid = false; + size_t m_memorySize = 0; +}; + +} // namespace Resources +} // namespace XCEngine +``` + +### 5.2 资源句柄 (ResourceHandle) + +```cpp +// ResourceHandle.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(); } + + // 获取GUID + 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 +``` + +### 5.3 加载器基类接口 (IResourceLoader) + +```cpp +// IResourceLoader.h +namespace XCEngine { +namespace Resources { + +// 加载结果 +struct LoadResult { + IResource* resource = nullptr; + bool success = false; + String errorMessage; + + LoadResult() = default; + + explicit LoadResult(IResource* res) + : resource(res), success(res != nullptr) {} + + explicit LoadResult(const String& error) + : success(false), errorMessage(error) {} + + explicit LoadResult(bool success, const 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 Array GetSupportedExtensions() const = 0; + + // 检查是否可以加载该文件 + virtual bool CanLoad(const String& path) const = 0; + + // 同步加载 + virtual LoadResult Load(const String& path, const ImportSettings* settings = nullptr) = 0; + + // 异步加载(默认实现:同步加载然后在主线程回调) + virtual void LoadAsync(const String& path, + const ImportSettings* settings, + std::function callback) { + LoadResult result = Load(path, settings); + if (callback) { + callback(result); + } + } + + // 获取默认导入设置 + virtual ImportSettings* GetDefaultSettings() const = 0; + +protected: + // 辅助方法:从文件读取数据 + static Array ReadFileData(const String& path); + + // 辅助方法:解析路径获取扩展名 + static String GetExtension(const 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 +``` + +### 5.4 资源管理器 (ResourceManager) + +```cpp +// ResourceManager.h +namespace XCEngine { +namespace Resources { + +class ResourceManager { +public: + static ResourceManager& Get(); + + // ==================== 初始化 ==================== + + void Initialize(); + void Shutdown(); + + // 设置资源根目录 + void SetResourceRoot(const String& rootPath); + const String& GetResourceRoot() const; + + // ==================== 同步加载 ==================== + + // 通过路径加载 + template + ResourceHandle Load(const String& path, ImportSettings* settings = nullptr) { + static_assert(std::is_base_of_v, "T must derive from IResource"); + + ResourcePath resourcePath(path); + ResourceGUID guid = resourcePath.ToGUID(); + + // 1. 检查缓存 + IResource* cached = FindInCache(guid); + if (cached) { + return ResourceHandle(static_cast(cached)); + } + + // 2. 查找加载器 + IResourceLoader* loader = FindLoader(GetResourceType()); + if (!loader) { + Debug::Logger::Get().Warning(Debug::LogCategory::FileSystem, + "No loader found for resource type: " + String(GetResourceTypeName(GetResourceType()))); + return ResourceHandle(); + } + + // 3. 加载资源 + LoadResult result = loader->Load(resourcePath.GetFullPath(), settings); + if (!result) { + Debug::Logger::Get().Error(Debug::LogCategory::FileSystem, + "Failed to load resource: " + path + " - " + result.errorMessage); + return ResourceHandle(); + } + + // 4. 添加到缓存 + AddToCache(guid, result.resource); + + return ResourceHandle(static_cast(result.resource)); + } + + // 通过GUID加载 + template + ResourceHandle Load(ResourceGUID guid) { + // 从GUID反向查找路径(需要维护guid到path的映射) + // 这里简化处理,实际实现需要从数据库查询 + return ResourceHandle(); + } + + // ==================== 异步加载 ==================== + + // 异步加载资源(需要显式指定类型) + void LoadAsync(const String& path, ResourceType type, + std::function callback); + + // 异步加载资源(带自定义设置) + void LoadAsync(const String& path, ResourceType type, ImportSettings* settings, + std::function callback); + + // ==================== 卸载 ==================== + + // 通过路径卸载 + void Unload(const String& path); + + // 通过GUID卸载 + void Unload(ResourceGUID guid); + + // 卸载所有未使用的资源 + void UnloadUnused(); + + // 卸载所有资源 + void UnloadAll(); + + // ==================== 引用计数 ==================== + + // 增加引用计数 + void AddRef(ResourceGUID guid); + + // 减少引用计数(引用计数为0时可能卸载资源) + void Release(ResourceGUID guid); + + // 获取引用计数 + Core::uint32 GetRefCount(ResourceGUID guid) const; + + // ==================== 加载器管理 ==================== + + // 注册加载器(ResourceManager拥有加载器) + 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 String& path); + IResource* Find(ResourceGUID guid); + + // 检查资源是否存在 + bool Exists(const String& path) const; + bool Exists(ResourceGUID guid) const; + + // ==================== 资源根目录相关 ==================== + + // 解析资源路径(添加资源根目录) + String ResolvePath(const 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); + + // 数据成员 + String m_resourceRoot; + + // 资源缓存 + HashMap m_resourceCache; + + // 引用计数 + HashMap m_refCounts; + + // GUID到路径的映射(用于从guid加载) + HashMap m_guidToPath; + + // 加载器 + HashMap> m_loaders; + + // 缓存统计 + size_t m_memoryUsage = 0; + size_t m_memoryBudget = 512 * 1024 * 1024; // 默认512MB + + // 异步加载器 + UniquePtr m_asyncLoader; + + // 互斥锁 + Threading::Mutex m_mutex; + + friend class ResourceHandleBase; +}; + +} // namespace Resources +} // namespace XCEngine +``` + +### 5.5 资源缓存 (ResourceCache) + +```cpp +// ResourceCache.h +#include + +namespace XCEngine { +namespace Resources { + +// 缓存条目 +struct CacheEntry { + IResource* resource; + ResourceGUID guid; + size_t memorySize; + Core::uint64 lastAccessTime; // 使用Profiler::Get().GetTickCount() + 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(); +}; + +// LRU缓存实现 +class ResourceCache { +public: + ResourceCache(); + ~ResourceCache(); + + // 添加资源到缓存 + void Add(ResourceGUID guid, IResource* resource); + + // 从缓存移除 + void Remove(ResourceGUID guid); + + // 查找资源(不移动到头部) + IResource* Find(ResourceGUID guid) const; + + // 访问资源(更新LRU信息) + 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); + + // 引用计数为0时的通知(供ResourceManager调用) + void OnZeroRefCount(ResourceGUID guid); + + // 刷新缓存(淘汰所有未使用的资源) + void Flush(); + + // 清空缓存 + void Clear(); + + // 获取最少使用的资源(用于调试) + Array GetLRUList(size_t count) const; + +private: + // 淘汰最少使用的资源 + void Evict(size_t requiredBytes); + + // 更新内存统计 + void UpdateMemoryStats(); + + // 数据成员 + HashMap m_cache; + Array m_lruOrder; // 按访问时间排序,最少使用的在前面 + size_t m_memoryUsage = 0; + size_t m_memoryBudget = 512 * 1024 * 1024; // 默认512MB + + Mutex m_mutex; +}; + +} // namespace Resources +} // namespace XCEngine +``` + +### 5.6 异步加载器 (AsyncLoader) + +```cpp +// AsyncLoader.h +#include +#include + +namespace XCEngine { +namespace Resources { + +// 加载请求 +struct LoadRequest { + String path; + ResourceType type; + std::function callback; + UniquePtr settings; + Core::uint64 requestId; + + LoadRequest() + : requestId(0) {} + + LoadRequest(const 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 String& path, ResourceType type, + std::function callback); + + // 提交加载请求(带自定义设置) + void Submit(const 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; } + + // 获取加载进度(0.0 - 1.0) + float GetProgress() const; + + // 取消所有待处理的请求 + void CancelAll(); + + // 取消特定请求 + void Cancel(Core::uint64 requestId); + +private: + AsyncLoader() = default; + ~AsyncLoader() = default; + + void SubmitInternal(LoadRequest& request); + + // 待处理的请求队列 + Threading::Mutex m_queueMutex; + Array m_pendingQueue; + + // 完成的请求队列(主线程处理) + Threading::Mutex m_completedMutex; + Array m_completedQueue; + + // 统计 + std::atomic m_pendingCount{0}; + std::atomic m_completedCount{0}; + Core::uint32 m_totalRequested = 0; + + // 加载器查找 + IResourceLoader* FindLoader(ResourceType type) const; +}; + +} // namespace Resources +} // namespace XCEngine +``` + +--- + +## 6. 具体资源类型 + +### 6.1 纹理资源 (Texture) + +```cpp +// Texture.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 +}; + +// 纹理使用flags +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; + + // IResource 接口 + ResourceType GetType() const override { return ResourceType::Texture; } + const String& GetName() const override { return m_name; } + const 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; } + + // RHI资源 + 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); + + // 生成Mipmap + bool GenerateMipmaps(); + +private: + // 成员变量 + String m_name; + String m_path; + ResourceGUID m_guid; + bool m_isValid = false; + size_t m_memorySize = 0; + + 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 +``` + +### 6.2 纹理导入设置 + +```cpp +// TextureImportSettings.h +namespace XCEngine { +namespace Resources { + +class TextureImportSettings : public ImportSettings { +public: + TextureImportSettings(); + virtual ~TextureImportSettings() override; + + // ==================== 纹理设置 ==================== + + // 纹理类型 + void SetTextureType(TextureType type) { m_textureType = type; } + TextureType GetTextureType() const { return m_textureType; } + + // 目标格式(用于压缩) + void SetTargetFormat(TextureFormat format) { m_targetFormat = format; } + TextureFormat GetTargetFormat() const { return m_targetFormat; } + + // 是否生成Mipmap + void SetGenerateMipmaps(bool generate) { m_generateMipmaps = generate; } + bool GetGenerateMipmaps() const { return m_generateMipmaps; } + + // Mipmap过滤方式 + void SetMipmapFilter(MipmapFilter filter) { m_mipmapFilter = filter; } + MipmapFilter GetMipmapFilter() const { return m_mipmapFilter; } + + // 各向异性过滤 + void SetMaxAnisotropy(Core::uint32 anisotropy) { m_maxAnisotropy = anisotropy; } + Core::uint32 GetMaxAnisotropy() const { return m_maxAnisotropy; } + + // 是否sRGB(影响着色器中的采样) + void SetSRGB(bool srgb) { m_sRGB = srgb; } + bool GetSRGB() const { return m_sRGB; } + + // 是否启用纹理数组 + void SetTextureArray(bool array) { m_textureArray = array; } + bool GetTextureArray() const { return m_textureArray; } + + // 垂直翻转 + void SetFlipVertical(bool flip) { m_flipVertical = flip; } + bool GetFlipVertical() const { return m_flipVertical; } + + // 水平翻转 + void SetFlipHorizontal(bool flip) { m_flipHorizontal = flip; } + bool GetFlipHorizontal() const { return m_flipHorizontal; } + + // 边框颜色(对于透明纹理) + void SetBorderColor(const Math::Color& color) { m_borderColor = color; } + const Math::Color& GetBorderColor() const { return m_borderColor; } + + // ==================== 压缩设置 ==================== + + // 压缩质量 + void SetCompressionQuality(CompressionQuality quality) { m_compressionQuality = quality; } + CompressionQuality GetCompressionQuality() const { return m_compressionQuality; } + + // 是否使用硬件压缩 + void SetUseHardwareCompression(bool use) { m_useHardwareCompression = use; } + bool GetUseHardwareCompression() const { return m_useHardwareCompression; } + + // ==================== 实用方法 ==================== + + // 克隆设置 + UniquePtr Clone() const override; + + // 从JSON加载 + bool LoadFromJSON(const String& json); + + // 保存为JSON + String SaveToJSON() const; + +private: + // 成员变量 + TextureType m_textureType = TextureType::Texture2D; + TextureFormat m_targetFormat = TextureFormat::Unknown; // 自动选择 + bool m_generateMipmaps = true; + MipmapFilter m_mipmapFilter = MipmapFilter::Box; + Core::uint32 m_maxAnisotropy = 16; + bool m_sRGB = false; + bool m_textureArray = false; + bool m_flipVertical = false; + bool m_flipHorizontal = false; + Math::Color m_borderColor = Math::Color::Black; + CompressionQuality m_compressionQuality = CompressionQuality::High; + bool m_useHardwareCompression = true; +}; + +// Mipmap过滤方式 +enum class MipmapFilter { + Box, + Kaiser +}; + +// 压缩质量 +enum class CompressionQuality { + Low, + Medium, + High, + Ultra +}; + +} // namespace Resources +} // namespace XCEngine +``` + +### 6.3 纹理加载器 + +```cpp +// TextureLoader.h +namespace XCEngine { +namespace Resources { + +class TextureLoader : public IResourceLoader { +public: + TextureLoader(); + virtual ~TextureLoader() override; + + // IResourceLoader 接口 + ResourceType GetResourceType() const override { + return ResourceType::Texture; + } + + Array GetSupportedExtensions() const override { + return Array{".png", ".jpg", ".jpeg", ".tga", ".bmp", + ".dds", ".hdr", ".exr", ".psd"}; + } + + bool CanLoad(const String& path) const override { + String ext = GetExtension(path); + return ext == ".png" || ext == ".jpg" || ext == ".jpeg" || + ext == ".tga" || ext == ".bmp" || ext == ".dds" || + ext == ".hdr" || ext == ".exr" || ext == ".psd"; + } + + LoadResult Load(const String& path, const ImportSettings* settings = nullptr) override; + + ImportSettings* GetDefaultSettings() const override { + return new TextureImportSettings(); + } + +private: + // 内部加载方法 + LoadResult LoadPNG(const String& path, const TextureImportSettings* settings); + LoadResult LoadJPG(const String& path, const TextureImportSettings* settings); + LoadResult LoadTGA(const String& path, const TextureImportSettings* settings); + LoadResult LoadDDS(const String& path, const TextureImportSettings* settings); + LoadResult LoadHDR(const String& path, const TextureImportSettings* settings); + + // 辅助方法 + TextureFormat DetectFormat(const String& path) const; + bool ConvertFormat(const Core::uint8* srcData, Core::uint32 width, Core::uint32 height, + TextureFormat srcFormat, TextureFormat dstFormat, + Core::uint8*& outData, size_t& outDataSize); +}; + +// 注册加载器 +REGISTER_RESOURCE_LOADER(TextureLoader); + +} // namespace Resources +} // namespace XCEngine +``` + +### 6.4 网格资源 (Mesh) + +```cpp +// Mesh.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; + + // IResource 接口 + ResourceType GetType() const override { return ResourceType::Mesh; } + const String& GetName() const override { return m_name; } + const 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 Array& GetSections() const { return m_sections; } + + // ==================== 包围盒 ==================== + + void SetBoundingBox(const Math::AABB& box); + const Math::AABB& GetBoundingBox() const { return m_boundingBox; } + + // ==================== 骨骼动画(可选)==================== + + void SetSkeleton(class Skeleton* skeleton); + class Skeleton* GetSkeleton() const { return m_skeleton; } + + // ==================== RHI资源 ==================== + + class IRHIBuffer* GetVertexBuffer() const { return m_vertexBuffer; } + class IRHIBuffer* GetIndexBuffer() const { return m_indexBuffer; } + void SetRHIBuffers(class IRHIBuffer* vb, class IRHIBuffer* ib); + +private: + // 成员变量 + String m_name; + String m_path; + ResourceGUID m_guid; + bool m_isValid = false; + size_t m_memorySize = 0; + + // 顶点数据 + Array m_vertexData; + Core::uint32 m_vertexCount = 0; + Core::uint32 m_vertexStride = 0; + VertexAttribute m_attributes = VertexAttribute::Position; + + // 索引数据 + Array m_indexData; + Core::uint32 m_indexCount = 0; + bool m_use32BitIndex = false; + + // 子网格 + Array m_sections; + + // 包围盒 + Math::AABB m_boundingBox; + + // 骨骼 + class Skeleton* m_skeleton = nullptr; + + // RHI资源 + class IRHIBuffer* m_vertexBuffer = nullptr; + class IRHIBuffer* m_indexBuffer = nullptr; +}; + +} // namespace Resources +} // namespace XCEngine +``` + +### 6.5 材质资源 (Material) + +```cpp +// Material.h +namespace XCEngine { +namespace Resources { + +// 材质属性类型 +enum class MaterialPropertyType { + Float, + Float2, + Float3, + Float4, + Int, + Int2, + Int3, + Int4, + Bool, + Texture, + Cubemap +}; + +// 材质属性 +struct MaterialProperty { + 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; + + // IResource 接口 + ResourceType GetType() const override { return ResourceType::Material; } + const String& GetName() const override { return m_name; } + const 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 String& name, float value); + void SetFloat2(const String& name, const Math::Vector2& value); + void SetFloat3(const String& name, const Math::Vector3& value); + void SetFloat4(const String& name, const Math::Vector4& value); + void SetInt(const String& name, int32 value); + void SetInt2(const String& name, const Math::IntVector2& value); + void SetInt3(const String& name, const Math::IntVector3& value); + void SetInt4(const String& name, const Math::IntVector4& value); + void SetBool(const String& name, bool value); + void SetTexture(const String& name, const ResourceHandle& texture); + + // ==================== 属性获取 ==================== + + float GetFloat(const String& name) const; + Math::Vector2 GetFloat2(const String& name) const; + // ... 其他Get方法 + + ResourceHandle GetTexture(const String& name) const; + + // ==================== 属性遍历 ==================== + + using PropertyIterator = HashMap::Iterator; + PropertyIterator BeginProperties() { return m_properties.Begin(); } + PropertyIterator EndProperties() { return m_properties.End(); } + + // ==================== 批处理数据 ==================== + + // 获取用于GPU的常数缓冲区数据 + const Array& GetConstantBufferData() const { return m_constantBufferData; } + + // 更新常数缓冲区(当属性变化时调用) + void UpdateConstantBuffer(); + +private: + // 成员变量 + String m_name; + String m_path; + ResourceGUID m_guid; + bool m_isValid = false; + size_t m_memorySize = 0; + + // 着色器 + ResourceHandle m_shader; + + // 属性表 + HashMap m_properties; + + // 常数缓冲区数据 + Array m_constantBufferData; + + // 纹理绑定信息(用于设置到Pipeline) + struct TextureBinding { + String name; + Core::uint32 slot; + ResourceHandle texture; + }; + Array m_textureBindings; +}; + +} // namespace Resources +} // namespace XCEngine +``` + +### 6.6 音频资源 (AudioClip) + +```cpp +// AudioClip.h +namespace XCEngine { +namespace Resources { + +// 音频格式 +enum class AudioFormat { + Unknown, + WAV, + OGG, + MP3, + FLAC +}; + +// 音频类型 +enum class AudioType { + SFX, // 音效 + Music, // 背景音乐 + Voice // 语音 +}; + +// 音频资源 +class AudioClip : public IResource { +public: + AudioClip(); + virtual ~AudioClip() override; + + // IResource 接口 + ResourceType GetType() const override { return ResourceType::AudioClip; } + const String& GetName() const override { return m_name; } + const 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 GetSampleRate() const { return m_sampleRate; } + + // 通道数 + Core::uint32 GetChannels() const { return m_channels; } + + // 位深度 + Core::uint32 GetBitsPerSample() const { return m_bitsPerSample; } + + // 持续时间(秒) + float GetDuration() const { return m_duration; } + + // 数据大小 + size_t GetDataSize() const { return m_data.Size(); } + + // 格式 + AudioFormat GetFormat() const { return m_format; } + + // 类型 + AudioType GetAudioType() const { return m_audioType; } + + // ==================== 音频数据 ==================== + + // 获取PCM数据 + const Core::uint8* GetData() const { return m_data.Data(); } + + // 是否流式(不加载到内存) + bool IsStreaming() const { return m_isStreaming; } + + // 设置流式 + void SetStreaming(bool streaming) { m_isStreaming = streaming; } + + // ==================== 播放控制 ==================== + + // 创建音频源(用于播放) + class IAudioSource* CreateSource() const; + +private: + // 成员变量 + String m_name; + String m_path; + ResourceGUID m_guid; + bool m_isValid = false; + size_t m_memorySize = 0; + + // 音频属性 + Core::uint32 m_sampleRate = 0; + Core::uint32 m_channels = 0; + Core::uint32 m_bitsPerSample = 0; + float m_duration = 0.0f; + AudioFormat m_format = AudioFormat::Unknown; + AudioType m_audioType = AudioType::SFX; + bool m_isStreaming = false; + + // 音频数据 + Array m_data; +}; + +} // namespace Resources +} // namespace XCEngine +``` + +--- + +## 7. 文件系统集成 + +### 7.1 文件系统接口 + +```cpp +// FileSystem.h (扩展现有IO模块) +namespace XCEngine { +namespace IO { + +// 文件系统接口 +class IFileSystem { +public: + virtual ~IFileSystem() = default; + + // 文件操作 + virtual bool FileExists(const String& path) const = 0; + virtual bool DirectoryExists(const String& path) const = 0; + + virtual size_t GetFileSize(const String& path) const = 0; + virtual bool GetFileTime(const String& path, Core::uint64& outTime) const = 0; + + // 读取 + virtual Array ReadAllBytes(const String& path) const = 0; + virtual String ReadAllText(const String& path) const = 0; + virtual bool Read(const String& path, void* buffer, size_t size, size_t offset = 0) const = 0; + + // 写入 + virtual bool WriteAllBytes(const String& path, const void* data, size_t size) = 0; + virtual bool WriteAllText(const String& path, const String& text) = 0; + virtual bool Write(const String& path, const void* data, size_t size, size_t offset = 0) = 0; + + // 目录操作 + virtual bool CreateDirectory(const String& path) = 0; + virtual bool DeleteDirectory(const String& path, bool recursive = false) = 0; + virtual bool DeleteFile(const String& path) = 0; + + // 遍历 + virtual void EnumerateFiles(const String& path, const String& pattern, + Array& outFiles) const = 0; + virtual void EnumerateDirectories(const String& path, const String& pattern, + Array& outDirectories) const = 0; + + // 获取路径信息 + virtual String GetExtension(const String& path) const = 0; + virtual String GetFileName(const String& path) const = 0; + virtual String GetFileNameWithoutExtension(const String& path) const = 0; + virtual String GetDirectoryName(const String& path) const = 0; + virtual String GetFullPath(const String& path) const = 0; + virtual String Combine(const String& path1, const String& path2) const = 0; +}; + +// 获取文件系统单例 +IFileSystem* GetFileSystem(); +void SetFileSystem(IFileSystem* fs); + +// Windows文件系统实现(默认) +class WindowsFileSystem : public IFileSystem { +public: + // 实现Windows API调用 +}; + +} // namespace IO +} // namespace XCEngine +``` + +### 7.2 资源文件系统 (ResourceFileSystem) + +```cpp +// ResourceFileSystem.h +namespace XCEngine { +namespace Resources { + +// 资源文件系统 - 管理资源包/归档 +class ResourceFileSystem { +public: + ResourceFileSystem(); + ~ResourceFileSystem(); + + // 初始化 + void Initialize(const String& rootPath); + void Shutdown(); + + // 添加资源包 + bool AddArchive(const String& archivePath); + bool AddDirectory(const String& directoryPath); + + // 移除资源包 + void RemoveArchive(const String& archivePath); + + // 查找资源 + bool FindResource(const String& relativePath, String& outAbsolutePath) const; + + // 读取资源数据 + Array ReadResource(const String& relativePath) const; + + // 检查资源是否存在 + bool Exists(const String& relativePath) const; + + // 获取资源信息 + struct ResourceInfo { + String path; + size_t size; + Core::uint64 modifiedTime; + bool inArchive; + String archivePath; + }; + + bool GetResourceInfo(const String& relativePath, ResourceInfo& outInfo) const; + + // 枚举资源 + void EnumerateResources(const String& pattern, Array& outResources) const; + +private: + // 资源包接口 + class IArchive { + public: + virtual ~IArchive() = default; + virtual bool Open(const String& path) = 0; + virtual void Close() = 0; + virtual bool Read(const String& fileName, void* buffer, size_t size, size_t offset) const = 0; + virtual size_t GetSize(const String& fileName) const = 0; + virtual bool Exists(const String& fileName) const = 0; + virtual void Enumerate(const String& pattern, Array& outFiles) const = 0; + }; + + // 数据成员 + String m_rootPath; + Array> m_archives; + Array m_directories; + + // 缓存 + mutable HashMap m_infoCache; +}; + +} // namespace Resources +} // namespace XCEngine +``` + +--- + +## 8. 资源打包系统 + +### 8.1 资源包格式 + +``` +┌─────────────────────────────────────────────────────┐ +│ ResourcePackage │ +├─────────────────────────────────────────────────────┤ +│ Header (固定大小) │ +│ ├── Magic: "XCRP" (4 bytes) │ +│ ├── Version: uint16 │ +│ ├── Manifest Size: uint32 │ +│ ├── Asset Count: uint32 │ +│ └── Data Offset: uint64 │ +├─────────────────────────────────────────────────────┤ +│ Manifest (JSON/二进制) │ +│ ├── File 1: { path, offset, size, checksum } │ +│ ├── File 2: { path, offset, size, checksum } │ +│ └── ... │ +├─────────────────────────────────────────────────────┤ +│ Data Section │ +│ ├── File 1 Data (对齐到16字节) │ +│ ├── File 2 Data │ +│ └── ... │ +└─────────────────────────────────────────────────────┘ +``` + +### 8.2 资源包构建器 + +```cpp +// ResourcePackageBuilder.h +namespace XCEngine { +namespace Resources { + +class ResourcePackageBuilder { +public: + ResourcePackageBuilder(); + ~ResourcePackageBuilder(); + + // 添加文件 + bool AddFile(const String& sourcePath, const String& relativePath); + + // 添加目录 + bool AddDirectory(const String& sourceDir, const String& relativeBase = ""); + + // 设置输出路径 + void SetOutputPath(const String& path) { m_outputPath = path; } + + // 构建包 + bool Build(); + + // 获取进度 + float GetProgress() const { return m_progress; } + + // 获取错误信息 + const String& GetError() const { return m_error; } + +private: + // 文件条目 + struct FileEntry { + String sourcePath; + String relativePath; + size_t size; + uint64 checksum; + }; + + // 成员变量 + String m_outputPath; + Array m_files; + float m_progress = 0.0f; + String m_error; + + // 辅助方法 + Core::uint64 CalculateChecksum(const void* data, size_t size); + bool WriteHeader(FileWriter& writer, size_t dataOffset); + bool WriteManifest(FileWriter& writer); + bool WriteData(FileWriter& writer); +}; + +} // namespace Resources +} // namespace XCEngine +``` + +--- + +## 9. 资源依赖管理 + +### 9.1 依赖图 + +```cpp +// ResourceDependencyGraph.h +namespace XCEngine { +namespace Resources { + +// 资源依赖节点 +struct DependencyNode { + ResourceGUID guid; + ResourceType type; + Array dependencies; // 当前资源依赖的资源 + Array dependents; // 依赖当前资源的资源 + Core::uint32 refCount = 0; +}; + +// 依赖图 +class ResourceDependencyGraph { +public: + ResourceDependencyGraph(); + ~ResourceDependencyGraph(); + + // 添加节点 + void AddNode(ResourceGUID guid, ResourceType type); + + // 添加依赖关系 + void AddDependency(ResourceGUID owner, ResourceGUID dependency); + + // 移除节点 + void RemoveNode(ResourceGUID guid); + + // 移除依赖关系 + void RemoveDependency(ResourceGUID owner, ResourceGUID dependency); + + // 获取依赖(当前资源依赖的资源) + Array GetDependencies(ResourceGUID guid) const; + + // 获取依赖者(依赖当前资源的资源) + Array GetDependents(ResourceGUID guid) const; + + // 获取传递依赖(所有层级的依赖) + Array GetAllDependencies(ResourceGUID guid) const; + + // 引用计数管理 + void IncrementRefCount(ResourceGUID guid); + void DecrementRefCount(ResourceGUID guid); + Core::uint32 GetRefCount(ResourceGUID guid) const; + + // 查找循环依赖 + bool HasCircularDependency(ResourceGUID guid, Array& outCycle) const; + + // 拓扑排序(用于加载顺序) + Array TopologicalSort() const; + + // 加载资源组及其所有依赖 + Array LoadWithDependencies(const String& entryPath); + + // 卸载资源组(仅当没有依赖者时) + bool Unload(ResourceGUID guid); + +private: + HashMap m_nodes; +}; + +} // namespace Resources +} // namespace XCEngine +``` + +--- + +## 10. 实现顺序 + +### 10.1 阶段划分 + +``` +阶段 4.1: 基础框架 (3天) + ├── 4.1.1 ResourceTypes.h - 资源类型枚举 + ├── 4.1.2 IResource.h - 资源基类接口 + ├── 4.1.3 ResourceHandle.h - 资源句柄 + ├── 4.1.4 IResourceLoader.h - 加载器接口 + └── 4.1.5 ResourceManager.h/cpp - 资源管理器基础 + +阶段 4.2: 缓存系统 (2天) + ├── 4.2.1 ResourceCache.h/cpp - LRU缓存实现 + └── 4.2.2 与ResourceManager集成 + +阶段 4.3: 异步加载 (2天) + ├── 4.3.1 AsyncLoader.h/cpp - 异步加载器 + ├── 4.3.2 与TaskSystem集成 + └── 4.3.3 完成回调机制 + +阶段 4.4: 具体资源类型 (4天) + ├── 4.4.1 Texture + TextureLoader - 纹理资源 + ├── 4.4.2 Mesh + MeshLoader - 网格资源 + ├── 4.4.3 Material + MaterialLoader - 材质资源 + └── 4.4.4 AudioClip + AudioLoader - 音频资源 + +阶段 4.5: 文件系统集成 (2天) + ├── 4.5.1 ResourceFileSystem - 资源文件系统 + └── 4.5.2 资源包支持 + +阶段 4.6: 依赖管理 (2天) + ├── 4.6.1 ResourceDependencyGraph - 依赖图 + └── 4.6.2 资源组加载/卸载 + +阶段 4.7: 测试与集成 (2天) + ├── 4.7.1 单元测试 + └── 4.7.2 与现有mvs集成 +``` + +### 10.2 详细任务列表 + +``` +任务 4.1.1: ResourceTypes.h + 实现: + - ResourceType 枚举(Texture, Mesh, Material, Shader, AudioClip等) + - GetResourceTypeName() 函数 + - ResourceGUID 结构体 + +任务 4.1.2: IResource.h + 实现: + - IResource 抽象基类 + - 纯虚方法:GetType(), GetName(), GetPath(), GetGUID(), IsValid(), GetMemorySize(), Release() + - 虚析构函数 + +任务 4.1.3: ResourceHandle.h + 实现: + - ResourceHandle 模板类 + - 构造/析构(自动引用计数) + - operator->(), Get(), IsValid() + - 移动语义支持 + +任务 4.1.4: IResourceLoader.h + 实现: + - IResourceLoader 抽象基类 + - LoadResult 结构体 + - GetResourceType(), GetSupportedExtensions(), CanLoad(), Load() + - REGISTER_RESOURCE_LOADER 宏 + +任务 4.1.5: ResourceManager.h/cpp + 实现: + - ResourceManager 单例 + - Initialize()/Shutdown() + - Load(path) 模板方法 + - Unload(path/guid) + - AddRef()/Release() + - RegisterLoader() + - SetMemoryBudget() + +任务 4.2.1: ResourceCache.h/cpp + 实现: + - CacheEntry 结构体 + - ResourceCache 类 + - Add(), Remove(), Find(), Touch() + - SetMemoryBudget(), OnMemoryPressure() + - LRU淘汰逻辑 + +任务 4.3.1: AsyncLoader.h/cpp + 实现: + - LoadRequest 结构体 + - AsyncLoader 单例 + - Submit(path, callback) + - Update() - 处理完成队列 + - IsLoading(), GetProgress() + +任务 4.4.1: Texture + TextureLoader + 实现: + - Texture 类(继承IResource) + - TextureImportSettings 类 + - TextureLoader 类(继承IResourceLoader) + - 使用stb_image加载PNG/JPG/TGA + - REGISTER_RESOURCE_LOADER(TextureLoader) + +任务 4.4.2: Mesh + MeshLoader + 实现: + - Mesh 类(继承IResource) + - MeshSection 结构体 + - MeshImportSettings 类 + - MeshLoader 类(使用Assimp) + - 支持OBJ/glTF格式 + - REGISTER_RESOURCE_LOADER(MeshLoader) + +任务 4.4.3: Material + MaterialLoader + 实现: + - Material 类 + - MaterialProperty 结构体 + - MaterialLoader 类(解析JSON格式) + - REGISTER_RESOURCE_LOADER(MaterialLoader) + +任务 4.4.4: AudioClip + AudioLoader + 实现: + - AudioClip 类 + - AudioLoader 类 + - 支持WAV格式 + - REGISTER_RESOURCE_LOADER(AudioLoader) + +任务 4.5.1: ResourceFileSystem + 实现: + - ResourceFileSystem 类 + - IArchive 接口 + - AddArchive(), AddDirectory() + - ReadResource(), Exists() + +任务 4.6.1: ResourceDependencyGraph + 实现: + - DependencyNode 结构体 + - ResourceDependencyGraph 类 + - AddDependency(), RemoveDependency() + - GetDependencies(), GetDependents() + - TopologicalSort() +``` + +--- + +## 11. 关键技术点 + +### 11.1 引用计数与缓存淘汰的交互 + +```cpp +// 引用计数管理 +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--; + + // 引用计数为0时,不立即卸载 + // 由缓存系统根据LRU策略决定何时卸载 + if (it->second == 0) { + m_refCounts.Erase(guid); + // 通知缓存系统资源可以淘汰 + m_cache.OnZeroRefCount(guid); + } + } +} +``` + +### 11.2 异步加载线程安全 + +```cpp +// AsyncLoader::Update() 在主线程调用 +void AsyncLoader::Update() { + // 1. 从完成队列取出结果(线程安全) + Array completed; + { + std::lock_guard lock(m_completedMutex); + completed = std::move(m_completedQueue); + m_completedQueue.Clear(); + } + + // 2. 在主线程处理完成回调 + for (auto& request : completed) { + if (request.callback) { + // 回调中可能创建ResourceHandle,增加引用计数 + request.callback(m_result); + } + } +} + +// 工作线程函数 +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)); +} +``` + +### 11.3 内存压力响应 + +```cpp +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; + + // 按LRU顺序淘汰 + for (auto it = m_lruOrder.Begin(); it != m_lruOrder.End() && targetRelease > 0; ) { + 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 releasedSize = entry.memorySize; + + // 从缓存移除 + m_cache.Erase(guid); + m_memoryUsage -= releasedSize; + targetRelease -= releasedSize; + + // 销毁资源 + entry.resource->Release(); + + // 从LRU列表移除 + it = m_lruOrder.Erase(it); + } else { + ++it; // 有外部引用,跳过 + } + } else { + ++it; + } + } +} +``` + +--- + +## 12. 使用示例 + +### 12.1 基本使用 + +```cpp +// 初始化资源系统 +void InitResourceSystem() { + // 设置资源根目录 + ResourceManager::Get().SetResourceRoot("resources/"); + + // 初始化异步加载器(2个工作线程) + AsyncLoader::Get().Initialize(2); + + // 设置内存预算(1GB) + ResourceManager::Get().SetMemoryBudget(1024 * 1024 * 1024); +} + +// 同步加载纹理 +void LoadTextureExample() { + // 加载纹理 + ResourceHandle tex = ResourceManager::Get().Load("textures/player.png"); + + if (tex.IsValid()) { + // 使用纹理 + Texture* texture = tex.Get(); + printf("Loaded texture: %s, %dx%d\n", + tex->GetName().CStr(), + texture->GetWidth(), + texture->GetHeight()); + + // 传递给渲染器 + renderer->SetTexture(0, texture->GetRHIResource()); + } + + // 离开作用域时自动释放(引用计数-1) +} + +// 异步加载网格 +void LoadMeshAsyncExample() { + ResourceManager::Get().LoadAsync("models/player.fbx", ResourceType::Mesh, + [](LoadResult result) { + if (result && result.resource) { + // 在主线程回调中处理 + // 注意:需要手动转换为正确的类型 + Mesh* mesh = static_cast(result.resource); + printf("Mesh loaded: %s\n", mesh->GetName().CStr()); + + // 添加到场景 + // 注意:这里需要创建ResourceHandle来管理生命周期 + ResourceHandle meshHandle(mesh); + scene->AddMesh(meshHandle); + } else { + printf("Failed to load mesh: %s\n", result.errorMessage.CStr()); + } + }); + + // 异步加载进行中... + // 主线程继续执行其他逻辑 +} +``` + +### 12.2 资源组加载 + +```cpp +// 加载场景所需的所有资源 +void LoadSceneResources(const String& scenePath) { + // 1. 加载场景配置文件 + String sceneConfigPath = "scenes/" + scenePath + ".scene"; + ResourceHandle sceneConfig = + ResourceManager::Get().Load(sceneConfigPath); + + // 2. 解析配置文件获取依赖列表 + Array dependencies = ParseSceneDependencies(sceneConfig.Get()); + + // 3. 异步加载所有依赖 + Core::uint32 totalResources = dependencies.Size(); + Core::uint32 loadedCount = 0; + + for (const auto& dep : dependencies) { + // 根据扩展名判断资源类型 + String ext = Path::GetExtension(dep); + ResourceType type = ResourceType::Binary; // 默认 + + if (ext == ".png" || ext == ".jpg") { + type = ResourceType::Texture; + } else if (ext == ".fbx" || ext == ".obj") { + type = ResourceType::Mesh; + } + // ... 其他类型 + + ResourceManager::Get().LoadAsync(dep, type, + [&loadedCount, totalResources](LoadResult result) { + loadedCount++; + printf("Loading progress: %d/%d\n", loadedCount, totalResources); + }); + } +} +``` + +### 12.3 自定义导入设置 + +```cpp +void LoadTextureWithSettings() { + // 创建导入设置 + TextureImportSettings* settings = new TextureImportSettings(); + settings->SetGenerateMipmaps(true); + settings->SetSRGB(true); + settings->SetTargetFormat(TextureFormat::BC7_UNORM); + settings->SetMaxAnisotropy(16); + + // 加载时传入设置 + ResourceHandle tex = ResourceManager::Get().Load( + "textures/diffuse.png", settings); + + // settings由ResourceManager管理,不需要手动delete +} +``` + +--- + +## 13. 验收标准 + +### 13.1 功能验收 + +- [ ] 能够通过路径加载Texture资源(PNG, JPG, TGA) +- [ ] 能够通过路径加载Mesh资源(OBJ, glTF) +- [ ] 能够通过路径加载Material资源(JSON格式) +- [ ] 能够通过路径加载AudioClip资源(WAV格式) +- [ ] 异步加载功能正常工作,回调在主线程执行 +- [ ] 资源缓存机制正常工作,LRU淘汰策略生效 +- [ ] 引用计数正确管理,零引用时资源可被淘汰 +- [ ] 内存预算控制正常工作,超出预算时自动淘汰资源 + +### 13.2 性能验收 + +- [ ] 缓存命中时资源加载时间为0 +- [ ] 异步加载不阻塞主线程 +- [ ] 多线程加载时无数据竞争 +- [ ] 内存使用稳定,无内存泄漏 + +### 13.3 代码质量 + +- [ ] 编译通过,无警告 +- [ ] 遵循项目编码规范 +- [ ] 必要的注释和文档 +- [ ] 错误处理完善 + +--- + +## 14. 后续扩展 + +### 14.1 可选的扩展功能 + +| 功能 | 说明 | 工作量 | +|------|------|--------| +| **资源热加载** | 编辑器中修改资源后实时更新 | 2天 | +| **资源版本控制** | 检测资源变化,自动重新加载 | 2天 | +| **资源加密** | 支持加密的资源包 | 1天 | +| **资源流式加载** | 大资源分块加载 | 3天 | +| **资源分析器** | 可视化资源使用情况 | 2天 | + +### 14.2 资源格式扩展 + +| 格式 | 说明 | 优先级 | +|------|------|--------| +| glTF 2.0 | 现代3D模型格式,高优先级 | P0 | +| DDS | 压缩纹理格式 | P0 | +| OGG/Vorbis | 压缩音频格式 | P1 | +| PSD | Photoshop源文件 | P2 | +| EXR | HDR图像 | P2 | + +--- + +## 15. 依赖关系 + +``` +资源系统依赖关系图: + +第一阶段基础层 + │ + ├── Math Library ─────┐ + │ │ + ├── Containers ──────┼──► 资源系统 + │ │ + ├── Memory ────────┤ + │ │ + └── Threading ─────────┘ + │ + ▼ + ┌─────────────────┐ + │ AsyncLoader │ (依赖TaskSystem) + └────────┬────────┘ + │ + ┌────────▼────────┐ + │ ResourceManager │ + └────────┬────────┘ + │ + ┌────────▼────────┐ ┌─────────────┐ + │ ResourceCache │────►│ 引用计数 │ + └────────┬────────┘ │ 管理 │ + │ └─────────────┘ + ┌────────▼────────┐ + │ ResourceLoader │ + └────────┬────────┘ + │ + ┌────────▼────────┐ + │ 具体资源类型 │ + │ (Texture等) │ + └─────────────────┘ +``` + +--- + +*文档版本: 1.0* +*更新日期: 2026-03-17* diff --git a/engine/include/XCEngine/RHI/D3D12/D3D12Buffer.h b/engine/include/XCEngine/RHI/D3D12/D3D12Buffer.h index 444109f6..44236de0 100644 --- a/engine/include/XCEngine/RHI/D3D12/D3D12Buffer.h +++ b/engine/include/XCEngine/RHI/D3D12/D3D12Buffer.h @@ -4,6 +4,7 @@ #include #include +#include "../RHIBuffer.h" #include "D3D12Enum.h" using Microsoft::WRL::ComPtr; @@ -11,16 +12,16 @@ using Microsoft::WRL::ComPtr; namespace XCEngine { namespace RHI { -class D3D12Buffer { +class D3D12Buffer : public RHIBuffer { public: D3D12Buffer(); - ~D3D12Buffer(); + ~D3D12Buffer() override; bool Initialize(ID3D12Device* device, uint64_t size, D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COMMON, D3D12_HEAP_TYPE heapType = D3D12_HEAP_TYPE_DEFAULT); bool InitializeFromExisting(ID3D12Resource* resource); bool InitializeWithData(ID3D12Device* device, ID3D12GraphicsCommandList* commandList, const void* data, uint64_t size, D3D12_RESOURCE_STATES finalState); - void Shutdown(); + void Shutdown() override; ID3D12Resource* GetResource() const { return m_resource.Get(); } D3D12_RESOURCE_DESC GetDesc() const { return m_resource->GetDesc(); } @@ -29,21 +30,25 @@ public: void UpdateData(const void* data, uint64_t size); - void* GetNativeHandle() const { return m_resource.Get(); } + void* GetNativeHandle() override { return m_resource.Get(); } ResourceStates GetState() const { return m_state; } void SetState(ResourceStates state) { m_state = state; } uint64_t GetGPUAddress() const { return m_resource->GetGPUVirtualAddress(); } - size_t GetSize() const { return GetDesc().Width; } + uint64_t GetSize() const override { return GetDesc().Width; } - const std::string& GetName() const { return m_name; } - void SetName(const std::string& name) { m_name = name; } + const std::string& GetName() const override { return m_name; } + void SetName(const std::string& name) override { m_name = name; } - uint32_t GetStride() const { return m_stride; } - BufferType GetBufferType() const { return m_bufferType; } + uint32_t GetStride() const override { return m_stride; } + BufferType GetBufferType() const override { return m_bufferType; } - void SetStride(uint32_t stride) { m_stride = stride; } - void SetBufferType(BufferType type) { m_bufferType = type; } + void SetStride(uint32_t stride) override { m_stride = stride; } + void SetBufferType(BufferType type) override { m_bufferType = type; } + + void* Map() override; + void Unmap() override; + void SetData(const void* data, size_t size, size_t offset = 0) override; private: ComPtr m_resource; diff --git a/engine/include/XCEngine/RHI/D3D12/D3D12Shader.h b/engine/include/XCEngine/RHI/D3D12/D3D12Shader.h index 26a5be4f..4f5fdfdd 100644 --- a/engine/include/XCEngine/RHI/D3D12/D3D12Shader.h +++ b/engine/include/XCEngine/RHI/D3D12/D3D12Shader.h @@ -5,6 +5,7 @@ #include #include +#include "../RHIShader.h" #include "D3D12Enum.h" #include "../RHITypes.h" @@ -13,21 +14,33 @@ using Microsoft::WRL::ComPtr; namespace XCEngine { namespace RHI { -class D3D12Shader { +class D3D12Shader : public RHIShader { public: D3D12Shader(); - ~D3D12Shader(); + ~D3D12Shader() override; - bool CompileFromFile(const wchar_t* filePath, const char* entryPoint, const char* target); - bool Compile(const void* sourceData, size_t sourceSize, const char* entryPoint, const char* target); - void Shutdown(); + bool CompileFromFile(const wchar_t* filePath, const char* entryPoint, const char* target) override; + bool Compile(const void* sourceData, size_t sourceSize, const char* entryPoint, const char* target) override; + void Shutdown() override; const D3D12_SHADER_BYTECODE GetD3D12Bytecode() const; const void* GetBytecode() const; size_t GetBytecodeSize() const; - ShaderType GetType() const; + ShaderType GetType() const override; const InputLayoutDesc& GetInputLayout() const; + void* GetNativeHandle() override { return m_bytecode.Get(); } + bool IsValid() const override { return m_bytecode != nullptr; } + + void Bind() override { } + void Unbind() override { } + + void SetInt(const char* name, int value) override { } + void SetFloat(const char* name, float value) override { } + void SetVec3(const char* name, float x, float y, float z) override { } + void SetVec4(const char* name, float x, float y, float z, float w) override { } + void SetMat4(const char* name, const float* value) override { } + private: ComPtr m_bytecode; ComPtr m_error; diff --git a/engine/include/XCEngine/RHI/D3D12/D3D12Texture.h b/engine/include/XCEngine/RHI/D3D12/D3D12Texture.h index 9caf6f13..6f6e6949 100644 --- a/engine/include/XCEngine/RHI/D3D12/D3D12Texture.h +++ b/engine/include/XCEngine/RHI/D3D12/D3D12Texture.h @@ -4,6 +4,7 @@ #include #include +#include "../RHITexture.h" #include "D3D12Enum.h" using Microsoft::WRL::ComPtr; @@ -11,39 +12,39 @@ using Microsoft::WRL::ComPtr; namespace XCEngine { namespace RHI { -class D3D12Texture { +class D3D12Texture : public RHITexture { public: D3D12Texture(); - ~D3D12Texture(); + ~D3D12Texture() override; bool Initialize(ID3D12Device* device, const D3D12_RESOURCE_DESC& desc, D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COMMON); bool InitializeFromExisting(ID3D12Resource* resource); bool InitializeFromData(ID3D12Device* device, ID3D12GraphicsCommandList* commandList, const void* pixelData, uint32_t width, uint32_t height, DXGI_FORMAT format); bool InitializeDepthStencil(ID3D12Device* device, uint32_t width, uint32_t height, DXGI_FORMAT format = DXGI_FORMAT_D24_UNORM_S8_UINT); - void Shutdown(); + void Shutdown() override; ID3D12Resource* GetResource() const { return m_resource.Get(); } D3D12_RESOURCE_DESC GetDesc() const { return m_resource->GetDesc(); } - uint32_t GetWidth() const { return static_cast(GetDesc().Width); } - uint32_t GetHeight() const { return GetDesc().Height; } - uint32_t GetDepth() const { return GetDesc().DepthOrArraySize; } - uint32_t GetMipLevels() const { return GetDesc().MipLevels; } + uint32_t GetWidth() const override { return static_cast(GetDesc().Width); } + uint32_t GetHeight() const override { return GetDesc().Height; } + uint32_t GetDepth() const override { return GetDesc().DepthOrArraySize; } + uint32_t GetMipLevels() const override { return GetDesc().MipLevels; } - void* GetNativeHandle() const { return m_resource.Get(); } - ResourceStates GetState() const { return m_state; } - void SetState(ResourceStates state) { m_state = state; } + void* GetNativeHandle() override { return m_resource.Get(); } + ResourceStates GetState() const override { return m_state; } + void SetState(ResourceStates state) override { m_state = state; } uint64_t GetGPUAddress() const { return m_resource->GetGPUVirtualAddress(); } size_t GetSize() const { return GetDesc().Width * GetDesc().Height * GetDesc().DepthOrArraySize; } - const std::string& GetName() const { return m_name; } - void SetName(const std::string& name) { m_name = name; } + const std::string& GetName() const override { return m_name; } + void SetName(const std::string& name) override { m_name = name; } uint32_t GetArraySize() const { return GetDesc().DepthOrArraySize; } - Format GetFormat() const { return static_cast(GetDesc().Format); } - TextureType GetTextureType() const { return TextureType::Texture2D; } + Format GetFormat() const override { return static_cast(GetDesc().Format); } + TextureType GetTextureType() const override { return TextureType::Texture2D; } private: ComPtr m_resource; diff --git a/engine/include/XCEngine/RHI/OpenGL/OpenGLBuffer.h b/engine/include/XCEngine/RHI/OpenGL/OpenGLBuffer.h index 3e982285..5f4bd654 100644 --- a/engine/include/XCEngine/RHI/OpenGL/OpenGLBuffer.h +++ b/engine/include/XCEngine/RHI/OpenGL/OpenGLBuffer.h @@ -3,6 +3,8 @@ #include #include +#include "../RHIBuffer.h" + namespace XCEngine { namespace RHI { @@ -18,35 +20,49 @@ enum class OpenGLBufferType { ShaderBindingTable }; -class OpenGLBuffer { +class OpenGLBuffer : public RHIBuffer { public: OpenGLBuffer(); - ~OpenGLBuffer(); + ~OpenGLBuffer() override; bool Initialize(OpenGLBufferType type, size_t size, const void* data = nullptr, bool dynamic = false); bool InitializeVertexBuffer(const void* data, size_t size); bool InitializeIndexBuffer(const void* data, size_t size); - void Shutdown(); + void Shutdown() override; void Bind() const; void Unbind() const; void BindBase(unsigned int target, unsigned int index) const; - void* Map(); - void Unmap(); - void SetData(const void* data, size_t size, size_t offset = 0); + void* Map() override; + void Unmap() override; + void SetData(const void* data, size_t size, size_t offset = 0) override; unsigned int GetID() const { return m_buffer; } - size_t GetSize() const { return m_size; } + uint64_t GetSize() const override { return m_size; } OpenGLBufferType GetType() const { return m_type; } bool IsDynamic() const { return m_dynamic; } + BufferType GetBufferType() const override { return m_bufferType; } + void SetBufferType(BufferType type) override { m_bufferType = type; } + + uint32_t GetStride() const override { return m_stride; } + void SetStride(uint32_t stride) override { m_stride = stride; } + + void* GetNativeHandle() override { return reinterpret_cast(static_cast(m_buffer)); } + + const std::string& GetName() const override { return m_name; } + void SetName(const std::string& name) override { m_name = name; } + private: unsigned int m_buffer; size_t m_size; bool m_isIndexBuffer; bool m_dynamic; OpenGLBufferType m_type; + BufferType m_bufferType = BufferType::Vertex; + uint32_t m_stride = 0; + std::string m_name; }; } // namespace RHI diff --git a/engine/include/XCEngine/RHI/OpenGL/OpenGLShader.h b/engine/include/XCEngine/RHI/OpenGL/OpenGLShader.h index 64be3edc..ef6d77fe 100644 --- a/engine/include/XCEngine/RHI/OpenGL/OpenGLShader.h +++ b/engine/include/XCEngine/RHI/OpenGL/OpenGLShader.h @@ -4,22 +4,19 @@ #include #include +#include "../RHIShader.h" + namespace XCEngine { namespace RHI { -enum class ShaderType { - Vertex, - Fragment, - Geometry, - Compute, - TessControl, - TessEvaluation -}; - -class OpenGLShader { +class OpenGLShader : public RHIShader { public: OpenGLShader(); - ~OpenGLShader(); + ~OpenGLShader() override; + + bool CompileFromFile(const wchar_t* filePath, const char* entryPoint, const char* target) override; + bool Compile(const void* sourceData, size_t sourceSize, const char* entryPoint, const char* target) override; + void Shutdown() override; bool CompileFromFile(const char* vertexPath, const char* fragmentPath); bool CompileFromFile(const char* vertexPath, const char* fragmentPath, const char* geometryPath); @@ -27,33 +24,34 @@ public: bool Compile(const char* vertexSource, const char* fragmentSource, const char* geometrySource); bool CompileCompute(const char* computeSource); bool Compile(const char* source, ShaderType type); - void Shutdown(); void Use() const; - void Bind() const { Use(); } - void Unbind() const; + void Bind() override { Use(); } + void Unbind() override; - void SetInt(const std::string& name, int value) const; - void SetIntArray(const std::string& name, const int* values, unsigned int count) const; - void SetFloat(const std::string& name, float value) const; - void SetFloatArray(const std::string& name, const float* values, unsigned int count) const; - void SetVec2(const std::string& name, float x, float y) const; - void SetVec2(const std::string& name, const float* values) const; - void SetVec3(const std::string& name, float x, float y, float z) const; - void SetVec3(const std::string& name, const float* values) const; - void SetVec4(const std::string& name, float x, float y, float z, float w) const; - void SetVec4(const std::string& name, const float* values) const; - void SetMat2(const std::string& name, const float* value) const; - void SetMat3(const std::string& name, const float* value) const; - void SetMat4(const std::string& name, const float* value) const; - void SetMat4Array(const std::string& name, const float* values, unsigned int count) const; + void SetInt(const char* name, int value) override; + void SetIntArray(const char* name, const int* values, unsigned int count); + void SetFloat(const char* name, float value) override; + void SetFloatArray(const char* name, const float* values, unsigned int count); + void SetVec3(const char* name, float x, float y, float z) override; + void SetVec3(const char* name, const float* values); + void SetVec4(const char* name, float x, float y, float z, float w) override; + void SetVec4(const char* name, const float* values); + void SetMat2(const char* name, const float* value); + void SetMat3(const char* name, const float* value); + void SetMat4(const char* name, const float* value) override; + void SetMat4Array(const char* name, const float* values, unsigned int count); - int GetUniformLocation(const std::string& name) const; + int GetUniformLocation(const char* name) const; unsigned int GetID() const { return m_program; } - bool IsValid() const { return m_program != 0; } + void* GetNativeHandle() override { return reinterpret_cast(static_cast(m_program)); } + bool IsValid() const override { return m_program != 0; } + + ShaderType GetType() const override { return m_type; } private: unsigned int m_program; + ShaderType m_type = ShaderType::Vertex; bool CheckCompileErrors(unsigned int shader, const char* type); bool CheckLinkErrors(unsigned int program); }; diff --git a/engine/include/XCEngine/RHI/OpenGL/OpenGLTexture.h b/engine/include/XCEngine/RHI/OpenGL/OpenGLTexture.h index ab0b9ba3..8dd32786 100644 --- a/engine/include/XCEngine/RHI/OpenGL/OpenGLTexture.h +++ b/engine/include/XCEngine/RHI/OpenGL/OpenGLTexture.h @@ -4,6 +4,8 @@ #include #include +#include "../RHITexture.h" + namespace XCEngine { namespace RHI { @@ -40,16 +42,16 @@ enum class OpenGLInternalFormat { CompressedDXT5 = 22 }; -class OpenGLTexture { +class OpenGLTexture : public RHITexture { public: OpenGLTexture(); - ~OpenGLTexture(); + ~OpenGLTexture() override; bool Initialize(OpenGLTextureType type, int width, int height, int depth, int mipLevels, OpenGLFormat format, const void* data = nullptr); bool Initialize2D(int width, int height, int channels, const void* data, bool generateMipmap = true); bool InitializeCubeMap(int size, int mipLevels, OpenGLFormat format, const void* data = nullptr); bool LoadFromFile(const char* path, bool flipVertical = true); - void Shutdown(); + void Shutdown() override; void Bind(int slot = 0) const; void Unbind() const; @@ -60,11 +62,35 @@ public: void SetWrapping(int wrapS, int wrapT, int wrapR = -1); unsigned int GetID() const { return m_texture; } - OpenGLTextureType GetType() const { return m_type; } - int GetWidth() const { return m_width; } - int GetHeight() const { return m_height; } - int GetDepth() const { return m_depth; } - int GetMipLevels() const { return m_mipLevels; } + OpenGLTextureType GetOpenGLType() const { return m_type; } + + uint32_t GetWidth() const override { return static_cast(m_width); } + uint32_t GetHeight() const override { return static_cast(m_height); } + uint32_t GetDepth() const override { return static_cast(m_depth); } + uint32_t GetMipLevels() const override { return static_cast(m_mipLevels); } + + TextureType GetTextureType() const override { + switch (m_type) { + case OpenGLTextureType::Texture1D: return TextureType::Texture1D; + case OpenGLTextureType::Texture2D: return TextureType::Texture2D; + case OpenGLTextureType::Texture2DArray: return TextureType::Texture2DArray; + case OpenGLTextureType::Texture3D: return TextureType::Texture3D; + case OpenGLTextureType::TextureCube: return TextureType::TextureCube; + case OpenGLTextureType::TextureCubeArray: return TextureType::TextureCubeArray; + default: return TextureType::Texture2D; + } + } + + void* GetNativeHandle() override { return reinterpret_cast(static_cast(m_texture)); } + + ResourceStates GetState() const override { return ResourceStates::Common; } + void SetState(ResourceStates state) override { } + + const std::string& GetName() const override { return m_name; } + void SetName(const std::string& name) override { m_name = name; } + + Format GetFormat() const override { return m_format; } + void SetFormat(Format format) { m_format = format; } private: unsigned int m_texture; @@ -74,6 +100,8 @@ private: int m_depth; int m_mipLevels; int m_channels; + Format m_format = Format::Unknown; + std::string m_name; }; } // namespace RHI diff --git a/engine/include/XCEngine/RHI/RHIBuffer.h b/engine/include/XCEngine/RHI/RHIBuffer.h new file mode 100644 index 00000000..b64f9c95 --- /dev/null +++ b/engine/include/XCEngine/RHI/RHIBuffer.h @@ -0,0 +1,33 @@ +#pragma once + +#include "RHITypes.h" +#include "RHIEnums.h" +#include + +namespace XCEngine { +namespace RHI { + +class RHIBuffer { +public: + virtual ~RHIBuffer() = default; + + virtual void* Map() = 0; + virtual void Unmap() = 0; + virtual void SetData(const void* data, size_t size, size_t offset = 0) = 0; + + virtual uint64_t GetSize() const = 0; + virtual BufferType GetBufferType() const = 0; + virtual void SetBufferType(BufferType type) = 0; + virtual uint32_t GetStride() const = 0; + virtual void SetStride(uint32_t stride) = 0; + + virtual void* GetNativeHandle() = 0; + + virtual const std::string& GetName() const = 0; + virtual void SetName(const std::string& name) = 0; + + virtual void Shutdown() = 0; +}; + +} // namespace RHI +} // namespace XCEngine diff --git a/engine/include/XCEngine/RHI/RHICapabilities.h b/engine/include/XCEngine/RHI/RHICapabilities.h new file mode 100644 index 00000000..ce1fb2a3 --- /dev/null +++ b/engine/include/XCEngine/RHI/RHICapabilities.h @@ -0,0 +1,47 @@ +#pragma once + +#include + +namespace XCEngine { +namespace RHI { + +struct RHICapabilities { + bool bSupportsRayTracing = false; + bool bSupportsMeshShaders = false; + bool bSupportsExplicitMultiThreading = false; + bool bSupportsGeometryShaders = false; + bool bSupportsTessellation = false; + bool bSupportsComputeShaders = false; + bool bSupportsDepthBoundsTest = false; + bool bSupportsAlphaToCoverage = false; + bool bSupportsIndependentBlend = false; + bool bSupportsLogicOps = false; + bool bSupportsMultiViewport = false; + bool bSupportsConservativeRasterization = false; + bool bSupportsProgrammableSamplePositions = false; + + uint32_t maxTexture2DSize = 0; + uint32_t maxTexture3DSize = 0; + uint32_t maxTextureCubeSize = 0; + uint32_t maxRenderTargets = 0; + uint32_t maxViewports = 0; + uint32_t maxVertexAttribs = 0; + uint32_t maxConstantBufferSize = 0; + uint32_t maxAnisotropy = 0; + uint32_t maxColorAttachments = 0; + + float minSmoothedLineWidth = 1.0f; + float maxSmoothedLineWidth = 1.0f; + float minPointSize = 1.0f; + float maxPointSize = 1.0f; + float maxPointSizeAA = 1.0f; + float maxLineWidth = 1.0f; + float maxLineWidthAA = 1.0f; + + int majorVersion = 0; + int minorVersion = 0; + std::string shaderModel; +}; + +} // namespace RHI +} // namespace XCEngine diff --git a/engine/include/XCEngine/RHI/RHIDevice.h b/engine/include/XCEngine/RHI/RHIDevice.h new file mode 100644 index 00000000..27d0b408 --- /dev/null +++ b/engine/include/XCEngine/RHI/RHIDevice.h @@ -0,0 +1,49 @@ +#pragma once + +#include "RHITypes.h" +#include "RHICapabilities.h" +#include + +namespace XCEngine { +namespace RHI { + +class RHIBuffer; +class RHITexture; +class RHISwapChain; +class RHICommandList; +class RHICommandQueue; +class RHIShader; +class RHIPipelineState; +class RHIFence; +class RHISampler; + +class RHIDevice { +public: + virtual ~RHIDevice() = default; + + virtual bool Initialize(const RHIDeviceDesc& desc) = 0; + virtual void Shutdown() = 0; + + virtual RHIBuffer* CreateBuffer(const BufferDesc& desc) = 0; + virtual RHITexture* CreateTexture(const TextureDesc& desc) = 0; + virtual RHISwapChain* CreateSwapChain(const SwapChainDesc& desc) = 0; + virtual RHICommandList* CreateCommandList(const CommandListDesc& desc) = 0; + virtual RHICommandQueue* CreateCommandQueue(const CommandQueueDesc& desc) = 0; + virtual RHIShader* CompileShader(const ShaderCompileDesc& desc) = 0; + virtual RHIPipelineState* CreatePipelineState(const PipelineStateDesc& desc) = 0; + virtual RHIFence* CreateFence(const FenceDesc& desc) = 0; + virtual RHISampler* CreateSampler(const SamplerDesc& desc) = 0; + + virtual const RHICapabilities& GetCapabilities() const = 0; + virtual const RHIDeviceInfo& GetDeviceInfo() const = 0; + + virtual void* GetNativeDevice() = 0; + + virtual bool PollEvents() = 0; + virtual void SwapBuffers() = 0; + virtual bool ShouldClose() const = 0; + virtual void SetShouldClose(bool shouldClose) = 0; +}; + +} // namespace RHI +} // namespace XCEngine diff --git a/engine/include/XCEngine/RHI/RHIEnums.h b/engine/include/XCEngine/RHI/RHIEnums.h index f0b0917a..91a58750 100644 --- a/engine/include/XCEngine/RHI/RHIEnums.h +++ b/engine/include/XCEngine/RHI/RHIEnums.h @@ -7,11 +7,13 @@ namespace RHI { enum class ShaderType : uint8_t { Vertex, + Fragment, + Geometry, + Compute, + TessControl, + TessEvaluation, Hull, Domain, - Geometry, - Pixel, - Compute, Amplification, Mesh, Library @@ -291,5 +293,12 @@ enum class HeapType : uint8_t { Custom }; +enum class RHIType : uint8_t { + D3D12, + OpenGL, + Vulkan, + Metal +}; + } // namespace RHI } // namespace XCEngine diff --git a/engine/include/XCEngine/RHI/RHIShader.h b/engine/include/XCEngine/RHI/RHIShader.h new file mode 100644 index 00000000..4bb36a33 --- /dev/null +++ b/engine/include/XCEngine/RHI/RHIShader.h @@ -0,0 +1,35 @@ +#pragma once + +#include "RHITypes.h" +#include "RHIEnums.h" +#include + +namespace XCEngine { +namespace RHI { + +class RHIShader { +public: + virtual ~RHIShader() = default; + + virtual bool CompileFromFile(const wchar_t* filePath, const char* entryPoint, const char* target) = 0; + virtual bool Compile(const void* sourceData, size_t sourceSize, const char* entryPoint, const char* target) = 0; + + virtual ShaderType GetType() const = 0; + virtual bool IsValid() const = 0; + + virtual void Bind() = 0; + virtual void Unbind() = 0; + + virtual void* GetNativeHandle() = 0; + + virtual void SetInt(const char* name, int value) = 0; + virtual void SetFloat(const char* name, float value) = 0; + virtual void SetVec3(const char* name, float x, float y, float z) = 0; + virtual void SetVec4(const char* name, float x, float y, float z, float w) = 0; + virtual void SetMat4(const char* name, const float* value) = 0; + + virtual void Shutdown() = 0; +}; + +} // namespace RHI +} // namespace XCEngine diff --git a/engine/include/XCEngine/RHI/RHITexture.h b/engine/include/XCEngine/RHI/RHITexture.h new file mode 100644 index 00000000..b7f0ddb3 --- /dev/null +++ b/engine/include/XCEngine/RHI/RHITexture.h @@ -0,0 +1,33 @@ +#pragma once + +#include "RHITypes.h" +#include "RHIEnums.h" +#include + +namespace XCEngine { +namespace RHI { + +class RHITexture { +public: + virtual ~RHITexture() = default; + + virtual uint32_t GetWidth() const = 0; + virtual uint32_t GetHeight() const = 0; + virtual uint32_t GetDepth() const = 0; + virtual uint32_t GetMipLevels() const = 0; + virtual Format GetFormat() const = 0; + virtual TextureType GetTextureType() const = 0; + + virtual ResourceStates GetState() const = 0; + virtual void SetState(ResourceStates state) = 0; + + virtual void* GetNativeHandle() = 0; + + virtual const std::string& GetName() const = 0; + virtual void SetName(const std::string& name) = 0; + + virtual void Shutdown() = 0; +}; + +} // namespace RHI +} // namespace XCEngine diff --git a/engine/include/XCEngine/RHI/RHITypes.h b/engine/include/XCEngine/RHI/RHITypes.h index b341c5b8..ba886c48 100644 --- a/engine/include/XCEngine/RHI/RHITypes.h +++ b/engine/include/XCEngine/RHI/RHITypes.h @@ -238,5 +238,54 @@ struct PipelineStateDesc { uint32_t size; }; +struct RHIDeviceDesc { + bool enableDebugLayer = false; + bool enableGPUValidation = false; + uint32_t adapterIndex = 0; + void* windowHandle = nullptr; + uint32_t width = 1280; + uint32_t height = 720; + std::wstring appName = L"XCEngine"; +}; + +struct RHIDeviceInfo { + std::wstring description; + std::wstring vendor; + std::wstring renderer; + std::wstring version; + uint64_t dedicatedVideoMemory = 0; + uint64_t dedicatedSystemMemory = 0; + uint64_t sharedSystemMemory = 0; + uint32_t vendorId = 0; + uint32_t deviceId = 0; + bool isSoftware = false; +}; + +struct RHIRenderPassDesc { + struct ColorAttachment { + void* texture = nullptr; + uint32_t loadAction = 0; + uint32_t storeAction = 0; + float clearColor[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + }; + ColorAttachment colorAttachments[8]; + uint32_t colorAttachmentCount = 0; + struct DepthStencilAttachment { + void* texture = nullptr; + uint32_t loadAction = 0; + uint32_t storeAction = 0; + float clearDepth = 1.0f; + uint8_t clearStencil = 0; + } depthStencilAttachment; + bool hasDepthStencil = false; +}; + +struct RHIPipelineLayoutDesc { + uint32_t constantBufferCount = 0; + uint32_t textureCount = 0; + uint32_t samplerCount = 0; + uint32_t uavCount = 0; +}; + } // namespace RHI } // namespace XCEngine diff --git a/engine/src/RHI/D3D12/D3D12Shader.cpp b/engine/src/RHI/D3D12/D3D12Shader.cpp index 150f1d62..1a4d1801 100644 --- a/engine/src/RHI/D3D12/D3D12Shader.cpp +++ b/engine/src/RHI/D3D12/D3D12Shader.cpp @@ -27,7 +27,7 @@ bool D3D12Shader::CompileFromFile(const wchar_t* filePath, const char* entryPoin if (strstr(target, "vs_")) { m_type = ShaderType::Vertex; } else if (strstr(target, "ps_")) { - m_type = ShaderType::Pixel; + m_type = ShaderType::Fragment; } else if (strstr(target, "gs_")) { m_type = ShaderType::Geometry; } else if (strstr(target, "cs_")) { diff --git a/engine/src/RHI/OpenGL/OpenGLShader.cpp b/engine/src/RHI/OpenGL/OpenGLShader.cpp index 5c1f7129..436710f0 100644 --- a/engine/src/RHI/OpenGL/OpenGLShader.cpp +++ b/engine/src/RHI/OpenGL/OpenGLShader.cpp @@ -213,68 +213,60 @@ void OpenGLShader::Use() const { glUseProgram(m_program); } -void OpenGLShader::Unbind() const { +void OpenGLShader::Unbind() { glUseProgram(0); } -void OpenGLShader::SetInt(const std::string& name, int value) const { - glUniform1i(glGetUniformLocation(m_program, name.c_str()), value); +void OpenGLShader::SetInt(const char* name, int value) { + glUniform1i(glGetUniformLocation(m_program, name), value); } -void OpenGLShader::SetIntArray(const std::string& name, const int* values, unsigned int count) const { - glUniform1iv(glGetUniformLocation(m_program, name.c_str()), count, values); +void OpenGLShader::SetIntArray(const char* name, const int* values, unsigned int count) { + glUniform1iv(glGetUniformLocation(m_program, name), count, values); } -void OpenGLShader::SetFloat(const std::string& name, float value) const { - glUniform1f(glGetUniformLocation(m_program, name.c_str()), value); +void OpenGLShader::SetFloat(const char* name, float value) { + glUniform1f(glGetUniformLocation(m_program, name), value); } -void OpenGLShader::SetFloatArray(const std::string& name, const float* values, unsigned int count) const { - glUniform1fv(glGetUniformLocation(m_program, name.c_str()), count, values); +void OpenGLShader::SetFloatArray(const char* name, const float* values, unsigned int count) { + glUniform1fv(glGetUniformLocation(m_program, name), count, values); } -void OpenGLShader::SetVec2(const std::string& name, float x, float y) const { - glUniform2f(glGetUniformLocation(m_program, name.c_str()), x, y); +void OpenGLShader::SetVec3(const char* name, float x, float y, float z) { + glUniform3f(glGetUniformLocation(m_program, name), x, y, z); } -void OpenGLShader::SetVec2(const std::string& name, const float* values) const { - glUniform2fv(glGetUniformLocation(m_program, name.c_str()), 1, values); +void OpenGLShader::SetVec3(const char* name, const float* values) { + glUniform3fv(glGetUniformLocation(m_program, name), 1, values); } -void OpenGLShader::SetVec3(const std::string& name, float x, float y, float z) const { - glUniform3f(glGetUniformLocation(m_program, name.c_str()), x, y, z); +void OpenGLShader::SetVec4(const char* name, float x, float y, float z, float w) { + glUniform4f(glGetUniformLocation(m_program, name), x, y, z, w); } -void OpenGLShader::SetVec3(const std::string& name, const float* values) const { - glUniform3fv(glGetUniformLocation(m_program, name.c_str()), 1, values); +void OpenGLShader::SetVec4(const char* name, const float* values) { + glUniform4fv(glGetUniformLocation(m_program, name), 1, values); } -void OpenGLShader::SetVec4(const std::string& name, float x, float y, float z, float w) const { - glUniform4f(glGetUniformLocation(m_program, name.c_str()), x, y, z, w); +void OpenGLShader::SetMat2(const char* name, const float* value) { + glUniformMatrix2fv(glGetUniformLocation(m_program, name), 1, GL_FALSE, value); } -void OpenGLShader::SetVec4(const std::string& name, const float* values) const { - glUniform4fv(glGetUniformLocation(m_program, name.c_str()), 1, values); +void OpenGLShader::SetMat3(const char* name, const float* value) { + glUniformMatrix3fv(glGetUniformLocation(m_program, name), 1, GL_FALSE, value); } -void OpenGLShader::SetMat2(const std::string& name, const float* value) const { - glUniformMatrix2fv(glGetUniformLocation(m_program, name.c_str()), 1, GL_FALSE, value); +void OpenGLShader::SetMat4(const char* name, const float* value) { + glUniformMatrix4fv(glGetUniformLocation(m_program, name), 1, GL_FALSE, value); } -void OpenGLShader::SetMat3(const std::string& name, const float* value) const { - glUniformMatrix3fv(glGetUniformLocation(m_program, name.c_str()), 1, GL_FALSE, value); +void OpenGLShader::SetMat4Array(const char* name, const float* values, unsigned int count) { + glUniformMatrix4fv(glGetUniformLocation(m_program, name), count, GL_FALSE, values); } -void OpenGLShader::SetMat4(const std::string& name, const float* value) const { - glUniformMatrix4fv(glGetUniformLocation(m_program, name.c_str()), 1, GL_FALSE, value); -} - -void OpenGLShader::SetMat4Array(const std::string& name, const float* values, unsigned int count) const { - glUniformMatrix4fv(glGetUniformLocation(m_program, name.c_str()), count, GL_FALSE, values); -} - -int OpenGLShader::GetUniformLocation(const std::string& name) const { - return glGetUniformLocation(m_program, name.c_str()); +int OpenGLShader::GetUniformLocation(const char* name) const { + return glGetUniformLocation(m_program, name); } bool OpenGLShader::CheckCompileErrors(unsigned int shader, const char* type) {