Bool GpuBlockAllocator::blockHasEnoughSpace(U blockIdx, PtrSize size, U alignment) const { ANKI_ASSERT(size > 0); const Block& block = m_blocks[blockIdx]; PtrSize allocEnd = getAlignedRoundUp(alignment, block.m_offset) + size; PtrSize blockEnd = (blockIdx + 1) * m_blockSize; return allocEnd <= blockEnd; }
Error GpuBlockAllocator::allocate(PtrSize size, U alignment, PtrSize& outOffset) { ANKI_ASSERT(isCreated()); ANKI_ASSERT(size < m_blockSize); Block* block = nullptr; Error err = ErrorCode::NONE; LockGuard<Mutex> lock(m_mtx); if(m_currentBlock == MAX_U32 || !blockHasEnoughSpace(m_currentBlock, size, alignment)) { // Need new block if(m_freeBlockCount > 0) { // Pop block from free U blockIdx = --m_freeBlockCount; block = &m_blocks[blockIdx]; block->m_offset = blockIdx * m_blockSize; ANKI_ASSERT(block->m_allocationCount == 0); // Make it in-use m_currentBlock = blockIdx; } } if(block) { PtrSize outOffset = getAlignedRoundUp(alignment, block->m_offset); block->m_offset = outOffset + size; ANKI_ASSERT(block->m_offset <= (block - &m_blocks[0] + 1) * m_blockSize); ++block->m_allocationCount; // Update the handle outOffset = outOffset; } else { err = ErrorCode::OUT_OF_MEMORY; outOffset = MAX_PTR_SIZE; } return err; }
void CommandBufferPtr::updateDynamicUniforms(void* data, U32 originalSize) { ANKI_ASSERT(data); ANKI_ASSERT(originalSize > 0); ANKI_ASSERT(originalSize <= 1024 * 4 && "Too high?"); GlState& state = get().getManager().getImplementation().getRenderingThread().getState(); const U uboSize = state.m_globalUboSize; const U subUboSize = GlState::MAX_UBO_SIZE; // Get offset in the contiguous buffer U size = getAlignedRoundUp(state.m_uniBuffOffsetAlignment, originalSize); U offset = state.m_globalUboCurrentOffset.fetchAdd(size); offset = offset % uboSize; while((offset % subUboSize) + size > subUboSize) { // Update area will fall between UBOs, need to start over offset = state.m_globalUboCurrentOffset.fetchAdd(size); offset = offset % uboSize; } ANKI_ASSERT(isAligned(state.m_uniBuffOffsetAlignment, offset)); ANKI_ASSERT(offset + size <= uboSize); // Get actual UBO address to write U uboIdx = offset / subUboSize; U subUboOffset = offset % subUboSize; ANKI_ASSERT(isAligned(state.m_uniBuffOffsetAlignment, subUboOffset)); U8* addressToWrite = state.m_globalUboAddresses[uboIdx] + subUboOffset; // Write memcpy(addressToWrite, data, originalSize); // Push bind command get().pushBackNewCommand<UpdateUniformsCommand>( state.m_globalUbos[uboIdx], subUboOffset, originalSize); }