From f3f17401dc393e558000616d1b0da229299ec278 Mon Sep 17 00:00:00 2001 From: Qbort <6035515-Qbort@users.noreply.gitlab.com> Date: Fri, 3 Jul 2020 20:57:00 +0100 Subject: [PATCH] Fix OPENGL_GAL initialization sequence - New public static function OPENGL_GAL::CheckFeatures() gets called in EDA_DRAW_PANEL_GAL::SwitchBackend() before switching to OPENGL_GAL - Moved all OpenGL feature checks from OPENGL_GAL constructor to OPENGL_GAL::init() Fixes https://gitlab.com/kicad/code/kicad/-/issues/4714 --- common/draw_panel_gal.cpp | 15 +++---- common/gal/opengl/opengl_gal.cpp | 71 +++++++++++++++++++++++--------- include/gal/opengl/opengl_gal.h | 10 ++++- 3 files changed, 69 insertions(+), 27 deletions(-) diff --git a/common/draw_panel_gal.cpp b/common/draw_panel_gal.cpp index b2533266be..ed866ba6dd 100644 --- a/common/draw_panel_gal.cpp +++ b/common/draw_panel_gal.cpp @@ -372,21 +372,22 @@ bool EDA_DRAW_PANEL_GAL::SwitchBackend( GAL_TYPE aGalType ) switch( aGalType ) { case GAL_TYPE_OPENGL: - try + { + wxString errormsg = KIGFX::OPENGL_GAL::CheckFeatures( m_options ); + + if( errormsg.empty() ) { new_gal = new KIGFX::OPENGL_GAL( m_options, this, this, this ); - break; } - catch( std::runtime_error& err ) + else { aGalType = GAL_TYPE_CAIRO; DisplayInfoMessage( m_parent, - _( "Could not use OpenGL, falling back to software rendering" ), - wxString( err.what() ) ); + _( "Could not use OpenGL, falling back to software rendering" ), errormsg ); + new_gal = new KIGFX::CAIRO_GAL( m_options, this, this, this ); } - - new_gal = new KIGFX::CAIRO_GAL( m_options, this, this, this ); break; + } case GAL_TYPE_CAIRO: new_gal = new KIGFX::CAIRO_GAL( m_options, this, this, this ); diff --git a/common/gal/opengl/opengl_gal.cpp b/common/gal/opengl/opengl_gal.cpp index fe7f30b6ce..c0150ce79f 100644 --- a/common/gal/opengl/opengl_gal.cpp +++ b/common/gal/opengl/opengl_gal.cpp @@ -207,30 +207,15 @@ OPENGL_GAL::OPENGL_GAL( GAL_DISPLAY_OPTIONS& aDisplayOptions, wxWindow* aParent, isContextLocked( false ), lockClientCookie( 0 ) { -// IsDisplayAttr() handles WX_GL_{MAJOR,MINOR}_VERSION correctly only in 3.0.4 -// starting with 3.1.0 one should use wxGLContext::IsOk() (done by GL_CONTEXT_MANAGER) -#if wxCHECK_VERSION( 3, 0, 3 ) and !wxCHECK_VERSION( 3, 1, 0 ) - const int attr[] = { WX_GL_MAJOR_VERSION, 2, WX_GL_MINOR_VERSION, 1, 0 }; - - if( !IsDisplaySupported( attr ) ) - throw std::runtime_error( "OpenGL 2.1 or higher is required!" ); -#endif /* wxCHECK_VERSION( 3, 0, 3 ) */ - if( glMainContext == NULL ) { glMainContext = GL_CONTEXT_MANAGER::Get().CreateCtx( this ); - if( !glMainContext ) - throw std::runtime_error( "Could not create the main OpenGL context" ); - glPrivContext = glMainContext; } else { glPrivContext = GL_CONTEXT_MANAGER::Get().CreateCtx( this, glMainContext ); - - if( !glPrivContext ) - throw std::runtime_error( "Could not create a private OpenGL context" ); } shader = new SHADER(); @@ -281,9 +266,6 @@ OPENGL_GAL::OPENGL_GAL( GAL_DISPLAY_OPTIONS& aDisplayOptions, wxWindow* aParent, tesselator = gluNewTess(); InitTesselatorCallbacks( tesselator ); - if( tesselator == NULL ) - throw std::runtime_error( "Could not create the tesselator" ); - gluTessProperty( tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE ); SetTarget( TARGET_NONCACHED ); @@ -340,6 +322,36 @@ OPENGL_GAL::~OPENGL_GAL() } +wxString OPENGL_GAL::CheckFeatures( GAL_DISPLAY_OPTIONS& aOptions ) +{ + + wxFrame* testFrame = + new wxFrame( NULL, wxID_ANY, wxT( "" ), wxDefaultPosition, wxSize( 1, 1 ) ); + KIGFX::OPENGL_GAL* opengl_gal = new KIGFX::OPENGL_GAL( aOptions, testFrame ); + + testFrame->Raise(); + testFrame->Show(); + + try + { + GAL_CONTEXT_LOCKER lock( opengl_gal ); + opengl_gal->init(); + } + catch( std::runtime_error& err ) + { + //Test failed + delete opengl_gal; + delete testFrame; + return wxString( err.what() ); + } + + //Test passed + delete opengl_gal; + delete testFrame; + return wxEmptyString; +} + + bool OPENGL_GAL::updatedGalDisplayOptions( const GAL_DISPLAY_OPTIONS& aOptions ) { bool refresh = false; @@ -1993,10 +2005,31 @@ unsigned int OPENGL_GAL::getNewGroupNumber() void OPENGL_GAL::init() { + wxASSERT( IsShownOnScreen() ); wxASSERT_MSG( isContextLocked, "This should only be called from within a locked context." ); +// IsDisplayAttr() handles WX_GL_{MAJOR,MINOR}_VERSION correctly only in 3.0.4 +// starting with 3.1.0 one should use wxGLContext::IsOk() (done by GL_CONTEXT_MANAGER) +#if wxCHECK_VERSION( 3, 0, 3 ) and !wxCHECK_VERSION( 3, 1, 0 ) + const int attr[] = { WX_GL_MAJOR_VERSION, 2, WX_GL_MINOR_VERSION, 1, 0 }; + + if( !IsDisplaySupported( attr ) ) + throw std::runtime_error( "OpenGL 2.1 or higher is required!" ); +#endif /* wxCHECK_VERSION( 3, 0, 3 ) */ + + // Check correct initialization from the constructor + if( !glMainContext ) + throw std::runtime_error( "Could not create the main OpenGL context" ); + + if( !glPrivContext ) + throw std::runtime_error( "Could not create a private OpenGL context" ); + + if( tesselator == NULL ) + throw std::runtime_error( "Could not create the tesselator" ); + // End initialzation checks + GLenum err = glewInit(); if( GLEW_OK != err ) @@ -2035,7 +2068,7 @@ void OPENGL_GAL::init() int maxTextureSize; glGetIntegerv( GL_MAX_TEXTURE_SIZE, &maxTextureSize ); - if( maxTextureSize < (int) font_image.width || maxTextureSize < (int)font_image.height ) + if( maxTextureSize < (int) font_image.width || maxTextureSize < (int) font_image.height ) { // TODO implement software texture scaling // for bitmap fonts and use a higher resolution texture? diff --git a/include/gal/opengl/opengl_gal.h b/include/gal/opengl/opengl_gal.h index ad367289fa..22521f08bb 100644 --- a/include/gal/opengl/opengl_gal.h +++ b/include/gal/opengl/opengl_gal.h @@ -86,6 +86,13 @@ public: virtual ~OPENGL_GAL(); + /** + * @brief Checks OpenGL features + * @param aOptions + * @return wxEmptyString if OpenGL 2.1 or greater is available, otherwise returns error message + */ + static wxString CheckFeatures( GAL_DISPLAY_OPTIONS& aOptions ); + virtual bool IsOpenGlEngine() override { return true; } /// @copydoc GAL::IsInitialized() @@ -479,7 +486,8 @@ private: VECTOR2D getScreenPixelSize() const; /** - * @brief Basic OpenGL initialization. + * @brief Basic OpenGL initialization and feature checks + * @throw std::runtime_error if any of the OpenGL feature checks failed */ void init(); };