GAL: OpenGL draw calls pooling/splitting

Improves rendering performance, esp. for large designs by:
- using a separate glDrawArrays calls() for large buffers of contiguous vertices (e.g. large zone fills)
- pooling smaller items into a small-sized index buffer held in system RAM (has to be DMAed to the GPU by the driver anyway)
This commit is contained in:
Tomasz Wlostowski 2021-11-28 22:32:46 +01:00
parent 569c39ac37
commit 2c6e9778a1
3 changed files with 113 additions and 101 deletions

View File

@ -30,6 +30,9 @@
#include <gal/opengl/noncached_container.h>
#include <gal/opengl/shader.h>
#include <gal/opengl/utils.h>
#include <gal/opengl/vertex_item.h>
#include <profile.h>
#include <typeinfo>
#include <confirm.h>
@ -82,26 +85,13 @@ void GPU_MANAGER::SetShader( SHADER& aShader )
GPU_CACHED_MANAGER::GPU_CACHED_MANAGER( VERTEX_CONTAINER* aContainer ) :
GPU_MANAGER( aContainer ),
m_buffersInitialized( false ),
m_indicesPtr( nullptr ),
m_indicesBuffer( 0 ),
m_indicesSize( 0 ),
m_indicesCapacity( 0 )
{
// Allocate the biggest possible buffer for indices
resizeIndices( aContainer->GetSize() );
}
GPU_CACHED_MANAGER::~GPU_CACHED_MANAGER()
{
if( m_buffersInitialized )
{
if( glBindBuffer )
glBindBuffer( GL_ARRAY_BUFFER, 0 );
if( glDeleteBuffers )
glDeleteBuffers( 1, &m_indicesBuffer );
}
}
@ -109,54 +99,40 @@ void GPU_CACHED_MANAGER::BeginDrawing()
{
wxASSERT( !m_isDrawing );
if( !m_buffersInitialized )
{
glGenBuffers( 1, &m_indicesBuffer );
checkGlError( "generating vertices buffer", __FILE__, __LINE__ );
m_buffersInitialized = true;
}
if( m_container->IsDirty() )
resizeIndices( m_container->GetSize() );
// Number of vertices to be drawn in the EndDrawing()
m_indicesSize = 0;
// Set the indices pointer to the beginning of the indices-to-draw buffer
m_indicesPtr = m_indices.get();
m_curVrangeSize = 0;
m_indexBufMaxSize = 0;
m_indexBufSize = 0;
m_vranges.clear();
m_isDrawing = true;
}
void GPU_CACHED_MANAGER::DrawIndices( unsigned int aOffset, unsigned int aSize )
void GPU_CACHED_MANAGER::DrawIndices( const VERTEX_ITEM *aItem )
{
wxASSERT( m_isDrawing );
// Copy indices of items that should be drawn to GPU memory
for( unsigned int i = aOffset; i < aOffset + aSize; *m_indicesPtr++ = i++ )
;
unsigned int offset = aItem->GetOffset();
unsigned int size = aItem->GetSize();
m_indicesSize += aSize;
}
void GPU_CACHED_MANAGER::DrawAll()
{
wxASSERT( m_isDrawing );
for( unsigned int i = 0; i < m_indicesSize; *m_indicesPtr++ = i++ )
;
m_indicesSize = m_container->GetSize();
if( size > 1000 )
{
m_totalHuge += size;
m_vranges.emplace_back( offset, offset + size - 1, true );
m_indexBufSize = std::max( m_curVrangeSize, m_indexBufSize );
m_curVrangeSize = 0;
}
else if ( size > 0 )
{
m_totalNormal += size;
m_vranges.emplace_back( offset, offset + size - 1, false );
m_curVrangeSize += size;
}
}
void GPU_CACHED_MANAGER::EndDrawing()
{
#ifdef KICAD_GAL_PROFILE
PROF_COUNTER totalRealTime;
#endif /* KICAD_GAL_PROFILE */
wxASSERT( m_isDrawing );
CACHED_CONTAINER* cached = static_cast<CACHED_CONTAINER*>( m_container );
@ -164,11 +140,10 @@ void GPU_CACHED_MANAGER::EndDrawing()
if( cached->IsMapped() )
cached->Unmap();
if( m_indicesSize == 0 )
{
m_isDrawing = false;
return;
}
m_indexBufSize = std::max( m_curVrangeSize, m_indexBufSize );
m_indexBufMaxSize = std::max( 2*m_indexBufSize, m_indexBufMaxSize );
resizeIndices( m_indexBufMaxSize );
if( m_enableDepthTest )
glEnable( GL_DEPTH_TEST );
@ -192,18 +167,58 @@ void GPU_CACHED_MANAGER::EndDrawing()
(GLvoid*) SHADER_OFFSET );
}
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_indicesBuffer );
glBufferData( GL_ELEMENT_ARRAY_BUFFER, m_indicesSize * sizeof( int ), (GLvoid*) m_indices.get(),
GL_DYNAMIC_DRAW );
PROF_COUNTER cntDraw( "gl-draw-elements" );
glDrawElements( GL_TRIANGLES, m_indicesSize, GL_UNSIGNED_INT, nullptr );
int n_ranges = m_vranges.size();
int n = 0;
GLuint* iptr = m_indices.get();
GLuint icnt = 0;
#ifdef KICAD_GAL_PROFILE
wxLogTrace( traceGalProfile, wxT( "Cached manager size: %d" ), m_indicesSize );
#endif /* KICAD_GAL_PROFILE */
int drawCalls = 0;
while( n < n_ranges )
{
VRANGE* cur = &m_vranges[n];
if( cur->m_isContinuous )
{
if( icnt > 0 )
{
glDrawElements( GL_TRIANGLES, icnt, GL_UNSIGNED_INT, m_indices.get() );
drawCalls++;
}
icnt = 0;
iptr = m_indices.get();
glDrawArrays( GL_TRIANGLES, cur->m_start, cur->m_end - cur->m_start + 1 );
drawCalls++;
}
else
{
for( GLuint i = cur->m_start; i <= cur->m_end; i++ )
{
*iptr++ = i;
icnt++;
}
}
n++;
}
if( icnt > 0 )
{
glDrawElements( GL_TRIANGLES, icnt, GL_UNSIGNED_INT, m_indices.get() );
drawCalls++;
}
cntDraw.Stop();
KI_TRACE( traceGalProfile,
"Cached manager size: VBO size %u iranges %llu max elt size %u drawcalls %u\n",
cached->AllItemsSize(), m_vranges.size(), m_indexBufMaxSize, drawCalls );
KI_TRACE( traceGalProfile, "Timing: %s\n", cntDraw.to_string() );
glBindBuffer( GL_ARRAY_BUFFER, 0 );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
cached->ClearDirty();
// Deactivate vertex array
@ -217,12 +232,6 @@ void GPU_CACHED_MANAGER::EndDrawing()
}
m_isDrawing = false;
#ifdef KICAD_GAL_PROFILE
totalRealTime.Stop();
wxLogTrace( traceGalProfile, wxT( "GPU_CACHED_MANAGER::EndDrawing(): %.1f ms" ),
totalRealTime.msecs() );
#endif /* KICAD_GAL_PROFILE */
}
@ -249,19 +258,12 @@ void GPU_NONCACHED_MANAGER::BeginDrawing()
}
void GPU_NONCACHED_MANAGER::DrawIndices( unsigned int aOffset, unsigned int aSize )
void GPU_NONCACHED_MANAGER::DrawIndices( const VERTEX_ITEM* aItem )
{
wxASSERT_MSG( false, wxT( "Not implemented yet" ) );
}
void GPU_NONCACHED_MANAGER::DrawAll()
{
// This is the default use case, nothing has to be done
// The real rendering takes place in the EndDrawing() function
}
void GPU_NONCACHED_MANAGER::EndDrawing()
{
#ifdef KICAD_GAL_PROFILE

View File

@ -243,10 +243,7 @@ void VERTEX_MANAGER::BeginDrawing() const
void VERTEX_MANAGER::DrawItem( const VERTEX_ITEM& aItem ) const
{
int size = aItem.GetSize();
int offset = aItem.GetOffset();
m_gpu->DrawIndices( offset, size );
m_gpu->DrawIndices( &aItem );
}

View File

@ -27,6 +27,7 @@
#ifndef GPU_MANAGER_H_
#define GPU_MANAGER_H_
#include <vector>
#include <gal/opengl/vertex_common.h>
#include <boost/scoped_array.hpp>
@ -34,6 +35,7 @@ namespace KIGFX
{
class SHADER;
class VERTEX_CONTAINER;
class VERTEX_ITEM;
class CACHED_CONTAINER;
class NONCACHED_CONTAINER;
@ -58,12 +60,7 @@ public:
* @param aOffset is the beginning of the range.
* @param aSize is the number of vertices to be drawn.
*/
virtual void DrawIndices( unsigned int aOffset, unsigned int aSize ) = 0;
/**
* Make the GPU draw all the vertices stored in the container.
*/
virtual void DrawAll() = 0;
virtual void DrawIndices( const VERTEX_ITEM* aItem ) = 0;
/**
* Clear the container after drawing routines.
@ -105,6 +102,19 @@ protected:
class GPU_CACHED_MANAGER : public GPU_MANAGER
{
public:
struct VRANGE
{
VRANGE( int aStart, int aEnd, bool aContinuous ) :
m_start( aStart ),
m_end( aEnd ),
m_isContinuous ( aContinuous )
{}
unsigned int m_start, m_end;
bool m_isContinuous;
};
GPU_CACHED_MANAGER( VERTEX_CONTAINER* aContainer );
~GPU_CACHED_MANAGER();
@ -112,10 +122,7 @@ public:
virtual void BeginDrawing() override;
///< @copydoc GPU_MANAGER::DrawIndices()
virtual void DrawIndices( unsigned int aOffset, unsigned int aSize ) override;
///< @copydoc GPU_MANAGER::DrawAll()
virtual void DrawAll() override;
virtual void DrawIndices( const VERTEX_ITEM* aItem ) override;
///< @copydoc GPU_MANAGER::EndDrawing()
virtual void EndDrawing() override;
@ -136,17 +143,26 @@ protected:
///< Pointer to the current indices buffer
boost::scoped_array<GLuint> m_indices;
///< Pointer to the first free cell in the indices buffer
GLuint* m_indicesPtr;
///< Handle to indices buffer
GLuint m_indicesBuffer;
///< Number of indices stored in the indices buffer
unsigned int m_indicesSize;
///< Current indices buffer size
unsigned int m_indicesCapacity;
///< Ranges of visible vertex indices to render
std::vector<VRANGE> m_vranges;
///< Number of huge VRANGEs (i.e. large zones) with separate draw calls
int m_totalHuge;
///< Number of regular VRANGEs (small items) pooled into single draw call
int m_totalNormal;
///< Current size of index buffer
unsigned int m_indexBufSize;
///< Maximum size taken by the index buffer for all frames rendered so far
unsigned int m_indexBufMaxSize;
///< Size of the current VRANGE
unsigned int m_curVrangeSize;
};
@ -159,10 +175,7 @@ public:
virtual void BeginDrawing() override;
///< @copydoc GPU_MANAGER::DrawIndices()
virtual void DrawIndices( unsigned int aOffset, unsigned int aSize ) override;
///< @copydoc GPU_MANAGER::DrawAll()
virtual void DrawAll() override;
virtual void DrawIndices( const VERTEX_ITEM* aItem ) override;
///< @copydoc GPU_MANAGER::EndDrawing()
virtual void EndDrawing() override;