7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-04-22 00:03:44 +00:00

Move GL Context into Singleton class

The GL context lock needs to be shared across kifaces.  Otherwise, we
can end up blocking the lock from one kiface.  Unfortunately, I can't
find the issue in GitLab right now for where the footprint viewer shows
a blank screen after opening too many contexts.  But that's what this
fixes.
This commit is contained in:
Seth Hillbrand 2025-01-03 17:24:24 -08:00
parent 02d1c12a4b
commit 5326c36a5f
13 changed files with 55 additions and 49 deletions
3d-viewer
3d_canvas
3d_model_viewer
3d_rendering/opengl
common/gal/opengl
eeschema
gerbview
include
pagelayout_editor
pcb_calculator
pcbnew

View File

@ -187,7 +187,7 @@ void EDA_3D_CANVAS::releaseOpenGL()
{ {
if( m_glRC ) if( m_glRC )
{ {
GL_CONTEXT_MANAGER::Get().LockCtx( m_glRC, this ); Pgm().GetGLContextManager()->LockCtx( m_glRC, this );
delete m_3d_render_raytracing; delete m_3d_render_raytracing;
m_3d_render_raytracing = nullptr; m_3d_render_raytracing = nullptr;
@ -198,8 +198,8 @@ void EDA_3D_CANVAS::releaseOpenGL()
// This is just a copy of a pointer, can safely be set to NULL. // This is just a copy of a pointer, can safely be set to NULL.
m_3d_render = nullptr; m_3d_render = nullptr;
GL_CONTEXT_MANAGER::Get().UnlockCtx( m_glRC ); Pgm().GetGLContextManager()->UnlockCtx( m_glRC );
GL_CONTEXT_MANAGER::Get().DestroyCtx( m_glRC ); Pgm().GetGLContextManager()->DestroyCtx( m_glRC );
m_glRC = nullptr; m_glRC = nullptr;
} }
} }
@ -390,7 +390,7 @@ void EDA_3D_CANVAS::DoRePaint()
// Explicitly create a new rendering context instance for this canvas. // Explicitly create a new rendering context instance for this canvas.
if( m_glRC == nullptr ) if( m_glRC == nullptr )
m_glRC = GL_CONTEXT_MANAGER::Get().CreateCtx( this ); m_glRC = Pgm().GetGLContextManager()->CreateCtx( this );
// CreateCtx could and does fail per sentry crash events, lets be graceful // CreateCtx could and does fail per sentry crash events, lets be graceful
if( m_glRC == nullptr ) if( m_glRC == nullptr )
@ -401,7 +401,7 @@ void EDA_3D_CANVAS::DoRePaint()
return; return;
} }
GL_CONTEXT_MANAGER::Get().LockCtx( m_glRC, this ); Pgm().GetGLContextManager()->LockCtx( m_glRC, this );
// Set the OpenGL viewport according to the client size of this canvas. // Set the OpenGL viewport according to the client size of this canvas.
// This is done here rather than in a wxSizeEvent handler because our // This is done here rather than in a wxSizeEvent handler because our
@ -418,7 +418,7 @@ void EDA_3D_CANVAS::DoRePaint()
{ {
if( !initializeOpenGL() ) if( !initializeOpenGL() )
{ {
GL_CONTEXT_MANAGER::Get().UnlockCtx( m_glRC ); Pgm().GetGLContextManager()->UnlockCtx( m_glRC );
m_is_currently_painting.clear(); m_is_currently_painting.clear();
return; return;
@ -440,7 +440,7 @@ void EDA_3D_CANVAS::DoRePaint()
SwapBuffers(); SwapBuffers();
GL_CONTEXT_MANAGER::Get().UnlockCtx( m_glRC ); Pgm().GetGLContextManager()->UnlockCtx( m_glRC );
m_is_currently_painting.clear(); m_is_currently_painting.clear();
return; return;
@ -528,7 +528,7 @@ void EDA_3D_CANVAS::DoRePaint()
m_is_opengl_version_supported = false; m_is_opengl_version_supported = false;
m_opengl_supports_raytracing = false; m_opengl_supports_raytracing = false;
m_is_opengl_initialized = false; m_is_opengl_initialized = false;
GL_CONTEXT_MANAGER::Get().UnlockCtx( m_glRC ); Pgm().GetGLContextManager()->UnlockCtx( m_glRC );
m_is_currently_painting.clear(); m_is_currently_painting.clear();
return; return;
} }
@ -553,7 +553,7 @@ void EDA_3D_CANVAS::DoRePaint()
// commands is displayed on the window." // commands is displayed on the window."
SwapBuffers(); SwapBuffers();
GL_CONTEXT_MANAGER::Get().UnlockCtx( m_glRC ); Pgm().GetGLContextManager()->UnlockCtx( m_glRC );
if( m_mouse_was_moved || m_camera_is_moving ) if( m_mouse_was_moved || m_camera_is_moving )
{ {

View File

@ -112,13 +112,13 @@ EDA_3D_MODEL_VIEWER::~EDA_3D_MODEL_VIEWER()
if( m_glRC ) if( m_glRC )
{ {
GL_CONTEXT_MANAGER::Get().LockCtx( m_glRC, this ); Pgm().GetGLContextManager()->LockCtx( m_glRC, this );
delete m_ogl_3dmodel; delete m_ogl_3dmodel;
m_ogl_3dmodel = nullptr; m_ogl_3dmodel = nullptr;
GL_CONTEXT_MANAGER::Get().UnlockCtx( m_glRC ); Pgm().GetGLContextManager()->UnlockCtx( m_glRC );
GL_CONTEXT_MANAGER::Get().DestroyCtx( m_glRC ); Pgm().GetGLContextManager()->DestroyCtx( m_glRC );
} }
} }
@ -256,7 +256,7 @@ void EDA_3D_MODEL_VIEWER::OnPaint( wxPaintEvent& event )
// context context current, i.e. it will be used by all subsequent OpenGL calls. // context context current, i.e. it will be used by all subsequent OpenGL calls.
// This function may only be called when the window is shown on screen" // This function may only be called when the window is shown on screen"
if( m_glRC == nullptr ) if( m_glRC == nullptr )
m_glRC = GL_CONTEXT_MANAGER::Get().CreateCtx( this ); m_glRC = Pgm().GetGLContextManager()->CreateCtx( this );
// CreateCtx could and does fail per sentry crash events, lets be graceful // CreateCtx could and does fail per sentry crash events, lets be graceful
if( m_glRC == nullptr ) if( m_glRC == nullptr )
@ -265,7 +265,7 @@ void EDA_3D_MODEL_VIEWER::OnPaint( wxPaintEvent& event )
return; return;
} }
GL_CONTEXT_MANAGER::Get().LockCtx( m_glRC, this ); Pgm().GetGLContextManager()->LockCtx( m_glRC, this );
// Set the OpenGL viewport according to the client size of this canvas. // Set the OpenGL viewport according to the client size of this canvas.
// This is done here rather than in a wxSizeEvent handler because our // This is done here rather than in a wxSizeEvent handler because our
@ -383,7 +383,7 @@ void EDA_3D_MODEL_VIEWER::OnPaint( wxPaintEvent& event )
// commands is displayed on the window." // commands is displayed on the window."
SwapBuffers(); SwapBuffers();
GL_CONTEXT_MANAGER::Get().UnlockCtx( m_glRC ); Pgm().GetGLContextManager()->UnlockCtx( m_glRC );
} }

View File

@ -26,22 +26,25 @@
#include <cstdint> #include <cstdint>
#include <gal/opengl/kiglew.h> // Must be included first #include <gal/opengl/kiglew.h> // Must be included first
#include "plugins/3dapi/xv3d_types.h"
#include "render_3d_opengl.h"
#include "opengl_utils.h" #include "opengl_utils.h"
#include "common_ogl/ogl_utils.h" #include "render_3d_opengl.h"
#include <3d_math.h>
#include <common_ogl/ogl_utils.h>
#include <plugins/3dapi/xv3d_types.h>
#include <base_units.h>
#include <board.h> #include <board.h>
#include <footprint.h> #include <footprint.h>
#include <gal/opengl/gl_context_mgr.h> #include <gal/opengl/gl_context_mgr.h>
#include <3d_math.h>
#include <glm/geometric.hpp> #include <glm/geometric.hpp>
#include <lset.h> #include <lset.h>
#include <pgm_base.h>
#include <math/util.h> // for KiROUND #include <math/util.h> // for KiROUND
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <wx/log.h> #include <wx/log.h>
#include <base_units.h>
/** /**
* Scale conversion from 3d model units to pcb units * Scale conversion from 3d model units to pcb units
@ -490,7 +493,7 @@ bool RENDER_3D_OPENGL::Redraw( bool aIsMoving, REPORTER* aStatusReporter,
// Careful here! // Careful here!
// We are in the middle of rendering and the reload method may show // We are in the middle of rendering and the reload method may show
// a dialog box that requires the opengl context for a redraw // a dialog box that requires the opengl context for a redraw
GL_CONTEXT_MANAGER::Get().RunWithoutCtxLock( [this, aStatusReporter, aWarningReporter]() Pgm().GetGLContextManager()->RunWithoutCtxLock( [this, aStatusReporter, aWarningReporter]()
{ {
reload( aStatusReporter, aWarningReporter ); reload( aStatusReporter, aWarningReporter );
} ); } );

View File

@ -27,14 +27,6 @@
#include <wx/debug.h> #include <wx/debug.h>
GL_CONTEXT_MANAGER& GL_CONTEXT_MANAGER::Get()
{
static GL_CONTEXT_MANAGER instance;
return instance;
}
wxGLContext* GL_CONTEXT_MANAGER::CreateCtx( wxGLCanvas* aCanvas, const wxGLContext* aOther ) wxGLContext* GL_CONTEXT_MANAGER::CreateCtx( wxGLCanvas* aCanvas, const wxGLContext* aOther )
{ {
wxGLContext* context = new wxGLContext( aCanvas, aOther ); wxGLContext* context = new wxGLContext( aCanvas, aOther );

View File

@ -43,6 +43,7 @@
#include <bitmap_base.h> #include <bitmap_base.h>
#include <bezier_curves.h> #include <bezier_curves.h>
#include <math/util.h> // for KiROUND #include <math/util.h> // for KiROUND
#include <pgm_base.h>
#include <trace_helpers.h> #include <trace_helpers.h>
#include <wx/frame.h> #include <wx/frame.h>
@ -331,7 +332,7 @@ OPENGL_GAL::OPENGL_GAL( const KIGFX::VC_SETTINGS& aVcSettings, GAL_DISPLAY_OPTIO
{ {
if( m_glMainContext == nullptr ) if( m_glMainContext == nullptr )
{ {
m_glMainContext = GL_CONTEXT_MANAGER::Get().CreateCtx( this ); m_glMainContext = Pgm().GetGLContextManager()->CreateCtx( this );
if( !m_glMainContext ) if( !m_glMainContext )
throw std::runtime_error( "Could not create the main OpenGL context" ); throw std::runtime_error( "Could not create the main OpenGL context" );
@ -340,7 +341,7 @@ OPENGL_GAL::OPENGL_GAL( const KIGFX::VC_SETTINGS& aVcSettings, GAL_DISPLAY_OPTIO
} }
else else
{ {
m_glPrivContext = GL_CONTEXT_MANAGER::Get().CreateCtx( this, m_glMainContext ); m_glPrivContext = Pgm().GetGLContextManager()->CreateCtx( this, m_glMainContext );
if( !m_glPrivContext ) if( !m_glPrivContext )
throw std::runtime_error( "Could not create a private OpenGL context" ); throw std::runtime_error( "Could not create a private OpenGL context" );
@ -420,7 +421,7 @@ OPENGL_GAL::OPENGL_GAL( const KIGFX::VC_SETTINGS& aVcSettings, GAL_DISPLAY_OPTIO
OPENGL_GAL::~OPENGL_GAL() OPENGL_GAL::~OPENGL_GAL()
{ {
GL_CONTEXT_MANAGER::Get().LockCtx( m_glPrivContext, this ); Pgm().GetGLContextManager()->LockCtx( m_glPrivContext, this );
--m_instanceCounter; --m_instanceCounter;
glFlush(); glFlush();
@ -437,19 +438,19 @@ OPENGL_GAL::~OPENGL_GAL()
delete m_tempManager; delete m_tempManager;
} }
GL_CONTEXT_MANAGER::Get().UnlockCtx( m_glPrivContext ); Pgm().GetGLContextManager()->UnlockCtx( m_glPrivContext );
// If it was the main context, then it will be deleted // If it was the main context, then it will be deleted
// when the last OpenGL GAL instance is destroyed (a few lines below) // when the last OpenGL GAL instance is destroyed (a few lines below)
if( m_glPrivContext != m_glMainContext ) if( m_glPrivContext != m_glMainContext )
GL_CONTEXT_MANAGER::Get().DestroyCtx( m_glPrivContext ); Pgm().GetGLContextManager()->DestroyCtx( m_glPrivContext );
delete m_shader; delete m_shader;
// Are we destroying the last GAL instance? // Are we destroying the last GAL instance?
if( m_instanceCounter == 0 ) if( m_instanceCounter == 0 )
{ {
GL_CONTEXT_MANAGER::Get().LockCtx( m_glMainContext, this ); Pgm().GetGLContextManager()->LockCtx( m_glMainContext, this );
if( m_isBitmapFontLoaded ) if( m_isBitmapFontLoaded )
{ {
@ -457,8 +458,8 @@ OPENGL_GAL::~OPENGL_GAL()
m_isBitmapFontLoaded = false; m_isBitmapFontLoaded = false;
} }
GL_CONTEXT_MANAGER::Get().UnlockCtx( m_glMainContext ); Pgm().GetGLContextManager()->UnlockCtx( m_glMainContext );
GL_CONTEXT_MANAGER::Get().DestroyCtx( m_glMainContext ); Pgm().GetGLContextManager()->DestroyCtx( m_glMainContext );
m_glMainContext = nullptr; m_glMainContext = nullptr;
} }
} }
@ -776,7 +777,7 @@ void OPENGL_GAL::LockContext( int aClientCookie )
m_isContextLocked = true; m_isContextLocked = true;
m_lockClientCookie = aClientCookie; m_lockClientCookie = aClientCookie;
GL_CONTEXT_MANAGER::Get().LockCtx( m_glPrivContext, this ); Pgm().GetGLContextManager()->LockCtx( m_glPrivContext, this );
} }
@ -790,7 +791,7 @@ void OPENGL_GAL::UnlockContext( int aClientCookie )
m_isContextLocked = false; m_isContextLocked = false;
GL_CONTEXT_MANAGER::Get().UnlockCtx( m_glPrivContext ); Pgm().GetGLContextManager()->UnlockCtx( m_glPrivContext );
} }

View File

@ -33,6 +33,7 @@ include_directories(
${CMAKE_SOURCE_DIR}/common ${CMAKE_SOURCE_DIR}/common
${CMAKE_SOURCE_DIR}/common/dialogs ${CMAKE_SOURCE_DIR}/common/dialogs
${CMAKE_SOURCE_DIR}/libs/sexpr/include ${CMAKE_SOURCE_DIR}/libs/sexpr/include
${INC_AFTER} ${INC_AFTER}
./dialogs ./dialogs
./libview ./libview
@ -565,6 +566,7 @@ set_source_files_properties( ${CMAKE_SOURCE_DIR}/common/single_top.cpp PROPERTIE
target_link_libraries( eeschema target_link_libraries( eeschema
kicommon kicommon
gal
${wxWidgets_LIBRARIES} ${wxWidgets_LIBRARIES}
) )
@ -603,6 +605,7 @@ add_library( eeschema_kiface MODULE
target_link_libraries( eeschema_kiface target_link_libraries( eeschema_kiface
PRIVATE PRIVATE
common common
gal
eeschema_kiface_objects eeschema_kiface_objects
markdown_lib markdown_lib
scripting scripting

View File

@ -112,6 +112,7 @@ set_source_files_properties( ${CMAKE_SOURCE_DIR}/common/single_top.cpp PROPERTIE
target_link_libraries( gerbview target_link_libraries( gerbview
core core
kicommon kicommon
gal
nlohmann_json nlohmann_json
${wxWidgets_LIBRARIES} ${wxWidgets_LIBRARIES}
) )

View File

@ -35,10 +35,8 @@
class GAL_API GL_CONTEXT_MANAGER class GAL_API GL_CONTEXT_MANAGER
{ {
public: public:
/**
* Return the GL_CONTEXT_MANAGER instance (singleton). GL_CONTEXT_MANAGER();
*/
static GL_CONTEXT_MANAGER& Get();
/** /**
* Create a managed OpenGL context. * Create a managed OpenGL context.
@ -142,11 +140,6 @@ private:
///< Lock to prevent unexpected GL context switching. ///< Lock to prevent unexpected GL context switching.
std::mutex m_glCtxMutex; std::mutex m_glCtxMutex;
// Singleton
GL_CONTEXT_MANAGER();
GL_CONTEXT_MANAGER( const GL_CONTEXT_MANAGER& );
void operator=( const GL_CONTEXT_MANAGER& );
}; };
#endif /* GL_CONTEXT_MANAGER_H */ #endif /* GL_CONTEXT_MANAGER_H */

View File

@ -112,6 +112,8 @@ public:
BS::thread_pool& GetThreadPool() { return *m_singleton.m_ThreadPool; } BS::thread_pool& GetThreadPool() { return *m_singleton.m_ThreadPool; }
GL_CONTEXT_MANAGER* GetGLContextManager() { return m_singleton.m_GLContextManager; }
/** /**
* Specific to MacOSX (not used under Linux or Windows). * Specific to MacOSX (not used under Linux or Windows).
* *

View File

@ -20,8 +20,9 @@
#ifndef KICAD_SINGLETON_H #ifndef KICAD_SINGLETON_H
#define KICAD_SINGLETON_H #define KICAD_SINGLETON_H
#include <bs_thread_pool.hpp>
#include <advanced_config.h> #include <advanced_config.h>
#include <bs_thread_pool.hpp>
#include <gal/opengl/gl_context_mgr.h>
class KICAD_SINGLETON class KICAD_SINGLETON
{ {
@ -34,6 +35,10 @@ public:
delete m_ThreadPool; delete m_ThreadPool;
m_ThreadPool = nullptr; m_ThreadPool = nullptr;
m_GLContextManager->DeleteAll();
delete m_GLContextManager;
m_GLContextManager = nullptr;
}; };
@ -41,9 +46,12 @@ public:
{ {
int num_threads = std::max( 0, ADVANCED_CFG::GetCfg().m_MaximumThreads ); int num_threads = std::max( 0, ADVANCED_CFG::GetCfg().m_MaximumThreads );
m_ThreadPool = new BS::thread_pool( num_threads ); m_ThreadPool = new BS::thread_pool( num_threads );
m_GLContextManager = new GL_CONTEXT_MANAGER();
} }
BS::thread_pool* m_ThreadPool; BS::thread_pool* m_ThreadPool;
GL_CONTEXT_MANAGER* m_GLContextManager;
}; };

View File

@ -82,6 +82,7 @@ set_source_files_properties( ${CMAKE_SOURCE_DIR}/common/single_top.cpp PROPERTIE
) )
target_link_libraries( pl_editor target_link_libraries( pl_editor
kicommon kicommon
gal
${wxWidgets_LIBRARIES} ${wxWidgets_LIBRARIES}
) )

View File

@ -96,6 +96,7 @@ set_source_files_properties( ${CMAKE_SOURCE_DIR}/common/single_top.cpp PROPERTIE
) )
target_link_libraries( pcb_calculator target_link_libraries( pcb_calculator
kicommon kicommon
gal
${wxWidgets_LIBRARIES} ${wxWidgets_LIBRARIES}
) )

View File

@ -690,6 +690,7 @@ set_source_files_properties( ${CMAKE_SOURCE_DIR}/common/single_top.cpp pcbnew.cp
) )
target_link_libraries( pcbnew target_link_libraries( pcbnew
kicommon kicommon
gal
${wxWidgets_LIBRARIES} ${wxWidgets_LIBRARIES}
) )