From b62ccfe7a3f4e9d4003911c2ecbd7ba2a4ae8a02 Mon Sep 17 00:00:00 2001 From: ZeroFault Date: Sun, 24 Jun 2018 02:55:42 -0600 Subject: [PATCH] [dxvk] Implement dedicated allocation (#448) Yields significant performance improvements on some Nvidia GPUs. --- src/dxvk/dxvk_buffer_res.cpp | 31 ++++++++++++++--- src/dxvk/dxvk_extensions.h | 4 ++- src/dxvk/dxvk_image.cpp | 35 +++++++++++++++---- src/dxvk/dxvk_memory.cpp | 50 +++++++++++++++------------- src/dxvk/dxvk_memory.h | 22 +++++++----- src/dxvk/vulkan/dxvk_vulkan_loader.h | 5 +++ 6 files changed, 103 insertions(+), 44 deletions(-) diff --git a/src/dxvk/dxvk_buffer_res.cpp b/src/dxvk/dxvk_buffer_res.cpp index ebd8bdc0f..352fea63e 100644 --- a/src/dxvk/dxvk_buffer_res.cpp +++ b/src/dxvk/dxvk_buffer_res.cpp @@ -27,10 +27,33 @@ namespace dxvk { "\n usage: ", info.usage)); } - VkMemoryRequirements memReq; - m_vkd->vkGetBufferMemoryRequirements( - m_vkd->device(), m_handle, &memReq); - m_memory = memAlloc.alloc(memReq, memFlags); + VkMemoryDedicatedRequirementsKHR dedicatedRequirements; + dedicatedRequirements.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR; + dedicatedRequirements.pNext = VK_NULL_HANDLE; + dedicatedRequirements.prefersDedicatedAllocation = VK_FALSE; + dedicatedRequirements.requiresDedicatedAllocation = VK_FALSE; + + VkMemoryRequirements2KHR memReq; + memReq.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR; + memReq.pNext = &dedicatedRequirements; + + VkBufferMemoryRequirementsInfo2KHR memReqInfo; + memReqInfo.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR; + memReqInfo.buffer = m_handle; + memReqInfo.pNext = VK_NULL_HANDLE; + + VkMemoryDedicatedAllocateInfoKHR dedMemoryAllocInfo; + dedMemoryAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR; + dedMemoryAllocInfo.pNext = VK_NULL_HANDLE; + dedMemoryAllocInfo.buffer = m_handle; + dedMemoryAllocInfo.image = VK_NULL_HANDLE; + + m_vkd->vkGetBufferMemoryRequirements2KHR( + m_vkd->device(), &memReqInfo, &memReq); + + bool useDedicated = dedicatedRequirements.prefersDedicatedAllocation; + m_memory = memAlloc.alloc(&memReq.memoryRequirements, + useDedicated ? &dedMemoryAllocInfo : nullptr, memFlags); if (m_vkd->vkBindBufferMemory(m_vkd->device(), m_handle, m_memory.memory(), m_memory.offset()) != VK_SUCCESS) diff --git a/src/dxvk/dxvk_extensions.h b/src/dxvk/dxvk_extensions.h index cc903c130..513c460a3 100644 --- a/src/dxvk/dxvk_extensions.h +++ b/src/dxvk/dxvk_extensions.h @@ -131,10 +131,12 @@ namespace dxvk { struct DxvkDeviceExtensions : public DxvkExtensionList { DxvkExtension extShaderViewportIndexLayer = { this, VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME, DxvkExtensionType::Desired }; DxvkExtension extVertexAttributeDivisor = { this, VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME, DxvkExtensionType::Required }; + DxvkExtension khrDedicatedAllocation = { this, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME, DxvkExtensionType::Required }; DxvkExtension khrDescriptorUpdateTemplate = { this, VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME, DxvkExtensionType::Required }; - DxvkExtension khrSamplerMirrorClampToEdge = { this, VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME, DxvkExtensionType::Desired }; + DxvkExtension khrGetMemoryRequirements2 = { this, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME, DxvkExtensionType::Required }; DxvkExtension khrMaintenance1 = { this, VK_KHR_MAINTENANCE1_EXTENSION_NAME, DxvkExtensionType::Required }; DxvkExtension khrMaintenance2 = { this, VK_KHR_MAINTENANCE2_EXTENSION_NAME, DxvkExtensionType::Required }; + DxvkExtension khrSamplerMirrorClampToEdge = { this, VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_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 }; }; diff --git a/src/dxvk/dxvk_image.cpp b/src/dxvk/dxvk_image.cpp index 3227c9da8..b25d9d977 100644 --- a/src/dxvk/dxvk_image.cpp +++ b/src/dxvk/dxvk_image.cpp @@ -46,17 +46,38 @@ namespace dxvk { // alignment on non-linear images in order not to violate the // bufferImageGranularity limit, which may be greater than the // required resource memory alignment on some GPUs. - VkMemoryRequirements memReq; + VkMemoryDedicatedRequirementsKHR dedicatedRequirements; + dedicatedRequirements.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR; + dedicatedRequirements.pNext = VK_NULL_HANDLE; + dedicatedRequirements.prefersDedicatedAllocation = VK_FALSE; + dedicatedRequirements.requiresDedicatedAllocation = VK_FALSE; - m_vkd->vkGetImageMemoryRequirements( - m_vkd->device(), m_image, &memReq); + VkMemoryRequirements2KHR memReq; + memReq.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR; + memReq.pNext = &dedicatedRequirements; + VkImageMemoryRequirementsInfo2KHR memReqInfo; + memReqInfo.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR; + memReqInfo.image = m_image; + memReqInfo.pNext = VK_NULL_HANDLE; + + VkMemoryDedicatedAllocateInfoKHR dedMemoryAllocInfo; + dedMemoryAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR; + dedMemoryAllocInfo.pNext = VK_NULL_HANDLE; + dedMemoryAllocInfo.buffer = VK_NULL_HANDLE; + dedMemoryAllocInfo.image = m_image; + + m_vkd->vkGetImageMemoryRequirements2KHR( + m_vkd->device(), &memReqInfo, &memReq); + if (info.tiling != VK_IMAGE_TILING_LINEAR) { - memReq.size = align(memReq.size, memAlloc.bufferImageGranularity()); - memReq.alignment = align(memReq.alignment , memAlloc.bufferImageGranularity()); + memReq.memoryRequirements.size = align(memReq.memoryRequirements.size, memAlloc.bufferImageGranularity()); + memReq.memoryRequirements.alignment = align(memReq.memoryRequirements.alignment , memAlloc.bufferImageGranularity()); } - - m_memory = memAlloc.alloc(memReq, memFlags); + + bool useDedicated = dedicatedRequirements.prefersDedicatedAllocation; + m_memory = memAlloc.alloc(&memReq.memoryRequirements, + useDedicated ? &dedMemoryAllocInfo : nullptr, memFlags); // Try to bind the allocated memory slice to the image if (m_vkd->vkBindImageMemory(m_vkd->device(), diff --git a/src/dxvk/dxvk_memory.cpp b/src/dxvk/dxvk_memory.cpp index 2c0f524f3..2337dccdc 100644 --- a/src/dxvk/dxvk_memory.cpp +++ b/src/dxvk/dxvk_memory.cpp @@ -166,22 +166,23 @@ namespace dxvk { DxvkMemory DxvkMemoryAllocator::alloc( - const VkMemoryRequirements& req, - const VkMemoryPropertyFlags flags) { + const VkMemoryRequirements* req, + const VkMemoryDedicatedAllocateInfoKHR* dedAllocInfo, + VkMemoryPropertyFlags flags) { std::lock_guard lock(m_mutex); - DxvkMemory result = this->tryAlloc(req, flags); + DxvkMemory result = this->tryAlloc(req, dedAllocInfo, flags); if (!result && (flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) - result = this->tryAlloc(req, flags & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + result = this->tryAlloc(req, dedAllocInfo, flags & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); if (!result) { Logger::err(str::format( "DxvkMemoryAllocator: Memory allocation failed", - "\n Size: ", req.size, - "\n Alignment: ", req.alignment, + "\n Size: ", req->size, + "\n Alignment: ", req->alignment, "\n Mem flags: ", "0x", std::hex, flags, - "\n Mem types: ", "0x", std::hex, req.memoryTypeBits)); + "\n Mem types: ", "0x", std::hex, req->memoryTypeBits)); throw DxvkError("DxvkMemoryAllocator: Memory allocation failed"); } @@ -204,17 +205,18 @@ namespace dxvk { DxvkMemory DxvkMemoryAllocator::tryAlloc( - const VkMemoryRequirements& req, - const VkMemoryPropertyFlags flags) { + const VkMemoryRequirements* req, + const VkMemoryDedicatedAllocateInfoKHR* dedAllocInfo, + VkMemoryPropertyFlags flags) { DxvkMemory result; - + for (uint32_t i = 0; i < m_memProps.memoryTypeCount && !result; i++) { - const bool supported = (req.memoryTypeBits & (1u << i)) != 0; + const bool supported = (req->memoryTypeBits & (1u << i)) != 0; const bool adequate = (m_memTypes[i].memType.propertyFlags & flags) == flags; if (supported && adequate) { - result = this->tryAllocFromType( - &m_memTypes[i], req.size, req.alignment); + result = this->tryAllocFromType(&m_memTypes[i], + req->size, req->alignment, dedAllocInfo); } } @@ -223,13 +225,14 @@ namespace dxvk { DxvkMemory DxvkMemoryAllocator::tryAllocFromType( - DxvkMemoryType* type, - VkDeviceSize size, - VkDeviceSize align) { + DxvkMemoryType* type, + VkDeviceSize size, + VkDeviceSize align, + const VkMemoryDedicatedAllocateInfoKHR* dedAllocInfo) { DxvkMemory memory; - if (size >= ChunkSize / 4) { - DxvkDeviceMemory devMem = this->tryAllocDeviceMemory(type, size); + if ((size >= ChunkSize / 4) || dedAllocInfo) { + DxvkDeviceMemory devMem = this->tryAllocDeviceMemory(type, size, dedAllocInfo); if (devMem.memHandle != VK_NULL_HANDLE) memory = DxvkMemory(this, nullptr, type, devMem.memHandle, 0, size, devMem.memPointer); @@ -238,7 +241,7 @@ namespace dxvk { memory = type->chunks[i]->alloc(size, align); if (!memory) { - DxvkDeviceMemory devMem = tryAllocDeviceMemory(type, ChunkSize); + DxvkDeviceMemory devMem = tryAllocDeviceMemory(type, ChunkSize, nullptr); if (devMem.memHandle == VK_NULL_HANDLE) return DxvkMemory(); @@ -258,18 +261,19 @@ namespace dxvk { DxvkDeviceMemory DxvkMemoryAllocator::tryAllocDeviceMemory( - DxvkMemoryType* type, - VkDeviceSize size) { + DxvkMemoryType* type, + VkDeviceSize size, + const VkMemoryDedicatedAllocateInfoKHR* dedAllocInfo) { if ((type->memType.propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) && (type->heap->stats.memoryAllocated + size > type->heap->properties.size)) return DxvkDeviceMemory(); DxvkDeviceMemory result; result.memSize = size; - + VkMemoryAllocateInfo info; info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - info.pNext = nullptr; + info.pNext = dedAllocInfo; info.allocationSize = size; info.memoryTypeIndex = type->memTypeId; diff --git a/src/dxvk/dxvk_memory.h b/src/dxvk/dxvk_memory.h index b6198882e..eed2603ce 100644 --- a/src/dxvk/dxvk_memory.h +++ b/src/dxvk/dxvk_memory.h @@ -237,8 +237,9 @@ namespace dxvk { * \returns Allocated memory slice */ DxvkMemory alloc( - const VkMemoryRequirements& req, - const VkMemoryPropertyFlags flags); + const VkMemoryRequirements* req, + const VkMemoryDedicatedAllocateInfoKHR* dedAllocInfo, + VkMemoryPropertyFlags flags); /** * \brief Queries memory stats @@ -262,17 +263,20 @@ namespace dxvk { std::array m_memTypes; DxvkMemory tryAlloc( - const VkMemoryRequirements& req, - const VkMemoryPropertyFlags flags); + const VkMemoryRequirements* req, + const VkMemoryDedicatedAllocateInfoKHR* dedAllocInfo, + VkMemoryPropertyFlags flags); DxvkMemory tryAllocFromType( - DxvkMemoryType* type, - VkDeviceSize size, - VkDeviceSize align); + DxvkMemoryType* type, + VkDeviceSize size, + VkDeviceSize align, + const VkMemoryDedicatedAllocateInfoKHR* dedAllocInfo); DxvkDeviceMemory tryAllocDeviceMemory( - DxvkMemoryType* type, - VkDeviceSize size); + DxvkMemoryType* type, + VkDeviceSize size, + const VkMemoryDedicatedAllocateInfoKHR* dedAllocInfo); void free( const DxvkMemory& memory); diff --git a/src/dxvk/vulkan/dxvk_vulkan_loader.h b/src/dxvk/vulkan/dxvk_vulkan_loader.h index a79af03d0..e352844a1 100644 --- a/src/dxvk/vulkan/dxvk_vulkan_loader.h +++ b/src/dxvk/vulkan/dxvk_vulkan_loader.h @@ -269,6 +269,11 @@ namespace dxvk::vk { VULKAN_FN(vkAcquireNextImageKHR); VULKAN_FN(vkQueuePresentKHR); #endif + + #ifdef VK_KHR_get_memory_requirements2 + VULKAN_FN(vkGetBufferMemoryRequirements2KHR); + VULKAN_FN(vkGetImageMemoryRequirements2KHR); + #endif }; } \ No newline at end of file