1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-01-31 05:52:11 +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));
}
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)

View File

@ -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 };
};

View File

@ -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(),

View File

@ -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<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))
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);
}
}
@ -225,11 +227,12 @@ namespace dxvk {
DxvkMemory DxvkMemoryAllocator::tryAllocFromType(
DxvkMemoryType* type,
VkDeviceSize size,
VkDeviceSize align) {
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();
@ -259,7 +262,8 @@ namespace dxvk {
DxvkDeviceMemory DxvkMemoryAllocator::tryAllocDeviceMemory(
DxvkMemoryType* type,
VkDeviceSize size) {
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();
@ -269,7 +273,7 @@ namespace dxvk {
VkMemoryAllocateInfo info;
info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
info.pNext = nullptr;
info.pNext = dedAllocInfo;
info.allocationSize = size;
info.memoryTypeIndex = type->memTypeId;

View File

@ -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<DxvkMemoryType, VK_MAX_MEMORY_TYPES> 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);
VkDeviceSize align,
const VkMemoryDedicatedAllocateInfoKHR* dedAllocInfo);
DxvkDeviceMemory tryAllocDeviceMemory(
DxvkMemoryType* type,
VkDeviceSize size);
VkDeviceSize size,
const VkMemoryDedicatedAllocateInfoKHR* dedAllocInfo);
void free(
const DxvkMemory& memory);

View File

@ -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
};
}