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:
parent
845c78fd20
commit
b62ccfe7a3
@ -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)
|
||||||
|
@ -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 };
|
||||||
};
|
};
|
||||||
|
@ -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(),
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user