Skip redundant VIEW updates and repaints
Add m_hasPendingItemUpdates to VIEW so UpdateItems() can return immediately when no item has queued update flags. The flag is set wherever m_requiredUpdate is modified and cleared at the end of UpdateItems(). In DoRePaint(), check the new flag alongside IsDirty() and cursor movement to skip both item processing and the GL draw cycle when nothing has changed. Route onPaint through Refresh() so the existing frame-rate throttle applies to native paint events as well.
This commit is contained in:
+41
-27
@@ -193,7 +193,7 @@ void EDA_DRAW_PANEL_GAL::SetFocus()
|
||||
|
||||
void EDA_DRAW_PANEL_GAL::onPaint( wxPaintEvent& WXUNUSED( aEvent ) )
|
||||
{
|
||||
DoRePaint();
|
||||
Refresh( false );
|
||||
}
|
||||
|
||||
|
||||
@@ -248,35 +248,48 @@ bool EDA_DRAW_PANEL_GAL::DoRePaint()
|
||||
|
||||
try
|
||||
{
|
||||
cntUpd.Start();
|
||||
|
||||
try
|
||||
{
|
||||
m_view->UpdateItems();
|
||||
}
|
||||
catch( std::out_of_range& err )
|
||||
{
|
||||
// Don't do anything here but don't fail
|
||||
// This can happen when we don't catch `at()` calls
|
||||
wxLogTrace( traceDrawPanel, wxS( "Out of Range error: %s" ), err.what() );
|
||||
}
|
||||
catch( std::runtime_error& err )
|
||||
{
|
||||
// Handle GL errors (e.g. glMapBuffer failure) that surface during UpdateItems().
|
||||
// These can occur on macOS under memory pressure when embedding large 3D models.
|
||||
// Log and continue so the outer handler can decide whether to switch backends.
|
||||
wxLogTrace( traceDrawPanel, wxS( "Runtime error during UpdateItems: %s" ), err.what() );
|
||||
throw;
|
||||
}
|
||||
|
||||
cntUpd.Stop();
|
||||
|
||||
VECTOR2D cursorPos = m_viewControls->GetCursorPosition();
|
||||
bool viewDirty = m_view->IsDirty();
|
||||
bool cursorMoved = ( cursorPos != m_lastCursorPosition );
|
||||
bool hasPendingItemUpdates = m_view->HasPendingItemUpdates();
|
||||
|
||||
// Skip the entire GL cycle when nothing has changed. The front buffer
|
||||
// still shows the previous frame so there is nothing to redraw.
|
||||
// Skip all update work when nothing has changed since the previous frame.
|
||||
if( !viewDirty && !cursorMoved && !hasPendingItemUpdates )
|
||||
{
|
||||
m_lastRepaintEnd = wxGetLocalTimeMillis();
|
||||
return true;
|
||||
}
|
||||
|
||||
if( hasPendingItemUpdates )
|
||||
{
|
||||
cntUpd.Start();
|
||||
|
||||
try
|
||||
{
|
||||
m_view->UpdateItems();
|
||||
}
|
||||
catch( std::out_of_range& err )
|
||||
{
|
||||
// Don't do anything here but don't fail
|
||||
// This can happen when we don't catch `at()` calls
|
||||
wxLogTrace( traceDrawPanel, wxS( "Out of Range error: %s" ), err.what() );
|
||||
}
|
||||
catch( std::runtime_error& err )
|
||||
{
|
||||
// Handle GL errors (e.g. glMapBuffer failure) that surface during UpdateItems().
|
||||
// These can occur on macOS under memory pressure when embedding large 3D models.
|
||||
// Log and continue so the outer handler can decide whether to switch backends.
|
||||
wxLogTrace( traceDrawPanel, wxS( "Runtime error during UpdateItems: %s" ),
|
||||
err.what() );
|
||||
throw;
|
||||
}
|
||||
|
||||
cntUpd.Stop();
|
||||
viewDirty = m_view->IsDirty();
|
||||
}
|
||||
|
||||
// After processing item updates, skip the GL cycle when neither the
|
||||
// view targets nor the cursor position have changed.
|
||||
if( !viewDirty && !cursorMoved )
|
||||
{
|
||||
m_lastRepaintEnd = wxGetLocalTimeMillis();
|
||||
@@ -422,13 +435,14 @@ void EDA_DRAW_PANEL_GAL::Refresh( bool aEraseBackground, const wxRect* aRect )
|
||||
{
|
||||
wxLongLong now = wxGetLocalTimeMillis();
|
||||
wxLongLong delta = now - m_lastRepaintEnd;
|
||||
bool galInitialized = m_gal && m_gal->IsInitialized();
|
||||
|
||||
// When vsync is available the driver throttles SwapBuffers, so we only need
|
||||
// a small guard to avoid queueing work faster than the GPU can consume it.
|
||||
// Without vsync, enforce a 60 FPS ceiling to prevent saturating the GPU.
|
||||
int minPeriodMs = 3;
|
||||
|
||||
if( m_gal && m_gal->IsInitialized() && m_gal->GetSwapInterval() == 0 )
|
||||
if( galInitialized && m_gal->GetSwapInterval() == 0 )
|
||||
minPeriodMs = 16;
|
||||
|
||||
if( delta >= minPeriodMs )
|
||||
|
||||
+29
-2
@@ -246,7 +246,8 @@ VIEW::VIEW() :
|
||||
m_gal( nullptr ),
|
||||
m_useDrawPriority( false ),
|
||||
m_nextDrawPriority( 0 ),
|
||||
m_reverseDrawOrder( false )
|
||||
m_reverseDrawOrder( false ),
|
||||
m_hasPendingItemUpdates( false )
|
||||
{
|
||||
// Set m_boundary to define the max area size. The default area size
|
||||
// is defined here as the max value of a int.
|
||||
@@ -724,6 +725,7 @@ void VIEW::ReorderLayerData( std::unordered_map<int, int> aReorderMap )
|
||||
viewData->reorderGroups( aReorderMap );
|
||||
|
||||
viewData->m_requiredUpdate |= COLOR;
|
||||
m_hasPendingItemUpdates = true;
|
||||
}
|
||||
|
||||
UpdateItems();
|
||||
@@ -1486,6 +1488,9 @@ void VIEW::UpdateItems()
|
||||
if( !m_gal->IsVisible() || !m_gal->IsInitialized() )
|
||||
return;
|
||||
|
||||
if( !m_hasPendingItemUpdates )
|
||||
return;
|
||||
|
||||
unsigned int cntGeomUpdate = 0;
|
||||
bool anyUpdated = false;
|
||||
|
||||
@@ -1571,15 +1576,23 @@ void VIEW::UpdateItems()
|
||||
|
||||
KI_TRACE( traceGalProfile, wxS( "View update: total items %u, geom %u anyUpdated %u\n" ),
|
||||
cntTotal, cntGeomUpdate, (unsigned) anyUpdated );
|
||||
|
||||
m_hasPendingItemUpdates = false;
|
||||
}
|
||||
|
||||
|
||||
void VIEW::UpdateAllItems( int aUpdateFlags )
|
||||
{
|
||||
if( aUpdateFlags == NONE )
|
||||
return;
|
||||
|
||||
for( VIEW_ITEM* item : *m_allItems )
|
||||
{
|
||||
if( item && item->viewPrivData() )
|
||||
{
|
||||
item->viewPrivData()->m_requiredUpdate |= aUpdateFlags;
|
||||
m_hasPendingItemUpdates = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1587,6 +1600,9 @@ void VIEW::UpdateAllItems( int aUpdateFlags )
|
||||
void VIEW::UpdateAllItemsConditionally( int aUpdateFlags,
|
||||
std::function<bool( VIEW_ITEM* )> aCondition )
|
||||
{
|
||||
if( aUpdateFlags == NONE )
|
||||
return;
|
||||
|
||||
for( VIEW_ITEM* item : *m_allItems )
|
||||
{
|
||||
if( !item )
|
||||
@@ -1595,7 +1611,10 @@ void VIEW::UpdateAllItemsConditionally( int aUpdateFlags,
|
||||
if( aCondition( item ) )
|
||||
{
|
||||
if( item->viewPrivData() )
|
||||
{
|
||||
item->viewPrivData()->m_requiredUpdate |= aUpdateFlags;
|
||||
m_hasPendingItemUpdates = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1609,7 +1628,13 @@ void VIEW::UpdateAllItemsConditionally( std::function<int( VIEW_ITEM* )> aItemFl
|
||||
continue;
|
||||
|
||||
if( item->viewPrivData() )
|
||||
item->viewPrivData()->m_requiredUpdate |= aItemFlagsProvider( item );
|
||||
{
|
||||
int flags = aItemFlagsProvider( item );
|
||||
item->viewPrivData()->m_requiredUpdate |= flags;
|
||||
|
||||
if( flags != NONE )
|
||||
m_hasPendingItemUpdates = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1620,6 +1645,7 @@ std::unique_ptr<VIEW> VIEW::DataReference() const
|
||||
std::unique_ptr<VIEW> ret = std::make_unique<VIEW>();
|
||||
ret->m_allItems = m_allItems;
|
||||
ret->m_layers = m_layers;
|
||||
ret->m_hasPendingItemUpdates = m_hasPendingItemUpdates;
|
||||
ret->SortOrderedLayers();
|
||||
return ret;
|
||||
}
|
||||
@@ -1708,6 +1734,7 @@ void VIEW::Update( const VIEW_ITEM* aItem, int aUpdateFlags ) const
|
||||
assert( aUpdateFlags != NONE );
|
||||
|
||||
viewData->m_requiredUpdate |= aUpdateFlags;
|
||||
m_hasPendingItemUpdates = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+11
-1
@@ -685,6 +685,14 @@ public:
|
||||
*/
|
||||
void UpdateItems();
|
||||
|
||||
/**
|
||||
* @return true when at least one item has queued update flags that still need processing.
|
||||
*/
|
||||
bool HasPendingItemUpdates() const
|
||||
{
|
||||
return m_hasPendingItemUpdates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all items in the view according to the given flags.
|
||||
*
|
||||
@@ -907,6 +915,8 @@ protected:
|
||||
|
||||
/// Flag to reverse the draw order when using draw priority.
|
||||
bool m_reverseDrawOrder;
|
||||
|
||||
/// True when at least one item has deferred update flags that still need processing.
|
||||
mutable bool m_hasPendingItemUpdates;
|
||||
};
|
||||
} // namespace KIGFX
|
||||
|
||||
|
||||
Reference in New Issue
Block a user