Vulkan UBO传递错误

时间:2017-11-10 17:30:19

标签: c++ glsl vulkan

我想将包含两个4x4矩阵的统一缓冲区对象传递给顶点着色器。我在C ++中声明了结构如下:

struct PerRenderUBO
{
    glm::mat4 viewProjection;
    glm::mat4 projection; //unused
};

在GLSL中:

layout(std140, set = 0, binding = 0) uniform UBO {
    mat4 viewProjection;
    mat4 projection; //unused
} perRenderUBO;

但是,只要我在UBO结构中声明多个成员,由于viewProjection矩阵错误,一些对象就会被错误地绘制。如果我发表评论'投影'一切都在PerRenderUBO结构和GLSL声明中,一切都正确呈现(虽然我甚至没有使用着色器中的投影)。

这让我相信数据对齐肯定存在问题。我已经使用std140注释声明了布局。 sizeof(PerRenderUBO)返回128.我试图宣布'投影'浮动,问题仍然存在。

以下是描述符集创建的最重要部分:

/** Create Layout **/
vk::DescriptorSetLayoutBinding perRenderUBOBinding;
perRenderUBOBinding.binding = 0;
perRenderUBOBinding.descriptorCount = 1;
perRenderUBOBinding.descriptorType = vk::DescriptorType::eUniformBuffer;
perRenderUBOBinding.stageFlags = vk::ShaderStageFlagBits::eVertex;
perRenderUBOBinding.pImmutableSamplers = nullptr;

std::vector<vk::DescriptorSetLayoutBinding> bindings{perRenderUBOBinding};

vk::DescriptorSetLayoutCreateInfo createInfo;
createInfo.bindingCount = bindings.size();
createInfo.pBindings = bindings.data();
this->perRenderUBOLayout = vkDevice->createDescriptorSetLayout(createInfo);

/** Create host-visible and host-coherent buffer **/
vk::BufferCreateInfo bufferCreateInfo;
bufferCreateInfo.size = sizeof(PerRenderUBO);
bufferCreateInfo.usage = vk::BufferUsageFlagBits::eUniformBuffer;
bufferCreateInfo.sharingMode = vk::SharingMode::eExclusive;
bufferCreateInfo.queueFamilyIndexCount = queueFamilyIndices.size();
bufferCreateInfo.pQueueFamilyIndices = queueFamilyIndices.data();
this->buffer = vkDevice->createBuffer(bufferCreateInfo);

vk::MemoryRequirements memoryRequirements = vkDevice->getBufferMemoryRequirements(this->buffer);
//allocates device memory as proposed in the specification (10.2 Device Memory)
this->bufferDeviceMemory = allocate(memoryRequirements, vk::MemoryPropertyFlags{vk::MemoryPropertyFlagBits::eHostVisible} | vk::MemoryPropertyFlags{vk::MemoryPropertyFlagBits::eHostCoherent});
vkDevice->bindBufferMemory(this->buffer, this->bufferDeviceMemory, 0);


this->descriptorPool = ...//create a descriptor pool for 1 uniform buffer
this->descriptorSet = ...//allocate descriptor set for above layout

vk::DescriptorBufferInfo bufferInfo;
bufferInfo.buffer = this->buffer;
bufferInfo.offset = 0;
bufferInfo.range = sizeof(PerRenderUBO);

vk::WriteDescriptorSet writeDescriptorSet;
writeDescriptorSet.dstSet = *this->descriptorSet;
writeDescriptorSet.dstBinding = 0;
writeDescriptorSet.dstArrayElement = 0;
writeDescriptorSet.descriptorType = vk::DescriptorType::eUniformBuffer;
writeDescriptorSet.descriptorCount = 1;
writeDescriptorSet.pBufferInfo = &bufferInfo;
writeDescriptorSet.pImageInfo = nullptr;
writeDescriptorSet.pTexelBufferView = nullptr;

vkDevice->updateDescriptorSets({writeDescriptorSet}, {});

在执行主绘制命令缓冲区之前,我更新了PerRenderUBO的缓冲区,如下所示:

std::vector<PerRenderUBO> data; //contains 1 instance of PerRenderUBO
vk::DeviceSize offset = 0;
vk::DeviceSize size = data.size() * sizeof(PerRenderUBO);

void* memory = vkDevice->mapMemory(this->bufferDeviceMemory, offset, size);
std::memcpy(memory, data.data(), size);
this->deviceMemory->unmap();

我已多次检查缓冲区大小和偏移量,一切看起来都很好。此外,由于每个绘图命令都绑定了相同的描述符集,并且某些对象正确呈现,我相信缓冲区本身的数据必须正确。 我错过了什么?

1 个答案:

答案 0 :(得分:1)

某些对象绘制不正确且某些对象正确的事实可能表明同步问题或缓冲区未及时更新。

首先您需要通知驱动程序主机更新缓冲区的哪些部分。我没有看到这样的代码,你也没有提到它。这是通过刷新内存来完成的 - 您需要调用 vkFlushMappedMemoryRanges()函数。

您可能还需要设置一个屏障,通知驱动程序主机访问了缓冲区。但据我记得,这个障碍是在命令缓冲区提交时隐式设置的。