So, I have a struct like this.
struct bufferDesc {
bool input;
bool isBuffer;
uint32_t size;
};
This should make sense I put it in a vector where the buffer types come before the uniforms.
The message is:
validation layer: vkUpdateDescriptorSets(): pDescriptorWrites[0].pBufferInfo[0].buffer was created with VK_BUFFER_USAGE_2_TRANSFER_DST_BIT|VK_BUFFER_USAGE_2_UNIFORM_BUFFER_BIT, but descriptorType is VK_DESCRIPTOR_TYPE_STORAGE_BUFFER.
The Vulkan spec states: If descriptorType is VK_DESCRIPTOR_TYPE_STORAGE_BUFFER or VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, the buffer member of each element of pBufferInfo must have been created with VK_BUFFER_USAGE_STORAGE_BUFFER_BIT set (https://vulkan.lunarg.com/doc/view/1.4.321.1/windows/antora/spec/latest/chapters/descriptorsets.html#VUID-VkWriteDescriptorSet-descriptorType-00331)
this is my code:
struct BuffReturn {
VkBuffer buffer;
VkDeviceMemory bufferMemory;
};
void MemoryObjects::createBuffers(std::vector<bufferDesc> bufTypes)
{
BufTypes = bufTypes;
for (int i = 0; i < BufTypes.size(); i++) {
assert(!(!BufTypes[i].isBuffer && !BufTypes[i].input), "Uniforms are not output buffers.");
BuffReturn bufs = createBufferAndMemory(i);
buffers.push_back(bufs.buffer);
bufferMemory.push_back(bufs.bufferMemory);
}
}
BuffReturn MemoryObjects::createBufferAndMemory(uint32_t num)
{
VkBuffer buffer = VK_NULL_HANDLE;
VkDeviceMemory memory = VK_NULL_HANDLE;
VkBufferUsageFlags usage;
if (BufTypes[num].isBuffer) {
usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
if (!BufTypes[num].input) usage = usage | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
}
else {
usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
}
VkBufferCreateInfo bufferInfo{};
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferInfo.size = BufTypes[num].size;
bufferInfo.usage = usage;
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
Check(vkCreateBuffer(logicalDevice, &bufferInfo, nullptr, &buffer),
"Could not create compute buffer");
VkMemoryRequirements memReqs;
vkGetBufferMemoryRequirements(logicalDevice, buffer, &memReqs);
VkMemoryAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocInfo.allocationSize = memReqs.size;
if (BufTypes[num].input) {
allocInfo.memoryTypeIndex = FindMemoryIndexByType(memReqs.memoryTypeBits,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
}
else {
allocInfo.memoryTypeIndex = FindMemoryIndexByType(memReqs.memoryTypeBits,
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
}
Check(vkAllocateMemory(logicalDevice, &allocInfo, nullptr, &memory),
"Could not allocate buffer memory");
Check(vkBindBufferMemory(logicalDevice, buffer, memory, 0),
"Could not bind buffer memory");
BuffReturn ret;
ret.buffer = buffer;
ret.bufferMemory = memory;
return ret;
}
void MemoryObjects::createDescriptorSet()
{
// Allocate descriptor set
VkDescriptorSetAllocateInfo descriptorSetAllocInfo{};
descriptorSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
descriptorSetAllocInfo.descriptorSetCount = 1;
descriptorSetAllocInfo.pSetLayouts = &DescriptorSetLayout;
descriptorSetAllocInfo.descriptorPool = DescriptorPool;
Check(vkAllocateDescriptorSets(logicalDevice, &descriptorSetAllocInfo, &DescriptorSet),
"Could not allocate compute descriptor set");
uint32_t bufCnt = 0;
for (uint32_t i = 0; i < (uint32_t)BufTypes.size();i++) {
if (!BufTypes[i].isBuffer) {
break;
}
bufCnt++;
}
assert(bufCnt > 0, "Shader should have at least 1 storage buffer");
// Prepare descriptor buffer info and write structures
std::vector<VkDescriptorBufferInfo> bufferInfos;
bufferInfos.reserve(bufCnt);
std::vector<VkWriteDescriptorSet> writeDescriptors;
for (uint32_t i = 0; i < bufCnt; i++) {
VkDescriptorBufferInfo bufferInfo{};
bufferInfo.buffer = buffers[i];
bufferInfo.offset = 0;
bufferInfo.range = BufTypes[i].size;
bufferInfos.push_back(bufferInfo);
}
VkWriteDescriptorSet write{};
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
write.dstSet = DescriptorSet;
write.dstBinding = 0;
write.descriptorCount = (uint32_t)bufferInfos.size();
write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
write.pBufferInfo = bufferInfos.data();
writeDescriptors.push_back(write);
bufferInfos.clear();
if (bufCnt < (uint32_t)BufTypes.size()) {
for (uint32_t i = bufCnt; i < (uint32_t)BufTypes.size(); i++) {
assert(!BufTypes[i].isBuffer, "Uniform buffers should come after storage buffers.");
VkDescriptorBufferInfo bufferInfo{};
bufferInfo.buffer = buffers[i];
bufferInfo.offset = 0;
bufferInfo.range = BufTypes[i].size;
bufferInfos.push_back(bufferInfo);
}
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
write.dstSet = DescriptorSet;
write.dstBinding = bufCnt;
write.descriptorCount = (uint32_t)bufferInfos.size();
write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
write.pBufferInfo = bufferInfos.data();
writeDescriptors.push_back(write);
}
vkUpdateDescriptorSets(
logicalDevice,
static_cast<uint32_t>(writeDescriptors.size()),
writeDescriptors.data(),
0,
nullptr
);
}