fix(rhi): make opengl descriptor binding set-aware
This commit is contained in:
@@ -10,6 +10,7 @@ namespace XCEngine {
|
|||||||
namespace RHI {
|
namespace RHI {
|
||||||
|
|
||||||
class OpenGLTextureUnitAllocator;
|
class OpenGLTextureUnitAllocator;
|
||||||
|
class OpenGLPipelineLayout;
|
||||||
|
|
||||||
struct DescriptorBinding {
|
struct DescriptorBinding {
|
||||||
uint32_t binding;
|
uint32_t binding;
|
||||||
@@ -30,6 +31,7 @@ public:
|
|||||||
|
|
||||||
void Bind() override;
|
void Bind() override;
|
||||||
void Unbind() override;
|
void Unbind() override;
|
||||||
|
void BindWithPipelineLayout(const OpenGLPipelineLayout* pipelineLayout, uint32_t setIndex);
|
||||||
|
|
||||||
void Update(uint32_t offset, RHIResourceView* view) override;
|
void Update(uint32_t offset, RHIResourceView* view) override;
|
||||||
void UpdateSampler(uint32_t offset, RHISampler* sampler) override;
|
void UpdateSampler(uint32_t offset, RHISampler* sampler) override;
|
||||||
@@ -48,6 +50,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
DescriptorBinding* FindBinding(uint32_t binding);
|
DescriptorBinding* FindBinding(uint32_t binding);
|
||||||
const DescriptorBinding* FindBinding(uint32_t binding) const;
|
const DescriptorBinding* FindBinding(uint32_t binding) const;
|
||||||
|
void EnsureConstantBufferUploaded();
|
||||||
|
|
||||||
OpenGLTextureUnitAllocator* m_allocator;
|
OpenGLTextureUnitAllocator* m_allocator;
|
||||||
std::vector<DescriptorBinding> m_bindings;
|
std::vector<DescriptorBinding> m_bindings;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "../RHIPipelineLayout.h"
|
#include "../RHIPipelineLayout.h"
|
||||||
@@ -9,6 +10,13 @@ namespace RHI {
|
|||||||
|
|
||||||
class OpenGLPipelineLayout : public RHIPipelineLayout {
|
class OpenGLPipelineLayout : public RHIPipelineLayout {
|
||||||
public:
|
public:
|
||||||
|
struct SetBindingPointMapping {
|
||||||
|
std::unordered_map<uint32_t, uint32_t> constantBufferBindingPoints;
|
||||||
|
std::unordered_map<uint32_t, uint32_t> shaderResourceBindingPoints;
|
||||||
|
std::unordered_map<uint32_t, uint32_t> unorderedAccessBindingPoints;
|
||||||
|
std::unordered_map<uint32_t, uint32_t> samplerBindingPoints;
|
||||||
|
};
|
||||||
|
|
||||||
OpenGLPipelineLayout() = default;
|
OpenGLPipelineLayout() = default;
|
||||||
~OpenGLPipelineLayout() override = default;
|
~OpenGLPipelineLayout() override = default;
|
||||||
|
|
||||||
@@ -16,10 +24,21 @@ public:
|
|||||||
void Shutdown() override;
|
void Shutdown() override;
|
||||||
|
|
||||||
void* GetNativeHandle() override { return m_initialized ? this : nullptr; }
|
void* GetNativeHandle() override { return m_initialized ? this : nullptr; }
|
||||||
|
bool UsesSetLayouts() const { return m_desc.setLayoutCount > 0 && m_desc.setLayouts != nullptr; }
|
||||||
|
uint32_t GetSetLayoutCount() const { return m_desc.setLayoutCount; }
|
||||||
|
bool HasConstantBufferBinding(uint32_t setIndex, uint32_t binding) const;
|
||||||
|
uint32_t GetConstantBufferBindingPoint(uint32_t setIndex, uint32_t binding) const;
|
||||||
|
bool HasShaderResourceBinding(uint32_t setIndex, uint32_t binding) const;
|
||||||
|
uint32_t GetShaderResourceBindingPoint(uint32_t setIndex, uint32_t binding) const;
|
||||||
|
bool HasUnorderedAccessBinding(uint32_t setIndex, uint32_t binding) const;
|
||||||
|
uint32_t GetUnorderedAccessBindingPoint(uint32_t setIndex, uint32_t binding) const;
|
||||||
|
bool HasSamplerBinding(uint32_t setIndex, uint32_t binding) const;
|
||||||
|
uint32_t GetSamplerBindingPoint(uint32_t setIndex, uint32_t binding) const;
|
||||||
const RHIPipelineLayoutDesc& GetDesc() const { return m_desc; }
|
const RHIPipelineLayoutDesc& GetDesc() const { return m_desc; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RHIPipelineLayoutDesc m_desc = {};
|
RHIPipelineLayoutDesc m_desc = {};
|
||||||
|
std::vector<SetBindingPointMapping> m_setBindingPointMappings;
|
||||||
std::vector<DescriptorSetLayoutDesc> m_setLayouts;
|
std::vector<DescriptorSetLayoutDesc> m_setLayouts;
|
||||||
std::vector<std::vector<DescriptorSetLayoutBinding>> m_setLayoutBindings;
|
std::vector<std::vector<DescriptorSetLayoutBinding>> m_setLayoutBindings;
|
||||||
bool m_initialized = false;
|
bool m_initialized = false;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "XCEngine/RHI/OpenGL/OpenGLCommandList.h"
|
#include "XCEngine/RHI/OpenGL/OpenGLCommandList.h"
|
||||||
#include "XCEngine/RHI/OpenGL/OpenGLResourceView.h"
|
#include "XCEngine/RHI/OpenGL/OpenGLResourceView.h"
|
||||||
#include "XCEngine/RHI/OpenGL/OpenGLPipelineState.h"
|
#include "XCEngine/RHI/OpenGL/OpenGLPipelineState.h"
|
||||||
|
#include "XCEngine/RHI/OpenGL/OpenGLPipelineLayout.h"
|
||||||
#include "XCEngine/RHI/OpenGL/OpenGLShader.h"
|
#include "XCEngine/RHI/OpenGL/OpenGLShader.h"
|
||||||
#include "XCEngine/RHI/OpenGL/OpenGLFramebuffer.h"
|
#include "XCEngine/RHI/OpenGL/OpenGLFramebuffer.h"
|
||||||
#include "XCEngine/RHI/OpenGL/OpenGLRenderPass.h"
|
#include "XCEngine/RHI/OpenGL/OpenGLRenderPass.h"
|
||||||
@@ -717,12 +718,13 @@ void OpenGLCommandList::SetGraphicsDescriptorSets(
|
|||||||
uint32_t count,
|
uint32_t count,
|
||||||
RHIDescriptorSet** descriptorSets,
|
RHIDescriptorSet** descriptorSets,
|
||||||
RHIPipelineLayout* pipelineLayout) {
|
RHIPipelineLayout* pipelineLayout) {
|
||||||
(void)firstSet;
|
OpenGLPipelineLayout* openGLPipelineLayout = static_cast<OpenGLPipelineLayout*>(pipelineLayout);
|
||||||
(void)pipelineLayout;
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < count; ++i) {
|
for (uint32_t i = 0; i < count; ++i) {
|
||||||
if (descriptorSets[i] != nullptr) {
|
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,
|
uint32_t count,
|
||||||
RHIDescriptorSet** descriptorSets,
|
RHIDescriptorSet** descriptorSets,
|
||||||
RHIPipelineLayout* pipelineLayout) {
|
RHIPipelineLayout* pipelineLayout) {
|
||||||
(void)firstSet;
|
OpenGLPipelineLayout* openGLPipelineLayout = static_cast<OpenGLPipelineLayout*>(pipelineLayout);
|
||||||
(void)pipelineLayout;
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < count; ++i) {
|
for (uint32_t i = 0; i < count; ++i) {
|
||||||
if (descriptorSets[i] != nullptr) {
|
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/OpenGLDescriptorSet.h"
|
||||||
|
#include "XCEngine/RHI/OpenGL/OpenGLPipelineLayout.h"
|
||||||
#include "XCEngine/RHI/OpenGL/OpenGLTextureUnitAllocator.h"
|
#include "XCEngine/RHI/OpenGL/OpenGLTextureUnitAllocator.h"
|
||||||
#include "XCEngine/RHI/OpenGL/OpenGLResourceView.h"
|
#include "XCEngine/RHI/OpenGL/OpenGLResourceView.h"
|
||||||
#include "XCEngine/RHI/OpenGL/OpenGLSampler.h"
|
#include "XCEngine/RHI/OpenGL/OpenGLSampler.h"
|
||||||
@@ -7,6 +8,32 @@
|
|||||||
namespace XCEngine {
|
namespace XCEngine {
|
||||||
namespace RHI {
|
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()
|
OpenGLDescriptorSet::OpenGLDescriptorSet()
|
||||||
: m_allocator(nullptr)
|
: m_allocator(nullptr)
|
||||||
, m_layoutBindings(nullptr)
|
, m_layoutBindings(nullptr)
|
||||||
@@ -97,6 +124,7 @@ void OpenGLDescriptorSet::Shutdown() {
|
|||||||
|
|
||||||
m_bindings.clear();
|
m_bindings.clear();
|
||||||
m_allocator = nullptr;
|
m_allocator = nullptr;
|
||||||
|
m_bound = false;
|
||||||
|
|
||||||
if (m_layoutBindings != nullptr) {
|
if (m_layoutBindings != nullptr) {
|
||||||
delete[] m_layoutBindings;
|
delete[] m_layoutBindings;
|
||||||
@@ -105,6 +133,20 @@ void OpenGLDescriptorSet::Shutdown() {
|
|||||||
m_bindingCount = 0;
|
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) {
|
void OpenGLDescriptorSet::Update(uint32_t offset, RHIResourceView* view) {
|
||||||
if (view == nullptr) {
|
if (view == nullptr) {
|
||||||
return;
|
return;
|
||||||
@@ -134,15 +176,7 @@ void OpenGLDescriptorSet::UpdateSampler(uint32_t offset, RHISampler* sampler) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLDescriptorSet::Bind() {
|
void OpenGLDescriptorSet::Bind() {
|
||||||
if (m_constantBufferDirty && !m_constantBufferData.empty()) {
|
EnsureConstantBufferUploaded();
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_constantBuffer != 0) {
|
if (m_constantBuffer != 0) {
|
||||||
for (const auto& binding : m_bindings) {
|
for (const auto& binding : m_bindings) {
|
||||||
@@ -178,6 +212,56 @@ void OpenGLDescriptorSet::Bind() {
|
|||||||
m_bound = true;
|
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() {
|
void OpenGLDescriptorSet::Unbind() {
|
||||||
for (size_t i = 0; i < m_bindings.size(); ++i) {
|
for (size_t i = 0; i < m_bindings.size(); ++i) {
|
||||||
const auto& binding = m_bindings[i];
|
const auto& binding = m_bindings[i];
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#include "XCEngine/RHI/OpenGL/OpenGLPipelineLayout.h"
|
#include "XCEngine/RHI/OpenGL/OpenGLPipelineLayout.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
namespace XCEngine {
|
namespace XCEngine {
|
||||||
namespace RHI {
|
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
|
} // namespace
|
||||||
|
|
||||||
bool OpenGLPipelineLayout::Initialize(const RHIPipelineLayoutDesc& desc) {
|
bool OpenGLPipelineLayout::Initialize(const RHIPipelineLayoutDesc& desc) {
|
||||||
m_desc = desc;
|
m_desc = desc;
|
||||||
|
m_setBindingPointMappings.clear();
|
||||||
m_setLayouts.clear();
|
m_setLayouts.clear();
|
||||||
m_setLayoutBindings.clear();
|
m_setLayoutBindings.clear();
|
||||||
|
|
||||||
@@ -62,14 +88,164 @@ bool OpenGLPipelineLayout::Initialize(const RHIPipelineLayoutDesc& desc) {
|
|||||||
|
|
||||||
m_desc.setLayouts = m_setLayouts.data();
|
m_desc.setLayouts = m_setLayouts.data();
|
||||||
m_desc.setLayoutCount = static_cast<uint32_t>(m_setLayouts.size());
|
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;
|
m_initialized = true;
|
||||||
return 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() {
|
void OpenGLPipelineLayout::Shutdown() {
|
||||||
m_desc = {};
|
m_desc = {};
|
||||||
|
m_setBindingPointMappings.clear();
|
||||||
m_setLayouts.clear();
|
m_setLayouts.clear();
|
||||||
m_setLayoutBindings.clear();
|
m_setLayoutBindings.clear();
|
||||||
m_initialized = false;
|
m_initialized = false;
|
||||||
|
|||||||
@@ -122,10 +122,10 @@ MatrixBufferData CreateMatrixBufferData() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const char kSphereHlsl[] = R"(
|
const char kSphereHlsl[] = R"(
|
||||||
Texture2D gDiffuseTexture : register(t0);
|
Texture2D gDiffuseTexture : register(t1);
|
||||||
SamplerState gSampler : register(s0);
|
SamplerState gSampler : register(s1);
|
||||||
|
|
||||||
cbuffer MatrixBuffer : register(b0) {
|
cbuffer MatrixBuffer : register(b1) {
|
||||||
float4x4 gProjectionMatrix;
|
float4x4 gProjectionMatrix;
|
||||||
float4x4 gViewMatrix;
|
float4x4 gViewMatrix;
|
||||||
float4x4 gModelMatrix;
|
float4x4 gModelMatrix;
|
||||||
@@ -159,7 +159,7 @@ const char kSphereVertexShader[] = R"(#version 430
|
|||||||
layout(location = 0) in vec4 aPosition;
|
layout(location = 0) in vec4 aPosition;
|
||||||
layout(location = 1) in vec2 aTexCoord;
|
layout(location = 1) in vec2 aTexCoord;
|
||||||
|
|
||||||
layout(std140, binding = 0) uniform MatrixBuffer {
|
layout(std140, binding = 1) uniform MatrixBuffer {
|
||||||
mat4 gProjectionMatrix;
|
mat4 gProjectionMatrix;
|
||||||
mat4 gViewMatrix;
|
mat4 gViewMatrix;
|
||||||
mat4 gModelMatrix;
|
mat4 gModelMatrix;
|
||||||
@@ -176,7 +176,7 @@ void main() {
|
|||||||
)";
|
)";
|
||||||
|
|
||||||
const char kSphereFragmentShader[] = R"(#version 430
|
const char kSphereFragmentShader[] = R"(#version 430
|
||||||
layout(binding = 0) uniform sampler2D uTexture;
|
layout(binding = 1) uniform sampler2D uTexture;
|
||||||
|
|
||||||
in vec2 vTexCoord;
|
in vec2 vTexCoord;
|
||||||
|
|
||||||
@@ -454,8 +454,24 @@ void SphereTest::InitializeSphereResources() {
|
|||||||
ASSERT_NE(mSamplerSet, nullptr);
|
ASSERT_NE(mSamplerSet, nullptr);
|
||||||
mSamplerSet->UpdateSampler(0, mSampler);
|
mSamplerSet->UpdateSampler(0, mSampler);
|
||||||
|
|
||||||
|
DescriptorSetLayoutBinding reservedSetBindings[3] = {};
|
||||||
|
reservedSetBindings[0].binding = 0;
|
||||||
|
reservedSetBindings[0].type = static_cast<uint32_t>(DescriptorType::CBV);
|
||||||
|
reservedSetBindings[0].count = 1;
|
||||||
|
reservedSetBindings[1].binding = 0;
|
||||||
|
reservedSetBindings[1].type = static_cast<uint32_t>(DescriptorType::SRV);
|
||||||
|
reservedSetBindings[1].count = 1;
|
||||||
|
reservedSetBindings[2].binding = 0;
|
||||||
|
reservedSetBindings[2].type = static_cast<uint32_t>(DescriptorType::Sampler);
|
||||||
|
reservedSetBindings[2].count = 1;
|
||||||
|
|
||||||
|
DescriptorSetLayoutDesc reservedLayoutDesc = {};
|
||||||
|
reservedLayoutDesc.bindings = reservedSetBindings;
|
||||||
|
reservedLayoutDesc.bindingCount = 3;
|
||||||
|
|
||||||
DescriptorSetLayoutDesc setLayouts[kSphereDescriptorSetCount] = {};
|
DescriptorSetLayoutDesc setLayouts[kSphereDescriptorSetCount] = {};
|
||||||
// Reserve set0 so the integration test exercises non-zero firstSet binding.
|
// Reserve slot0 so the bound sets land on binding point 1 for every descriptor class.
|
||||||
|
setLayouts[0] = reservedLayoutDesc;
|
||||||
setLayouts[1] = constantLayoutDesc;
|
setLayouts[1] = constantLayoutDesc;
|
||||||
setLayouts[2] = textureLayoutDesc;
|
setLayouts[2] = textureLayoutDesc;
|
||||||
setLayouts[3] = samplerLayoutDesc;
|
setLayouts[3] = samplerLayoutDesc;
|
||||||
|
|||||||
@@ -362,3 +362,59 @@ TEST_P(RHITestFixture, PipelineLayout_D3D12SeparatesOverlappingBindingsAcrossSet
|
|||||||
layout->Shutdown();
|
layout->Shutdown();
|
||||||
delete layout;
|
delete layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_P(RHITestFixture, PipelineLayout_OpenGLSeparatesOverlappingBindingsAcrossSetSlots) {
|
||||||
|
if (GetBackendType() != RHIType::OpenGL) {
|
||||||
|
GTEST_SKIP() << "OpenGL-specific binding point verification";
|
||||||
|
}
|
||||||
|
|
||||||
|
DescriptorSetLayoutBinding set0Bindings[3] = {};
|
||||||
|
set0Bindings[0].binding = 0;
|
||||||
|
set0Bindings[0].type = static_cast<uint32_t>(DescriptorType::CBV);
|
||||||
|
set0Bindings[0].count = 1;
|
||||||
|
set0Bindings[1].binding = 0;
|
||||||
|
set0Bindings[1].type = static_cast<uint32_t>(DescriptorType::SRV);
|
||||||
|
set0Bindings[1].count = 1;
|
||||||
|
set0Bindings[2].binding = 0;
|
||||||
|
set0Bindings[2].type = static_cast<uint32_t>(DescriptorType::Sampler);
|
||||||
|
set0Bindings[2].count = 1;
|
||||||
|
|
||||||
|
DescriptorSetLayoutBinding set1Bindings[3] = {};
|
||||||
|
set1Bindings[0].binding = 0;
|
||||||
|
set1Bindings[0].type = static_cast<uint32_t>(DescriptorType::CBV);
|
||||||
|
set1Bindings[0].count = 1;
|
||||||
|
set1Bindings[1].binding = 0;
|
||||||
|
set1Bindings[1].type = static_cast<uint32_t>(DescriptorType::SRV);
|
||||||
|
set1Bindings[1].count = 1;
|
||||||
|
set1Bindings[2].binding = 0;
|
||||||
|
set1Bindings[2].type = static_cast<uint32_t>(DescriptorType::Sampler);
|
||||||
|
set1Bindings[2].count = 1;
|
||||||
|
|
||||||
|
DescriptorSetLayoutDesc setLayouts[2] = {};
|
||||||
|
setLayouts[0].bindings = set0Bindings;
|
||||||
|
setLayouts[0].bindingCount = 3;
|
||||||
|
setLayouts[1].bindings = set1Bindings;
|
||||||
|
setLayouts[1].bindingCount = 3;
|
||||||
|
|
||||||
|
RHIPipelineLayoutDesc desc = {};
|
||||||
|
desc.setLayouts = setLayouts;
|
||||||
|
desc.setLayoutCount = 2;
|
||||||
|
|
||||||
|
RHIPipelineLayout* layout = GetDevice()->CreatePipelineLayout(desc);
|
||||||
|
ASSERT_NE(layout, nullptr);
|
||||||
|
|
||||||
|
auto* openGLLayout = static_cast<OpenGLPipelineLayout*>(layout);
|
||||||
|
EXPECT_TRUE(openGLLayout->UsesSetLayouts());
|
||||||
|
EXPECT_EQ(openGLLayout->GetSetLayoutCount(), 2u);
|
||||||
|
EXPECT_TRUE(openGLLayout->HasConstantBufferBinding(0, 0));
|
||||||
|
EXPECT_TRUE(openGLLayout->HasConstantBufferBinding(1, 0));
|
||||||
|
EXPECT_EQ(openGLLayout->GetConstantBufferBindingPoint(0, 0), 0u);
|
||||||
|
EXPECT_EQ(openGLLayout->GetConstantBufferBindingPoint(1, 0), 1u);
|
||||||
|
EXPECT_EQ(openGLLayout->GetShaderResourceBindingPoint(0, 0), 0u);
|
||||||
|
EXPECT_EQ(openGLLayout->GetShaderResourceBindingPoint(1, 0), 1u);
|
||||||
|
EXPECT_EQ(openGLLayout->GetSamplerBindingPoint(0, 0), 0u);
|
||||||
|
EXPECT_EQ(openGLLayout->GetSamplerBindingPoint(1, 0), 1u);
|
||||||
|
|
||||||
|
layout->Shutdown();
|
||||||
|
delete layout;
|
||||||
|
}
|
||||||
|
|||||||
@@ -175,6 +175,7 @@ tests/RHI/integration/
|
|||||||
5. 两个后端都必须与同一张 `GT.ppm` 做比对。
|
5. 两个后端都必须与同一张 `GT.ppm` 做比对。
|
||||||
6. 新测试如果暴露抽象层缺口,应先补 RHI,再补测试。
|
6. 新测试如果暴露抽象层缺口,应先补 RHI,再补测试。
|
||||||
7. 至少保留一个场景覆盖 `firstSet != 0` 的描述符绑定路径,当前由 `sphere` 负责验证。
|
7. 至少保留一个场景覆盖 `firstSet != 0` 的描述符绑定路径,当前由 `sphere` 负责验证。
|
||||||
|
8. `sphere` 需要通过预留 `set0` 把实际 shader 绑定点推进到 `binding = 1`,避免出现“忽略 set 语义也能误通过”的假阳性。
|
||||||
|
|
||||||
### 6.3 命名
|
### 6.3 命名
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user