From 1cf64ffaef6c72ac28aa30fb5280db410e27731c Mon Sep 17 00:00:00 2001 From: Wunk Date: Sun, 5 Nov 2023 12:25:59 -0800 Subject: [PATCH] vk_stream_buf: Allow dedicated allocations (#7103) * vk_stream_buf: Avoid protected memory heaps * Add an "Exclude" argument when finding a memory-type that avoids `VK_MEMORY_PROPERTY_PROTECTED_BIT` by default * vk_stream_buf: Utilize dedicated allocations when preferred by driver `VK_KHR_dedicated_allocation` is part of the core Vulkan 1.1 specification and should be utilized when `prefersDedicatedAllocation` is set. --- .../renderer_vulkan/vk_stream_buffer.cpp | 44 ++++++++++++++----- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp b/src/video_core/renderer_vulkan/vk_stream_buffer.cpp index 27b1314427..fd557bdd87 100644 --- a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp +++ b/src/video_core/renderer_vulkan/vk_stream_buffer.cpp @@ -44,11 +44,12 @@ vk::MemoryPropertyFlags MakePropertyFlags(BufferType type) { } /// Find a memory type with the passed requirements -std::optional FindMemoryType(const vk::PhysicalDeviceMemoryProperties& properties, - vk::MemoryPropertyFlags wanted) { +std::optional FindMemoryType( + const vk::PhysicalDeviceMemoryProperties& properties, vk::MemoryPropertyFlags wanted, + vk::MemoryPropertyFlags excluded = vk::MemoryPropertyFlagBits::eProtected) { for (u32 i = 0; i < properties.memoryTypeCount; ++i) { const auto flags = properties.memoryTypes[i].propertyFlags; - if ((flags & wanted) == wanted) { + if (((flags & wanted) == wanted) && (!(flags & excluded))) { return i; } } @@ -166,25 +167,46 @@ void StreamBuffer::CreateBuffers(u64 prefered_size) { static_cast(mem_type.propertyFlags & vk::MemoryPropertyFlagBits::eHostCoherent); // Substract from the preferred heap size some bytes to avoid getting out of memory. - const VkDeviceSize heap_size = memory_properties.memoryHeaps[preferred_heap].size; + const vk::DeviceSize heap_size = memory_properties.memoryHeaps[preferred_heap].size; // As per DXVK's example, using `heap_size / 2` - const VkDeviceSize allocable_size = heap_size / 2; + const vk::DeviceSize allocable_size = heap_size / 2; buffer = device.createBuffer({ .size = std::min(prefered_size, allocable_size), .usage = usage, }); - const auto requirements = device.getBufferMemoryRequirements(buffer); - stream_buffer_size = static_cast(requirements.size); + const auto requirements_chain = + device + .getBufferMemoryRequirements2( + {.buffer = buffer}); + + const auto& requirements = requirements_chain.get(); + const auto& dedicated_requirements = requirements_chain.get(); + + stream_buffer_size = static_cast(requirements.memoryRequirements.size); LOG_INFO(Render_Vulkan, "Creating {} buffer with size {} KB with flags {}", BufferTypeName(type), stream_buffer_size / 1024, vk::to_string(mem_type.propertyFlags)); - memory = device.allocateMemory({ - .allocationSize = requirements.size, - .memoryTypeIndex = preferred_type, - }); + if (dedicated_requirements.prefersDedicatedAllocation) { + vk::StructureChain alloc_chain = + {}; + + auto& alloc_info = alloc_chain.get(); + alloc_info.allocationSize = requirements.memoryRequirements.size; + alloc_info.memoryTypeIndex = preferred_type; + + auto& dedicated_alloc_info = alloc_chain.get(); + dedicated_alloc_info.buffer = buffer; + + memory = device.allocateMemory(alloc_chain.get()); + } else { + memory = device.allocateMemory({ + .allocationSize = requirements.memoryRequirements.size, + .memoryTypeIndex = preferred_type, + }); + } device.bindBufferMemory(buffer, memory, 0); mapped = reinterpret_cast(device.mapMemory(memory, 0, VK_WHOLE_SIZE));