GpuSceneBuffer.cpp 5.6 KB

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