Files
XCEngine/docs/RHI抽象层设计与实现.md
ssdfasd be72e2f4a7 Enhance OpenGL RTV and DSV with comprehensive framebuffer support
OpenGLRenderTargetView:
- Add RenderTargetType enum for different texture types
- Add RenderTargetViewDesc struct with mip level, array slice, layer info
- Add Initialize() with desc parameter for 2D/2DArray/3D/Cube
- Add InitializeCubemap() for cubemap faces
- Add Bind(count) overload for multiple framebuffers
- Add Clear() methods for color and depth-stencil
- Add static BindFramebuffer/UnbindFramebuffer methods

OpenGLDepthStencilView:
- Add DepthStencilType enum for different texture types
- Add DepthStencilViewDesc struct with mip level, array slice, layer info
- Add Initialize() with desc parameter for 2D/2DArray/Cube
- Add InitializeCubemap() for cubemap faces
- Add ClearDepth, ClearStencil, ClearDepthStencil methods
- Add static BindFramebuffer/UnbindFramebuffer methods
2026-03-17 02:20:56 +08:00

13 KiB
Raw Blame History

跨平台 RHI 渲染架构设计文档

1. 项目背景

本项目旨在参考 Unity 渲染架构,为已有的 OpenGLDirect3D 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

#pragma once
#include <cstdint>

// 通用资源格式
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

#pragma once

struct RHICapabilities {
    bool bSupportsRayTracing = false;
    bool bSupportsMeshShaders = false;
    bool bSupportsExplicitMultiThreading = false;
    // ... 其他特性
};

4.2.3 设备抽象RHIDevice.h

#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

#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

#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

#pragma once
#include "RHIDevice.h"
#include <string>

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 根签名 vs OpenGL 资源绑定

  • D3D12:显式 RootSignature 定义资源绑定规则
  • OpenGL:隐式通过 glUniformLocationglBindTextureUnit 绑定
  • 解决方案
    • RHIPipelineLayout 统一抽象
    • D3D12 后端:内部创建 ID3D12RootSignature
    • OpenGL 后端:存储绑定点数量,绘制时自动调用 glBind*

5.2 描述符堆 vs OpenGL 纹理单元

  • D3D12:显式 DescriptorHeap 管理资源视图
  • OpenGL:隐式通过 glActiveTexture 绑定
  • 解决方案
    • RHIDescriptorPool 统一抽象
    • 提供"自动模式"(默认)和"显式模式"(可选)
    • D3D12 后端:从堆分配槽位,更新描述符
    • OpenGL 后端:维护绑定点计数器,绘制时自动绑定

5.3 多线程命令录制

  • D3D12:原生支持多线程录制不同 CommandList
  • OpenGL:状态机模型,单线程上下文
  • 解决方案
    • 抽象层统一提供多线程接口
    • D3D12 后端:真·并行提交
    • OpenGL 后端:命令缓冲队列,单线程回放

5.4 高级特性(光线追踪等)

  • 解决方案
    1. 特性检测:通过 RHICapabilities 查询支持情况
    2. 降级方案:不支持时用传统路径替代
    3. 底层逃逸:通过 GetNativeDevice() 直接访问原生 API

6. 后端实现示例

6.1 D3D12 设备实现D3D12Device.h

#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

#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 最小渲染循环测试

#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. 补全抽象基类:重点实现 RHIDeviceRHICommandListRHIPipelineLayout
  2. 改造现有后端:让 D3D12DeviceOpenGLDevice 继承抽象基类并实现接口
  3. 实现工厂类:完成 RHIFactory 以支持动态切换后端
  4. 测试验证:用最小渲染循环测试 D3D12 和 OpenGL 后端
  5. 扩展功能:逐步添加资源管理、着色器跨平台、多线程渲染等功能

9. 关键注意事项

  • 上层只调用抽象接口:绝不直接访问 D3D12/OpenGL 特有类
  • 合理使用底层逃逸:仅在必要时使用 GetNativeDevice(),并注明破坏跨平台性
  • 优先保证核心功能:先实现 90% 常用功能的统一抽象,再处理高级特性
  • 保持设计可扩展:为未来支持 Vulkan/Metal 预留空间

需要我帮你细化某个具体模块的实现代码吗?