1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-02-07 07:54:15 +01:00

[dxvk] Implement dedicated allocation (#448)

Yields significant performance improvements on some Nvidia GPUs.
This commit is contained in:
ZeroFault 2018-06-24 02:55:42 -06:00 committed by Philip Rebohle
parent 845c78fd20
commit b62ccfe7a3
6 changed files with 103 additions and 44 deletions

View File

@ -27,10 +27,33 @@ namespace dxvk {
"\n usage: ", info.usage)); "\n usage: ", info.usage));
} }
VkMemoryRequirements memReq; VkMemoryDedicatedRequirementsKHR dedicatedRequirements;
m_vkd->vkGetBufferMemoryRequirements( dedicatedRequirements.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR;
m_vkd->device(), m_handle, &memReq); dedicatedRequirements.pNext = VK_NULL_HANDLE;
m_memory = memAlloc.alloc(memReq, memFlags); 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, if (m_vkd->vkBindBufferMemory(m_vkd->device(), m_handle,
m_memory.memory(), m_memory.offset()) != VK_SUCCESS) m_memory.memory(), m_memory.offset()) != VK_SUCCESS)

View File

@ -131,10 +131,12 @@ namespace dxvk {
struct DxvkDeviceExtensions : public DxvkExtensionList { struct DxvkDeviceExtensions : public DxvkExtensionList {
DxvkExtension extShaderViewportIndexLayer = { this, VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME, DxvkExtensionType::Desired }; 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 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 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 khrMaintenance1 = { this, VK_KHR_MAINTENANCE1_EXTENSION_NAME, DxvkExtensionType::Required };
DxvkExtension khrMaintenance2 = { this, VK_KHR_MAINTENANCE2_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 khrShaderDrawParameters = { this, VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME, DxvkExtensionType::Required };
DxvkExtension khrSwapchain = { this, VK_KHR_SWAPCHAIN_EXTENSION_NAME, DxvkExtensionType::Required }; DxvkExtension khrSwapchain = { this, VK_KHR_SWAPCHAIN_EXTENSION_NAME, DxvkExtensionType::Required };
}; };

View File

@ -46,17 +46,38 @@ namespace dxvk {
// alignment on non-linear images in order not to violate the // alignment on non-linear images in order not to violate the
// bufferImageGranularity limit, which may be greater than the // bufferImageGranularity limit, which may be greater than the
// required resource memory alignment on some GPUs. // 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( VkMemoryRequirements2KHR memReq;
m_vkd->device(), m_image, &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) { if (info.tiling != VK_IMAGE_TILING_LINEAR) {
memReq.size = align(memReq.size, memAlloc.bufferImageGranularity()); memReq.memoryRequirements.size = align(memReq.memoryRequirements.size, memAlloc.bufferImageGranularity());
memReq.alignment = align(memReq.alignment , 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 // Try to bind the allocated memory slice to the image
if (m_vkd->vkBindImageMemory(m_vkd->device(), if (m_vkd->vkBindImageMemory(m_vkd->device(),

View File

@ -166,22 +166,23 @@ namespace dxvk {
DxvkMemory DxvkMemoryAllocator::alloc( DxvkMemory DxvkMemoryAllocator::alloc(
const VkMemoryRequirements& req, const VkMemoryRequirements* req,
const VkMemoryPropertyFlags flags) { const VkMemoryDedicatedAllocateInfoKHR* dedAllocInfo,
VkMemoryPropertyFlags flags) {
std::lock_guard<std::mutex> lock(m_mutex); std::lock_guard<std::mutex> 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)) 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) { if (!result) {
Logger::err(str::format( Logger::err(str::format(
"DxvkMemoryAllocator: Memory allocation failed", "DxvkMemoryAllocator: Memory allocation failed",
"\n Size: ", req.size, "\n Size: ", req->size,
"\n Alignment: ", req.alignment, "\n Alignment: ", req->alignment,
"\n Mem flags: ", "0x", std::hex, flags, "\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"); throw DxvkError("DxvkMemoryAllocator: Memory allocation failed");
} }
@ -204,17 +205,18 @@ namespace dxvk {
DxvkMemory DxvkMemoryAllocator::tryAlloc( DxvkMemory DxvkMemoryAllocator::tryAlloc(
const VkMemoryRequirements& req, const VkMemoryRequirements* req,
const VkMemoryPropertyFlags flags) { const VkMemoryDedicatedAllocateInfoKHR* dedAllocInfo,
VkMemoryPropertyFlags flags) {
DxvkMemory result; DxvkMemory result;
for (uint32_t i = 0; i < m_memProps.memoryTypeCount && !result; i++) { 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; const bool adequate = (m_memTypes[i].memType.propertyFlags & flags) == flags;
if (supported && adequate) { if (supported && adequate) {
result = this->tryAllocFromType( result = this->tryAllocFromType(&m_memTypes[i],
&m_memTypes[i], req.size, req.alignment); req->size, req->alignment, dedAllocInfo);
} }
} }
@ -223,13 +225,14 @@ namespace dxvk {
DxvkMemory DxvkMemoryAllocator::tryAllocFromType( DxvkMemory DxvkMemoryAllocator::tryAllocFromType(
DxvkMemoryType* type, DxvkMemoryType* type,
VkDeviceSize size, VkDeviceSize size,
VkDeviceSize align) { VkDeviceSize align,
const VkMemoryDedicatedAllocateInfoKHR* dedAllocInfo) {
DxvkMemory memory; DxvkMemory memory;
if (size >= ChunkSize / 4) { if ((size >= ChunkSize / 4) || dedAllocInfo) {
DxvkDeviceMemory devMem = this->tryAllocDeviceMemory(type, size); DxvkDeviceMemory devMem = this->tryAllocDeviceMemory(type, size, dedAllocInfo);
if (devMem.memHandle != VK_NULL_HANDLE) if (devMem.memHandle != VK_NULL_HANDLE)
memory = DxvkMemory(this, nullptr, type, devMem.memHandle, 0, size, devMem.memPointer); memory = DxvkMemory(this, nullptr, type, devMem.memHandle, 0, size, devMem.memPointer);
@ -238,7 +241,7 @@ namespace dxvk {
memory = type->chunks[i]->alloc(size, align); memory = type->chunks[i]->alloc(size, align);
if (!memory) { if (!memory) {
DxvkDeviceMemory devMem = tryAllocDeviceMemory(type, ChunkSize); DxvkDeviceMemory devMem = tryAllocDeviceMemory(type, ChunkSize, nullptr);
if (devMem.memHandle == VK_NULL_HANDLE) if (devMem.memHandle == VK_NULL_HANDLE)
return DxvkMemory(); return DxvkMemory();
@ -258,8 +261,9 @@ namespace dxvk {
DxvkDeviceMemory DxvkMemoryAllocator::tryAllocDeviceMemory( DxvkDeviceMemory DxvkMemoryAllocator::tryAllocDeviceMemory(
DxvkMemoryType* type, DxvkMemoryType* type,
VkDeviceSize size) { VkDeviceSize size,
const VkMemoryDedicatedAllocateInfoKHR* dedAllocInfo) {
if ((type->memType.propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) if ((type->memType.propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
&& (type->heap->stats.memoryAllocated + size > type->heap->properties.size)) && (type->heap->stats.memoryAllocated + size > type->heap->properties.size))
return DxvkDeviceMemory(); return DxvkDeviceMemory();
@ -269,7 +273,7 @@ namespace dxvk {
VkMemoryAllocateInfo info; VkMemoryAllocateInfo info;
info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
info.pNext = nullptr; info.pNext = dedAllocInfo;
info.allocationSize = size; info.allocationSize = size;
info.memoryTypeIndex = type->memTypeId; info.memoryTypeIndex = type->memTypeId;

View File

@ -237,8 +237,9 @@ namespace dxvk {
* \returns Allocated memory slice * \returns Allocated memory slice
*/ */
DxvkMemory alloc( DxvkMemory alloc(
const VkMemoryRequirements& req, const VkMemoryRequirements* req,
const VkMemoryPropertyFlags flags); const VkMemoryDedicatedAllocateInfoKHR* dedAllocInfo,
VkMemoryPropertyFlags flags);
/** /**
* \brief Queries memory stats * \brief Queries memory stats
@ -262,17 +263,20 @@ namespace dxvk {
std::array<DxvkMemoryType, VK_MAX_MEMORY_TYPES> m_memTypes; std::array<DxvkMemoryType, VK_MAX_MEMORY_TYPES> m_memTypes;
DxvkMemory tryAlloc( DxvkMemory tryAlloc(
const VkMemoryRequirements& req, const VkMemoryRequirements* req,
const VkMemoryPropertyFlags flags); const VkMemoryDedicatedAllocateInfoKHR* dedAllocInfo,
VkMemoryPropertyFlags flags);
DxvkMemory tryAllocFromType( DxvkMemory tryAllocFromType(
DxvkMemoryType* type, DxvkMemoryType* type,
VkDeviceSize size, VkDeviceSize size,
VkDeviceSize align); VkDeviceSize align,
const VkMemoryDedicatedAllocateInfoKHR* dedAllocInfo);
DxvkDeviceMemory tryAllocDeviceMemory( DxvkDeviceMemory tryAllocDeviceMemory(
DxvkMemoryType* type, DxvkMemoryType* type,
VkDeviceSize size); VkDeviceSize size,
const VkMemoryDedicatedAllocateInfoKHR* dedAllocInfo);
void free( void free(
const DxvkMemory& memory); const DxvkMemory& memory);

View File

@ -269,6 +269,11 @@ namespace dxvk::vk {
VULKAN_FN(vkAcquireNextImageKHR); VULKAN_FN(vkAcquireNextImageKHR);
VULKAN_FN(vkQueuePresentKHR); VULKAN_FN(vkQueuePresentKHR);
#endif #endif
#ifdef VK_KHR_get_memory_requirements2
VULKAN_FN(vkGetBufferMemoryRequirements2KHR);
VULKAN_FN(vkGetImageMemoryRequirements2KHR);
#endif
}; };
} }