fix(rhi): make opengl descriptor binding set-aware
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
#include "XCEngine/RHI/OpenGL/OpenGLCommandList.h"
|
||||
#include "XCEngine/RHI/OpenGL/OpenGLResourceView.h"
|
||||
#include "XCEngine/RHI/OpenGL/OpenGLPipelineState.h"
|
||||
#include "XCEngine/RHI/OpenGL/OpenGLPipelineLayout.h"
|
||||
#include "XCEngine/RHI/OpenGL/OpenGLShader.h"
|
||||
#include "XCEngine/RHI/OpenGL/OpenGLFramebuffer.h"
|
||||
#include "XCEngine/RHI/OpenGL/OpenGLRenderPass.h"
|
||||
@@ -717,12 +718,13 @@ void OpenGLCommandList::SetGraphicsDescriptorSets(
|
||||
uint32_t count,
|
||||
RHIDescriptorSet** descriptorSets,
|
||||
RHIPipelineLayout* pipelineLayout) {
|
||||
(void)firstSet;
|
||||
(void)pipelineLayout;
|
||||
OpenGLPipelineLayout* openGLPipelineLayout = static_cast<OpenGLPipelineLayout*>(pipelineLayout);
|
||||
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
if (descriptorSets[i] != nullptr) {
|
||||
descriptorSets[i]->Bind();
|
||||
static_cast<OpenGLDescriptorSet*>(descriptorSets[i])->BindWithPipelineLayout(
|
||||
openGLPipelineLayout,
|
||||
firstSet + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -732,12 +734,13 @@ void OpenGLCommandList::SetComputeDescriptorSets(
|
||||
uint32_t count,
|
||||
RHIDescriptorSet** descriptorSets,
|
||||
RHIPipelineLayout* pipelineLayout) {
|
||||
(void)firstSet;
|
||||
(void)pipelineLayout;
|
||||
OpenGLPipelineLayout* openGLPipelineLayout = static_cast<OpenGLPipelineLayout*>(pipelineLayout);
|
||||
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
if (descriptorSets[i] != nullptr) {
|
||||
descriptorSets[i]->Bind();
|
||||
static_cast<OpenGLDescriptorSet*>(descriptorSets[i])->BindWithPipelineLayout(
|
||||
openGLPipelineLayout,
|
||||
firstSet + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "XCEngine/RHI/OpenGL/OpenGLPipelineLayout.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace RHI {
|
||||
|
||||
@@ -27,10 +29,34 @@ void AccumulateDescriptorCounts(const DescriptorSetLayoutDesc& setLayout, RHIPip
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<const DescriptorSetLayoutBinding*> GatherBindingsOfTypeSorted(
|
||||
const DescriptorSetLayoutDesc& setLayout,
|
||||
DescriptorType type) {
|
||||
std::vector<const DescriptorSetLayoutBinding*> bindings;
|
||||
bindings.reserve(setLayout.bindingCount);
|
||||
|
||||
for (uint32_t bindingIndex = 0; bindingIndex < setLayout.bindingCount; ++bindingIndex) {
|
||||
const DescriptorSetLayoutBinding& binding = setLayout.bindings[bindingIndex];
|
||||
if (static_cast<DescriptorType>(binding.type) == type) {
|
||||
bindings.push_back(&binding);
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(
|
||||
bindings.begin(),
|
||||
bindings.end(),
|
||||
[](const DescriptorSetLayoutBinding* left, const DescriptorSetLayoutBinding* right) {
|
||||
return left->binding < right->binding;
|
||||
});
|
||||
|
||||
return bindings;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool OpenGLPipelineLayout::Initialize(const RHIPipelineLayoutDesc& desc) {
|
||||
m_desc = desc;
|
||||
m_setBindingPointMappings.clear();
|
||||
m_setLayouts.clear();
|
||||
m_setLayoutBindings.clear();
|
||||
|
||||
@@ -62,14 +88,164 @@ bool OpenGLPipelineLayout::Initialize(const RHIPipelineLayoutDesc& desc) {
|
||||
|
||||
m_desc.setLayouts = m_setLayouts.data();
|
||||
m_desc.setLayoutCount = static_cast<uint32_t>(m_setLayouts.size());
|
||||
|
||||
m_setBindingPointMappings.assign(m_desc.setLayoutCount, SetBindingPointMapping{});
|
||||
|
||||
uint32_t nextCBVBindingPoint = 0;
|
||||
uint32_t nextSRVBindingPoint = 0;
|
||||
uint32_t nextUAVBindingPoint = 0;
|
||||
uint32_t nextSamplerBindingPoint = 0;
|
||||
|
||||
for (uint32_t setIndex = 0; setIndex < m_desc.setLayoutCount; ++setIndex) {
|
||||
const DescriptorSetLayoutDesc& setLayout = m_desc.setLayouts[setIndex];
|
||||
SetBindingPointMapping& mapping = m_setBindingPointMappings[setIndex];
|
||||
|
||||
const auto appendBindings =
|
||||
[&setLayout](
|
||||
DescriptorType type,
|
||||
std::unordered_map<uint32_t, uint32_t>& bindingPoints,
|
||||
uint32_t& nextBindingPoint) {
|
||||
const auto bindings = GatherBindingsOfTypeSorted(setLayout, type);
|
||||
for (const DescriptorSetLayoutBinding* binding : bindings) {
|
||||
bindingPoints[binding->binding] = nextBindingPoint;
|
||||
nextBindingPoint += binding->count > 0 ? binding->count : 1u;
|
||||
}
|
||||
};
|
||||
|
||||
appendBindings(
|
||||
DescriptorType::CBV,
|
||||
mapping.constantBufferBindingPoints,
|
||||
nextCBVBindingPoint);
|
||||
appendBindings(
|
||||
DescriptorType::SRV,
|
||||
mapping.shaderResourceBindingPoints,
|
||||
nextSRVBindingPoint);
|
||||
appendBindings(
|
||||
DescriptorType::UAV,
|
||||
mapping.unorderedAccessBindingPoints,
|
||||
nextUAVBindingPoint);
|
||||
appendBindings(
|
||||
DescriptorType::Sampler,
|
||||
mapping.samplerBindingPoints,
|
||||
nextSamplerBindingPoint);
|
||||
}
|
||||
}
|
||||
|
||||
m_initialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenGLPipelineLayout::HasConstantBufferBinding(uint32_t setIndex, uint32_t binding) const {
|
||||
if (!UsesSetLayouts()) {
|
||||
return setIndex == 0;
|
||||
}
|
||||
|
||||
if (setIndex >= m_setBindingPointMappings.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_setBindingPointMappings[setIndex].constantBufferBindingPoints.find(binding) !=
|
||||
m_setBindingPointMappings[setIndex].constantBufferBindingPoints.end();
|
||||
}
|
||||
|
||||
uint32_t OpenGLPipelineLayout::GetConstantBufferBindingPoint(uint32_t setIndex, uint32_t binding) const {
|
||||
if (!UsesSetLayouts()) {
|
||||
return setIndex == 0 ? binding : UINT32_MAX;
|
||||
}
|
||||
|
||||
if (setIndex >= m_setBindingPointMappings.size()) {
|
||||
return UINT32_MAX;
|
||||
}
|
||||
|
||||
const auto& bindingPoints = m_setBindingPointMappings[setIndex].constantBufferBindingPoints;
|
||||
auto it = bindingPoints.find(binding);
|
||||
return it != bindingPoints.end() ? it->second : UINT32_MAX;
|
||||
}
|
||||
|
||||
bool OpenGLPipelineLayout::HasShaderResourceBinding(uint32_t setIndex, uint32_t binding) const {
|
||||
if (!UsesSetLayouts()) {
|
||||
return setIndex == 0;
|
||||
}
|
||||
|
||||
if (setIndex >= m_setBindingPointMappings.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_setBindingPointMappings[setIndex].shaderResourceBindingPoints.find(binding) !=
|
||||
m_setBindingPointMappings[setIndex].shaderResourceBindingPoints.end();
|
||||
}
|
||||
|
||||
uint32_t OpenGLPipelineLayout::GetShaderResourceBindingPoint(uint32_t setIndex, uint32_t binding) const {
|
||||
if (!UsesSetLayouts()) {
|
||||
return setIndex == 0 ? binding : UINT32_MAX;
|
||||
}
|
||||
|
||||
if (setIndex >= m_setBindingPointMappings.size()) {
|
||||
return UINT32_MAX;
|
||||
}
|
||||
|
||||
const auto& bindingPoints = m_setBindingPointMappings[setIndex].shaderResourceBindingPoints;
|
||||
auto it = bindingPoints.find(binding);
|
||||
return it != bindingPoints.end() ? it->second : UINT32_MAX;
|
||||
}
|
||||
|
||||
bool OpenGLPipelineLayout::HasUnorderedAccessBinding(uint32_t setIndex, uint32_t binding) const {
|
||||
if (!UsesSetLayouts()) {
|
||||
return setIndex == 0;
|
||||
}
|
||||
|
||||
if (setIndex >= m_setBindingPointMappings.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_setBindingPointMappings[setIndex].unorderedAccessBindingPoints.find(binding) !=
|
||||
m_setBindingPointMappings[setIndex].unorderedAccessBindingPoints.end();
|
||||
}
|
||||
|
||||
uint32_t OpenGLPipelineLayout::GetUnorderedAccessBindingPoint(uint32_t setIndex, uint32_t binding) const {
|
||||
if (!UsesSetLayouts()) {
|
||||
return setIndex == 0 ? binding : UINT32_MAX;
|
||||
}
|
||||
|
||||
if (setIndex >= m_setBindingPointMappings.size()) {
|
||||
return UINT32_MAX;
|
||||
}
|
||||
|
||||
const auto& bindingPoints = m_setBindingPointMappings[setIndex].unorderedAccessBindingPoints;
|
||||
auto it = bindingPoints.find(binding);
|
||||
return it != bindingPoints.end() ? it->second : UINT32_MAX;
|
||||
}
|
||||
|
||||
bool OpenGLPipelineLayout::HasSamplerBinding(uint32_t setIndex, uint32_t binding) const {
|
||||
if (!UsesSetLayouts()) {
|
||||
return setIndex == 0;
|
||||
}
|
||||
|
||||
if (setIndex >= m_setBindingPointMappings.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_setBindingPointMappings[setIndex].samplerBindingPoints.find(binding) !=
|
||||
m_setBindingPointMappings[setIndex].samplerBindingPoints.end();
|
||||
}
|
||||
|
||||
uint32_t OpenGLPipelineLayout::GetSamplerBindingPoint(uint32_t setIndex, uint32_t binding) const {
|
||||
if (!UsesSetLayouts()) {
|
||||
return setIndex == 0 ? binding : UINT32_MAX;
|
||||
}
|
||||
|
||||
if (setIndex >= m_setBindingPointMappings.size()) {
|
||||
return UINT32_MAX;
|
||||
}
|
||||
|
||||
const auto& bindingPoints = m_setBindingPointMappings[setIndex].samplerBindingPoints;
|
||||
auto it = bindingPoints.find(binding);
|
||||
return it != bindingPoints.end() ? it->second : UINT32_MAX;
|
||||
}
|
||||
|
||||
void OpenGLPipelineLayout::Shutdown() {
|
||||
m_desc = {};
|
||||
m_setBindingPointMappings.clear();
|
||||
m_setLayouts.clear();
|
||||
m_setLayoutBindings.clear();
|
||||
m_initialized = false;
|
||||
|
||||
Reference in New Issue
Block a user