diff --git a/attachments/23_descriptor_sets.cpp b/attachments/23_descriptor_sets.cpp index be42187a..881abc5c 100644 --- a/attachments/23_descriptor_sets.cpp +++ b/attachments/23_descriptor_sets.cpp @@ -44,14 +44,13 @@ struct Vertex static vk::VertexInputBindingDescription getBindingDescription() { - return {0, sizeof(Vertex), vk::VertexInputRate::eVertex}; + return {.binding = 0, .stride = sizeof(Vertex), .inputRate = vk::VertexInputRate::eVertex}; } static std::array getAttributeDescriptions() { - return { - vk::VertexInputAttributeDescription(0, 0, vk::Format::eR32G32Sfloat, offsetof(Vertex, pos)), - vk::VertexInputAttributeDescription(1, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, color))}; + return {{{.location = 0, .binding = 0, .format = vk::Format::eR32G32Sfloat, .offset = offsetof(Vertex, pos)}, + {.location = 1, .binding = 0, .format = vk::Format::eR32G32B32Sfloat, .offset = offsetof(Vertex, color)}}}; } }; @@ -141,7 +140,7 @@ class HelloTriangleApplication static void framebufferResizeCallback(GLFWwindow *window, int width, int height) { - auto app = static_cast(glfwGetWindowUserPointer(window)); + auto app = reinterpret_cast(glfwGetWindowUserPointer(window)); app->framebufferResized = true; } @@ -266,7 +265,7 @@ class HelloTriangleApplication vk::DebugUtilsMessageSeverityFlagsEXT severityFlags(vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning | vk::DebugUtilsMessageSeverityFlagBitsEXT::eError); vk::DebugUtilsMessageTypeFlagsEXT messageTypeFlags( - vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral | vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance | vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation); + vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral | vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance | vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation); vk::DebugUtilsMessengerCreateInfoEXT debugUtilsMessengerCreateInfoEXT{.messageSeverity = severityFlags, .messageType = messageTypeFlags, .pfnUserCallback = &debugCallback}; @@ -308,6 +307,7 @@ class HelloTriangleApplication vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>(); bool supportsRequiredFeatures = features.template get().shaderDrawParameters && features.template get().dynamicRendering && + features.template get().synchronization2 && features.template get().extendedDynamicState; // Return true if the physicalDevice meets all the criteria @@ -346,12 +346,16 @@ class HelloTriangleApplication } // query for required features (Vulkan 1.1 and 1.3) - vk::StructureChain featureChain = { - {}, // vk::PhysicalDeviceFeatures2 - {.shaderDrawParameters = true}, // vk::PhysicalDeviceVulkan11Features - {.synchronization2 = true, .dynamicRendering = true}, // vk::PhysicalDeviceVulkan13Features - {.extendedDynamicState = true} // vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT - }; + vk::StructureChain + featureChain = { + {}, // vk::PhysicalDeviceFeatures2 + {.shaderDrawParameters = true}, // vk::PhysicalDeviceVulkan11Features + {.synchronization2 = true, .dynamicRendering = true}, // vk::PhysicalDeviceVulkan13Features + {.extendedDynamicState = true} // vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT + }; // create a Device float queuePriority = 0.5f; @@ -411,7 +415,8 @@ class HelloTriangleApplication void createDescriptorSetLayout() { - vk::DescriptorSetLayoutBinding uboLayoutBinding(0, vk::DescriptorType::eUniformBuffer, 1, vk::ShaderStageFlagBits::eVertex, nullptr); + vk::DescriptorSetLayoutBinding uboLayoutBinding{ + .binding = 0, .descriptorType = vk::DescriptorType::eUniformBuffer, .descriptorCount = 1, .stageFlags = vk::ShaderStageFlagBits::eVertex}; vk::DescriptorSetLayoutCreateInfo layoutInfo{.bindingCount = 1, .pBindings = &uboLayoutBinding}; descriptorSetLayout = vk::raii::DescriptorSetLayout(device, layoutInfo); } @@ -426,7 +431,10 @@ class HelloTriangleApplication auto bindingDescription = Vertex::getBindingDescription(); auto attributeDescriptions = Vertex::getAttributeDescriptions(); - vk::PipelineVertexInputStateCreateInfo vertexInputInfo{.vertexBindingDescriptionCount = 1, .pVertexBindingDescriptions = &bindingDescription, .vertexAttributeDescriptionCount = static_cast(attributeDescriptions.size()), .pVertexAttributeDescriptions = attributeDescriptions.data()}; + vk::PipelineVertexInputStateCreateInfo vertexInputInfo{.vertexBindingDescriptionCount = 1, + .pVertexBindingDescriptions = &bindingDescription, + .vertexAttributeDescriptionCount = static_cast(attributeDescriptions.size()), + .pVertexAttributeDescriptions = attributeDescriptions.data()}; vk::PipelineInputAssemblyStateCreateInfo inputAssembly{.topology = vk::PrimitiveTopology::eTriangleList}; vk::PipelineViewportStateCreateInfo viewportState{.viewportCount = 1, .scissorCount = 1}; @@ -434,7 +442,7 @@ class HelloTriangleApplication .rasterizerDiscardEnable = vk::False, .polygonMode = vk::PolygonMode::eFill, .cullMode = vk::CullModeFlagBits::eBack, - .frontFace = vk::FrontFace::eClockwise, + .frontFace = vk::FrontFace::eCounterClockwise, .depthBiasEnable = vk::False, .lineWidth = 1.0f}; @@ -450,7 +458,7 @@ class HelloTriangleApplication std::vector dynamicStates = {vk::DynamicState::eViewport, vk::DynamicState::eScissor}; vk::PipelineDynamicStateCreateInfo dynamicState{.dynamicStateCount = static_cast(dynamicStates.size()), .pDynamicStates = dynamicStates.data()}; - vk::PipelineLayoutCreateInfo pipelineLayoutInfo{.setLayoutCount = 0, .pushConstantRangeCount = 0}; + vk::PipelineLayoutCreateInfo pipelineLayoutInfo{.setLayoutCount = 1, .pSetLayouts = &*descriptorSetLayout, .pushConstantRangeCount = 0}; pipelineLayout = vk::raii::PipelineLayout(device, pipelineLayoutInfo); vk::StructureChain pipelineCreateInfoChain = { @@ -477,18 +485,30 @@ class HelloTriangleApplication commandPool = vk::raii::CommandPool(device, poolInfo); } + std::pair createBuffer(vk::DeviceSize size, vk::BufferUsageFlags usage, vk::MemoryPropertyFlags properties) + { + vk::BufferCreateInfo bufferInfo{.size = size, .usage = usage, .sharingMode = vk::SharingMode::eExclusive}; + vk::raii::Buffer buffer = vk::raii::Buffer(device, bufferInfo); + vk::MemoryRequirements memRequirements = buffer.getMemoryRequirements(); + vk::MemoryAllocateInfo allocInfo{.allocationSize = memRequirements.size, .memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties)}; + vk::raii::DeviceMemory bufferMemory = vk::raii::DeviceMemory(device, allocInfo); + buffer.bindMemory(*bufferMemory, 0); + return {std::move(buffer), std::move(bufferMemory)}; + } + void createVertexBuffer() { - vk::DeviceSize bufferSize = sizeof(vertices[0]) * vertices.size(); - vk::raii::Buffer stagingBuffer({}); - vk::raii::DeviceMemory stagingBufferMemory({}); - createBuffer(bufferSize, vk::BufferUsageFlagBits::eTransferSrc, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent, stagingBuffer, stagingBufferMemory); + vk::DeviceSize bufferSize = sizeof(vertices[0]) * vertices.size(); + + auto [stagingBuffer, stagingBufferMemory] = + createBuffer(bufferSize, vk::BufferUsageFlagBits::eTransferSrc, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent); void *dataStaging = stagingBufferMemory.mapMemory(0, bufferSize); memcpy(dataStaging, vertices.data(), bufferSize); stagingBufferMemory.unmapMemory(); - createBuffer(bufferSize, vk::BufferUsageFlagBits::eTransferDst | vk::BufferUsageFlagBits::eVertexBuffer, vk::MemoryPropertyFlagBits::eDeviceLocal, vertexBuffer, vertexBufferMemory); + std::tie(vertexBuffer, vertexBufferMemory) = + createBuffer(bufferSize, vk::BufferUsageFlagBits::eVertexBuffer | vk::BufferUsageFlagBits::eTransferDst, vk::MemoryPropertyFlagBits::eDeviceLocal); copyBuffer(stagingBuffer, vertexBuffer, bufferSize); } @@ -497,40 +517,35 @@ class HelloTriangleApplication { vk::DeviceSize bufferSize = sizeof(indices[0]) * indices.size(); - vk::raii::Buffer stagingBuffer({}); - vk::raii::DeviceMemory stagingBufferMemory({}); - createBuffer(bufferSize, vk::BufferUsageFlagBits::eTransferSrc, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent, stagingBuffer, stagingBufferMemory); + auto [stagingBuffer, stagingBufferMemory] = + createBuffer(bufferSize, vk::BufferUsageFlagBits::eTransferSrc, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent); void *data = stagingBufferMemory.mapMemory(0, bufferSize); memcpy(data, indices.data(), (size_t) bufferSize); stagingBufferMemory.unmapMemory(); - createBuffer(bufferSize, vk::BufferUsageFlagBits::eTransferDst | vk::BufferUsageFlagBits::eIndexBuffer, vk::MemoryPropertyFlagBits::eDeviceLocal, indexBuffer, indexBufferMemory); + std::tie(indexBuffer, indexBufferMemory) = + createBuffer(bufferSize, vk::BufferUsageFlagBits::eIndexBuffer | vk::BufferUsageFlagBits::eTransferDst, vk::MemoryPropertyFlagBits::eDeviceLocal); copyBuffer(stagingBuffer, indexBuffer, bufferSize); } void createUniformBuffers() { - uniformBuffers.clear(); - uniformBuffersMemory.clear(); - uniformBuffersMapped.clear(); - for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - vk::DeviceSize bufferSize = sizeof(UniformBufferObject); - vk::raii::Buffer buffer({}); - vk::raii::DeviceMemory bufferMem({}); - createBuffer(bufferSize, vk::BufferUsageFlagBits::eUniformBuffer, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent, buffer, bufferMem); + vk::DeviceSize bufferSize = sizeof(UniformBufferObject); + auto [buffer, bufferMem] = createBuffer( + bufferSize, vk::BufferUsageFlagBits::eUniformBuffer, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent); uniformBuffers.emplace_back(std::move(buffer)); uniformBuffersMemory.emplace_back(std::move(bufferMem)); - uniformBuffersMapped.emplace_back(uniformBuffersMemory[i].mapMemory(0, bufferSize)); + uniformBuffersMapped.emplace_back(uniformBuffersMemory.back().mapMemory(0, bufferSize)); } } void createDescriptorPool() { - vk::DescriptorPoolSize poolSize(vk::DescriptorType::eUniformBuffer, MAX_FRAMES_IN_FLIGHT); + vk::DescriptorPoolSize poolSize{.type = vk::DescriptorType::eUniformBuffer, .descriptorCount = MAX_FRAMES_IN_FLIGHT}; vk::DescriptorPoolCreateInfo poolInfo{.flags = vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet, .maxSets = MAX_FRAMES_IN_FLIGHT, .poolSizeCount = 1, .pPoolSizes = &poolSize}; descriptorPool = vk::raii::DescriptorPool(device, poolInfo); } @@ -538,33 +553,30 @@ class HelloTriangleApplication void createDescriptorSets() { std::vector layouts(MAX_FRAMES_IN_FLIGHT, *descriptorSetLayout); - vk::DescriptorSetAllocateInfo allocInfo{.descriptorPool = descriptorPool, .descriptorSetCount = static_cast(layouts.size()), .pSetLayouts = layouts.data()}; + vk::DescriptorSetAllocateInfo allocInfo{.descriptorPool = descriptorPool, + .descriptorSetCount = static_cast(layouts.size()), + .pSetLayouts = layouts.data()}; descriptorSets = device.allocateDescriptorSets(allocInfo); for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { vk::DescriptorBufferInfo bufferInfo{.buffer = uniformBuffers[i], .offset = 0, .range = sizeof(UniformBufferObject)}; - vk::WriteDescriptorSet descriptorWrite{.dstSet = descriptorSets[i], .dstBinding = 0, .dstArrayElement = 0, .descriptorCount = 1, .descriptorType = vk::DescriptorType::eUniformBuffer, .pBufferInfo = &bufferInfo}; + vk::WriteDescriptorSet descriptorWrite{.dstSet = descriptorSets[i], + .dstBinding = 0, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = vk::DescriptorType::eUniformBuffer, + .pBufferInfo = &bufferInfo}; device.updateDescriptorSets(descriptorWrite, {}); } } - void createBuffer(vk::DeviceSize size, vk::BufferUsageFlags usage, vk::MemoryPropertyFlags properties, vk::raii::Buffer &buffer, vk::raii::DeviceMemory &bufferMemory) - { - vk::BufferCreateInfo bufferInfo{.size = size, .usage = usage, .sharingMode = vk::SharingMode::eExclusive}; - buffer = vk::raii::Buffer(device, bufferInfo); - vk::MemoryRequirements memRequirements = buffer.getMemoryRequirements(); - vk::MemoryAllocateInfo allocInfo{.allocationSize = memRequirements.size, .memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties)}; - bufferMemory = vk::raii::DeviceMemory(device, allocInfo); - buffer.bindMemory(bufferMemory, 0); - } - void copyBuffer(vk::raii::Buffer &srcBuffer, vk::raii::Buffer &dstBuffer, vk::DeviceSize size) { vk::CommandBufferAllocateInfo allocInfo{.commandPool = commandPool, .level = vk::CommandBufferLevel::ePrimary, .commandBufferCount = 1}; vk::raii::CommandBuffer commandCopyBuffer = std::move(device.allocateCommandBuffers(allocInfo).front()); - commandCopyBuffer.begin(vk::CommandBufferBeginInfo{.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit}); + commandCopyBuffer.begin({.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit}); commandCopyBuffer.copyBuffer(*srcBuffer, *dstBuffer, vk::BufferCopy(0, 0, size)); commandCopyBuffer.end(); queue.submit(vk::SubmitInfo{.commandBufferCount = 1, .pCommandBuffers = &*commandCopyBuffer}, nullptr); @@ -597,7 +609,8 @@ class HelloTriangleApplication { auto &commandBuffer = commandBuffers[frameIndex]; commandBuffer.begin({}); - // Before starting rendering, transition the swapchain image to COLOR_ATTACHMENT_OPTIMAL + + // Before starting rendering, transition the swapchain image to vk::ImageLayout::eColorAttachmentOptimal transition_image_layout( imageIndex, vk::ImageLayout::eUndefined, @@ -624,11 +637,12 @@ class HelloTriangleApplication commandBuffer.setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), 0.0f, 1.0f)); commandBuffer.setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent)); commandBuffer.bindVertexBuffers(0, *vertexBuffer, {0}); - commandBuffer.bindIndexBuffer(*indexBuffer, 0, vk::IndexType::eUint16); + commandBuffer.bindIndexBuffer(*indexBuffer, 0, vk::IndexTypeValue::value); commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, *descriptorSets[frameIndex], nullptr); - commandBuffer.drawIndexed(indices.size(), 1, 0, 0, 0); + commandBuffer.drawIndexed(static_cast(indices.size()), 1, 0, 0, 0); commandBuffer.endRendering(); - // After rendering, transition the swapchain image to PRESENT_SRC + + // After rendering, transition the swapchain image to vk::ImageLayout::ePresentSrcKHR transition_image_layout( imageIndex, vk::ImageLayout::eColorAttachmentOptimal, @@ -661,11 +675,11 @@ class HelloTriangleApplication .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .image = swapChainImages[imageIndex], .subresourceRange = { - .aspectMask = vk::ImageAspectFlagBits::eColor, - .baseMipLevel = 0, - .levelCount = 1, - .baseArrayLayer = 0, - .layerCount = 1}}; + .aspectMask = vk::ImageAspectFlagBits::eColor, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1}}; vk::DependencyInfo dependency_info = { .dependencyFlags = {}, .imageMemoryBarrierCount = 1, @@ -699,7 +713,8 @@ class HelloTriangleApplication UniformBufferObject ubo{}; ubo.model = rotate(glm::mat4(1.0f), time * glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f)); ubo.view = lookAt(glm::vec3(2.0f, 2.0f, 2.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f)); - ubo.proj = glm::perspective(glm::radians(45.0f), static_cast(swapChainExtent.width) / static_cast(swapChainExtent.height), 0.1f, 10.0f); + ubo.proj = + glm::perspective(glm::radians(45.0f), static_cast(swapChainExtent.width) / static_cast(swapChainExtent.height), 0.1f, 10.0f); ubo.proj[1][1] *= -1; memcpy(uniformBuffersMapped[currentImage], &ubo, sizeof(ubo)); @@ -806,7 +821,7 @@ class HelloTriangleApplication vk::PresentModeKHR::eFifo; } - vk::Extent2D chooseSwapExtent(const vk::SurfaceCapabilitiesKHR &capabilities) + vk::Extent2D chooseSwapExtent(vk::SurfaceCapabilitiesKHR const &capabilities) { if (capabilities.currentExtent.width != std::numeric_limits::max()) { diff --git a/en/05_Uniform_buffers/01_Descriptor_pool_and_sets.adoc b/en/05_Uniform_buffers/01_Descriptor_pool_and_sets.adoc index afca51ea..50f1a7a7 100644 --- a/en/05_Uniform_buffers/01_Descriptor_pool_and_sets.adoc +++ b/en/05_Uniform_buffers/01_Descriptor_pool_and_sets.adoc @@ -5,7 +5,7 @@ == Introduction The descriptor set layout from the previous chapter describes the type of descriptors that can be bound. -In this chapter we're going to create a descriptor set for each `VkBuffer` resource to bind it to the uniform buffer descriptor. +In this chapter we're going to create a descriptor set for each `vk::raii::Buffer` resource to bind it to the uniform buffer descriptor. == Descriptor pool @@ -15,7 +15,8 @@ We'll write a new function `createDescriptorPool` to set it up. [,c++] ---- -void initVulkan() { +void initVulkan() +{ ... createUniformBuffers(); createDescriptorPool(); @@ -24,31 +25,30 @@ void initVulkan() { ... -void createDescriptorPool() { - +void createDescriptorPool() +{ } ---- -We first need to describe which descriptor types our descriptor sets are going to contain and how many of them, using `VkDescriptorPoolSize` structures. +We first need to describe which descriptor types our descriptor sets are going to contain and how many of them, using `vk::DescriptorPoolSize` structures. [,c++] ---- -vk::DescriptorPoolSize poolSize(vk::DescriptorType::eUniformBuffer, MAX_FRAMES_IN_FLIGHT); +vk::DescriptorPoolSize poolSize{ .type = vk::DescriptorType::eUniformBuffer, .descriptorCount = MAX_FRAMES_IN_FLIGHT); ---- We will allocate one of these descriptors for every frame. -This pool size structure is referenced by the main `VkDescriptorPoolCreateInfo`: +This pool size structure is referenced by the main `vk::DescriptorPoolCreateInfo`: [,c++] ---- vk::DescriptorPoolCreateInfo poolInfo{ .flags = vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet, .maxSets = MAX_FRAMES_IN_FLIGHT, .poolSizeCount = 1, .pPoolSizes = &poolSize }; ---- -Aside from the maximum number of individual descriptors that are available, we also need to specify the maximum number of descriptor sets that may be allocated: +Aside from the maximum number of individual descriptors that are available, we also need to specify the maximum number of descriptor sets that may be allocated. -The structure has an optional flag similar to command pools that determines if individual descriptor sets can be freed or not: `VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT`. -We're not going to touch the descriptor set after creating it, so we don't need this flag. -You can leave `flags` to its default value of `0`. +The structure has an optional flag similar to command pools that determines if individual descriptor sets can be freed or not. +As the `vk::raii::DescriptorSets` destroy the underlying `VkDescriptorSet` on destruction we need to set it to `vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet` to allow that. [,c++] ---- @@ -59,7 +59,7 @@ vk::raii::DescriptorPool descriptorPool = nullptr; descriptorPool = vk::raii::DescriptorPool(device, poolInfo); ---- -Add a new class member to store the handle of the descriptor pool and call `vkCreateDescriptorPool` to create it. +Add a new class member to store the handle of the descriptor pool and call the `vk::raii::DescriptorPool` constructor to create it. == Descriptor set @@ -68,7 +68,8 @@ Add a `createDescriptorSets` function for that purpose: [,c++] ---- -void initVulkan() { +void initVulkan() +{ ... createDescriptorPool(); createDescriptorSets(); @@ -77,33 +78,34 @@ void initVulkan() { ... -void createDescriptorSets() { - +void createDescriptorSets() +{ } ---- -A descriptor set allocation is described with a `VkDescriptorSetAllocateInfo` struct. +A descriptor set allocation is described with a `vk::DescriptorSetAllocateInfo` struct. You need to specify the descriptor pool to allocate from, the number of descriptor sets to allocate, and the descriptor set layout to base them on: [,c++] ---- std::vector layouts(MAX_FRAMES_IN_FLIGHT, *descriptorSetLayout); -vk::DescriptorSetAllocateInfo allocInfo{ .descriptorPool = descriptorPool, .descriptorSetCount = static_cast(layouts.size()), .pSetLayouts = layouts.data() }; +vk::DescriptorSetAllocateInfo allocInfo{.descriptorPool = descriptorPool, + .descriptorSetCount = static_cast(layouts.size()), + .pSetLayouts = layouts.data()}; ---- In our case, we will create one descriptor set for each frame in flight, all with the same layout. Unfortunately, we do need all the copies of the layout because the next function expects an array matching the number of sets. -Add a class member to hold the descriptor set handles and allocate them with `vkAllocateDescriptorSets`: +Add a class member to hold the descriptor set handles and allocate them with `vk::raii::Device::allocateDescriptorSets`: [,c++] ---- -vk::raii::DescriptorPool descriptorPool = nullptr; +vk::raii::DescriptorPool descriptorPool = nullptr; std::vector descriptorSets; ... -descriptorSets.clear(); descriptorSets = device.allocateDescriptorSets(allocInfo); ---- @@ -112,27 +114,34 @@ We'll now add a loop to populate every descriptor: [,c++] ---- -for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - +for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) +{ } ---- -Descriptors that refer to buffers, like our uniform buffer descriptor, are configured with a `VkDescriptorBufferInfo` struct. +Descriptors that refer to buffers, like our uniform buffer descriptor, are configured with a `vk::DescriptorBufferInfo` struct. This structure specifies the buffer and the region within it that contains the data for the descriptor. [,c++] ---- -for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { +for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) +{ vk::DescriptorBufferInfo bufferInfo{ .buffer = uniformBuffers[i], .offset = 0, .range = sizeof(UniformBufferObject) }; } ---- -If you're overwriting the whole buffer, like we are in this case, then it is also possible to use the `VK_WHOLE_SIZE` value for the range. -The configuration of descriptors is updated using the `vkUpdateDescriptorSets` function, which takes an array of `VkWriteDescriptorSet` structs as parameter. +If you're overwriting the whole buffer, like we are in this case, then it is also possible to use the `vk::WholeSize` value for the range. +The configuration of descriptors is updated using the `vk::raii::Device::updateDescriptorSets` function, which takes an array of `vk::WriteDescriptorSet` structs as parameter. [,c++] ---- -vk::WriteDescriptorSet descriptorWrite{ .dstSet = descriptorSets[i], .dstBinding = 0, .dstArrayElement = 0, .descriptorCount = 1, .descriptorType = vk::DescriptorType::eUniformBuffer, .pBufferInfo = &bufferInfo }; +vk::DescriptorBufferInfo bufferInfo{.buffer = uniformBuffers[i], .offset = 0, .range = sizeof(UniformBufferObject)}; +vk::WriteDescriptorSet descriptorWrite{.dstSet = descriptorSets[i], + .dstBinding = 0, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = vk::DescriptorType::eUniformBuffer, + .pBufferInfo = &bufferInfo}; ---- The first two fields specify the descriptor set to update and the binding. @@ -146,46 +155,52 @@ The `descriptorCount` field specifies how many array elements you want to update The last field references an array with `descriptorCount` structs that actually configure the descriptors. It depends on the type of descriptor which one of the three you actually need to use. -The `pBufferInfo` field is used for descriptors that refer to buffer data, `pImageInfo` is used for descriptors that refer to image data, and `pTexelBufferView` is used for descriptors that refer to buffer views. -Our descriptor is based on buffers, so we're using `pBufferInfo`. +The `pBufferInfo` field is used for descriptors that refer to buffer data. There are additional elements in this struct, that are not +used in this sample: `pImageInfo` is used for descriptors that refer to image data, and `pTexelBufferView` is used for descriptors that refer to buffer views. +Our descriptor is based on buffers, so we're just using `pBufferInfo`. [,c++] ---- device.updateDescriptorSets(descriptorWrite, {}); ---- -The updates are applied using `vkUpdateDescriptorSets`. -It accepts two kinds of arrays as parameters: an array of `VkWriteDescriptorSet` and an array of `VkCopyDescriptorSet`. +The updates are applied using `vk::raii::Device::updateDescriptorSets`. +It accepts two arrays as parameters: an array of `vk::WriteDescriptorSet` and an array of `vk::CopyDescriptorSet`. The latter can be used to copy descriptors to each other, as its name implies. == Using descriptor sets -We now need to update the `recordCommandBuffer` function to actually bind the right descriptor set for each frame to the descriptors in the shader with `vkCmdBindDescriptorSets`. -This needs to be done before the `vkCmdDrawIndexed` call: +We now need to update the `recordCommandBuffer` function to actually bind the right descriptor set for each frame to the descriptors in the shader with `vk::raii::CommandBuffer::bindDescriptorSets`. +This needs to be done before the `vk::raii::CommandBuffer::drawIndexed` call: [,c++] ---- commandBuffers[frameIndex].bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, *descriptorSets[frameIndex], nullptr); -commandBuffers[frameIndex].drawIndexed(indices.size(), 1, 0, 0, 0); +commandBuffer.drawIndexed(static_cast(indices.size()), 1, 0, 0, 0); ---- Unlike vertex and index buffers, descriptor sets are not unique to graphics pipelines. Therefore, we need to specify if we want to bind descriptor sets to the graphics or compute pipeline. The next parameter is the layout that the descriptors are based on. -The next three parameters specify the index of the first descriptor set, the number of sets to bind, and the array of sets to bind. +The next two parameters specify the index of the first descriptor set, and the array of sets to bind. We'll get back to this in a moment. -The last two parameters specify an array of offsets that are used for dynamic descriptors. +The last parameter specifies an array of offsets that are used for dynamic descriptors. We'll look at these in a future chapter. If you run your program now, then you'll notice that unfortunately nothing is visible. The problem is that because of the Y-flip we did in the projection matrix, the vertices are now being drawn in counter-clockwise order instead of clockwise order. This causes backface culling to kick in and prevents any geometry from being drawn. -Go to the `createGraphicsPipeline` function and modify the `frontFace` in `VkPipelineRasterizationStateCreateInfo` to correct this: +Go to the `createGraphicsPipeline` function and modify the `frontFace` in `vk::PipelineRasterizationStateCreateInfo` to correct this: [,c++] ---- - vk::PipelineRasterizationStateCreateInfo rasterizer({}, vk::False, vk::False, vk::PolygonMode::eFill, - vk::CullModeFlagBits::eBack, vk::FrontFace::eCounterClockwise, vk::False, 0.0f, 0.0f, 1.0f, 1.0f); +vk::PipelineRasterizationStateCreateInfo rasterizer{.depthClampEnable = vk::False, + .rasterizerDiscardEnable = vk::False, + .polygonMode = vk::PolygonMode::eFill, + .cullMode = vk::CullModeFlagBits::eBack, + .frontFace = vk::FrontFace::eCounterClockwise, + .depthBiasEnable = vk::False, + .lineWidth = 1.0f}; ---- Run your program again, and you should now see the following: @@ -202,13 +217,15 @@ It seems obvious enough to simply use the same types in both: [,c++] ---- -struct UniformBufferObject { +struct UniformBufferObject +{ glm::mat4 model; glm::mat4 view; glm::mat4 proj; }; -struct UniformBuffer { +struct UniformBuffer +{ float4x4 model; float4x4 view; float4x4 proj; @@ -221,7 +238,8 @@ For example, try modifying the struct and shader to look like this: [,c++] ---- -struct UniformBufferObject { +struct UniformBufferObject +{ glm::vec2 foo; glm::mat4 model; glm::mat4 view; @@ -260,7 +278,8 @@ To fix this problem we can use the https://en.cppreference.com/w/cpp/language/al [,c++] ---- -struct UniformBufferObject { +struct UniformBufferObject +{ glm::vec2 foo; alignas(16) glm::mat4 model; glm::mat4 view; @@ -287,11 +306,13 @@ Consider the following definition in the C{pp} code: [,c++] ---- -struct Foo { +struct Foo +{ glm::vec2 v; }; -struct UniformBufferObject { +struct UniformBufferObject +{ Foo f1; Foo f2; }; @@ -301,11 +322,13 @@ And the following shader definition: [,c++] ---- -struct Foo { +struct Foo +{ vec2 v; }; -struct UniformBuffer { +struct UniformBuffer +{ Foo f1; Foo f2; }; @@ -317,7 +340,8 @@ In this case, you must specify the alignment yourself: [,c++] ---- -struct UniformBufferObject { +struct UniformBufferObject +{ Foo f1; alignas(16) Foo f2; }; @@ -328,7 +352,8 @@ That way you won't be caught off guard by the strange symptoms of alignment erro [,c++] ---- -struct UniformBufferObject { +struct UniformBufferObject +{ alignas(16) glm::mat4 model; alignas(16) glm::mat4 view; alignas(16) glm::mat4 proj; @@ -345,7 +370,8 @@ Shaders can then reference specific descriptor sets like this: [,c++] ---- -struct UniformBuffer { +struct UniformBuffer +{ }; ConstantBuffer ubo; ----