Alternative version of CACHED_CONTAINER::defragmentResize() Certain GPUs do not support glCopyBufferSubData(), therefore there is an alternative version working with good, old memcpy().
This commit is contained in:
parent
d23a508aa3
commit
2f09e0ee40
|
@ -75,6 +75,7 @@ void CACHED_CONTAINER::SetItem( VERTEX_ITEM* aItem )
|
||||||
unsigned int itemSize = aItem->GetSize();
|
unsigned int itemSize = aItem->GetSize();
|
||||||
m_item = aItem;
|
m_item = aItem;
|
||||||
m_chunkSize = itemSize;
|
m_chunkSize = itemSize;
|
||||||
|
m_useCopyBuffer = GLEW_ARB_copy_buffer;
|
||||||
|
|
||||||
// Get the previously set offset if the item was stored previously
|
// Get the previously set offset if the item was stored previously
|
||||||
m_chunkOffset = itemSize > 0 ? aItem->GetOffset() : -1;
|
m_chunkOffset = itemSize > 0 ? aItem->GetOffset() : -1;
|
||||||
|
@ -410,6 +411,9 @@ void CACHED_CONTAINER::mergeFreeChunks()
|
||||||
|
|
||||||
bool CACHED_CONTAINER::defragmentResize( unsigned int aNewSize )
|
bool CACHED_CONTAINER::defragmentResize( unsigned int aNewSize )
|
||||||
{
|
{
|
||||||
|
if( !m_useCopyBuffer )
|
||||||
|
return defragmentResizeMemcpy( aNewSize );
|
||||||
|
|
||||||
assert( IsMapped() );
|
assert( IsMapped() );
|
||||||
|
|
||||||
wxLogTrace( "GAL_CACHED_CONTAINER",
|
wxLogTrace( "GAL_CACHED_CONTAINER",
|
||||||
|
@ -486,7 +490,101 @@ bool CACHED_CONTAINER::defragmentResize( unsigned int aNewSize )
|
||||||
|
|
||||||
// Switch to the new vertex buffer
|
// Switch to the new vertex buffer
|
||||||
m_glBufferHandle = newBuffer;
|
m_glBufferHandle = newBuffer;
|
||||||
glBindBuffer( GL_ARRAY_BUFFER, m_glBufferHandle );
|
Map();
|
||||||
|
checkGlError( "switching buffers during defragmentation" );
|
||||||
|
|
||||||
|
#ifdef __WXDEBUG__
|
||||||
|
prof_end( &totalTime );
|
||||||
|
|
||||||
|
wxLogTrace( "GAL_CACHED_CONTAINER",
|
||||||
|
wxT( "Defragmented container storing %d vertices / %.1f ms" ),
|
||||||
|
m_currentSize - m_freeSpace, totalTime.msecs() );
|
||||||
|
#endif /* __WXDEBUG__ */
|
||||||
|
|
||||||
|
m_freeSpace += ( aNewSize - m_currentSize );
|
||||||
|
m_currentSize = aNewSize;
|
||||||
|
|
||||||
|
// Now there is only one big chunk of free memory
|
||||||
|
m_freeChunks.clear();
|
||||||
|
m_freeChunks.insert( std::make_pair( m_freeSpace, m_currentSize - m_freeSpace ) );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool CACHED_CONTAINER::defragmentResizeMemcpy( unsigned int aNewSize )
|
||||||
|
{
|
||||||
|
assert( IsMapped() );
|
||||||
|
|
||||||
|
wxLogTrace( "GAL_CACHED_CONTAINER",
|
||||||
|
wxT( "Resizing & defragmenting container (memcpy) from %d to %d" ),
|
||||||
|
m_currentSize, aNewSize );
|
||||||
|
|
||||||
|
// No shrinking if we cannot fit all the data
|
||||||
|
if( usedSpace() > aNewSize )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
#ifdef __WXDEBUG__
|
||||||
|
prof_counter totalTime;
|
||||||
|
prof_start( &totalTime );
|
||||||
|
#endif /* __WXDEBUG__ */
|
||||||
|
|
||||||
|
GLuint newBuffer;
|
||||||
|
VERTEX* newBufferMem;
|
||||||
|
|
||||||
|
// Create the destination buffer
|
||||||
|
glGenBuffers( 1, &newBuffer );
|
||||||
|
|
||||||
|
// It would be best to use GL_COPY_WRITE_BUFFER here,
|
||||||
|
// but it is not available everywhere
|
||||||
|
#ifdef __WXDEBUG__
|
||||||
|
GLint eaBuffer = -1;
|
||||||
|
glGetIntegerv( GL_ELEMENT_ARRAY_BUFFER_BINDING, &eaBuffer );
|
||||||
|
assert( eaBuffer == 0 );
|
||||||
|
#endif /* __WXDEBUG__ */
|
||||||
|
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, newBuffer );
|
||||||
|
glBufferData( GL_ELEMENT_ARRAY_BUFFER, aNewSize * VertexSize, NULL, GL_DYNAMIC_DRAW );
|
||||||
|
newBufferMem = static_cast<VERTEX*>( glMapBuffer( GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY ) );
|
||||||
|
checkGlError( "creating buffer during defragmentation" );
|
||||||
|
|
||||||
|
// Special case: the container is either already defragmented or filled up to its capacity,
|
||||||
|
// so we just resize it and move the current data
|
||||||
|
if( ( m_freeChunks.size() == 0 )
|
||||||
|
|| ( m_freeChunks.size() == 1 && m_freeChunks.begin()->second == usedSpace() ) )
|
||||||
|
{
|
||||||
|
assert( aNewSize != m_currentSize );
|
||||||
|
memcpy( newBufferMem, m_vertices, usedSpace() * VertexSize );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ITEMS::iterator it, it_end;
|
||||||
|
int newOffset = 0;
|
||||||
|
|
||||||
|
for( it = m_items.begin(), it_end = m_items.end(); it != it_end; ++it )
|
||||||
|
{
|
||||||
|
VERTEX_ITEM* item = *it;
|
||||||
|
int itemOffset = item->GetOffset();
|
||||||
|
int itemSize = item->GetSize();
|
||||||
|
|
||||||
|
// Move an item to the new container
|
||||||
|
memcpy( &newBufferMem[newOffset], &m_vertices[itemOffset], itemSize * VertexSize );
|
||||||
|
|
||||||
|
// Update new offset
|
||||||
|
item->setOffset( newOffset );
|
||||||
|
|
||||||
|
// Move to the next free space
|
||||||
|
newOffset += itemSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
glUnmapBuffer( GL_ELEMENT_ARRAY_BUFFER );
|
||||||
|
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
|
||||||
|
Unmap();
|
||||||
|
glDeleteBuffers( 1, &m_glBufferHandle );
|
||||||
|
|
||||||
|
// Switch to the new vertex buffer
|
||||||
|
m_glBufferHandle = newBuffer;
|
||||||
Map();
|
Map();
|
||||||
checkGlError( "switching buffers during defragmentation" );
|
checkGlError( "switching buffers during defragmentation" );
|
||||||
|
|
||||||
|
|
|
@ -107,10 +107,18 @@ protected:
|
||||||
unsigned int m_chunkSize;
|
unsigned int m_chunkSize;
|
||||||
unsigned int m_chunkOffset;
|
unsigned int m_chunkOffset;
|
||||||
|
|
||||||
|
///> Flag saying if vertex buffer is currently mapped
|
||||||
bool m_isMapped;
|
bool m_isMapped;
|
||||||
|
|
||||||
|
///> Flag saying if the vertex buffer is initialized
|
||||||
bool m_isInitialized;
|
bool m_isInitialized;
|
||||||
|
|
||||||
|
///> Vertex buffer handle
|
||||||
unsigned int m_glBufferHandle;
|
unsigned int m_glBufferHandle;
|
||||||
|
|
||||||
|
///> Flag saying whether it is safe to use glCopyBufferSubData
|
||||||
|
bool m_useCopyBuffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function init()
|
* Function init()
|
||||||
* performs the GL vertex buffer initialization. It can be invoked only when an OpenGL context
|
* performs the GL vertex buffer initialization. It can be invoked only when an OpenGL context
|
||||||
|
@ -138,6 +146,7 @@ protected:
|
||||||
* @return false in case of failure (e.g. memory shortage)
|
* @return false in case of failure (e.g. memory shortage)
|
||||||
*/
|
*/
|
||||||
bool defragmentResize( unsigned int aNewSize );
|
bool defragmentResize( unsigned int aNewSize );
|
||||||
|
bool defragmentResizeMemcpy( unsigned int aNewSize );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function mergeFreeChunks()
|
* Function mergeFreeChunks()
|
||||||
|
|
Loading…
Reference in New Issue