Files
XCEngine/docs/used/RHI抽象层设计与实现.md
2026-03-29 01:36:53 +08:00

36 KiB
Raw Permalink 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 缓冲区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 抽象接口定义

// 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. 初始化参数差异

    • D3D12CreateBuffer() 时由 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 创建接口

    // 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 显式管理 ResourceStatesOpenGL 无需管理(透明)
格式枚举差异 求同存异 基类统一 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 抽象接口定义

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*
    • D3D12return m_resource.Get();
    • OpenGLreturn reinterpret_cast<void*>(static_cast<uintptr_t>(m_texture));
  3. 资源状态管理(特性降级)

    • D3D12显式 ResourceStates 管理,需要转换 barrier
    • OpenGL无资源状态概念
    • 解决:基类提供 GetState/SetStateD3D12 实现具体逻辑OpenGL 空实现
  4. 格式枚举差异(求同存异)

    • D3D12DXGI_FORMAT
    • OpenGLOpenGLFormat
    • 解决:基类统一使用 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 抽象接口定义

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. 句柄类型差异(底层逃逸)

    • D3D12ID3DBlob
    • OpenGLGLuint (program)
    • 解决GetNativeHandle() 返回 void*
  3. Uniform 设置(特性降级)

    • D3D12通过 RootSignature/CBV 设置,不在 Shader 类
    • OpenGL通过 glUniform* 设置
    • 解决D3D12 实现为空OpenGL 实现具体逻辑
  4. 绑定方式

    • D3D12通过 CommandList->SetPipelineState
    • OpenGLglUseProgram
    • 解决:基类提供 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 抽象接口定义

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 管理
    • OpenGLGLuint
    • 解决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 抽象接口定义

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. 句柄类型差异(底层逃逸)

    • D3D12ID3D12Fence*
    • OpenGLGLsync
    • 解决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 抽象接口定义

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. 初始化参数差异(求同存异)

    • D3D12Initialize(enableDebugLayer)
    • OpenGLCreateRenderWindow / 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. 底层设备类型差异(底层逃逸)

    • D3D12ID3D12Device*
    • OpenGL无对等概念
    • 解决GetNativeDevice() 返回 void*OpenGL 返回 nullptr 或窗口句柄
  • D3D12:显式 RootSignature 定义资源绑定规则
  • OpenGL:隐式通过 glUniformLocationglBindTextureUnit 绑定
  • 解决方案
    • 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 抽象接口定义

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. 执行命令差异(特性降级)

    • D3D12ExecuteCommandLists() 提交命令列表
    • OpenGL状态机模型无命令队列概念
    • 解决OpenGL 空实现
  3. 同步机制差异(特性降级)

    • D3D12Signal/Wait/Fence 完整实现
    • OpenGL无对等概念
    • 解决OpenGL 空实现
  4. 句柄类型差异(底层逃逸)

    • D3D12ID3D12CommandQueue*
    • OpenGL无对等概念
    • 解决GetNativeHandle() 返回 void*

5.12 命令列表RHICommandList抽象设计

5.12.1 设计理念对应

差异点 设计理念 处理方案
资源状态转换 特性降级 D3D12 实现转换OpenGL 空实现
绑定方式 求同存异 统一接口,后端各自实现
渲染目标 求同存异 统一接口,后端各自实现

5.12.2 现有实现对比

功能 D3D12CommandList OpenGLCommandList 处理方案
资源转换 TransitionBarrier glBarrier 统一 TransitionBarrier
PSO 设置 SetPipelineState UseShader 统一 SetPipelineState
视口/裁剪 SetViewport/ScissorRect SetViewport/Scissor 统一
顶点缓冲 SetVertexBuffer BindVertexArray 统一
索引缓冲 SetIndexBuffer BindVertexArray 统一
绘制 Draw/DrawIndexed Draw/DrawIndexed 统一
渲染目标 SetRenderTargets glBindFramebuffer 统一
清除 ClearRenderTargetView Clear 统一
复制 CopyResource CopyImageSubData 统一
计算 Dispatch DispatchCompute 统一

5.12.3 抽象接口定义

class RHICommandList {
public:
    virtual ~RHICommandList() = default;

    virtual void Shutdown() = 0;

    virtual void Reset() = 0;
    virtual void Close() = 0;

    virtual void TransitionBarrier(void* resource, ResourceStates stateBefore, ResourceStates stateAfter) = 0;

    virtual void SetPipelineState(void* pso) = 0;
    virtual void SetViewport(const Viewport& viewport) = 0;
    virtual void SetScissorRect(const Rect& rect) = 0;
    virtual void SetRenderTargets(uint32_t count, void** renderTargets, void* depthStencil = nullptr) = 0;

    virtual void SetVertexBuffer(uint32_t slot, void* buffer, uint64_t offset, uint32_t stride) = 0;
    virtual void SetIndexBuffer(void* buffer, uint64_t offset, Format format) = 0;

    virtual void Draw(uint32_t vertexCount, uint32_t instanceCount = 1, uint32_t startVertex = 0, uint32_t startInstance = 0) = 0;
    virtual void DrawIndexed(uint32_t indexCount, uint32_t instanceCount = 1, uint32_t startIndex = 0, int32_t baseVertex = 0, uint32_t startInstance = 0) = 0;

    virtual void Clear(float r, float g, float b, float a, uint32_t buffers) = 0;
    virtual void ClearRenderTarget(void* renderTarget, const float color[4]) = 0;
    virtual void ClearDepthStencil(void* depthStencil, float depth, uint8_t stencil) = 0;

    virtual void CopyResource(void* dst, void* src) = 0;

    virtual void Dispatch(uint32_t x, uint32_t y, uint32_t z) = 0;
};

5.12.4 差异处理策略

  1. 资源状态转换(特性降级)

    • D3D12显式 TransitionBarrier 管理资源状态
    • OpenGL无资源状态概念
    • 解决D3D12 实现转换OpenGL 空实现
  2. 绑定方式(求同存异)

    • D3D12通过 DescriptorHeap 和 RootSignature
    • OpenGL通过 glBind* 和 VAO
    • 解决:统一 Set* 接口,后端各自实现
  3. 渲染目标(求同存异)

    • D3D12SetRenderTargets 设置渲染目标视图
    • OpenGLglBindFramebuffer 绑定帧缓冲
    • 解决:统一 SetRenderTargets 接口

5.13 交换链RHISwapChain抽象设计

5.13.1 设计理念对应

差异点 设计理念 处理方案
初始化参数差异 求同存异 统一 Desc后端各自处理
窗口管理差异 特性降级 OpenGL 有D3D12 无
呈现方式差异 求同存异 统一 Present 接口

5.13.2 现有实现对比

功能 D3D12SwapChain OpenGLSwapChain 处理方案
初始化 factory/queue/hwnd window 统一 Initialize(Desc)
后缓冲 GetBackBuffer() 通过 GetCurrentBackBuffer
显示 Present(sync, flags) Present() 统一 Present()
调整大小 Resize(w, h) Resize(w, h) 统一
窗口事件 ShouldClose/PollEvents OpenGL 实现

5.13.3 抽象接口定义

class RHISwapChain {
public:
    virtual ~RHISwapChain() = default;

    virtual void Shutdown() = 0;

    virtual uint32_t GetCurrentBackBufferIndex() const = 0;
    virtual RHITexture* GetCurrentBackBuffer() = 0;
    virtual void Present(uint32_t syncInterval = 1, uint32_t flags = 0) = 0;
    virtual void Resize(uint32_t width, uint32_t height) = 0;

    virtual bool ShouldClose() const = 0;
    virtual void SetShouldClose(bool shouldClose) = 0;
    virtual void PollEvents() = 0;
};

5.13.4 差异处理策略

  1. 初始化参数差异(求同存异)

    • D3D12factory + commandQueue + hwnd
    • OpenGLwindow
    • 解决Device 的 CreateSwapChain() 统一接收 SwapChainDesc
  2. 窗口管理差异(特性降级)

    • OpenGLShouldClose/PollEvents
    • D3D12
    • 解决OpenGL 实现具体功能D3D12 空实现
  3. 呈现方式差异(求同存异)

    • D3D12Present(syncInterval, flags)
    • OpenGLPresent() / SwapBuffers()
    • 解决:统一 Present(syncInterval, flags)

5.14 管线状态RHIPipelineState抽象设计

5.14.1 设计理念对应

差异点 设计理念 处理方案
初始化差异 求同存异 后端各自处理
状态管理差异 特性降级 D3D12 实现状态块OpenGL 分离状态
绑定方式差异 求同存异 统一 Bind 接口

5.14.2 现有实现对比

功能 D3D12PipelineState OpenGLPipelineState 处理方案
初始化 device + desc 构造函数 后端各自处理
状态设置 单一 PSO 对象 分离状态对象 后端各自处理
绑定 CommandList->SetPipelineState AttachShader/Apply 统一 Bind
句柄 ID3D12PipelineState* GLuint (program) 统一 void*

5.14.3 抽象接口定义

class RHIPipelineState {
public:
    virtual ~RHIPipelineState() = default;

    virtual void Shutdown() = 0;

    virtual void Bind() = 0;
    virtual void Unbind() = 0;

    virtual void* GetNativeHandle() = 0;
    virtual PipelineType GetType() const = 0;
};

5.14.4 差异处理策略

  1. 初始化差异(求同存异)

    • D3D12device + D3D12_GRAPHICS_PIPELINE_STATE_DESC
    • OpenGL通过 SetDepthStencilState/BlendState/RasterizerState
    • 解决Device 的 CreatePipelineState() 统一接收 PipelineStateDesc
  2. 状态管理差异(特性降级)

    • D3D12单一 PSO 对象包含所有状态
    • OpenGL分离的状态对象
    • 解决:后端各自实现,基类提供统一 Bind/Unbind
  3. 绑定方式差异(求同存异)

    • D3D12通过 CommandList->SetPipelineState
    • OpenGLAttachShader + Apply
    • 解决:统一 Bind/Unbind 接口

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 预留空间

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