From 1bbc5691510445c56dd73b65d1d5717697d09554 Mon Sep 17 00:00:00 2001 From: Roberto Fernandez Bautista Date: Tue, 3 Nov 2020 00:13:31 +0000 Subject: [PATCH] Fix DoRePaint routine in EDA_3D_CANVAS - Check that we aren't already painting (return if we are) - Check that GLEW functions exist before calling them in 3D canvas and throw exception if they are no longer available - Catch above exceptions in paint routine and show an infobar message to the user Fixes https://gitlab.com/kicad/code/kicad/-/issues/6246 --- 3d-viewer/3d_canvas/eda_3d_canvas.cpp | 46 +++++++++++++++---- 3d-viewer/3d_canvas/eda_3d_canvas.h | 3 +- .../3d_render_ogl_legacy/c_ogl_3dmodel.cpp | 21 +++++++-- 3d-viewer/common_ogl/ogl_utils.cpp | 3 ++ 4 files changed, 58 insertions(+), 15 deletions(-) diff --git a/3d-viewer/3d_canvas/eda_3d_canvas.cpp b/3d-viewer/3d_canvas/eda_3d_canvas.cpp index 2ff26516ff..263799e739 100644 --- a/3d-viewer/3d_canvas/eda_3d_canvas.cpp +++ b/3d-viewer/3d_canvas/eda_3d_canvas.cpp @@ -48,6 +48,7 @@ #include #include +#include #include @@ -134,6 +135,8 @@ EDA_3D_CANVAS::EDA_3D_CANVAS( wxWindow* aParent, const int* aAttribList, BOARD* NULL, this ); + m_is_currently_painting.clear(); + m_3d_render_raytracing = new C3D_RENDER_RAYTRACING( m_boardAdapter, m_camera ); m_3d_render_ogl_legacy = new C3D_RENDER_OGL_LEGACY( m_boardAdapter, m_camera ); @@ -361,10 +364,15 @@ void EDA_3D_CANVAS::OnPaint( wxPaintEvent& aEvent ) void EDA_3D_CANVAS::DoRePaint() { + if( m_is_currently_painting.test_and_set() ) + return; + + // SwapBuffer requires the window to be shown before calling if( !IsShownOnScreen() ) { wxLogTrace( m_logTrace, "EDA_3D_CANVAS::DoRePaint !IsShown" ); + m_is_currently_painting.clear(); return; } @@ -414,6 +422,7 @@ void EDA_3D_CANVAS::DoRePaint() if( !initializeOpenGL() ) { GL_CONTEXT_MANAGER::Get().UnlockCtx( m_glRC ); + m_is_currently_painting.clear(); return; } @@ -435,6 +444,7 @@ void EDA_3D_CANVAS::DoRePaint() SwapBuffers(); GL_CONTEXT_MANAGER::Get().UnlockCtx( m_glRC ); + m_is_currently_painting.clear(); return; } @@ -493,19 +503,32 @@ void EDA_3D_CANVAS::DoRePaint() if( m_3d_render ) { - m_3d_render->SetCurWindowSize( clientSize ); + try + { + m_3d_render->SetCurWindowSize( clientSize ); - bool reloadRaytracingForIntersectionCalculations = false; + bool reloadRaytracingForIntersectionCalculations = false; - if( ( m_boardAdapter.RenderEngineGet() == RENDER_ENGINE::OPENGL_LEGACY ) && - m_3d_render_ogl_legacy->IsReloadRequestPending() ) - reloadRaytracingForIntersectionCalculations = true; + if( ( m_boardAdapter.RenderEngineGet() == RENDER_ENGINE::OPENGL_LEGACY ) + && m_3d_render_ogl_legacy->IsReloadRequestPending() ) + reloadRaytracingForIntersectionCalculations = true; - requested_redraw = m_3d_render->Redraw( m_mouse_was_moved || m_camera_is_moving, - &activityReporter, &warningReporter ); + requested_redraw = m_3d_render->Redraw( + m_mouse_was_moved || m_camera_is_moving, &activityReporter, &warningReporter ); - if( reloadRaytracingForIntersectionCalculations ) - m_3d_render_raytracing->Reload( nullptr, nullptr, true ); + if( reloadRaytracingForIntersectionCalculations ) + m_3d_render_raytracing->Reload( nullptr, nullptr, true ); + } + catch( std::runtime_error& err ) + { + DisplayInfoMessage( m_parent, _( "Unable to use OpenGL" ), wxString( err.what() ) ); + m_is_opengl_version_supported = false; + m_opengl_supports_raytracing = false; + m_is_opengl_initialized = false; + GL_CONTEXT_MANAGER::Get().UnlockCtx( m_glRC ); + m_is_currently_painting.clear(); + return; + } } if( m_render_pivot ) @@ -546,6 +569,8 @@ void EDA_3D_CANVAS::DoRePaint() m_mouse_was_moved = false; Request_refresh( false ); } + + m_is_currently_painting.clear(); } @@ -872,7 +897,8 @@ void EDA_3D_CANVAS::stop_editingTimeOut_Timer() void EDA_3D_CANVAS::restart_editingTimeOut_Timer() { - m_editing_timeout_timer.Start( m_3d_render->GetWaitForEditingTimeOut() , wxTIMER_ONE_SHOT ); + if( m_3d_render ) + m_editing_timeout_timer.Start( m_3d_render->GetWaitForEditingTimeOut(), wxTIMER_ONE_SHOT ); } diff --git a/3d-viewer/3d_canvas/eda_3d_canvas.h b/3d-viewer/3d_canvas/eda_3d_canvas.h index ad9cc191cc..0bba75e7bf 100644 --- a/3d-viewer/3d_canvas/eda_3d_canvas.h +++ b/3d-viewer/3d_canvas/eda_3d_canvas.h @@ -25,7 +25,7 @@ #ifndef EDA_3D_CANVAS_H #define EDA_3D_CANVAS_H - +#include #include "board_adapter.h" #include "3d_rendering/3d_render_raytracing/accelerators/caccelerator.h" #include "3d_rendering/c3d_render_base.h" @@ -249,6 +249,7 @@ private: wxTimer m_editing_timeout_timer; // Expires after some time signalling that // the mouse / keyboard movements are over wxTimer m_redraw_trigger_timer; // Used to schedule a redraw event + std::atomic_flag m_is_currently_painting; // Avoid drawing twice at the same time bool m_mouse_is_moving; // Mouse activity is in progress bool m_mouse_was_moved; diff --git a/3d-viewer/3d_rendering/3d_render_ogl_legacy/c_ogl_3dmodel.cpp b/3d-viewer/3d_rendering/3d_render_ogl_legacy/c_ogl_3dmodel.cpp index 58fb2ce603..ca3a0a1261 100644 --- a/3d-viewer/3d_rendering/3d_render_ogl_legacy/c_ogl_3dmodel.cpp +++ b/3d-viewer/3d_rendering/3d_render_ogl_legacy/c_ogl_3dmodel.cpp @@ -400,6 +400,10 @@ void C_OGL_3DMODEL::Draw(bool aTransparent, float aOpacity, bool aUseSelectedMat if( aOpacity <= FLT_EPSILON ) return; + + if( !glBindBuffer ) + throw std::runtime_error( "The OpenGL context no longer exists: unable to draw" ); + glBindBuffer( GL_ARRAY_BUFFER, m_vertex_buffer ); glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_index_buffer ); @@ -457,15 +461,21 @@ void C_OGL_3DMODEL::Draw(bool aTransparent, float aOpacity, bool aUseSelectedMat C_OGL_3DMODEL::~C_OGL_3DMODEL() { - glDeleteBuffers( 1, &m_vertex_buffer ); - glDeleteBuffers( 1, &m_index_buffer ); - glDeleteBuffers( 1, &m_bbox_vertex_buffer ); - glDeleteBuffers( 1, &m_bbox_index_buffer ); + if( glDeleteBuffers ) + { + glDeleteBuffers( 1, &m_vertex_buffer ); + glDeleteBuffers( 1, &m_index_buffer ); + glDeleteBuffers( 1, &m_bbox_vertex_buffer ); + glDeleteBuffers( 1, &m_bbox_index_buffer ); + } } void C_OGL_3DMODEL::Draw_bbox() const { + if( !glBindBuffer ) + throw std::runtime_error( "The OpenGL context no longer exists: unable to draw bbox" ); + glBindBuffer( GL_ARRAY_BUFFER, m_bbox_vertex_buffer ); glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_bbox_index_buffer ); @@ -482,6 +492,9 @@ void C_OGL_3DMODEL::Draw_bbox() const void C_OGL_3DMODEL::Draw_bboxes() const { + if( !glBindBuffer ) + throw std::runtime_error( "The OpenGL context no longer exists: unable to draw bboxes" ); + glBindBuffer( GL_ARRAY_BUFFER, m_bbox_vertex_buffer ); glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_bbox_index_buffer ); diff --git a/3d-viewer/common_ogl/ogl_utils.cpp b/3d-viewer/common_ogl/ogl_utils.cpp index 7d343314b4..65e57792c6 100644 --- a/3d-viewer/common_ogl/ogl_utils.cpp +++ b/3d-viewer/common_ogl/ogl_utils.cpp @@ -212,6 +212,9 @@ void OGL_DrawBackground( const SFVEC3F &aTopColor, const SFVEC3F &aBotColor ) void OGL_ResetTextureStateDefaults() { + if( !glActiveTexture || !glClientActiveTexture ) + throw std::runtime_error( "The OpenGL context no longer exists: unable to Reset Textures" ); + glActiveTexture( GL_TEXTURE0 ); glBindTexture( GL_TEXTURE_2D, 0 ); glClientActiveTexture( GL_TEXTURE0 );