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:
@@ -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<D3D12Framebuffer*>(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<D3D12RenderPass*>(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<D3D12_CLEAR_FLAGS>(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;
|
||||
|
||||
56
engine/src/RHI/D3D12/D3D12Framebuffer.cpp
Normal file
56
engine/src/RHI/D3D12/D3D12Framebuffer.cpp
Normal file
@@ -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<D3D12ResourceView*>(colorAttachments[i]);
|
||||
m_renderTargetHandles[i] = view->GetCPUHandle();
|
||||
}
|
||||
}
|
||||
|
||||
if (depthStencilAttachment) {
|
||||
D3D12ResourceView* view = static_cast<D3D12ResourceView*>(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
|
||||
103
engine/src/RHI/D3D12/D3D12RenderPass.cpp
Normal file
103
engine/src/RHI/D3D12/D3D12RenderPass.cpp
Normal file
@@ -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
|
||||
@@ -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 <glad/glad.h>
|
||||
|
||||
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<OpenGLFramebuffer*>(framebuffer);
|
||||
glFramebuffer->Bind();
|
||||
|
||||
OpenGLRenderPass* glRenderPass = static_cast<OpenGLRenderPass*>(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<float>(clearValues[colorCount].stencil);
|
||||
glClearBufferfv(GL_STENCIL, 0, &stencilValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLCommandList::EndRenderPass() {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
void OpenGLCommandList::SetViewport(const Viewport& viewport) {
|
||||
glViewport(static_cast<int>(viewport.topLeftX), static_cast<int>(viewport.topLeftY),
|
||||
static_cast<int>(viewport.width), static_cast<int>(viewport.height));
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "XCEngine/RHI/OpenGL/OpenGLFramebuffer.h"
|
||||
#include "XCEngine/RHI/OpenGL/OpenGLResourceView.h"
|
||||
#include <glad/glad.h>
|
||||
|
||||
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<int>(width);
|
||||
m_height = static_cast<int>(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<OpenGLResourceView*>(colorAttachments[i]);
|
||||
GLenum glAttachment = GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(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<OpenGLResourceView*>(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);
|
||||
}
|
||||
|
||||
38
engine/src/RHI/OpenGL/OpenGLRenderPass.cpp
Normal file
38
engine/src/RHI/OpenGL/OpenGLRenderPass.cpp
Normal file
@@ -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
|
||||
Reference in New Issue
Block a user