Support nested GetTempMemory calls on replay

* On capture we have a fast temporary thread-local memory allocator that only
  supports one allocation at a time, which is sufficient for unwrapping the
  parameters to a single function call.
* On replay though we might want to unwrap a function's parameters, and then
  inside do things like e.g. call a drawcall callback which makes its own calls
  that need to be unwrapped.
* To support these nested calls we instead allocate 4MB per thread on replay and
  use it like a ring buffer.
This commit is contained in:
baldurk
2021-04-15 14:25:05 +01:00
parent 7b18d1c68e
commit cf50fef33a
2 changed files with 40 additions and 1 deletions
+32
View File
@@ -608,8 +608,40 @@ void WrappedVulkan::SetDebugMessageSink(WrappedVulkan::ScopedDebugMessageSink *s
Threading::SetTLSValue(debugMessageSinkTLSSlot, (void *)sink);
}
byte *WrappedVulkan::GetRingTempMemory(size_t s)
{
TempMem *mem = (TempMem *)Threading::GetTLSValue(tempMemoryTLSSlot);
if(!mem || mem->size < s)
{
if(mem && mem->size < s)
RDCWARN("More than %zu bytes needed to unwrap!", mem->size);
mem = new TempMem();
mem->size = AlignUp(s, size_t(4 * 1024 * 1024));
mem->memory = mem->cur = new byte[mem->size];
SCOPED_LOCK(m_ThreadTempMemLock);
m_ThreadTempMem.push_back(mem);
Threading::SetTLSValue(tempMemoryTLSSlot, (void *)mem);
}
// if we'd wrap, go back to the start
if(mem->cur + s >= mem->memory + mem->size)
mem->cur = mem->memory;
// save the return value and update the cur pointer
byte *ret = mem->cur;
mem->cur = AlignUpPtr(mem->cur + s, 16);
return ret;
}
byte *WrappedVulkan::GetTempMemory(size_t s)
{
if(IsReplayMode(m_State))
return GetRingTempMemory(s);
TempMem *mem = (TempMem *)Threading::GetTLSValue(tempMemoryTLSSlot);
if(mem && mem->size >= s)
return mem->memory;
+8 -1
View File
@@ -309,8 +309,9 @@ private:
uint64_t tempMemoryTLSSlot;
struct TempMem
{
TempMem() : memory(NULL), size(0) {}
TempMem() : memory(NULL), cur(NULL), size(0) {}
byte *memory;
byte *cur;
size_t size;
};
Threading::CriticalSection m_ThreadTempMemLock;
@@ -821,6 +822,12 @@ private:
bytebuf m_MaskedMapData;
// on replay we may need to allocate several bits of temporary memory, so the single-region
// doesn't work as well. We're not quite as performance-sensitive so we allocate 4MB per thread
// and use it in a ring-buffer fashion. This allows multiple allocations to live at once as long
// as we don't need it all in one stack.
byte *GetRingTempMemory(size_t s);
// returns thread-local temporary memory
byte *GetTempMemory(size_t s);
template <class T>