From a14141eb52fa5e89d8f3b9948f488d13a07f46fa Mon Sep 17 00:00:00 2001 From: Benson Joeris Date: Wed, 4 Sep 2019 11:24:10 -0400 Subject: [PATCH] Align MemRef intervals (#1510) When initializing VkDeviceMemory resources, some regions may be cleared using vkCmdFillBuffer, rather than having initial data copied. vkCmdFillBuffer requires that the interval offset and size are multiples of 4. This change aligns all of the intervals containing the `FrameRefType`s used to determine the initialization requirements for VkDeviceMemory. This alignment is done as the intervals are loaded so that the initialization (before the first replay) and reset (before subsequent replays) use consisent alignment. Change-Id: Icb1a1ba5fc0045fc4ec1ccbfe9caad06154f2338 --- renderdoc/driver/vulkan/vk_initstate.cpp | 9 ++-- renderdoc/driver/vulkan/vk_manager.cpp | 55 +++++++++++++++++++++--- 2 files changed, 56 insertions(+), 8 deletions(-) diff --git a/renderdoc/driver/vulkan/vk_initstate.cpp b/renderdoc/driver/vulkan/vk_initstate.cpp index 41298d0d6..3a0c92805 100644 --- a/renderdoc/driver/vulkan/vk_initstate.cpp +++ b/renderdoc/driver/vulkan/vk_initstate.cpp @@ -2145,15 +2145,18 @@ void WrappedVulkan::Apply_InitialState(WrappedVkRes *live, const VkInitialConten { if(it->start() >= initial.mem.size) continue; + VkDeviceSize start = it->start(); VkDeviceSize finish = RDCMIN(it->finish(), initial.mem.size); - VkDeviceSize size = finish - it->start(); + VkDeviceSize size = finish - start; switch(it->value()) { case eInitReq_Clear: - ObjDisp(cmd)->CmdFillBuffer(Unwrap(cmd), Unwrap(dstBuf), it->start(), size, 0); + if(finish >= initial.mem.size) + size = VK_WHOLE_SIZE; + ObjDisp(cmd)->CmdFillBuffer(Unwrap(cmd), Unwrap(dstBuf), start, size, 0); fillCount++; break; - case eInitReq_Copy: regions.push_back({it->start(), it->start(), size}); break; + case eInitReq_Copy: regions.push_back({start, start, size}); break; default: break; } } diff --git a/renderdoc/driver/vulkan/vk_manager.cpp b/renderdoc/driver/vulkan/vk_manager.cpp index b79988df7..dbeaed409 100644 --- a/renderdoc/driver/vulkan/vk_manager.cpp +++ b/renderdoc/driver/vulkan/vk_manager.cpp @@ -433,18 +433,63 @@ bool VulkanResourceManager::Serialise_DeviceMemoryRefs(SerialiserType &ser, ResourceId mem = it_data->memory; auto res = m_MemFrameRefs.insert(std::pair(mem, MemRefs())); - RDCASSERTMSG("MemRefIntervals for each memory resource must be contigous", res.second); + RDCASSERTMSG("MemRefIntervals for each memory resource must be contiguous", res.second); Intervals &rangeRefs = res.first->second.rangeRefs; auto it_ints = rangeRefs.begin(); uint64_t last = 0; + FrameRefType lastRef = eFrameRef_None; while(it_data != data.end() && it_data->memory == mem) { - RDCASSERT("MemRefInterval starts must be strictly increasing", - it_data->start > last || last == 0); - last = it_data->start; - it_ints->split(it_data->start); + uint64_t start = it_data->start; + if(start & 0x3) + { + // start is not a multiple of 4. We need to shift start to a multiple of 4 to satisfy the + // alignment requirements of `vkCmdFillBuffer`. + + uint64_t nextDWord = AlignUp4(start); + + // Compute the overall ref type for the dword, including all the ref types of intervals + // intersecting the dword + FrameRefType overlapRef = lastRef; + for(; it_data->start < nextDWord; ++it_data) + overlapRef = ComposeFrameRefsDisjoint(overlapRef, it_data->refType); + + --it_data; + // it_data now points to the last interval intersecting the dword. + + if(overlapRef == lastRef) + { + // The ref type for the overlap dword is the same as the ref type of the previous + // interval; move the entire overlap dword into the previous interval, which means the + // start of this interval moves up to the the next higher dword. + start = nextDWord; + } + else if(overlapRef == it_data->refType) + { + // The ref type for the overlap dword is the same as for this interval; move the entire + // overlap dword into this interval, which means the start of this interval moves down + // to the next lower dword. + start = nextDWord - 4; + } + else + { + // The ref type of the overlap dword matches neither the previous interval nor this + // interval; insert a new interval for the overlap. + if(last < nextDWord - 4) + it_ints->split(nextDWord - 4); + it_ints->setValue(overlapRef); + last = nextDWord - 4; + start = nextDWord; + } + } + RDCASSERT("MemRefInterval starts must be increasing", start >= last); + + if(last < start) + it_ints->split(start); it_ints->setValue(it_data->refType); + last = start; + lastRef = it_data->refType; it_data++; } }