mirror of
https://github.com/doitsujin/dxvk.git
synced 2024-12-12 04:08:52 +01:00
[dxvk] Add function to create buffer resource
This commit is contained in:
parent
00f7545d15
commit
5813e7c031
@ -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(
|
DxvkDeviceMemory DxvkMemoryAllocator::allocateDeviceMemory(
|
||||||
DxvkMemoryType& type,
|
DxvkMemoryType& type,
|
||||||
VkDeviceSize size,
|
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 {
|
void DxvkMemoryAllocator::logMemoryError(const VkMemoryRequirements& req) const {
|
||||||
std::stringstream sstr;
|
std::stringstream sstr;
|
||||||
sstr << "DxvkMemoryAllocator: Memory allocation failed" << std::endl
|
sstr << "DxvkMemoryAllocator: Memory allocation failed" << std::endl
|
||||||
|
@ -820,6 +820,19 @@ namespace dxvk {
|
|||||||
VkMemoryPropertyFlags properties,
|
VkMemoryPropertyFlags properties,
|
||||||
const void* next);
|
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
|
* \brief Queries memory stats
|
||||||
*
|
*
|
||||||
@ -956,6 +969,9 @@ namespace dxvk {
|
|||||||
|
|
||||||
void determineMemoryTypesWithPropertyFlags();
|
void determineMemoryTypesWithPropertyFlags();
|
||||||
|
|
||||||
|
VkDeviceAddress getBufferDeviceAddress(
|
||||||
|
VkBuffer buffer) const;
|
||||||
|
|
||||||
void logMemoryError(
|
void logMemoryError(
|
||||||
const VkMemoryRequirements& req) const;
|
const VkMemoryRequirements& req) const;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user