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
This commit is contained in:
Benson Joeris
2019-09-04 11:24:10 -04:00
committed by Baldur Karlsson
parent 16164d5157
commit a14141eb52
2 changed files with 56 additions and 8 deletions
+6 -3
View File
@@ -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;
}
}
+50 -5
View File
@@ -433,18 +433,63 @@ bool VulkanResourceManager::Serialise_DeviceMemoryRefs(SerialiserType &ser,
ResourceId mem = it_data->memory;
auto res = m_MemFrameRefs.insert(std::pair<ResourceId, MemRefs>(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<FrameRefType> &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++;
}
}