GpuSceneBuffer.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  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/GpuSceneBuffer.h>
  6. #include <AnKi/Core/GpuMemory/RebarTransientMemoryPool.h>
  7. #include <AnKi/Core/ConfigSet.h>
  8. #include <AnKi/Core/StatsSet.h>
  9. #include <AnKi/Util/Tracer.h>
  10. #include <AnKi/Resource/ResourceManager.h>
  11. #include <AnKi/Gr/CommandBuffer.h>
  12. namespace anki {
  13. static StatCounter g_gpuSceneBufferAllocatedSize(StatCategory::kGpuMem, "GPU scene allocated", StatFlag::kBytes);
  14. static StatCounter g_gpuSceneBufferTotal(StatCategory::kGpuMem, "GPU scene total", StatFlag::kBytes);
  15. static StatCounter g_gpuSceneBufferFragmentation(StatCategory::kGpuMem, "GPU scene fragmentation", StatFlag::kFloat);
  16. static NumericCVar<PtrSize> g_gpuSceneInitialSizeCVar(CVarSubsystem::kCore, "GpuSceneInitialSize", 64_MB, 16_MB, 2_GB,
  17. "Global memory for the GPU scene");
  18. void GpuSceneBuffer::init()
  19. {
  20. const PtrSize poolSize = g_gpuSceneInitialSizeCVar.get();
  21. const Array classes = {32_B, 64_B, 128_B, 256_B, poolSize};
  22. BufferUsageBit buffUsage = BufferUsageBit::kAllStorage | BufferUsageBit::kTransferDestination;
  23. m_pool.init(buffUsage, classes, poolSize, "GpuScene", true);
  24. // Allocate something dummy to force creating the GPU buffer
  25. GpuSceneBufferAllocation alloc;
  26. allocate(16, 4, alloc);
  27. deferredFree(alloc);
  28. }
  29. void GpuSceneBuffer::updateStats() const
  30. {
  31. F32 externalFragmentation;
  32. PtrSize userAllocatedSize, totalSize;
  33. m_pool.getStats(externalFragmentation, userAllocatedSize, totalSize);
  34. g_gpuSceneBufferAllocatedSize.set(userAllocatedSize);
  35. g_gpuSceneBufferTotal.set(totalSize);
  36. g_gpuSceneBufferFragmentation.set(externalFragmentation);
  37. }
  38. /// It packs the source and destination offsets as well as the size of the patch itself.
  39. class GpuSceneMicroPatcher::PatchHeader
  40. {
  41. public:
  42. U32 m_dwordCountAndSrcDwordOffsetPack;
  43. U32 m_dstDwordOffset;
  44. };
  45. GpuSceneMicroPatcher::GpuSceneMicroPatcher()
  46. {
  47. }
  48. GpuSceneMicroPatcher::~GpuSceneMicroPatcher()
  49. {
  50. static_assert(sizeof(PatchHeader) == 8);
  51. }
  52. Error GpuSceneMicroPatcher::init()
  53. {
  54. ANKI_CHECK(ResourceManager::getSingleton().loadResource("ShaderBinaries/GpuSceneMicroPatching.ankiprogbin", m_copyProgram));
  55. const ShaderProgramResourceVariant* variant;
  56. m_copyProgram->getOrCreateVariant(variant);
  57. m_grProgram.reset(&variant->getProgram());
  58. return Error::kNone;
  59. }
  60. void GpuSceneMicroPatcher::newCopy(StackMemoryPool& frameCpuPool, PtrSize gpuSceneDestOffset, PtrSize dataSize, const void* data)
  61. {
  62. ANKI_ASSERT(dataSize > 0 && (dataSize % 4) == 0);
  63. ANKI_ASSERT((ptrToNumber(data) % 4) == 0);
  64. ANKI_ASSERT((gpuSceneDestOffset % 4) == 0 && gpuSceneDestOffset / 4 < kMaxU32);
  65. const U32 dataDwords = U32(dataSize / 4);
  66. U32 gpuSceneDestDwordOffset = U32(gpuSceneDestOffset / 4);
  67. const U32* patchIt = static_cast<const U32*>(data);
  68. const U32* const patchEnd = patchIt + dataDwords;
  69. // Break the data into multiple copies
  70. LockGuard lock(m_mtx);
  71. if(m_crntFramePatchHeaders.getSize() == 0)
  72. {
  73. m_crntFramePatchHeaders = DynamicArray<PatchHeader, MemoryPoolPtrWrapper<StackMemoryPool>>(&frameCpuPool);
  74. m_crntFramePatchData = DynamicArray<U32, MemoryPoolPtrWrapper<StackMemoryPool>>(&frameCpuPool);
  75. }
  76. while(patchIt < patchEnd)
  77. {
  78. const U32 patchDwords = min(kDwordsPerPatch, U32(patchEnd - patchIt));
  79. PatchHeader& header = *m_crntFramePatchHeaders.emplaceBack();
  80. ANKI_ASSERT(((patchDwords - 1) & 0b111111) == (patchDwords - 1));
  81. header.m_dwordCountAndSrcDwordOffsetPack = patchDwords - 1;
  82. header.m_dwordCountAndSrcDwordOffsetPack <<= 26;
  83. ANKI_ASSERT((m_crntFramePatchData.getSize() & 0x3FFFFFF) == m_crntFramePatchData.getSize());
  84. header.m_dwordCountAndSrcDwordOffsetPack |= m_crntFramePatchData.getSize();
  85. header.m_dstDwordOffset = gpuSceneDestDwordOffset;
  86. const U32 srcOffset = m_crntFramePatchData.getSize();
  87. m_crntFramePatchData.resize(srcOffset + patchDwords);
  88. memcpy(&m_crntFramePatchData[srcOffset], patchIt, patchDwords * 4);
  89. patchIt += patchDwords;
  90. gpuSceneDestDwordOffset += patchDwords;
  91. }
  92. }
  93. void GpuSceneMicroPatcher::patchGpuScene(CommandBuffer& cmdb)
  94. {
  95. if(m_crntFramePatchHeaders.getSize() == 0)
  96. {
  97. return;
  98. }
  99. ANKI_ASSERT(m_crntFramePatchData.getSize() > 0);
  100. ANKI_TRACE_INC_COUNTER(GpuSceneMicroPatches, m_crntFramePatchHeaders.getSize());
  101. ANKI_TRACE_INC_COUNTER(GpuSceneMicroPatchUploadData, m_crntFramePatchData.getSizeInBytes());
  102. RebarAllocation headersToken;
  103. void* mapped = RebarTransientMemoryPool::getSingleton().allocateFrame(m_crntFramePatchHeaders.getSizeInBytes(), headersToken);
  104. memcpy(mapped, &m_crntFramePatchHeaders[0], m_crntFramePatchHeaders.getSizeInBytes());
  105. RebarAllocation dataToken;
  106. mapped = RebarTransientMemoryPool::getSingleton().allocateFrame(m_crntFramePatchData.getSizeInBytes(), dataToken);
  107. memcpy(mapped, &m_crntFramePatchData[0], m_crntFramePatchData.getSizeInBytes());
  108. cmdb.bindStorageBuffer(0, 0, &RebarTransientMemoryPool::getSingleton().getBuffer(), headersToken.m_offset, headersToken.m_range);
  109. cmdb.bindStorageBuffer(0, 1, &RebarTransientMemoryPool::getSingleton().getBuffer(), dataToken.m_offset, dataToken.m_range);
  110. cmdb.bindStorageBuffer(0, 2, &GpuSceneBuffer::getSingleton().getBuffer(), 0, kMaxPtrSize);
  111. cmdb.bindShaderProgram(m_grProgram.get());
  112. const U32 workgroupCountX = m_crntFramePatchHeaders.getSize();
  113. cmdb.dispatchCompute(workgroupCountX, 1, 1);
  114. // Cleanup to prepare for the new frame
  115. U32* data;
  116. U32 size, storage;
  117. m_crntFramePatchData.moveAndReset(data, size, storage);
  118. PatchHeader* datah;
  119. m_crntFramePatchHeaders.moveAndReset(datah, size, storage);
  120. }
  121. } // end namespace anki