From 94aa650f3e250b79b449bb2f8b058e4ce7e11983 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Sat, 17 Mar 2018 23:50:03 +0100 Subject: [PATCH] [dxvk] Enable the use of VK_KHR_descriptor_update_template Reduces the CPU overhead of descriptor set updates, which usually happen once per draw call. Gains seem to be minor in most games, some outliers show significantly better performance (i.e. Tomb Raider). --- src/dxvk/dxvk_cmdlist.h | 11 +++--- src/dxvk/dxvk_compute.cpp | 3 +- src/dxvk/dxvk_context.cpp | 24 ++---------- src/dxvk/dxvk_context.h | 1 - src/dxvk/dxvk_extensions.h | 11 +++--- src/dxvk/dxvk_graphics.cpp | 3 +- src/dxvk/dxvk_pipelayout.cpp | 72 ++++++++++++++++++++++++------------ src/dxvk/dxvk_pipelayout.h | 18 +++++++-- 8 files changed, 83 insertions(+), 60 deletions(-) diff --git a/src/dxvk/dxvk_cmdlist.h b/src/dxvk/dxvk_cmdlist.h index 695ab56bb..3d7a30dad 100644 --- a/src/dxvk/dxvk_cmdlist.h +++ b/src/dxvk/dxvk_cmdlist.h @@ -134,11 +134,12 @@ namespace dxvk { } - void updateDescriptorSet( - uint32_t descriptorCount, - const VkWriteDescriptorSet* descriptorWrites) { - m_vkd->vkUpdateDescriptorSets(m_vkd->device(), - descriptorCount, descriptorWrites, 0, nullptr); + void updateDescriptorSetWithTemplate( + VkDescriptorSet descriptorSet, + VkDescriptorUpdateTemplateKHR descriptorTemplate, + const void* data) { + m_vkd->vkUpdateDescriptorSetWithTemplateKHR(m_vkd->device(), + descriptorSet, descriptorTemplate, data); } diff --git a/src/dxvk/dxvk_compute.cpp b/src/dxvk/dxvk_compute.cpp index 511a5aae6..e78927b92 100644 --- a/src/dxvk/dxvk_compute.cpp +++ b/src/dxvk/dxvk_compute.cpp @@ -26,7 +26,8 @@ namespace dxvk { m_layout = new DxvkPipelineLayout(m_vkd, slotMapping.bindingCount(), - slotMapping.bindingInfos()); + slotMapping.bindingInfos(), + VK_PIPELINE_BIND_POINT_COMPUTE); m_cs = cs->createShaderModule(m_vkd, slotMapping); } diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 929f1bf74..f879796f7 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -7,20 +7,7 @@ namespace dxvk { DxvkContext::DxvkContext(const Rc& device) - : m_device(device) { - for (uint32_t i = 0; i < m_descWrites.size(); i++) { - m_descWrites[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - m_descWrites[i].pNext = nullptr; - m_descWrites[i].dstSet = VK_NULL_HANDLE; - m_descWrites[i].dstBinding = i; - m_descWrites[i].dstArrayElement = 0; - m_descWrites[i].descriptorCount = 1; - m_descWrites[i].descriptorType = VkDescriptorType(0); - m_descWrites[i].pImageInfo = &m_descInfos[i].image; - m_descWrites[i].pBufferInfo = &m_descInfos[i].buffer; - m_descWrites[i].pTexelBufferView = &m_descInfos[i].texelBuffer; - } - } + : m_device(device) { } DxvkContext::~DxvkContext() { @@ -1620,13 +1607,10 @@ namespace dxvk { m_cmd->allocateDescriptorSet( layout->descriptorSetLayout()); - for (uint32_t i = 0; i < layout->bindingCount(); i++) { - m_descWrites[i].dstSet = dset; - m_descWrites[i].descriptorType = layout->binding(i).type; - } + m_cmd->updateDescriptorSetWithTemplate( + dset, layout->descriptorTemplate(), + m_descInfos.data()); - m_cmd->updateDescriptorSet( - layout->bindingCount(), m_descWrites.data()); m_cmd->cmdBindDescriptorSet(bindPoint, layout->pipelineLayout(), dset); } diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index 61c6b2088..6a819ede2 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -578,7 +578,6 @@ namespace dxvk { std::array m_rc; std::array m_descInfos; - std::array m_descWrites; void renderPassBegin(); void renderPassEnd(); diff --git a/src/dxvk/dxvk_extensions.h b/src/dxvk/dxvk_extensions.h index 74108476e..d66379103 100644 --- a/src/dxvk/dxvk_extensions.h +++ b/src/dxvk/dxvk_extensions.h @@ -129,11 +129,12 @@ namespace dxvk { * used by DXVK if supported by the implementation. */ struct DxvkDeviceExtensions : public DxvkExtensionList { - DxvkExtension amdRasterizationOrder = { this, VK_AMD_RASTERIZATION_ORDER_EXTENSION_NAME, DxvkExtensionType::Optional }; - DxvkExtension khrMaintenance1 = { this, VK_KHR_MAINTENANCE1_EXTENSION_NAME, DxvkExtensionType::Required }; - DxvkExtension khrMaintenance2 = { this, VK_KHR_MAINTENANCE2_EXTENSION_NAME, DxvkExtensionType::Desired }; - DxvkExtension khrShaderDrawParameters = { this, VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME, DxvkExtensionType::Required }; - DxvkExtension khrSwapchain = { this, VK_KHR_SWAPCHAIN_EXTENSION_NAME, DxvkExtensionType::Required }; + DxvkExtension amdRasterizationOrder = { this, VK_AMD_RASTERIZATION_ORDER_EXTENSION_NAME, DxvkExtensionType::Optional }; + DxvkExtension khrDescriptorUpdateTemplate = { this, VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME, DxvkExtensionType::Required }; + DxvkExtension khrMaintenance1 = { this, VK_KHR_MAINTENANCE1_EXTENSION_NAME, DxvkExtensionType::Required }; + DxvkExtension khrMaintenance2 = { this, VK_KHR_MAINTENANCE2_EXTENSION_NAME, DxvkExtensionType::Desired }; + DxvkExtension khrShaderDrawParameters = { this, VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME, DxvkExtensionType::Required }; + DxvkExtension khrSwapchain = { this, VK_KHR_SWAPCHAIN_EXTENSION_NAME, DxvkExtensionType::Required }; }; } \ No newline at end of file diff --git a/src/dxvk/dxvk_graphics.cpp b/src/dxvk/dxvk_graphics.cpp index b5586bb12..769e05e29 100644 --- a/src/dxvk/dxvk_graphics.cpp +++ b/src/dxvk/dxvk_graphics.cpp @@ -52,7 +52,8 @@ namespace dxvk { m_layout = new DxvkPipelineLayout(m_vkd, slotMapping.bindingCount(), - slotMapping.bindingInfos()); + slotMapping.bindingInfos(), + VK_PIPELINE_BIND_POINT_GRAPHICS); if (vs != nullptr) m_vs = vs ->createShaderModule(m_vkd, slotMapping); if (tcs != nullptr) m_tcs = tcs->createShaderModule(m_vkd, slotMapping); diff --git a/src/dxvk/dxvk_pipelayout.cpp b/src/dxvk/dxvk_pipelayout.cpp index 80412fedc..0f4c98c28 100644 --- a/src/dxvk/dxvk_pipelayout.cpp +++ b/src/dxvk/dxvk_pipelayout.cpp @@ -1,5 +1,6 @@ #include +#include "dxvk_descriptor.h" #include "dxvk_pipelayout.h" namespace dxvk { @@ -44,26 +45,32 @@ namespace dxvk { DxvkPipelineLayout::DxvkPipelineLayout( const Rc& vkd, uint32_t bindingCount, - const DxvkDescriptorSlot* bindingInfos) - : m_vkd(vkd) { - - m_bindingSlots.resize(bindingCount); + const DxvkDescriptorSlot* bindingInfos, + VkPipelineBindPoint pipelineBindPoint) + : m_vkd(vkd), m_bindingSlots(bindingCount) { for (uint32_t i = 0; i < bindingCount; i++) m_bindingSlots[i] = bindingInfos[i]; - std::vector bindings; + std::vector bindings(bindingCount); + std::vector tEntries(bindingCount); for (uint32_t i = 0; i < bindingCount; i++) { - VkDescriptorSetLayoutBinding binding; - binding.binding = i; - binding.descriptorType = bindingInfos[i].type; - binding.descriptorCount = 1; - binding.stageFlags = bindingInfos[i].stages; - binding.pImmutableSamplers = nullptr; - bindings.push_back(binding); + bindings[i].binding = i; + bindings[i].descriptorType = bindingInfos[i].type; + bindings[i].descriptorCount = 1; + bindings[i].stageFlags = bindingInfos[i].stages; + bindings[i].pImmutableSamplers = nullptr; + + tEntries[i].dstBinding = i; + tEntries[i].dstArrayElement = 0; + tEntries[i].descriptorCount = 1; + tEntries[i].descriptorType = bindingInfos[i].type; + tEntries[i].offset = sizeof(DxvkDescriptorInfo) * i; + tEntries[i].stride = 0; } + // Create descriptor set layout VkDescriptorSetLayoutCreateInfo dsetInfo; dsetInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; dsetInfo.pNext = nullptr; @@ -75,6 +82,7 @@ namespace dxvk { &dsetInfo, nullptr, &m_descriptorSetLayout) != VK_SUCCESS) throw DxvkError("DxvkPipelineLayout: Failed to create descriptor set layout"); + // Create pipeline layout VkPipelineLayoutCreateInfo pipeInfo; pipeInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipeInfo.pNext = nullptr; @@ -85,24 +93,42 @@ namespace dxvk { pipeInfo.pPushConstantRanges = nullptr; if (m_vkd->vkCreatePipelineLayout(m_vkd->device(), - &pipeInfo, nullptr, &m_pipelineLayout) != VK_SUCCESS) { - m_vkd->vkDestroyDescriptorSetLayout( - m_vkd->device(), m_descriptorSetLayout, nullptr); + &pipeInfo, nullptr, &m_pipelineLayout) != VK_SUCCESS) { + m_vkd->vkDestroyDescriptorSetLayout(m_vkd->device(), m_descriptorSetLayout, nullptr); throw DxvkError("DxvkPipelineLayout: Failed to create pipeline layout"); } + + // Create descriptor update template + VkDescriptorUpdateTemplateCreateInfoKHR templateInfo; + templateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR; + templateInfo.pNext = nullptr; + templateInfo.flags = 0; + templateInfo.descriptorUpdateEntryCount = tEntries.size(); + templateInfo.pDescriptorUpdateEntries = tEntries.data(); + templateInfo.templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR; + templateInfo.descriptorSetLayout = m_descriptorSetLayout; + templateInfo.pipelineBindPoint = pipelineBindPoint; + templateInfo.pipelineLayout = m_pipelineLayout; + templateInfo.set = 0; + + if (m_vkd->vkCreateDescriptorUpdateTemplateKHR(m_vkd->device(), + &templateInfo, nullptr, &m_descriptorTemplate) != VK_SUCCESS) { + m_vkd->vkDestroyDescriptorSetLayout(m_vkd->device(), m_descriptorSetLayout, nullptr); + m_vkd->vkDestroyPipelineLayout(m_vkd->device(), m_pipelineLayout, nullptr); + throw DxvkError("DxvkPipelineLayout: Failed to create descriptor update template"); + } } DxvkPipelineLayout::~DxvkPipelineLayout() { - if (m_pipelineLayout != VK_NULL_HANDLE) { - m_vkd->vkDestroyPipelineLayout( - m_vkd->device(), m_pipelineLayout, nullptr); - } + m_vkd->vkDestroyDescriptorUpdateTemplateKHR( + m_vkd->device(), m_descriptorTemplate, nullptr); - if (m_descriptorSetLayout != VK_NULL_HANDLE) { - m_vkd->vkDestroyDescriptorSetLayout( - m_vkd->device(), m_descriptorSetLayout, nullptr); - } + m_vkd->vkDestroyPipelineLayout( + m_vkd->device(), m_pipelineLayout, nullptr); + + m_vkd->vkDestroyDescriptorSetLayout( + m_vkd->device(), m_descriptorSetLayout, nullptr); } } \ No newline at end of file diff --git a/src/dxvk/dxvk_pipelayout.h b/src/dxvk/dxvk_pipelayout.h index bee0df02a..e89a006ec 100644 --- a/src/dxvk/dxvk_pipelayout.h +++ b/src/dxvk/dxvk_pipelayout.h @@ -111,7 +111,8 @@ namespace dxvk { DxvkPipelineLayout( const Rc& vkd, uint32_t bindingCount, - const DxvkDescriptorSlot* bindingInfos); + const DxvkDescriptorSlot* bindingInfos, + VkPipelineBindPoint pipelineBindPoint); ~DxvkPipelineLayout(); @@ -157,12 +158,21 @@ namespace dxvk { return m_pipelineLayout; } + /** + * \brief Descriptor update template + * \returns Descriptor update template + */ + VkDescriptorUpdateTemplateKHR descriptorTemplate() const { + return m_descriptorTemplate; + } + private: - Rc m_vkd; + Rc m_vkd; - VkDescriptorSetLayout m_descriptorSetLayout = VK_NULL_HANDLE; - VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE; + VkDescriptorSetLayout m_descriptorSetLayout = VK_NULL_HANDLE; + VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE; + VkDescriptorUpdateTemplateKHR m_descriptorTemplate = VK_NULL_HANDLE; std::vector m_bindingSlots;