diff --git a/renderdoc/driver/vulkan/vk_common.h b/renderdoc/driver/vulkan/vk_common.h index 34f04b536..fc3058223 100644 --- a/renderdoc/driver/vulkan/vk_common.h +++ b/renderdoc/driver/vulkan/vk_common.h @@ -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, }; diff --git a/renderdoc/driver/vulkan/vk_debug.cpp b/renderdoc/driver/vulkan/vk_debug.cpp index 228dff688..e6b46d058 100644 --- a/renderdoc/driver/vulkan/vk_debug.cpp +++ b/renderdoc/driver/vulkan/vk_debug.cpp @@ -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); } diff --git a/renderdoc/driver/vulkan/vk_memory.cpp b/renderdoc/driver/vulkan/vk_memory.cpp index 9f70970bd..c754db8e6 100644 --- a/renderdoc/driver/vulkan/vk_memory.cpp +++ b/renderdoc/driver/vulkan/vk_memory.cpp @@ -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 &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; diff --git a/renderdoc/driver/vulkan/vk_replay.h b/renderdoc/driver/vulkan/vk_replay.h index d0c052d83..e09124a47 100644 --- a/renderdoc/driver/vulkan/vk_replay.h +++ b/renderdoc/driver/vulkan/vk_replay.h @@ -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] = {};