Commit bbc0e8eb authored by Maciej Suminski's avatar Maciej Suminski
Browse files

Refactorization of VBO_CONTAINER.

parent 99e88140
Loading
Loading
Loading
Loading
+193 −194
Original line number Original line Diff line number Diff line
@@ -28,9 +28,8 @@
 */
 */


#include <gal/opengl/vbo_container.h>
#include <gal/opengl/vbo_container.h>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <list>
#include <boost/foreach.hpp>
#include <wx/log.h>
#include <wx/log.h>
#ifdef __WXDEBUG__
#ifdef __WXDEBUG__
#include <profile.h>
#include <profile.h>
@@ -39,7 +38,7 @@
using namespace KiGfx;
using namespace KiGfx;


VBO_CONTAINER::VBO_CONTAINER( unsigned int aSize ) :
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 )
        m_failed( false )
{
{
    // By default no shader is used
    // 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;
    m_item      = aItem;
    item = aVboItem;
    m_itemSize  = aItem->GetSize();
    itemSize = 0;
    m_chunkSize = m_itemSize;


    // Reserve minimal sensible chunk size (at least to store a single triangle)
    if( m_itemSize == 0 )
    itemChunkSize = 3;
        m_items.insert( m_item );   // The item was not stored before
    allocate( aVboItem, itemChunkSize );
    else
        m_chunkOffset = m_item->GetOffset();
}
}




void VBO_CONTAINER::EndItem()
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
        // Add the not used memory back to the pool
        int itemChunkOffset = item->GetOffset();
        m_freeChunks.insert( Chunk( m_chunkSize - m_itemSize, m_chunkOffset + m_itemSize ) );

        m_freeSpace += ( m_chunkSize - m_itemSize );
        m_reservedChunks.erase( item );
        m_reservedChunks.insert( ReservedChunk( item, Chunk( itemSize, itemChunkOffset ) ) );

        m_freeChunks.insert( Chunk( itemChunkSize - itemSize, itemChunkOffset + itemSize ) );
        m_freeSpace += ( itemChunkSize - itemSize );
    }
    }


    item = NULL;
    m_item = NULL;
    itemStarted = false;
}
}




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;

    if( m_failed )
        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
    // Pointer to the vertex that we are currently adding
            // so it will not be removed during a possible defragmentation
    VBO_VERTEX* vertexPtr = allocate( aSize );
            ReservedChunkMap::iterator it = m_reservedChunks.find( item );
            m_reservedChunks.insert( ReservedChunk( static_cast<VBO_ITEM*>( 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( vertexPtr == NULL )
            if( itemChunkOffset > m_currentSize )
            {
                m_failed = true;
        return;
        return;
            }

            it = m_reservedChunks.find( static_cast<VBO_ITEM*>( 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 )
    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
        // Modify the vertex according to the currently used transformations
        if( m_transform != NULL )
        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->shader[j] = m_shader[j];
        }
        }

        vertexPtr++;
    }
    }


}
}
@@ -206,41 +135,90 @@ void VBO_CONTAINER::Clear()
{
{
    // Change size to the default one
    // Change size to the default one
    m_vertices = static_cast<VBO_VERTEX*>( realloc( m_vertices,
    m_vertices = static_cast<VBO_VERTEX*>( 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
    // Reset state variables
    m_freeSpace = defaultInitSize;
    m_currentSize = defaultInitSize;
    itemStarted = false;
    m_transform = NULL;
    m_transform = NULL;
    m_failed = false;
    m_failed = false;


    // By default no shader is used
    // By default no shader is used
    m_shader[0] = 0;
    m_shader[0] = 0;


    m_freeChunks.clear();
    m_reservedChunks.clear();

    // In the beginning there is only free space
    // 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 ) );
    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
VBO_VERTEX* VBO_CONTAINER::GetAllVertices() const
{
{
    return m_vertices;
    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];
    return &m_vertices[offset];
}
}


VBO_VERTEX* VBO_CONTAINER::allocate( unsigned int aSize )
{
    wxASSERT( m_item != NULL );

    if( m_failed )
        return NULL;


unsigned int VBO_CONTAINER::allocate( VBO_ITEM* aVboItem, unsigned int aSize )
    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?
    // Is there enough space to store vertices?
    if( m_freeSpace < aSize )
    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 ) );
            result = resizeContainer( getPowerOf2( m_currentSize * 2 + aSize ) );
        }
        }


        // An error has occurred
        if( !result )
        if( !result )
        {
            return UINT_MAX;
            return UINT_MAX;
    }
    }
    }


    // Look for the space with at least given size
    // Look for the free space of at least given size
    FreeChunkMap::iterator it = m_freeChunks.lower_bound( aSize );
    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
        // In the case when there is enough space to store the vertices,
        // storing vertices, but the space is not continous
        // but the free space is not continous we should defragment the container
        if( !defragment() )
        if( !defragment() )
        {
            return UINT_MAX;
            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
        // 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
        // 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;
    // Parameters of the allocated cuhnk
    unsigned int chunkOffset = it->second;
    unsigned int chunkSize = newChunk->first;

    unsigned int chunkOffset = newChunk->second;
    m_freeChunks.erase( it );


    wxASSERT( chunkSize >= aSize );
    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 there is some space left, return it to the pool - add an entry for it
    if( chunkSize > aSize )
    if( chunkSize > aSize )
    {
    {
        m_freeChunks.insert( Chunk( chunkSize - aSize, chunkOffset + 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;
    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 )
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 )
    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<VBO_VERTEX*>( malloc( m_currentSize * sizeof( VBO_VERTEX ) ) );
        aTarget = static_cast<VBO_VERTEX*>( malloc( m_currentSize * sizeof( VBO_VERTEX ) ) );
        if( aTarget == NULL )
        if( aTarget == NULL )
        {
        {
@@ -336,20 +308,18 @@ bool VBO_CONTAINER::defragment( VBO_VERTEX* aTarget )
    }
    }


    int newOffset = 0;
    int newOffset = 0;
    ReservedChunkMap::iterator it, it_end;
    Items::iterator it, it_end;
    for( it = m_reservedChunks.begin(), it_end = m_reservedChunks.end(); it != it_end; ++it )
    for( it = m_items.begin(), it_end = m_items.end(); it != it_end; ++it )
    {
    {
        VBO_ITEM* vboItem = getChunkVboItem( *it );
        VBO_ITEM* item = *it;
        int itemOffset = getChunkOffset( *it );
        int itemOffset = item->GetOffset();
        int itemSize = getChunkSize( *it );
        int itemSize = item->GetSize();


        // Move an item to the new container
        // Move an item to the new container
        memcpy( &aTarget[newOffset], &m_vertices[itemOffset], itemSize * VBO_ITEM::VertByteSize );
        memcpy( &aTarget[newOffset], &m_vertices[itemOffset], itemSize * VBO_ITEM::VertByteSize );


        // Update new offset
        // Update its offset
        if( vboItem )
        item->setOffset( newOffset );
            vboItem->SetOffset( newOffset );
        setChunkOffset( *it, newOffset );


        // Move to the next free space
        // Move to the next free space
        newOffset += itemSize;
        newOffset += itemSize;
@@ -360,28 +330,52 @@ bool VBO_CONTAINER::defragment( VBO_VERTEX* aTarget )


    // Now there is only one big chunk of free memory
    // Now there is only one big chunk of free memory
    m_freeChunks.clear();
    m_freeChunks.clear();
    m_freeChunks.insert( Chunk( m_freeSpace, m_currentSize - m_freeSpace ) );
    m_freeChunks.insert( Chunk( m_freeSpace, reservedSpace() ) );


    return true;
    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
    // Reversed free chunks map - this one stores chunk size with its offset as the key
    ReservedChunkMap::iterator it = m_reservedChunks.find( aVboItem );
    std::list<Chunk> freeChunks;
    int size = getChunkSize( *it );
    int offset = getChunkOffset( *it );


    int newOffset = allocate( aVboItem, aNewSize );
    FreeChunkMap::const_iterator it, it_end;
    memcpy( &m_vertices[newOffset], &m_vertices[offset], size * VBO_ITEM::VertByteSize );
    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
    std::list<Chunk>::const_iterator itf, itf_end;
    m_reservedChunks.erase( it );
    unsigned int offset = freeChunks.front().first;
    m_freeChunks.insert( Chunk( size, offset ) );
    unsigned int size   = freeChunks.front().second;
    m_freeSpace += size;
    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 )
    if( aNewSize < m_currentSize )
    {
    {
        // Shrinking container
        // Sanity check, no shrinking if we cannot fit all the data
        // Sanity check, no shrinking if we cannot fit all the data
        if( ( m_currentSize - m_freeSpace ) > aNewSize )
        if( reservedSpace() > aNewSize )
            return false;
            return false;


        newContainer = static_cast<VBO_VERTEX*>( malloc( aNewSize * sizeof( VBO_VERTEX ) ) );
        newContainer = static_cast<VBO_VERTEX*>( malloc( aNewSize * sizeof( VBO_VERTEX ) ) );
@@ -404,52 +399,56 @@ bool VBO_CONTAINER::resizeContainer( unsigned int aNewSize )


        // Defragment directly to the new, smaller container
        // Defragment directly to the new, smaller container
        defragment( newContainer );
        defragment( newContainer );

        // We have to correct freeChunks after defragmentation
        m_freeChunks.clear();
        m_freeChunks.insert( Chunk( aNewSize - reservedSpace(), reservedSpace() ) );
    }
    }
    else
    else
    {
    {
        // Enlarging container
        newContainer = static_cast<VBO_VERTEX*>( realloc( m_vertices, aNewSize * sizeof( VBO_VERTEX ) ) );
        newContainer = static_cast<VBO_VERTEX*>( realloc( m_vertices, aNewSize * sizeof( VBO_VERTEX ) ) );
        if( newContainer == NULL )
        if( newContainer == NULL )
        {
        {
            wxLogError( wxT( "Run out of memory" ) );
            wxLogError( wxT( "Run out of memory" ) );
            return false;
            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;
    m_vertices = newContainer;


    // Update variables
    m_freeSpace += ( aNewSize - m_currentSize );
    unsigned int lastFreeSize = 0;
    m_currentSize = aNewSize;
    unsigned int lastFreeOffset = 0;


    // Search for the last free chunk *at the end of the container* (not the last chunk in general)
    return true;
    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 )

void VBO_CONTAINER::freeItem( VBO_ITEM* aItem )
{
{
        // We found a chunk at the end of the container
    int size    = aItem->GetSize();
        m_freeChunks.erase( lastFree.base() );
    int offset  = aItem->GetOffset();
        // so we can merge it with the new freeChunk chunk

        m_freeChunks.insert( Chunk( aNewSize - m_currentSize + lastFreeSize,    // size
    m_freeChunks.insert( Chunk( size, offset ) );
                                    m_currentSize - lastFreeSize ) );           // 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 );
}
}
    else

    {

        // As there is no free chunk at the end of container - simply add a new entry
void VBO_CONTAINER::test() const
        if( aNewSize > m_currentSize )  // only in the case of enlargement
{
{
            m_freeChunks.insert( Chunk( aNewSize - m_currentSize,               // size
    unsigned int freeSpace = 0;
                                        m_currentSize ) );                      // offset
    FreeChunkMap::const_iterator it, it_end;
        }
    }


    m_freeSpace += ( aNewSize - m_currentSize );
    // Check if the amount of free memory stored as chunks is the same as reported by m_freeSpace
    m_currentSize = aNewSize;
    for( it = m_freeChunks.begin(), it_end = m_freeChunks.end(); it != it_end; ++it )
        freeSpace += it->first;


    return true;
    wxASSERT( freeSpace == m_freeSpace );
}
}
+1 −2
Original line number Original line Diff line number Diff line
@@ -52,9 +52,8 @@ VBO_ITEM::~VBO_ITEM()


void VBO_ITEM::PushVertex( const VBO_VERTEX* aVertex )
void VBO_ITEM::PushVertex( const VBO_VERTEX* aVertex )
{
{
    m_container->Add( this, aVertex );
    m_container->Add( aVertex );


    m_size++;
    m_isDirty = true;
    m_isDirty = true;
}
}


+71 −86

File changed.

Preview size limit exceeded, changes collapsed.

+23 −11
Original line number Original line Diff line number Diff line
@@ -47,6 +47,8 @@ class VBO_CONTAINER;


class VBO_ITEM
class VBO_ITEM
{
{
friend class VBO_CONTAINER;

public:
public:
    VBO_ITEM( VBO_CONTAINER* aContainer );
    VBO_ITEM( VBO_CONTAINER* aContainer );
    ~VBO_ITEM();
    ~VBO_ITEM();
@@ -89,16 +91,6 @@ public:
        return m_size;
        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()
     * Function GetOffset()
     * Returns data offset in the VBO.
     * Returns data offset in the VBO.
@@ -149,7 +141,7 @@ public:


    static const unsigned int IndByteSize        = sizeof(GLuint);
    static const unsigned int IndByteSize        = sizeof(GLuint);


private:
protected:
    ///< Offset and size of data stored in the VBO_CONTAINER.
    ///< Offset and size of data stored in the VBO_CONTAINER.
    unsigned int    m_offset;
    unsigned int    m_offset;
    unsigned int    m_size;
    unsigned int    m_size;
@@ -159,6 +151,26 @@ private:


    ///< Flag telling if the item should be recached in VBO or not.
    ///< Flag telling if the item should be recached in VBO or not.
    bool            m_isDirty;
    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
} // namespace KiGfx