Commit b1ace160 authored by Maciej Suminski's avatar Maciej Suminski
Browse files

Reworked GAL switching.

Now OpenGL can report its problems instead of shutting down the application.
parent b19010ff
Loading
Loading
Loading
Loading
+57 −40
Original line number Diff line number Diff line
/*
 * 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 <tomasz.wlostowski@cern.ch>
 * @author Maciej Suminski <maciej.suminski@cern.ch>
 *
 * 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 <wx/event.h>
#include <wx/colour.h>
#include <wx/filename.h>
#include <confirm.h>

#include <class_draw_panel_gal.h>
#include <view/view.h>
@@ -116,8 +118,9 @@ 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();
@@ -140,7 +143,6 @@ void EDA_DRAW_PANEL_GAL::onPaint( wxPaintEvent& WXUNUSED( aEvent ) )

    m_drawing = false;
}
}


void EDA_DRAW_PANEL_GAL::onSize( wxSizeEvent& aEvent )
@@ -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,31 +275,36 @@ 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;

    try
    {
        switch( aGalType )
        {
        case GAL_TYPE_OPENGL:
        m_gal = new KIGFX::OPENGL_GAL( this, this, this );
            new_gal = new KIGFX::OPENGL_GAL( this, this, this );
            break;

        case GAL_TYPE_CAIRO:
        m_gal = new KIGFX::CAIRO_GAL( this, this, this );
            new_gal = new KIGFX::CAIRO_GAL( this, this, this );
            break;

        case GAL_TYPE_NONE:
        return;
            return false;
        }

        delete m_gal;
        m_gal = new_gal;

        wxSize size = GetClientSize();
        m_gal->ResizeScreen( size.GetX(), size.GetY() );

@@ -307,6 +316,14 @@ void EDA_DRAW_PANEL_GAL::SwitchBackend( GalType aGalType )

        m_backend = aGalType;
    }
    catch (std::runtime_error& err)
    {
            DisplayError( m_parent, wxString( err.what() ) );
            return false;
    }

    return true;
}


void EDA_DRAW_PANEL_GAL::onEvent( wxEvent& aEvent )
+23 −23
Original line number Diff line number Diff line
/*
 * 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 <maciej.suminski@cern.ch>
 *
 * 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 <gal/opengl/opengl_compositor.h>
#include <wx/msgdlg.h>
#include <confirm.h>

#include <stdexcept>
#include <cassert>

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;
+32 −70
Original line number Diff line number Diff line
@@ -3,7 +3,7 @@
 *
 * Copyright (C) 2012 Torsten Hueter, torstenhtr <at> 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 <maciej.suminski@cern.ch>
 *
 * Graphics Abstraction Layer (GAL) for OpenGL
@@ -31,7 +31,6 @@

#include <wx/log.h>
#include <macros.h>
#include <confirm.h>
#ifdef __WXDEBUG__
#include <profile.h>
#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 );

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


+11 −25
Original line number Diff line number Diff line
@@ -28,10 +28,10 @@

#include <iostream>
#include <fstream>
#include <stdexcept>

#include <wx/log.h>
#include <wx/gdicmn.h>
#include <confirm.h>
#include <cstring>
#include <cassert>

#include <gal/opengl/shader.h>
#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 );
+1 −1
Original line number Diff line number Diff line
@@ -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
Loading