Rework offset and size calculations

Refs #1045
This commit is contained in:
Sascha Willems 2023-10-29 18:11:08 +01:00
parent 94198a7548
commit e006185ca0

View file

@ -31,14 +31,6 @@ public:
VkPipeline pipeline; VkPipeline pipeline;
VkPipelineLayout pipelineLayout; VkPipelineLayout pipelineLayout;
VkDescriptorSetLayout descriptorSetLayoutBuffers;
VkDescriptorSetLayout descriptorSetLayoutImages;
vks::Buffer resourceDescriptorBuffer;
vks::Buffer imageDescriptorBuffer;
VkDeviceOrHostAddressConstKHR resourceDescriptorBufferDeviceAddress;
VkDeviceOrHostAddressConstKHR imageDescriptorBufferDeviceAddress;
PFN_vkGetBufferDeviceAddressKHR vkGetBufferDeviceAddressKHR; PFN_vkGetBufferDeviceAddressKHR vkGetBufferDeviceAddressKHR;
VkPhysicalDeviceDescriptorBufferFeaturesEXT enabledDeviceDescriptorBufferFeaturesEXT{}; VkPhysicalDeviceDescriptorBufferFeaturesEXT enabledDeviceDescriptorBufferFeaturesEXT{};
@ -52,8 +44,16 @@ public:
PFN_vkGetDescriptorEXT vkGetDescriptorEXT; PFN_vkGetDescriptorEXT vkGetDescriptorEXT;
PFN_vkCmdBindDescriptorBufferEmbeddedSamplersEXT vkCmdBindDescriptorBufferEmbeddedSamplersEXT; PFN_vkCmdBindDescriptorBufferEmbeddedSamplersEXT vkCmdBindDescriptorBufferEmbeddedSamplersEXT;
VkDeviceSize uniformDescriptorOffset; // Stores all values that are required to setup a descriptor buffer for a resource buffer
VkDeviceSize imageDescriptorOffset; struct DescriptorInfo {
VkDeviceSize layoutOffset;
VkDeviceSize layoutSize;
VkDescriptorSetLayout setLayout;
VkDeviceOrHostAddressConstKHR bufferDeviceAddress;
vks::Buffer buffer;
};
DescriptorInfo uniformDescriptor{};
DescriptorInfo combinedImageDescriptor{};
uint64_t getBufferDeviceAddress(VkBuffer buffer) uint64_t getBufferDeviceAddress(VkBuffer buffer)
{ {
@ -94,8 +94,8 @@ public:
~VulkanExample() ~VulkanExample()
{ {
vkDestroyDescriptorSetLayout(device, descriptorSetLayoutBuffers, nullptr); vkDestroyDescriptorSetLayout(device, uniformDescriptor.setLayout, nullptr);
vkDestroyDescriptorSetLayout(device, descriptorSetLayoutImages, nullptr); vkDestroyDescriptorSetLayout(device, combinedImageDescriptor.setLayout, nullptr);
vkDestroyPipeline(device, pipeline, nullptr); vkDestroyPipeline(device, pipeline, nullptr);
vkDestroyPipelineLayout(device, pipelineLayout, nullptr); vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
for (auto cube : cubes) { for (auto cube : cubes) {
@ -103,8 +103,8 @@ public:
cube.texture.destroy(); cube.texture.destroy();
} }
uniformBufferCamera.destroy(); uniformBufferCamera.destroy();
resourceDescriptorBuffer.destroy(); uniformDescriptor.buffer.destroy();
imageDescriptorBuffer.destroy(); combinedImageDescriptor.buffer.destroy();
} }
virtual void getEnabledFeatures() virtual void getEnabledFeatures()
@ -129,7 +129,7 @@ public:
setLayoutBinding.descriptorCount = 1; setLayoutBinding.descriptorCount = 1;
descriptorLayoutCI.pBindings = &setLayoutBinding; descriptorLayoutCI.pBindings = &setLayoutBinding;
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayoutCI, nullptr, &descriptorSetLayoutBuffers)); VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayoutCI, nullptr, &uniformDescriptor.setLayout));
setLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; setLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
setLayoutBinding.binding = 0; setLayoutBinding.binding = 0;
@ -137,7 +137,7 @@ public:
setLayoutBinding.descriptorCount = 1; setLayoutBinding.descriptorCount = 1;
descriptorLayoutCI.pBindings = &setLayoutBinding; descriptorLayoutCI.pBindings = &setLayoutBinding;
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayoutCI, nullptr, &descriptorSetLayoutImages)); VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayoutCI, nullptr, &combinedImageDescriptor.setLayout));
} }
void preparePipelines() void preparePipelines()
@ -145,7 +145,7 @@ public:
// Set 0 = Camera UBO // Set 0 = Camera UBO
// Set 1 = Model UBO // Set 1 = Model UBO
// Set 2 = Model image // Set 2 = Model image
const std::array<VkDescriptorSetLayout, 3> setLayouts = { descriptorSetLayoutBuffers, descriptorSetLayoutBuffers, descriptorSetLayoutImages }; const std::array<VkDescriptorSetLayout, 3> setLayouts = { uniformDescriptor.setLayout, uniformDescriptor.setLayout, combinedImageDescriptor.setLayout };
VkPipelineLayoutCreateInfo pipelineLayoutCI{}; VkPipelineLayoutCreateInfo pipelineLayoutCI{};
pipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
@ -186,27 +186,9 @@ public:
void prepareDescriptorBuffer() void prepareDescriptorBuffer()
{ {
std::array<VkDeviceSize, 2> descriptorLayoutSizes{}; // We need to get sizes and offsets for the descriptor layouts
vkGetDescriptorSetLayoutSizeEXT(device, descriptorSetLayoutBuffers, &descriptorLayoutSizes[0]);
vkGetDescriptorSetLayoutSizeEXT(device, descriptorSetLayoutImages, &descriptorLayoutSizes[1]);
VK_CHECK_RESULT(vulkanDevice->createBuffer(
VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
&resourceDescriptorBuffer,
3 * descriptorLayoutSizes[0]));
resourceDescriptorBuffer.map();
VK_CHECK_RESULT(vulkanDevice->createBuffer(
VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT | VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, // Flags 1 & 2 are required for combined images
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
&imageDescriptorBuffer,
2 * descriptorLayoutSizes[1]));
imageDescriptorBuffer.map();
resourceDescriptorBufferDeviceAddress.deviceAddress = getBufferDeviceAddress(resourceDescriptorBuffer.buffer);
imageDescriptorBufferDeviceAddress.deviceAddress = getBufferDeviceAddress(imageDescriptorBuffer.buffer);
// This is done using a new extension structures and features
PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR = reinterpret_cast<PFN_vkGetPhysicalDeviceProperties2KHR>(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties2KHR")); PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR = reinterpret_cast<PFN_vkGetPhysicalDeviceProperties2KHR>(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties2KHR"));
assert(vkGetPhysicalDeviceProperties2KHR); assert(vkGetPhysicalDeviceProperties2KHR);
VkPhysicalDeviceProperties2KHR deviceProps2{}; VkPhysicalDeviceProperties2KHR deviceProps2{};
@ -215,33 +197,59 @@ public:
deviceProps2.pNext = &descriptorBufferProperties; deviceProps2.pNext = &descriptorBufferProperties;
vkGetPhysicalDeviceProperties2KHR(physicalDevice, &deviceProps2); vkGetPhysicalDeviceProperties2KHR(physicalDevice, &deviceProps2);
// We need buffer offsets in some places, which are implementation depenendend, so we get them from the decsriptor buffer properties structure vkGetDescriptorSetLayoutSizeEXT(device, uniformDescriptor.setLayout, &uniformDescriptor.layoutSize);
uniformDescriptorOffset = vks::tools::alignedSize(descriptorBufferProperties.uniformBufferDescriptorSize, descriptorBufferProperties.descriptorBufferOffsetAlignment); vkGetDescriptorSetLayoutSizeEXT(device, combinedImageDescriptor.setLayout, &combinedImageDescriptor.layoutSize);
imageDescriptorOffset = vks::tools::alignedSize(descriptorBufferProperties.combinedImageSamplerDescriptorSize, descriptorBufferProperties.descriptorBufferOffsetAlignment);
VkDescriptorGetInfoEXT desc_info = { VK_STRUCTURE_TYPE_DESCRIPTOR_GET_INFO_EXT }; vkGetDescriptorSetLayoutBindingOffsetEXT(device, uniformDescriptor.setLayout, 0, &uniformDescriptor.layoutOffset);
vkGetDescriptorSetLayoutBindingOffsetEXT(device, combinedImageDescriptor.setLayout, 0, &combinedImageDescriptor.layoutOffset);
// Set descriptors for images // In order to copy resource descriptors to the correct place, we need to calculate aligned sizes
char* imageDescriptorBufPtr = (char*)imageDescriptorBuffer.mapped; uniformDescriptor.layoutSize = vks::tools::alignedSize(uniformDescriptor.layoutSize, descriptorBufferProperties.descriptorBufferOffsetAlignment);
desc_info.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; combinedImageDescriptor.layoutSize = vks::tools::alignedSize(combinedImageDescriptor.layoutSize, descriptorBufferProperties.descriptorBufferOffsetAlignment);
// This buffer will contain resource descriptors for all the uniform buffers (one per cube and one with global matrices)
VK_CHECK_RESULT(vulkanDevice->createBuffer(
VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
&uniformDescriptor.buffer,
(static_cast<uint32_t>(cubes.size()) + 1) * uniformDescriptor.layoutSize));
uniformDescriptor.buffer.map();
// This buffer contains resource descriptors for the combined images (one per cube)
VK_CHECK_RESULT(vulkanDevice->createBuffer(
VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT | VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, // Flags 1 & 2 are required for combined images
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
&combinedImageDescriptor.buffer,
static_cast<uint32_t>(cubes.size()) * combinedImageDescriptor.layoutSize));
combinedImageDescriptor.buffer.map();
uniformDescriptor.bufferDeviceAddress.deviceAddress = getBufferDeviceAddress(uniformDescriptor.buffer.buffer);
combinedImageDescriptor.bufferDeviceAddress.deviceAddress = getBufferDeviceAddress(combinedImageDescriptor.buffer.buffer);
VkDescriptorGetInfoEXT descriptorInfo{};
descriptorInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_GET_INFO_EXT;
// Put image descriptors into the corresponding resource buffer
char* imageDescriptorBufPtr = (char*)combinedImageDescriptor.buffer.mapped;
descriptorInfo.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
for (uint32_t i = 0; i < static_cast<uint32_t>(cubes.size()); i++) { for (uint32_t i = 0; i < static_cast<uint32_t>(cubes.size()); i++) {
desc_info.data.pCombinedImageSampler = &cubes[i].texture.descriptor; descriptorInfo.data.pCombinedImageSampler = &cubes[i].texture.descriptor;
vkGetDescriptorEXT(device, &desc_info, descriptorBufferProperties.combinedImageSamplerDescriptorSize, imageDescriptorBufPtr + i * imageDescriptorOffset); vkGetDescriptorEXT(device, &descriptorInfo, descriptorBufferProperties.combinedImageSamplerDescriptorSize, imageDescriptorBufPtr + i * uniformDescriptor.layoutSize + uniformDescriptor.layoutOffset);
} }
// For uniform buffers we only need buffer device addresses // For uniform buffers we only need buffer device addresses
// Global uniform buffer // Global uniform buffer
char* uniformDescriptorBufPtr = (char*)resourceDescriptorBuffer.mapped; char* uniformDescriptorBufPtr = (char*)uniformDescriptor.buffer.mapped;
VkDescriptorAddressInfoEXT descriptorAddressInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_ADDRESS_INFO_EXT }; VkDescriptorAddressInfoEXT descriptorAddressInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_ADDRESS_INFO_EXT };
descriptorAddressInfo.address = getBufferDeviceAddress(uniformBufferCamera.buffer); descriptorAddressInfo.address = getBufferDeviceAddress(uniformBufferCamera.buffer);
descriptorAddressInfo.range = uniformBufferCamera.size; descriptorAddressInfo.range = uniformBufferCamera.size;
descriptorAddressInfo.format = VK_FORMAT_UNDEFINED; descriptorAddressInfo.format = VK_FORMAT_UNDEFINED;
desc_info.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; descriptorInfo.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
desc_info.data.pCombinedImageSampler = nullptr; descriptorInfo.data.pCombinedImageSampler = nullptr;
desc_info.data.pUniformBuffer = &descriptorAddressInfo; descriptorInfo.data.pUniformBuffer = &descriptorAddressInfo;
vkGetDescriptorEXT(device, &desc_info, descriptorBufferProperties.uniformBufferDescriptorSize, uniformDescriptorBufPtr); vkGetDescriptorEXT(device, &descriptorInfo, descriptorBufferProperties.uniformBufferDescriptorSize, uniformDescriptorBufPtr);
// Per-model uniform buffers // Per-model uniform buffers
for (uint32_t i = 0; i < static_cast<uint32_t>(cubes.size()); i++) { for (uint32_t i = 0; i < static_cast<uint32_t>(cubes.size()); i++) {
@ -250,14 +258,13 @@ public:
addr_info.range = cubes[i].uniformBuffer.size; addr_info.range = cubes[i].uniformBuffer.size;
addr_info.format = VK_FORMAT_UNDEFINED; addr_info.format = VK_FORMAT_UNDEFINED;
desc_info.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; descriptorInfo.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
desc_info.data.pCombinedImageSampler = nullptr; descriptorInfo.data.pCombinedImageSampler = nullptr;
desc_info.data.pUniformBuffer = &addr_info; descriptorInfo.data.pUniformBuffer = &addr_info;
vkGetDescriptorEXT(device, &desc_info, descriptorBufferProperties.uniformBufferDescriptorSize, uniformDescriptorBufPtr + (i + 1) * uniformDescriptorOffset); vkGetDescriptorEXT(device, &descriptorInfo, descriptorBufferProperties.uniformBufferDescriptorSize, uniformDescriptorBufPtr + (i + 1) * uniformDescriptor.layoutSize + uniformDescriptor.layoutOffset);
} }
} }
void buildCommandBuffers() void buildCommandBuffers()
{ {
VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo(); VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();
@ -297,12 +304,12 @@ public:
// Set 0 = uniform buffer // Set 0 = uniform buffer
VkDescriptorBufferBindingInfoEXT bindingInfos[2]{}; VkDescriptorBufferBindingInfoEXT bindingInfos[2]{};
bindingInfos[0].sType = VK_STRUCTURE_TYPE_DESCRIPTOR_BUFFER_BINDING_INFO_EXT; bindingInfos[0].sType = VK_STRUCTURE_TYPE_DESCRIPTOR_BUFFER_BINDING_INFO_EXT;
bindingInfos[0].address = resourceDescriptorBufferDeviceAddress.deviceAddress; bindingInfos[0].address = uniformDescriptor.bufferDeviceAddress.deviceAddress;
bindingInfos[0].usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT;// | VK_BUFFER_USAGE_PUSH_DESCRIPTORS_DESCRIPTOR_BUFFER_BIT_EXT; bindingInfos[0].usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT;// | VK_BUFFER_USAGE_PUSH_DESCRIPTORS_DESCRIPTOR_BUFFER_BIT_EXT;
// Set 1 = Image // Set 1 = Image
bindingInfos[1].sType = VK_STRUCTURE_TYPE_DESCRIPTOR_BUFFER_BINDING_INFO_EXT; bindingInfos[1].sType = VK_STRUCTURE_TYPE_DESCRIPTOR_BUFFER_BINDING_INFO_EXT;
bindingInfos[1].pNext = nullptr; bindingInfos[1].pNext = nullptr;
bindingInfos[1].address = imageDescriptorBufferDeviceAddress.deviceAddress; bindingInfos[1].address = combinedImageDescriptor.bufferDeviceAddress.deviceAddress;
bindingInfos[1].usage = VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT | VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT; bindingInfos[1].usage = VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT | VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT;
vkCmdBindDescriptorBuffersEXT(drawCmdBuffers[i], 2, bindingInfos); vkCmdBindDescriptorBuffersEXT(drawCmdBuffers[i], 2, bindingInfos);
@ -317,11 +324,11 @@ public:
for (uint32_t j = 0; j < static_cast<uint32_t>(cubes.size()); j++) { for (uint32_t j = 0; j < static_cast<uint32_t>(cubes.size()); j++) {
// Uniform buffer (set 1) // Uniform buffer (set 1)
// Model ubos start at offset * 1 (slot 0 is global matrices) // Model ubos start at offset * 1 (slot 0 is global matrices)
bufferOffset = (j + 1) * uniformDescriptorOffset; bufferOffset = (j + 1) * uniformDescriptor.layoutSize;
vkCmdSetDescriptorBufferOffsetsEXT(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 1, 1, &bufferIndexUbo, &bufferOffset); vkCmdSetDescriptorBufferOffsetsEXT(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 1, 1, &bufferIndexUbo, &bufferOffset);
// Image (set 2) // Image (set 2)
uint32_t bufferIndexImage = 1; uint32_t bufferIndexImage = 1;
bufferOffset = j * imageDescriptorOffset; bufferOffset = j * combinedImageDescriptor.layoutSize;
vkCmdSetDescriptorBufferOffsetsEXT(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 2, 1, &bufferIndexImage, &bufferOffset); vkCmdSetDescriptorBufferOffsetsEXT(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 2, 1, &bufferIndexImage, &bufferOffset);
model.draw(drawCmdBuffers[i]); model.draw(drawCmdBuffers[i]);
} }