Refactor RHI ResourceView abstraction layer for unified cross-platform interface

- Create unified RHIResourceView base interface with type-specific Initialize methods
- Implement D3D12ResourceView with RTV/DSV/SRV/UAV/CBV support
- Implement OpenGL ResourceView simulation layer using FBO, texture units, and UBO
- Add OpenGLTextureUnitAllocator for managing texture unit bindings
- Add OpenGLUniformBufferManager for UBO binding points
- Add OpenGLFramebuffer for FBO management
- Remove deprecated D3D12 view classes (RenderTargetView, DepthStencilView, etc.)
- Fix ExecuteCommandLists type confusion bug by adding GetNativeHandle to RHICommandList
- Fix test bug where Close() was called before ExecuteCommandLists
- Update all integration tests to use new D3D12ResourceView class
- All tests pass: 144 unit tests + 8 integration tests
This commit is contained in:
2026-03-24 03:49:13 +08:00
parent 86b6d6b042
commit 0a3fe842b9
32 changed files with 1288 additions and 233 deletions

View File

@@ -99,6 +99,8 @@ public:
void DispatchIndirect(void* argBuffer, uint64_t alignedByteOffset);
void DispatchIndirectInternal(ID3D12Resource* argBuffer, uint64_t alignedByteOffset);
void* GetNativeHandle() override { return GetCommandList(); }
void ExecuteBundle(ID3D12GraphicsCommandList* bundle);
ResourceStates GetResourceState(ID3D12Resource* resource) const;

View File

@@ -1,27 +0,0 @@
#pragma once
#include <d3d12.h>
#include <wrl/client.h>
using Microsoft::WRL::ComPtr;
namespace XCEngine {
namespace RHI {
class D3D12ConstantBufferView {
public:
D3D12ConstantBufferView();
~D3D12ConstantBufferView();
void Initialize(ID3D12Device* device, ID3D12Resource* buffer, const D3D12_CONSTANT_BUFFER_VIEW_DESC* desc = nullptr);
void Shutdown();
D3D12_CPU_DESCRIPTOR_HANDLE GetCPUDescriptorHandle() const { return m_handle; }
private:
D3D12_CPU_DESCRIPTOR_HANDLE m_handle;
ID3D12Resource* m_resource;
};
} // namespace RHI
} // namespace XCEngine

View File

@@ -1,33 +0,0 @@
#pragma once
#include <d3d12.h>
#include <wrl/client.h>
#include "../RHIEnums.h"
#include "D3D12Enums.h"
using Microsoft::WRL::ComPtr;
namespace XCEngine {
namespace RHI {
class D3D12DepthStencilView {
public:
D3D12DepthStencilView();
~D3D12DepthStencilView();
void Initialize(ID3D12Device* device, ID3D12Resource* resource, const D3D12_DEPTH_STENCIL_VIEW_DESC* desc = nullptr);
void InitializeAt(ID3D12Device* device, ID3D12Resource* resource, D3D12_CPU_DESCRIPTOR_HANDLE handle, const D3D12_DEPTH_STENCIL_VIEW_DESC* desc = nullptr);
void Shutdown();
D3D12_CPU_DESCRIPTOR_HANDLE GetCPUDescriptorHandle() const { return m_handle; }
static D3D12_DEPTH_STENCIL_VIEW_DESC CreateDesc(Format format, D3D12_DSV_DIMENSION dimension = D3D12_DSV_DIMENSION_TEXTURE2D);
private:
D3D12_CPU_DESCRIPTOR_HANDLE m_handle;
ID3D12Resource* m_resource;
};
} // namespace RHI
} // namespace XCEngine

View File

@@ -29,11 +29,7 @@ class D3D12Texture;
class D3D12Buffer;
class D3D12SwapChain;
class D3D12Shader;
class D3D12RenderTargetView;
class D3D12DepthStencilView;
class D3D12ShaderResourceView;
class D3D12UnorderedAccessView;
class D3D12ConstantBufferView;
class D3D12ResourceView;
struct AdapterInfo {
std::wstring description;
@@ -76,6 +72,11 @@ public:
RHIFence* CreateFence(const FenceDesc& desc) override;
RHISampler* CreateSampler(const SamplerDesc& desc) 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;
RHIResourceView* CreateUnorderedAccessView(RHITexture* texture, const ResourceViewDesc& desc) override;
const RHICapabilities& GetCapabilities() const override;
const RHIDeviceInfo& GetDeviceInfo() const override;
@@ -89,12 +90,6 @@ public:
D3D12QueryHeap* CreateQueryHeap(const QueryHeapDesc& desc);
D3D12RootSignature* CreateRootSignature(const RootSignatureDesc& desc);
D3D12RenderTargetView* CreateRenderTargetView(D3D12Buffer* resource, const RenderTargetViewDesc& desc);
D3D12DepthStencilView* CreateDepthStencilView(D3D12Buffer* resource, const DepthStencilViewDesc& desc);
D3D12ShaderResourceView* CreateShaderResourceView(D3D12Buffer* resource, const ShaderResourceViewDesc& desc);
D3D12UnorderedAccessView* CreateUnorderedAccessView(D3D12Buffer* resource, const UnorderedAccessViewDesc& desc);
D3D12ConstantBufferView* CreateConstantBufferView(D3D12Buffer* resource, const ConstantBufferViewDesc& desc);
private:
bool CreateDXGIFactory(bool enableDebugLayer);
bool CreateDevice(IDXGIAdapter1* adapter);

View File

@@ -1,33 +0,0 @@
#pragma once
#include <d3d12.h>
#include <wrl/client.h>
#include "../RHIEnums.h"
#include "D3D12Enums.h"
using Microsoft::WRL::ComPtr;
namespace XCEngine {
namespace RHI {
class D3D12RenderTargetView {
public:
D3D12RenderTargetView();
~D3D12RenderTargetView();
void Initialize(ID3D12Device* device, ID3D12Resource* resource, const D3D12_RENDER_TARGET_VIEW_DESC* desc = nullptr);
void InitializeAt(ID3D12Device* device, ID3D12Resource* resource, D3D12_CPU_DESCRIPTOR_HANDLE handle, const D3D12_RENDER_TARGET_VIEW_DESC* desc = nullptr);
void Shutdown();
D3D12_CPU_DESCRIPTOR_HANDLE GetCPUDescriptorHandle() const { return m_handle; }
static D3D12_RENDER_TARGET_VIEW_DESC CreateDesc(Format format, D3D12_RTV_DIMENSION dimension = D3D12_RTV_DIMENSION_TEXTURE2D);
private:
D3D12_CPU_DESCRIPTOR_HANDLE m_handle;
ID3D12Resource* m_resource;
};
} // namespace RHI
} // namespace XCEngine

View File

@@ -0,0 +1,65 @@
#pragma once
#include <d3d12.h>
#include <wrl/client.h>
#include "../RHIResourceView.h"
#include "../RHIEnums.h"
#include "D3D12Enums.h"
using Microsoft::WRL::ComPtr;
namespace XCEngine {
namespace RHI {
class D3D12DescriptorHeap;
class D3D12ResourceView : public RHIResourceView {
public:
D3D12ResourceView();
~D3D12ResourceView() override;
void Shutdown() override;
void* GetNativeHandle() override;
bool IsValid() const override;
void SetViewType(ResourceViewType type) { m_viewType = type; }
ResourceViewType GetViewType() const { return m_viewType; }
void InitializeAsRenderTarget(ID3D12Device* device, ID3D12Resource* resource,
const D3D12_RENDER_TARGET_VIEW_DESC* desc,
D3D12DescriptorHeap* heap, uint32_t slotIndex);
void InitializeAsDepthStencil(ID3D12Device* device, ID3D12Resource* resource,
const D3D12_DEPTH_STENCIL_VIEW_DESC* desc,
D3D12DescriptorHeap* heap, uint32_t slotIndex);
void InitializeAsShaderResource(ID3D12Device* device, ID3D12Resource* resource,
const D3D12_SHADER_RESOURCE_VIEW_DESC* desc,
D3D12DescriptorHeap* heap, uint32_t slotIndex);
void InitializeAsUnorderedAccess(ID3D12Device* device, ID3D12Resource* resource,
const D3D12_UNORDERED_ACCESS_VIEW_DESC* desc,
D3D12DescriptorHeap* heap, uint32_t slotIndex);
void InitializeAsConstantBuffer(ID3D12Device* device, ID3D12Resource* resource,
const D3D12_CONSTANT_BUFFER_VIEW_DESC* desc,
D3D12DescriptorHeap* heap, uint32_t slotIndex);
D3D12_CPU_DESCRIPTOR_HANDLE GetCPUHandle() const { return m_handle; }
GPUDescriptorHandle GetGPUHandle() const;
ID3D12Resource* GetResource() const { return m_resource; }
D3D12DescriptorHeap* GetHeap() const { return m_heap; }
uint32_t GetSlotIndex() const { return m_slotIndex; }
static D3D12_RENDER_TARGET_VIEW_DESC CreateRenderTargetDesc(Format format, D3D12_RTV_DIMENSION dimension);
static D3D12_DEPTH_STENCIL_VIEW_DESC CreateDepthStencilDesc(Format format, D3D12_DSV_DIMENSION dimension);
static D3D12_SHADER_RESOURCE_VIEW_DESC CreateShaderResourceDesc(Format format, D3D12_SRV_DIMENSION dimension, uint32_t mipLevels = 0);
static D3D12_UNORDERED_ACCESS_VIEW_DESC CreateUnorderedAccessDesc(Format format, D3D12_UAV_DIMENSION dimension);
private:
ResourceViewType m_viewType;
D3D12_CPU_DESCRIPTOR_HANDLE m_handle;
ID3D12Resource* m_resource;
D3D12DescriptorHeap* m_heap;
uint32_t m_slotIndex;
};
} // namespace RHI
} // namespace XCEngine

View File

@@ -1,33 +0,0 @@
#pragma once
#include <d3d12.h>
#include <wrl/client.h>
#include "../RHIEnums.h"
#include "D3D12Enums.h"
using Microsoft::WRL::ComPtr;
namespace XCEngine {
namespace RHI {
class D3D12ShaderResourceView {
public:
D3D12ShaderResourceView();
~D3D12ShaderResourceView();
void Initialize(ID3D12Device* device, ID3D12Resource* resource, const D3D12_SHADER_RESOURCE_VIEW_DESC* desc = nullptr);
void InitializeAt(ID3D12Device* device, ID3D12Resource* resource, D3D12_CPU_DESCRIPTOR_HANDLE handle, const D3D12_SHADER_RESOURCE_VIEW_DESC* desc = nullptr);
void Shutdown();
D3D12_CPU_DESCRIPTOR_HANDLE GetCPUDescriptorHandle() const { return m_handle; }
static D3D12_SHADER_RESOURCE_VIEW_DESC CreateDesc(Format format, D3D12_SRV_DIMENSION dimension = D3D12_SRV_DIMENSION_TEXTURE2D, uint32_t mipLevels = 1);
private:
D3D12_CPU_DESCRIPTOR_HANDLE m_handle;
ID3D12Resource* m_resource;
};
} // namespace RHI
} // namespace XCEngine

View File

@@ -1,27 +0,0 @@
#pragma once
#include <d3d12.h>
#include <wrl/client.h>
using Microsoft::WRL::ComPtr;
namespace XCEngine {
namespace RHI {
class D3D12UnorderedAccessView {
public:
D3D12UnorderedAccessView();
~D3D12UnorderedAccessView();
void Initialize(ID3D12Device* device, ID3D12Resource* resource, const D3D12_UNORDERED_ACCESS_VIEW_DESC* desc = nullptr);
void Shutdown();
D3D12_CPU_DESCRIPTOR_HANDLE GetCPUDescriptorHandle() const { return m_handle; }
private:
D3D12_CPU_DESCRIPTOR_HANDLE m_handle;
ID3D12Resource* m_resource;
};
} // namespace RHI
} // namespace XCEngine

View File

@@ -1,6 +1,7 @@
#pragma once
#include <string>
#include <memory>
#include <Windows.h>
#include "../RHIDevice.h"
@@ -16,6 +17,8 @@ using HWND = HWND__*;
using HGLRC = HGLRC__*;
class OpenGLSwapChain;
class OpenGLTextureUnitAllocator;
class OpenGLUniformBufferManager;
class OpenGLDevice : public RHIDevice {
public:
@@ -32,6 +35,9 @@ public:
HGLRC GetGLContext() const { return m_hglrc; }
const RHIDeviceInfo& GetDeviceInfoImpl() const { return m_deviceInfo; }
OpenGLTextureUnitAllocator* GetTextureUnitAllocator() { return m_textureUnitAllocator.get(); }
OpenGLUniformBufferManager* GetUniformBufferManager() { return m_uniformBufferManager.get(); }
void SwapBuffers();
bool PollEvents();
void SetShouldClose(bool shouldClose);
@@ -47,6 +53,11 @@ public:
RHIFence* CreateFence(const FenceDesc& desc) override;
RHISampler* CreateSampler(const SamplerDesc& desc) 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;
RHIResourceView* CreateUnorderedAccessView(RHITexture* texture, const ResourceViewDesc& desc) override;
const RHICapabilities& GetCapabilities() const override;
const RHIDeviceInfo& GetDeviceInfo() const override;
@@ -64,6 +75,9 @@ private:
bool m_initialized = false;
bool m_ownsWindow = false;
bool m_shouldClose = false;
std::unique_ptr<OpenGLTextureUnitAllocator> m_textureUnitAllocator;
std::unique_ptr<OpenGLUniformBufferManager> m_uniformBufferManager;
};
} // namespace RHI

View File

@@ -0,0 +1,66 @@
#pragma once
#include <cstdint>
#include <vector>
namespace XCEngine {
namespace RHI {
enum class FramebufferAttachmentType {
Color,
Depth,
DepthStencil,
Stencil
};
struct FramebufferAttachment {
unsigned int texture = 0;
int mipLevel = 0;
int layer = 0;
FramebufferAttachmentType type = FramebufferAttachmentType::Color;
uint32_t format = 0;
};
struct FramebufferDesc {
int width = 0;
int height = 0;
int samples = 1;
std::vector<FramebufferAttachment> colorAttachments;
FramebufferAttachment depthAttachment;
FramebufferAttachment stencilAttachment;
};
class OpenGLFramebuffer {
public:
OpenGLFramebuffer();
~OpenGLFramebuffer();
bool Initialize(const FramebufferDesc& desc);
void Shutdown();
void Bind();
void Unbind();
void ClearColor(int attachmentIndex, float r, float g, float b, float a);
void ClearDepth(float depth);
void ClearStencil(uint8_t stencil);
void ClearDepthStencil(float depth, uint8_t stencil);
unsigned int GetFramebuffer() const { return m_framebuffer; }
int GetWidth() const { return m_width; }
int GetHeight() const { return m_height; }
bool IsValid() const { return m_framebuffer != 0; }
static void BindFramebuffer(unsigned int framebuffer);
static void UnbindFramebuffer();
private:
unsigned int m_framebuffer;
int m_width;
int m_height;
int m_samples;
FramebufferDesc m_desc;
};
} // namespace RHI
} // namespace XCEngine

View File

@@ -0,0 +1,69 @@
#pragma once
#include "XCEngine/RHI/RHIResourceView.h"
#include "XCEngine/RHI/RHITypes.h"
namespace XCEngine {
namespace RHI {
class OpenGLTexture;
class OpenGLBuffer;
class OpenGLFramebuffer;
class OpenGLTextureUnitAllocator;
class OpenGLUniformBufferManager;
class OpenGLResourceView : public RHIResourceView {
public:
OpenGLResourceView();
~OpenGLResourceView() override;
void Shutdown() override;
void* GetNativeHandle() override;
bool IsValid() const override;
bool InitializeAsRenderTarget(
OpenGLTexture* texture,
const ResourceViewDesc& desc,
OpenGLFramebuffer* framebuffer);
bool InitializeAsDepthStencil(
OpenGLTexture* texture,
const ResourceViewDesc& desc,
OpenGLFramebuffer* framebuffer);
bool InitializeAsShaderResource(
OpenGLTexture* texture,
const ResourceViewDesc& desc,
OpenGLTextureUnitAllocator* allocator);
bool InitializeAsUnorderedAccess(
OpenGLTexture* texture,
const ResourceViewDesc& desc,
OpenGLTextureUnitAllocator* allocator);
bool InitializeAsConstantBuffer(
OpenGLBuffer* buffer,
const ResourceViewDesc& desc,
OpenGLUniformBufferManager* manager);
ResourceViewType GetViewType() const { return m_viewType; }
unsigned int GetFramebuffer() const;
int32_t GetTextureUnit() const { return m_textureUnit; }
int32_t GetBindingPoint() const { return m_bindingPoint; }
unsigned int GetTexture() const;
unsigned int GetBuffer() const;
private:
ResourceViewType m_viewType;
unsigned int m_framebufferID;
int32_t m_textureUnit;
int32_t m_bindingPoint;
OpenGLTexture* m_texture;
OpenGLBuffer* m_buffer;
OpenGLFramebuffer* m_framebuffer;
OpenGLTextureUnitAllocator* m_textureUnitAllocator;
OpenGLUniformBufferManager* m_uniformBufferManager;
};
} // namespace RHI
} // namespace XCEngine

View File

@@ -0,0 +1,36 @@
#pragma once
#include <vector>
#include <cstdint>
namespace XCEngine {
namespace RHI {
class OpenGLTexture;
class OpenGLTextureUnitAllocator {
public:
OpenGLTextureUnitAllocator();
~OpenGLTextureUnitAllocator();
void Initialize(uint32_t maxUnits = 16);
void Shutdown();
int32_t Allocate();
void Free(int32_t unit);
void BindTexture(int32_t unit, OpenGLTexture* texture);
void UnbindTexture(int32_t unit);
OpenGLTexture* GetBoundTexture(int32_t unit) const;
bool IsAllocated(int32_t unit) const;
uint32_t GetMaxUnits() const { return m_maxUnits; }
private:
uint32_t m_maxUnits;
std::vector<bool> m_allocated;
std::vector<OpenGLTexture*> m_boundTextures;
};
} // namespace RHI
} // namespace XCEngine

View File

@@ -0,0 +1,36 @@
#pragma once
#include <vector>
#include <cstdint>
namespace XCEngine {
namespace RHI {
class OpenGLBuffer;
class OpenGLUniformBufferManager {
public:
OpenGLUniformBufferManager();
~OpenGLUniformBufferManager();
void Initialize(uint32_t maxBindingPoints = 16);
void Shutdown();
int32_t Allocate();
void Free(int32_t bindingPoint);
void BindBuffer(int32_t bindingPoint, OpenGLBuffer* buffer, uint32_t offset = 0, uint32_t size = 0);
void UnbindBuffer(int32_t bindingPoint);
OpenGLBuffer* GetBoundBuffer(int32_t bindingPoint) const;
bool IsAllocated(int32_t bindingPoint) const;
uint32_t GetMaxBindingPoints() const { return m_maxBindingPoints; }
private:
uint32_t m_maxBindingPoints;
std::vector<bool> m_allocated;
std::vector<OpenGLBuffer*> m_boundBuffers;
};
} // namespace RHI
} // namespace XCEngine

View File

@@ -78,6 +78,8 @@ public:
virtual void CopyResource(void* dst, void* src) = 0;
virtual void Dispatch(uint32_t x, uint32_t y, uint32_t z) = 0;
virtual void* GetNativeHandle() { return nullptr; }
};
} // namespace RHI

View File

@@ -16,6 +16,7 @@ class RHIShader;
class RHIPipelineState;
class RHIFence;
class RHISampler;
class RHIResourceView;
class RHIDevice {
public:
@@ -34,6 +35,11 @@ public:
virtual RHIFence* CreateFence(const FenceDesc& desc) = 0;
virtual RHISampler* CreateSampler(const SamplerDesc& desc) = 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;
virtual RHIResourceView* CreateUnorderedAccessView(RHITexture* texture, const ResourceViewDesc& desc) = 0;
virtual const RHICapabilities& GetCapabilities() const = 0;
virtual const RHIDeviceInfo& GetDeviceInfo() const = 0;

View File

@@ -241,6 +241,31 @@ enum class DescriptorHeapType : uint8_t {
DSV
};
enum class ResourceViewDimension : uint8_t {
Unknown,
Texture1D,
Texture1DArray,
Texture2D,
Texture2DArray,
Texture2DMS,
Texture2DMSArray,
Texture3D,
TextureCube,
TextureCubeArray,
Buffer,
StructuredBuffer,
RawBuffer
};
enum class ResourceViewType : uint8_t {
RenderTarget,
DepthStencil,
ShaderResource,
UnorderedAccess,
ConstantBuffer,
Sampler
};
enum class QueryType : uint8_t {
Occlusion,
Timestamp,

View File

@@ -0,0 +1,21 @@
#pragma once
#include "RHIEnums.h"
#include "RHITypes.h"
namespace XCEngine {
namespace RHI {
class RHIResourceView {
public:
virtual ~RHIResourceView() = default;
virtual void Shutdown() = 0;
virtual void* GetNativeHandle() = 0;
virtual bool IsValid() const = 0;
};
} // namespace RHI
} // namespace XCEngine

View File

@@ -1,5 +1,7 @@
#pragma once
#include "RHIEnums.h"
#include <cstdint>
#include <string>
#include <vector>
@@ -135,6 +137,7 @@ struct DescriptorHeapDesc {
uint32_t heapType;
uint32_t flags;
uint32_t nodeMask;
bool shaderVisible = false;
};
struct CommandQueueDesc {
@@ -289,5 +292,16 @@ struct RHIPipelineLayoutDesc {
uint32_t uavCount = 0;
};
struct ResourceViewDesc {
uint32_t format = 0;
ResourceViewDimension dimension = ResourceViewDimension::Unknown;
uint32_t mipLevel = 0;
uint32_t arraySize = 0;
uint32_t firstArraySlice = 0;
uint32_t planeSlice = 0;
uint64_t bufferLocation = 0;
uint32_t structureByteStride = 0;
};
} // namespace RHI
} // namespace XCEngine