| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #include <Atom/RPI.Public/Buffer/BufferSystemInterface.h>
- #include <Atom/RPI.Public/Buffer/Buffer.h>
- #include <Atom/RPI.Public/DynamicDraw/DynamicBufferAllocator.h>
- #include <Atom/RPI.Public/DynamicDraw/DynamicBuffer.h>
- namespace AZ
- {
- namespace RPI
- {
- void DynamicBufferAllocator::Init(uint32_t ringBufferSize)
- {
- if (m_ringBuffer)
- {
- AZ_Assert(false, "DynamicBufferAllocator was already initialized");
- return;
- }
- // Create the ring buffer from common pool
- RPI::CommonBufferDescriptor desc;
- desc.m_poolType = RPI::CommonBufferPoolType::DynamicInputAssembly;
- desc.m_bufferName = "DyanmicBufferRing";
- desc.m_elementSize = 1;
- desc.m_byteCount = ringBufferSize;
- m_ringBuffer = RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc);
- if (m_ringBuffer.get() == nullptr)
- {
- AZ_Assert(false, "Failed to initialize DyanmicBufferAllocator");
- return;
- }
-
- m_ringBufferSize = ringBufferSize;
- m_ringBufferStartAddress = m_ringBuffer->Map(m_ringBufferSize, 0);
-
- m_currentPosition = 0;
- m_endPositionLimit = 0;
- m_currentFrame = 0;
- for (uint32_t frame = 0; frame < AZ::RHI::Limits::Device::FrameCountMax; frame++)
- {
- m_frameStartPositions[frame] = 0;
- }
- }
- void DynamicBufferAllocator::Shutdown()
- {
- m_ringBuffer->Unmap();
- m_ringBuffer = nullptr;
- m_ringBufferStartAddress = nullptr;
- }
- // [GFX TODO][ATOM-13182] Add unit tests for DynamicBufferAllocator's Allocate function
- RHI::Ptr<DynamicBuffer> DynamicBufferAllocator::Allocate(uint32_t size, [[maybe_unused]]uint32_t alignment)
- {
- size = RHI::AlignUp(size, alignment);
- uint32_t allocatePosition = 0;
- //m_ringBufferStartAddress can be null for Null back end
- if (!m_ringBufferStartAddress)
- {
- return nullptr;
- }
- if (size > m_ringBufferSize)
- {
- AZ_WarningOnce("RPI", !m_enableAllocationWarning, "DynamicBufferAllocator::Allocate: try to allocate buffer which size is larger than the ring buffer size");
- return nullptr;
- }
- // Return if the allocation of current frame has reached limit
- if (m_endPositionLimit == m_currentPosition && m_currentAllocatedSize > 0)
- {
- AZ_WarningOnce("RPI", !m_enableAllocationWarning, "DynamicBufferAllocator::Allocate: no more buffer is available");
- return nullptr;
- }
- if (m_endPositionLimit > m_currentPosition)
- {
- if (m_endPositionLimit - m_currentPosition >= size)
- {
- allocatePosition = m_currentPosition;
- m_currentPosition += size;
- }
- else
- {
- AZ_WarningOnce("RPI", !m_enableAllocationWarning, "DynamicBufferAllocator::Allocate: requested size (%d bytes) is larger than the size left (%d bytes)", size, m_endPositionLimit - m_currentPosition);
- return nullptr;
- }
- }
- else
- {
- if (m_ringBufferSize - m_currentPosition >= size)
- {
- allocatePosition = m_currentPosition;
- m_currentPosition += size;
- if (m_ringBufferSize == m_currentPosition)
- {
- m_currentPosition = 0;
- }
- }
- else
- {
- if (m_endPositionLimit >= size)
- {
- allocatePosition = 0;
- m_currentPosition = size;
- }
- else
- {
- AZ_WarningOnce("RPI", !m_enableAllocationWarning, "DynamicBufferAllocator::Allocate: requested size (%d bytes) is larger than the size left (%d bytes)", size, m_endPositionLimit);
- return nullptr;
- }
- }
- }
- m_currentAllocatedSize += size;
- RHI::Ptr<DynamicBuffer> allocatedBuffer = aznew DynamicBuffer();
- allocatedBuffer->m_address = (uint8_t*)m_ringBufferStartAddress + allocatePosition;
- allocatedBuffer->m_size = size;
- allocatedBuffer->m_allocator = this;
- return allocatedBuffer;
- }
- RHI::IndexBufferView DynamicBufferAllocator::GetIndexBufferView(RHI::Ptr<DynamicBuffer> dynamicBuffer, RHI::IndexFormat format)
- {
- return RHI::IndexBufferView(
- *m_ringBuffer->GetRHIBuffer(),
- GetBufferAddressOffset(dynamicBuffer),
- dynamicBuffer->m_size,
- format
- );
- }
- RHI::StreamBufferView DynamicBufferAllocator::GetStreamBufferView(RHI::Ptr<DynamicBuffer> dynamicBuffer, uint32_t strideByteCount)
- {
- return RHI::StreamBufferView(
- *m_ringBuffer->GetRHIBuffer(),
- GetBufferAddressOffset(dynamicBuffer),
- dynamicBuffer->m_size,
- strideByteCount
- );
- }
- uint32_t DynamicBufferAllocator::GetBufferAddressOffset(RHI::Ptr<DynamicBuffer> dynamicBuffer)
- {
- return aznumeric_cast<uint32_t>((uint8_t*)dynamicBuffer->m_address - (uint8_t*)m_ringBufferStartAddress);
- }
- void DynamicBufferAllocator::SetEnableAllocationWarning(bool enable)
- {
- m_enableAllocationWarning = enable;
- }
- void DynamicBufferAllocator::FrameEnd()
- {
- uint32_t nextFrame = (m_currentFrame + 1) % AZ::RHI::Limits::Device::FrameCountMax;
- // 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
- m_endPositionLimit = m_frameStartPositions[nextFrame];
- // Save start position for current frame
- m_frameStartPositions[m_currentFrame] = m_currentPosition;
- m_currentFrame = nextFrame;
- m_currentAllocatedSize = 0;
- }
- }
- }
|