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 695ab56b..3d7a30da 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 511a5aae..e78927b9 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 929f1bf7..f879796f 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 61c6b208..6a819ede 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 74108476..d6637910 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 b5586bb1..769e05e2 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 80412fed..0f4c98c2 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 bee0df02..e89a006e 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;