Fixes for video cards unable to use gl{Un,}MapBuffer correctly
Fixes: lp:1685335 * https://bugs.launchpad.net/kicad/+bug/1685335 Fixes: lp:1683041 * https://bugs.launchpad.net/kicad/+bug/1683041
This commit is contained in:
parent
46b5575c51
commit
262fcc91af
|
@ -49,6 +49,8 @@ set( GAL_SRCS
|
||||||
gal/opengl/vertex_item.cpp
|
gal/opengl/vertex_item.cpp
|
||||||
gal/opengl/vertex_container.cpp
|
gal/opengl/vertex_container.cpp
|
||||||
gal/opengl/cached_container.cpp
|
gal/opengl/cached_container.cpp
|
||||||
|
gal/opengl/cached_container_gpu.cpp
|
||||||
|
gal/opengl/cached_container_ram.cpp
|
||||||
gal/opengl/noncached_container.cpp
|
gal/opengl/noncached_container.cpp
|
||||||
gal/opengl/vertex_manager.cpp
|
gal/opengl/vertex_manager.cpp
|
||||||
gal/opengl/gpu_manager.cpp
|
gal/opengl/gpu_manager.cpp
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2013-2016 CERN
|
* Copyright 2013-2017 CERN
|
||||||
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
|
@ -32,10 +32,8 @@
|
||||||
#include <gal/opengl/cached_container.h>
|
#include <gal/opengl/cached_container.h>
|
||||||
#include <gal/opengl/vertex_manager.h>
|
#include <gal/opengl/vertex_manager.h>
|
||||||
#include <gal/opengl/vertex_item.h>
|
#include <gal/opengl/vertex_item.h>
|
||||||
#include <gal/opengl/shader.h>
|
|
||||||
#include <gal/opengl/utils.h>
|
#include <gal/opengl/utils.h>
|
||||||
|
|
||||||
#include <confirm.h>
|
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
|
@ -47,27 +45,13 @@
|
||||||
using namespace KIGFX;
|
using namespace KIGFX;
|
||||||
|
|
||||||
CACHED_CONTAINER::CACHED_CONTAINER( unsigned int aSize ) :
|
CACHED_CONTAINER::CACHED_CONTAINER( unsigned int aSize ) :
|
||||||
VERTEX_CONTAINER( aSize ), m_item( NULL ),
|
VERTEX_CONTAINER( aSize ), m_item( NULL ), m_chunkSize( 0 ), m_chunkOffset( 0 )
|
||||||
m_chunkSize( 0 ), m_chunkOffset( 0 ), m_isMapped( false ),
|
|
||||||
m_isInitialized( false ), m_glBufferHandle( -1 )
|
|
||||||
{
|
{
|
||||||
// In the beginning there is only free space
|
// In the beginning there is only free space
|
||||||
m_freeChunks.insert( std::make_pair( aSize, 0 ) );
|
m_freeChunks.insert( std::make_pair( aSize, 0 ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
CACHED_CONTAINER::~CACHED_CONTAINER()
|
|
||||||
{
|
|
||||||
if( m_isMapped )
|
|
||||||
Unmap();
|
|
||||||
|
|
||||||
if( m_isInitialized )
|
|
||||||
{
|
|
||||||
glDeleteBuffers( 1, &m_glBufferHandle );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void CACHED_CONTAINER::SetItem( VERTEX_ITEM* aItem )
|
void CACHED_CONTAINER::SetItem( VERTEX_ITEM* aItem )
|
||||||
{
|
{
|
||||||
assert( aItem != NULL );
|
assert( aItem != NULL );
|
||||||
|
@ -75,7 +59,6 @@ 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;
|
||||||
|
@ -120,7 +103,7 @@ void CACHED_CONTAINER::FinishItem()
|
||||||
VERTEX* CACHED_CONTAINER::Allocate( unsigned int aSize )
|
VERTEX* CACHED_CONTAINER::Allocate( unsigned int aSize )
|
||||||
{
|
{
|
||||||
assert( m_item != NULL );
|
assert( m_item != NULL );
|
||||||
assert( m_isMapped );
|
assert( IsMapped() );
|
||||||
|
|
||||||
if( m_failed )
|
if( m_failed )
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -211,9 +194,7 @@ void CACHED_CONTAINER::Clear()
|
||||||
// Set the size of all the stored VERTEX_ITEMs to 0, so it is clear that they are not held
|
// Set the size of all the stored VERTEX_ITEMs to 0, so it is clear that they are not held
|
||||||
// in the container anymore
|
// in the container anymore
|
||||||
for( ITEMS::iterator it = m_items.begin(); it != m_items.end(); ++it )
|
for( ITEMS::iterator it = m_items.begin(); it != m_items.end(); ++it )
|
||||||
{
|
|
||||||
( *it )->setSize( 0 );
|
( *it )->setSize( 0 );
|
||||||
}
|
|
||||||
|
|
||||||
m_items.clear();
|
m_items.clear();
|
||||||
|
|
||||||
|
@ -223,51 +204,10 @@ void CACHED_CONTAINER::Clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CACHED_CONTAINER::Map()
|
|
||||||
{
|
|
||||||
assert( !IsMapped() );
|
|
||||||
|
|
||||||
if( !m_isInitialized )
|
|
||||||
init();
|
|
||||||
|
|
||||||
glBindBuffer( GL_ARRAY_BUFFER, m_glBufferHandle );
|
|
||||||
m_vertices = static_cast<VERTEX*>( glMapBuffer( GL_ARRAY_BUFFER, GL_READ_WRITE ) );
|
|
||||||
checkGlError( "mapping vertices buffer" );
|
|
||||||
|
|
||||||
m_isMapped = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void CACHED_CONTAINER::Unmap()
|
|
||||||
{
|
|
||||||
assert( IsMapped() );
|
|
||||||
|
|
||||||
glUnmapBuffer( GL_ARRAY_BUFFER );
|
|
||||||
checkGlError( "unmapping vertices buffer" );
|
|
||||||
glBindBuffer( GL_ARRAY_BUFFER, 0 );
|
|
||||||
m_vertices = NULL;
|
|
||||||
checkGlError( "unbinding vertices buffer" );
|
|
||||||
|
|
||||||
m_isMapped = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void CACHED_CONTAINER::init()
|
|
||||||
{
|
|
||||||
glGenBuffers( 1, &m_glBufferHandle );
|
|
||||||
glBindBuffer( GL_ARRAY_BUFFER, m_glBufferHandle );
|
|
||||||
glBufferData( GL_ARRAY_BUFFER, m_currentSize * VertexSize, NULL, GL_DYNAMIC_DRAW );
|
|
||||||
glBindBuffer( GL_ARRAY_BUFFER, 0 );
|
|
||||||
checkGlError( "allocating video memory for cached container" );
|
|
||||||
|
|
||||||
m_isInitialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool CACHED_CONTAINER::reallocate( unsigned int aSize )
|
bool CACHED_CONTAINER::reallocate( unsigned int aSize )
|
||||||
{
|
{
|
||||||
assert( aSize > 0 );
|
assert( aSize > 0 );
|
||||||
assert( m_isMapped );
|
assert( IsMapped() );
|
||||||
|
|
||||||
unsigned int itemSize = m_item->GetSize();
|
unsigned int itemSize = m_item->GetSize();
|
||||||
|
|
||||||
|
@ -336,6 +276,38 @@ bool CACHED_CONTAINER::reallocate( unsigned int aSize )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CACHED_CONTAINER::defragment( VERTEX* aTarget )
|
||||||
|
{
|
||||||
|
// Defragmentation
|
||||||
|
ITEMS::iterator it, it_end;
|
||||||
|
int newOffset = 0;
|
||||||
|
|
||||||
|
for( VERTEX_ITEM* item : m_items )
|
||||||
|
{
|
||||||
|
int itemOffset = item->GetOffset();
|
||||||
|
int itemSize = item->GetSize();
|
||||||
|
|
||||||
|
// Move an item to the new container
|
||||||
|
memcpy( &aTarget[newOffset], &m_vertices[itemOffset], itemSize * VertexSize );
|
||||||
|
|
||||||
|
// Update new offset
|
||||||
|
item->setOffset( newOffset );
|
||||||
|
|
||||||
|
// Move to the next free space
|
||||||
|
newOffset += itemSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the current item and place it at the end
|
||||||
|
if( m_item->GetSize() > 0 )
|
||||||
|
{
|
||||||
|
memcpy( &aTarget[newOffset], &m_vertices[m_item->GetOffset()],
|
||||||
|
m_item->GetSize() * VertexSize );
|
||||||
|
m_item->setOffset( newOffset );
|
||||||
|
m_chunkOffset = newOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void CACHED_CONTAINER::mergeFreeChunks()
|
void CACHED_CONTAINER::mergeFreeChunks()
|
||||||
{
|
{
|
||||||
if( m_freeChunks.size() <= 1 ) // There are no chunks that can be merged
|
if( m_freeChunks.size() <= 1 ) // There are no chunks that can be merged
|
||||||
|
@ -395,200 +367,6 @@ void CACHED_CONTAINER::mergeFreeChunks()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool CACHED_CONTAINER::defragmentResize( unsigned int aNewSize )
|
|
||||||
{
|
|
||||||
if( !m_useCopyBuffer )
|
|
||||||
return defragmentResizeMemcpy( aNewSize );
|
|
||||||
|
|
||||||
assert( IsMapped() );
|
|
||||||
|
|
||||||
wxLogTrace( "GAL_CACHED_CONTAINER",
|
|
||||||
wxT( "Resizing & defragmenting container 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;
|
|
||||||
#endif /* __WXDEBUG__ */
|
|
||||||
|
|
||||||
GLuint newBuffer;
|
|
||||||
|
|
||||||
// glCopyBufferSubData requires a buffer to be unmapped
|
|
||||||
glUnmapBuffer( GL_ARRAY_BUFFER );
|
|
||||||
|
|
||||||
// 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 );
|
|
||||||
checkGlError( "creating buffer during defragmentation" );
|
|
||||||
|
|
||||||
ITEMS::iterator it, it_end;
|
|
||||||
int newOffset = 0;
|
|
||||||
|
|
||||||
// Defragmentation
|
|
||||||
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
|
|
||||||
glCopyBufferSubData( GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER,
|
|
||||||
itemOffset * VertexSize, newOffset * VertexSize, itemSize * VertexSize );
|
|
||||||
|
|
||||||
// Update new offset
|
|
||||||
item->setOffset( newOffset );
|
|
||||||
|
|
||||||
// Move to the next free space
|
|
||||||
newOffset += itemSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move the current item and place it at the end
|
|
||||||
if( m_item->GetSize() > 0 )
|
|
||||||
{
|
|
||||||
glCopyBufferSubData( GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER,
|
|
||||||
m_item->GetOffset() * VertexSize, newOffset * VertexSize,
|
|
||||||
m_item->GetSize() * VertexSize );
|
|
||||||
|
|
||||||
m_item->setOffset( newOffset );
|
|
||||||
m_chunkOffset = newOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanup
|
|
||||||
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
|
|
||||||
glBindBuffer( GL_ARRAY_BUFFER, 0 );
|
|
||||||
// Previously we have unmapped the array buffer, now when it is also
|
|
||||||
// unbound, it may be officially marked as unmapped
|
|
||||||
m_isMapped = false;
|
|
||||||
glDeleteBuffers( 1, &m_glBufferHandle );
|
|
||||||
|
|
||||||
// Switch to the new vertex buffer
|
|
||||||
m_glBufferHandle = newBuffer;
|
|
||||||
Map();
|
|
||||||
checkGlError( "switching buffers during defragmentation" );
|
|
||||||
|
|
||||||
#ifdef __WXDEBUG__
|
|
||||||
totalTime.Stop();
|
|
||||||
|
|
||||||
wxLogTrace( "GAL_CACHED_CONTAINER",
|
|
||||||
"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;
|
|
||||||
#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" );
|
|
||||||
|
|
||||||
// Defragmentation
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move the current item and place it at the end
|
|
||||||
if( m_item->GetSize() > 0 )
|
|
||||||
{
|
|
||||||
memcpy( &newBufferMem[newOffset], &m_vertices[m_item->GetOffset()],
|
|
||||||
m_item->GetSize() * VertexSize );
|
|
||||||
m_item->setOffset( newOffset );
|
|
||||||
m_chunkOffset = newOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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();
|
|
||||||
checkGlError( "switching buffers during defragmentation" );
|
|
||||||
|
|
||||||
#ifdef __WXDEBUG__
|
|
||||||
totalTime.Stop();
|
|
||||||
|
|
||||||
wxLogTrace( "GAL_CACHED_CONTAINER",
|
|
||||||
"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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void CACHED_CONTAINER::addFreeChunk( unsigned int aOffset, unsigned int aSize )
|
void CACHED_CONTAINER::addFreeChunk( unsigned int aOffset, unsigned int aSize )
|
||||||
{
|
{
|
||||||
assert( aOffset + aSize <= m_currentSize );
|
assert( aOffset + aSize <= m_currentSize );
|
||||||
|
@ -669,4 +447,3 @@ void CACHED_CONTAINER::test()
|
||||||
// Overlapping check TODO
|
// Overlapping check TODO
|
||||||
#endif /* __WXDEBUG__ */
|
#endif /* __WXDEBUG__ */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,265 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright 2013-2017 CERN
|
||||||
|
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you may find one here:
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||||
|
* or you may write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <gal/opengl/cached_container_gpu.h>
|
||||||
|
#include <gal/opengl/vertex_manager.h>
|
||||||
|
#include <gal/opengl/vertex_item.h>
|
||||||
|
#include <gal/opengl/shader.h>
|
||||||
|
#include <gal/opengl/utils.h>
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#ifdef __WXDEBUG__
|
||||||
|
#include <wx/log.h>
|
||||||
|
#include <profile.h>
|
||||||
|
#endif /* __WXDEBUG__ */
|
||||||
|
|
||||||
|
using namespace KIGFX;
|
||||||
|
|
||||||
|
CACHED_CONTAINER_GPU::CACHED_CONTAINER_GPU( unsigned int aSize ) :
|
||||||
|
CACHED_CONTAINER( aSize ), m_isMapped( false ),
|
||||||
|
m_isInitialized( false ), m_glBufferHandle( -1 )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CACHED_CONTAINER_GPU::~CACHED_CONTAINER_GPU()
|
||||||
|
{
|
||||||
|
if( m_isMapped )
|
||||||
|
Unmap();
|
||||||
|
|
||||||
|
if( m_isInitialized )
|
||||||
|
glDeleteBuffers( 1, &m_glBufferHandle );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CACHED_CONTAINER_GPU::Map()
|
||||||
|
{
|
||||||
|
assert( !IsMapped() );
|
||||||
|
|
||||||
|
if( !m_isInitialized )
|
||||||
|
init();
|
||||||
|
|
||||||
|
glBindBuffer( GL_ARRAY_BUFFER, m_glBufferHandle );
|
||||||
|
m_vertices = static_cast<VERTEX*>( glMapBuffer( GL_ARRAY_BUFFER, GL_READ_WRITE ) );
|
||||||
|
checkGlError( "mapping vertices buffer" );
|
||||||
|
|
||||||
|
m_isMapped = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CACHED_CONTAINER_GPU::Unmap()
|
||||||
|
{
|
||||||
|
assert( IsMapped() );
|
||||||
|
|
||||||
|
glUnmapBuffer( GL_ARRAY_BUFFER );
|
||||||
|
checkGlError( "unmapping vertices buffer" );
|
||||||
|
glBindBuffer( GL_ARRAY_BUFFER, 0 );
|
||||||
|
m_vertices = NULL;
|
||||||
|
checkGlError( "unbinding vertices buffer" );
|
||||||
|
|
||||||
|
m_isMapped = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CACHED_CONTAINER_GPU::init()
|
||||||
|
{
|
||||||
|
m_useCopyBuffer = GLEW_ARB_copy_buffer;
|
||||||
|
|
||||||
|
glGenBuffers( 1, &m_glBufferHandle );
|
||||||
|
glBindBuffer( GL_ARRAY_BUFFER, m_glBufferHandle );
|
||||||
|
glBufferData( GL_ARRAY_BUFFER, m_currentSize * VertexSize, NULL, GL_DYNAMIC_DRAW );
|
||||||
|
glBindBuffer( GL_ARRAY_BUFFER, 0 );
|
||||||
|
checkGlError( "allocating video memory for cached container" );
|
||||||
|
|
||||||
|
m_isInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool CACHED_CONTAINER_GPU::defragmentResize( unsigned int aNewSize )
|
||||||
|
{
|
||||||
|
if( !m_useCopyBuffer )
|
||||||
|
return defragmentResizeMemcpy( aNewSize );
|
||||||
|
|
||||||
|
assert( IsMapped() );
|
||||||
|
|
||||||
|
wxLogTrace( "GAL_CACHED_CONTAINER_GPU",
|
||||||
|
wxT( "Resizing & defragmenting container 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;
|
||||||
|
#endif /* __WXDEBUG__ */
|
||||||
|
|
||||||
|
GLuint newBuffer;
|
||||||
|
|
||||||
|
// glCopyBufferSubData requires a buffer to be unmapped
|
||||||
|
glUnmapBuffer( GL_ARRAY_BUFFER );
|
||||||
|
|
||||||
|
// 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 );
|
||||||
|
checkGlError( "creating buffer during defragmentation" );
|
||||||
|
|
||||||
|
ITEMS::iterator it, it_end;
|
||||||
|
int newOffset = 0;
|
||||||
|
|
||||||
|
// Defragmentation
|
||||||
|
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
|
||||||
|
glCopyBufferSubData( GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER,
|
||||||
|
itemOffset * VertexSize, newOffset * VertexSize, itemSize * VertexSize );
|
||||||
|
|
||||||
|
// Update new offset
|
||||||
|
item->setOffset( newOffset );
|
||||||
|
|
||||||
|
// Move to the next free space
|
||||||
|
newOffset += itemSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the current item and place it at the end
|
||||||
|
if( m_item->GetSize() > 0 )
|
||||||
|
{
|
||||||
|
glCopyBufferSubData( GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER,
|
||||||
|
m_item->GetOffset() * VertexSize, newOffset * VertexSize,
|
||||||
|
m_item->GetSize() * VertexSize );
|
||||||
|
|
||||||
|
m_item->setOffset( newOffset );
|
||||||
|
m_chunkOffset = newOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
|
||||||
|
glBindBuffer( GL_ARRAY_BUFFER, 0 );
|
||||||
|
// Previously we have unmapped the array buffer, now when it is also
|
||||||
|
// unbound, it may be officially marked as unmapped
|
||||||
|
m_isMapped = false;
|
||||||
|
glDeleteBuffers( 1, &m_glBufferHandle );
|
||||||
|
|
||||||
|
// Switch to the new vertex buffer
|
||||||
|
m_glBufferHandle = newBuffer;
|
||||||
|
Map();
|
||||||
|
checkGlError( "switching buffers during defragmentation" );
|
||||||
|
|
||||||
|
#ifdef __WXDEBUG__
|
||||||
|
totalTime.Stop();
|
||||||
|
|
||||||
|
wxLogTrace( "GAL_CACHED_CONTAINER_GPU",
|
||||||
|
"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_GPU::defragmentResizeMemcpy( unsigned int aNewSize )
|
||||||
|
{
|
||||||
|
assert( IsMapped() );
|
||||||
|
|
||||||
|
wxLogTrace( "GAL_CACHED_CONTAINER_GPU",
|
||||||
|
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;
|
||||||
|
#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" );
|
||||||
|
|
||||||
|
defragment( newBufferMem );
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
checkGlError( "switching buffers during defragmentation" );
|
||||||
|
|
||||||
|
#ifdef __WXDEBUG__
|
||||||
|
totalTime.Stop();
|
||||||
|
|
||||||
|
wxLogTrace( "GAL_CACHED_CONTAINER_GPU",
|
||||||
|
"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;
|
||||||
|
}
|
|
@ -0,0 +1,121 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright 2013-2017 CERN
|
||||||
|
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you may find one here:
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||||
|
* or you may write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <gal/opengl/cached_container_ram.h>
|
||||||
|
#include <gal/opengl/vertex_manager.h>
|
||||||
|
#include <gal/opengl/vertex_item.h>
|
||||||
|
#include <gal/opengl/shader.h>
|
||||||
|
#include <gal/opengl/utils.h>
|
||||||
|
|
||||||
|
#include <confirm.h>
|
||||||
|
#include <list>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#ifdef __WXDEBUG__
|
||||||
|
#include <wx/log.h>
|
||||||
|
#include <profile.h>
|
||||||
|
#endif /* __WXDEBUG__ */
|
||||||
|
|
||||||
|
using namespace KIGFX;
|
||||||
|
|
||||||
|
CACHED_CONTAINER_RAM::CACHED_CONTAINER_RAM( unsigned int aSize ) :
|
||||||
|
CACHED_CONTAINER( aSize ), m_isInitialized( false ), m_verticesBuffer( 0 )
|
||||||
|
{
|
||||||
|
m_vertices = static_cast<VERTEX*>( malloc( aSize * VertexSize ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CACHED_CONTAINER_RAM::~CACHED_CONTAINER_RAM()
|
||||||
|
{
|
||||||
|
if( m_isInitialized )
|
||||||
|
glDeleteBuffers( 1, &m_verticesBuffer );
|
||||||
|
|
||||||
|
free( m_vertices );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CACHED_CONTAINER_RAM::Unmap()
|
||||||
|
{
|
||||||
|
if( !m_dirty )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( !m_isInitialized )
|
||||||
|
{
|
||||||
|
glGenBuffers( 1, &m_verticesBuffer );
|
||||||
|
checkGlError( "generating vertices buffer" );
|
||||||
|
m_isInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upload vertices coordinates and shader types to GPU memory
|
||||||
|
glBindBuffer( GL_ARRAY_BUFFER, m_verticesBuffer );
|
||||||
|
checkGlError( "binding vertices buffer" );
|
||||||
|
glBufferData( GL_ARRAY_BUFFER, usedSpace() * VertexSize, m_vertices, GL_STREAM_DRAW );
|
||||||
|
checkGlError( "transferring vertices" );
|
||||||
|
glBindBuffer( GL_ARRAY_BUFFER, 0 );
|
||||||
|
checkGlError( "unbinding vertices buffer" );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool CACHED_CONTAINER_RAM::defragmentResize( unsigned int aNewSize )
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
#endif /* __WXDEBUG__ */
|
||||||
|
|
||||||
|
VERTEX* newBufferMem = static_cast<VERTEX*>( malloc( aNewSize * VertexSize ) );
|
||||||
|
|
||||||
|
if( !newBufferMem )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
defragment( newBufferMem );
|
||||||
|
|
||||||
|
// Switch to the new vertex buffer
|
||||||
|
free( m_vertices );
|
||||||
|
m_vertices = newBufferMem;
|
||||||
|
|
||||||
|
#ifdef __WXDEBUG__
|
||||||
|
totalTime.Stop();
|
||||||
|
|
||||||
|
wxLogTrace( "GAL_CACHED_CONTAINER",
|
||||||
|
"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;
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2013-2016 CERN
|
* Copyright 2013-2017 CERN
|
||||||
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
|
@ -22,13 +22,9 @@
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* @file gpu_manager.cpp
|
|
||||||
* @brief Class to handle uploading vertices and indices to GPU in drawing purposes.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <gal/opengl/gpu_manager.h>
|
#include <gal/opengl/gpu_manager.h>
|
||||||
#include <gal/opengl/cached_container.h>
|
#include <gal/opengl/cached_container_gpu.h>
|
||||||
|
#include <gal/opengl/cached_container_ram.h>
|
||||||
#include <gal/opengl/noncached_container.h>
|
#include <gal/opengl/noncached_container.h>
|
||||||
#include <gal/opengl/shader.h>
|
#include <gal/opengl/shader.h>
|
||||||
#include <gal/opengl/utils.h>
|
#include <gal/opengl/utils.h>
|
||||||
|
@ -45,13 +41,10 @@ using namespace KIGFX;
|
||||||
|
|
||||||
GPU_MANAGER* GPU_MANAGER::MakeManager( VERTEX_CONTAINER* aContainer )
|
GPU_MANAGER* GPU_MANAGER::MakeManager( VERTEX_CONTAINER* aContainer )
|
||||||
{
|
{
|
||||||
if( typeid( *aContainer ) == typeid( CACHED_CONTAINER ) )
|
if( aContainer->IsCached() )
|
||||||
return new GPU_CACHED_MANAGER( aContainer );
|
return new GPU_CACHED_MANAGER( aContainer );
|
||||||
else if( typeid( *aContainer ) == typeid( NONCACHED_CONTAINER ) )
|
else
|
||||||
return new GPU_NONCACHED_MANAGER( aContainer );
|
return new GPU_NONCACHED_MANAGER( aContainer );
|
||||||
|
|
||||||
wxASSERT_MSG( false, wxT( "Not handled container type" ) );
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -87,10 +87,6 @@ OPENGL_GAL::OPENGL_GAL( GAL_DISPLAY_OPTIONS& aDisplayOptions, wxWindow* aParent,
|
||||||
compositor = new OPENGL_COMPOSITOR;
|
compositor = new OPENGL_COMPOSITOR;
|
||||||
compositor->SetAntialiasingMode( options.gl_antialiasing_mode );
|
compositor->SetAntialiasingMode( options.gl_antialiasing_mode );
|
||||||
|
|
||||||
cachedManager = new VERTEX_MANAGER( true );
|
|
||||||
nonCachedManager = new VERTEX_MANAGER( false );
|
|
||||||
overlayManager = new VERTEX_MANAGER( false );
|
|
||||||
|
|
||||||
// Initialize the flags
|
// Initialize the flags
|
||||||
isFramebufferInitialized = false;
|
isFramebufferInitialized = false;
|
||||||
isBitmapFontInitialized = false;
|
isBitmapFontInitialized = false;
|
||||||
|
@ -154,9 +150,13 @@ OPENGL_GAL::~OPENGL_GAL()
|
||||||
ClearCache();
|
ClearCache();
|
||||||
|
|
||||||
delete compositor;
|
delete compositor;
|
||||||
delete cachedManager;
|
|
||||||
delete nonCachedManager;
|
if( isInitialized )
|
||||||
delete overlayManager;
|
{
|
||||||
|
delete cachedManager;
|
||||||
|
delete nonCachedManager;
|
||||||
|
delete overlayManager;
|
||||||
|
}
|
||||||
|
|
||||||
GL_CONTEXT_MANAGER::Get().UnlockCtx( glPrivContext );
|
GL_CONTEXT_MANAGER::Get().UnlockCtx( glPrivContext );
|
||||||
|
|
||||||
|
@ -1251,7 +1251,9 @@ void OPENGL_GAL::DeleteGroup( int aGroupNumber )
|
||||||
void OPENGL_GAL::ClearCache()
|
void OPENGL_GAL::ClearCache()
|
||||||
{
|
{
|
||||||
groups.clear();
|
groups.clear();
|
||||||
cachedManager->Clear();
|
|
||||||
|
if( isInitialized )
|
||||||
|
cachedManager->Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1762,6 +1764,10 @@ void OPENGL_GAL::init()
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cachedManager = new VERTEX_MANAGER( true );
|
||||||
|
nonCachedManager = new VERTEX_MANAGER( false );
|
||||||
|
overlayManager = new VERTEX_MANAGER( false );
|
||||||
|
|
||||||
// Make VBOs use shaders
|
// Make VBOs use shaders
|
||||||
cachedManager->SetShader( *shader );
|
cachedManager->SetShader( *shader );
|
||||||
nonCachedManager->SetShader( *shader );
|
nonCachedManager->SetShader( *shader );
|
||||||
|
|
|
@ -28,18 +28,30 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <gal/opengl/vertex_container.h>
|
#include <gal/opengl/vertex_container.h>
|
||||||
#include <gal/opengl/cached_container.h>
|
#include <gal/opengl/cached_container_ram.h>
|
||||||
|
#include <gal/opengl/cached_container_gpu.h>
|
||||||
#include <gal/opengl/noncached_container.h>
|
#include <gal/opengl/noncached_container.h>
|
||||||
#include <gal/opengl/shader.h>
|
#include <gal/opengl/shader.h>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
using namespace KIGFX;
|
using namespace KIGFX;
|
||||||
|
|
||||||
VERTEX_CONTAINER* VERTEX_CONTAINER::MakeContainer( bool aCached )
|
VERTEX_CONTAINER* VERTEX_CONTAINER::MakeContainer( bool aCached )
|
||||||
{
|
{
|
||||||
if( aCached )
|
if( aCached )
|
||||||
return new CACHED_CONTAINER;
|
{
|
||||||
else
|
const unsigned char* vendor = glGetString( GL_VENDOR );
|
||||||
return new NONCACHED_CONTAINER;
|
|
||||||
|
// AMD/ATI cards do not cope well with GPU memory mapping,
|
||||||
|
// so the vertex data has to be kept in RAM
|
||||||
|
if( strstr( (const char*) vendor, "AMD" ) )
|
||||||
|
return new CACHED_CONTAINER_RAM;
|
||||||
|
else
|
||||||
|
return new CACHED_CONTAINER_GPU;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new NONCACHED_CONTAINER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2013 CERN
|
* Copyright 2013-2017 CERN
|
||||||
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
|
@ -22,13 +22,6 @@
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* @file cached_container.h
|
|
||||||
* @brief Class to store instances of VERTEX with caching. It allows storing VERTEX objects and
|
|
||||||
* associates them with VERTEX_ITEMs. This leads to a possibility of caching vertices data in the
|
|
||||||
* GPU memory and a fast reuse of that data.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef CACHED_CONTAINER_H_
|
#ifndef CACHED_CONTAINER_H_
|
||||||
#define CACHED_CONTAINER_H_
|
#define CACHED_CONTAINER_H_
|
||||||
|
|
||||||
|
@ -41,11 +34,22 @@ namespace KIGFX
|
||||||
class VERTEX_ITEM;
|
class VERTEX_ITEM;
|
||||||
class SHADER;
|
class SHADER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Class to store VERTEX instances with caching. It associates VERTEX
|
||||||
|
* objects and with VERTEX_ITEMs. Caching vertices data in the memory and a
|
||||||
|
* enables fast reuse of that data.
|
||||||
|
*/
|
||||||
|
|
||||||
class CACHED_CONTAINER : public VERTEX_CONTAINER
|
class CACHED_CONTAINER : public VERTEX_CONTAINER
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CACHED_CONTAINER( unsigned int aSize = defaultInitSize );
|
CACHED_CONTAINER( unsigned int aSize = DEFAULT_SIZE );
|
||||||
~CACHED_CONTAINER();
|
virtual ~CACHED_CONTAINER() {}
|
||||||
|
|
||||||
|
bool IsCached() const override
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
///> @copydoc VERTEX_CONTAINER::SetItem()
|
///> @copydoc VERTEX_CONTAINER::SetItem()
|
||||||
virtual void SetItem( VERTEX_ITEM* aItem ) override;
|
virtual void SetItem( VERTEX_ITEM* aItem ) override;
|
||||||
|
@ -66,25 +70,19 @@ public:
|
||||||
* Function GetBufferHandle()
|
* Function GetBufferHandle()
|
||||||
* returns handle to the vertex buffer. It might be negative if the buffer is not initialized.
|
* returns handle to the vertex buffer. It might be negative if the buffer is not initialized.
|
||||||
*/
|
*/
|
||||||
inline unsigned int GetBufferHandle() const
|
virtual unsigned int GetBufferHandle() const = 0;
|
||||||
{
|
|
||||||
return m_glBufferHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function IsMapped()
|
* Function IsMapped()
|
||||||
* returns true if vertex buffer is currently mapped.
|
* returns true if vertex buffer is currently mapped.
|
||||||
*/
|
*/
|
||||||
inline bool IsMapped() const
|
virtual bool IsMapped() const = 0;
|
||||||
{
|
|
||||||
return m_isMapped;
|
|
||||||
}
|
|
||||||
|
|
||||||
///> @copydoc VERTEX_CONTAINER::Map()
|
///> @copydoc VERTEX_CONTAINER::Map()
|
||||||
void Map() override;
|
virtual void Map() override = 0;
|
||||||
|
|
||||||
///> @copydoc VERTEX_CONTAINER::Unmap()
|
///> @copydoc VERTEX_CONTAINER::Unmap()
|
||||||
void Unmap() override;
|
virtual void Unmap() override = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
///> Maps size of free memory chunks to their offsets
|
///> Maps size of free memory chunks to their offsets
|
||||||
|
@ -107,25 +105,6 @@ 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;
|
|
||||||
|
|
||||||
///> Flag saying if the vertex buffer is initialized
|
|
||||||
bool m_isInitialized;
|
|
||||||
|
|
||||||
///> Vertex buffer handle
|
|
||||||
unsigned int m_glBufferHandle;
|
|
||||||
|
|
||||||
///> Flag saying whether it is safe to use glCopyBufferSubData
|
|
||||||
bool m_useCopyBuffer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function init()
|
|
||||||
* performs the GL vertex buffer initialization. It can be invoked only when an OpenGL context
|
|
||||||
* is bound.
|
|
||||||
*/
|
|
||||||
void init();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function reallocate()
|
* Function reallocate()
|
||||||
* resizes the chunk that stores the current item to the given size. The current item has
|
* resizes the chunk that stores the current item to the given size. The current item has
|
||||||
|
@ -145,8 +124,14 @@ protected:
|
||||||
* @param aNewSize is the new size of container, expressed in number of vertices
|
* @param aNewSize is the new size of container, expressed in number of vertices
|
||||||
* @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 );
|
virtual bool defragmentResize( unsigned int aNewSize ) = 0;
|
||||||
bool defragmentResizeMemcpy( unsigned int aNewSize );
|
|
||||||
|
/**
|
||||||
|
* Transfers all stored data to a new buffer, removing empty spaces between the data chunks
|
||||||
|
* in the container.
|
||||||
|
* @param aTarget is the destination for the defragmented data.
|
||||||
|
*/
|
||||||
|
void defragment( VERTEX* aTarget );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function mergeFreeChunks()
|
* Function mergeFreeChunks()
|
||||||
|
@ -155,15 +140,6 @@ protected:
|
||||||
*/
|
*/
|
||||||
void mergeFreeChunks();
|
void mergeFreeChunks();
|
||||||
|
|
||||||
/**
|
|
||||||
* Function getPowerOf2()
|
|
||||||
* returns the nearest power of 2, bigger than aNumber.
|
|
||||||
*
|
|
||||||
* @param aNumber is the number for which we look for a bigger power of 2.
|
|
||||||
*/
|
|
||||||
unsigned int getPowerOf2( unsigned int aNumber ) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
/**
|
/**
|
||||||
* Function getChunkSize()
|
* Function getChunkSize()
|
||||||
* returns size of the given chunk.
|
* returns size of the given chunk.
|
||||||
|
@ -192,6 +168,7 @@ private:
|
||||||
*/
|
*/
|
||||||
void addFreeChunk( unsigned int aOffset, unsigned int aSize );
|
void addFreeChunk( unsigned int aOffset, unsigned int aSize );
|
||||||
|
|
||||||
|
private:
|
||||||
/// Debug & test functions
|
/// Debug & test functions
|
||||||
void showFreeChunks();
|
void showFreeChunks();
|
||||||
void showUsedChunks();
|
void showUsedChunks();
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright 2013-2017 CERN
|
||||||
|
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you may find one here:
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||||
|
* or you may write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CACHED_CONTAINER_GPU_H_
|
||||||
|
#define CACHED_CONTAINER_GPU_H_
|
||||||
|
|
||||||
|
#include <gal/opengl/cached_container.h>
|
||||||
|
|
||||||
|
namespace KIGFX
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Specialization of CACHED_CONTAINER that stores data in video memory via memory mapping.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class CACHED_CONTAINER_GPU : public CACHED_CONTAINER
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CACHED_CONTAINER_GPU( unsigned int aSize = DEFAULT_SIZE );
|
||||||
|
~CACHED_CONTAINER_GPU();
|
||||||
|
|
||||||
|
unsigned int GetBufferHandle() const override
|
||||||
|
{
|
||||||
|
return m_glBufferHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsMapped() const override
|
||||||
|
{
|
||||||
|
return m_isMapped;
|
||||||
|
}
|
||||||
|
|
||||||
|
///> @copydoc VERTEX_CONTAINER::Map()
|
||||||
|
void Map() override;
|
||||||
|
|
||||||
|
///> @copydoc VERTEX_CONTAINER::Unmap()
|
||||||
|
void Unmap() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
///> Flag saying if vertex buffer is currently mapped
|
||||||
|
bool m_isMapped;
|
||||||
|
|
||||||
|
///> Flag saying if the vertex buffer is initialized
|
||||||
|
bool m_isInitialized;
|
||||||
|
|
||||||
|
///> Vertex buffer handle
|
||||||
|
unsigned int m_glBufferHandle;
|
||||||
|
|
||||||
|
///> Flag saying whether it is safe to use glCopyBufferSubData
|
||||||
|
bool m_useCopyBuffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function init()
|
||||||
|
* performs the GL vertex buffer initialization. It can be invoked only when an OpenGL context
|
||||||
|
* is bound.
|
||||||
|
*/
|
||||||
|
void init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function defragmentResize()
|
||||||
|
* removes empty spaces between chunks and optionally resizes the container.
|
||||||
|
* After the operation there is continous space for storing vertices at the end of the container.
|
||||||
|
*
|
||||||
|
* @param aNewSize is the new size of container, expressed in number of vertices
|
||||||
|
* @return false in case of failure (e.g. memory shortage)
|
||||||
|
*/
|
||||||
|
bool defragmentResize( unsigned int aNewSize ) override;
|
||||||
|
bool defragmentResizeMemcpy( unsigned int aNewSize );
|
||||||
|
};
|
||||||
|
} // namespace KIGFX
|
||||||
|
|
||||||
|
#endif /* CACHED_CONTAINER_GPU_H_ */
|
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright 2013-2017 CERN
|
||||||
|
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you may find one here:
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||||
|
* or you may write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CACHED_CONTAINER_RAM_H_
|
||||||
|
#define CACHED_CONTAINER_RAM_H_
|
||||||
|
|
||||||
|
#include <gal/opengl/cached_container.h>
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
namespace KIGFX
|
||||||
|
{
|
||||||
|
class VERTEX_ITEM;
|
||||||
|
class SHADER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Specialization of CACHED_CONTAINER that stores data in RAM. This is mainly for
|
||||||
|
* video cards/drivers that do not cope well with video memory mapping.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class CACHED_CONTAINER_RAM : public CACHED_CONTAINER
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CACHED_CONTAINER_RAM( unsigned int aSize = DEFAULT_SIZE );
|
||||||
|
~CACHED_CONTAINER_RAM();
|
||||||
|
|
||||||
|
///> @copydoc VERTEX_CONTAINER::Unmap()
|
||||||
|
void Map() override {}
|
||||||
|
|
||||||
|
///> @copydoc VERTEX_CONTAINER::Unmap()
|
||||||
|
void Unmap() override;
|
||||||
|
|
||||||
|
bool IsMapped() const override
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function GetBufferHandle()
|
||||||
|
* returns handle to the vertex buffer. It might be negative if the buffer is not initialized.
|
||||||
|
*/
|
||||||
|
unsigned int GetBufferHandle() const override
|
||||||
|
{
|
||||||
|
return m_verticesBuffer; // make common with CACHED_CONTAINER_RAM
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
///> Flag saying if the vertex buffer is initialized
|
||||||
|
bool m_isInitialized;
|
||||||
|
|
||||||
|
///> Handle to vertices buffer
|
||||||
|
GLuint m_verticesBuffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defragments the currently stored data and resizes the buffer.
|
||||||
|
* @param aNewSize is the new buffer vertex buffer size, expressed as the number of vertices.
|
||||||
|
* @return true on success.
|
||||||
|
*/
|
||||||
|
bool defragmentResize( unsigned int aNewSize ) override;
|
||||||
|
};
|
||||||
|
} // namespace KIGFX
|
||||||
|
|
||||||
|
#endif /* CACHED_CONTAINER_RAM_H_ */
|
|
@ -22,11 +22,6 @@
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* @file gpu_manager.h
|
|
||||||
* @brief Class to handle uploading vertices and indices to GPU in drawing purposes.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef GPU_MANAGER_H_
|
#ifndef GPU_MANAGER_H_
|
||||||
#define GPU_MANAGER_H_
|
#define GPU_MANAGER_H_
|
||||||
|
|
||||||
|
@ -40,6 +35,10 @@ class VERTEX_CONTAINER;
|
||||||
class CACHED_CONTAINER;
|
class CACHED_CONTAINER;
|
||||||
class NONCACHED_CONTAINER;
|
class NONCACHED_CONTAINER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Class to handle uploading vertices and indices to GPU in drawing purposes.
|
||||||
|
*/
|
||||||
|
|
||||||
class GPU_MANAGER
|
class GPU_MANAGER
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -41,9 +41,14 @@ class SHADER;
|
||||||
class NONCACHED_CONTAINER : public VERTEX_CONTAINER
|
class NONCACHED_CONTAINER : public VERTEX_CONTAINER
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NONCACHED_CONTAINER( unsigned int aSize = defaultInitSize );
|
NONCACHED_CONTAINER( unsigned int aSize = DEFAULT_SIZE );
|
||||||
virtual ~NONCACHED_CONTAINER();
|
virtual ~NONCACHED_CONTAINER();
|
||||||
|
|
||||||
|
bool IsCached() const override
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// @copydoc VERTEX_CONTAINER::SetItem( VERTEX_ITEM* aItem )
|
/// @copydoc VERTEX_CONTAINER::SetItem( VERTEX_ITEM* aItem )
|
||||||
virtual void SetItem( VERTEX_ITEM* aItem ) override;
|
virtual void SetItem( VERTEX_ITEM* aItem ) override;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2013 CERN
|
* Copyright 2013-2017 CERN
|
||||||
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
|
@ -48,6 +48,12 @@ public:
|
||||||
|
|
||||||
virtual ~VERTEX_CONTAINER();
|
virtual ~VERTEX_CONTAINER();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the container caches vertex data in RAM or video memory.
|
||||||
|
* Otherwise it is a single batch draw which is later discarded.
|
||||||
|
*/
|
||||||
|
virtual bool IsCached() const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Map()
|
* Function Map()
|
||||||
* prepares the container for vertices updates.
|
* prepares the container for vertices updates.
|
||||||
|
@ -58,8 +64,7 @@ public:
|
||||||
* Function Unmap()
|
* Function Unmap()
|
||||||
* finishes the vertices updates stage.
|
* finishes the vertices updates stage.
|
||||||
*/
|
*/
|
||||||
virtual void Unmap()
|
virtual void Unmap() {}
|
||||||
{}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function SetItem()
|
* Function SetItem()
|
||||||
|
@ -153,7 +158,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
VERTEX_CONTAINER( unsigned int aSize = defaultInitSize );
|
VERTEX_CONTAINER( unsigned int aSize = DEFAULT_SIZE );
|
||||||
|
|
||||||
///< How many vertices we can store in the container
|
///< How many vertices we can store in the container
|
||||||
unsigned int m_freeSpace;
|
unsigned int m_freeSpace;
|
||||||
|
@ -182,7 +187,7 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
///< Default initial size of a container (expressed in vertices)
|
///< Default initial size of a container (expressed in vertices)
|
||||||
static const unsigned int defaultInitSize = 1048576;
|
static constexpr unsigned int DEFAULT_SIZE = 1048576;
|
||||||
};
|
};
|
||||||
} // namespace KIGFX
|
} // namespace KIGFX
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@ class VERTEX_ITEM
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
friend class CACHED_CONTAINER;
|
friend class CACHED_CONTAINER;
|
||||||
|
friend class CACHED_CONTAINER_GPU;
|
||||||
friend class VERTEX_MANAGER;
|
friend class VERTEX_MANAGER;
|
||||||
|
|
||||||
explicit VERTEX_ITEM( const VERTEX_MANAGER& aManager );
|
explicit VERTEX_ITEM( const VERTEX_MANAGER& aManager );
|
||||||
|
|
Loading…
Reference in New Issue