VboBlock* Vbo::freeBlock(VboBlock& block) { #ifdef _DEBUG_VBO checkBlockChain(); checkFreeBlocks(); #endif VboBlock* previous = block.m_previous; VboBlock* next = block.m_next; m_freeCapacity += block.capacity(); block.m_free = true; if (previous != NULL && previous->free() && next != NULL && next->free()) { resizeBlock(*previous, previous->capacity() + block.capacity() + next->capacity()); if (m_last == next) m_last = previous; removeFreeBlock(*next); previous->insertBetween(previous->m_previous, next->m_next); delete █ delete next; return previous; } if (previous != NULL && previous->free()) { resizeBlock(*previous, previous->capacity() + block.capacity()); if (m_last == &block) m_last = previous; previous->insertBetween(previous->m_previous, next); delete █ return previous; } if (next != NULL && next->free()) { if (m_last == next) m_last = █ removeFreeBlock(*next); block.m_capacity += next->capacity(); block.m_free = true; block.insertBetween(previous, next->m_next); insertFreeBlock(block); delete next; return █ } insertFreeBlock(block); #ifdef _DEBUG_VBO checkBlockChain(); checkFreeBlocks(); #endif return █ }
void * realloc(void * ptr, size_t size) { char * charPtr = static_cast<char *>(ptr); Block & block = blocks.at(charPtr); Block & next = nextBlock(charPtr); /* There is enough place ahead of the current block */ if(block.size == size) { } else if(block.size > size) { splitBlock(block, size); Block & rest = blocks.at(block.ptr + size); markBlockFree(rest); if(next.free) { resizeBlock(rest, rest.size + next.size); removeBlock(next); } } else if(next.free && block.size + next.size >= size) { splitBlock(next, size-block.size); removeBlock(next); resizeBlock(block, size); } else { void * newPtr = alloc(size); if(newPtr != NULL) { memcpy(newPtr, ptr, block.size); free(ptr); ptr = newPtr; } } #ifdef SELFTEST selfTest(); #endif return ptr; }
void splitBlock(Block & block, size_t newSize) { assert(block.size >= newSize); size_t oldSize = block.size; resizeBlock(block, newSize); if(newSize < oldSize) createBlock(block.ptr+newSize, oldSize-newSize, block.free); }
void free(void * ptr) { char * charPtr = static_cast<char *>(ptr); Block & prev = prevBlock(charPtr); Block & next = nextBlock(charPtr); Block & block = blocks.at(charPtr); assert(block.free == false); assert(prev.ptr == NULL || prev.ptr + prev.size == block.ptr); assert(next.ptr == NULL || block.ptr + block.size == next.ptr); /* prev is busy and next is busy */ /* just mark current block as free */ if(!prev.free && !next.free) { markBlockFree(block); } /* prev is free and next is busy */ /* concat prev and curr block into one free block */ else if(prev.free && !next.free) { resizeBlock(prev, prev.size + block.size); removeBlock(block); } /* prev is busy and next is free */ /* concat curr and next block into one free block */ else if(!prev.free && next.free) { resizeBlock(block, block.size + next.size); removeBlock(next); markBlockFree(block); } /* concat all three blocks into one block*/ else if(prev.free && next.free) { resizeBlock(prev, prev.size + block.size + next.size); removeBlock(block); removeBlock(next); } #ifdef SELFTEST selfTest(); #endif }
VboBlock* Vbo::packBlock(VboBlock& block) { VboBlock* first = block.m_next; if (first == NULL) return NULL; VboBlock* previous = NULL; VboBlock* last = first; size_t size = 0; size_t address = first->address(); do { last->m_address -= block.capacity(); size += last->capacity(); previous = last; last = last->m_next; } while (last != NULL && !last->free()); memmove(m_buffer + block.address(), m_buffer + address, size); if (last != NULL) { last->m_address -= block.capacity(); resizeBlock(*last, last->capacity() + block.capacity()); } else { VboBlock* newBlock = new VboBlock(*this, previous->address() + previous->capacity(), block.capacity()); insertFreeBlock(*newBlock); newBlock->insertBetween(previous, NULL); m_last = newBlock; } if (m_first == &block) m_first = block.m_next; removeFreeBlock(block); if (block.m_previous != NULL) block.m_previous->m_next = block.m_next; if (block.m_next != NULL) block.m_next->m_previous = block.m_previous; delete █ return last; }
void Vbo::resizeVbo(size_t newCapacity) { VboState oldState = m_state; unsigned char* temp = NULL; MemBlock::List memBlocks; if (m_vboId != 0 && m_freeCapacity < m_totalCapacity) { VboBlock* currentBlock = m_first; size_t totalLength = 0; while (currentBlock != NULL) { while (currentBlock != NULL && currentBlock->free()) currentBlock = currentBlock->m_next; if (currentBlock != NULL) { size_t start = currentBlock->address(); size_t length = 0; while (currentBlock != NULL && !currentBlock->free()) { length += currentBlock->capacity(); currentBlock = currentBlock->m_next; } memBlocks.push_back(MemBlock(start, length)); totalLength += length; } } if (m_state < VboActive) activate(); if (m_state < VboMapped) map(); temp = new unsigned char[totalLength]; size_t offset = 0; MemBlock::List::const_iterator it, end; for (it = memBlocks.begin(), end = memBlocks.end(); it != end; ++it) { const MemBlock& memBlock = *it; memcpy(temp + offset, m_buffer + memBlock.start, memBlock.length); offset += memBlock.length; } } size_t addedCapacity = newCapacity - m_totalCapacity; m_freeCapacity = newCapacity - (m_totalCapacity - m_freeCapacity); m_totalCapacity = newCapacity; if (m_last->free()) { resizeBlock(*m_last, m_last->capacity() + addedCapacity); } else { VboBlock* block = new VboBlock(*this, m_last->address() + m_last->capacity(), addedCapacity); block->insertBetween(m_last, NULL); insertFreeBlock(*block); m_last = block; } if (m_vboId != 0) { if (m_state == VboMapped) unmap(); if (m_state == VboActive) deactivate(); glDeleteBuffers(1, &m_vboId); m_vboId = 0; } if (temp != NULL) { assert(!memBlocks.empty()); if (m_state < VboActive) activate(); if (m_state < VboMapped) map(); size_t offset = 0; MemBlock::List::const_iterator it, end; for (it = memBlocks.begin(), end = memBlocks.end(); it != end; ++it) { const MemBlock& memBlock = *it; memcpy(m_buffer + memBlock.start, temp + offset, memBlock.length); } delete [] temp; temp = NULL; memBlocks.clear(); if (oldState < VboMapped) unmap(); if (oldState < VboActive) deactivate(); } else { if (oldState > VboInactive && m_state < VboActive) activate(); if (oldState > VboActive && m_state < VboMapped) map(); } #ifdef _DEBUG_VBO checkBlockChain(); checkFreeBlocks(); #endif }