RHI: Fix view type signatures in CommandList abstraction
- Unified RHICommandList interface to use RHIResourceView* for all view types - Fixed OpenGLCommandList override signatures (SetVertexBuffers, SetIndexBuffer, etc.) - Fixed D3D12CommandList by removing duplicate SetVertexBuffer methods - Updated OpenGLCommandList.cpp to match new signatures - Build and all 845 tests pass
This commit is contained in:
432
RHI_Design_Issues.md
Normal file
432
RHI_Design_Issues.md
Normal file
@@ -0,0 +1,432 @@
|
||||
# RHI 模块设计问题分析报告(第二版)
|
||||
|
||||
## 1. 项目背景
|
||||
|
||||
本项目 RHI 模块参考 Unity 渲染架构设计,面向 **Direct3D 12** 和 **Vulkan** 等现代图形 API,目标是为引擎上层(SRP/RenderGraph)提供统一的渲染硬件抽象层,屏蔽 API 差异,实现跨后端移植。
|
||||
|
||||
当前已实现两个后端:D3D12 和 OpenGL。基础框架已有雏形(Reset/Close、TransitionBarrier、PipelineState),但存在**被 OpenGL 风格带偏、不符合现代 D3D12/Vulkan 显式设计**的关键问题。
|
||||
|
||||
---
|
||||
|
||||
## 2. 做得好的地方
|
||||
|
||||
1. **有显式生命周期管理**:`Reset()` / `Close()` 是 D3D12/Vulkan 风格,理解"录制-提交"的分离
|
||||
2. **考虑了资源状态转换**:`TransitionBarrier()` 是现代 API 必须的,预留了接口
|
||||
3. **覆盖了图形+计算**:`Draw` / `DrawIndexed` / `Dispatch` 都有,功能完整
|
||||
4. **预留了原生句柄**:`GetNativeHandle()` 方便调试和特殊场景扩展
|
||||
|
||||
---
|
||||
|
||||
## 3. 核心问题(按严重程度排序)
|
||||
|
||||
### 3.1 最大的坑:字符串查找 SetUniform 是 OpenGL 风格
|
||||
|
||||
**问题描述**:当前接口使用字符串名称设置 Uniform/Texture:
|
||||
```cpp
|
||||
virtual void SetUniformInt(const char* name, int value) = 0;
|
||||
virtual void SetGlobalTexture(const char* name, RHIResourceView* texture) = 0;
|
||||
```
|
||||
|
||||
这是**典型的 OpenGL 立即模式风格**,问题极大:
|
||||
|
||||
| 问题 | 说明 |
|
||||
|------|------|
|
||||
| **性能差** | 运行时通过字符串查找 uniform 位置,驱动开销大 |
|
||||
| **无法多线程** | 字符串查找不是线程安全的,不利于多线程录制 CommandList |
|
||||
| **接 Vulkan 不可能** | D3D12/Vulkan 用 **DescriptorSet + PipelineLayout**,根本没有"按名字设 uniform"的概念 |
|
||||
|
||||
**根本原因**:这是 OpenGL 风格的设计,没有对齐 D3D12/Vulkan 的显式 Descriptor 绑定模型。
|
||||
|
||||
**D3D12/Vulkan 正确做法**:
|
||||
```cpp
|
||||
// D3D12: 通过 Root Signature + Descriptor Table 绑定
|
||||
commandList->SetGraphicsRootDescriptorTable(rootIndex, gpuDescriptorHandle);
|
||||
|
||||
// Vulkan: 通过 DescriptorSet 绑定
|
||||
vkCmdBindDescriptorSets(commandBuffer, ..., descriptorSet, ...);
|
||||
```
|
||||
|
||||
**修改建议**:
|
||||
```cpp
|
||||
// 新增:DescriptorSet 绑定接口(替代 SetUniform/SetGlobal)
|
||||
virtual void SetGraphicsDescriptorSets(
|
||||
uint32_t firstSet,
|
||||
uint32_t count,
|
||||
RHIDescriptorSet** descriptorSets,
|
||||
RHIPipelineLayout* pipelineLayout) = 0;
|
||||
|
||||
virtual void SetComputeDescriptorSets(
|
||||
uint32_t firstSet,
|
||||
uint32_t count,
|
||||
RHIDescriptorSet** descriptorSets,
|
||||
RHIPipelineLayout* pipelineLayout) = 0;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.2 缺少显式 RenderPass
|
||||
|
||||
**问题描述**:当前只有 `SetRenderTargets()`,没有 `BeginRenderPass()` / `EndRenderPass()`:
|
||||
|
||||
```cpp
|
||||
// 当前设计
|
||||
virtual void SetRenderTargets(uint32_t count, RHIResourceView** renderTargets, ...) = 0;
|
||||
virtual void ClearRenderTarget(RHIResourceView* renderTarget, const float color[4]) = 0;
|
||||
```
|
||||
|
||||
这是**不符合现代 API 设计**的:
|
||||
|
||||
| 问题 | 说明 |
|
||||
|------|------|
|
||||
| **不符合显式设计** | D3D12/Vulkan 要求显式定义渲染通道的开始和结束 |
|
||||
| **清屏逻辑不规范** | 现代 API 推荐用 RenderPass 的 `LoadOp`(Clear/Load/DontCare)清屏 |
|
||||
| **Tile GPU 性能差** | 对移动端 Tile GPU 至关重要,隐式行为无法优化 |
|
||||
|
||||
**根本原因**:OpenGL 的 `glClear()` 是立即模式,没有 RenderPass 概念。
|
||||
|
||||
**D3D12/Vulkan 正确做法**:
|
||||
```cpp
|
||||
// D3D12: Begin/End Render Pass
|
||||
commandList->BeginRenderPass(...);
|
||||
commandList->EndRenderPass();
|
||||
|
||||
// Vulkan: vkCmdBeginRenderPass / vkCmdEndRenderPass
|
||||
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, ...);
|
||||
vkCmdEndRenderPass(commandBuffer);
|
||||
```
|
||||
|
||||
**修改建议**:
|
||||
```cpp
|
||||
// 新增:显式渲染通道
|
||||
virtual void BeginRenderPass(
|
||||
RHIRenderPass* renderPass,
|
||||
RHIFramebuffer* framebuffer,
|
||||
const Rect& renderArea,
|
||||
uint32_t clearValueCount,
|
||||
const ClearValue* clearValues) = 0;
|
||||
|
||||
virtual void EndRenderPass() = 0;
|
||||
|
||||
// 移除 SetRenderTargets,改由 Framebuffer 定义
|
||||
// 移除或废弃 ClearRenderTarget,改为 BeginRenderPass 的 LoadOp
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.3 动态状态太多,应该收敛到 PipelineState
|
||||
|
||||
**问题描述**:当前把 DepthStencilState、BlendState、PrimitiveTopology 都放在 CommandList 里动态设置:
|
||||
|
||||
```cpp
|
||||
virtual void SetDepthStencilState(const DepthStencilState& state) = 0;
|
||||
virtual void SetBlendState(const BlendState& state) = 0;
|
||||
virtual void SetPrimitiveTopology(PrimitiveTopology topology) = 0;
|
||||
```
|
||||
|
||||
这是**OpenGL 风格的残留**:
|
||||
|
||||
| 问题 | 说明 |
|
||||
|------|------|
|
||||
| **驱动开销大** | 现代 API 中这些状态大部分是 PipelineState 的一部分,是不可变的 |
|
||||
| **不符合显式设计** | 动态状态应该只保留极少数(Viewport/Scissor/StencilRef/BlendFactor) |
|
||||
| **状态不一致风险** | CommandList 动态设置的状态可能与 PSO 中定义的状态冲突 |
|
||||
|
||||
**根本原因**:OpenGL 是状态机,可以在任何时候设置任何状态。D3D12/Vulkan 把大部分状态打包到 PSO 中。
|
||||
|
||||
**D3D12/Vulkan 正确做法**:
|
||||
- `DepthStencilState`、`BlendState`、`PrimitiveTopology` 在 **PSO 创建时就确定**
|
||||
- CommandList 只设置**真正的动态状态**:Viewport、Scissor、StencilRef、BlendFactor
|
||||
|
||||
**修改建议**:
|
||||
```cpp
|
||||
// PipelineState 应该包含:
|
||||
// - Shader
|
||||
// - VertexLayout
|
||||
// - RenderPass 兼容
|
||||
// - DepthStencilState(不可变)
|
||||
// - BlendState(不可变)
|
||||
// - PrimitiveTopology(不可变)
|
||||
// - 动态状态掩码
|
||||
|
||||
// CommandList 只保留必要的动态状态:
|
||||
virtual void SetViewports(uint32_t count, const Viewport* viewports) = 0;
|
||||
virtual void SetScissorRects(uint32_t count, const Rect* rects) = 0;
|
||||
virtual void SetStencilRef(uint8_t ref) = 0;
|
||||
virtual void SetBlendFactor(const float factor[4]) = 0;
|
||||
|
||||
// 移除:
|
||||
virtual void SetDepthStencilState(const DepthStencilState& state) = 0; // 移到 PSO
|
||||
virtual void SetBlendState(const BlendState& state) = 0; // 移到 PSO
|
||||
virtual void SetPrimitiveTopology(PrimitiveTopology topology) = 0; // 移到 PSO
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.4 ResourceView 类型不明确
|
||||
|
||||
**问题描述**:当前用 `RHIResourceView*` 代表所有视图:
|
||||
|
||||
```cpp
|
||||
virtual void SetVertexBuffer(uint32_t slot, RHIResourceView* buffer, ...) = 0;
|
||||
virtual void SetRenderTargets(uint32_t count, RHIResourceView** renderTargets, ...) = 0;
|
||||
```
|
||||
|
||||
这会导致:
|
||||
|
||||
| 问题 | 说明 |
|
||||
|------|------|
|
||||
| **类型不安全** | 容易把 SRV 当成 RTV 传,运行时才发现错误 |
|
||||
| **后端处理麻烦** | D3D12/Vulkan 对不同视图有严格区分(RTV/DSV/SRV/UAV/VBV/IBV) |
|
||||
| **语义模糊** | `RHIResourceView` 到底是哪种视图?调用者必须查文档 |
|
||||
|
||||
**根本原因**:没有在类型层面区分不同视图的语义。
|
||||
|
||||
**修改建议**:定义明确的视图类型层次结构
|
||||
```cpp
|
||||
// 基类
|
||||
class RHIResourceView {};
|
||||
|
||||
// 具体视图类型
|
||||
class RHIRenderTargetView : public RHIResourceView {};
|
||||
class RHIDepthStencilView : public RHIResourceView {};
|
||||
class RHIShaderResourceView : public RHIResourceView {};
|
||||
class RHIUnorderedAccessView : public RHIResourceView {};
|
||||
class RHIVertexBufferView : public RHIResourceView {};
|
||||
class RHIIndexBufferView : public RHIResourceView {};
|
||||
class RHIConstantBufferView : public RHIResourceView {};
|
||||
```
|
||||
|
||||
```cpp
|
||||
// 修改 CommandList 接口
|
||||
virtual void SetVertexBuffers(
|
||||
uint32_t startSlot,
|
||||
uint32_t count,
|
||||
RHIVertexBufferView** buffers,
|
||||
const uint64_t* offsets,
|
||||
const uint32_t* strides) = 0;
|
||||
|
||||
virtual void SetIndexBuffer(
|
||||
RHIIndexBufferView* buffer,
|
||||
uint64_t offset,
|
||||
IndexFormat format) = 0;
|
||||
|
||||
// BeginRenderPass 里用 Framebuffer,Framebuffer 内部包含 RTV/DSV
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.5 TransitionBarrier 针对 View 而非 Resource
|
||||
|
||||
**问题描述**:当前接口:
|
||||
```cpp
|
||||
virtual void TransitionBarrier(RHIResourceView* resource, ResourceStates stateBefore, ResourceStates stateAfter) = 0;
|
||||
```
|
||||
|
||||
资源状态转换是针对 **Resource(Buffer/Texture 本身)** 的,不是针对 View 的。一张 Texture 可能创建多个 View(SRV、RTV、DSV),但状态转换是对整个 Texture 做的。
|
||||
|
||||
**根本原因**:没有区分 Resource 和 ResourceView 的概念。
|
||||
|
||||
**修改建议**:
|
||||
```cpp
|
||||
// 新增 Resource 基类
|
||||
class RHIResource {};
|
||||
class RHIBuffer : public RHIResource {};
|
||||
class RHITexture : public RHIResource {};
|
||||
|
||||
// 修改 TransitionBarrier
|
||||
struct ResourceBarrier {
|
||||
RHIResource* resource;
|
||||
ResourceStates stateBefore;
|
||||
ResourceStates stateAfter;
|
||||
uint32_t subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
};
|
||||
|
||||
virtual void ResourceBarrier(uint32_t count, const ResourceBarrier* barriers) = 0;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 其他需要修改的问题
|
||||
|
||||
### 4.1 SetGlobal* 是空操作
|
||||
|
||||
详见第一版文档,此处不再赘述。
|
||||
|
||||
### 4.2 PrimitiveType 和 PrimitiveTopology 冲突
|
||||
|
||||
详见第一版文档,此处不再赘述。
|
||||
|
||||
### 4.3 OpenGL 特有方法暴露
|
||||
|
||||
详见第一版文档,此处不再赘述。
|
||||
|
||||
### 4.4 缺少 Compute Pipeline 抽象
|
||||
|
||||
详见第一版文档,此处不再赘述。
|
||||
|
||||
### 4.5 RHIPipelineLayout 空壳
|
||||
|
||||
详见第一版文档,此处不再赘述。
|
||||
|
||||
---
|
||||
|
||||
## 5. 修改后的 CommandList 核心接口
|
||||
|
||||
```cpp
|
||||
class RHICommandList {
|
||||
public:
|
||||
virtual ~RHICommandList() = default;
|
||||
|
||||
// ========== 生命周期 ==========
|
||||
virtual void Reset(RHICommandPool* pool = nullptr) = 0;
|
||||
virtual void Close() = 0;
|
||||
|
||||
// ========== 资源状态转换 ==========
|
||||
virtual void ResourceBarrier(uint32_t count, const ResourceBarrier* barriers) = 0;
|
||||
|
||||
// ========== 渲染通道(新增)==========
|
||||
virtual void BeginRenderPass(
|
||||
RHIRenderPass* renderPass,
|
||||
RHIFramebuffer* framebuffer,
|
||||
const Rect& renderArea,
|
||||
uint32_t clearValueCount,
|
||||
const ClearValue* clearValues) = 0;
|
||||
virtual void EndRenderPass() = 0;
|
||||
|
||||
// ========== 管线与描述符 ==========
|
||||
virtual void SetPipelineState(RHIPipelineState* pso) = 0;
|
||||
virtual void SetGraphicsDescriptorSets(
|
||||
uint32_t firstSet,
|
||||
uint32_t count,
|
||||
RHIDescriptorSet** descriptorSets,
|
||||
RHIPipelineLayout* pipelineLayout) = 0;
|
||||
|
||||
// ========== 动态状态(精简后)==========
|
||||
virtual void SetViewports(uint32_t count, const Viewport* viewports) = 0;
|
||||
virtual void SetScissorRects(uint32_t count, const Rect* rects) = 0;
|
||||
virtual void SetStencilRef(uint8_t ref) = 0;
|
||||
virtual void SetBlendFactor(const float factor[4]) = 0;
|
||||
|
||||
// ========== 顶点/索引 ==========
|
||||
virtual void SetVertexBuffers(
|
||||
uint32_t startSlot,
|
||||
uint32_t count,
|
||||
RHIVertexBufferView** buffers,
|
||||
const uint64_t* offsets,
|
||||
const uint32_t* strides) = 0;
|
||||
virtual void SetIndexBuffer(
|
||||
RHIIndexBufferView* buffer,
|
||||
uint64_t offset,
|
||||
IndexFormat 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 SetComputePipelineState(RHIPipelineState* pso) = 0;
|
||||
virtual void SetComputeDescriptorSets(
|
||||
uint32_t firstSet,
|
||||
uint32_t count,
|
||||
RHIDescriptorSet** descriptorSets,
|
||||
RHIPipelineLayout* pipelineLayout) = 0;
|
||||
virtual void Dispatch(uint32_t x, uint32_t y, uint32_t z) = 0;
|
||||
|
||||
// ========== 复制 ==========
|
||||
virtual void CopyResource(RHIResource* dst, RHIResource* src) = 0;
|
||||
|
||||
// ========== 原生句柄 ==========
|
||||
virtual void* GetNativeHandle() = 0;
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 需要同时新增的抽象
|
||||
|
||||
### 6.1 RHIDescriptorSet
|
||||
```cpp
|
||||
class RHIDescriptorSet {
|
||||
public:
|
||||
virtual ~RHIDescriptorSet() = default;
|
||||
virtual void Update(uint32_t offset, RHIResourceView* view) = 0;
|
||||
virtual void UpdateSampler(uint32_t offset, RHISampler* sampler) = 0;
|
||||
virtual void* GetNativeHandle() = 0;
|
||||
};
|
||||
```
|
||||
|
||||
### 6.2 RHIRenderPass
|
||||
```cpp
|
||||
struct AttachmentDesc {
|
||||
Format format;
|
||||
LoadAction loadOp = LoadAction::DontCare;
|
||||
StoreAction storeOp = StoreAction::Store;
|
||||
LoadAction stencilLoadOp = LoadAction::DontCare;
|
||||
StoreAction stencilStoreOp = StoreAction::DontCare;
|
||||
};
|
||||
|
||||
class RHIRenderPass {
|
||||
public:
|
||||
virtual ~RHIRenderPass() = default;
|
||||
virtual bool Initialize(uint32_t colorAttachmentCount, const AttachmentDesc* colorAttachments,
|
||||
const AttachmentDesc* depthStencilAttachment) = 0;
|
||||
virtual void Shutdown() = 0;
|
||||
virtual void* GetNativeHandle() = 0;
|
||||
};
|
||||
```
|
||||
|
||||
### 6.3 RHIFramebuffer
|
||||
```cpp
|
||||
class RHIFramebuffer {
|
||||
public:
|
||||
virtual ~RHIFramebuffer() = default;
|
||||
virtual bool Initialize(RHIRenderPass* renderPass, uint32_t attachmentCount,
|
||||
RHIResourceView** attachments, uint32_t width, uint32_t height) = 0;
|
||||
virtual void Shutdown() = 0;
|
||||
virtual void* GetNativeHandle() = 0;
|
||||
};
|
||||
```
|
||||
|
||||
### 6.4 RHIResource 基类
|
||||
```cpp
|
||||
class RHIResource {
|
||||
public:
|
||||
virtual ~RHIResource() = default;
|
||||
virtual void* GetNativeHandle() = 0;
|
||||
virtual ResourceStates GetState() const = 0;
|
||||
virtual void SetState(ResourceStates state) = 0;
|
||||
};
|
||||
|
||||
class RHIBuffer : public RHIResource { ... };
|
||||
class RHITexture : public RHIResource { ... };
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 问题优先级总结
|
||||
|
||||
| 优先级 | 问题 | 严重性 | 修复难度 |
|
||||
|--------|------|--------|----------|
|
||||
| 1 | 字符串查找 SetUniform 不符合 D3D12/Vulkan | 🔴 致命 | 高 |
|
||||
| 2 | 缺少显式 RenderPass | 🔴 致命 | 高 |
|
||||
| 3 | 动态状态太多 | 🔴 高 | 高 |
|
||||
| 4 | ResourceView 类型不明确 | 🟡 中 | 中 |
|
||||
| 5 | TransitionBarrier 针对 View 而非 Resource | 🟡 中 | 中 |
|
||||
| 6 | SetGlobal* 空操作 | 🟡 中 | 低 |
|
||||
| 7 | OpenGL 特有方法暴露 | 🟡 中 | 高 |
|
||||
| 8 | 缺少 Compute Pipeline 抽象 | 🟡 中 | 中 |
|
||||
|
||||
---
|
||||
|
||||
## 8. 总结
|
||||
|
||||
当前 RHI 模块的基础框架有 D3D12/Vulkan 的影子,但**被 OpenGL 风格带偏**了。最核心的问题是:
|
||||
|
||||
1. **用字符串查找设 uniform** —— 这是 OpenGL 风格,必须改成 DescriptorSet 绑定
|
||||
2. **缺少显式 RenderPass** —— 现代 API 的基础,必须添加
|
||||
3. **动态状态太多** —— 应该收敛到 PSO,只保留必要的动态状态
|
||||
|
||||
修复这些问题后,RHI 抽象层将完全对齐 D3D12/Vulkan 的显式模型,未来接入 Vulkan 将会非常顺利。
|
||||
@@ -70,9 +70,6 @@ public:
|
||||
void SetRenderTargetsInternal(uint32_t count, ID3D12Resource** renderTargets, ID3D12Resource* depthStencil = nullptr);
|
||||
void SetRenderTargetsHandle(uint32_t count, const D3D12_CPU_DESCRIPTOR_HANDLE* renderTargetHandles, const D3D12_CPU_DESCRIPTOR_HANDLE* depthStencilHandle = nullptr);
|
||||
|
||||
void SetVertexBuffer(uint32_t slot, RHIResourceView* buffer, uint64_t offset) override;
|
||||
void SetVertexBuffer(uint32_t slot, ID3D12Resource* buffer, uint64_t offset, uint32_t stride);
|
||||
void SetVertexBufferInternal(uint32_t slot, ID3D12Resource* buffer, uint64_t offset, uint32_t stride);
|
||||
void SetVertexBuffers(uint32_t startSlot, uint32_t count, RHIResourceView** buffers, const uint64_t* offsets, const uint32_t* strides) override;
|
||||
void SetVertexBuffersInternal(uint32_t startSlot, uint32_t count, const D3D12_VERTEX_BUFFER_VIEW* views);
|
||||
void SetIndexBuffer(RHIResourceView* buffer, uint64_t offset) override;
|
||||
|
||||
@@ -68,7 +68,6 @@ public:
|
||||
void SetGlobalTexture(const char* name, RHIResourceView* texture) override;
|
||||
|
||||
void SetPipelineState(RHIPipelineState* pipelineState) override;
|
||||
void SetVertexBuffer(uint32_t slot, RHIResourceView* buffer, uint64_t offset) override;
|
||||
void SetVertexBuffers(uint32_t startSlot, uint32_t count, RHIResourceView** buffers, const uint64_t* offsets, const uint32_t* strides) override;
|
||||
void SetIndexBuffer(RHIResourceView* buffer, uint64_t offset) override;
|
||||
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
|
||||
#include "RHITypes.h"
|
||||
#include "RHIEnums.h"
|
||||
#include "RHIResource.h"
|
||||
#include <string>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace RHI {
|
||||
|
||||
class RHIBuffer {
|
||||
class RHIBuffer : public RHIResource {
|
||||
public:
|
||||
virtual ~RHIBuffer() = default;
|
||||
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
|
||||
#include "RHITypes.h"
|
||||
#include "RHIEnums.h"
|
||||
#include "RHIResource.h"
|
||||
#include "RHIResourceView.h"
|
||||
|
||||
namespace XCEngine {
|
||||
namespace RHI {
|
||||
|
||||
class RHIResourceView;
|
||||
class RHIPipelineState;
|
||||
class RHIShader;
|
||||
|
||||
@@ -83,7 +84,6 @@ public:
|
||||
virtual void SetBlendState(const BlendState& state) = 0;
|
||||
virtual void SetBlendFactor(const float factor[4]) = 0;
|
||||
|
||||
virtual void SetVertexBuffer(uint32_t slot, RHIResourceView* buffer, uint64_t offset) = 0;
|
||||
virtual void SetVertexBuffers(uint32_t startSlot, uint32_t count, RHIResourceView** buffers, const uint64_t* offsets, const uint32_t* strides) = 0;
|
||||
virtual void SetIndexBuffer(RHIResourceView* buffer, uint64_t offset) = 0;
|
||||
|
||||
|
||||
19
engine/include/XCEngine/RHI/RHIResource.h
Normal file
19
engine/include/XCEngine/RHI/RHIResource.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "RHITypes.h"
|
||||
#include "RHIEnums.h"
|
||||
|
||||
namespace XCEngine {
|
||||
namespace RHI {
|
||||
|
||||
class RHIResource {
|
||||
public:
|
||||
virtual ~RHIResource() = default;
|
||||
|
||||
virtual void* GetNativeHandle() = 0;
|
||||
virtual ResourceStates GetState() const = 0;
|
||||
virtual void SetState(ResourceStates state) = 0;
|
||||
};
|
||||
|
||||
} // namespace RHI
|
||||
} // namespace XCEngine
|
||||
@@ -21,5 +21,51 @@ public:
|
||||
virtual Format GetFormat() const = 0;
|
||||
};
|
||||
|
||||
class RHIVertexBufferView : public RHIResourceView {
|
||||
public:
|
||||
virtual ~RHIVertexBufferView() = default;
|
||||
|
||||
virtual uint64_t GetBufferAddress() const = 0;
|
||||
virtual uint32_t GetSize() const = 0;
|
||||
virtual uint32_t GetStride() const = 0;
|
||||
};
|
||||
|
||||
class RHIIndexBufferView : public RHIResourceView {
|
||||
public:
|
||||
virtual ~RHIIndexBufferView() = default;
|
||||
|
||||
virtual uint64_t GetBufferAddress() const = 0;
|
||||
virtual uint32_t GetSize() const = 0;
|
||||
virtual Format GetIndexFormat() const = 0;
|
||||
};
|
||||
|
||||
class RHIRenderTargetView : public RHIResourceView {
|
||||
public:
|
||||
virtual ~RHIRenderTargetView() = default;
|
||||
};
|
||||
|
||||
class RHIDepthStencilView : public RHIResourceView {
|
||||
public:
|
||||
virtual ~RHIDepthStencilView() = default;
|
||||
};
|
||||
|
||||
class RHIShaderResourceView : public RHIResourceView {
|
||||
public:
|
||||
virtual ~RHIShaderResourceView() = default;
|
||||
};
|
||||
|
||||
class RHIUnorderedAccessView : public RHIResourceView {
|
||||
public:
|
||||
virtual ~RHIUnorderedAccessView() = default;
|
||||
};
|
||||
|
||||
class RHIConstantBufferView : public RHIResourceView {
|
||||
public:
|
||||
virtual ~RHIConstantBufferView() = default;
|
||||
|
||||
virtual uint64_t GetBufferAddress() const = 0;
|
||||
virtual uint32_t GetSize() const = 0;
|
||||
};
|
||||
|
||||
} // namespace RHI
|
||||
} // namespace XCEngine
|
||||
@@ -2,12 +2,13 @@
|
||||
|
||||
#include "RHITypes.h"
|
||||
#include "RHIEnums.h"
|
||||
#include "RHIResource.h"
|
||||
#include <string>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace RHI {
|
||||
|
||||
class RHITexture {
|
||||
class RHITexture : public RHIResource {
|
||||
public:
|
||||
virtual ~RHITexture() = default;
|
||||
|
||||
|
||||
@@ -369,29 +369,6 @@ void D3D12CommandList::SetRenderTargetsHandle(uint32_t count, const D3D12_CPU_DE
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12CommandList::SetVertexBuffer(uint32_t slot, RHIResourceView* buffer, uint64_t offset) {
|
||||
if (!buffer || !buffer->IsValid()) return;
|
||||
D3D12ResourceView* view = static_cast<D3D12ResourceView*>(buffer);
|
||||
D3D12_VERTEX_BUFFER_VIEW vbView = {};
|
||||
vbView.BufferLocation = view->GetResource()->GetGPUVirtualAddress() + offset;
|
||||
vbView.SizeInBytes = static_cast<UINT>(view->GetResource()->GetDesc().Width) - static_cast<UINT>(offset);
|
||||
vbView.StrideInBytes = 0;
|
||||
m_commandList->IASetVertexBuffers(slot, 1, &vbView);
|
||||
}
|
||||
|
||||
void D3D12CommandList::SetVertexBuffer(uint32_t slot, ID3D12Resource* buffer, uint64_t offset, uint32_t stride) {
|
||||
SetVertexBufferInternal(slot, buffer, offset, stride);
|
||||
}
|
||||
|
||||
void D3D12CommandList::SetVertexBufferInternal(uint32_t slot, ID3D12Resource* buffer, uint64_t offset, uint32_t stride) {
|
||||
D3D12_VERTEX_BUFFER_VIEW view = {};
|
||||
view.BufferLocation = buffer->GetGPUVirtualAddress() + offset;
|
||||
view.SizeInBytes = static_cast<UINT>(buffer->GetDesc().Width) - static_cast<UINT>(offset);
|
||||
view.StrideInBytes = stride;
|
||||
|
||||
m_commandList->IASetVertexBuffers(slot, 1, &view);
|
||||
}
|
||||
|
||||
void D3D12CommandList::SetVertexBuffers(uint32_t startSlot, uint32_t count, RHIResourceView** buffers, const uint64_t* offsets, const uint32_t* strides) {
|
||||
std::vector<D3D12_VERTEX_BUFFER_VIEW> views(count);
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
|
||||
@@ -609,17 +609,6 @@ void OpenGLCommandList::SetPipelineState(RHIPipelineState* pipelineState) {
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLCommandList::SetVertexBuffer(uint32_t slot, RHIResourceView* buffer, uint64_t offset) {
|
||||
if (!buffer) return;
|
||||
OpenGLResourceView* view = static_cast<OpenGLResourceView*>(buffer);
|
||||
if (!view->IsValid()) return;
|
||||
|
||||
GLuint glBuffer = view->GetBuffer();
|
||||
glBindBuffer(GL_ARRAY_BUFFER, glBuffer);
|
||||
glVertexAttribPointer(slot, 4, GL_FLOAT, GL_FALSE, 0, reinterpret_cast<void*>(static_cast<uintptr_t>(offset)));
|
||||
glEnableVertexAttribArray(slot);
|
||||
}
|
||||
|
||||
void OpenGLCommandList::SetVertexBuffers(uint32_t startSlot, uint32_t count, RHIResourceView** buffers, const uint64_t* offsets, const uint32_t* strides) {
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
if (!buffers[i]) continue;
|
||||
|
||||
Reference in New Issue
Block a user