TransferGpuAllocator.cpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. // Copyright (C) 2009-2022, 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/Resource/TransferGpuAllocator.h>
  6. #include <AnKi/Gr/Fence.h>
  7. #include <AnKi/Gr/Buffer.h>
  8. #include <AnKi/Gr/GrManager.h>
  9. #include <AnKi/Util/Tracer.h>
  10. namespace anki {
  11. Error TransferGpuAllocator::StackAllocatorBuilderInterface::allocateChunk(PtrSize size, Chunk*& out)
  12. {
  13. out = m_parent->m_alloc.newInstance<Chunk>();
  14. BufferInitInfo bufferInit(size, BufferUsageBit::TRANSFER_SOURCE, BufferMapAccessBit::WRITE, "Transfer");
  15. out->m_buffer = m_parent->m_gr->newBuffer(bufferInit);
  16. out->m_mappedBuffer = out->m_buffer->map(0, MAX_PTR_SIZE, BufferMapAccessBit::WRITE);
  17. return Error::NONE;
  18. }
  19. void TransferGpuAllocator::StackAllocatorBuilderInterface::freeChunk(Chunk* chunk)
  20. {
  21. ANKI_ASSERT(chunk);
  22. chunk->m_buffer->unmap();
  23. m_parent->m_alloc.deleteInstance(chunk);
  24. }
  25. TransferGpuAllocator::TransferGpuAllocator()
  26. {
  27. }
  28. TransferGpuAllocator::~TransferGpuAllocator()
  29. {
  30. for(Pool& pool : m_pools)
  31. {
  32. ANKI_ASSERT(pool.m_pendingReleases == 0);
  33. pool.m_fences.destroy(m_alloc);
  34. }
  35. }
  36. Error TransferGpuAllocator::init(PtrSize maxSize, GrManager* gr, ResourceAllocator<U8> alloc)
  37. {
  38. m_alloc = alloc;
  39. m_gr = gr;
  40. m_maxAllocSize = getAlignedRoundUp(CHUNK_INITIAL_SIZE * POOL_COUNT, maxSize);
  41. ANKI_RESOURCE_LOGI("Will use %zuMB of memory for transfer scratch", m_maxAllocSize / PtrSize(1_MB));
  42. for(Pool& pool : m_pools)
  43. {
  44. pool.m_stackAlloc.getInterface().m_parent = this;
  45. }
  46. return Error::NONE;
  47. }
  48. Error TransferGpuAllocator::allocate(PtrSize size, TransferGpuAllocatorHandle& handle)
  49. {
  50. ANKI_TRACE_SCOPED_EVENT(RSRC_ALLOCATE_TRANSFER);
  51. const PtrSize poolSize = m_maxAllocSize / POOL_COUNT;
  52. LockGuard<Mutex> lock(m_mtx);
  53. Pool* pool;
  54. if(m_crntPoolAllocatedSize + size <= poolSize)
  55. {
  56. // Have enough space in the pool
  57. pool = &m_pools[m_crntPool];
  58. }
  59. else
  60. {
  61. // Don't have enough space. Wait for one pool used in the past
  62. m_crntPool = U8((m_crntPool + 1) % POOL_COUNT);
  63. pool = &m_pools[m_crntPool];
  64. {
  65. ANKI_TRACE_SCOPED_EVENT(RSRC_WAIT_TRANSFER);
  66. // Wait for all memory to be released
  67. while(pool->m_pendingReleases != 0)
  68. {
  69. m_condVar.wait(m_mtx);
  70. }
  71. // All memory is released, loop until all fences are triggered
  72. while(!pool->m_fences.isEmpty())
  73. {
  74. FencePtr fence = pool->m_fences.getFront();
  75. const Bool done = fence->clientWait(MAX_FENCE_WAIT_TIME);
  76. if(done)
  77. {
  78. pool->m_fences.popFront(m_alloc);
  79. }
  80. }
  81. }
  82. pool->m_stackAlloc.reset();
  83. m_crntPoolAllocatedSize = 0;
  84. }
  85. Chunk* chunk;
  86. PtrSize offset;
  87. [[maybe_unused]] const Error err = pool->m_stackAlloc.allocate(size, GPU_BUFFER_ALIGNMENT, chunk, offset);
  88. ANKI_ASSERT(!err);
  89. handle.m_buffer = chunk->m_buffer;
  90. handle.m_mappedMemory = static_cast<U8*>(chunk->m_mappedBuffer) + offset;
  91. handle.m_offsetInBuffer = offset;
  92. handle.m_range = size;
  93. handle.m_pool = U8(pool - &m_pools[0]);
  94. m_crntPoolAllocatedSize += size;
  95. ++pool->m_pendingReleases;
  96. // Do a cleanup of done fences. Do that to avoid having too many fences alive. Fences are implemented with file
  97. // decriptors in Linux and we don't want to exceed the process' limit of max open file descriptors
  98. for(Pool& p : m_pools)
  99. {
  100. List<FencePtr>::Iterator it = p.m_fences.getBegin();
  101. while(it != p.m_fences.getEnd())
  102. {
  103. const Bool fenceDone = (*it)->clientWait(0.0);
  104. if(fenceDone)
  105. {
  106. auto nextIt = it + 1;
  107. p.m_fences.erase(m_alloc, it);
  108. it = nextIt;
  109. }
  110. else
  111. {
  112. ++it;
  113. }
  114. }
  115. }
  116. return Error::NONE;
  117. }
  118. void TransferGpuAllocator::release(TransferGpuAllocatorHandle& handle, FencePtr fence)
  119. {
  120. ANKI_ASSERT(fence);
  121. ANKI_ASSERT(handle.valid());
  122. Pool& pool = m_pools[handle.m_pool];
  123. {
  124. LockGuard<Mutex> lock(m_mtx);
  125. pool.m_fences.pushBack(m_alloc, fence);
  126. ANKI_ASSERT(pool.m_pendingReleases > 0);
  127. --pool.m_pendingReleases;
  128. m_condVar.notifyOne();
  129. }
  130. handle.invalidate();
  131. }
  132. } // end namespace anki