diff --git a/common/gal/opengl/vbo_container.cpp b/common/gal/opengl/vbo_container.cpp index cbf5320035..fd6dea86f3 100644 --- a/common/gal/opengl/vbo_container.cpp +++ b/common/gal/opengl/vbo_container.cpp @@ -28,9 +28,8 @@ */ #include -#include -#include -#include +#include +#include #include #ifdef __WXDEBUG__ #include @@ -39,7 +38,7 @@ using namespace KiGfx; VBO_CONTAINER::VBO_CONTAINER( unsigned int aSize ) : - m_freeSpace( aSize ), m_currentSize( aSize ), itemStarted( false ), m_transform( NULL ), + m_freeSpace( aSize ), m_currentSize( aSize ), m_initialSize( aSize ), m_transform( NULL ), m_failed( false ) { // By default no shader is used @@ -58,114 +57,42 @@ VBO_CONTAINER::~VBO_CONTAINER() } -void VBO_CONTAINER::StartItem( VBO_ITEM* aVboItem ) +void VBO_CONTAINER::StartItem( VBO_ITEM* aItem ) { - itemStarted = true; - item = aVboItem; - itemSize = 0; + m_item = aItem; + m_itemSize = aItem->GetSize(); + m_chunkSize = m_itemSize; - // Reserve minimal sensible chunk size (at least to store a single triangle) - itemChunkSize = 3; - allocate( aVboItem, itemChunkSize ); + if( m_itemSize == 0 ) + m_items.insert( m_item ); // The item was not stored before + else + m_chunkOffset = m_item->GetOffset(); } void VBO_CONTAINER::EndItem() { - if( itemSize < itemChunkSize ) + if( m_itemSize < m_chunkSize ) { - // There is some memory left, so we should return it to the pool - int itemChunkOffset = item->GetOffset(); - - m_reservedChunks.erase( item ); - m_reservedChunks.insert( ReservedChunk( item, Chunk( itemSize, itemChunkOffset ) ) ); - - m_freeChunks.insert( Chunk( itemChunkSize - itemSize, itemChunkOffset + itemSize ) ); - m_freeSpace += ( itemChunkSize - itemSize ); + // Add the not used memory back to the pool + m_freeChunks.insert( Chunk( m_chunkSize - m_itemSize, m_chunkOffset + m_itemSize ) ); + m_freeSpace += ( m_chunkSize - m_itemSize ); } - item = NULL; - itemStarted = false; + m_item = NULL; } -void VBO_CONTAINER::Add( VBO_ITEM* aVboItem, const VBO_VERTEX* aVertex, unsigned int aSize ) +void VBO_CONTAINER::Add( const VBO_VERTEX* aVertex, unsigned int aSize ) { - unsigned int offset; - VBO_VERTEX* vertexPtr; + // Pointer to the vertex that we are currently adding + VBO_VERTEX* vertexPtr = allocate( aSize ); - if( m_failed ) + if( vertexPtr == NULL ) return; - if( itemStarted ) // There is an item being created with an unknown size.. - { - unsigned int itemChunkOffset; - - // ..and unfortunately does not fit into currently reserved chunk - if( itemSize + aSize > itemChunkSize ) - { - // Find the previous chunk for the item and change mark it as NULL - // so it will not be removed during a possible defragmentation - ReservedChunkMap::iterator it = m_reservedChunks.find( item ); - m_reservedChunks.insert( ReservedChunk( static_cast( NULL ), it->second ) ); - m_reservedChunks.erase( it ); - - // Reserve bigger memory fo r the current item - int newSize = ( 2 * itemSize ) + aSize; - itemChunkOffset = allocate( aVboItem, newSize ); - aVboItem->SetOffset( itemChunkOffset ); - - // Check if there was no error - if( itemChunkOffset > m_currentSize ) - { - m_failed = true; - return; - } - - it = m_reservedChunks.find( static_cast( NULL ) ); - // Check if the chunk was not reallocated after defragmentation - int oldItemChunkOffset = getChunkOffset( *it ); - // Free the space previously used by the chunk - freeChunk( it ); - - // Copy all the old data - memcpy( &m_vertices[itemChunkOffset], &m_vertices[oldItemChunkOffset], - itemSize * VBO_ITEM::VertByteSize ); - - itemChunkSize = newSize; - } - else - { - itemChunkOffset = item->GetOffset(); - } - - // Store new vertices in the chunk reserved for the unknown-sized item - offset = itemChunkOffset + itemSize; - itemSize += aSize; - } - else - { - // Add vertices to previously already finished item - wxASSERT_MSG( false, wxT( "Warning: not tested yet" ) ); - - ReservedChunkMap::iterator it = m_reservedChunks.find( aVboItem ); - unsigned int chunkSize = getChunkSize( *it ); - unsigned int itemSize = aVboItem->GetSize(); - - if( chunkSize < itemSize + aSize ) - { - resizeChunk( aVboItem, itemSize + aSize ); - it = m_reservedChunks.find( aVboItem ); - } - - offset = getChunkOffset( *it ) + itemSize; - } - for( unsigned int i = 0; i < aSize; ++i ) { - // Pointer to the vertex that we are currently adding - vertexPtr = &m_vertices[offset + i]; - // Modify the vertex according to the currently used transformations if( m_transform != NULL ) { @@ -197,6 +124,8 @@ void VBO_CONTAINER::Add( VBO_ITEM* aVboItem, const VBO_VERTEX* aVertex, unsigned { vertexPtr->shader[j] = m_shader[j]; } + + vertexPtr++; } } @@ -206,41 +135,90 @@ void VBO_CONTAINER::Clear() { // Change size to the default one m_vertices = static_cast( realloc( m_vertices, - defaultInitSize * sizeof( VBO_VERTEX ) ) ); + m_initialSize * sizeof( VBO_VERTEX ) ) ); + + // Set the size of all the stored VERTEX_ITEMs to 0, so it is clear that they are not held + // in the container anymore + Items::iterator it; + for( it = m_items.begin(); it != m_items.end(); ++it ) + { + ( *it )->setSize( 0 ); + } + m_items.clear(); // Reset state variables - m_freeSpace = defaultInitSize; - m_currentSize = defaultInitSize; - itemStarted = false; m_transform = NULL; m_failed = false; // By default no shader is used m_shader[0] = 0; - m_freeChunks.clear(); - m_reservedChunks.clear(); - // In the beginning there is only free space + m_freeSpace = m_initialSize; + m_currentSize = m_initialSize; + m_freeChunks.clear(); m_freeChunks.insert( Chunk( m_freeSpace, 0 ) ); } +void VBO_CONTAINER::Free( VBO_ITEM* aItem ) +{ + freeItem( aItem ); + + // Dynamic memory freeing, there is no point in holding + // a large amount of memory when there is no use for it + if( m_freeSpace > ( m_currentSize / 2 ) && m_currentSize > defaultInitSize ) + { + resizeContainer( m_currentSize / 2 ); + } +} + + VBO_VERTEX* VBO_CONTAINER::GetAllVertices() const { return m_vertices; } -VBO_VERTEX* VBO_CONTAINER::GetVertices( const VBO_ITEM* aVboItem ) const +VBO_VERTEX* VBO_CONTAINER::GetVertices( const VBO_ITEM* aItem ) const { - int offset = aVboItem->GetOffset(); + int offset = aItem->GetOffset(); return &m_vertices[offset]; } +VBO_VERTEX* VBO_CONTAINER::allocate( unsigned int aSize ) +{ + wxASSERT( m_item != NULL ); -unsigned int VBO_CONTAINER::allocate( VBO_ITEM* aVboItem, unsigned int aSize ) + if( m_failed ) + return NULL; + + if( m_itemSize + aSize > m_chunkSize ) + { + // There is not enough space in the currently reserved chunk, so we have to resize it + + // Reserve a bigger memory chunk for the current item + m_chunkSize = std::max( ( 2 * m_itemSize ) + aSize, (unsigned) 3 ); + // Save the current size before reallocating + m_chunkOffset = reallocate( m_chunkSize ); + + if( m_chunkOffset > m_currentSize ) + { + m_failed = true; + return NULL; + } + } + + VBO_VERTEX* reserved = &m_vertices[m_chunkOffset + m_itemSize]; + m_itemSize += aSize; + m_item->setSize( m_itemSize ); + + return reserved; +} + + +unsigned int VBO_CONTAINER::reallocate( unsigned int aSize ) { // Is there enough space to store vertices? if( m_freeSpace < aSize ) @@ -259,74 +237,68 @@ unsigned int VBO_CONTAINER::allocate( VBO_ITEM* aVboItem, unsigned int aSize ) result = resizeContainer( getPowerOf2( m_currentSize * 2 + aSize ) ); } - // An error has occurred if( !result ) - { return UINT_MAX; - } } - // Look for the space with at least given size - FreeChunkMap::iterator it = m_freeChunks.lower_bound( aSize ); + // Look for the free space of at least given size + FreeChunkMap::iterator newChunk = m_freeChunks.lower_bound( aSize ); - if( it == m_freeChunks.end() ) + if( newChunk == m_freeChunks.end() ) { - // This means that there is enough space for - // storing vertices, but the space is not continous + // In the case when there is enough space to store the vertices, + // but the free space is not continous we should defragment the container if( !defragment() ) - { return UINT_MAX; - } + + // Update the current offset + m_chunkOffset = m_item->GetOffset(); // We can take the first free chunk, as there is only one after defragmentation // and we can be sure that it provides enough space to store the object - it = m_freeChunks.begin(); + newChunk = m_freeChunks.begin(); } - unsigned int chunkSize = it->first; - unsigned int chunkOffset = it->second; - - m_freeChunks.erase( it ); + // Parameters of the allocated cuhnk + unsigned int chunkSize = newChunk->first; + unsigned int chunkOffset = newChunk->second; wxASSERT( chunkSize >= aSize ); + wxASSERT( chunkOffset < m_currentSize ); + + // Check if the item was previously stored in the container + if( m_itemSize > 0 ) + { + // The item was reallocated, so we have to copy all the old data to the new place + memcpy( &m_vertices[chunkOffset], &m_vertices[m_chunkOffset], + m_itemSize * VBO_ITEM::VertByteSize ); + + // Free the space previously used by the chunk + m_freeChunks.insert( Chunk( m_itemSize, m_chunkOffset ) ); + m_freeSpace += m_itemSize; + } + // Remove the allocated chunk from the free space pool + m_freeChunks.erase( newChunk ); + m_freeSpace -= chunkSize; // If there is some space left, return it to the pool - add an entry for it if( chunkSize > aSize ) { m_freeChunks.insert( Chunk( chunkSize - aSize, chunkOffset + aSize ) ); + m_freeSpace += chunkSize - aSize; } - m_freeSpace -= aSize; - m_reservedChunks.insert( ReservedChunk( aVboItem, Chunk( aSize, chunkOffset ) ) ); - aVboItem->SetOffset( chunkOffset ); + m_item->setOffset( chunkOffset ); return chunkOffset; } -void VBO_CONTAINER::freeChunk( const ReservedChunkMap::iterator& aChunk ) -{ - // Remove the chunk from the reserved chunks map and add to the free chunks map - int size = getChunkSize( *aChunk ); - int offset = getChunkOffset( *aChunk ); - - m_reservedChunks.erase( aChunk ); - m_freeChunks.insert( Chunk( size, offset ) ); - m_freeSpace += size; -} - - bool VBO_CONTAINER::defragment( VBO_VERTEX* aTarget ) { - if( m_freeChunks.size() <= 1 ) - { - // There is no point in defragmenting, as there is only one or no free chunks - return true; - } - if( aTarget == NULL ) { - // No target was specified, so we have to allocate our own space + // No target was specified, so we have to reallocate our own space aTarget = static_cast( malloc( m_currentSize * sizeof( VBO_VERTEX ) ) ); if( aTarget == NULL ) { @@ -336,20 +308,18 @@ bool VBO_CONTAINER::defragment( VBO_VERTEX* aTarget ) } int newOffset = 0; - ReservedChunkMap::iterator it, it_end; - for( it = m_reservedChunks.begin(), it_end = m_reservedChunks.end(); it != it_end; ++it ) + Items::iterator it, it_end; + for( it = m_items.begin(), it_end = m_items.end(); it != it_end; ++it ) { - VBO_ITEM* vboItem = getChunkVboItem( *it ); - int itemOffset = getChunkOffset( *it ); - int itemSize = getChunkSize( *it ); + VBO_ITEM* item = *it; + int itemOffset = item->GetOffset(); + int itemSize = item->GetSize(); // Move an item to the new container memcpy( &aTarget[newOffset], &m_vertices[itemOffset], itemSize * VBO_ITEM::VertByteSize ); - // Update new offset - if( vboItem ) - vboItem->SetOffset( newOffset ); - setChunkOffset( *it, newOffset ); + // Update its offset + item->setOffset( newOffset ); // Move to the next free space newOffset += itemSize; @@ -360,28 +330,52 @@ bool VBO_CONTAINER::defragment( VBO_VERTEX* aTarget ) // Now there is only one big chunk of free memory m_freeChunks.clear(); - m_freeChunks.insert( Chunk( m_freeSpace, m_currentSize - m_freeSpace ) ); + m_freeChunks.insert( Chunk( m_freeSpace, reservedSpace() ) ); return true; } -void VBO_CONTAINER::resizeChunk( VBO_ITEM* aVboItem, int aNewSize ) +void VBO_CONTAINER::mergeFreeChunks() { - wxASSERT_MSG( false, wxT( "Warning: not tested yet" ) ); + if( m_freeChunks.size() < 2 ) // There are no chunks that can be merged + return; - // TODO ESPECIALLY test the case of shrinking chunk - ReservedChunkMap::iterator it = m_reservedChunks.find( aVboItem ); - int size = getChunkSize( *it ); - int offset = getChunkOffset( *it ); + // Reversed free chunks map - this one stores chunk size with its offset as the key + std::list freeChunks; - int newOffset = allocate( aVboItem, aNewSize ); - memcpy( &m_vertices[newOffset], &m_vertices[offset], size * VBO_ITEM::VertByteSize ); + FreeChunkMap::const_iterator it, it_end; + for( it = m_freeChunks.begin(), it_end = m_freeChunks.end(); it != it_end; ++it ) + { + freeChunks.push_back( std::make_pair( it->second, it->first ) ); + } + m_freeChunks.clear(); + freeChunks.sort(); - // Remove the chunk from the reserved chunks map and add to the free chunks map - m_reservedChunks.erase( it ); - m_freeChunks.insert( Chunk( size, offset ) ); - m_freeSpace += size; + std::list::const_iterator itf, itf_end; + unsigned int offset = freeChunks.front().first; + unsigned int size = freeChunks.front().second; + freeChunks.pop_front(); + for( itf = freeChunks.begin(), itf_end = freeChunks.end(); itf != itf_end; ++itf ) + { + if( itf->first == offset + size ) + { + // These chunks can be merged, so just increase the current chunk size and go on + size += itf->second; + } + else + { + // These chunks cannot be merged + // So store the previous one + m_freeChunks.insert( std::make_pair( size, offset ) ); + // and let's check the next chunk + offset = itf->first; + size = itf->second; + } + } + + // Add the last one + m_freeChunks.insert( std::make_pair( size, offset ) ); } @@ -391,8 +385,9 @@ bool VBO_CONTAINER::resizeContainer( unsigned int aNewSize ) if( aNewSize < m_currentSize ) { + // Shrinking container // Sanity check, no shrinking if we cannot fit all the data - if( ( m_currentSize - m_freeSpace ) > aNewSize ) + if( reservedSpace() > aNewSize ) return false; newContainer = static_cast( malloc( aNewSize * sizeof( VBO_VERTEX ) ) ); @@ -404,52 +399,56 @@ bool VBO_CONTAINER::resizeContainer( unsigned int aNewSize ) // Defragment directly to the new, smaller container defragment( newContainer ); + + // We have to correct freeChunks after defragmentation + m_freeChunks.clear(); + m_freeChunks.insert( Chunk( aNewSize - reservedSpace(), reservedSpace() ) ); } else { + // Enlarging container newContainer = static_cast( realloc( m_vertices, aNewSize * sizeof( VBO_VERTEX ) ) ); if( newContainer == NULL ) { wxLogError( wxT( "Run out of memory" ) ); return false; } + + // Add an entry for the new memory chunk at the end of the container + m_freeChunks.insert( Chunk( aNewSize - m_currentSize, m_currentSize ) ); } m_vertices = newContainer; - // Update variables - unsigned int lastFreeSize = 0; - unsigned int lastFreeOffset = 0; - - // Search for the last free chunk *at the end of the container* (not the last chunk in general) - FreeChunkMap::reverse_iterator lastFree, freeEnd; - for( lastFree = m_freeChunks.rbegin(), freeEnd = m_freeChunks.rend(); - lastFree != freeEnd && lastFreeSize + lastFreeOffset != m_currentSize; ++lastFree ) - { - lastFreeSize = getChunkSize( *lastFree ); - lastFreeOffset = getChunkOffset( *lastFree ); - } - - if( lastFreeSize + lastFreeOffset == m_currentSize ) - { - // We found a chunk at the end of the container - m_freeChunks.erase( lastFree.base() ); - // so we can merge it with the new freeChunk chunk - m_freeChunks.insert( Chunk( aNewSize - m_currentSize + lastFreeSize, // size - m_currentSize - lastFreeSize ) ); // offset - } - else - { - // As there is no free chunk at the end of container - simply add a new entry - if( aNewSize > m_currentSize ) // only in the case of enlargement - { - m_freeChunks.insert( Chunk( aNewSize - m_currentSize, // size - m_currentSize ) ); // offset - } - } - m_freeSpace += ( aNewSize - m_currentSize ); m_currentSize = aNewSize; return true; } + + +void VBO_CONTAINER::freeItem( VBO_ITEM* aItem ) +{ + int size = aItem->GetSize(); + int offset = aItem->GetOffset(); + + m_freeChunks.insert( Chunk( size, offset ) ); + m_freeSpace += size; + m_items.erase( aItem ); + + // Item size is set to 0, so it means that it is not stored in the container + aItem->setSize( 0 ); +} + + +void VBO_CONTAINER::test() const +{ + unsigned int freeSpace = 0; + FreeChunkMap::const_iterator it, it_end; + + // Check if the amount of free memory stored as chunks is the same as reported by m_freeSpace + for( it = m_freeChunks.begin(), it_end = m_freeChunks.end(); it != it_end; ++it ) + freeSpace += it->first; + + wxASSERT( freeSpace == m_freeSpace ); +} diff --git a/common/gal/opengl/vbo_item.cpp b/common/gal/opengl/vbo_item.cpp index 3f3d21b6b0..15bdcc68d4 100644 --- a/common/gal/opengl/vbo_item.cpp +++ b/common/gal/opengl/vbo_item.cpp @@ -52,9 +52,8 @@ VBO_ITEM::~VBO_ITEM() void VBO_ITEM::PushVertex( const VBO_VERTEX* aVertex ) { - m_container->Add( this, aVertex ); + m_container->Add( aVertex ); - m_size++; m_isDirty = true; } diff --git a/include/gal/opengl/vbo_container.h b/include/gal/opengl/vbo_container.h index de2faf1f2d..cb48204fc7 100644 --- a/include/gal/opengl/vbo_container.h +++ b/include/gal/opengl/vbo_container.h @@ -35,8 +35,7 @@ #include #include #include -#include -#include +#include namespace KiGfx { @@ -47,23 +46,22 @@ class VBO_CONTAINER { public: VBO_CONTAINER( unsigned int aSize = defaultInitSize ); - ~VBO_CONTAINER(); + virtual ~VBO_CONTAINER(); ///< Maps size of free memory chunks to their offsets typedef std::pair Chunk; typedef std::multimap FreeChunkMap; - ///< Maps VBO_ITEMs to reserved memory chunks offsets & sizes - typedef std::pair ReservedChunk; - typedef boost::unordered_map ReservedChunkMap; + /// List of all the stored items + typedef std::set Items; /** * Function StartItem() - * Starts an unknown sized item. After calling the function it is possible to add vertices - * using function Add(). - * @param aVboItem is the item that is going to store vertices in the container. + * Sets an item to start its modifications. After calling the function it is possible to add + * vertices using function Add(). + * @param aItem is the item that is going to store vertices in the container. */ - void StartItem( VBO_ITEM* aVboItem ); + void StartItem( VBO_ITEM* aItem ); /** * Function EndItem() @@ -74,30 +72,20 @@ public: /** * Function Add() - * Stores given number of vertices in the container for the specific VBO_ITEM. - * @param aVboItem is the owner of the vertices. + * Stores given number of vertices in the container for the specific VBO_ITEM (started by + * StartItem() function). + * @param aItem is the owner of the vertices. * @param aVertex are vertices data to be stored. * @param aSize is the number of vertices to be added. */ - void Add( VBO_ITEM* aVboItem, const VBO_VERTEX* aVertex, unsigned int aSize = 1 ); + void Add( const VBO_VERTEX* aVertex, unsigned int aSize = 1 ); /** * Function Free() - * Frees the chunk reserved by the aVboItem. - * @param aVboItem is the owner of the chunk to be freed. + * Frees the chunk reserved by the aItem. + * @param aItem is the owner of the chunk to be freed. */ - inline void Free( VBO_ITEM* aVboItem ) - { - ReservedChunkMap::iterator it = m_reservedChunks.find( aVboItem ); - freeChunk( it ); - - // Dynamic memory freeing, there is no point in holding - // a large amount of memory when there is no use for it - if( m_freeSpace > ( m_currentSize / 2 ) ) - { - resizeContainer( m_currentSize / 2 ); - } - } + void Free( VBO_ITEM* aItem ); /** * Function Clear() @@ -115,9 +103,9 @@ public: /** * Function GetVertices() * Returns vertices stored by the specific item. - * @aVboItem is the specific item. + * @aItem is the specific item. */ - VBO_VERTEX* GetVertices( const VBO_ITEM* aVboItem ) const; + VBO_VERTEX* GetVertices( const VBO_ITEM* aItem ) const; /** * Function GetVertices() @@ -208,51 +196,50 @@ public: private: ///< Stores size & offset of free chunks. FreeChunkMap m_freeChunks; - ///< Stores owners (VBO_ITEM*) of reserved chunks and their size & offset. - ReservedChunkMap m_reservedChunks; + ///< Stored VERTEX_ITEMs + Items m_items; /** - * Function allocate() - * Finds an offset where the number of vertices can be stored in a continous space. If there is - * no such chunk, appropriate amount of memory is allocated first. - * @param aVboItem is the owner of vertices to be stored. + * Function allocate() + * Allocates the given amount of memory for the current VBO_ITEM (set by StartItem() function). + * @param aSize is the number of vertices that are requested to be allocated. + * @return Pointer to the allocated space. + */ + VBO_VERTEX* allocate( unsigned int aSize ); + + /** + * Function reallocate() + * Resizes the chunk that stores the current item to the given size. * @param aSize is the number of vertices to be stored. + * @return Offset of the new chunk. */ - unsigned int allocate( VBO_ITEM* aVboItem, unsigned int aSize ); + unsigned int reallocate( unsigned int aSize ); /** * Function getChunkSize() - * Returns size of the given chunk (works both for reserved and free chunks). + * Returns size of the given chunk. * @param aChunk is the chunk. + * @return Size of the chunk. */ - inline int getChunkSize( const Chunk& aChunk ) const + inline unsigned int getChunkSize( const Chunk& aChunk ) const { return aChunk.first; } - inline int getChunkSize( const ReservedChunk& aChunk ) const - { - return aChunk.second.first; - } - /** * Function getChunkOffset() - * Returns offset of the given chunk (works both for reserved and free chunks). + * Returns offset of the given chunk. * @param aChunk is the chunk. + * @return Offset of the chunk. */ inline unsigned int getChunkOffset( const Chunk& aChunk ) const { return aChunk.second; } - inline unsigned int getChunkOffset( const ReservedChunk& aChunk ) const - { - return aChunk.second.second; - } - /** - * Function getChunkOffset() - * Upadtes offset of the given chunk (works both for reserved and free chunks). + * Function setChunkOffset() + * Updates offset of the given chunk. * !! IMPORTANT: it does not reallocate the chunk, it just changes its properties. * @param aChunk is the chunk. */ @@ -261,51 +248,45 @@ private: aChunk.second = aOffset; } - inline void setChunkOffset( ReservedChunk& aChunk, unsigned int aOffset ) const - { - aChunk.second.second = aOffset; - } - - /** - * Function getChunkVboItem() - * Returns owner of the given reserved chunk. - * @param aChunk is the chunk. - */ - inline VBO_ITEM* getChunkVboItem( const ReservedChunk& aChunk ) const - { - return aChunk.first; - } - /** * Function defragment() * Removes empty spaces between chunks, so after that there is a long continous space * for storing vertices at the and of the container. - * @return false in case of failure (eg. memory shortage) + * @return false in case of failure (eg. memory shortage). */ bool defragment( VBO_VERTEX* aTarget = NULL ); /** - * Function resizeChunk() - * Changes size of the chunk that stores vertices of aVboItem. - * @param aVboItem is the item for which reserved space size should be changed. - * @param aNewSize is the new size for the aVboItem, expressed in vertices number. + * Function mergeFreeChunks() + * Looks for consecutive free memory chunks and merges them, decreasing fragmentation of + * memory. */ - void resizeChunk( VBO_ITEM* aVboItem, int aNewSize ); + void mergeFreeChunks(); /** * Function resizeContainer() * Prepares a bigger container of a given size. * @param aNewSize is the new size of container, expressed in vertices - * @return false in case of failure (eg. memory shortage) + * @return false in case of failure (eg. memory shortage). */ bool resizeContainer( unsigned int aNewSize ); /** - * Function freeChunk() - * Frees the space described in aChunk and returns it to the free space pool. - * @param aChunk is a space to be freed. + * Function freeItem() + * Frees the space occupied by the item and returns it to the free space pool. + * @param aItem is the item to be freed. */ - void freeChunk( const ReservedChunkMap::iterator& aChunk ); + void freeItem( VBO_ITEM* aItem ); + + /** + * Function reservedSpace() + * Returns size of the reserved memory space. + * @return Size of the reserved memory space (expressed as a number of vertices). + */ + unsigned int reservedSpace() + { + return m_currentSize - m_freeSpace; + } ///< How many vertices we can store in the container unsigned int m_freeSpace; @@ -316,25 +297,26 @@ private: ///< Actual storage memory VBO_VERTEX* m_vertices; - ///< A flag saying if there is the item with an unknown size being added - bool itemStarted; + ///< Initial size, used on clearing the container + unsigned int m_initialSize; - ///< Variables holding the state of the item currently being added - unsigned int itemSize; - unsigned int itemChunkSize; - VBO_ITEM* item; + ///< Variables holding the state of the item currently being modified + unsigned int m_itemSize; + unsigned int m_chunkSize; + unsigned int m_chunkOffset; + VBO_ITEM* m_item; - ///< Color used for new vertices pushed. + ///< Color used for the new vertices pushed. GLubyte m_color[VBO_ITEM::ColorStride]; ///< Shader and its parameters used for new vertices pushed GLfloat m_shader[VBO_ITEM::ShaderStride]; ///< Current transform matrix applied for every new vertex pushed. - const glm::mat4* m_transform; + const glm::mat4* m_transform; ///< Failure flag - bool m_failed; + bool m_failed; /** * Function getPowerOf2() @@ -353,6 +335,9 @@ private: ///< Default initial size of a container (expressed in vertices) static const unsigned int defaultInitSize = 1048576; + + ///< Basic tests for the container, use only for debugging. + void test() const; }; } // namespace KiGfx diff --git a/include/gal/opengl/vbo_item.h b/include/gal/opengl/vbo_item.h index 146f0966a2..e30f92d8ec 100644 --- a/include/gal/opengl/vbo_item.h +++ b/include/gal/opengl/vbo_item.h @@ -47,6 +47,8 @@ class VBO_CONTAINER; class VBO_ITEM { +friend class VBO_CONTAINER; + public: VBO_ITEM( VBO_CONTAINER* aContainer ); ~VBO_ITEM(); @@ -89,16 +91,6 @@ public: return m_size; } - /** - * Function SetOffset() - * Sets data offset in the VBO. - * @param aOffset is the offset expressed as a number of vertices. - */ - inline void SetOffset( unsigned int aOffset ) - { - m_offset = aOffset; - } - /** * Function GetOffset() * Returns data offset in the VBO. @@ -149,7 +141,7 @@ public: static const unsigned int IndByteSize = sizeof(GLuint); -private: +protected: ///< Offset and size of data stored in the VBO_CONTAINER. unsigned int m_offset; unsigned int m_size; @@ -159,6 +151,26 @@ private: ///< Flag telling if the item should be recached in VBO or not. bool m_isDirty; + + /** + * Function setSize() + * Sets data size in the VBO. + * @param aSize is the size expressed as a number of vertices. + */ + void setSize( unsigned int aSize ) + { + m_size = aSize; + } + + /** + * Function setOffset() + * Sets data offset in the VBO. + * @param aOffset is the offset expressed as a number of vertices. + */ + inline void setOffset( unsigned int aOffset ) + { + m_offset = aOffset; + } }; } // namespace KiGfx