Make sure that when checking persistent maps, refdata matches serialised

* The comment goes into more detail, but basically if there's a delay
  between fetching the first full-flush of the map, and fetching the
  ref data, some changes could happen in between and get lost.
This commit is contained in:
baldurk
2016-01-24 19:07:25 +01:00
parent 19a0fc5094
commit c0717042de
3 changed files with 37 additions and 6 deletions
+3 -1
View File
@@ -686,9 +686,11 @@ struct MemMapState
{
MemMapState()
: mapOffset(0), mapSize(0)
, mapFlushed(false), mapCoherent(false), mappedPtr(NULL), refData(NULL)
, needRefData(false), mapFlushed(false), mapCoherent(false)
, mappedPtr(NULL), refData(NULL)
{ }
VkDeviceSize mapOffset, mapSize;
bool needRefData;
bool mapFlushed;
bool mapCoherent;
byte *mappedPtr;
@@ -593,16 +593,26 @@ VkResult WrappedVulkan::vkQueueSubmit(
(VkDeviceMemory)(uint64_t)record->Resource,
state.mapOffset+diffStart, diffEnd-diffStart
};
// this causes the call within to allocate state.refData and copy what was
// serialised into it. We want to copy *precisely* the serialised data,
// otherwise there is a gap in time between serialising out a snapshot of
// the buffer and whenever we then copy into the ref data, e.g. below.
// during this time, data could be written to the buffer and it won't have
// been caught in the serialised snapshot, and if it doesn't change then
// it *also* won't be caught in any future FindDiffRange() calls.
//
// Note: it's still possible that data is being written to by the
// application while it's being serialised out in the snapshot below. That
// is OK, since the application is responsible for ensuring it's not writing
// data that would be needed by the GPU in this submit. As long as the
// refdata we use for future use is identical to what was serialised, we
// shouldn't miss anything
state.needRefData = true;
vkFlushMappedMemoryRanges(dev, 1, &range);
state.mapFlushed = false;
}
GetResourceManager()->MarkPendingDirty(record->GetResourceID());
// allocate ref data so we can compare next time to minimise serialised data
if(state.refData == NULL)
state.refData = Serialiser::AllocAlignedBuffer((size_t)state.mapSize, 64);
memcpy(state.refData, state.mappedPtr, (size_t)state.mapSize);
}
else
{
@@ -487,6 +487,25 @@ bool WrappedVulkan::Serialise_vkFlushMappedMemoryRanges(
SERIALISE_ELEMENT(uint64_t, memSize, pMemRanges->size);
SERIALISE_ELEMENT_BUF(byte*, data, state->mappedPtr + (size_t)memOffset, (size_t)memSize);
// if we need to save off this serialised buffer as reference for future comparison,
// do so now. See the call to vkFlushMappedMemoryRanges in WrappedVulkan::vkQueueSubmit()
if(m_State >= WRITING && state->needRefData && !state->refData)
{
// if we're in this case, the range should be for the whole memory region.
RDCASSERT(memOffset == 0 && memSize == state->mapSize);
// it's no longer safe to use state->mappedPtr, we need to save *precisely* what
// was serialised. We do this by copying out of the serialiser since we know this
// memory is not changing
size_t offs = size_t(localSerialiser->GetOffset() - memSize);
byte *serialisedData = localSerialiser->GetRawPtr(offs);
// allocate ref data so we can compare next time to minimise serialised data
state->refData = Serialiser::AllocAlignedBuffer((size_t)state->mapSize);
memcpy(state->refData, serialisedData, (size_t)state->mapSize);
}
if(m_State < WRITING)
{
device = GetResourceManager()->GetLiveHandle<VkDevice>(devId);