fix(rhi): make opengl descriptor binding set-aware

This commit is contained in:
2026-03-26 15:10:03 +08:00
parent 9218ea20b5
commit 733b573963
8 changed files with 379 additions and 21 deletions

View File

@@ -1,4 +1,5 @@
#include "XCEngine/RHI/OpenGL/OpenGLDescriptorSet.h"
#include "XCEngine/RHI/OpenGL/OpenGLPipelineLayout.h"
#include "XCEngine/RHI/OpenGL/OpenGLTextureUnitAllocator.h"
#include "XCEngine/RHI/OpenGL/OpenGLResourceView.h"
#include "XCEngine/RHI/OpenGL/OpenGLSampler.h"
@@ -7,6 +8,32 @@
namespace XCEngine {
namespace RHI {
namespace {
uint32_t ResolveBindingPoint(
const OpenGLPipelineLayout* pipelineLayout,
uint32_t setIndex,
const DescriptorBinding& binding) {
if (pipelineLayout == nullptr || !pipelineLayout->UsesSetLayouts()) {
return binding.binding;
}
switch (binding.type) {
case DescriptorType::CBV:
return pipelineLayout->GetConstantBufferBindingPoint(setIndex, binding.binding);
case DescriptorType::SRV:
return pipelineLayout->GetShaderResourceBindingPoint(setIndex, binding.binding);
case DescriptorType::UAV:
return pipelineLayout->GetUnorderedAccessBindingPoint(setIndex, binding.binding);
case DescriptorType::Sampler:
return pipelineLayout->GetSamplerBindingPoint(setIndex, binding.binding);
default:
return UINT32_MAX;
}
}
} // namespace
OpenGLDescriptorSet::OpenGLDescriptorSet()
: m_allocator(nullptr)
, m_layoutBindings(nullptr)
@@ -97,6 +124,7 @@ void OpenGLDescriptorSet::Shutdown() {
m_bindings.clear();
m_allocator = nullptr;
m_bound = false;
if (m_layoutBindings != nullptr) {
delete[] m_layoutBindings;
@@ -105,6 +133,20 @@ void OpenGLDescriptorSet::Shutdown() {
m_bindingCount = 0;
}
void OpenGLDescriptorSet::EnsureConstantBufferUploaded() {
if (!m_constantBufferDirty || m_constantBufferData.empty()) {
return;
}
if (m_constantBuffer == 0) {
glGenBuffers(1, reinterpret_cast<GLuint*>(&m_constantBuffer));
}
glBindBuffer(GL_UNIFORM_BUFFER, m_constantBuffer);
glBufferData(GL_UNIFORM_BUFFER, m_constantBufferData.size(), m_constantBufferData.data(), GL_DYNAMIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
m_constantBufferDirty = false;
}
void OpenGLDescriptorSet::Update(uint32_t offset, RHIResourceView* view) {
if (view == nullptr) {
return;
@@ -134,15 +176,7 @@ void OpenGLDescriptorSet::UpdateSampler(uint32_t offset, RHISampler* sampler) {
}
void OpenGLDescriptorSet::Bind() {
if (m_constantBufferDirty && !m_constantBufferData.empty()) {
if (m_constantBuffer == 0) {
glGenBuffers(1, reinterpret_cast<GLuint*>(&m_constantBuffer));
}
glBindBuffer(GL_UNIFORM_BUFFER, m_constantBuffer);
glBufferData(GL_UNIFORM_BUFFER, m_constantBufferData.size(), m_constantBufferData.data(), GL_DYNAMIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
m_constantBufferDirty = false;
}
EnsureConstantBufferUploaded();
if (m_constantBuffer != 0) {
for (const auto& binding : m_bindings) {
@@ -178,6 +212,56 @@ void OpenGLDescriptorSet::Bind() {
m_bound = true;
}
void OpenGLDescriptorSet::BindWithPipelineLayout(const OpenGLPipelineLayout* pipelineLayout, uint32_t setIndex) {
EnsureConstantBufferUploaded();
if (m_constantBuffer != 0) {
for (const auto& binding : m_bindings) {
if (binding.type != DescriptorType::CBV) {
continue;
}
const uint32_t baseBindingPoint = ResolveBindingPoint(pipelineLayout, setIndex, binding);
if (baseBindingPoint == UINT32_MAX) {
continue;
}
for (uint32_t i = 0; i < binding.count; ++i) {
glBindBufferBase(GL_UNIFORM_BUFFER, baseBindingPoint + i, m_constantBuffer);
}
}
}
for (const auto& binding : m_bindings) {
const uint32_t baseBindingPoint = ResolveBindingPoint(pipelineLayout, setIndex, binding);
if (baseBindingPoint == UINT32_MAX) {
continue;
}
for (size_t i = 0; i < binding.textureIds.size(); ++i) {
const uint32_t bindingPoint = baseBindingPoint + static_cast<uint32_t>(i);
const uint32_t textureId = binding.textureIds[i];
if (textureId != 0) {
if (binding.type == DescriptorType::UAV) {
glBindImageTexture(bindingPoint, textureId, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8);
} else if (binding.type != DescriptorType::Sampler) {
glActiveTexture(GL_TEXTURE0 + bindingPoint);
glBindTexture(GL_TEXTURE_2D, textureId);
}
}
if (binding.type == DescriptorType::Sampler && i < binding.samplerIds.size()) {
const uint32_t samplerId = binding.samplerIds[i];
if (samplerId != 0) {
glBindSampler(bindingPoint, samplerId);
}
}
}
}
m_bound = true;
}
void OpenGLDescriptorSet::Unbind() {
for (size_t i = 0; i < m_bindings.size(); ++i) {
const auto& binding = m_bindings[i];