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.
This commit is contained in:
Wunk 2023-11-05 12:25:59 -08:00 committed by GitHub
parent 998b9a9525
commit 1cf64ffaef
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -44,11 +44,12 @@ vk::MemoryPropertyFlags MakePropertyFlags(BufferType type) {
} }
/// Find a memory type with the passed requirements /// Find a memory type with the passed requirements
std::optional<u32> FindMemoryType(const vk::PhysicalDeviceMemoryProperties& properties, std::optional<u32> FindMemoryType(
vk::MemoryPropertyFlags wanted) { const vk::PhysicalDeviceMemoryProperties& properties, vk::MemoryPropertyFlags wanted,
vk::MemoryPropertyFlags excluded = vk::MemoryPropertyFlagBits::eProtected) {
for (u32 i = 0; i < properties.memoryTypeCount; ++i) { for (u32 i = 0; i < properties.memoryTypeCount; ++i) {
const auto flags = properties.memoryTypes[i].propertyFlags; const auto flags = properties.memoryTypes[i].propertyFlags;
if ((flags & wanted) == wanted) { if (((flags & wanted) == wanted) && (!(flags & excluded))) {
return i; return i;
} }
} }
@ -166,25 +167,46 @@ void StreamBuffer::CreateBuffers(u64 prefered_size) {
static_cast<bool>(mem_type.propertyFlags & vk::MemoryPropertyFlagBits::eHostCoherent); static_cast<bool>(mem_type.propertyFlags & vk::MemoryPropertyFlagBits::eHostCoherent);
// Substract from the preferred heap size some bytes to avoid getting out of memory. // 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` // 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({ buffer = device.createBuffer({
.size = std::min(prefered_size, allocable_size), .size = std::min(prefered_size, allocable_size),
.usage = usage, .usage = usage,
}); });
const auto requirements = device.getBufferMemoryRequirements(buffer); const auto requirements_chain =
stream_buffer_size = static_cast<u64>(requirements.size); device
.getBufferMemoryRequirements2<vk::MemoryRequirements2, vk::MemoryDedicatedRequirements>(
{.buffer = buffer});
const auto& requirements = requirements_chain.get<vk::MemoryRequirements2>();
const auto& dedicated_requirements = requirements_chain.get<vk::MemoryDedicatedRequirements>();
stream_buffer_size = static_cast<u64>(requirements.memoryRequirements.size);
LOG_INFO(Render_Vulkan, "Creating {} buffer with size {} KB with flags {}", LOG_INFO(Render_Vulkan, "Creating {} buffer with size {} KB with flags {}",
BufferTypeName(type), stream_buffer_size / 1024, BufferTypeName(type), stream_buffer_size / 1024,
vk::to_string(mem_type.propertyFlags)); vk::to_string(mem_type.propertyFlags));
if (dedicated_requirements.prefersDedicatedAllocation) {
vk::StructureChain<vk::MemoryAllocateInfo, vk::MemoryDedicatedAllocateInfo> alloc_chain =
{};
auto& alloc_info = alloc_chain.get<vk::MemoryAllocateInfo>();
alloc_info.allocationSize = requirements.memoryRequirements.size;
alloc_info.memoryTypeIndex = preferred_type;
auto& dedicated_alloc_info = alloc_chain.get<vk::MemoryDedicatedAllocateInfo>();
dedicated_alloc_info.buffer = buffer;
memory = device.allocateMemory(alloc_chain.get());
} else {
memory = device.allocateMemory({ memory = device.allocateMemory({
.allocationSize = requirements.size, .allocationSize = requirements.memoryRequirements.size,
.memoryTypeIndex = preferred_type, .memoryTypeIndex = preferred_type,
}); });
}
device.bindBufferMemory(buffer, memory, 0); device.bindBufferMemory(buffer, memory, 0);
mapped = reinterpret_cast<u8*>(device.mapMemory(memory, 0, VK_WHOLE_SIZE)); mapped = reinterpret_cast<u8*>(device.mapMemory(memory, 0, VK_WHOLE_SIZE));