From 5eb731bc2d4d75d33f923fc2e266c7ba214acbf6 Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Tue, 24 Mar 2026 23:59:44 +0800 Subject: [PATCH] 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. --- .../XCEngine/RHI/D3D12/D3D12CommandList.h | 6 + .../XCEngine/RHI/D3D12/D3D12Framebuffer.h | 52 +++++++++ .../XCEngine/RHI/D3D12/D3D12RenderPass.h | 44 ++++++++ .../XCEngine/RHI/OpenGL/OpenGLCommandList.h | 3 + .../XCEngine/RHI/OpenGL/OpenGLFramebuffer.h | 20 +++- .../XCEngine/RHI/OpenGL/OpenGLRenderPass.h | 35 ++++++ engine/include/XCEngine/RHI/RHICommandList.h | 4 + engine/include/XCEngine/RHI/RHIFramebuffer.h | 28 +++++ engine/include/XCEngine/RHI/RHIRenderPass.h | 35 ++++++ engine/src/RHI/D3D12/D3D12CommandList.cpp | 48 ++++++++ engine/src/RHI/D3D12/D3D12Framebuffer.cpp | 56 ++++++++++ engine/src/RHI/D3D12/D3D12RenderPass.cpp | 103 ++++++++++++++++++ engine/src/RHI/OpenGL/OpenGLCommandList.cpp | 41 +++++++ engine/src/RHI/OpenGL/OpenGLFramebuffer.cpp | 52 +++++++++ engine/src/RHI/OpenGL/OpenGLRenderPass.cpp | 38 +++++++ 15 files changed, 559 insertions(+), 6 deletions(-) create mode 100644 engine/include/XCEngine/RHI/D3D12/D3D12Framebuffer.h create mode 100644 engine/include/XCEngine/RHI/D3D12/D3D12RenderPass.h create mode 100644 engine/include/XCEngine/RHI/OpenGL/OpenGLRenderPass.h create mode 100644 engine/include/XCEngine/RHI/RHIFramebuffer.h create mode 100644 engine/include/XCEngine/RHI/RHIRenderPass.h create mode 100644 engine/src/RHI/D3D12/D3D12Framebuffer.cpp create mode 100644 engine/src/RHI/D3D12/D3D12RenderPass.cpp create mode 100644 engine/src/RHI/OpenGL/OpenGLRenderPass.cpp diff --git a/engine/include/XCEngine/RHI/D3D12/D3D12CommandList.h b/engine/include/XCEngine/RHI/D3D12/D3D12CommandList.h index 7233c0c2..2b5bcbb5 100644 --- a/engine/include/XCEngine/RHI/D3D12/D3D12CommandList.h +++ b/engine/include/XCEngine/RHI/D3D12/D3D12CommandList.h @@ -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); diff --git a/engine/include/XCEngine/RHI/D3D12/D3D12Framebuffer.h b/engine/include/XCEngine/RHI/D3D12/D3D12Framebuffer.h new file mode 100644 index 00000000..c2209a3e --- /dev/null +++ b/engine/include/XCEngine/RHI/D3D12/D3D12Framebuffer.h @@ -0,0 +1,52 @@ +#pragma once + +#include +#include +#include + +#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(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 m_renderTargetHandles; + D3D12_CPU_DESCRIPTOR_HANDLE m_depthStencilHandle = {}; +}; + +} // namespace RHI +} // namespace XCEngine \ No newline at end of file diff --git a/engine/include/XCEngine/RHI/D3D12/D3D12RenderPass.h b/engine/include/XCEngine/RHI/D3D12/D3D12RenderPass.h new file mode 100644 index 00000000..a226a9d8 --- /dev/null +++ b/engine/include/XCEngine/RHI/D3D12/D3D12RenderPass.h @@ -0,0 +1,44 @@ +#pragma once + +#include +#include +#include + +#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 m_colorAttachments; + AttachmentDesc m_depthStencilAttachment; + bool m_hasDepthStencil = false; +}; + +} // namespace RHI +} // namespace XCEngine \ No newline at end of file diff --git a/engine/include/XCEngine/RHI/OpenGL/OpenGLCommandList.h b/engine/include/XCEngine/RHI/OpenGL/OpenGLCommandList.h index 7f31019c..07f97adb 100644 --- a/engine/include/XCEngine/RHI/OpenGL/OpenGLCommandList.h +++ b/engine/include/XCEngine/RHI/OpenGL/OpenGLCommandList.h @@ -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; diff --git a/engine/include/XCEngine/RHI/OpenGL/OpenGLFramebuffer.h b/engine/include/XCEngine/RHI/OpenGL/OpenGLFramebuffer.h index 27dc98b5..b845e977 100644 --- a/engine/include/XCEngine/RHI/OpenGL/OpenGLFramebuffer.h +++ b/engine/include/XCEngine/RHI/OpenGL/OpenGLFramebuffer.h @@ -3,6 +3,9 @@ #include #include +#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(m_framebuffer); } + uint32_t GetWidth() const override { return static_cast(m_width); } + uint32_t GetHeight() const override { return static_cast(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(); diff --git a/engine/include/XCEngine/RHI/OpenGL/OpenGLRenderPass.h b/engine/include/XCEngine/RHI/OpenGL/OpenGLRenderPass.h new file mode 100644 index 00000000..22decfbe --- /dev/null +++ b/engine/include/XCEngine/RHI/OpenGL/OpenGLRenderPass.h @@ -0,0 +1,35 @@ +#pragma once + +#include + +#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 m_colorAttachments; + AttachmentDesc m_depthStencilAttachment; + bool m_hasDepthStencil = false; +}; + +} // namespace RHI +} // namespace XCEngine \ No newline at end of file diff --git a/engine/include/XCEngine/RHI/RHICommandList.h b/engine/include/XCEngine/RHI/RHICommandList.h index 91e64b86..1112d115 100644 --- a/engine/include/XCEngine/RHI/RHICommandList.h +++ b/engine/include/XCEngine/RHI/RHICommandList.h @@ -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; diff --git a/engine/include/XCEngine/RHI/RHIFramebuffer.h b/engine/include/XCEngine/RHI/RHIFramebuffer.h new file mode 100644 index 00000000..1fb91a2f --- /dev/null +++ b/engine/include/XCEngine/RHI/RHIFramebuffer.h @@ -0,0 +1,28 @@ +#pragma once + +#include "RHITypes.h" +#include "RHIEnums.h" +#include "RHIResourceView.h" +#include + +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 \ No newline at end of file diff --git a/engine/include/XCEngine/RHI/RHIRenderPass.h b/engine/include/XCEngine/RHI/RHIRenderPass.h new file mode 100644 index 00000000..9437338b --- /dev/null +++ b/engine/include/XCEngine/RHI/RHIRenderPass.h @@ -0,0 +1,35 @@ +#pragma once + +#include "RHITypes.h" +#include "RHIEnums.h" +#include + +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 \ No newline at end of file diff --git a/engine/src/RHI/D3D12/D3D12CommandList.cpp b/engine/src/RHI/D3D12/D3D12CommandList.cpp index 997ce920..9b35b10a 100644 --- a/engine/src/RHI/D3D12/D3D12CommandList.cpp +++ b/engine/src/RHI/D3D12/D3D12CommandList.cpp @@ -3,6 +3,8 @@ #include "XCEngine/RHI/D3D12/D3D12PipelineState.h" #include "XCEngine/RHI/D3D12/D3D12Shader.h" #include "XCEngine/RHI/D3D12/D3D12PipelineLayout.h" +#include "XCEngine/RHI/D3D12/D3D12RenderPass.h" +#include "XCEngine/RHI/D3D12/D3D12Framebuffer.h" namespace XCEngine { namespace RHI { @@ -245,6 +247,52 @@ void D3D12CommandList::AliasBarrierInternal(ID3D12Resource* beforeResource, ID3D m_commandList->ResourceBarrier(1, &barrier); } +void D3D12CommandList::BeginRenderPass(RHIRenderPass* renderPass, RHIFramebuffer* framebuffer, + const Rect& renderArea, uint32_t clearValueCount, const ClearValue* clearValues) { + (void)renderArea; + if (!framebuffer || !renderPass) return; + + D3D12Framebuffer* d3d12Framebuffer = static_cast(framebuffer); + + uint32_t rtCount = d3d12Framebuffer->GetRenderTargetCount(); + const D3D12_CPU_DESCRIPTOR_HANDLE* rtHandles = d3d12Framebuffer->GetRenderTargetHandles(); + bool hasDS = d3d12Framebuffer->HasDepthStencil(); + D3D12_CPU_DESCRIPTOR_HANDLE dsHandle = d3d12Framebuffer->GetDepthStencilHandle(); + + D3D12RenderPass* d3d12RenderPass = static_cast(renderPass); + const AttachmentDesc* attachments = d3d12RenderPass->GetColorAttachments(); + + for (uint32_t i = 0; i < rtCount; ++i) { + if (attachments[i].loadOp == LoadAction::Clear && clearValueCount > i) { + m_commandList->ClearRenderTargetView(rtHandles[i], &clearValues[i].color.r, 0, nullptr); + } + } + + if (hasDS) { + const AttachmentDesc* dsAttachment = d3d12RenderPass->GetDepthStencilAttachment(); + if (dsAttachment) { + uint32_t clearFlags = 0; + if (dsAttachment->loadOp == LoadAction::Clear) clearFlags |= D3D12_CLEAR_FLAG_DEPTH; + if (dsAttachment->stencilLoadOp == LoadAction::Clear) clearFlags |= D3D12_CLEAR_FLAG_STENCIL; + if (clearFlags && clearValueCount > rtCount) { + m_commandList->ClearDepthStencilView(dsHandle, static_cast(clearFlags), clearValues[rtCount].depth, clearValues[rtCount].stencil, 0, nullptr); + } + } + } + + m_commandList->OMSetRenderTargets(rtCount, rtHandles, FALSE, hasDS ? &dsHandle : nullptr); + + m_boundRenderTargets.clear(); + for (uint32_t i = 0; i < rtCount; ++i) { + m_boundRenderTargets.push_back(rtHandles[i]); + } + m_boundDepthStencil = dsHandle; + m_depthStencilBound = hasDS; +} + +void D3D12CommandList::EndRenderPass() { +} + void D3D12CommandList::SetPipelineStateInternal(ID3D12PipelineState* pso) { m_commandList->SetPipelineState(pso); m_currentPipelineState = pso; diff --git a/engine/src/RHI/D3D12/D3D12Framebuffer.cpp b/engine/src/RHI/D3D12/D3D12Framebuffer.cpp new file mode 100644 index 00000000..44247bb4 --- /dev/null +++ b/engine/src/RHI/D3D12/D3D12Framebuffer.cpp @@ -0,0 +1,56 @@ +#include "XCEngine/RHI/D3D12/D3D12Framebuffer.h" +#include "XCEngine/RHI/D3D12/D3D12RenderPass.h" +#include "XCEngine/RHI/D3D12/D3D12ResourceView.h" + +namespace XCEngine { +namespace RHI { + +D3D12Framebuffer::D3D12Framebuffer() { +} + +D3D12Framebuffer::~D3D12Framebuffer() { + Shutdown(); +} + +void D3D12Framebuffer::Shutdown() { + m_renderTargetHandles.clear(); + m_depthStencilHandle = {}; + m_renderPass = nullptr; + m_width = 0; + m_height = 0; +} + +bool D3D12Framebuffer::Initialize(D3D12RenderPass* renderPass, uint32_t width, uint32_t height, + uint32_t colorAttachmentCount, RHIResourceView** colorAttachments, + RHIResourceView* depthStencilAttachment) { + m_renderPass = renderPass; + m_width = width; + m_height = height; + + m_renderTargetHandles.resize(colorAttachmentCount); + for (uint32_t i = 0; i < colorAttachmentCount; ++i) { + if (colorAttachments[i]) { + D3D12ResourceView* view = static_cast(colorAttachments[i]); + m_renderTargetHandles[i] = view->GetCPUHandle(); + } + } + + if (depthStencilAttachment) { + D3D12ResourceView* view = static_cast(depthStencilAttachment); + m_depthStencilHandle = view->GetCPUHandle(); + } else { + m_depthStencilHandle = {}; + } + + return true; +} + +D3D12_CPU_DESCRIPTOR_HANDLE D3D12Framebuffer::GetRenderTargetHandle(uint32_t index) const { + if (index >= m_renderTargetHandles.size()) { + return {}; + } + return m_renderTargetHandles[index]; +} + +} // namespace RHI +} // namespace XCEngine \ No newline at end of file diff --git a/engine/src/RHI/D3D12/D3D12RenderPass.cpp b/engine/src/RHI/D3D12/D3D12RenderPass.cpp new file mode 100644 index 00000000..03e63a0c --- /dev/null +++ b/engine/src/RHI/D3D12/D3D12RenderPass.cpp @@ -0,0 +1,103 @@ +#include "XCEngine/RHI/D3D12/D3D12RenderPass.h" +#include "XCEngine/RHI/D3D12/D3D12Framebuffer.h" + +namespace XCEngine { +namespace RHI { + +D3D12RenderPass::D3D12RenderPass() { +} + +D3D12RenderPass::~D3D12RenderPass() { + Shutdown(); +} + +void D3D12RenderPass::Shutdown() { + m_colorAttachments.clear(); + m_colorAttachmentCount = 0; + m_hasDepthStencil = false; +} + +bool D3D12RenderPass::Initialize(uint32_t colorAttachmentCount, const AttachmentDesc* colorAttachments, + const AttachmentDesc* depthStencilAttachment) { + m_colorAttachmentCount = colorAttachmentCount; + m_colorAttachments.resize(colorAttachmentCount); + for (uint32_t i = 0; i < colorAttachmentCount; ++i) { + m_colorAttachments[i] = colorAttachments[i]; + } + + if (depthStencilAttachment != nullptr) { + m_hasDepthStencil = true; + m_depthStencilAttachment = *depthStencilAttachment; + } else { + m_hasDepthStencil = false; + } + + return true; +} + +D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE D3D12RenderPass::GetBeginningAccessType(uint32_t index) const { + if (index >= m_colorAttachmentCount) { + return D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE::D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS; + } + switch (m_colorAttachments[index].loadOp) { + case LoadAction::Clear: + return D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE::D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR; + case LoadAction::Load: + return D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE::D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE; + case LoadAction::Undefined: + default: + return D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE::D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_DISCARD; + } +} + +D3D12_RENDER_PASS_ENDING_ACCESS_TYPE D3D12RenderPass::GetEndingAccessType(uint32_t index) const { + if (index >= m_colorAttachmentCount) { + return D3D12_RENDER_PASS_ENDING_ACCESS_TYPE::D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS; + } + switch (m_colorAttachments[index].storeOp) { + case StoreAction::Store: + return D3D12_RENDER_PASS_ENDING_ACCESS_TYPE::D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE; + case StoreAction::Discard: + return D3D12_RENDER_PASS_ENDING_ACCESS_TYPE::D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_DISCARD; + case StoreAction::Resolve: + return D3D12_RENDER_PASS_ENDING_ACCESS_TYPE::D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_RESOLVE; + case StoreAction::StoreAndResolve: + return D3D12_RENDER_PASS_ENDING_ACCESS_TYPE::D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_STORE_AND_RESOLVE; + case StoreAction::Undefined: + default: + return D3D12_RENDER_PASS_ENDING_ACCESS_TYPE::D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS; + } +} + +D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE D3D12RenderPass::GetDepthBeginningAccessType() const { + if (!m_hasDepthStencil) { + return D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE::D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS; + } + switch (m_depthStencilAttachment.loadOp) { + case LoadAction::Clear: + return D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE::D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR; + case LoadAction::Load: + return D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE::D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE; + case LoadAction::Undefined: + default: + return D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE::D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_DISCARD; + } +} + +D3D12_RENDER_PASS_ENDING_ACCESS_TYPE D3D12RenderPass::GetDepthEndingAccessType() const { + if (!m_hasDepthStencil) { + return D3D12_RENDER_PASS_ENDING_ACCESS_TYPE::D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS; + } + switch (m_depthStencilAttachment.storeOp) { + case StoreAction::Store: + return D3D12_RENDER_PASS_ENDING_ACCESS_TYPE::D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE; + case StoreAction::Discard: + return D3D12_RENDER_PASS_ENDING_ACCESS_TYPE::D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_DISCARD; + case StoreAction::Undefined: + default: + return D3D12_RENDER_PASS_ENDING_ACCESS_TYPE::D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS; + } +} + +} // namespace RHI +} // namespace XCEngine \ No newline at end of file diff --git a/engine/src/RHI/OpenGL/OpenGLCommandList.cpp b/engine/src/RHI/OpenGL/OpenGLCommandList.cpp index 5df96f52..ca378831 100644 --- a/engine/src/RHI/OpenGL/OpenGLCommandList.cpp +++ b/engine/src/RHI/OpenGL/OpenGLCommandList.cpp @@ -2,6 +2,8 @@ #include "XCEngine/RHI/OpenGL/OpenGLResourceView.h" #include "XCEngine/RHI/OpenGL/OpenGLPipelineState.h" #include "XCEngine/RHI/OpenGL/OpenGLShader.h" +#include "XCEngine/RHI/OpenGL/OpenGLFramebuffer.h" +#include "XCEngine/RHI/OpenGL/OpenGLRenderPass.h" #include namespace XCEngine { @@ -508,6 +510,45 @@ void OpenGLCommandList::TransitionBarrier(RHIResourceView* resource, ResourceSta glMemoryBarrier(GL_ALL_BARRIER_BITS); } +void OpenGLCommandList::BeginRenderPass(RHIRenderPass* renderPass, RHIFramebuffer* framebuffer, + const Rect& renderArea, uint32_t clearValueCount, const ClearValue* clearValues) { + (void)renderArea; + (void)clearValueCount; + (void)clearValues; + + if (!framebuffer) return; + + OpenGLFramebuffer* glFramebuffer = static_cast(framebuffer); + glFramebuffer->Bind(); + + OpenGLRenderPass* glRenderPass = static_cast(renderPass); + if (glRenderPass) { + const AttachmentDesc* colorAttachments = glRenderPass->GetColorAttachments(); + uint32_t colorCount = glRenderPass->GetColorAttachmentCount(); + + for (uint32_t i = 0; i < colorCount && i < clearValueCount; ++i) { + if (colorAttachments[i].loadOp == LoadAction::Clear) { + glClearBufferfv(GL_COLOR, i, &clearValues[i].color.r); + } + } + + const AttachmentDesc* dsAttachment = glRenderPass->GetDepthStencilAttachment(); + if (dsAttachment && clearValueCount > colorCount) { + if (dsAttachment->loadOp == LoadAction::Clear) { + glClearBufferfv(GL_DEPTH, 0, &clearValues[colorCount].depth); + } + if (dsAttachment->stencilLoadOp == LoadAction::Clear) { + float stencilValue = static_cast(clearValues[colorCount].stencil); + glClearBufferfv(GL_STENCIL, 0, &stencilValue); + } + } + } +} + +void OpenGLCommandList::EndRenderPass() { + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + void OpenGLCommandList::SetViewport(const Viewport& viewport) { glViewport(static_cast(viewport.topLeftX), static_cast(viewport.topLeftY), static_cast(viewport.width), static_cast(viewport.height)); diff --git a/engine/src/RHI/OpenGL/OpenGLFramebuffer.cpp b/engine/src/RHI/OpenGL/OpenGLFramebuffer.cpp index d917ef38..d1a00cf6 100644 --- a/engine/src/RHI/OpenGL/OpenGLFramebuffer.cpp +++ b/engine/src/RHI/OpenGL/OpenGLFramebuffer.cpp @@ -1,4 +1,5 @@ #include "XCEngine/RHI/OpenGL/OpenGLFramebuffer.h" +#include "XCEngine/RHI/OpenGL/OpenGLResourceView.h" #include namespace XCEngine { @@ -97,6 +98,57 @@ void OpenGLFramebuffer::Shutdown() { m_samples = 1; } +bool OpenGLFramebuffer::Initialize(class RHIRenderPass* renderPass, uint32_t width, uint32_t height, + uint32_t colorAttachmentCount, RHIResourceView** colorAttachments, + RHIResourceView* depthStencilAttachment) { + (void)renderPass; + m_width = static_cast(width); + m_height = static_cast(height); + m_samples = 1; + + glGenFramebuffers(1, &m_framebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer); + + GLenum drawBuffers[16] = { GL_NONE }; + int drawBufferCount = 0; + + for (uint32_t i = 0; i < colorAttachmentCount && i < 16; ++i) { + if (colorAttachments[i]) { + OpenGLResourceView* view = static_cast(colorAttachments[i]); + GLenum glAttachment = GL_COLOR_ATTACHMENT0 + static_cast(i); + unsigned int texture = view->GetTexture(); + if (texture) { + glFramebufferTexture2D(GL_FRAMEBUFFER, glAttachment, GL_TEXTURE_2D, texture, 0); + } + drawBuffers[drawBufferCount++] = glAttachment; + } + } + + if (depthStencilAttachment) { + OpenGLResourceView* view = static_cast(depthStencilAttachment); + unsigned int texture = view->GetTexture(); + if (texture) { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, texture, 0); + } + } + + if (drawBufferCount > 0) { + glDrawBuffers(drawBufferCount, drawBuffers); + } else { + glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + } + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + glBindFramebuffer(GL_FRAMEBUFFER, 0); + return false; + } + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + return true; +} + void OpenGLFramebuffer::Bind() { glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer); } diff --git a/engine/src/RHI/OpenGL/OpenGLRenderPass.cpp b/engine/src/RHI/OpenGL/OpenGLRenderPass.cpp new file mode 100644 index 00000000..d745e388 --- /dev/null +++ b/engine/src/RHI/OpenGL/OpenGLRenderPass.cpp @@ -0,0 +1,38 @@ +#include "XCEngine/RHI/OpenGL/OpenGLRenderPass.h" + +namespace XCEngine { +namespace RHI { + +OpenGLRenderPass::OpenGLRenderPass() { +} + +OpenGLRenderPass::~OpenGLRenderPass() { + Shutdown(); +} + +void OpenGLRenderPass::Shutdown() { + m_colorAttachments.clear(); + m_colorAttachmentCount = 0; + m_hasDepthStencil = false; +} + +bool OpenGLRenderPass::Initialize(uint32_t colorAttachmentCount, const AttachmentDesc* colorAttachments, + const AttachmentDesc* depthStencilAttachment) { + m_colorAttachmentCount = colorAttachmentCount; + m_colorAttachments.resize(colorAttachmentCount); + for (uint32_t i = 0; i < colorAttachmentCount; ++i) { + m_colorAttachments[i] = colorAttachments[i]; + } + + if (depthStencilAttachment != nullptr) { + m_hasDepthStencil = true; + m_depthStencilAttachment = *depthStencilAttachment; + } else { + m_hasDepthStencil = false; + } + + return true; +} + +} // namespace RHI +} // namespace XCEngine \ No newline at end of file