diff --git a/common/gal/opengl/opengl_gal.cpp b/common/gal/opengl/opengl_gal.cpp index 83a1f8c90e..bccc05153c 100644 --- a/common/gal/opengl/opengl_gal.cpp +++ b/common/gal/opengl/opengl_gal.cpp @@ -26,8 +26,6 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -#include - #include #include #include @@ -39,6 +37,7 @@ #endif /* __WXDEBUG__ */ #include +#include #ifndef CALLBACK #define CALLBACK @@ -82,7 +81,6 @@ OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener, groupCounter = 0; transform = glm::mat4( 1.0f ); // Identity matrix - SetSize( parentSize ); screenSize.x = parentSize.x; @@ -1606,10 +1604,9 @@ void OPENGL_GAL::EndGroup() void OPENGL_GAL::ClearCache() { - std::map::iterator it, end; - for( it = groups.begin(), end = groups.end(); it != end; it++ ) + BOOST_FOREACH( GroupsMap::value_type it, groups ) { - delete it->second; + delete it.second; } groups.clear(); diff --git a/common/gal/opengl/vbo_container.cpp b/common/gal/opengl/vbo_container.cpp index 63f0ca1f80..8e888d8bd5 100644 --- a/common/gal/opengl/vbo_container.cpp +++ b/common/gal/opengl/vbo_container.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #ifdef __WXDEBUG__ #include @@ -38,7 +39,8 @@ using namespace KiGfx; VBO_CONTAINER::VBO_CONTAINER( int aSize ) : - m_freeSpace( aSize ), m_currentSize( aSize ), itemStarted( false ), m_transform( NULL ) + m_freeSpace( aSize ), m_currentSize( aSize ), itemStarted( false ), m_transform( NULL ), + m_failed( false ) { // By default no shader is used m_shader[0] = 0; @@ -82,6 +84,7 @@ void VBO_CONTAINER::EndItem() m_freeSpace += ( itemChunkSize - itemSize ); } + item = NULL; itemStarted = false; } @@ -91,6 +94,9 @@ void VBO_CONTAINER::Add( VBO_ITEM* aVboItem, const VBO_VERTEX* aVertex, unsigned 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; @@ -98,27 +104,34 @@ void VBO_CONTAINER::Add( VBO_ITEM* aVboItem, const VBO_VERTEX* aVertex, unsigned // ..and unfortunately does not fit into currently reserved chunk if( itemSize + aSize > itemChunkSize ) { - // Find the previous chunk for the item, save it, so it can be removed later + // 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 for the current item + // 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; + } - // Save previous chunk's offset for copying data + 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 ); - // Return memory used by the previous chunk - freeChunk( it ); - itemChunkSize = newSize; } else @@ -310,7 +323,8 @@ bool VBO_CONTAINER::defragment( VBO_VERTEX* aTarget ) memcpy( &aTarget[newOffset], &m_vertices[itemOffset], itemSize * VBO_ITEM::VertByteSize ); // Update new offset - vboItem->SetOffset( newOffset ); + if( vboItem ) + vboItem->SetOffset( newOffset ); setChunkOffset( *it, newOffset ); // Move to the next free space @@ -349,26 +363,32 @@ void VBO_CONTAINER::resizeChunk( VBO_ITEM* aVboItem, int aNewSize ) bool VBO_CONTAINER::resizeContainer( unsigned int aNewSize ) { - unsigned int copySize; + VBO_VERTEX* newContainer; + if( aNewSize < m_currentSize ) { // Sanity check, no shrinking if we cannot fit all the data if( ( m_currentSize - m_freeSpace ) > aNewSize ) return false; - defragment(); - copySize = ( m_currentSize - m_freeSpace ); + newContainer = static_cast( malloc( aNewSize * sizeof( VBO_VERTEX ) ) ); + if( newContainer == NULL ) + { + wxLogError( wxT( "Run out of memory" ) ); + return false; + } + + // Defragment directly to the new, smaller container + defragment( newContainer ); } else { - copySize = m_currentSize; - } - - VBO_VERTEX* newContainer = static_cast( realloc( m_vertices, aNewSize * sizeof( VBO_VERTEX ) ) ); - if( newContainer == NULL ) - { - wxLogError( wxT( "Run out of memory" ) ); - return false; + newContainer = static_cast( realloc( m_vertices, aNewSize * sizeof( VBO_VERTEX ) ) ); + if( newContainer == NULL ) + { + wxLogError( wxT( "Run out of memory" ) ); + return false; + } } m_vertices = newContainer; diff --git a/include/gal/opengl/opengl_gal.h b/include/gal/opengl/opengl_gal.h index 663bb29d6b..115652c99e 100644 --- a/include/gal/opengl/opengl_gal.h +++ b/include/gal/opengl/opengl_gal.h @@ -49,6 +49,7 @@ #include #include #include +#include #include #include @@ -355,7 +356,8 @@ private: GLuint displayListSemiCircle; ///< Semi circle display list // Vertex buffer objects related fields - std::map groups; ///< Stores informations about VBO objects (groups) + typedef boost::unordered_map GroupsMap; + GroupsMap groups; ///< Stores informations about VBO objects (groups) unsigned int groupCounter; ///< Counter used for generating keys for groups VBO_ITEM* currentGroup; ///< Currently used VBO_ITEM (for grouping) VBO_CONTAINER* vboContainer; ///< Container for storing VBO_ITEMs @@ -559,7 +561,7 @@ private: if( isGrouping ) { // New vertex coordinates for VBO - VBO_VERTEX vertex = { aX, aY, aZ }; + const VBO_VERTEX vertex = { aX, aY, aZ }; currentGroup->PushVertex( &vertex ); } else diff --git a/include/gal/opengl/vbo_container.h b/include/gal/opengl/vbo_container.h index 2f1c8a3075..6ce50193dd 100644 --- a/include/gal/opengl/vbo_container.h +++ b/include/gal/opengl/vbo_container.h @@ -35,6 +35,7 @@ #include #include #include +#include #include namespace KiGfx @@ -52,9 +53,9 @@ public: typedef std::pair Chunk; typedef std::multimap FreeChunkMap; - ///< Maps size of reserved memory chunks to their owners (VBO_ITEMs) + ///< Maps VBO_ITEMs to reserved memory chunks offsets & sizes typedef std::pair ReservedChunk; - typedef std::multimap ReservedChunkMap; + typedef boost::unordered_map ReservedChunkMap; /** * Function StartItem() @@ -115,7 +116,7 @@ public: /** * Function GetVertices() * Returns vertices stored at the specific offset. - * @aOffest is the specific offset. + * @aOffset is the specific offset. */ inline VBO_VERTEX* GetVertices( unsigned int aOffset ) const { @@ -326,6 +327,9 @@ private: ///< Current transform matrix applied for every new vertex pushed. const glm::mat4* m_transform; + ///< Failure flag + bool m_failed; + /** * Function getPowerOf2() * Returns the nearest power of 2, bigger than aNumber.