From 5326c36a5ff8a3a465d386cc31172aa90847a9e9 Mon Sep 17 00:00:00 2001 From: Seth Hillbrand <seth@kipro-pcb.com> Date: Fri, 3 Jan 2025 17:24:24 -0800 Subject: [PATCH] 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. --- 3d-viewer/3d_canvas/eda_3d_canvas.cpp | 18 ++++++++-------- .../3d_model_viewer/eda_3d_model_viewer.cpp | 12 +++++------ .../3d_rendering/opengl/render_3d_opengl.cpp | 15 +++++++------ common/gal/opengl/gl_context_mgr.cpp | 8 ------- common/gal/opengl/opengl_gal.cpp | 21 ++++++++++--------- eeschema/CMakeLists.txt | 3 +++ gerbview/CMakeLists.txt | 1 + include/gal/opengl/gl_context_mgr.h | 11 ++-------- include/pgm_base.h | 2 ++ include/singleton.h | 10 ++++++++- pagelayout_editor/CMakeLists.txt | 1 + pcb_calculator/CMakeLists.txt | 1 + pcbnew/CMakeLists.txt | 1 + 13 files changed, 55 insertions(+), 49 deletions(-) diff --git a/3d-viewer/3d_canvas/eda_3d_canvas.cpp b/3d-viewer/3d_canvas/eda_3d_canvas.cpp index 0214ac0999..5cdb68bec4 100644 --- a/3d-viewer/3d_canvas/eda_3d_canvas.cpp +++ b/3d-viewer/3d_canvas/eda_3d_canvas.cpp @@ -187,7 +187,7 @@ void EDA_3D_CANVAS::releaseOpenGL() { if( m_glRC ) { - GL_CONTEXT_MANAGER::Get().LockCtx( m_glRC, this ); + Pgm().GetGLContextManager()->LockCtx( m_glRC, this ); delete m_3d_render_raytracing; 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. m_3d_render = nullptr; - GL_CONTEXT_MANAGER::Get().UnlockCtx( m_glRC ); - GL_CONTEXT_MANAGER::Get().DestroyCtx( m_glRC ); + Pgm().GetGLContextManager()->UnlockCtx( m_glRC ); + Pgm().GetGLContextManager()->DestroyCtx( m_glRC ); m_glRC = nullptr; } } @@ -390,7 +390,7 @@ void EDA_3D_CANVAS::DoRePaint() // Explicitly create a new rendering context instance for this canvas. 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 if( m_glRC == nullptr ) @@ -401,7 +401,7 @@ void EDA_3D_CANVAS::DoRePaint() 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. // This is done here rather than in a wxSizeEvent handler because our @@ -418,7 +418,7 @@ void EDA_3D_CANVAS::DoRePaint() { if( !initializeOpenGL() ) { - GL_CONTEXT_MANAGER::Get().UnlockCtx( m_glRC ); + Pgm().GetGLContextManager()->UnlockCtx( m_glRC ); m_is_currently_painting.clear(); return; @@ -440,7 +440,7 @@ void EDA_3D_CANVAS::DoRePaint() SwapBuffers(); - GL_CONTEXT_MANAGER::Get().UnlockCtx( m_glRC ); + Pgm().GetGLContextManager()->UnlockCtx( m_glRC ); m_is_currently_painting.clear(); return; @@ -528,7 +528,7 @@ void EDA_3D_CANVAS::DoRePaint() m_is_opengl_version_supported = false; m_opengl_supports_raytracing = false; m_is_opengl_initialized = false; - GL_CONTEXT_MANAGER::Get().UnlockCtx( m_glRC ); + Pgm().GetGLContextManager()->UnlockCtx( m_glRC ); m_is_currently_painting.clear(); return; } @@ -553,7 +553,7 @@ void EDA_3D_CANVAS::DoRePaint() // commands is displayed on the window." SwapBuffers(); - GL_CONTEXT_MANAGER::Get().UnlockCtx( m_glRC ); + Pgm().GetGLContextManager()->UnlockCtx( m_glRC ); if( m_mouse_was_moved || m_camera_is_moving ) { diff --git a/3d-viewer/3d_model_viewer/eda_3d_model_viewer.cpp b/3d-viewer/3d_model_viewer/eda_3d_model_viewer.cpp index 632449ad5c..584ee6a3fd 100644 --- a/3d-viewer/3d_model_viewer/eda_3d_model_viewer.cpp +++ b/3d-viewer/3d_model_viewer/eda_3d_model_viewer.cpp @@ -112,13 +112,13 @@ EDA_3D_MODEL_VIEWER::~EDA_3D_MODEL_VIEWER() if( m_glRC ) { - GL_CONTEXT_MANAGER::Get().LockCtx( m_glRC, this ); + Pgm().GetGLContextManager()->LockCtx( m_glRC, this ); delete m_ogl_3dmodel; m_ogl_3dmodel = nullptr; - GL_CONTEXT_MANAGER::Get().UnlockCtx( m_glRC ); - GL_CONTEXT_MANAGER::Get().DestroyCtx( m_glRC ); + Pgm().GetGLContextManager()->UnlockCtx( 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. // This function may only be called when the window is shown on screen" 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 if( m_glRC == nullptr ) @@ -265,7 +265,7 @@ void EDA_3D_MODEL_VIEWER::OnPaint( wxPaintEvent& event ) 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. // 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." SwapBuffers(); - GL_CONTEXT_MANAGER::Get().UnlockCtx( m_glRC ); + Pgm().GetGLContextManager()->UnlockCtx( m_glRC ); } diff --git a/3d-viewer/3d_rendering/opengl/render_3d_opengl.cpp b/3d-viewer/3d_rendering/opengl/render_3d_opengl.cpp index d776a6e93d..c7656b08aa 100644 --- a/3d-viewer/3d_rendering/opengl/render_3d_opengl.cpp +++ b/3d-viewer/3d_rendering/opengl/render_3d_opengl.cpp @@ -26,22 +26,25 @@ #include <cstdint> #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 "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 <footprint.h> #include <gal/opengl/gl_context_mgr.h> -#include <3d_math.h> #include <glm/geometric.hpp> #include <lset.h> +#include <pgm_base.h> #include <math/util.h> // for KiROUND #include <utility> #include <vector> #include <wx/log.h> -#include <base_units.h> /** * Scale conversion from 3d model units to pcb units @@ -490,7 +493,7 @@ bool RENDER_3D_OPENGL::Redraw( bool aIsMoving, REPORTER* aStatusReporter, // Careful here! // We are in the middle of rendering and the reload method may show // 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 ); } ); diff --git a/common/gal/opengl/gl_context_mgr.cpp b/common/gal/opengl/gl_context_mgr.cpp index 2a4d22d964..c4fb3d9a00 100644 --- a/common/gal/opengl/gl_context_mgr.cpp +++ b/common/gal/opengl/gl_context_mgr.cpp @@ -27,14 +27,6 @@ #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* context = new wxGLContext( aCanvas, aOther ); diff --git a/common/gal/opengl/opengl_gal.cpp b/common/gal/opengl/opengl_gal.cpp index ab6bfbea03..4fdcae364f 100644 --- a/common/gal/opengl/opengl_gal.cpp +++ b/common/gal/opengl/opengl_gal.cpp @@ -43,6 +43,7 @@ #include <bitmap_base.h> #include <bezier_curves.h> #include <math/util.h> // for KiROUND +#include <pgm_base.h> #include <trace_helpers.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 ) { - m_glMainContext = GL_CONTEXT_MANAGER::Get().CreateCtx( this ); + m_glMainContext = Pgm().GetGLContextManager()->CreateCtx( this ); if( !m_glMainContext ) 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 { - m_glPrivContext = GL_CONTEXT_MANAGER::Get().CreateCtx( this, m_glMainContext ); + m_glPrivContext = Pgm().GetGLContextManager()->CreateCtx( this, m_glMainContext ); if( !m_glPrivContext ) 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() { - GL_CONTEXT_MANAGER::Get().LockCtx( m_glPrivContext, this ); + Pgm().GetGLContextManager()->LockCtx( m_glPrivContext, this ); --m_instanceCounter; glFlush(); @@ -437,19 +438,19 @@ OPENGL_GAL::~OPENGL_GAL() 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 // when the last OpenGL GAL instance is destroyed (a few lines below) if( m_glPrivContext != m_glMainContext ) - GL_CONTEXT_MANAGER::Get().DestroyCtx( m_glPrivContext ); + Pgm().GetGLContextManager()->DestroyCtx( m_glPrivContext ); delete m_shader; // Are we destroying the last GAL instance? if( m_instanceCounter == 0 ) { - GL_CONTEXT_MANAGER::Get().LockCtx( m_glMainContext, this ); + Pgm().GetGLContextManager()->LockCtx( m_glMainContext, this ); if( m_isBitmapFontLoaded ) { @@ -457,8 +458,8 @@ OPENGL_GAL::~OPENGL_GAL() m_isBitmapFontLoaded = false; } - GL_CONTEXT_MANAGER::Get().UnlockCtx( m_glMainContext ); - GL_CONTEXT_MANAGER::Get().DestroyCtx( m_glMainContext ); + Pgm().GetGLContextManager()->UnlockCtx( m_glMainContext ); + Pgm().GetGLContextManager()->DestroyCtx( m_glMainContext ); m_glMainContext = nullptr; } } @@ -776,7 +777,7 @@ void OPENGL_GAL::LockContext( int aClientCookie ) m_isContextLocked = true; 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; - GL_CONTEXT_MANAGER::Get().UnlockCtx( m_glPrivContext ); + Pgm().GetGLContextManager()->UnlockCtx( m_glPrivContext ); } diff --git a/eeschema/CMakeLists.txt b/eeschema/CMakeLists.txt index d58fe5ba5e..d291ce6d56 100644 --- a/eeschema/CMakeLists.txt +++ b/eeschema/CMakeLists.txt @@ -33,6 +33,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/common ${CMAKE_SOURCE_DIR}/common/dialogs ${CMAKE_SOURCE_DIR}/libs/sexpr/include + ${INC_AFTER} ./dialogs ./libview @@ -565,6 +566,7 @@ set_source_files_properties( ${CMAKE_SOURCE_DIR}/common/single_top.cpp PROPERTIE target_link_libraries( eeschema kicommon + gal ${wxWidgets_LIBRARIES} ) @@ -603,6 +605,7 @@ add_library( eeschema_kiface MODULE target_link_libraries( eeschema_kiface PRIVATE common + gal eeschema_kiface_objects markdown_lib scripting diff --git a/gerbview/CMakeLists.txt b/gerbview/CMakeLists.txt index 0f24c8ceb2..7c28da3808 100644 --- a/gerbview/CMakeLists.txt +++ b/gerbview/CMakeLists.txt @@ -112,6 +112,7 @@ set_source_files_properties( ${CMAKE_SOURCE_DIR}/common/single_top.cpp PROPERTIE target_link_libraries( gerbview core kicommon + gal nlohmann_json ${wxWidgets_LIBRARIES} ) diff --git a/include/gal/opengl/gl_context_mgr.h b/include/gal/opengl/gl_context_mgr.h index ebf3d358c6..5440c7df13 100644 --- a/include/gal/opengl/gl_context_mgr.h +++ b/include/gal/opengl/gl_context_mgr.h @@ -35,10 +35,8 @@ class GAL_API GL_CONTEXT_MANAGER { public: - /** - * Return the GL_CONTEXT_MANAGER instance (singleton). - */ - static GL_CONTEXT_MANAGER& Get(); + + GL_CONTEXT_MANAGER(); /** * Create a managed OpenGL context. @@ -142,11 +140,6 @@ private: ///< Lock to prevent unexpected GL context switching. 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 */ diff --git a/include/pgm_base.h b/include/pgm_base.h index e43906fca9..2952ce5f90 100644 --- a/include/pgm_base.h +++ b/include/pgm_base.h @@ -112,6 +112,8 @@ public: 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). * diff --git a/include/singleton.h b/include/singleton.h index 27b9dd74ca..f24c1454e3 100644 --- a/include/singleton.h +++ b/include/singleton.h @@ -20,8 +20,9 @@ #ifndef KICAD_SINGLETON_H #define KICAD_SINGLETON_H -#include <bs_thread_pool.hpp> #include <advanced_config.h> +#include <bs_thread_pool.hpp> +#include <gal/opengl/gl_context_mgr.h> class KICAD_SINGLETON { @@ -34,6 +35,10 @@ public: delete m_ThreadPool; 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 ); m_ThreadPool = new BS::thread_pool( num_threads ); + m_GLContextManager = new GL_CONTEXT_MANAGER(); } BS::thread_pool* m_ThreadPool; + GL_CONTEXT_MANAGER* m_GLContextManager; + }; diff --git a/pagelayout_editor/CMakeLists.txt b/pagelayout_editor/CMakeLists.txt index f287e5368a..dcbe151d65 100644 --- a/pagelayout_editor/CMakeLists.txt +++ b/pagelayout_editor/CMakeLists.txt @@ -82,6 +82,7 @@ set_source_files_properties( ${CMAKE_SOURCE_DIR}/common/single_top.cpp PROPERTIE ) target_link_libraries( pl_editor kicommon + gal ${wxWidgets_LIBRARIES} ) diff --git a/pcb_calculator/CMakeLists.txt b/pcb_calculator/CMakeLists.txt index 8fcf58e46c..e2e1b75390 100644 --- a/pcb_calculator/CMakeLists.txt +++ b/pcb_calculator/CMakeLists.txt @@ -96,6 +96,7 @@ set_source_files_properties( ${CMAKE_SOURCE_DIR}/common/single_top.cpp PROPERTIE ) target_link_libraries( pcb_calculator kicommon + gal ${wxWidgets_LIBRARIES} ) diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index 7630594371..a104d3646b 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -690,6 +690,7 @@ set_source_files_properties( ${CMAKE_SOURCE_DIR}/common/single_top.cpp pcbnew.cp ) target_link_libraries( pcbnew kicommon + gal ${wxWidgets_LIBRARIES} )