From b1ace1607b95fb1a601616b098e195c2923323d2 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Sun, 15 Feb 2015 02:18:35 +0100 Subject: [PATCH] Reworked GAL switching. Now OpenGL can report its problems instead of shutting down the application. --- common/draw_panel_gal.cpp | 105 ++++++++++++++---------- common/gal/opengl/opengl_compositor.cpp | 46 +++++------ common/gal/opengl/opengl_gal.cpp | 102 ++++++++--------------- common/gal/opengl/shader.cpp | 36 +++----- include/class_draw_panel_gal.h | 2 +- include/gal/opengl/opengl_gal.h | 2 - pcbnew/pcbframe.cpp | 14 ++-- 7 files changed, 136 insertions(+), 171 deletions(-) diff --git a/common/draw_panel_gal.cpp b/common/draw_panel_gal.cpp index f0be4b0316..1458fdfe43 100644 --- a/common/draw_panel_gal.cpp +++ b/common/draw_panel_gal.cpp @@ -1,8 +1,9 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2013-2014 CERN + * Copyright (C) 2013-2015 CERN * @author Tomasz Wlostowski + * @author Maciej Suminski * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -28,6 +29,7 @@ #include #include #include +#include #include #include @@ -116,30 +118,30 @@ void EDA_DRAW_PANEL_GAL::onPaint( wxPaintEvent& WXUNUSED( aEvent ) ) m_pendingRefresh = false; m_lastRefresh = wxGetLocalTimeMillis(); - if( !m_drawing ) + if( m_drawing ) + return; + + m_drawing = true; + + m_view->UpdateItems(); + m_gal->BeginDrawing(); + m_gal->ClearScreen( m_painter->GetSettings()->GetBackgroundColor() ); + + if( m_view->IsDirty() ) { - m_drawing = true; + m_view->ClearTargets(); - m_view->UpdateItems(); - m_gal->BeginDrawing(); - m_gal->ClearScreen( m_painter->GetSettings()->GetBackgroundColor() ); - - if( m_view->IsDirty() ) - { - m_view->ClearTargets(); - - // Grid has to be redrawn only when the NONCACHED target is redrawn - if( m_view->IsTargetDirty( KIGFX::TARGET_NONCACHED ) ) + // Grid has to be redrawn only when the NONCACHED target is redrawn + if( m_view->IsTargetDirty( KIGFX::TARGET_NONCACHED ) ) m_gal->DrawGrid(); - m_view->Redraw(); - } - - m_gal->DrawCursor( m_viewControls->GetCursorPosition() ); - m_gal->EndDrawing(); - - m_drawing = false; + m_view->Redraw(); } + + m_gal->DrawCursor( m_viewControls->GetCursorPosition() ); + m_gal->EndDrawing(); + + m_drawing = false; } @@ -233,7 +235,8 @@ void EDA_DRAW_PANEL_GAL::SetEventDispatcher( TOOL_DISPATCHER* aEventDispatcher ) void EDA_DRAW_PANEL_GAL::StartDrawing() { - m_pendingRefresh = false; + m_drawing = false; + m_pendingRefresh = true; Connect( wxEVT_PAINT, wxPaintEventHandler( EDA_DRAW_PANEL_GAL::onPaint ), NULL, this ); wxPaintEvent redrawEvent; @@ -243,7 +246,8 @@ void EDA_DRAW_PANEL_GAL::StartDrawing() void EDA_DRAW_PANEL_GAL::StopDrawing() { - m_pendingRefresh = true; + m_pendingRefresh = false; + m_drawing = true; m_refreshTimer.Stop(); Disconnect( wxEVT_PAINT, wxPaintEventHandler( EDA_DRAW_PANEL_GAL::onPaint ), NULL, this ); } @@ -271,41 +275,54 @@ void EDA_DRAW_PANEL_GAL::SetTopLayer( LAYER_ID aLayer ) } -void EDA_DRAW_PANEL_GAL::SwitchBackend( GalType aGalType ) +bool EDA_DRAW_PANEL_GAL::SwitchBackend( GalType aGalType ) { // Do not do anything if the currently used GAL is correct if( aGalType == m_backend && m_gal != NULL ) - return; + return true; // Prevent refreshing canvas during backend switch StopDrawing(); - delete m_gal; + KIGFX::GAL* new_gal = NULL; - switch( aGalType ) + try { - case GAL_TYPE_OPENGL: - m_gal = new KIGFX::OPENGL_GAL( this, this, this ); - break; + switch( aGalType ) + { + case GAL_TYPE_OPENGL: + new_gal = new KIGFX::OPENGL_GAL( this, this, this ); + break; - case GAL_TYPE_CAIRO: - m_gal = new KIGFX::CAIRO_GAL( this, this, this ); - break; + case GAL_TYPE_CAIRO: + new_gal = new KIGFX::CAIRO_GAL( this, this, this ); + break; - case GAL_TYPE_NONE: - return; + case GAL_TYPE_NONE: + return false; + } + + delete m_gal; + m_gal = new_gal; + + wxSize size = GetClientSize(); + m_gal->ResizeScreen( size.GetX(), size.GetY() ); + + if( m_painter ) + m_painter->SetGAL( m_gal ); + + if( m_view ) + m_view->SetGAL( m_gal ); + + m_backend = aGalType; + } + catch (std::runtime_error& err) + { + DisplayError( m_parent, wxString( err.what() ) ); + return false; } - wxSize size = GetClientSize(); - m_gal->ResizeScreen( size.GetX(), size.GetY() ); - - if( m_painter ) - m_painter->SetGAL( m_gal ); - - if( m_view ) - m_view->SetGAL( m_gal ); - - m_backend = aGalType; + return true; } diff --git a/common/gal/opengl/opengl_compositor.cpp b/common/gal/opengl/opengl_compositor.cpp index 26b136bbbc..bf80b563aa 100644 --- a/common/gal/opengl/opengl_compositor.cpp +++ b/common/gal/opengl/opengl_compositor.cpp @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2015 CERN * @author Maciej Suminski * * This program is free software; you can redistribute it and/or @@ -24,13 +24,14 @@ /** * @file opengl_compositor.cpp - * @brief Class that handles multitarget rendering (ie. to different textures/surfaces) and + * @brief Class that handles multitarget rendering (i.e. to different textures/surfaces) and * later compositing into a single image (OpenGL flavour). */ #include -#include -#include + +#include +#include using namespace KIGFX; @@ -89,7 +90,7 @@ void OPENGL_COMPOSITOR::Resize( unsigned int aWidth, unsigned int aHeight ) unsigned int OPENGL_COMPOSITOR::CreateBuffer() { - wxASSERT( m_initialized ); + assert( m_initialized ); unsigned int maxBuffers; @@ -98,10 +99,9 @@ unsigned int OPENGL_COMPOSITOR::CreateBuffer() if( usedBuffers() >= maxBuffers ) { - DisplayError( NULL, wxT( "Cannot create more framebuffers. OpenGL rendering " + throw std::runtime_error("Cannot create more framebuffers. OpenGL rendering " "backend requires at least 3 framebuffers. You may try to update/change " - "your graphic drivers." ) ); - return 0; // Unfortunately we have no more free buffers left + "your graphic drivers."); } // GL_COLOR_ATTACHMENTn are consecutive integers @@ -133,38 +133,38 @@ unsigned int OPENGL_COMPOSITOR::CreateBuffer() switch( status ) { case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: - DisplayError( NULL,wxT( "Cannot create the framebuffer." ) ); + throw std::runtime_error( "Cannot create the framebuffer." ); break; case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: - DisplayError( NULL, wxT( "The framebuffer attachment points are incomplete." ) ); + throw std::runtime_error( "The framebuffer attachment points are incomplete." ); break; case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: - DisplayError( NULL, wxT( "The framebuffer does not have at least " - "one image attached to it." ) ); + throw std::runtime_error( "The framebuffer does not have at least one " + "image attached to it." ); break; case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: - DisplayError( NULL, wxT( "The framebuffer read buffer is incomplete." ) ); + throw std::runtime_error( "The framebuffer read buffer is incomplete." ); break; case GL_FRAMEBUFFER_UNSUPPORTED_EXT: - DisplayError( NULL, wxT( "The combination of internal formats of the attached images " - "violates an implementation-dependent set of restrictions." ) ); + throw std::runtime_error( "The combination of internal formats of the attached " + "images violates an implementation-dependent set of restrictions." ); break; case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT: - DisplayError( NULL, wxT( "GL_RENDERBUFFER_SAMPLES is not the same " - "for all attached renderbuffers" ) ); + throw std::runtime_error( "GL_RENDERBUFFER_SAMPLES is not the same for " + "all attached renderbuffers" ); break; case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT: - DisplayError( NULL, wxT( "Framebuffer incomplete layer targets errors." ) ); + throw std::runtime_error( "Framebuffer incomplete layer targets errors." ); break; default: - DisplayError( NULL, wxT( "Cannot create the framebuffer." ) ); + throw std::runtime_error( "Cannot create the framebuffer." ); break; } @@ -211,7 +211,7 @@ void OPENGL_COMPOSITOR::SetBuffer( unsigned int aBufferHandle ) void OPENGL_COMPOSITOR::ClearBuffer() { - wxASSERT( m_initialized ); + assert( m_initialized ); glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); @@ -220,8 +220,8 @@ void OPENGL_COMPOSITOR::ClearBuffer() void OPENGL_COMPOSITOR::DrawBuffer( unsigned int aBufferHandle ) { - wxASSERT( m_initialized ); - wxASSERT( aBufferHandle != 0 && aBufferHandle <= usedBuffers() ); + assert( m_initialized ); + assert( aBufferHandle != 0 && aBufferHandle <= usedBuffers() ); // Switch to the main framebuffer and blit the scene glBindFramebufferEXT( GL_FRAMEBUFFER, DIRECT_RENDERING ); @@ -267,7 +267,7 @@ void OPENGL_COMPOSITOR::DrawBuffer( unsigned int aBufferHandle ) void OPENGL_COMPOSITOR::clean() { - wxASSERT( m_initialized ); + assert( m_initialized ); glBindFramebufferEXT( GL_FRAMEBUFFER, DIRECT_RENDERING ); m_currentFbo = DIRECT_RENDERING; diff --git a/common/gal/opengl/opengl_gal.cpp b/common/gal/opengl/opengl_gal.cpp index 404e3a0728..a7901dc515 100644 --- a/common/gal/opengl/opengl_gal.cpp +++ b/common/gal/opengl/opengl_gal.cpp @@ -3,7 +3,7 @@ * * Copyright (C) 2012 Torsten Hueter, torstenhtr gmx.de * Copyright (C) 2012 Kicad Developers, see change_log.txt for contributors. - * Copyright (C) 2013 CERN + * Copyright (C) 2013-2015 CERN * @author Maciej Suminski * * Graphics Abstraction Layer (GAL) for OpenGL @@ -31,7 +31,6 @@ #include #include -#include #ifdef __WXDEBUG__ #include #endif /* __WXDEBUG__ */ @@ -51,6 +50,9 @@ OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener, wxEvtHandler* aPaintListener, const wxString& aName ) : wxGLCanvas( aParent, wxID_ANY, (int*) glAttributes, wxDefaultPosition, wxDefaultSize, wxEXPAND, aName ), + parentWindow( aParent ), + mouseListener( aMouseListener ), + paintListener( aPaintListener ), cachedManager( true ), nonCachedManager( false ), overlayManager( false ) @@ -59,14 +61,29 @@ OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener, if( glContext == NULL ) glContext = new wxGLContext( this ); - parentWindow = aParent; - mouseListener = aMouseListener; - paintListener = aPaintListener; + aParent->Show(); // wxWidgets require the window to be visible to set its GL context + + // Initialize GLEW, FBOs & VBOs + SetCurrent( *glContext ); + initGlew(); + + // Prepare shaders + if( !shader.LoadBuiltinShader( 0, SHADER_TYPE_VERTEX ) ) + throw std::runtime_error( "Cannot compile vertex shader!" ); + + if( !shader.LoadBuiltinShader( 1, SHADER_TYPE_FRAGMENT ) ) + throw std::runtime_error( "Cannot compile fragment shader!" ); + + if( !shader.Link() ) + throw std::runtime_error( "Cannot link the shaders!" ); + + // Make VBOs use shaders + cachedManager.SetShader( shader ); + nonCachedManager.SetShader( shader ); + overlayManager.SetShader( shader ); // Initialize the flags - isGlewInitialized = false; isFramebufferInitialized = false; - isShaderInitialized = false; isGrouping = false; groupCounter = 0; @@ -100,10 +117,7 @@ OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener, InitTesselatorCallbacks( tesselator ); if( tesselator == NULL ) - { - DisplayError( parentWindow, wxT( "Could not create the tesselator" ) ); - exit( 1 ); - } + throw std::runtime_error( "Could not create the tesselator" ); gluTessProperty( tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE ); @@ -123,13 +137,8 @@ OPENGL_GAL::~OPENGL_GAL() void OPENGL_GAL::BeginDrawing() { SetCurrent( *glContext ); - clientDC = new wxClientDC( this ); - // Initialize GLEW, FBOs & VBOs - if( !isGlewInitialized ) - initGlew(); - // Set up the view port glMatrixMode( GL_PROJECTION ); glLoadIdentity(); @@ -148,35 +157,6 @@ void OPENGL_GAL::BeginDrawing() isFramebufferInitialized = true; } - // Compile the shaders - if( !isShaderInitialized ) - { - if( !shader.LoadBuiltinShader( 0, SHADER_TYPE_VERTEX ) ) - { - DisplayError( parentWindow, wxT( "Cannot compile vertex shader!" ) ); - exit( 1 ); - } - - if( !shader.LoadBuiltinShader( 1, SHADER_TYPE_FRAGMENT ) ) - { - DisplayError( parentWindow, wxT( "Cannot compile fragment shader!" ) ); - exit( 1 ); - } - - if( !shader.Link() ) - { - DisplayError( parentWindow, wxT( "Cannot link the shaders!" ) ); - exit( 1 ); - } - - // Make VBOs use shaders - cachedManager.SetShader( shader ); - nonCachedManager.SetShader( shader ); - overlayManager.SetShader( shader ); - - isShaderInitialized = true; - } - // Disable 2D Textures glDisable( GL_TEXTURE_2D ); @@ -815,7 +795,7 @@ void OPENGL_GAL::drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEnd if( lineLength <= 0.0 ) return; - + double scale = 0.5 * lineWidth / lineLength; // The perpendicular vector also needs transformations @@ -941,8 +921,7 @@ void OPENGL_GAL::initGlew() if( GLEW_OK != err ) { - DisplayError( parentWindow, wxString::FromUTF8( (char*) glewGetErrorString( err ) ) ); - exit( 1 ); + throw std::runtime_error( (const char*) glewGetErrorString( err ) ); } else { @@ -952,30 +931,17 @@ void OPENGL_GAL::initGlew() // Check the OpenGL version (minimum 2.1 is required) if( GLEW_VERSION_2_1 ) - { wxLogInfo( wxT( "OpenGL 2.1 supported." ) ); - } else - { - DisplayError( parentWindow, wxT( "OpenGL 2.1 or higher is required!" ) ); - exit( 1 ); - } + throw std::runtime_error( "OpenGL 2.1 or higher is required!" ); // Framebuffers have to be supported if( !GLEW_EXT_framebuffer_object ) - { - DisplayError( parentWindow, wxT( "Framebuffer objects are not supported!" ) ); - exit( 1 ); - } + throw std::runtime_error( "Framebuffer objects are not supported!" ); // Vertex buffer has to be supported if( !GLEW_ARB_vertex_buffer_object ) - { - DisplayError( parentWindow, wxT( "Vertex buffer objects are not supported!" ) ); - exit( 1 ); - } - - isGlewInitialized = true; + throw std::runtime_error( "Vertex buffer objects are not supported!" ); } @@ -1058,12 +1024,8 @@ void CALLBACK EdgeCallback( GLboolean aEdgeFlag ) void CALLBACK ErrorCallback( GLenum aErrorCode ) { - const GLubyte* eString = gluErrorString( aErrorCode ); - - DisplayError( NULL, wxT( "Tessellation error: " ) + - wxString( (const char*)( eString ), wxConvUTF8 ) ); - - exit( 1 ); + //throw std::runtime_error( std::string( "Tessellation error: " ) + + //std::string( (const char*) gluErrorString( aErrorCode ) ); } diff --git a/common/gal/opengl/shader.cpp b/common/gal/opengl/shader.cpp index 6210776300..8edb1c350b 100644 --- a/common/gal/opengl/shader.cpp +++ b/common/gal/opengl/shader.cpp @@ -28,10 +28,10 @@ #include #include +#include -#include -#include -#include +#include +#include #include #include "shader_src.h" @@ -102,8 +102,7 @@ bool SHADER::Link() glGetObjectParameterivARB( programNumber, GL_OBJECT_LINK_STATUS_ARB, (GLint*) &isShaderLinked ); -#ifdef __WXDEBUG__ - +#ifdef DEBUG if( !isShaderLinked ) { int maxLength; @@ -115,8 +114,7 @@ bool SHADER::Link() std::cerr << linkInfoLog; delete[] linkInfoLog; } - -#endif /* __WXDEBUG__ */ +#endif /* DEBUG */ return isShaderLinked; } @@ -127,9 +125,7 @@ int SHADER::AddParameter( const std::string& aParameterName ) GLint location = glGetUniformLocation( programNumber, aParameterName.c_str() ); if( location != -1 ) - { parameterLocation.push_back( location ); - } return location; } @@ -167,7 +163,7 @@ void SHADER::programInfo( GLuint aProgram ) GLchar* glInfoLog = new GLchar[glInfoLogLength]; glGetProgramInfoLog( aProgram, glInfoLogLength, &writtenChars, glInfoLog ); - wxLogInfo( wxString::FromUTF8( (char*) glInfoLog ) ); + std::cerr << glInfoLog << std::endl; delete[] glInfoLog; } @@ -188,7 +184,7 @@ void SHADER::shaderInfo( GLuint aShader ) GLchar* glInfoLog = new GLchar[glInfoLogLength]; glGetShaderInfoLog( aShader, glInfoLogLength, &writtenChars, glInfoLog ); - wxLogInfo( wxString::FromUTF8( (char*) glInfoLog ) ); + std::cerr << glInfoLog << std::endl; delete[] glInfoLog; } @@ -202,11 +198,7 @@ std::string SHADER::readSource( std::string aShaderSourceName ) std::string shaderSource; if( !inputFile ) - { - DisplayError( NULL, wxString::FromUTF8( "Can't read the shader source: " ) + - wxString( aShaderSourceName.c_str(), wxConvUTF8 ) ); - exit( 1 ); - } + throw std::runtime_error( "Can't read the shader source: " + aShaderSourceName ); std::string shaderSourceLine; @@ -223,10 +215,7 @@ std::string SHADER::readSource( std::string aShaderSourceName ) bool SHADER::addSource( const std::string& aShaderSource, SHADER_TYPE aShaderType ) { - if( isShaderLinked ) - { - wxLogDebug( wxT( "Shader is already linked!" ) ); - } + assert( !isShaderLinked ); // Create the program if( !isProgramCreated ) @@ -244,7 +233,7 @@ bool SHADER::addSource( const std::string& aShaderSource, SHADER_TYPE aShaderTyp // Copy to char array char* source = new char[aShaderSource.size() + 1]; - strcpy( source, aShaderSource.c_str() ); + strncpy( source, aShaderSource.c_str(), aShaderSource.size() + 1 ); const char** source_ = (const char**) ( &source ); // Attach the source @@ -261,11 +250,8 @@ bool SHADER::addSource( const std::string& aShaderSource, SHADER_TYPE aShaderTyp if( status != GL_TRUE ) { - DisplayError( NULL, wxT( "Shader compilation error" ) ); - shaderInfo( shaderNumber ); - - return false; + throw std::runtime_error( "Shader compilation error" ); } glAttachShader( programNumber, shaderNumber ); diff --git a/include/class_draw_panel_gal.h b/include/class_draw_panel_gal.h index d070548682..04375ace3d 100644 --- a/include/class_draw_panel_gal.h +++ b/include/class_draw_panel_gal.h @@ -66,7 +66,7 @@ public: * Switches method of rendering graphics. * @param aGalType is a type of rendering engine that you want to use. */ - void SwitchBackend( GalType aGalType ); + bool SwitchBackend( GalType aGalType ); /** * Function GetBackend diff --git a/include/gal/opengl/opengl_gal.h b/include/gal/opengl/opengl_gal.h index 779a119ac7..ff618b9554 100644 --- a/include/gal/opengl/opengl_gal.h +++ b/include/gal/opengl/opengl_gal.h @@ -277,9 +277,7 @@ private: SHADER shader; ///< There is only one shader used for different objects // Internal flags - bool isGlewInitialized; ///< Is GLEW initialized? bool isFramebufferInitialized; ///< Are the framebuffers initialized? - bool isShaderInitialized; ///< Was the shader initialized? bool isGrouping; ///< Was a group started? // Polygon tesselation diff --git a/pcbnew/pcbframe.cpp b/pcbnew/pcbframe.cpp index f715fcc13a..1ccc128d66 100644 --- a/pcbnew/pcbframe.cpp +++ b/pcbnew/pcbframe.cpp @@ -694,24 +694,26 @@ void PCB_EDIT_FRAME::UseGalCanvas( bool aEnable ) void PCB_EDIT_FRAME::SwitchCanvas( wxCommandEvent& aEvent ) { int id = aEvent.GetId(); + bool use_gal = false; switch( id ) { case ID_MENU_CANVAS_DEFAULT: - Compile_Ratsnest( NULL, true ); - UseGalCanvas( false ); break; case ID_MENU_CANVAS_CAIRO: - GetGalCanvas()->SwitchBackend( EDA_DRAW_PANEL_GAL::GAL_TYPE_CAIRO ); - UseGalCanvas( true ); + use_gal = GetGalCanvas()->SwitchBackend( EDA_DRAW_PANEL_GAL::GAL_TYPE_CAIRO ); break; case ID_MENU_CANVAS_OPENGL: - GetGalCanvas()->SwitchBackend( EDA_DRAW_PANEL_GAL::GAL_TYPE_OPENGL ); - UseGalCanvas( true ); + use_gal = GetGalCanvas()->SwitchBackend( EDA_DRAW_PANEL_GAL::GAL_TYPE_OPENGL ); break; } + + if( !use_gal ) + Compile_Ratsnest( NULL, true ); + + UseGalCanvas( use_gal ); }