mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-03-14 22:29:15 +01:00
[dxvk] Clean up internal memory allocation API
This commit is contained in:
parent
5117210c93
commit
a2a21cb4d3
@ -65,25 +65,32 @@ namespace dxvk {
|
|||||||
|
|
||||||
DxvkBufferHandle handle;
|
DxvkBufferHandle handle;
|
||||||
|
|
||||||
if (vkd->vkCreateBuffer(vkd->device(),
|
if (vkd->vkCreateBuffer(vkd->device(), &info, nullptr, &handle.buffer)) {
|
||||||
&info, nullptr, &handle.buffer) != VK_SUCCESS) {
|
|
||||||
throw DxvkError(str::format(
|
throw DxvkError(str::format(
|
||||||
"DxvkBuffer: Failed to create buffer:"
|
"DxvkBuffer: Failed to create buffer:"
|
||||||
"\n size: ", info.size,
|
"\n size: ", info.size,
|
||||||
"\n usage: ", info.usage));
|
"\n usage: ", info.usage));
|
||||||
}
|
}
|
||||||
|
|
||||||
VkMemoryDedicatedRequirements dedicatedRequirements = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS };
|
|
||||||
VkMemoryRequirements2 memReq = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, &dedicatedRequirements };
|
|
||||||
|
|
||||||
VkBufferMemoryRequirementsInfo2 memReqInfo = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2 };
|
|
||||||
memReqInfo.buffer = handle.buffer;
|
|
||||||
|
|
||||||
VkMemoryDedicatedAllocateInfo dedMemoryAllocInfo = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO };
|
|
||||||
dedMemoryAllocInfo.buffer = handle.buffer;
|
|
||||||
|
|
||||||
vkd->vkGetBufferMemoryRequirements2(
|
// Query memory requirements and whether to use a dedicated allocation
|
||||||
vkd->device(), &memReqInfo, &memReq);
|
DxvkMemoryRequirements memoryRequirements = { };
|
||||||
|
memoryRequirements.dedicated = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS };
|
||||||
|
memoryRequirements.core = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, &memoryRequirements.dedicated };
|
||||||
|
|
||||||
|
VkBufferMemoryRequirementsInfo2 memoryRequirementInfo = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2 };
|
||||||
|
memoryRequirementInfo.buffer = handle.buffer;
|
||||||
|
|
||||||
|
vkd->vkGetBufferMemoryRequirements2(vkd->device(),
|
||||||
|
&memoryRequirementInfo, &memoryRequirements.core);
|
||||||
|
|
||||||
|
// Fill in desired memory properties
|
||||||
|
DxvkMemoryProperties memoryProperties = { };
|
||||||
|
memoryProperties.flags = m_memFlags;
|
||||||
|
|
||||||
|
if (memoryRequirements.dedicated.prefersDedicatedAllocation) {
|
||||||
|
memoryProperties.dedicated = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO };
|
||||||
|
memoryProperties.dedicated.buffer = handle.buffer;
|
||||||
|
}
|
||||||
|
|
||||||
// Use high memory priority for GPU-writable resources
|
// Use high memory priority for GPU-writable resources
|
||||||
bool isGpuWritable = (m_info.access & (
|
bool isGpuWritable = (m_info.access & (
|
||||||
@ -102,9 +109,7 @@ namespace dxvk {
|
|||||||
&& (m_info.usage & VK_BUFFER_USAGE_TRANSFER_SRC_BIT))
|
&& (m_info.usage & VK_BUFFER_USAGE_TRANSFER_SRC_BIT))
|
||||||
hints.set(DxvkMemoryFlag::Transient);
|
hints.set(DxvkMemoryFlag::Transient);
|
||||||
|
|
||||||
// Ask driver whether we should be using a dedicated allocation
|
handle.memory = m_memAlloc->alloc(memoryRequirements, memoryProperties, hints);
|
||||||
handle.memory = m_memAlloc->alloc(&memReq.memoryRequirements,
|
|
||||||
dedicatedRequirements, dedMemoryAllocInfo, m_memFlags, hints);
|
|
||||||
|
|
||||||
if (vkd->vkBindBufferMemory(vkd->device(), handle.buffer,
|
if (vkd->vkBindBufferMemory(vkd->device(), handle.buffer,
|
||||||
handle.memory.memory(), handle.memory.offset()) != VK_SUCCESS)
|
handle.memory.memory(), handle.memory.offset()) != VK_SUCCESS)
|
||||||
|
@ -22,7 +22,10 @@ namespace dxvk {
|
|||||||
VkImageFormatListCreateInfo formatList = { VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO };
|
VkImageFormatListCreateInfo formatList = { VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO };
|
||||||
formatList.viewFormatCount = createInfo.viewFormatCount;
|
formatList.viewFormatCount = createInfo.viewFormatCount;
|
||||||
formatList.pViewFormats = createInfo.viewFormats;
|
formatList.pViewFormats = createInfo.viewFormats;
|
||||||
|
|
||||||
|
VkExternalMemoryImageCreateInfo externalInfo = { VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO };
|
||||||
|
externalInfo.handleTypes = createInfo.sharing.type;
|
||||||
|
|
||||||
VkImageCreateInfo info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, &formatList };
|
VkImageCreateInfo info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, &formatList };
|
||||||
info.flags = createInfo.flags;
|
info.flags = createInfo.flags;
|
||||||
info.imageType = createInfo.type;
|
info.imageType = createInfo.type;
|
||||||
@ -36,17 +39,10 @@ namespace dxvk {
|
|||||||
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
info.initialLayout = createInfo.initialLayout;
|
info.initialLayout = createInfo.initialLayout;
|
||||||
|
|
||||||
m_shared = canShareImage(info, createInfo.sharing);
|
if ((m_shared = canShareImage(info, createInfo.sharing)))
|
||||||
|
|
||||||
VkExternalMemoryImageCreateInfo externalInfo = { VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO };
|
|
||||||
|
|
||||||
if (m_shared) {
|
|
||||||
externalInfo.pNext = std::exchange(info.pNext, &externalInfo);
|
externalInfo.pNext = std::exchange(info.pNext, &externalInfo);
|
||||||
externalInfo.handleTypes = createInfo.sharing.type;
|
|
||||||
}
|
if (m_vkd->vkCreateImage(m_vkd->device(), &info, nullptr, &m_image.image)) {
|
||||||
|
|
||||||
if (m_vkd->vkCreateImage(m_vkd->device(),
|
|
||||||
&info, nullptr, &m_image.image) != VK_SUCCESS) {
|
|
||||||
throw DxvkError(str::format(
|
throw DxvkError(str::format(
|
||||||
"DxvkImage: Failed to create image:",
|
"DxvkImage: Failed to create image:",
|
||||||
"\n Type: ", info.imageType,
|
"\n Type: ", info.imageType,
|
||||||
@ -61,40 +57,52 @@ namespace dxvk {
|
|||||||
"\n Tiling: ", info.tiling));
|
"\n Tiling: ", info.tiling));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get memory requirements for the image. We may enforce strict
|
// Get memory requirements for the image and ask driver
|
||||||
// alignment on non-linear images in order not to violate the
|
// whether we need to use a dedicated allocation.
|
||||||
// bufferImageGranularity limit, which may be greater than the
|
DxvkMemoryRequirements memoryRequirements = { };
|
||||||
// required resource memory alignment on some GPUs.
|
memoryRequirements.dedicated = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS };
|
||||||
VkMemoryDedicatedRequirements dedicatedRequirements = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS };
|
memoryRequirements.core = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, &memoryRequirements.dedicated };
|
||||||
VkMemoryRequirements2 memReq = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, &dedicatedRequirements };
|
|
||||||
|
|
||||||
VkImageMemoryRequirementsInfo2 memReqInfo = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2 };
|
|
||||||
memReqInfo.image = m_image.image;
|
|
||||||
|
|
||||||
VkMemoryDedicatedAllocateInfo dedMemoryAllocInfo = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO };
|
VkImageMemoryRequirementsInfo2 memoryRequirementInfo = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2 };
|
||||||
dedMemoryAllocInfo.image = m_image.image;
|
memoryRequirementInfo.image = m_image.image;
|
||||||
|
|
||||||
VkExportMemoryAllocateInfo exportInfo = { VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO };
|
m_vkd->vkGetImageMemoryRequirements2(m_vkd->device(),
|
||||||
if (m_shared && createInfo.sharing.mode == DxvkSharedHandleMode::Export) {
|
&memoryRequirementInfo, &memoryRequirements.core);
|
||||||
exportInfo.pNext = std::exchange(dedMemoryAllocInfo.pNext, &exportInfo);
|
|
||||||
exportInfo.handleTypes = createInfo.sharing.type;
|
// Fill in desired memory properties
|
||||||
|
DxvkMemoryProperties memoryProperties = { };
|
||||||
|
memoryProperties.flags = m_memFlags;
|
||||||
|
|
||||||
|
if (m_shared) {
|
||||||
|
memoryRequirements.dedicated.prefersDedicatedAllocation = VK_TRUE;
|
||||||
|
memoryRequirements.dedicated.requiresDedicatedAllocation = VK_TRUE;
|
||||||
|
|
||||||
|
if (createInfo.sharing.mode == DxvkSharedHandleMode::Export) {
|
||||||
|
memoryProperties.sharedExport = { VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO };
|
||||||
|
memoryProperties.sharedExport.handleTypes = createInfo.sharing.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (createInfo.sharing.mode == DxvkSharedHandleMode::Import) {
|
||||||
|
memoryProperties.sharedImportWin32 = { VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR };
|
||||||
|
memoryProperties.sharedImportWin32.handleType = createInfo.sharing.type;
|
||||||
|
memoryProperties.sharedImportWin32.handle = createInfo.sharing.handle;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
if (memoryRequirements.dedicated.prefersDedicatedAllocation) {
|
||||||
VkImportMemoryWin32HandleInfoKHR importInfo = { VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR };
|
memoryProperties.dedicated = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO };
|
||||||
if (m_shared && createInfo.sharing.mode == DxvkSharedHandleMode::Import) {
|
memoryProperties.dedicated.image = m_image.image;
|
||||||
importInfo.pNext = std::exchange(dedMemoryAllocInfo.pNext, &importInfo);
|
|
||||||
importInfo.handleType = createInfo.sharing.type;
|
|
||||||
importInfo.handle = createInfo.sharing.handle;
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
m_vkd->vkGetImageMemoryRequirements2(
|
// If there's a chance we won't create the image with a dedicated
|
||||||
m_vkd->device(), &memReqInfo, &memReq);
|
// allocation, enforce strict alignment for tiled images to not
|
||||||
|
// violate the bufferImageGranularity requirement on some GPUs.
|
||||||
|
if (info.tiling != VK_IMAGE_TILING_LINEAR && !memoryRequirements.dedicated.requiresDedicatedAllocation) {
|
||||||
|
VkDeviceSize granularity = memAlloc.bufferImageGranularity();
|
||||||
|
|
||||||
if (info.tiling != VK_IMAGE_TILING_LINEAR && !dedicatedRequirements.prefersDedicatedAllocation) {
|
auto& core = memoryRequirements.core.memoryRequirements;
|
||||||
memReq.memoryRequirements.size = align(memReq.memoryRequirements.size, memAlloc.bufferImageGranularity());
|
core.size = align(core.size, granularity);
|
||||||
memReq.memoryRequirements.alignment = align(memReq.memoryRequirements.alignment , memAlloc.bufferImageGranularity());
|
core.alignment = align(core.alignment, granularity);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use high memory priority for GPU-writable resources
|
// Use high memory priority for GPU-writable resources
|
||||||
@ -110,14 +118,7 @@ namespace dxvk {
|
|||||||
if (isGpuWritable)
|
if (isGpuWritable)
|
||||||
hints.set(DxvkMemoryFlag::GpuWritable);
|
hints.set(DxvkMemoryFlag::GpuWritable);
|
||||||
|
|
||||||
if (m_shared) {
|
m_image.memory = memAlloc.alloc(memoryRequirements, memoryProperties, hints);
|
||||||
dedicatedRequirements.prefersDedicatedAllocation = VK_TRUE;
|
|
||||||
dedicatedRequirements.requiresDedicatedAllocation = VK_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ask driver whether we should be using a dedicated allocation
|
|
||||||
m_image.memory = memAlloc.alloc(&memReq.memoryRequirements,
|
|
||||||
dedicatedRequirements, dedMemoryAllocInfo, memFlags, hints);
|
|
||||||
|
|
||||||
// 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(), m_image.image,
|
if (m_vkd->vkBindImageMemory(m_vkd->device(), m_image.image,
|
||||||
|
@ -211,63 +211,66 @@ namespace dxvk {
|
|||||||
|
|
||||||
|
|
||||||
DxvkMemory DxvkMemoryAllocator::alloc(
|
DxvkMemory DxvkMemoryAllocator::alloc(
|
||||||
const VkMemoryRequirements* req,
|
const DxvkMemoryRequirements& req,
|
||||||
const VkMemoryDedicatedRequirements& dedAllocReq,
|
DxvkMemoryProperties info,
|
||||||
const VkMemoryDedicatedAllocateInfo& dedAllocInfo,
|
|
||||||
VkMemoryPropertyFlags flags,
|
|
||||||
DxvkMemoryFlags hints) {
|
DxvkMemoryFlags hints) {
|
||||||
std::lock_guard<dxvk::mutex> lock(m_mutex);
|
std::lock_guard<dxvk::mutex> lock(m_mutex);
|
||||||
|
|
||||||
// Keep small allocations together to avoid fragmenting
|
// Keep small allocations together to avoid fragmenting
|
||||||
// chunks for larger resources with lots of small gaps,
|
// chunks for larger resources with lots of small gaps,
|
||||||
// as well as resources with potentially weird lifetimes
|
// as well as resources with potentially weird lifetimes
|
||||||
if (req->size <= SmallAllocationThreshold) {
|
if (req.core.memoryRequirements.size <= SmallAllocationThreshold) {
|
||||||
hints.set(DxvkMemoryFlag::Small);
|
hints.set(DxvkMemoryFlag::Small);
|
||||||
hints.clr(DxvkMemoryFlag::GpuWritable, DxvkMemoryFlag::GpuReadable);
|
hints.clr(DxvkMemoryFlag::GpuWritable, DxvkMemoryFlag::GpuReadable);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore most hints for host-visible allocations since they
|
// Ignore most hints for host-visible allocations since they
|
||||||
// usually don't make much sense for those resources
|
// usually don't make much sense for those resources
|
||||||
if (flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
|
if (info.flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
|
||||||
hints = hints & DxvkMemoryFlag::Transient;
|
hints = hints & DxvkMemoryFlag::Transient;
|
||||||
|
|
||||||
// Try to allocate from a memory type which supports the given flags exactly
|
// Try to allocate from a memory type which supports the given flags exactly
|
||||||
auto dedAllocPtr = dedAllocReq.prefersDedicatedAllocation ? &dedAllocInfo : nullptr;
|
DxvkMemory result = this->tryAlloc(req, info, hints);
|
||||||
DxvkMemory result = this->tryAlloc(req, dedAllocPtr, flags, hints);
|
|
||||||
|
|
||||||
// If the first attempt failed, try ignoring the dedicated allocation
|
if (!result && !req.dedicated.requiresDedicatedAllocation) {
|
||||||
if (!result && dedAllocPtr && !dedAllocReq.requiresDedicatedAllocation) {
|
// If that failed, try without a dedicated allocation
|
||||||
result = this->tryAlloc(req, nullptr, flags, hints);
|
if (info.dedicated.image || info.dedicated.buffer) {
|
||||||
dedAllocPtr = nullptr;
|
info.dedicated.image = VK_NULL_HANDLE;
|
||||||
|
info.dedicated.buffer = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
result = this->tryAlloc(req, info, hints);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retry without the hint constraints
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
|
// Retry without the hint constraints
|
||||||
hints.set(DxvkMemoryFlag::IgnoreConstraints);
|
hints.set(DxvkMemoryFlag::IgnoreConstraints);
|
||||||
result = this->tryAlloc(req, nullptr, flags, hints);
|
result = this->tryAlloc(req, info, hints);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If that still didn't work, probe slower memory types as well
|
if (!result) {
|
||||||
VkMemoryPropertyFlags optFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
|
// If that still didn't work, probe slower memory types as well
|
||||||
| VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
|
VkMemoryPropertyFlags optFlags = info.flags & (
|
||||||
VkMemoryPropertyFlags remFlags = 0;
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
|
||||||
|
VK_MEMORY_PROPERTY_HOST_CACHED_BIT);
|
||||||
while (!result && (flags & optFlags)) {
|
|
||||||
remFlags |= optFlags & -optFlags;
|
|
||||||
optFlags &= ~remFlags;
|
|
||||||
|
|
||||||
result = this->tryAlloc(req, dedAllocPtr, flags & ~remFlags, hints);
|
while (!result && optFlags) {
|
||||||
|
VkMemoryPropertyFlags bit = optFlags & -optFlags;
|
||||||
|
optFlags &= ~bit;
|
||||||
|
|
||||||
|
info.flags &= ~bit;
|
||||||
|
result = this->tryAlloc(req, info, hints);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
DxvkAdapterMemoryInfo memHeapInfo = m_device->adapter()->getMemoryHeapInfo();
|
DxvkAdapterMemoryInfo memHeapInfo = m_device->adapter()->getMemoryHeapInfo();
|
||||||
|
|
||||||
Logger::err(str::format(
|
Logger::err(str::format(
|
||||||
"DxvkMemoryAllocator: Memory allocation failed",
|
"DxvkMemoryAllocator: Memory allocation failed",
|
||||||
"\n Size: ", req->size,
|
"\n Size: ", req.core.memoryRequirements.size,
|
||||||
"\n Alignment: ", req->alignment,
|
"\n Alignment: ", req.core.memoryRequirements.alignment,
|
||||||
"\n Mem flags: ", "0x", std::hex, flags,
|
"\n Mem types: ", "0x", std::hex, req.core.memoryRequirements.memoryTypeBits));
|
||||||
"\n Mem types: ", "0x", std::hex, req->memoryTypeBits));
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < m_memProps.memoryHeapCount; i++) {
|
for (uint32_t i = 0; i < m_memProps.memoryHeapCount; i++) {
|
||||||
Logger::err(str::format("Heap ", i, ": ",
|
Logger::err(str::format("Heap ", i, ": ",
|
||||||
@ -290,19 +293,20 @@ namespace dxvk {
|
|||||||
|
|
||||||
|
|
||||||
DxvkMemory DxvkMemoryAllocator::tryAlloc(
|
DxvkMemory DxvkMemoryAllocator::tryAlloc(
|
||||||
const VkMemoryRequirements* req,
|
const DxvkMemoryRequirements& req,
|
||||||
const VkMemoryDedicatedAllocateInfo* dedAllocInfo,
|
const DxvkMemoryProperties& info,
|
||||||
VkMemoryPropertyFlags flags,
|
|
||||||
DxvkMemoryFlags hints) {
|
DxvkMemoryFlags hints) {
|
||||||
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.core.memoryRequirements.memoryTypeBits & (1u << i)) != 0;
|
||||||
const bool adequate = (m_memTypes[i].memType.propertyFlags & flags) == flags;
|
const bool adequate = (m_memTypes[i].memType.propertyFlags & info.flags) == info.flags;
|
||||||
|
|
||||||
if (supported && adequate) {
|
if (supported && adequate) {
|
||||||
result = this->tryAllocFromType(&m_memTypes[i],
|
result = this->tryAllocFromType(&m_memTypes[i],
|
||||||
flags, req->size, req->alignment, hints, dedAllocInfo);
|
req.core.memoryRequirements.size,
|
||||||
|
req.core.memoryRequirements.alignment,
|
||||||
|
info, hints);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -312,27 +316,25 @@ namespace dxvk {
|
|||||||
|
|
||||||
DxvkMemory DxvkMemoryAllocator::tryAllocFromType(
|
DxvkMemory DxvkMemoryAllocator::tryAllocFromType(
|
||||||
DxvkMemoryType* type,
|
DxvkMemoryType* type,
|
||||||
VkMemoryPropertyFlags flags,
|
|
||||||
VkDeviceSize size,
|
VkDeviceSize size,
|
||||||
VkDeviceSize align,
|
VkDeviceSize align,
|
||||||
DxvkMemoryFlags hints,
|
const DxvkMemoryProperties& info,
|
||||||
const VkMemoryDedicatedAllocateInfo* dedAllocInfo) {
|
DxvkMemoryFlags hints) {
|
||||||
VkDeviceSize chunkSize = pickChunkSize(type->memTypeId, hints);
|
VkDeviceSize chunkSize = pickChunkSize(type->memTypeId, hints);
|
||||||
|
|
||||||
DxvkMemory memory;
|
DxvkMemory memory;
|
||||||
|
|
||||||
if (size >= chunkSize || dedAllocInfo) {
|
if (size >= chunkSize || info.dedicated.buffer || info.dedicated.image) {
|
||||||
if (this->shouldFreeEmptyChunks(type->heap, size))
|
if (this->shouldFreeEmptyChunks(type->heap, size))
|
||||||
this->freeEmptyChunks(type->heap);
|
this->freeEmptyChunks(type->heap);
|
||||||
|
|
||||||
DxvkDeviceMemory devMem = this->tryAllocDeviceMemory(
|
DxvkDeviceMemory devMem = this->tryAllocDeviceMemory(type, size, info, hints);
|
||||||
type, flags, size, hints, 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);
|
||||||
} else {
|
} else {
|
||||||
for (uint32_t i = 0; i < type->chunks.size() && !memory; i++)
|
for (uint32_t i = 0; i < type->chunks.size() && !memory; i++)
|
||||||
memory = type->chunks[i]->alloc(flags, size, align, hints);
|
memory = type->chunks[i]->alloc(info.flags, size, align, hints);
|
||||||
|
|
||||||
if (!memory) {
|
if (!memory) {
|
||||||
DxvkDeviceMemory devMem;
|
DxvkDeviceMemory devMem;
|
||||||
@ -341,11 +343,11 @@ namespace dxvk {
|
|||||||
this->freeEmptyChunks(type->heap);
|
this->freeEmptyChunks(type->heap);
|
||||||
|
|
||||||
for (uint32_t i = 0; i < 6 && (chunkSize >> i) >= size && !devMem.memHandle; i++)
|
for (uint32_t i = 0; i < 6 && (chunkSize >> i) >= size && !devMem.memHandle; i++)
|
||||||
devMem = tryAllocDeviceMemory(type, flags, chunkSize >> i, hints, nullptr);
|
devMem = tryAllocDeviceMemory(type, chunkSize >> i, info, hints);
|
||||||
|
|
||||||
if (devMem.memHandle) {
|
if (devMem.memHandle) {
|
||||||
Rc<DxvkMemoryChunk> chunk = new DxvkMemoryChunk(this, type, devMem, hints);
|
Rc<DxvkMemoryChunk> chunk = new DxvkMemoryChunk(this, type, devMem, hints);
|
||||||
memory = chunk->alloc(flags, size, align, hints);
|
memory = chunk->alloc(info.flags, size, align, hints);
|
||||||
|
|
||||||
type->chunks.push_back(std::move(chunk));
|
type->chunks.push_back(std::move(chunk));
|
||||||
}
|
}
|
||||||
@ -361,11 +363,10 @@ namespace dxvk {
|
|||||||
|
|
||||||
DxvkDeviceMemory DxvkMemoryAllocator::tryAllocDeviceMemory(
|
DxvkDeviceMemory DxvkMemoryAllocator::tryAllocDeviceMemory(
|
||||||
DxvkMemoryType* type,
|
DxvkMemoryType* type,
|
||||||
VkMemoryPropertyFlags flags,
|
|
||||||
VkDeviceSize size,
|
VkDeviceSize size,
|
||||||
DxvkMemoryFlags hints,
|
DxvkMemoryProperties info,
|
||||||
const VkMemoryDedicatedAllocateInfo* dedAllocInfo) {
|
DxvkMemoryFlags hints) {
|
||||||
bool useMemoryPriority = (flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
|
bool useMemoryPriority = (info.flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
|
||||||
&& (m_device->features().extMemoryPriority.memoryPriority);
|
&& (m_device->features().extMemoryPriority.memoryPriority);
|
||||||
|
|
||||||
if (type->heap->budget && type->heap->stats.memoryAllocated + size > type->heap->budget)
|
if (type->heap->budget && type->heap->stats.memoryAllocated + size > type->heap->budget)
|
||||||
@ -380,23 +381,32 @@ namespace dxvk {
|
|||||||
|
|
||||||
DxvkDeviceMemory result;
|
DxvkDeviceMemory result;
|
||||||
result.memSize = size;
|
result.memSize = size;
|
||||||
result.memFlags = flags;
|
result.memFlags = info.flags;
|
||||||
result.priority = priority;
|
result.priority = priority;
|
||||||
|
|
||||||
VkMemoryPriorityAllocateInfoEXT prio = { VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT };
|
VkMemoryPriorityAllocateInfoEXT priorityInfo = { VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT };
|
||||||
prio.priority = priority;
|
priorityInfo.priority = priority;
|
||||||
|
|
||||||
VkMemoryAllocateInfo info = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, dedAllocInfo };
|
VkMemoryAllocateInfo memoryInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
|
||||||
info.allocationSize = size;
|
memoryInfo.allocationSize = size;
|
||||||
info.memoryTypeIndex = type->memTypeId;
|
memoryInfo.memoryTypeIndex = type->memTypeId;
|
||||||
|
|
||||||
|
if (info.sharedExport.handleTypes)
|
||||||
|
info.sharedExport.pNext = std::exchange(memoryInfo.pNext, &info.sharedExport);
|
||||||
|
|
||||||
|
if (info.sharedImportWin32.handleType)
|
||||||
|
info.sharedImportWin32.pNext = std::exchange(memoryInfo.pNext, &info.sharedImportWin32);
|
||||||
|
|
||||||
|
if (info.dedicated.buffer || info.dedicated.image)
|
||||||
|
info.dedicated.pNext = std::exchange(memoryInfo.pNext, &info.dedicated);
|
||||||
|
|
||||||
if (useMemoryPriority)
|
if (useMemoryPriority)
|
||||||
prio.pNext = std::exchange(info.pNext, &prio);
|
priorityInfo.pNext = std::exchange(memoryInfo.pNext, &priorityInfo);
|
||||||
|
|
||||||
if (m_vkd->vkAllocateMemory(m_vkd->device(), &info, nullptr, &result.memHandle) != VK_SUCCESS)
|
if (m_vkd->vkAllocateMemory(m_vkd->device(), &memoryInfo, nullptr, &result.memHandle) != VK_SUCCESS)
|
||||||
return DxvkDeviceMemory();
|
return DxvkDeviceMemory();
|
||||||
|
|
||||||
if (flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
|
if (info.flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
|
||||||
VkResult status = m_vkd->vkMapMemory(m_vkd->device(), result.memHandle, 0, VK_WHOLE_SIZE, 0, &result.memPointer);
|
VkResult status = m_vkd->vkMapMemory(m_vkd->device(), result.memHandle, 0, VK_WHOLE_SIZE, 0, &result.memPointer);
|
||||||
|
|
||||||
if (status != VK_SUCCESS) {
|
if (status != VK_SUCCESS) {
|
||||||
|
@ -271,8 +271,28 @@ namespace dxvk {
|
|||||||
bool checkHints(DxvkMemoryFlags hints) const;
|
bool checkHints(DxvkMemoryFlags hints) const;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Memory requirement info
|
||||||
|
*/
|
||||||
|
struct DxvkMemoryRequirements {
|
||||||
|
VkMemoryDedicatedRequirements dedicated;
|
||||||
|
VkMemoryRequirements2 core;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Memory allocation info
|
||||||
|
*/
|
||||||
|
struct DxvkMemoryProperties {
|
||||||
|
VkExportMemoryAllocateInfo sharedExport;
|
||||||
|
VkImportMemoryWin32HandleInfoKHR sharedImportWin32;
|
||||||
|
VkMemoryDedicatedAllocateInfo dedicated;
|
||||||
|
VkMemoryPropertyFlags flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Memory allocator
|
* \brief Memory allocator
|
||||||
*
|
*
|
||||||
@ -305,17 +325,13 @@ namespace dxvk {
|
|||||||
* \brief Allocates device memory
|
* \brief Allocates device memory
|
||||||
*
|
*
|
||||||
* \param [in] req Memory requirements
|
* \param [in] req Memory requirements
|
||||||
* \param [in] dedAllocReq Dedicated allocation requirements
|
* \param [in] info Memory properties
|
||||||
* \param [in] dedAllocInfo Dedicated allocation info
|
|
||||||
* \param [in] flags Memory type flags
|
|
||||||
* \param [in] hints Memory hints
|
* \param [in] hints Memory hints
|
||||||
* \returns Allocated memory slice
|
* \returns Allocated memory slice
|
||||||
*/
|
*/
|
||||||
DxvkMemory alloc(
|
DxvkMemory alloc(
|
||||||
const VkMemoryRequirements* req,
|
const DxvkMemoryRequirements& req,
|
||||||
const VkMemoryDedicatedRequirements& dedAllocReq,
|
DxvkMemoryProperties info,
|
||||||
const VkMemoryDedicatedAllocateInfo& dedAllocInfo,
|
|
||||||
VkMemoryPropertyFlags flags,
|
|
||||||
DxvkMemoryFlags hints);
|
DxvkMemoryFlags hints);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -342,25 +358,22 @@ 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 DxvkMemoryRequirements& req,
|
||||||
const VkMemoryDedicatedAllocateInfo* dedAllocInfo,
|
const DxvkMemoryProperties& info,
|
||||||
VkMemoryPropertyFlags flags,
|
|
||||||
DxvkMemoryFlags hints);
|
DxvkMemoryFlags hints);
|
||||||
|
|
||||||
DxvkMemory tryAllocFromType(
|
DxvkMemory tryAllocFromType(
|
||||||
DxvkMemoryType* type,
|
DxvkMemoryType* type,
|
||||||
VkMemoryPropertyFlags flags,
|
|
||||||
VkDeviceSize size,
|
VkDeviceSize size,
|
||||||
VkDeviceSize align,
|
VkDeviceSize align,
|
||||||
DxvkMemoryFlags hints,
|
const DxvkMemoryProperties& info,
|
||||||
const VkMemoryDedicatedAllocateInfo* dedAllocInfo);
|
DxvkMemoryFlags hints);
|
||||||
|
|
||||||
DxvkDeviceMemory tryAllocDeviceMemory(
|
DxvkDeviceMemory tryAllocDeviceMemory(
|
||||||
DxvkMemoryType* type,
|
DxvkMemoryType* type,
|
||||||
VkMemoryPropertyFlags flags,
|
|
||||||
VkDeviceSize size,
|
VkDeviceSize size,
|
||||||
DxvkMemoryFlags hints,
|
DxvkMemoryProperties info,
|
||||||
const VkMemoryDedicatedAllocateInfo* dedAllocInfo);
|
DxvkMemoryFlags hints);
|
||||||
|
|
||||||
void free(
|
void free(
|
||||||
const DxvkMemory& memory);
|
const DxvkMemory& memory);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user