RHI: Add explicit RenderPass abstraction (BeginRenderPass/EndRenderPass)

New abstractions:
- RHIFramebuffer: Framebuffer interface with Initialize/Bind/GetHandle
- RHIRenderPass: RenderPass interface with AttachmentDesc for load/store actions
- D3D12Framebuffer/D3D12RenderPass: D3D12 implementation
- OpenGLFramebuffer/OpenGLRenderPass: OpenGL implementation (adapted from existing)

RHICommandList changes:
- Added BeginRenderPass(RHIRenderPass*, RHIFramebuffer*, Rect, clearValues...)
- Added EndRenderPass()

Implementation notes:
- D3D12: Uses OMSetRenderTargets + ClearRenderTargetView (fallback from native RenderPass API)
- OpenGL: Uses glBindFramebuffer + glClearBufferfv for LoadOp handling
- Old SetRenderTargets/ClearRenderTarget retained for backward compatibility

All 845 tests pass.
This commit is contained in:
2026-03-24 23:59:44 +08:00
parent 1e88beacb8
commit 5eb731bc2d
15 changed files with 559 additions and 6 deletions

View File

@@ -19,6 +19,8 @@ class RHIPipelineState;
class D3D12ResourceView;
class D3D12Shader;
class D3D12PipelineLayout;
class D3D12RenderPass;
class D3D12Framebuffer;
class D3D12CommandList : public RHICommandList {
public:
@@ -56,6 +58,10 @@ public:
void AliasBarrier(ID3D12Resource* beforeResource = nullptr, ID3D12Resource* afterResource = nullptr);
void AliasBarrierInternal(ID3D12Resource* beforeResource, ID3D12Resource* afterResource);
void BeginRenderPass(class RHIRenderPass* renderPass, class RHIFramebuffer* framebuffer,
const Rect& renderArea, uint32_t clearValueCount, const ClearValue* clearValues) override;
void EndRenderPass() override;
void SetPipelineState(RHIPipelineState* pso) override;
void SetPipelineState(ID3D12PipelineState* pso);
void SetPipelineStateInternal(ID3D12PipelineState* pso);

View File

@@ -0,0 +1,52 @@
#pragma once
#include <d3d12.h>
#include <wrl/client.h>
#include <vector>
#include "../RHIFramebuffer.h"
#include "../RHIRenderPass.h"
using Microsoft::WRL::ComPtr;
namespace XCEngine {
namespace RHI {
class D3D12ResourceView;
class D3D12DescriptorHeap;
class D3D12RenderPass;
class D3D12Framebuffer : public RHIFramebuffer {
public:
D3D12Framebuffer();
~D3D12Framebuffer() override;
void Shutdown() override;
bool Initialize(D3D12RenderPass* renderPass, uint32_t width, uint32_t height,
uint32_t colorAttachmentCount, RHIResourceView** colorAttachments,
RHIResourceView* depthStencilAttachment);
void* GetNativeHandle() override { return nullptr; }
uint32_t GetWidth() const override { return m_width; }
uint32_t GetHeight() const override { return m_height; }
bool IsValid() const override { return m_renderPass != nullptr; }
D3D12_CPU_DESCRIPTOR_HANDLE GetRenderTargetHandle(uint32_t index) const;
D3D12_CPU_DESCRIPTOR_HANDLE GetDepthStencilHandle() const { return m_depthStencilHandle; }
bool HasDepthStencil() const { return m_depthStencilHandle.ptr != 0; }
uint32_t GetRenderTargetCount() const { return static_cast<uint32_t>(m_renderTargetHandles.size()); }
const D3D12_CPU_DESCRIPTOR_HANDLE* GetRenderTargetHandles() const { return m_renderTargetHandles.data(); }
D3D12RenderPass* GetRenderPass() const { return m_renderPass; }
private:
uint32_t m_width = 0;
uint32_t m_height = 0;
D3D12RenderPass* m_renderPass = nullptr;
std::vector<D3D12_CPU_DESCRIPTOR_HANDLE> m_renderTargetHandles;
D3D12_CPU_DESCRIPTOR_HANDLE m_depthStencilHandle = {};
};
} // namespace RHI
} // namespace XCEngine

View File

@@ -0,0 +1,44 @@
#pragma once
#include <d3d12.h>
#include <wrl/client.h>
#include <vector>
#include "../RHIRenderPass.h"
using Microsoft::WRL::ComPtr;
namespace XCEngine {
namespace RHI {
class D3D12Framebuffer;
class D3D12RenderPass : public RHIRenderPass {
public:
D3D12RenderPass();
~D3D12RenderPass() override;
void Shutdown() override;
bool Initialize(uint32_t colorAttachmentCount, const AttachmentDesc* colorAttachments,
const AttachmentDesc* depthStencilAttachment) override;
uint32_t GetColorAttachmentCount() const override { return m_colorAttachmentCount; }
const AttachmentDesc* GetColorAttachments() const override { return m_colorAttachments.data(); }
const AttachmentDesc* GetDepthStencilAttachment() const override { return m_hasDepthStencil ? &m_depthStencilAttachment : nullptr; }
void* GetNativeHandle() override { return nullptr; }
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE GetBeginningAccessType(uint32_t index) const;
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE GetEndingAccessType(uint32_t index) const;
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE GetDepthBeginningAccessType() const;
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE GetDepthEndingAccessType() const;
private:
uint32_t m_colorAttachmentCount = 0;
std::vector<AttachmentDesc> m_colorAttachments;
AttachmentDesc m_depthStencilAttachment;
bool m_hasDepthStencil = false;
};
} // namespace RHI
} // namespace XCEngine

View File

@@ -172,6 +172,9 @@ public:
void PopDebugGroup();
void TransitionBarrier(RHIResourceView* resource, ResourceStates stateBefore, ResourceStates stateAfter) override;
void BeginRenderPass(class RHIRenderPass* renderPass, class RHIFramebuffer* framebuffer,
const Rect& renderArea, uint32_t clearValueCount, const ClearValue* clearValues) override;
void EndRenderPass() override;
void SetPrimitiveTopology(PrimitiveTopology topology) override;
void SetViewport(const Viewport& viewport) override;
void SetViewports(uint32_t count, const Viewport* viewports) override;

View File

@@ -3,6 +3,9 @@
#include <cstdint>
#include <vector>
#include "../RHIFramebuffer.h"
#include "../RHIResourceView.h"
namespace XCEngine {
namespace RHI {
@@ -30,13 +33,21 @@ struct FramebufferDesc {
FramebufferAttachment stencilAttachment;
};
class OpenGLFramebuffer {
class OpenGLFramebuffer : public RHIFramebuffer {
public:
OpenGLFramebuffer();
~OpenGLFramebuffer();
~OpenGLFramebuffer() override;
bool Initialize(const FramebufferDesc& desc);
void Shutdown();
void Shutdown() override;
bool Initialize(class RHIRenderPass* renderPass, uint32_t width, uint32_t height,
uint32_t colorAttachmentCount, RHIResourceView** colorAttachments,
RHIResourceView* depthStencilAttachment) override;
void* GetNativeHandle() override { return reinterpret_cast<void*>(m_framebuffer); }
uint32_t GetWidth() const override { return static_cast<uint32_t>(m_width); }
uint32_t GetHeight() const override { return static_cast<uint32_t>(m_height); }
bool IsValid() const override { return m_framebuffer != 0; }
void Bind();
void Unbind();
@@ -47,9 +58,6 @@ public:
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();

View File

@@ -0,0 +1,35 @@
#pragma once
#include <vector>
#include "../RHIRenderPass.h"
namespace XCEngine {
namespace RHI {
class OpenGLFramebuffer;
class OpenGLRenderPass : public RHIRenderPass {
public:
OpenGLRenderPass();
~OpenGLRenderPass() override;
void Shutdown() override;
bool Initialize(uint32_t colorAttachmentCount, const AttachmentDesc* colorAttachments,
const AttachmentDesc* depthStencilAttachment) override;
uint32_t GetColorAttachmentCount() const override { return m_colorAttachmentCount; }
const AttachmentDesc* GetColorAttachments() const override { return m_colorAttachments.data(); }
const AttachmentDesc* GetDepthStencilAttachment() const override { return m_hasDepthStencil ? &m_depthStencilAttachment : nullptr; }
void* GetNativeHandle() override { return nullptr; }
private:
uint32_t m_colorAttachmentCount = 0;
std::vector<AttachmentDesc> m_colorAttachments;
AttachmentDesc m_depthStencilAttachment;
bool m_hasDepthStencil = false;
};
} // namespace RHI
} // namespace XCEngine

View File

@@ -56,6 +56,10 @@ public:
virtual void TransitionBarrier(RHIResourceView* resource, ResourceStates stateBefore, ResourceStates stateAfter) = 0;
virtual void BeginRenderPass(class RHIRenderPass* renderPass, class RHIFramebuffer* framebuffer,
const Rect& renderArea, uint32_t clearValueCount, const ClearValue* clearValues) = 0;
virtual void EndRenderPass() = 0;
virtual void SetShader(RHIShader* shader) = 0;
virtual void SetUniformInt(const char* name, int value) = 0;

View File

@@ -0,0 +1,28 @@
#pragma once
#include "RHITypes.h"
#include "RHIEnums.h"
#include "RHIResourceView.h"
#include <cstdint>
namespace XCEngine {
namespace RHI {
class RHIFramebuffer {
public:
virtual ~RHIFramebuffer() = default;
virtual void Shutdown() = 0;
virtual bool Initialize(class RHIRenderPass* renderPass, uint32_t width, uint32_t height,
uint32_t colorAttachmentCount, RHIResourceView** colorAttachments,
RHIResourceView* depthStencilAttachment) = 0;
virtual void* GetNativeHandle() = 0;
virtual uint32_t GetWidth() const = 0;
virtual uint32_t GetHeight() const = 0;
virtual bool IsValid() const = 0;
};
} // namespace RHI
} // namespace XCEngine

View File

@@ -0,0 +1,35 @@
#pragma once
#include "RHITypes.h"
#include "RHIEnums.h"
#include <cstdint>
namespace XCEngine {
namespace RHI {
struct AttachmentDesc {
Format format = Format::Unknown;
LoadAction loadOp = LoadAction::Undefined;
StoreAction storeOp = StoreAction::Store;
LoadAction stencilLoadOp = LoadAction::Undefined;
StoreAction stencilStoreOp = StoreAction::Undefined;
ClearValue clearValue;
};
class RHIRenderPass {
public:
virtual ~RHIRenderPass() = default;
virtual void Shutdown() = 0;
virtual bool Initialize(uint32_t colorAttachmentCount, const AttachmentDesc* colorAttachments,
const AttachmentDesc* depthStencilAttachment) = 0;
virtual uint32_t GetColorAttachmentCount() const = 0;
virtual const AttachmentDesc* GetColorAttachments() const = 0;
virtual const AttachmentDesc* GetDepthStencilAttachment() const = 0;
virtual void* GetNativeHandle() = 0;
};
} // namespace RHI
} // namespace XCEngine