mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-11 21:58:31 +09:00
[Fix, Test] (MG_Backend/DirectVulkan): an SSBO block instance array is one binding of N descriptors, so bind every element from its own GL binding point
This commit is contained in:
@@ -2578,6 +2578,16 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
}
|
}
|
||||||
entry.storageBlockNameByBinding[binding] = uniformName;
|
entry.storageBlockNameByBinding[binding] = uniformName;
|
||||||
entry.storageBlockIndexByBinding[binding] = static_cast<Int>(blockIndex);
|
entry.storageBlockIndexByBinding[binding] = static_cast<Int>(blockIndex);
|
||||||
|
|
||||||
|
// A block INSTANCE array is ONE Vulkan binding carrying `count`
|
||||||
|
// descriptors, while GL assigns its elements consecutive binding points
|
||||||
|
// starting at the declared one (GL 4.6 core 7.8). Recording only element 0 -
|
||||||
|
// which is all this used to do - left the layout claiming descriptorCount 1,
|
||||||
|
// so every element past the first read a descriptor nobody wrote and
|
||||||
|
// `b[1].data.length()` answered from an unconstrained buffer instead of its
|
||||||
|
// own bound range (KHR-GL43.shader_storage_buffer_object.-
|
||||||
|
// advanced-unsizedArrayLength-*).
|
||||||
|
entry.bindingDescriptorCounts[binding] = static_cast<Uint16>(std::max<Uint32>(1u, sampler->count));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -677,7 +677,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
Bool UniformManager::ResolveStorageBufferDescriptor(const MG_State::GLState::ProgramObject& program,
|
Bool UniformManager::ResolveStorageBufferDescriptor(const MG_State::GLState::ProgramObject& program,
|
||||||
const ProgramFactory::VkProgramObject& programObj,
|
const ProgramFactory::VkProgramObject& programObj,
|
||||||
Uint32 binding,
|
Uint32 binding, Uint32 element,
|
||||||
VkDescriptorBufferInfo& outBufferInfo) const {
|
VkDescriptorBufferInfo& outBufferInfo) const {
|
||||||
outBufferInfo = {};
|
outBufferInfo = {};
|
||||||
MOBILEGL_ASSERT(m_bufferManager != nullptr, "ResolveStorageBufferDescriptor: buffer manager is null");
|
MOBILEGL_ASSERT(m_bufferManager != nullptr, "ResolveStorageBufferDescriptor: buffer manager is null");
|
||||||
@@ -688,8 +688,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
const Int blockIndex = programObj.storageBlockIndexByBinding[binding];
|
const Int blockIndex = programObj.storageBlockIndexByBinding[binding];
|
||||||
MOBILEGL_ASSERT(blockIndex >= 0, "ResolveStorageBufferDescriptor: no SSBO block mapped to binding %u",
|
MOBILEGL_ASSERT(blockIndex >= 0, "ResolveStorageBufferDescriptor: no SSBO block mapped to binding %u",
|
||||||
binding);
|
binding);
|
||||||
|
// A block instance array declares one block whose elements take consecutive GL binding
|
||||||
|
// points from the declared one (GL 4.6 core 7.8), and the reflection collapses the whole
|
||||||
|
// array to that one block - so the element index IS the offset from its binding.
|
||||||
const GLuint frontendBinding =
|
const GLuint frontendBinding =
|
||||||
GetShaderStorageBlockBinding(program, static_cast<GLuint>(blockIndex));
|
GetShaderStorageBlockBinding(program, static_cast<GLuint>(blockIndex)) + element;
|
||||||
const Uint32 bindingPointCount =
|
const Uint32 bindingPointCount =
|
||||||
static_cast<Uint32>(MG_State::pGLContext->GetBufferBindingPointCount(BufferTarget::ShaderStorage));
|
static_cast<Uint32>(MG_State::pGLContext->GetBufferBindingPointCount(BufferTarget::ShaderStorage));
|
||||||
MOBILEGL_ASSERT(frontendBinding < bindingPointCount,
|
MOBILEGL_ASSERT(frontendBinding < bindingPointCount,
|
||||||
@@ -1416,12 +1419,17 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
dynamicOffsets.clear();
|
dynamicOffsets.clear();
|
||||||
// Arrayed UBO bindings contribute extra buffer infos and dynamic offsets; reserve for
|
// Arrayed UBO bindings contribute extra buffer infos and dynamic offsets; reserve for
|
||||||
// the worst case so the pBufferInfo pointers taken below never dangle on reallocation.
|
// the worst case so the pBufferInfo pointers taken below never dangle on reallocation.
|
||||||
|
// Arrayed SSBO bindings contribute extra buffer infos too (but no dynamic offsets).
|
||||||
Uint32 uboArrayExtra = 0;
|
Uint32 uboArrayExtra = 0;
|
||||||
for (const auto& arrayEntry : programObj.arrayedUniformBlockIndicesByBinding) {
|
for (const auto& arrayEntry : programObj.arrayedUniformBlockIndicesByBinding) {
|
||||||
uboArrayExtra += static_cast<Uint32>(arrayEntry.second.size()) - 1u;
|
uboArrayExtra += static_cast<Uint32>(arrayEntry.second.size()) - 1u;
|
||||||
}
|
}
|
||||||
|
Uint32 ssboArrayExtra = 0;
|
||||||
|
for (const Uint16 count : programObj.bindingDescriptorCounts) {
|
||||||
|
if (count > 1) ssboArrayExtra += static_cast<Uint32>(count) - 1u;
|
||||||
|
}
|
||||||
writes.reserve(m_maxBindings);
|
writes.reserve(m_maxBindings);
|
||||||
bufferInfos.reserve(m_maxBindings + uboArrayExtra);
|
bufferInfos.reserve(m_maxBindings + uboArrayExtra + ssboArrayExtra);
|
||||||
imageInfos.reserve(m_maxBindings);
|
imageInfos.reserve(m_maxBindings);
|
||||||
texelBufferViews.reserve(m_maxBindings);
|
texelBufferViews.reserve(m_maxBindings);
|
||||||
dynamicOffsets.reserve(programObj.dynamicBindings.size() + uboArrayExtra);
|
dynamicOffsets.reserve(programObj.dynamicBindings.size() + uboArrayExtra);
|
||||||
@@ -1493,18 +1501,30 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
write.pTexelBufferView = &texelBufferViews.back();
|
write.pTexelBufferView = &texelBufferViews.back();
|
||||||
writes.push_back(write);
|
writes.push_back(write);
|
||||||
} else if (kind == ProgramFactory::DescriptorBindingKind::StorageBuffer) {
|
} else if (kind == ProgramFactory::DescriptorBindingKind::StorageBuffer) {
|
||||||
VkDescriptorBufferInfo bufferInfo{};
|
// One write per binding, but `descriptorCount` buffer infos: a GLSL block
|
||||||
if (!ResolveStorageBufferDescriptor(program, programObj, binding, bufferInfo)) {
|
// instance array occupies a single binding whose elements each come from their
|
||||||
MGLOG_E(
|
// own GL binding point.
|
||||||
"UniformDescriptorBinder::BindProgramUniformBuffers failed: storage buffer binding %u has no valid descriptor",
|
const Uint32 descriptorCount =
|
||||||
binding);
|
binding < programObj.bindingDescriptorCounts.size()
|
||||||
return false;
|
? std::max<Uint32>(1, programObj.bindingDescriptorCounts[binding])
|
||||||
|
: 1u;
|
||||||
|
const SizeT firstBufferInfoIndex = bufferInfos.size();
|
||||||
|
for (Uint32 element = 0; element < descriptorCount; ++element) {
|
||||||
|
VkDescriptorBufferInfo bufferInfo{};
|
||||||
|
if (!ResolveStorageBufferDescriptor(program, programObj, binding, element, bufferInfo)) {
|
||||||
|
MGLOG_E(
|
||||||
|
"UniformDescriptorBinder::BindProgramUniformBuffers failed: storage buffer binding %u "
|
||||||
|
"element %u has no valid descriptor",
|
||||||
|
binding, element);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bufferInfos.push_back(bufferInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
bufferInfos.push_back(bufferInfo);
|
|
||||||
fastRebindKindsEligible = false;
|
fastRebindKindsEligible = false;
|
||||||
write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||||
write.pBufferInfo = &bufferInfos.back();
|
write.descriptorCount = descriptorCount;
|
||||||
|
write.pBufferInfo = &bufferInfos[firstBufferInfoIndex];
|
||||||
writes.push_back(write);
|
writes.push_back(write);
|
||||||
} else if (kind == ProgramFactory::DescriptorBindingKind::StorageImage) {
|
} else if (kind == ProgramFactory::DescriptorBindingKind::StorageImage) {
|
||||||
VkDescriptorImageInfo imageInfo{};
|
VkDescriptorImageInfo imageInfo{};
|
||||||
|
|||||||
@@ -166,9 +166,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
Bool ResolveTexelBufferDescriptor(const MG_State::GLState::ProgramObject& program,
|
Bool ResolveTexelBufferDescriptor(const MG_State::GLState::ProgramObject& program,
|
||||||
const ProgramFactory::VkProgramObject& programObj, Uint32 binding,
|
const ProgramFactory::VkProgramObject& programObj, Uint32 binding,
|
||||||
Uint32 frameIndex, VkBufferView& outBufferView);
|
Uint32 frameIndex, VkBufferView& outBufferView);
|
||||||
|
// `element` indexes a block INSTANCE array's descriptors; it is 0 for every ordinary
|
||||||
|
// block. Each element resolves through its own GL storage block, and so its own GL
|
||||||
|
// binding point, buffer and glBindBufferRange window.
|
||||||
Bool ResolveStorageBufferDescriptor(const MG_State::GLState::ProgramObject& program,
|
Bool ResolveStorageBufferDescriptor(const MG_State::GLState::ProgramObject& program,
|
||||||
const ProgramFactory::VkProgramObject& programObj, Uint32 binding,
|
const ProgramFactory::VkProgramObject& programObj, Uint32 binding,
|
||||||
VkDescriptorBufferInfo& outBufferInfo) const;
|
Uint32 element, VkDescriptorBufferInfo& outBufferInfo) const;
|
||||||
Bool ResolveStorageImageDescriptor(VkCommandBuffer commandBuffer,
|
Bool ResolveStorageImageDescriptor(VkCommandBuffer commandBuffer,
|
||||||
const MG_State::GLState::ProgramObject& program,
|
const MG_State::GLState::ProgramObject& program,
|
||||||
const ProgramFactory::VkProgramObject& programObj, Uint32 binding,
|
const ProgramFactory::VkProgramObject& programObj, Uint32 binding,
|
||||||
|
|||||||
Reference in New Issue
Block a user