diff --git a/renderdoc/driver/vulkan/vk_core.cpp b/renderdoc/driver/vulkan/vk_core.cpp index 7e2364900..9063e3429 100644 --- a/renderdoc/driver/vulkan/vk_core.cpp +++ b/renderdoc/driver/vulkan/vk_core.cpp @@ -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; diff --git a/renderdoc/driver/vulkan/vk_core.h b/renderdoc/driver/vulkan/vk_core.h index 9a1fea77c..bb7ffdca3 100644 --- a/renderdoc/driver/vulkan/vk_core.h +++ b/renderdoc/driver/vulkan/vk_core.h @@ -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