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
This commit is contained in:
2026-03-17 02:20:56 +08:00
parent 6126404e3f
commit be72e2f4a7
5 changed files with 265 additions and 17 deletions

View File

@@ -60,8 +60,8 @@ engine/
### 4.1 目录结构调整建议
```
include/XCEngine/RHI/
├── Enums.h # 通用枚举
├── Types.h # 通用结构体
├── RHIEnums.h # 通用枚举
├── RHITypes.h # 通用结构体
├── RHICapabilities.h # 硬件能力检测
├── RHIDevice.h # 设备抽象(核心入口)
├── RHICommandQueue.h # 命令队列抽象

View File

@@ -1,6 +1,7 @@
#pragma once
#include <GLFW/glfw3.h>
#include <cstdint>
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

View File

@@ -1,27 +1,63 @@
#pragma once
#include <GLFW/glfw3.h>
#include <cstdint>
#include <vector>
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<unsigned int> m_framebuffers;
};
} // namespace RHI

View File

@@ -6,21 +6,69 @@
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;
}
@@ -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

View File

@@ -6,21 +6,86 @@
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;
}
@@ -33,15 +98,55 @@ void OpenGLRenderTargetView::Shutdown() {
glDeleteFramebuffers(1, &m_framebuffer);
m_framebuffer = 0;
}
if (!m_framebuffers.empty()) {
glDeleteFramebuffers(static_cast<GLsizei>(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