| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
- // All rights reserved.
- // Code licensed under the BSD License.
- // http://www.anki3d.org/LICENSE
- #pragma once
- #include <AnKi/Resource/Common.h>
- #include <AnKi/Util/StackAllocatorBuilder.h>
- #include <AnKi/Util/List.h>
- #include <AnKi/Gr/Buffer.h>
- namespace anki {
- /// @addtogroup resource
- /// @{
- /// Memory handle.
- class TransferGpuAllocatorHandle
- {
- friend class TransferGpuAllocator;
- public:
- TransferGpuAllocatorHandle()
- {
- }
- TransferGpuAllocatorHandle(const TransferGpuAllocatorHandle&) = delete;
- TransferGpuAllocatorHandle(TransferGpuAllocatorHandle&& b)
- {
- *this = std::move(b);
- }
- ~TransferGpuAllocatorHandle()
- {
- ANKI_ASSERT(!valid() && "Forgot to release");
- }
- TransferGpuAllocatorHandle& operator=(TransferGpuAllocatorHandle&& b)
- {
- m_buffer = b.m_buffer;
- m_mappedMemory = b.m_mappedMemory;
- m_offsetInBuffer = b.m_offsetInBuffer;
- m_range = b.m_range;
- m_pool = b.m_pool;
- b.invalidate();
- return *this;
- }
- operator BufferView() const
- {
- return {m_buffer.get(), m_offsetInBuffer, m_range};
- }
- Buffer& getBuffer() const
- {
- return *m_buffer;
- }
- void* getMappedMemory() const
- {
- ANKI_ASSERT(m_mappedMemory);
- return m_mappedMemory;
- }
- PtrSize getOffset() const
- {
- ANKI_ASSERT(m_offsetInBuffer != kMaxPtrSize);
- return m_offsetInBuffer;
- }
- PtrSize getRange() const
- {
- ANKI_ASSERT(m_range != 0);
- return m_range;
- }
- private:
- BufferPtr m_buffer;
- void* m_mappedMemory = nullptr;
- PtrSize m_offsetInBuffer = kMaxPtrSize;
- PtrSize m_range = 0;
- U8 m_pool = kMaxU8;
- Bool valid() const
- {
- return m_range != 0 && m_pool < kMaxU8;
- }
- void invalidate()
- {
- m_buffer.reset(nullptr);
- m_mappedMemory = nullptr;
- m_offsetInBuffer = kMaxPtrSize;
- m_range = 0;
- m_pool = kMaxU8;
- }
- };
- /// GPU memory allocator for GPU buffers used in transfer operations.
- class TransferGpuAllocator : public MakeSingleton<TransferGpuAllocator>
- {
- friend class TransferGpuAllocatorHandle;
- public:
- /// Choose an alignment that satisfies 16 bytes and 3 bytes. RGB8 formats require 3 bytes alignment for the source
- /// of the buffer to image copies.
- static constexpr U32 kGpuBufferAlignment = 16 * 3;
- static constexpr U32 kPoolCount = 2;
- static constexpr PtrSize kChunkInitialSize = 64_MB;
- static constexpr Second kMaxFenceWaitTime = 500.0_ms;
- TransferGpuAllocator();
- ~TransferGpuAllocator();
- Error init(PtrSize maxSize);
- /// Allocate some transfer memory. If there is not enough memory it will block until some is releaced. It's
- /// threadsafe.
- Error allocate(PtrSize size, TransferGpuAllocatorHandle& handle);
- /// Release the memory. It will not be recycled before the fence is signaled. It's threadsafe.
- void release(TransferGpuAllocatorHandle& handle, FencePtr fence);
- private:
- /// This is the chunk the StackAllocatorBuilder will be allocating.
- class Chunk
- {
- public:
- /// Required by StackAllocatorBuilder.
- Chunk* m_nextChunk;
- /// Required by StackAllocatorBuilder.
- Atomic<PtrSize> m_offsetInChunk;
- /// Required by StackAllocatorBuilder.
- PtrSize m_chunkSize;
- /// The GPU memory.
- BufferPtr m_buffer;
- /// Points to the mapped m_buffer.
- void* m_mappedBuffer;
- };
- /// Implements the StackAllocatorBuilder TInterface
- class StackAllocatorBuilderInterface
- {
- public:
- // The rest of the functions implement the StackAllocatorBuilder TInterface.
- static constexpr PtrSize getInitialChunkSize()
- {
- return kChunkInitialSize;
- }
- static constexpr F64 getNextChunkGrowScale()
- {
- return 1.0;
- }
- static constexpr PtrSize getNextChunkGrowBias()
- {
- return 0;
- }
- static constexpr Bool ignoreDeallocationErrors()
- {
- return false;
- }
- static constexpr PtrSize getMaxChunkSize()
- {
- return kChunkInitialSize;
- }
- Error allocateChunk(PtrSize size, Chunk*& out);
- void freeChunk(Chunk* chunk);
- void recycleChunk([[maybe_unused]] Chunk& chunk)
- {
- // Do nothing
- }
- constexpr Atomic<U32>* getAllocationCount()
- {
- return nullptr;
- }
- };
- class Pool
- {
- public:
- StackAllocatorBuilder<Chunk, StackAllocatorBuilderInterface, DummyMutex> m_stackAlloc;
- ResourceList<FencePtr> m_fences;
- U32 m_pendingReleases = 0;
- };
- PtrSize m_maxAllocSize = 0;
- Mutex m_mtx; ///< Protect all members bellow.
- ConditionVariable m_condVar;
- Array<Pool, kPoolCount> m_pools;
- U8 m_crntPool = 0;
- PtrSize m_crntPoolAllocatedSize = 0;
- };
- /// @}
- } // end namespace anki
|