1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-11 10:24:10 +01:00

[dxvk] Add function to create buffer resource

This commit is contained in:
Philip Rebohle 2024-09-23 00:22:21 +02:00 committed by Philip Rebohle
parent 00f7545d15
commit 5813e7c031
2 changed files with 140 additions and 0 deletions

View File

@ -416,6 +416,120 @@ namespace dxvk {
}
Rc<DxvkResourceAllocation> DxvkMemoryAllocator::createBufferResource(
const VkBufferCreateInfo& createInfo,
VkMemoryPropertyFlags properties) {
Rc<DxvkResourceAllocation> allocation;
if (likely(!createInfo.flags && createInfo.sharingMode == VK_SHARING_MODE_EXCLUSIVE)) {
VkMemoryRequirements memoryRequirements = { };
memoryRequirements.size = createInfo.size;
memoryRequirements.alignment = GlobalBufferAlignment;
memoryRequirements.memoryTypeBits = m_globalBufferMemoryTypes;
if (unlikely(createInfo.usage & ~m_globalBufferUsageFlags))
memoryRequirements.memoryTypeBits = findGlobalBufferMemoryTypeMask(createInfo.usage);
// If there is at least one memory type that supports the required
// buffer usage flags and requested memory properties, suballocate
// from a global buffer.
if (likely(memoryRequirements.memoryTypeBits)) {
allocation = allocateMemory(memoryRequirements, properties);
if (likely(allocation && allocation->m_buffer))
return allocation;
if (!allocation && (properties & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) {
allocation = allocateMemory(memoryRequirements,
properties & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
if (likely(allocation && allocation->m_buffer))
return allocation;
}
// If we end up here with an allocation but no buffer, something
// is weird, but we can keep the allocation around for now.
if (allocation && !allocation->m_buffer) {
Logger::err(str::format("Got allocation from memory type ",
allocation->m_type->index, " without global buffer"));
}
}
}
// If we can't suballocate from an existing global buffer
// for any reason, create a dedicated buffer resource.
auto vk = m_device->vkd();
VkBuffer buffer = VK_NULL_HANDLE;
VkResult vr = vk->vkCreateBuffer(vk->device(),
&createInfo, nullptr, &buffer);
if (vr != VK_SUCCESS) {
throw DxvkError(str::format("Failed to create buffer: ", vr,
"\n size: ", createInfo.size,
"\n usage: ", std::hex, createInfo.usage,
"\n flags: ", createInfo.flags));
}
if (!(createInfo.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT)) {
VkBufferMemoryRequirementsInfo2 requirementInfo = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2 };
requirementInfo.buffer = buffer;
VkMemoryRequirements2 requirements = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2 };
vk->vkGetBufferMemoryRequirements2(vk->device(), &requirementInfo, &requirements);
// If we have an existing global allocation from earlier, make sure it is suitable
if (!allocation || !(requirements.memoryRequirements.memoryTypeBits & (1u << allocation->m_type->index))
|| (allocation->m_size < requirements.memoryRequirements.size)
|| (allocation->m_address & requirements.memoryRequirements.alignment))
allocation = allocateMemory(requirements.memoryRequirements, properties);
if (!allocation && (properties & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) {
allocation = allocateMemory(requirements.memoryRequirements,
properties & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
}
if (!allocation) {
logMemoryError(requirements.memoryRequirements);
logMemoryStats();
}
} else {
// TODO implement sparse
}
if (!allocation) {
vk->vkDestroyBuffer(vk->device(), buffer, nullptr);
return nullptr;
}
// Transfer ownership of te Vulkan buffer to the allocation
// and set up all remaining properties.
allocation->m_flags.set(DxvkAllocationFlag::OwnsBuffer);
allocation->m_buffer = buffer;
allocation->m_bufferOffset = 0u;
allocation->m_bufferAddress = 0u;
// Bind memory if the buffer is not sparse
if (allocation->m_memory) {
vr = vk->vkBindBufferMemory(vk->device(), allocation->m_buffer,
allocation->m_memory, allocation->m_address & DxvkPageAllocator::ChunkAddressMask);
if (vr != VK_SUCCESS) {
throw DxvkError(str::format("Failed to bind buffer memory: ", vr,
"\n size: ", createInfo.size,
"\n usage: ", std::hex, createInfo.usage,
"\n flags: ", createInfo.flags));
}
}
// Query device address after binding memory, or the address would be invalid
if (createInfo.usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT)
allocation->m_bufferAddress = getBufferDeviceAddress(buffer);
return allocation;
}
DxvkDeviceMemory DxvkMemoryAllocator::allocateDeviceMemory(
DxvkMemoryType& type,
VkDeviceSize size,
@ -1086,6 +1200,16 @@ namespace dxvk {
}
VkDeviceAddress DxvkMemoryAllocator::getBufferDeviceAddress(VkBuffer buffer) const {
auto vk = m_device->vkd();
VkBufferDeviceAddressInfo bdaInfo = { VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO };
bdaInfo.buffer = buffer;
return vk->vkGetBufferDeviceAddress(vk->device(), &bdaInfo);
}
void DxvkMemoryAllocator::logMemoryError(const VkMemoryRequirements& req) const {
std::stringstream sstr;
sstr << "DxvkMemoryAllocator: Memory allocation failed" << std::endl

View File

@ -820,6 +820,19 @@ namespace dxvk {
VkMemoryPropertyFlags properties,
const void* next);
/**
* \brief Creates buffer resource
*
* Will make use of global buffers whenever possible, but
* may fall back to creating a dedicated Vulkan buffer.
* \param [in] createInfo Buffer create info
* \param [in] properties Memory property flags
* \returns Buffer resource
*/
Rc<DxvkResourceAllocation> createBufferResource(
const VkBufferCreateInfo& createInfo,
VkMemoryPropertyFlags properties);
/**
* \brief Queries memory stats
*
@ -956,6 +969,9 @@ namespace dxvk {
void determineMemoryTypesWithPropertyFlags();
VkDeviceAddress getBufferDeviceAddress(
VkBuffer buffer) const;
void logMemoryError(
const VkMemoryRequirements& req) const;