mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-01-30 20:52:11 +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));
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -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 };
|
||||
};
|
||||
|
@ -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(),
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -223,13 +225,14 @@ namespace dxvk {
|
||||
|
||||
|
||||
DxvkMemory DxvkMemoryAllocator::tryAllocFromType(
|
||||
DxvkMemoryType* type,
|
||||
VkDeviceSize size,
|
||||
VkDeviceSize align) {
|
||||
DxvkMemoryType* type,
|
||||
VkDeviceSize size,
|
||||
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();
|
||||
@ -258,18 +261,19 @@ namespace dxvk {
|
||||
|
||||
|
||||
DxvkDeviceMemory DxvkMemoryAllocator::tryAllocDeviceMemory(
|
||||
DxvkMemoryType* type,
|
||||
VkDeviceSize size) {
|
||||
DxvkMemoryType* type,
|
||||
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();
|
||||
|
||||
DxvkDeviceMemory result;
|
||||
result.memSize = size;
|
||||
|
||||
|
||||
VkMemoryAllocateInfo info;
|
||||
info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
info.pNext = nullptr;
|
||||
info.pNext = dedAllocInfo;
|
||||
info.allocationSize = size;
|
||||
info.memoryTypeIndex = type->memTypeId;
|
||||
|
||||
|
@ -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);
|
||||
DxvkMemoryType* type,
|
||||
VkDeviceSize size,
|
||||
VkDeviceSize align,
|
||||
const VkMemoryDedicatedAllocateInfoKHR* dedAllocInfo);
|
||||
|
||||
DxvkDeviceMemory tryAllocDeviceMemory(
|
||||
DxvkMemoryType* type,
|
||||
VkDeviceSize size);
|
||||
DxvkMemoryType* type,
|
||||
VkDeviceSize size,
|
||||
const VkMemoryDedicatedAllocateInfoKHR* dedAllocInfo);
|
||||
|
||||
void free(
|
||||
const DxvkMemory& memory);
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user