From be72e2f4a7a44ed1a601b1f66ae27572bb38c7c2 Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Tue, 17 Mar 2026 02:20:56 +0800 Subject: [PATCH] Enhance OpenGL RTV and DSV with comprehensive framebuffer support OpenGLRenderTargetView: - Add RenderTargetType enum for different texture types - Add RenderTargetViewDesc struct with mip level, array slice, layer info - Add Initialize() with desc parameter for 2D/2DArray/3D/Cube - Add InitializeCubemap() for cubemap faces - Add Bind(count) overload for multiple framebuffers - Add Clear() methods for color and depth-stencil - Add static BindFramebuffer/UnbindFramebuffer methods OpenGLDepthStencilView: - Add DepthStencilType enum for different texture types - Add DepthStencilViewDesc struct with mip level, array slice, layer info - Add Initialize() with desc parameter for 2D/2DArray/Cube - Add InitializeCubemap() for cubemap faces - Add ClearDepth, ClearStencil, ClearDepthStencil methods - Add static BindFramebuffer/UnbindFramebuffer methods --- docs/RHI抽象层设计与实现.md | 4 +- .../RHI/OpenGL/OpenGLDepthStencilView.h | 34 ++++- .../RHI/OpenGL/OpenGLRenderTargetView.h | 40 +++++- .../src/RHI/OpenGL/OpenGLDepthStencilView.cpp | 87 ++++++++++++- .../src/RHI/OpenGL/OpenGLRenderTargetView.cpp | 117 +++++++++++++++++- 5 files changed, 265 insertions(+), 17 deletions(-) diff --git a/docs/RHI抽象层设计与实现.md b/docs/RHI抽象层设计与实现.md index 1e6ab2f5..ae79c291 100644 --- a/docs/RHI抽象层设计与实现.md +++ b/docs/RHI抽象层设计与实现.md @@ -60,8 +60,8 @@ engine/ ### 4.1 目录结构调整建议 ``` include/XCEngine/RHI/ -├── Enums.h # 通用枚举 -├── Types.h # 通用结构体 +├── RHIEnums.h # 通用枚举 +├── RHITypes.h # 通用结构体 ├── RHICapabilities.h # 硬件能力检测 ├── RHIDevice.h # 设备抽象(核心入口) ├── RHICommandQueue.h # 命令队列抽象 diff --git a/engine/include/XCEngine/RHI/OpenGL/OpenGLDepthStencilView.h b/engine/include/XCEngine/RHI/OpenGL/OpenGLDepthStencilView.h index ad0e6c57..1154480d 100644 --- a/engine/include/XCEngine/RHI/OpenGL/OpenGLDepthStencilView.h +++ b/engine/include/XCEngine/RHI/OpenGL/OpenGLDepthStencilView.h @@ -1,6 +1,7 @@ #pragma once #include +#include namespace XCEngine { namespace RHI { @@ -12,23 +13,54 @@ enum class DepthStencilFormat { D32_FLOAT_S8X24_UINT }; +enum class DepthStencilType { + Texture2D, + Texture2DArray, + TextureCube +}; + +struct DepthStencilViewDesc { + DepthStencilType type = DepthStencilType::Texture2D; + int mipLevel = 0; + int baseArraySlice = 0; + int arraySize = 1; + int layer = 0; +}; + class OpenGLDepthStencilView { public: OpenGLDepthStencilView(); ~OpenGLDepthStencilView(); + bool Initialize(unsigned int texture, const DepthStencilViewDesc& desc); bool Initialize(unsigned int texture, int mipLevel = 0); + bool InitializeCubemap(unsigned int cubemap, int face, int mipLevel = 0); void Shutdown(); void Bind(); void Unbind(); - unsigned int GetID() const { return m_texture; } + void ClearDepth(float depth); + void ClearStencil(uint8_t stencil); + void ClearDepthStencil(float depth, uint8_t stencil); + + unsigned int GetFramebuffer() const { return m_framebuffer; } + unsigned int GetTexture() const { return m_texture; } + int GetMipLevel() const { return m_mipLevel; } + int GetWidth() const { return m_width; } + int GetHeight() const { return m_height; } + + static void BindFramebuffer(unsigned int framebuffer); + static void UnbindFramebuffer(); private: unsigned int m_texture; unsigned int m_framebuffer; int m_mipLevel; + int m_width; + int m_height; + DepthStencilType m_type; + DepthStencilFormat m_format; }; } // namespace RHI diff --git a/engine/include/XCEngine/RHI/OpenGL/OpenGLRenderTargetView.h b/engine/include/XCEngine/RHI/OpenGL/OpenGLRenderTargetView.h index fdcbaab6..0d6c0bcb 100644 --- a/engine/include/XCEngine/RHI/OpenGL/OpenGLRenderTargetView.h +++ b/engine/include/XCEngine/RHI/OpenGL/OpenGLRenderTargetView.h @@ -1,27 +1,63 @@ #pragma once #include +#include +#include namespace XCEngine { namespace RHI { +enum class RenderTargetType { + Texture2D, + Texture2DArray, + Texture3D, + TextureCube, + TextureCubeArray +}; + +struct RenderTargetViewDesc { + RenderTargetType type = RenderTargetType::Texture2D; + int mipLevel = 0; + int baseArraySlice = 0; + int arraySize = 1; + int layer = 0; + uint32_t format = 0; +}; + class OpenGLRenderTargetView { public: OpenGLRenderTargetView(); ~OpenGLRenderTargetView(); + bool Initialize(unsigned int texture, const RenderTargetViewDesc& desc); bool Initialize(unsigned int texture, int mipLevel = 0); + bool InitializeCubemap(unsigned int cubemap, int face, int mipLevel = 0); void Shutdown(); - void Bind(unsigned int slot); + void Bind(unsigned int slot = 0); + void Bind(unsigned int count, const unsigned int* framebuffers, const int* drawBuffers); void Unbind(); - unsigned int GetID() const { return m_texture; } + void Clear(float r, float g, float b, float a); + void Clear(float r, float g, float b, float a, float depth, uint8_t stencil); + + unsigned int GetFramebuffer() const { return m_framebuffer; } + unsigned int GetTexture() const { return m_texture; } + int GetMipLevel() const { return m_mipLevel; } + int GetWidth() const { return m_width; } + int GetHeight() const { return m_height; } + + static void BindFramebuffer(unsigned int framebuffer); + static void UnbindFramebuffer(); private: unsigned int m_texture; unsigned int m_framebuffer; int m_mipLevel; + int m_width; + int m_height; + RenderTargetType m_type; + std::vector m_framebuffers; }; } // namespace RHI diff --git a/engine/src/RHI/OpenGL/OpenGLDepthStencilView.cpp b/engine/src/RHI/OpenGL/OpenGLDepthStencilView.cpp index c3810334..e74ad8d1 100644 --- a/engine/src/RHI/OpenGL/OpenGLDepthStencilView.cpp +++ b/engine/src/RHI/OpenGL/OpenGLDepthStencilView.cpp @@ -6,24 +6,72 @@ namespace XCEngine { namespace RHI { -OpenGLDepthStencilView::OpenGLDepthStencilView() : m_texture(0), m_framebuffer(0), m_mipLevel(0) { +OpenGLDepthStencilView::OpenGLDepthStencilView() + : m_texture(0) + , m_framebuffer(0) + , m_mipLevel(0) + , m_width(0) + , m_height(0) + , m_type(DepthStencilType::Texture2D) + , m_format(DepthStencilFormat::D24_UNORM_S8_UINT) { } OpenGLDepthStencilView::~OpenGLDepthStencilView() { + Shutdown(); } -bool OpenGLDepthStencilView::Initialize(unsigned int texture, int mipLevel) { +bool OpenGLDepthStencilView::Initialize(unsigned int texture, const DepthStencilViewDesc& desc) { m_texture = texture; - m_mipLevel = mipLevel; + m_mipLevel = desc.mipLevel; + m_type = desc.type; glGenFramebuffers(1, &m_framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, texture, mipLevel); - + + GLenum depthAttachment = GL_DEPTH_ATTACHMENT; + GLenum stencilAttachment = GL_STENCIL_ATTACHMENT; + + switch (desc.type) { + case DepthStencilType::Texture2D: + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, texture, desc.mipLevel); + break; + case DepthStencilType::Texture2DArray: + glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, texture, desc.mipLevel, desc.baseArraySlice); + break; + case DepthStencilType::TextureCube: + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + desc.baseArraySlice, texture, desc.mipLevel); + break; + } + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + glBindFramebuffer(GL_FRAMEBUFFER, 0); return false; } - + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + return true; +} + +bool OpenGLDepthStencilView::Initialize(unsigned int texture, int mipLevel) { + DepthStencilViewDesc desc; + desc.mipLevel = mipLevel; + return Initialize(texture, desc); +} + +bool OpenGLDepthStencilView::InitializeCubemap(unsigned int cubemap, int face, int mipLevel) { + m_texture = cubemap; + m_mipLevel = mipLevel; + m_type = DepthStencilType::TextureCube; + + glGenFramebuffers(1, &m_framebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, cubemap, mipLevel); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + glBindFramebuffer(GL_FRAMEBUFFER, 0); + return false; + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); return true; } @@ -43,5 +91,32 @@ void OpenGLDepthStencilView::Unbind() { glBindFramebuffer(GL_FRAMEBUFFER, 0); } +void OpenGLDepthStencilView::ClearDepth(float depth) { + glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer); + glClearDepth(depth); + glClear(GL_DEPTH_BUFFER_BIT); +} + +void OpenGLDepthStencilView::ClearStencil(uint8_t stencil) { + glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer); + glClearStencil(stencil); + glClear(GL_STENCIL_BUFFER_BIT); +} + +void OpenGLDepthStencilView::ClearDepthStencil(float depth, uint8_t stencil) { + glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer); + glClearDepth(depth); + glClearStencil(stencil); + glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); +} + +void OpenGLDepthStencilView::BindFramebuffer(unsigned int framebuffer) { + glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); +} + +void OpenGLDepthStencilView::UnbindFramebuffer() { + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + } // namespace RHI } // namespace XCEngine diff --git a/engine/src/RHI/OpenGL/OpenGLRenderTargetView.cpp b/engine/src/RHI/OpenGL/OpenGLRenderTargetView.cpp index 8174cfa3..a951776c 100644 --- a/engine/src/RHI/OpenGL/OpenGLRenderTargetView.cpp +++ b/engine/src/RHI/OpenGL/OpenGLRenderTargetView.cpp @@ -6,24 +6,89 @@ namespace XCEngine { namespace RHI { -OpenGLRenderTargetView::OpenGLRenderTargetView() : m_texture(0), m_framebuffer(0), m_mipLevel(0) { +static unsigned int ToGLRenderTargetType(RenderTargetType type) { + switch (type) { + case RenderTargetType::Texture2D: return GL_TEXTURE_2D; + case RenderTargetType::Texture2DArray: return GL_TEXTURE_2D_ARRAY; + case RenderTargetType::Texture3D: return GL_TEXTURE_3D; + case RenderTargetType::TextureCube: return GL_TEXTURE_CUBE_MAP; + case RenderTargetType::TextureCubeArray: return GL_TEXTURE_CUBE_MAP_ARRAY; + default: return GL_TEXTURE_2D; + } +} + +OpenGLRenderTargetView::OpenGLRenderTargetView() + : m_texture(0) + , m_framebuffer(0) + , m_mipLevel(0) + , m_width(0) + , m_height(0) + , m_type(RenderTargetType::Texture2D) { } OpenGLRenderTargetView::~OpenGLRenderTargetView() { + Shutdown(); } -bool OpenGLRenderTargetView::Initialize(unsigned int texture, int mipLevel) { +bool OpenGLRenderTargetView::Initialize(unsigned int texture, const RenderTargetViewDesc& desc) { m_texture = texture; - m_mipLevel = mipLevel; + m_mipLevel = desc.mipLevel; + m_type = desc.type; glGenFramebuffers(1, &m_framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, mipLevel); - + + unsigned int target = ToGLRenderTargetType(desc.type); + GLenum attachment = GL_COLOR_ATTACHMENT0; + + switch (desc.type) { + case RenderTargetType::Texture2D: + glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, texture, desc.mipLevel); + break; + case RenderTargetType::Texture2DArray: + glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment, texture, desc.mipLevel, desc.baseArraySlice); + break; + case RenderTargetType::Texture3D: + glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment, texture, desc.mipLevel, desc.layer); + break; + case RenderTargetType::TextureCube: + glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_CUBE_MAP_POSITIVE_X + desc.baseArraySlice, texture, desc.mipLevel); + break; + case RenderTargetType::TextureCubeArray: + glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment, texture, desc.mipLevel, desc.baseArraySlice); + break; + } + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + glBindFramebuffer(GL_FRAMEBUFFER, 0); return false; } - + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + return true; +} + +bool OpenGLRenderTargetView::Initialize(unsigned int texture, int mipLevel) { + RenderTargetViewDesc desc; + desc.type = RenderTargetType::Texture2D; + desc.mipLevel = mipLevel; + return Initialize(texture, desc); +} + +bool OpenGLRenderTargetView::InitializeCubemap(unsigned int cubemap, int face, int mipLevel) { + m_texture = cubemap; + m_mipLevel = mipLevel; + m_type = RenderTargetType::TextureCube; + + glGenFramebuffers(1, &m_framebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, cubemap, mipLevel); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + glBindFramebuffer(GL_FRAMEBUFFER, 0); + return false; + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); return true; } @@ -33,15 +98,55 @@ void OpenGLRenderTargetView::Shutdown() { glDeleteFramebuffers(1, &m_framebuffer); m_framebuffer = 0; } + if (!m_framebuffers.empty()) { + glDeleteFramebuffers(static_cast(m_framebuffers.size()), m_framebuffers.data()); + m_framebuffers.clear(); + } } void OpenGLRenderTargetView::Bind(unsigned int slot) { glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer); + (void)slot; +} + +void OpenGLRenderTargetView::Bind(unsigned int count, const unsigned int* framebuffers, const int* drawBuffers) { + if (count == 1) { + glBindFramebuffer(GL_FRAMEBUFFER, framebuffers[0]); + } else { + glBindFramebuffer(GL_FRAMEBUFFER, 0); + for (unsigned int i = 0; i < count; i++) { + glBindFramebuffer(GL_FRAMEBUFFER, framebuffers[i]); + glDrawBuffers(1, (const GLenum*)&drawBuffers[i]); + } + } + (void)count; } void OpenGLRenderTargetView::Unbind() { glBindFramebuffer(GL_FRAMEBUFFER, 0); } +void OpenGLRenderTargetView::Clear(float r, float g, float b, float a) { + glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer); + glClearColor(r, g, b, a); + glClear(GL_COLOR_BUFFER_BIT); +} + +void OpenGLRenderTargetView::Clear(float r, float g, float b, float a, float depth, uint8_t stencil) { + glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer); + glClearColor(r, g, b, a); + glClearDepth(depth); + glClearStencil(stencil); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); +} + +void OpenGLRenderTargetView::BindFramebuffer(unsigned int framebuffer) { + glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); +} + +void OpenGLRenderTargetView::UnbindFramebuffer() { + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + } // namespace RHI } // namespace XCEngine