DynamicBufferAllocator.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <Atom/RPI.Public/Buffer/BufferSystemInterface.h>
  9. #include <Atom/RPI.Public/Buffer/Buffer.h>
  10. #include <Atom/RPI.Public/DynamicDraw/DynamicBufferAllocator.h>
  11. #include <Atom/RPI.Public/DynamicDraw/DynamicBuffer.h>
  12. namespace AZ
  13. {
  14. namespace RPI
  15. {
  16. void DynamicBufferAllocator::Init(uint32_t ringBufferSize)
  17. {
  18. if (m_ringBuffer)
  19. {
  20. AZ_Assert(false, "DynamicBufferAllocator was already initialized");
  21. return;
  22. }
  23. // Create the ring buffer from common pool
  24. RPI::CommonBufferDescriptor desc;
  25. desc.m_poolType = RPI::CommonBufferPoolType::DynamicInputAssembly;
  26. desc.m_bufferName = "DyanmicBufferRing";
  27. desc.m_elementSize = 1;
  28. desc.m_byteCount = ringBufferSize;
  29. m_ringBuffer = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc);
  30. if (m_ringBuffer.get() == nullptr)
  31. {
  32. AZ_Assert(false, "Failed to initialize DyanmicBufferAllocator");
  33. return;
  34. }
  35. m_ringBufferSize = ringBufferSize;
  36. m_ringBufferStartAddress = m_ringBuffer->Map(m_ringBufferSize, 0);
  37. m_currentPosition = 0;
  38. m_endPositionLimit = 0;
  39. m_currentFrame = 0;
  40. for (uint32_t frame = 0; frame < AZ::RHI::Limits::Device::FrameCountMax; frame++)
  41. {
  42. m_frameStartPositions[frame] = 0;
  43. }
  44. }
  45. void DynamicBufferAllocator::Shutdown()
  46. {
  47. m_ringBuffer->Unmap();
  48. m_ringBuffer = nullptr;
  49. m_ringBufferStartAddress = nullptr;
  50. }
  51. // [GFX TODO][ATOM-13182] Add unit tests for DynamicBufferAllocator's Allocate function
  52. RHI::Ptr<DynamicBuffer> DynamicBufferAllocator::Allocate(uint32_t size, [[maybe_unused]]uint32_t alignment)
  53. {
  54. size = RHI::AlignUp(size, alignment);
  55. uint32_t allocatePosition = 0;
  56. //m_ringBufferStartAddress can be null for Null back end
  57. if (!m_ringBufferStartAddress)
  58. {
  59. return nullptr;
  60. }
  61. if (size > m_ringBufferSize)
  62. {
  63. AZ_WarningOnce("RPI", !m_enableAllocationWarning, "DynamicBufferAllocator::Allocate: try to allocate buffer which size is larger than the ring buffer size");
  64. return nullptr;
  65. }
  66. // Return if the allocation of current frame has reached limit
  67. if (m_endPositionLimit == m_currentPosition && m_currentAllocatedSize > 0)
  68. {
  69. AZ_WarningOnce("RPI", !m_enableAllocationWarning, "DynamicBufferAllocator::Allocate: no more buffer is available");
  70. return nullptr;
  71. }
  72. if (m_endPositionLimit > m_currentPosition)
  73. {
  74. if (m_endPositionLimit - m_currentPosition >= size)
  75. {
  76. allocatePosition = m_currentPosition;
  77. m_currentPosition += size;
  78. }
  79. else
  80. {
  81. AZ_WarningOnce("RPI", !m_enableAllocationWarning, "DynamicBufferAllocator::Allocate: requested size (%d bytes) is larger than the size left (%d bytes)", size, m_endPositionLimit - m_currentPosition);
  82. return nullptr;
  83. }
  84. }
  85. else
  86. {
  87. if (m_ringBufferSize - m_currentPosition >= size)
  88. {
  89. allocatePosition = m_currentPosition;
  90. m_currentPosition += size;
  91. if (m_ringBufferSize == m_currentPosition)
  92. {
  93. m_currentPosition = 0;
  94. }
  95. }
  96. else
  97. {
  98. if (m_endPositionLimit >= size)
  99. {
  100. allocatePosition = 0;
  101. m_currentPosition = size;
  102. }
  103. else
  104. {
  105. AZ_WarningOnce("RPI", !m_enableAllocationWarning, "DynamicBufferAllocator::Allocate: requested size (%d bytes) is larger than the size left (%d bytes)", size, m_endPositionLimit);
  106. return nullptr;
  107. }
  108. }
  109. }
  110. m_currentAllocatedSize += size;
  111. RHI::Ptr<DynamicBuffer> allocatedBuffer = aznew DynamicBuffer();
  112. allocatedBuffer->m_address = (uint8_t*)m_ringBufferStartAddress + allocatePosition;
  113. allocatedBuffer->m_size = size;
  114. allocatedBuffer->m_allocator = this;
  115. return allocatedBuffer;
  116. }
  117. RHI::IndexBufferView DynamicBufferAllocator::GetIndexBufferView(RHI::Ptr<DynamicBuffer> dynamicBuffer, RHI::IndexFormat format)
  118. {
  119. return RHI::IndexBufferView(
  120. *m_ringBuffer->GetRHIBuffer(),
  121. GetBufferAddressOffset(dynamicBuffer),
  122. dynamicBuffer->m_size,
  123. format
  124. );
  125. }
  126. RHI::StreamBufferView DynamicBufferAllocator::GetStreamBufferView(RHI::Ptr<DynamicBuffer> dynamicBuffer, uint32_t strideByteCount)
  127. {
  128. return RHI::StreamBufferView(
  129. *m_ringBuffer->GetRHIBuffer(),
  130. GetBufferAddressOffset(dynamicBuffer),
  131. dynamicBuffer->m_size,
  132. strideByteCount
  133. );
  134. }
  135. uint32_t DynamicBufferAllocator::GetBufferAddressOffset(RHI::Ptr<DynamicBuffer> dynamicBuffer)
  136. {
  137. return aznumeric_cast<uint32_t>((uint8_t*)dynamicBuffer->m_address - (uint8_t*)m_ringBufferStartAddress);
  138. }
  139. void DynamicBufferAllocator::SetEnableAllocationWarning(bool enable)
  140. {
  141. m_enableAllocationWarning = enable;
  142. }
  143. void DynamicBufferAllocator::FrameEnd()
  144. {
  145. uint32_t nextFrame = (m_currentFrame + 1) % AZ::RHI::Limits::Device::FrameCountMax;
  146. // The saved frame start position will become available since it's old than FrameCountMax. The saved start position of next frame is the new limit
  147. m_endPositionLimit = m_frameStartPositions[nextFrame];
  148. // Save start position for current frame
  149. m_frameStartPositions[m_currentFrame] = m_currentPosition;
  150. m_currentFrame = nextFrame;
  151. m_currentAllocatedSize = 0;
  152. }
  153. }
  154. }