# 跨平台 RHI 渲染架构设计文档 ## 1. 项目背景 本项目旨在参考 Unity 渲染架构,为已有的 **OpenGL** 和 **Direct3D 12** 图形 API 后端设计统一的**渲染硬件抽象层(RHI)**,屏蔽 API 差异,实现引擎上层逻辑与底层图形 API 的解耦。 ### 现有项目结构 ``` engine/ ├── include/XCEngine/RHI/ │ ├── Enums.h # 通用枚举定义 │ ├── Types.h # 通用结构体定义 │ ├── D3D12/ # D3D12 后端实现 │ └── OpenGL/ # OpenGL 后端实现 └── src/RHI/ ├── D3D12/ # D3D12 源码 └── OpenGL/ # OpenGL 源码 ``` ## 2. 核心设计理念 ### 2.1 总体原则 **求同存异,分层抽象,特性降级,底层逃逸** - **求同存异**:优先提取 API 共性作为核心抽象,差异部分通过模拟/降级处理 - **分层抽象**:通过清晰的层级结构隔离 API 差异 - **特性降级**:对高级特性提供能力检测和替代方案 - **底层逃逸**:允许直接访问原生 API 以满足极端需求 ### 2.2 差异分类与处理策略 | 差异类型 | 典型示例 | 处理方案 | |----------|----------|----------| | 概念命名不同但本质相似 | D3D12 `CommandList` ≈ OpenGL 状态机绘制 | 直接统一抽象 | | 显式控制 vs 隐式管理 | D3D12 `DescriptorHeap` vs OpenGL 纹理单元 | 提供"自动模式"+"显式模式" | | API 独有高级特性 | D3D12 光线追踪、网格着色器 | 特性检测 + 降级方案 + 底层逃逸 | ## 3. RHI 分层架构 ### 3.1 通用分层模型 ``` ┌─────────────────────────────────┐ │ 引擎功能层(场景/材质/光照) │ ├─────────────────────────────────┤ │ 渲染管线层(SRP/Render Graph) │ ├─────────────────────────────────┤ │ RHI 抽象层(统一接口) │ ← 核心设计重点 ├─────────────────────────────────┤ │ API 后端层(D3D12/OpenGL) │ ├─────────────────────────────────┤ │ 驱动/硬件层 │ └─────────────────────────────────┘ ``` ### 3.2 层级职责说明 1. **引擎功能层**:提供场景管理、材质系统、光照等高级功能接口 2. **渲染管线层**:定义渲染流程(前向/延迟渲染) 3. **RHI 抽象层**:统一图形 API 接口,屏蔽差异 4. **API 后端层**:针对具体 API 的实现 5. **驱动/硬件层**:最终执行渲染指令 ## 4. RHI 抽象基类设计 ### 4.1 目录结构调整建议 ``` include/XCEngine/RHI/ ├── RHIEnums.h # 通用枚举 ├── RHITypes.h # 通用结构体 ├── RHICapabilities.h # 硬件能力检测 ├── RHIDevice.h # 设备抽象(核心入口) ├── RHICommandQueue.h # 命令队列抽象 ├── RHICommandList.h # 命令列表抽象 ├── RHIBuffer.h # 缓冲区抽象 ├── RHITexture.h # 纹理抽象 ├── RHIShader.h # 着色器抽象 ├── RHIPipelineLayout.h # 管线布局抽象(替代 RootSignature) ├── RHIPipelineState.h # 管线状态抽象 ├── RHISwapChain.h # 交换链抽象 ├── RHIFence.h # 同步栅栏抽象 ├── RHIDescriptorPool.h # 描述符池抽象 └── RHIFactory.h # RHI 工厂类 ``` ### 4.2 核心抽象基类定义 #### 4.2.1 通用类型定义(Types.h) ```cpp #pragma once #include // 通用资源格式 enum class RHIFormat { R8G8B8A8_UNORM, D32_FLOAT, // ... 其他格式 }; // 缓冲区用途 enum class RHIBufferUsage { VertexBuffer, IndexBuffer, ConstantBuffer, // ... 其他用途 }; // 通用缓冲区描述 struct RHIBufferDesc { uint64_t size; RHIBufferUsage usage; // ... 其他参数 }; // 通用纹理描述 struct RHITextureDesc { uint32_t width; uint32_t height; RHIFormat format; // ... 其他参数 }; // 通用渲染通道描述 struct RHIRenderPassDesc { struct Attachment { RHITexture* texture; float clearColor[4]; // ... 其他参数 } colorAttachments[8]; uint32_t colorAttachmentCount; Attachment depthStencilAttachment; // ... 其他参数 }; ``` #### 4.2.2 硬件能力检测(RHICapabilities.h) ```cpp #pragma once struct RHICapabilities { bool bSupportsRayTracing = false; bool bSupportsMeshShaders = false; bool bSupportsExplicitMultiThreading = false; // ... 其他特性 }; ``` #### 4.2.3 设备抽象(RHIDevice.h) ```cpp #pragma once #include "Types.h" #include "RHICapabilities.h" class RHISwapChain; class RHICommandQueue; class RHIBuffer; class RHITexture; class RHIDevice { public: virtual ~RHIDevice() = default; // 初始化设备 virtual bool Initialize(const RHIDeviceDesc& desc) = 0; // 资源创建接口 virtual RHIBuffer* CreateBuffer(const RHIBufferDesc& desc) = 0; virtual RHITexture* CreateTexture(const RHITextureDesc& desc) = 0; virtual RHICommandQueue* CreateCommandQueue(const RHICommandQueueDesc& desc) = 0; virtual RHISwapChain* CreateSwapChain(const RHISwapChainDesc& desc) = 0; // 硬件能力查询 virtual const RHICapabilities& GetCapabilities() const = 0; // 底层逃逸口(谨慎使用) virtual void* GetNativeDevice() = 0; // 清理 virtual void Shutdown() = 0; }; ``` #### 4.2.4 命令列表抽象(RHICommandList.h) ```cpp #pragma once #include "Types.h" class RHIBuffer; class RHITexture; class RHIPipelineState; class RHICommandList { public: virtual ~RHICommandList() = default; // 命令录制 virtual void Begin() = 0; virtual void End() = 0; // 渲染通道 virtual void BeginRenderPass(const RHIRenderPassDesc& desc) = 0; virtual void EndRenderPass() = 0; // 状态设置 virtual void SetPipelineState(RHIPipelineState* pso) = 0; virtual void SetVertexBuffers(uint32_t slot, RHIBuffer* const* buffers, uint32_t count) = 0; virtual void SetIndexBuffer(RHIBuffer* buffer, RHIFormat format, uint32_t offset) = 0; // 绘制命令 virtual void DrawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t startIndex, int32_t baseVertex, uint32_t startInstance) = 0; // 资源拷贝 virtual void CopyBuffer(RHIBuffer* dst, RHIBuffer* src, uint64_t size) = 0; }; ``` #### 4.2.5 管线布局抽象(RHIPipelineLayout.h) ```cpp #pragma once #include "Types.h" // 管线布局描述(统一描述资源绑定规则) struct RHIPipelineLayoutDesc { uint32_t constantBufferCount; uint32_t textureCount; uint32_t samplerCount; // ... 其他参数 }; class RHIPipelineLayout { public: virtual ~RHIPipelineLayout() = default; // 具体实现由后端处理 }; ``` #### 4.2.6 RHI 工厂类(RHIFactory.h) ```cpp #pragma once #include "RHIDevice.h" #include enum class RHIType { D3D12, OpenGL, // 未来扩展 Vulkan/Metal }; class RHIFactory { public: // 根据类型创建 RHI 设备 static RHIDevice* CreateRHIDevice(RHIType type); // 根据字符串选择(从配置文件读取) static RHIDevice* CreateRHIDevice(const std::string& typeName); }; ``` ## 5. 核心差异处理方案 ### 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 采样器(RHISampler)抽象设计 #### 5.8.1 设计理念对应 | 差异点 | 设计理念 | 处理方案 | |--------|---------|---------| | 初始化参数差异 | 求同存异 | 后端各自实现初始化 | | 句柄类型差异 | 底层逃逸 | 统一返回 void* | | 绑定方式 | 求同存异 | 基类提供 Bind/Unbind | #### 5.8.2 现有实现对比 | 功能 | D3D12Sampler | OpenGLSampler | |------|--------------|---------------| | 初始化 | Initialize(device, desc) | Initialize(desc) | | 销毁 | Shutdown() | Shutdown() | | 绑定 | 通过 DescriptorHeap | Bind(unit) | | 句柄 | GetNativeHandle() | GetID() | #### 5.8.3 抽象接口定义 ```cpp class RHISampler { public: virtual ~RHISampler() = default; virtual void Shutdown() = 0; virtual void Bind(unsigned int unit) = 0; virtual void Unbind(unsigned int unit) = 0; virtual void* GetNativeHandle() = 0; virtual unsigned int GetID() = 0; }; ``` #### 5.8.4 差异处理策略 1. **初始化参数差异(求同存异)** - D3D12:需要 device 参数 - OpenGL:不需要 device - 解决:Device 的 CreateSampler() 统一接收 SamplerDesc,后端各自实现 Initialize() 2. **句柄类型差异(底层逃逸)** - D3D12:通过 DescriptorHeap 管理 - OpenGL:GLuint - 解决:GetNativeHandle() 返回 void* ### 5.9 同步栅栏(RHIFence)抽象设计 #### 5.9.1 设计理念对应 | 差异点 | 设计理念 | 处理方案 | |--------|---------|---------| | 初始化参数差异 | 求同存异 | 后端各自实现初始化 | | 句柄类型差异 | 底层逃逸 | 统一返回 void* | | 状态查询 | 求同存异 | 统一 IsSignaled/GetCompletedValue 接口 | #### 5.9.2 现有实现对比 | 功能 | D3D12Fence | OpenGLFence | |------|-------------|-------------| | 初始化 | Initialize(device, value) | Initialize(signaled) | | Signal | Signal(value) | Signal()/Signal(value) | | Wait | Wait(value) | Wait(timeoutNs) | | 状态 | GetCompletedValue() | IsSignaled()/GetStatus() | | 句柄 | ID3D12Fence* | GLsync | #### 5.9.3 抽象接口定义 ```cpp class RHIFence { public: virtual ~RHIFence() = default; virtual void Shutdown() = 0; virtual void Signal(uint64_t value) = 0; virtual void Wait(uint64_t value) = 0; virtual uint64_t GetCompletedValue() = 0; virtual bool IsSignaled() const = 0; virtual void* GetNativeHandle() = 0; }; ``` #### 5.9.4 差异处理策略 1. **初始化参数差异(求同存异)** - D3D12:需要 device 参数 - OpenGL:不需要 device - 解决:后端各自实现 Initialize() 2. **句柄类型差异(底层逃逸)** - D3D12:ID3D12Fence* - OpenGL:GLsync - 解决:GetNativeHandle() 返回 void* ### 5.10 设备(RHIDevice)抽象设计 #### 5.10.1 设计理念对应 | 差异点 | 设计理念 | 处理方案 | |--------|---------|---------| | 初始化参数差异 | 求同存异 | 统一 Initialize 接口,后端各自处理 | | 工厂方法差异 | 特性降级 | D3D12 实现,OpenGL 返回 nullptr | | 窗口管理差异 | 特性降级 | OpenGL 有,D3D12 通过 SwapChain 处理 | | 适配器枚举差异 | 特性降级 | D3D12 实现,OpenGL 空实现 | | 底层设备类型差异 | 底层逃逸 | 统一返回 void* | #### 5.10.2 现有实现对比 | 功能 | D3D12Device | OpenGLDevice | 处理方案 | |------|--------------|---------------|----------| | 初始化 | Initialize(debugLayer) | CreateRenderWindow/InitializeWithExistingWindow | 统一 Initialize | | 关闭 | Shutdown() | Shutdown() | 统一 | | 获取设备 | GetDevice() | 无 | GetNativeHandle 统一 | | 适配器信息 | GetAdapterInfo() | GetDeviceInfo() | 统一 GetDeviceInfo | | 工厂方法 | CreateBuffer/Texture/Shader... | 无 | OpenGL 返回 nullptr | | 窗口管理 | 通过 SwapChain | GetWindow/SwapBuffers/PollEvents | OpenGL 有,D3D12 无 | #### 5.10.3 抽象接口定义 ```cpp class RHIDevice { public: virtual ~RHIDevice() = default; virtual bool Initialize(const RHIDeviceDesc& desc) = 0; virtual void Shutdown() = 0; virtual const RHIDeviceInfo& GetDeviceInfo() const = 0; virtual const RHICapabilities& GetCapabilities() const = 0; virtual RHIBuffer* CreateBuffer(const BufferDesc& desc) = 0; virtual RHITexture* CreateTexture(const TextureDesc& desc) = 0; virtual RHIShader* CompileShader(const ShaderCompileDesc& desc) = 0; virtual RHISampler* CreateSampler(const SamplerDesc& desc) = 0; virtual RHIFence* CreateFence(const FenceDesc& desc) = 0; virtual void* GetNativeDevice() = 0; virtual void* GetNativeHandle() const = 0; }; ``` #### 5.10.4 差异处理策略 1. **初始化参数差异(求同存异)** - D3D12:`Initialize(enableDebugLayer)` - OpenGL:`CreateRenderWindow` / `InitializeWithExistingWindow` - 解决:统一 `Initialize(const RHIDeviceDesc& desc)` 接口,Desc 中包含窗口参数 2. **工厂方法差异(特性降级)** - D3D12:有完整的工厂方法 - OpenGL:资源直接用 glGen* 创建,没有工厂方法 - 解决:OpenGL 后端返回 nullptr,上层需直接创建 OpenGL 资源 3. **窗口管理差异(特性降级)** - OpenGL:直接管理窗口,有 GetWindow/SwapBuffers/PollEvents - D3D12:通过 SwapChain 处理 - 解决:OpenGL 提供窗口管理接口,D3D12 空实现 4. **适配器枚举差异(特性降级)** - D3D12:支持 EnumerateAdapters - OpenGL:无此概念 - 解决:D3D12 实现具体功能,OpenGL 返回空 5. **底层设备类型差异(底层逃逸)** - D3D12:ID3D12Device* - OpenGL:无对等概念 - 解决:GetNativeDevice() 返回 void*,OpenGL 返回 nullptr 或窗口句柄 - **D3D12**:显式 `RootSignature` 定义资源绑定规则 - **OpenGL**:隐式通过 `glUniformLocation`、`glBindTextureUnit` 绑定 - **解决方案**: - 用 `RHIPipelineLayout` 统一抽象 - D3D12 后端:内部创建 `ID3D12RootSignature` - OpenGL 后端:存储绑定点数量,绘制时自动调用 `glBind*` ### 5.4 描述符堆 vs OpenGL 纹理单元 - **D3D12**:显式 `DescriptorHeap` 管理资源视图 - **OpenGL**:隐式通过 `glActiveTexture` 绑定 - **解决方案**: - 用 `RHIDescriptorPool` 统一抽象 - 提供"自动模式"(默认)和"显式模式"(可选) - D3D12 后端:从堆分配槽位,更新描述符 - OpenGL 后端:维护绑定点计数器,绘制时自动绑定 ### 5.5 多线程命令录制 - **D3D12**:原生支持多线程录制不同 `CommandList` - **OpenGL**:状态机模型,单线程上下文 - **解决方案**: - 抽象层统一提供多线程接口 - D3D12 后端:真·并行提交 - OpenGL 后端:命令缓冲队列,单线程回放 ### 5.6 高级特性(光线追踪等) - **解决方案**: 1. **特性检测**:通过 `RHICapabilities` 查询支持情况 2. **降级方案**:不支持时用传统路径替代 3. **底层逃逸**:通过 `GetNativeDevice()` 直接访问原生 API ### 5.11 命令队列(RHICommandQueue)抽象设计 #### 5.11.1 设计理念对应 | 差异点 | 设计理念 | 处理方案 | |--------|---------|---------| | 初始化参数差异 | 求同存异 | 后端各自实现初始化 | | 执行命令差异 | 特性降级 | D3D12 实现,OpenGL 空实现 | | 同步机制差异 | 特性降级 | D3D12 实现,OpenGL 空实现 | | 句柄类型差异 | 底层逃逸 | 统一返回 void* | #### 5.11.2 现有实现对比 | 功能 | D3D12CommandQueue | OpenGL | 处理方案 | |------|-------------------|--------|----------| | 初始化 | Initialize(device, type) | 无 | OpenGL 空实现 | | 执行命令 | ExecuteCommandLists() | 无 | OpenGL 空实现 | | 信号同步 | Signal/Wait | 无 | OpenGL 空实现 | | 空闲等待 | WaitForIdle() | 无 | OpenGL 空实现 | | 句柄 | ID3D12CommandQueue* | 无 | GetNativeHandle | #### 5.11.3 抽象接口定义 ```cpp class RHICommandQueue { public: virtual ~RHICommandQueue() = default; virtual void Shutdown() = 0; virtual void ExecuteCommandLists(uint32_t count, void** lists) = 0; virtual void Signal(RHIFence* fence, uint64_t value) = 0; virtual void Wait(RHIFence* fence, uint64_t value) = 0; virtual uint64_t GetCompletedValue() = 0; virtual void WaitForIdle() = 0; virtual CommandQueueType GetType() const = 0; virtual uint64_t GetTimestampFrequency() const = 0; virtual void* GetNativeHandle() = 0; }; ``` #### 5.11.4 差异处理策略 1. **初始化参数差异(求同存异)** - D3D12:需要 device + type 参数 - OpenGL:无对等概念 - 解决:Device 的 CreateCommandQueue() 统一接收 CommandQueueDesc 2. **执行命令差异(特性降级)** - D3D12:ExecuteCommandLists() 提交命令列表 - OpenGL:状态机模型,无命令队列概念 - 解决:OpenGL 空实现 3. **同步机制差异(特性降级)** - D3D12:Signal/Wait/Fence 完整实现 - OpenGL:无对等概念 - 解决:OpenGL 空实现 4. **句柄类型差异(底层逃逸)** - D3D12:ID3D12CommandQueue* - OpenGL:无对等概念 - 解决:GetNativeHandle() 返回 void* ## 6. 后端实现示例 ### 6.1 D3D12 设备实现(D3D12Device.h) ```cpp #pragma once #include "../RHIDevice.h" #include "D3D12Common.h" class D3D12Device : public RHIDevice { public: virtual bool Initialize(const RHIDeviceDesc& desc) override; virtual RHIBuffer* CreateBuffer(const RHIBufferDesc& desc) override; virtual RHITexture* CreateTexture(const RHITextureDesc& desc) override; virtual RHICommandQueue* CreateCommandQueue(const RHICommandQueueDesc& desc) override; virtual RHISwapChain* CreateSwapChain(const RHISwapChainDesc& desc) override; virtual const RHICapabilities& GetCapabilities() const override; virtual void* GetNativeDevice() override { return m_pd3d12Device; } virtual void Shutdown() override; // D3D12 特有接口 ID3D12Device* GetD3D12Device() const { return m_pd3d12Device; } private: ID3D12Device* m_pd3d12Device = nullptr; ID3D12CommandQueue* m_pd3d12CommandQueue = nullptr; RHICapabilities m_capabilities; }; ``` ### 6.2 OpenGL 设备实现(OpenGLDevice.h) ```cpp #pragma once #include "../RHIDevice.h" #include "OpenGLCommon.h" class OpenGLDevice : public RHIDevice { public: virtual bool Initialize(const RHIDeviceDesc& desc) override; virtual RHIBuffer* CreateBuffer(const RHIBufferDesc& desc) override; virtual RHITexture* CreateTexture(const RHITextureDesc& desc) override; virtual RHICommandQueue* CreateCommandQueue(const RHICommandQueueDesc& desc) override; virtual RHISwapChain* CreateSwapChain(const RHISwapChainDesc& desc) override; virtual const RHICapabilities& GetCapabilities() const override; virtual void* GetNativeDevice() override { return m_context; } virtual void Shutdown() override; // OpenGL 特有接口 HGLRC GetContext() const { return m_context; } private: HGLRC m_context = nullptr; RHICapabilities m_capabilities; }; ``` ## 7. 测试用例示例 ### 7.1 最小渲染循环测试 ```cpp #include "XCEngine/RHI/RHIFactory.h" #include "XCEngine/RHI/RHIDevice.h" #include "XCEngine/RHI/RHISwapChain.h" #include "XCEngine/RHI/RHICommandList.h" int main() { // 1. 创建 RHI 设备(可切换 D3D12/OpenGL) RHIDevice* pDevice = RHIFactory::CreateRHIDevice(RHIType::D3D12); pDevice->Initialize(RHIDeviceDesc{...}); // 2. 创建交换链和命令队列 RHISwapChain* pSwapChain = pDevice->CreateSwapChain(RHISwapChainDesc{...}); RHICommandQueue* pCommandQueue = pDevice->CreateCommandQueue(RHICommandQueueDesc{...}); RHICommandList* pCommandList = pDevice->CreateCommandList(RHICommandListDesc{...}); // 3. 渲染循环 while (!ShouldQuit()) { // 录制命令 pCommandList->Begin(); // 清屏 RHIRenderPassDesc renderPassDesc = {}; renderPassDesc.colorAttachments[0].texture = pSwapChain->GetCurrentBackBuffer(); renderPassDesc.colorAttachments[0].loadOp = RHIRenderPassLoadOp::Clear; renderPassDesc.colorAttachments[0].clearColor = {0.2f, 0.4f, 0.8f, 1.0f}; pCommandList->BeginRenderPass(renderPassDesc); pCommandList->EndRenderPass(); // 提交命令 pCommandList->End(); pCommandQueue->SubmitCommandList(pCommandList); // 呈现 pSwapChain->Present(); } // 4. 清理 pDevice->Shutdown(); delete pDevice; return 0; } ``` ## 8. 下一步行动指南 1. **补全抽象基类**:重点实现 `RHIDevice`、`RHICommandList`、`RHIPipelineLayout` 2. **改造现有后端**:让 `D3D12Device`、`OpenGLDevice` 继承抽象基类并实现接口 3. **实现工厂类**:完成 `RHIFactory` 以支持动态切换后端 4. **测试验证**:用最小渲染循环测试 D3D12 和 OpenGL 后端 5. **扩展功能**:逐步添加资源管理、着色器跨平台、多线程渲染等功能 ## 9. 关键注意事项 - **上层只调用抽象接口**:绝不直接访问 D3D12/OpenGL 特有类 - **合理使用底层逃逸**:仅在必要时使用 `GetNativeDevice()`,并注明破坏跨平台性 - **优先保证核心功能**:先实现 90% 常用功能的统一抽象,再处理高级特性 - **保持设计可扩展**:为未来支持 Vulkan/Metal 预留空间 需要我帮你细化某个具体模块的实现代码吗?