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
This commit is contained in:
Roberto Fernandez Bautista 2020-11-03 00:13:31 +00:00 committed by Mark Roszko
parent 2d33b23530
commit 1bbc569151
4 changed files with 58 additions and 15 deletions

View File

@ -48,6 +48,7 @@
#include <settings/settings_manager.h>
#include <tool/tool_dispatcher.h>
#include <confirm.h>
#include <widgets/wx_busy_indicator.h>
@ -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 );
}

View File

@ -25,7 +25,7 @@
#ifndef EDA_3D_CANVAS_H
#define EDA_3D_CANVAS_H
#include <atomic>
#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;

View File

@ -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 );

View File

@ -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 );