RHI: Add DescriptorSet abstraction for D3D12 and OpenGL backends

- Add RHIDescriptorSet base class with Update/UpdateSampler/GetNativeHandle
- Add RHIDescriptorPool with AllocateSet/FreeSet methods
- Add SetGraphicsDescriptorSets/SetComputeDescriptorSets to RHICommandList
- Implement D3D12DescriptorSet using descriptor heap allocation
- Implement OpenGLDescriptorSet using TextureUnitAllocator
- Add CreateDescriptorPool/CreateDescriptorSet factory methods to RHIDevice
- Fix unit test SetVertexBuffer -> SetVertexBuffers API
- Add SetVertexBuffer convenience method for D3D12 backward compatibility
- Update CMakeLists.txt with new source files
This commit is contained in:
2026-03-25 00:26:16 +08:00
parent c5c43ae7aa
commit c6fe9547aa
22 changed files with 688 additions and 1 deletions

View File

@@ -67,6 +67,16 @@ public:
void SetPipelineStateInternal(ID3D12PipelineState* pso);
void SetPipelineLayout(D3D12PipelineLayout* layout);
void SetRootSignature(ID3D12RootSignature* signature);
void SetGraphicsDescriptorSets(
uint32_t firstSet,
uint32_t count,
RHIDescriptorSet** descriptorSets,
RHIPipelineLayout* pipelineLayout) override;
void SetComputeDescriptorSets(
uint32_t firstSet,
uint32_t count,
RHIDescriptorSet** descriptorSets,
RHIPipelineLayout* pipelineLayout) override;
void SetViewport(const Viewport& viewport) override;
void SetViewports(uint32_t count, const Viewport* viewports) override;
void SetScissorRect(const Rect& rect) override;
@@ -78,6 +88,7 @@ public:
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 SetVertexBuffer(uint32_t slot, ID3D12Resource* resource, uint64_t offset, uint32_t stride);
void SetIndexBuffer(RHIResourceView* buffer, uint64_t offset) override;
void SetIndexBuffer(ID3D12Resource* buffer, uint64_t offset, Format format);
void SetIndexBufferInternal(ID3D12Resource* buffer, uint64_t offset, Format indexFormat);

View File

@@ -2,6 +2,7 @@
#include <d3d12.h>
#include <wrl/client.h>
#include <vector>
#include "../RHIEnums.h"
#include "../RHITypes.h"
@@ -13,6 +14,8 @@ using Microsoft::WRL::ComPtr;
namespace XCEngine {
namespace RHI {
class D3D12DescriptorSet;
class D3D12DescriptorHeap : public RHIDescriptorPool {
public:
D3D12DescriptorHeap();
@@ -23,6 +26,7 @@ public:
bool Initialize(const DescriptorPoolDesc& desc) override;
ID3D12Device* GetDevice() const { return m_device.Get(); }
ID3D12DescriptorHeap* GetDescriptorHeap() const { return m_descriptorHeap.Get(); }
CPUDescriptorHandle GetCPUDescriptorHandle(uint32_t index);
@@ -38,12 +42,17 @@ public:
static D3D12_DESCRIPTOR_HEAP_DESC CreateDesc(DescriptorHeapType type, uint32_t numDescriptors, bool shaderVisible = false);
RHIDescriptorSet* AllocateSet(const DescriptorSetLayoutDesc& layout) override;
void FreeSet(RHIDescriptorSet* set) override;
private:
ComPtr<ID3D12Device> m_device;
ComPtr<ID3D12DescriptorHeap> m_descriptorHeap;
DescriptorHeapType m_type;
uint32_t m_numDescriptors;
uint32_t m_descriptorSize;
bool m_shaderVisible;
std::vector<D3D12DescriptorSet*> m_allocatedSets;
};
} // namespace RHI

View File

@@ -0,0 +1,45 @@
#pragma once
#include <d3d12.h>
#include <wrl/client.h>
#include "../RHIEnums.h"
#include "../RHITypes.h"
#include "../RHIDescriptorSet.h"
#include "D3D12Common.h"
namespace XCEngine {
namespace RHI {
class D3D12DescriptorHeap;
class D3D12DescriptorSet : public RHIDescriptorSet {
public:
D3D12DescriptorSet();
~D3D12DescriptorSet() override;
bool Initialize(D3D12DescriptorHeap* heap, uint32_t offset, uint32_t count, const DescriptorSetLayoutDesc& layout);
void Shutdown() override;
void Update(uint32_t offset, RHIResourceView* view) override;
void UpdateSampler(uint32_t offset, RHISampler* sampler) override;
void* GetNativeHandle() override;
uint32_t GetBindingCount() const override { return m_bindingCount; }
const DescriptorSetLayoutBinding* GetBindings() const override { return m_bindings; }
D3D12_GPU_DESCRIPTOR_HANDLE GetGPUHandle(uint32_t index = 0) const;
uint32_t GetOffset() const { return m_offset; }
uint32_t GetCount() const { return m_count; }
D3D12DescriptorHeap* GetHeap() const { return m_heap; }
private:
D3D12DescriptorHeap* m_heap;
uint32_t m_offset;
uint32_t m_count;
uint32_t m_bindingCount;
DescriptorSetLayoutBinding* m_bindings;
};
} // namespace RHI
} // namespace XCEngine

View File

@@ -74,6 +74,9 @@ public:
RHIFence* CreateFence(const FenceDesc& desc) override;
RHISampler* CreateSampler(const SamplerDesc& desc) override;
RHIDescriptorPool* CreateDescriptorPool(const DescriptorPoolDesc& desc) override;
RHIDescriptorSet* CreateDescriptorSet(RHIDescriptorPool* pool, const DescriptorSetLayoutDesc& layout) override;
RHIResourceView* CreateRenderTargetView(RHITexture* texture, const ResourceViewDesc& desc) override;
RHIResourceView* CreateDepthStencilView(RHITexture* texture, const ResourceViewDesc& desc) override;
RHIResourceView* CreateShaderResourceView(RHITexture* texture, const ResourceViewDesc& desc) override;

View File

@@ -68,6 +68,16 @@ public:
void SetGlobalTexture(const char* name, RHIResourceView* texture) override;
void SetPipelineState(RHIPipelineState* pipelineState) override;
void SetGraphicsDescriptorSets(
uint32_t firstSet,
uint32_t count,
RHIDescriptorSet** descriptorSets,
RHIPipelineLayout* pipelineLayout) override;
void SetComputeDescriptorSets(
uint32_t firstSet,
uint32_t count,
RHIDescriptorSet** descriptorSets,
RHIPipelineLayout* pipelineLayout) 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;

View File

@@ -0,0 +1,39 @@
#pragma once
#include <vector>
#include <cstdint>
#include "../RHIEnums.h"
#include "../RHIDescriptorPool.h"
namespace XCEngine {
namespace RHI {
class OpenGLTextureUnitAllocator;
class OpenGLDescriptorPool : public RHIDescriptorPool {
public:
OpenGLDescriptorPool();
~OpenGLDescriptorPool() override;
bool Initialize(const DescriptorPoolDesc& desc) override;
void Shutdown() override;
void* GetNativeHandle() override { return this; }
uint32_t GetDescriptorCount() const override { return m_maxSets; }
DescriptorHeapType GetType() const override { return m_type; }
RHIDescriptorSet* AllocateSet(const DescriptorSetLayoutDesc& layout) override;
void FreeSet(RHIDescriptorSet* set) override;
void SetTextureUnitAllocator(OpenGLTextureUnitAllocator* allocator) { m_textureUnitAllocator = allocator; }
private:
DescriptorHeapType m_type;
uint32_t m_maxSets;
std::vector<class OpenGLDescriptorSet*> m_allocatedSets;
class OpenGLTextureUnitAllocator* m_textureUnitAllocator;
};
} // namespace RHI
} // namespace XCEngine

View File

@@ -0,0 +1,50 @@
#pragma once
#include <vector>
#include <cstdint>
#include "../RHIEnums.h"
#include "../RHIDescriptorSet.h"
namespace XCEngine {
namespace RHI {
class OpenGLTextureUnitAllocator;
struct DescriptorBinding {
uint32_t binding;
DescriptorType type;
uint32_t count;
std::vector<uint32_t> textureUnits;
std::vector<uint32_t> textureIds;
std::vector<uint32_t> samplerIds;
};
class OpenGLDescriptorSet : public RHIDescriptorSet {
public:
OpenGLDescriptorSet();
~OpenGLDescriptorSet() override;
bool Initialize(OpenGLTextureUnitAllocator* allocator, uint32_t count, const DescriptorSetLayoutDesc& layout);
void Shutdown() override;
void Update(uint32_t offset, RHIResourceView* view) override;
void UpdateSampler(uint32_t offset, RHISampler* sampler) override;
void* GetNativeHandle() override { return this; }
uint32_t GetBindingCount() const override { return static_cast<uint32_t>(m_bindings.size()); }
const DescriptorSetLayoutBinding* GetBindings() const override { return m_layoutBindings; }
void Bind();
uint32_t GetBindingPoint(uint32_t binding) const;
private:
OpenGLTextureUnitAllocator* m_allocator;
std::vector<DescriptorBinding> m_bindings;
DescriptorSetLayoutBinding* m_layoutBindings;
uint32_t m_bindingCount;
bool m_bound;
};
} // namespace RHI
} // namespace XCEngine

View File

@@ -49,6 +49,9 @@ public:
RHIFence* CreateFence(const FenceDesc& desc) override;
RHISampler* CreateSampler(const SamplerDesc& desc) override;
RHIDescriptorPool* CreateDescriptorPool(const DescriptorPoolDesc& desc) override;
RHIDescriptorSet* CreateDescriptorSet(RHIDescriptorPool* pool, const DescriptorSetLayoutDesc& layout) override;
RHIResourceView* CreateRenderTargetView(RHITexture* texture, const ResourceViewDesc& desc) override;
RHIResourceView* CreateDepthStencilView(RHITexture* texture, const ResourceViewDesc& desc) override;
RHIResourceView* CreateShaderResourceView(RHITexture* texture, const ResourceViewDesc& desc) override;

View File

@@ -4,11 +4,13 @@
#include "RHIEnums.h"
#include "RHIResource.h"
#include "RHIResourceView.h"
#include "RHIDescriptorSet.h"
namespace XCEngine {
namespace RHI {
class RHIPipelineState;
class RHIPipelineLayout;
class RHIShader;
struct DepthStencilState {
@@ -76,6 +78,16 @@ public:
virtual void SetGlobalTexture(const char* name, RHIResourceView* texture) = 0;
virtual void SetPipelineState(RHIPipelineState* pso) = 0;
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;
virtual void SetPrimitiveTopology(PrimitiveTopology topology) = 0;
virtual void SetViewport(const Viewport& viewport) = 0;
virtual void SetViewports(uint32_t count, const Viewport* viewports) = 0;

View File

@@ -6,6 +6,9 @@
namespace XCEngine {
namespace RHI {
class RHIDescriptorSet;
struct DescriptorSetLayoutDesc;
struct DescriptorPoolDesc {
void* device;
DescriptorHeapType type;
@@ -24,6 +27,9 @@ public:
virtual uint32_t GetDescriptorCount() const = 0;
virtual DescriptorHeapType GetType() const = 0;
virtual RHIDescriptorSet* AllocateSet(const DescriptorSetLayoutDesc& layout) = 0;
virtual void FreeSet(RHIDescriptorSet* set) = 0;
};
} // namespace RHI

View File

@@ -0,0 +1,42 @@
#pragma once
#include "RHIEnums.h"
#include "RHITypes.h"
namespace XCEngine {
namespace RHI {
class RHIDescriptorPool;
class RHIResourceView;
class RHISampler;
struct DescriptorSetLayoutBinding {
uint32_t binding;
DescriptorType type;
uint32_t count;
ShaderVisibility visibility = ShaderVisibility::All;
};
struct DescriptorSetLayoutDesc {
DescriptorSetLayoutBinding* bindings = nullptr;
uint32_t bindingCount = 0;
};
class RHIDescriptorSet {
public:
virtual ~RHIDescriptorSet() = default;
virtual void Shutdown() = 0;
virtual void Update(uint32_t offset, RHIResourceView* view) = 0;
virtual void UpdateSampler(uint32_t offset, RHISampler* sampler) = 0;
virtual void* GetNativeHandle() = 0;
virtual uint32_t GetBindingCount() const = 0;
virtual const DescriptorSetLayoutBinding* GetBindings() const = 0;
protected:
RHIDescriptorSet() = default;
};
} // namespace RHI
} // namespace XCEngine

View File

@@ -2,6 +2,8 @@
#include "RHITypes.h"
#include "RHICapabilities.h"
#include "RHIDescriptorPool.h"
#include "RHIDescriptorSet.h"
#include <string>
namespace XCEngine {
@@ -37,6 +39,9 @@ public:
virtual RHIFence* CreateFence(const FenceDesc& desc) = 0;
virtual RHISampler* CreateSampler(const SamplerDesc& desc) = 0;
virtual RHIDescriptorPool* CreateDescriptorPool(const DescriptorPoolDesc& desc) = 0;
virtual RHIDescriptorSet* CreateDescriptorSet(RHIDescriptorPool* pool, const DescriptorSetLayoutDesc& layout) = 0;
virtual RHIResourceView* CreateRenderTargetView(RHITexture* texture, const ResourceViewDesc& desc) = 0;
virtual RHIResourceView* CreateDepthStencilView(RHITexture* texture, const ResourceViewDesc& desc) = 0;
virtual RHIResourceView* CreateShaderResourceView(RHITexture* texture, const ResourceViewDesc& desc) = 0;