【发布时间】:2017-11-10 17:30:18
【问题描述】:
我想将包含两个 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();
我已经检查了几次缓冲区大小和偏移量,一切看起来都很好。另外,由于每个绘图命令都绑定了相同的描述符集,并且某些对象正确渲染,我相信缓冲区本身的数据必须是正确的。 我错过了什么?
【问题讨论】:
-
能不能也加上实际上传ubo数据的部分?
-
我已经添加了缓冲区创建和缓冲区更新的代码。
-
您只有一个 PerRenderUBO 实例,但您谈论渲染多个对象。每个命令缓冲区是否只有一次绘制(因为您在提交命令缓冲区之前映射/memcpy/unmap)?如果是这样,什么可以确保您在第 N 次抽签完成之前不会覆盖第 N+1 次抽签的 UBO 内容?