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
This commit is contained in:
Qbort 2020-07-03 20:57:00 +01:00 committed by Ian McInerney
parent 3bf7cf2b54
commit f3f17401dc
3 changed files with 69 additions and 27 deletions

View File

@ -372,21 +372,22 @@ bool EDA_DRAW_PANEL_GAL::SwitchBackend( GAL_TYPE aGalType )
switch( aGalType ) switch( aGalType )
{ {
case GAL_TYPE_OPENGL: 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 ); new_gal = new KIGFX::OPENGL_GAL( m_options, this, this, this );
break;
} }
catch( std::runtime_error& err ) else
{ {
aGalType = GAL_TYPE_CAIRO; aGalType = GAL_TYPE_CAIRO;
DisplayInfoMessage( m_parent, DisplayInfoMessage( m_parent,
_( "Could not use OpenGL, falling back to software rendering" ), _( "Could not use OpenGL, falling back to software rendering" ), errormsg );
wxString( err.what() ) ); new_gal = new KIGFX::CAIRO_GAL( m_options, this, this, this );
} }
new_gal = new KIGFX::CAIRO_GAL( m_options, this, this, this );
break; break;
}
case GAL_TYPE_CAIRO: case GAL_TYPE_CAIRO:
new_gal = new KIGFX::CAIRO_GAL( m_options, this, this, this ); new_gal = new KIGFX::CAIRO_GAL( m_options, this, this, this );

View File

@ -207,30 +207,15 @@ OPENGL_GAL::OPENGL_GAL( GAL_DISPLAY_OPTIONS& aDisplayOptions, wxWindow* aParent,
isContextLocked( false ), isContextLocked( false ),
lockClientCookie( 0 ) 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 ) if( glMainContext == NULL )
{ {
glMainContext = GL_CONTEXT_MANAGER::Get().CreateCtx( this ); glMainContext = GL_CONTEXT_MANAGER::Get().CreateCtx( this );
if( !glMainContext )
throw std::runtime_error( "Could not create the main OpenGL context" );
glPrivContext = glMainContext; glPrivContext = glMainContext;
} }
else else
{ {
glPrivContext = GL_CONTEXT_MANAGER::Get().CreateCtx( this, glMainContext ); glPrivContext = GL_CONTEXT_MANAGER::Get().CreateCtx( this, glMainContext );
if( !glPrivContext )
throw std::runtime_error( "Could not create a private OpenGL context" );
} }
shader = new SHADER(); shader = new SHADER();
@ -281,9 +266,6 @@ OPENGL_GAL::OPENGL_GAL( GAL_DISPLAY_OPTIONS& aDisplayOptions, wxWindow* aParent,
tesselator = gluNewTess(); tesselator = gluNewTess();
InitTesselatorCallbacks( tesselator ); InitTesselatorCallbacks( tesselator );
if( tesselator == NULL )
throw std::runtime_error( "Could not create the tesselator" );
gluTessProperty( tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE ); gluTessProperty( tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE );
SetTarget( TARGET_NONCACHED ); 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 OPENGL_GAL::updatedGalDisplayOptions( const GAL_DISPLAY_OPTIONS& aOptions )
{ {
bool refresh = false; bool refresh = false;
@ -1993,10 +2005,31 @@ unsigned int OPENGL_GAL::getNewGroupNumber()
void OPENGL_GAL::init() void OPENGL_GAL::init()
{ {
wxASSERT( IsShownOnScreen() ); wxASSERT( IsShownOnScreen() );
wxASSERT_MSG( isContextLocked, "This should only be called from within a locked context." ); 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(); GLenum err = glewInit();
if( GLEW_OK != err ) if( GLEW_OK != err )
@ -2035,7 +2068,7 @@ void OPENGL_GAL::init()
int maxTextureSize; int maxTextureSize;
glGetIntegerv( GL_MAX_TEXTURE_SIZE, &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 // TODO implement software texture scaling
// for bitmap fonts and use a higher resolution texture? // for bitmap fonts and use a higher resolution texture?

View File

@ -86,6 +86,13 @@ public:
virtual ~OPENGL_GAL(); 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; } virtual bool IsOpenGlEngine() override { return true; }
/// @copydoc GAL::IsInitialized() /// @copydoc GAL::IsInitialized()
@ -479,7 +486,8 @@ private:
VECTOR2D getScreenPixelSize() const; 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(); void init();
}; };