Use AllocateMemoryForResource for dummy image/buffer memory

* This makes the allocation more reliable e.g. for cases where the image memory
  can't share with buffer memory.
This commit is contained in:
baldurk
2020-05-05 17:12:50 +01:00
parent df58309f08
commit 9dbdee0199
4 changed files with 60 additions and 79 deletions
+3
View File
@@ -353,6 +353,9 @@ enum class MemoryScope : uint8_t
{
InitialContents,
First = InitialContents,
// On replay, initial contents memory is never freed, so any immutable replay memory can be
// allocated the same way
ImmutableReplayDebug = InitialContents,
IndirectReadback,
Count,
};
+8 -63
View File
@@ -1981,9 +1981,6 @@ void VulkanReplay::TextureRendering::Init(WrappedVulkan *driver, VkDescriptorPoo
VkSampleCountFlagBits sampleCounts[] = {VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_1_BIT,
VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_4_BIT};
VkDeviceSize offsets[ARRAY_COUNT(formats)][ARRAY_COUNT(types)];
VkDeviceSize curOffset = 0;
// type max is one higher than the last RESTYPE, and RESTYPES are 1-indexed
RDCCOMPILE_ASSERT(RESTYPE_TEXTYPEMAX - 1 == ARRAY_COUNT(types),
"RESTYPE values don't match formats for dummy images");
@@ -2000,10 +1997,6 @@ void VulkanReplay::TextureRendering::Init(WrappedVulkan *driver, VkDescriptorPoo
RDCCOMPILE_ASSERT(ARRAY_COUNT(DummyWrites) == ARRAY_COUNT(DummyInfos),
"dummy image arrays mismatched sizes");
VkMemoryAllocateInfo allocInfo = {
VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, NULL, 0, ~0U,
};
CREATE_OBJECT(DummySampler, VK_FILTER_NEAREST);
for(size_t fmt = 0; fmt < ARRAY_COUNT(formats); fmt++)
@@ -2039,22 +2032,12 @@ void VulkanReplay::TextureRendering::Init(WrappedVulkan *driver, VkDescriptorPoo
vkr = driver->vkCreateImage(driver->GetDev(), &imInfo, NULL, &DummyImages[fmt][type]);
RDCASSERTEQUAL(vkr, VK_SUCCESS);
VkMemoryRequirements mrq = {0};
driver->vkGetImageMemoryRequirements(driver->GetDev(), DummyImages[fmt][type], &mrq);
MemoryAllocation alloc = driver->AllocateMemoryForResource(
DummyImages[fmt][type], MemoryScope::ImmutableReplayDebug, MemoryType::GPULocal);
uint32_t memIndex = driver->GetGPULocalMemoryIndex(mrq.memoryTypeBits);
// make sure all images can use the same memory type
RDCASSERTMSG("memory type indices don't overlap!",
allocInfo.memoryTypeIndex == ~0U || allocInfo.memoryTypeIndex == memIndex,
allocInfo.memoryTypeIndex, memIndex, fmt, type);
allocInfo.memoryTypeIndex = memIndex;
// align to our alignment, then increment curOffset by our size
curOffset = AlignUp(curOffset, mrq.alignment);
offsets[fmt][type] = curOffset;
curOffset += mrq.size;
vkr = driver->vkBindImageMemory(driver->GetDev(), DummyImages[fmt][type], alloc.mem,
alloc.offs);
RDCASSERTEQUAL(vkr, VK_SUCCESS);
// fill out the descriptor set write to the write binding - set will be filled out
// on demand when we're actually using these writes.
@@ -2099,10 +2082,7 @@ void VulkanReplay::TextureRendering::Init(WrappedVulkan *driver, VkDescriptorPoo
DummyInfos[index + 1].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
// align up for the dummy buffer
VkDeviceSize bufferOffset = 0;
{
curOffset = AlignUp(curOffset, driver->GetDeviceProps().limits.bufferImageGranularity);
VkBufferCreateInfo bufInfo = {
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, NULL, 0, 16,
VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT,
@@ -2111,43 +2091,10 @@ void VulkanReplay::TextureRendering::Init(WrappedVulkan *driver, VkDescriptorPoo
vkr = driver->vkCreateBuffer(driver->GetDev(), &bufInfo, NULL, &DummyBuffer);
RDCASSERTEQUAL(vkr, VK_SUCCESS);
VkMemoryRequirements mrq = {0};
driver->vkGetBufferMemoryRequirements(driver->GetDev(), DummyBuffer, &mrq);
MemoryAllocation alloc = driver->AllocateMemoryForResource(
DummyBuffer, MemoryScope::ImmutableReplayDebug, MemoryType::GPULocal);
if(mrq.memoryTypeBits & (1U << allocInfo.memoryTypeIndex))
{
curOffset = AlignUp(curOffset, mrq.alignment);
bufferOffset = curOffset;
curOffset += mrq.size;
}
else
{
RDCERR("Can't use memory type %u for dummy buffer!", allocInfo.memoryTypeIndex);
driver->vkDestroyBuffer(driver->GetDev(), DummyBuffer, NULL);
}
}
// align up a bit just to be safe
allocInfo.allocationSize = AlignUp(curOffset, (VkDeviceSize)1024ULL);
// allocate one big block
vkr = driver->vkAllocateMemory(driver->GetDev(), &allocInfo, NULL, &DummyMemory);
RDCASSERTEQUAL(vkr, VK_SUCCESS);
// bind all the image memory
for(size_t fmt = 0; fmt < ARRAY_COUNT(formats); fmt++)
{
for(size_t type = 0; type < ARRAY_COUNT(types); type++)
{
vkr = driver->vkBindImageMemory(driver->GetDev(), DummyImages[fmt][type], DummyMemory,
offsets[fmt][type]);
RDCASSERTEQUAL(vkr, VK_SUCCESS);
}
}
if(DummyBuffer != VK_NULL_HANDLE)
{
vkr = driver->vkBindBufferMemory(driver->GetDev(), DummyBuffer, DummyMemory, bufferOffset);
vkr = driver->vkBindBufferMemory(driver->GetDev(), DummyBuffer, alloc.mem, alloc.offs);
RDCASSERTEQUAL(vkr, VK_SUCCESS);
}
@@ -2280,8 +2227,6 @@ void VulkanReplay::TextureRendering::Destroy(WrappedVulkan *driver)
driver->vkDestroyBufferView(driver->GetDev(), DummyBufferView[fmt], NULL);
driver->vkDestroyBuffer(driver->GetDev(), DummyBuffer, NULL);
driver->vkFreeMemory(driver->GetDev(), DummyMemory, NULL);
driver->vkDestroySampler(driver->GetDev(), DummySampler, NULL);
}
+49 -15
View File
@@ -22,8 +22,12 @@
* THE SOFTWARE.
******************************************************************************/
#include "core/settings.h"
#include "vk_core.h"
RDOC_DEBUG_CONFIG(bool, Vulkan_Debug_MemoryAllocationLogging, false,
"Output verbose debug logging messages when allocating internal memory.");
void WrappedVulkan::ChooseMemoryIndices()
{
// we need to do this little dance because Get*MemoryIndex checks to see if the existing
@@ -158,9 +162,12 @@ MemoryAllocation WrappedVulkan::AllocateMemoryForResource(bool buffer, VkMemoryR
// invalidate/flush safely. This is at most 256 bytes which is likely already satisfied.
ret.size = AlignUp(ret.size, nonCoherentAtomSize);
RDCDEBUG("Allocating 0x%llx (0x%llx requested) with alignment 0x%llx in 0x%x for a %s (%s in %s)",
if(Vulkan_Debug_MemoryAllocationLogging)
{
RDCLOG("Allocating 0x%llx (0x%llx requested) with alignment 0x%llx in 0x%x for a %s (%s in %s)",
ret.size, mrq.size, mrq.alignment, mrq.memoryTypeBits, buffer ? "buffer" : "image",
ToStr(type).c_str(), ToStr(scope).c_str());
}
rdcarray<MemoryAllocation> &blockList = m_MemoryBlocks[(size_t)scope];
@@ -168,17 +175,23 @@ MemoryAllocation WrappedVulkan::AllocateMemoryForResource(bool buffer, VkMemoryR
int i = 0;
for(MemoryAllocation &block : blockList)
{
RDCDEBUG(
"Considering block %d: memory type %u and type %s. Total size 0x%llx, current offset "
"0x%llx, last alloc was %s",
i, block.memoryTypeIndex, ToStr(block.type).c_str(), block.size, block.offs,
block.buffer ? "buffer" : "image");
if(Vulkan_Debug_MemoryAllocationLogging)
{
RDCLOG(
"Considering block %d: memory type %u and type %s. Total size 0x%llx, current offset "
"0x%llx, last alloc was %s",
i, block.memoryTypeIndex, ToStr(block.type).c_str(), block.size, block.offs,
block.buffer ? "buffer" : "image");
}
i++;
// skip this block if it's not the memory type we want
if(ret.type != block.type || (mrq.memoryTypeBits & (1 << block.memoryTypeIndex)) == 0)
{
RDCDEBUG("block type %d or memory type %d is incompatible", block.type, block.memoryTypeIndex);
if(Vulkan_Debug_MemoryAllocationLogging)
{
RDCLOG("block type %d or memory type %d is incompatible", block.type, block.memoryTypeIndex);
}
continue;
}
@@ -194,15 +207,21 @@ MemoryAllocation WrappedVulkan::AllocateMemoryForResource(bool buffer, VkMemoryR
if(offs > block.size)
{
RDCDEBUG("Next offset 0x%llx would be off the end of the memory (size 0x%llx).", offs,
if(Vulkan_Debug_MemoryAllocationLogging)
{
RDCLOG("Next offset 0x%llx would be off the end of the memory (size 0x%llx).", offs,
block.size);
}
continue;
}
VkDeviceSize avail = block.size - offs;
RDCDEBUG("At next offset 0x%llx, there's 0x%llx bytes available for 0x%llx bytes requested",
if(Vulkan_Debug_MemoryAllocationLogging)
{
RDCLOG("At next offset 0x%llx, there's 0x%llx bytes available for 0x%llx bytes requested",
offs, avail, ret.size);
}
// if the allocation will fit, we've found our candidate.
if(ret.size <= avail)
@@ -215,7 +234,10 @@ MemoryAllocation WrappedVulkan::AllocateMemoryForResource(bool buffer, VkMemoryR
ret.offs = offs;
ret.mem = block.mem;
RDCDEBUG("Allocating using this block: 0x%llx -> 0x%llx", ret.offs, block.offs);
if(Vulkan_Debug_MemoryAllocationLogging)
{
RDCLOG("Allocating using this block: 0x%llx -> 0x%llx", ret.offs, block.offs);
}
// stop searching
break;
@@ -224,7 +246,10 @@ MemoryAllocation WrappedVulkan::AllocateMemoryForResource(bool buffer, VkMemoryR
if(ret.mem == VK_NULL_HANDLE)
{
RDCDEBUG("No available block found - allocating new block");
if(Vulkan_Debug_MemoryAllocationLogging)
{
RDCLOG("No available block found - allocating new block");
}
VkDeviceSize &allocSize = m_MemoryBlockSize[(size_t)scope];
@@ -237,7 +262,7 @@ MemoryAllocation WrappedVulkan::AllocateMemoryForResource(bool buffer, VkMemoryR
case 128:
case 256: allocSize = 256; break;
default:
RDCDEBUG("Unexpected previous allocation size 0x%llx bytes, allocating 256MB", allocSize);
RDCWARN("Unexpected previous allocation size 0x%llx bytes, allocating 256MB", allocSize);
allocSize = 256;
break;
}
@@ -255,8 +280,11 @@ MemoryAllocation WrappedVulkan::AllocateMemoryForResource(bool buffer, VkMemoryR
{
if(mrq.memoryTypeBits > (1U << m))
{
RDCDEBUG("Avoiding memory type %u due to small heap size (%llu)", m,
if(Vulkan_Debug_MemoryAllocationLogging)
{
RDCLOG("Avoiding memory type %u due to small heap size (%llu)", m,
m_PhysicalDeviceData.memProps.memoryHeaps[heap].size);
}
mrq.memoryTypeBits &= ~(1U << m);
}
}
@@ -288,12 +316,18 @@ MemoryAllocation WrappedVulkan::AllocateMemoryForResource(bool buffer, VkMemoryR
// if it's still over-sized, just allocate precisely enough and give it a dedicated allocation
if(ret.size > info.allocationSize)
{
RDCDEBUG("Over-sized allocation for 0x%llx bytes", ret.size);
if(Vulkan_Debug_MemoryAllocationLogging)
{
RDCLOG("Over-sized allocation for 0x%llx bytes", ret.size);
}
info.allocationSize = ret.size;
}
}
RDCDEBUG("Creating new allocation of 0x%llx bytes", info.allocationSize);
if(Vulkan_Debug_MemoryAllocationLogging)
{
RDCLOG("Creating new allocation of 0x%llx bytes", info.allocationSize);
}
MemoryAllocation chunk;
chunk.buffer = ret.buffer;
-1
View File
@@ -570,7 +570,6 @@ private:
VkImageView DummyImageViews[3][5] = {};
VkWriteDescriptorSet DummyWrites[14] = {};
VkDescriptorImageInfo DummyInfos[14] = {};
VkDeviceMemory DummyMemory = VK_NULL_HANDLE;
VkSampler DummySampler = VK_NULL_HANDLE;
VkBuffer DummyBuffer = VK_NULL_HANDLE;
VkBufferView DummyBufferView[3] = {};