ContiguousArrayAllocator.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  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/Scene/ContiguousArrayAllocator.h>
  6. #include <AnKi/Scene/SceneGraph.h>
  7. #include <AnKi/Core/ConfigSet.h>
  8. #include <AnKi/Gr/GrManager.h>
  9. namespace anki {
  10. void AllGpuSceneContiguousArrays::ContiguousArrayAllocator::destroy(GpuSceneMemoryPool* gpuScene,
  11. HeapMemoryPool* cpuPool)
  12. {
  13. for(U32 i = 0; i < kMaxFramesInFlight; ++i)
  14. {
  15. collectGarbage(i, gpuScene, cpuPool);
  16. }
  17. }
  18. AllGpuSceneContiguousArrays::ContiguousArrayAllocator::Index
  19. AllGpuSceneContiguousArrays::ContiguousArrayAllocator::allocateObject(GpuSceneMemoryPool* gpuScene,
  20. HeapMemoryPool* cpuPool)
  21. {
  22. ANKI_ASSERT(gpuScene && cpuPool);
  23. LockGuard lock(m_mtx);
  24. if(m_poolToken.m_offset == kMaxPtrSize)
  25. {
  26. // Initialize
  27. const U32 alignment = sizeof(U32);
  28. gpuScene->allocate(m_objectSize * m_initialArraySize, alignment, m_poolToken);
  29. m_nextSlotIndex = 0;
  30. m_freeSlotStack.create(*cpuPool, m_initialArraySize);
  31. for(U32 i = 0; i < m_initialArraySize; ++i)
  32. {
  33. m_freeSlotStack[i] = i;
  34. }
  35. }
  36. else if(m_nextSlotIndex == m_freeSlotStack.getSize())
  37. {
  38. // Grow
  39. ANKI_ASSERT(!"TODO");
  40. }
  41. const Index idx = m_freeSlotStack[m_nextSlotIndex];
  42. ++m_nextSlotIndex;
  43. ANKI_ASSERT(idx < m_freeSlotStack.getSize());
  44. return idx;
  45. }
  46. void AllGpuSceneContiguousArrays::ContiguousArrayAllocator::deferredFree(U32 crntFrameIdx, HeapMemoryPool* cpuPool,
  47. Index index)
  48. {
  49. ANKI_ASSERT(cpuPool);
  50. LockGuard lock(m_mtx);
  51. ANKI_ASSERT(index < m_freeSlotStack.getSize());
  52. m_garbage[crntFrameIdx].emplaceBack(*cpuPool, index);
  53. }
  54. void AllGpuSceneContiguousArrays::ContiguousArrayAllocator::collectGarbage(U32 newFrameIdx,
  55. GpuSceneMemoryPool* gpuScene,
  56. HeapMemoryPool* cpuPool)
  57. {
  58. ANKI_ASSERT(gpuScene && cpuPool);
  59. LockGuard lock(m_mtx);
  60. if(m_garbage[newFrameIdx].getSize() == 0) [[likely]]
  61. {
  62. return;
  63. }
  64. // Release deferred frees
  65. for(Index idx : m_garbage[newFrameIdx])
  66. {
  67. ANKI_ASSERT(m_nextSlotIndex > 0);
  68. --m_nextSlotIndex;
  69. m_freeSlotStack[m_nextSlotIndex] = idx;
  70. }
  71. m_garbage[newFrameIdx].destroy(*cpuPool);
  72. // Sort so we can keep memory close to the beginning of the array for better cache behaviour
  73. std::sort(m_freeSlotStack.getBegin() + m_nextSlotIndex, m_freeSlotStack.getEnd());
  74. // Adjust the stack size
  75. const U32 allocatedSlots = m_nextSlotIndex;
  76. if(U32(F32(allocatedSlots) * m_growRate) < m_freeSlotStack.getSize()
  77. && m_freeSlotStack.getSize() > m_initialArraySize)
  78. {
  79. // Shrink
  80. ANKI_ASSERT(!"TODO");
  81. }
  82. else if(allocatedSlots == 0)
  83. {
  84. ANKI_ASSERT(m_nextSlotIndex == 0);
  85. gpuScene->deferredFree(m_poolToken);
  86. m_freeSlotStack.destroy(*cpuPool);
  87. }
  88. }
  89. void AllGpuSceneContiguousArrays::init(SceneGraph* scene)
  90. {
  91. m_scene = scene;
  92. const ConfigSet& cfg = *scene->m_subsystems.m_config;
  93. constexpr F32 kGrowRate = 2.0;
  94. const Array<U32, U32(GpuSceneContiguousArrayType::kCount)> minElementCount = {
  95. cfg.getSceneMinGpuSceneTransforms(), cfg.getSceneMinGpuSceneMeshes(),
  96. cfg.getSceneMinGpuSceneParticleEmitters(), cfg.getSceneMinGpuSceneLights(),
  97. cfg.getSceneMinGpuSceneReflectionProbes(), cfg.getSceneMinGpuSceneGlobalIlluminationProbes(),
  98. cfg.getSceneMinGpuSceneDecals(), cfg.getSceneMinGpuSceneFogDensityVolumes()};
  99. for(GpuSceneContiguousArrayType type : EnumIterable<GpuSceneContiguousArrayType>())
  100. {
  101. const U32 initialArraySize = minElementCount[type] / m_componentCount[type];
  102. const U16 elementSize = m_componentSize[type] * m_componentCount[type];
  103. m_allocs[type].init(initialArraySize, elementSize, kGrowRate);
  104. }
  105. }
  106. void AllGpuSceneContiguousArrays::destroy()
  107. {
  108. for(GpuSceneContiguousArrayType type : EnumIterable<GpuSceneContiguousArrayType>())
  109. {
  110. m_allocs[type].destroy(m_scene->m_subsystems.m_gpuSceneMemoryPool, &m_scene->m_pool);
  111. }
  112. }
  113. PtrSize AllGpuSceneContiguousArrays::allocate(GpuSceneContiguousArrayType type)
  114. {
  115. const U32 idx = m_allocs[type].allocateObject(m_scene->m_subsystems.m_gpuSceneMemoryPool, &m_scene->m_pool);
  116. return PtrSize(idx) * m_componentCount[type] * m_componentSize[type] + m_allocs[type].m_poolToken.m_offset;
  117. }
  118. void AllGpuSceneContiguousArrays::deferredFree(GpuSceneContiguousArrayType type, PtrSize offset)
  119. {
  120. ANKI_ASSERT(offset >= m_allocs[type].m_poolToken.m_offset);
  121. offset -= m_allocs[type].m_poolToken.m_offset;
  122. ANKI_ASSERT((offset % (m_componentCount[type] * m_componentSize[type])) == 0);
  123. const U32 idx = U32(offset / (m_componentCount[type] * m_componentSize[type]));
  124. m_allocs[type].deferredFree(m_frame, &m_scene->m_pool, idx);
  125. }
  126. void AllGpuSceneContiguousArrays::endFrame()
  127. {
  128. m_frame = (m_frame + 1) % kMaxFramesInFlight;
  129. for(GpuSceneContiguousArrayType type : EnumIterable<GpuSceneContiguousArrayType>())
  130. {
  131. m_allocs[type].collectGarbage(m_frame, m_scene->m_subsystems.m_gpuSceneMemoryPool, &m_scene->m_pool);
  132. }
  133. }
  134. } // end namespace anki