36 constexpr U64 memoryCleanInterval = 256u;
38 thread_local U64 lastSyncedFrame = 0u;
40 if ( frameCount - lastSyncedFrame > memoryCleanInterval )
43 if (g_zeroData.size() >= detail::zeroDataBaseSize * 4 )
45 g_zeroData.set_capacity( 0 );
48 lastSyncedFrame = frameCount;
54 const size_t alignment,
55 const gl46core::BufferStorageMask storageMask,
56 const gl46core::BufferAccessMask accessMask,
57 const gl46core::GLenum usage)
58 : _storageMask(storageMask),
59 _accessMask(accessMask),
61 _alignment(alignment),
62 _poolAllocations(poolAllocations)
69 static U32 g_bufferIndex = 0u;
81 if (
_blocks[0]._bufferHandle > 0u)
83 gl46core::glDeleteBuffers(1, &
_blocks[0]._bufferHandle);
88 if (block._bufferHandle > 0u)
90 gl46core::glDeleteBuffers(1, &block._bufferHandle);
101 assert(blockIt != cend(
_blocks));
102 blockIt->
_free =
true;
114bool Chunk::allocate(
const size_t size,
const char* name,
const std::pair<bufferPtr, size_t> initialData,
Block &blockOut)
120 if (requestedSize >
_blocks.back()._size)
125 const size_t count =
_blocks.size();
126 for (
size_t i = 0u; i < count; ++i)
129 const size_t remainingSize = block.
_size;
131 if (!block.
_free || remainingSize < requestedSize)
138 memcpy(block.
_ptr, initialData.first, initialData.second);
147 block.
_size = requestedSize;
150 if (remainingSize > requestedSize)
159 nextBlock.
_size = remainingSize - requestedSize;
162 _blocks.emplace_back(nextBlock);
183 const size_t alignment,
184 const gl46core::BufferStorageMask storageMask,
185 const gl46core::BufferAccessMask accessMask,
186 const gl46core::GLenum usage)
const
190 const size_t overflowSize =
to_size(1) <<
to_size(std::log2(size) + 1);
191 return std::make_unique<Chunk>(poolAllocations, (size >
_size ? overflowSize :
_size), alignment, storageMask, accessMask, usage);
195 : _memoryType(memoryType)
207 const size_t alignment,
208 const gl46core::BufferStorageMask storageMask,
209 const gl46core::BufferAccessMask accessMask,
210 const gl46core::GLenum usage,
211 const char* blockName,
212 const std::pair<bufferPtr, size_t> initialData)
221 if (chunk->storageMask() == storageMask &&
222 chunk->accessMask() == accessMask &&
223 chunk->usage() == usage &&
224 chunk->alignment() == alignment &&
225 chunk->poolAllocations() == poolAllocations)
227 if (chunk->allocate(size, blockName, initialData, block))
234 _chunks.emplace_back(
_chunkAllocator->allocate(poolAllocations, size, alignment, storageMask, accessMask, usage));
235 if(!
_chunks.back()->allocate(size, blockName, initialData, block))
250 if (chunk->containsBlock(block))
252 chunk->deallocate(block);
269 const gl46core::BufferStorageMask storageMask,
270 const gl46core::BufferAccessMask accessMask,
271 gl46core::GLuint& bufferIdOut,
272 const std::pair<bufferPtr, size_t> initialData,
277 gl46core::glCreateBuffers(1, &bufferIdOut);
280 gl46core::glObjectLabel( gl46core::GL_BUFFER, bufferIdOut, -1,
286 assert(bufferIdOut != 0 &&
"GLUtil::allocPersistentBuffer error: buffer creation failed");
287 const bool hasAllSourceData = initialData.second == bufferSize && initialData.first !=
nullptr;
289 gl46core::glNamedBufferStorage(bufferIdOut, bufferSize, hasAllSourceData ? initialData.first : GLMemory::GetZeroData(bufferSize), storageMask);
290 Byte* ptr = (
Byte*)gl46core::glMapNamedBufferRange(bufferIdOut, 0, bufferSize, accessMask);
291 assert(ptr !=
nullptr);
293 if (!hasAllSourceData && initialData.second > 0 && initialData.first !=
nullptr)
295 memcpy(ptr, initialData.first, initialData.second);
305 gl46core::glCreateBuffers(1, &bufferIdOut);
309 gl46core::glObjectLabel(gl46core::GL_BUFFER, bufferIdOut, -1,
318 const gl46core::GLenum usageMask,
319 gl46core::GLuint& bufferIdOut,
320 const std::pair<bufferPtr, size_t> initialData,
328 const bool hasAllSourceData = initialData.second == bufferSize && initialData.first !=
nullptr;
330 assert(bufferIdOut != 0 &&
"GLUtil::allocBuffer error: buffer creation failed");
331 glNamedBufferData(bufferIdOut, bufferSize, hasAllSourceData ? initialData.first : GLMemory::GetZeroData( bufferSize ), usageMask);
333 if (!hasAllSourceData && initialData.second > 0u && initialData.first !=
nullptr )
335 const gl46core::BufferAccessMask accessMask = gl46core::GL_MAP_WRITE_BIT | gl46core::GL_MAP_INVALIDATE_BUFFER_BIT;
337 Byte* ptr = (
Byte*)glMapNamedBufferRange(bufferIdOut, 0, bufferSize, accessMask);
338 memcpy(ptr, initialData.first, initialData.second);
339 gl46core::glUnmapNamedBuffer(bufferIdOut);
349 if (mappedPtr !=
nullptr)
351 [[maybe_unused]]
const gl46core::GLboolean result = gl46core::glUnmapNamedBuffer(bufferId);
352 DIVIDE_ASSERT(result != gl46core::GL_FALSE &&
"GLUtil::freeBuffer error: buffer unmapping failed");
#define PROFILE_SCOPE_AUTO(CATEGORY)
static bool DeleteBuffers(gl46core::GLuint count, gl46core::GLuint *buffers)
ChunkAllocator(size_t size) noexcept
std::unique_ptr< Chunk > allocate(bool poolAllocations, size_t size, size_t alignment, gl46core::BufferStorageMask storageMask, gl46core::BufferAccessMask accessMask, gl46core::GLenum usage) const
const bool _poolAllocations
Chunk(bool poolAllocations, size_t size, size_t alignment, gl46core::BufferStorageMask storageMask, gl46core::BufferAccessMask accessMask, gl46core::GLenum usage)
bool containsBlock(const Block &block) const
bool allocate(size_t size, const char *name, std::pair< bufferPtr, size_t > initialData, Block &blockOut)
void deallocate(const Block &block)
vector< std::unique_ptr< Chunk > > _chunks
ChunkAllocator_uptr _chunkAllocator
DeviceAllocator(GLMemoryType memoryType) noexcept
Mutex _chunkAllocatorLock
Block allocate(bool poolAllocations, size_t size, size_t alignment, gl46core::BufferStorageMask storageMask, gl46core::BufferAccessMask accessMask, gl46core::GLenum usage, const char *blockName, std::pair< bufferPtr, size_t > initialData)
constexpr bool ENABLE_GPU_VALIDATION
Error callbacks, validations, buffer checks, etc. are controlled by this flag. Heavy performance impa...
constexpr size_t zeroDataBaseSize
eastl::vector< Byte > g_zeroData(detail::zeroDataBaseSize, Byte_ZERO)
FORCE_INLINE Byte * GetZeroData(const size_t bufferSize)
void OnFrameEnd(const U64 frameCount)
void createBuffer(gl46core::GLuint &bufferIdOut, const char *name)
void freeBuffer(gl46core::GLuint &bufferId, bufferPtr mappedPtr)
Byte * createAndAllocPersistentBuffer(const size_t bufferSize, const gl46core::BufferStorageMask storageMask, const gl46core::BufferAccessMask accessMask, gl46core::GLuint &bufferIdOut, const std::pair< bufferPtr, size_t > initialData, const char *name)
void createAndAllocBuffer(const size_t bufferSize, const gl46core::GLenum usageMask, gl46core::GLuint &bufferIdOut, const std::pair< bufferPtr, size_t > initialData, const char *name)
constexpr Optick::Category::Type Graphics
Str StringFormat(const char *fmt, Args &&...args)
FORCE_INLINE size_t GetAlignmentCorrected(const size_t value, const size_t alignment) noexcept
Handle console commands that start with a forward slash.
std::lock_guard< mutex > LockGuard
constexpr gl46core::GLuint GL_NULL_HANDLE
Invalid object value. Used to compare handles and determine if they were properly created.
constexpr bool isPowerOfTwo(const T x) noexcept
constexpr size_t to_size(const T value)
gl46core::GLuint _bufferHandle