RebarTransientMemoryPool.cpp 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. // Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/Core/GpuMemory/RebarTransientMemoryPool.h>
  6. #include <AnKi/Core/ConfigSet.h>
  7. #include <AnKi/Core/StatsSet.h>
  8. #include <AnKi/Util/Tracer.h>
  9. #include <AnKi/Gr/GrManager.h>
  10. #include <AnKi/Gr/Buffer.h>
  11. namespace anki {
  12. static StatCounter g_rebarUserMemory(StatCategory::kGpuMem, "ReBAR used mem", StatFlag::kBytes);
  13. static NumericCVar<PtrSize> g_rebarGpuMemorySizeCvar(CVarSubsystem::kCore, "RebarGpuMemorySize", 24_MB, 1_MB, 1_GB,
  14. "ReBAR: always mapped GPU memory");
  15. RebarTransientMemoryPool::~RebarTransientMemoryPool()
  16. {
  17. GrManager::getSingleton().finish();
  18. m_buffer->unmap();
  19. m_buffer.reset(nullptr);
  20. }
  21. void RebarTransientMemoryPool::init()
  22. {
  23. BufferInitInfo buffInit("ReBar");
  24. buffInit.m_mapAccess = BufferMapAccessBit::kWrite;
  25. buffInit.m_size = g_rebarGpuMemorySizeCvar.get();
  26. buffInit.m_usage = BufferUsageBit::kAllUniform | BufferUsageBit::kAllStorage | BufferUsageBit::kVertex | BufferUsageBit::kIndex
  27. | BufferUsageBit::kShaderBindingTable | BufferUsageBit::kAllIndirect;
  28. m_buffer = GrManager::getSingleton().newBuffer(buffInit);
  29. m_bufferSize = buffInit.m_size;
  30. m_alignment = GrManager::getSingleton().getDeviceCapabilities().m_uniformBufferBindOffsetAlignment;
  31. m_alignment = max(m_alignment, GrManager::getSingleton().getDeviceCapabilities().m_storageBufferBindOffsetAlignment);
  32. m_alignment = max(m_alignment, GrManager::getSingleton().getDeviceCapabilities().m_sbtRecordAlignment);
  33. m_mappedMem = static_cast<U8*>(m_buffer->map(0, kMaxPtrSize, BufferMapAccessBit::kWrite));
  34. }
  35. void* RebarTransientMemoryPool::allocateFrame(PtrSize size, RebarAllocation& token)
  36. {
  37. void* address = tryAllocateFrame(size, token);
  38. if(address == nullptr) [[unlikely]]
  39. {
  40. ANKI_CORE_LOGF("Out of ReBAR GPU memory");
  41. }
  42. return address;
  43. }
  44. void* RebarTransientMemoryPool::tryAllocateFrame(PtrSize origSize, RebarAllocation& token)
  45. {
  46. const PtrSize size = getAlignedRoundUp(m_alignment, origSize);
  47. // Try in a loop because we may end up with an allocation its offset crosses the buffer's end
  48. PtrSize offset;
  49. Bool done = false;
  50. do
  51. {
  52. offset = m_offset.fetchAdd(size) % m_bufferSize;
  53. const PtrSize end = (offset + origSize) % (m_bufferSize + 1);
  54. done = offset < end;
  55. } while(!done);
  56. void* address = m_mappedMem + offset;
  57. token.m_offset = offset;
  58. token.m_range = origSize;
  59. return address;
  60. }
  61. void RebarTransientMemoryPool::endFrame()
  62. {
  63. const PtrSize crntOffset = m_offset.getNonAtomically();
  64. const PtrSize usedMemory = crntOffset - m_previousFrameEndOffset;
  65. m_previousFrameEndOffset = crntOffset;
  66. if(usedMemory >= PtrSize(0.8 * F64(m_bufferSize / kMaxFramesInFlight)))
  67. {
  68. ANKI_CORE_LOGW("Frame used more that 80%% of its safe limit of ReBAR memory");
  69. }
  70. ANKI_TRACE_INC_COUNTER(ReBarUsedMemory, usedMemory);
  71. g_rebarUserMemory.set(usedMemory);
  72. }
  73. } // end namespace anki