diff --git a/common/gal/opengl/gpu_manager.cpp b/common/gal/opengl/gpu_manager.cpp index 138bf4f0fb..0c623e0a4e 100644 --- a/common/gal/opengl/gpu_manager.cpp +++ b/common/gal/opengl/gpu_manager.cpp @@ -30,6 +30,9 @@ #include #include #include +#include + +#include #include #include @@ -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( 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 diff --git a/common/gal/opengl/vertex_manager.cpp b/common/gal/opengl/vertex_manager.cpp index ba4e3b925f..6e7baddfb2 100644 --- a/common/gal/opengl/vertex_manager.cpp +++ b/common/gal/opengl/vertex_manager.cpp @@ -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 ); } diff --git a/include/gal/opengl/gpu_manager.h b/include/gal/opengl/gpu_manager.h index dbbf524019..8f4e84ae48 100644 --- a/include/gal/opengl/gpu_manager.h +++ b/include/gal/opengl/gpu_manager.h @@ -27,6 +27,7 @@ #ifndef GPU_MANAGER_H_ #define GPU_MANAGER_H_ +#include #include #include @@ -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 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 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;