Allow using custom getProcAddress for glew; Render OpenGL in paint event.

Fixes OpenGL rendering on Linux.
This commit is contained in:
Alex Shvartzkop 2024-06-21 21:30:51 +03:00
parent 2efc256a75
commit 96fb82e769
14 changed files with 218 additions and 71 deletions

View File

@ -223,7 +223,7 @@ bool EDA_3D_CANVAS::initializeOpenGL()
{
wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::initializeOpenGL" ) );
const GLenum err = glewInit();
const GLenum err = kiglewInit();
if( GLEW_OK != err )
{

View File

@ -182,7 +182,7 @@ void EDA_3D_MODEL_VIEWER::Clear3DModel()
void EDA_3D_MODEL_VIEWER::ogl_initialize()
{
const GLenum err = glewInit();
const GLenum err = kiglewInit();
if( GLEW_OK != err )
{

View File

@ -121,10 +121,9 @@ cmake_dependent_option( KICAD_USE_EGL
OFF "UNIX_NOT_APPLE"
OFF)
cmake_dependent_option( KICAD_USE_BUNDLED_GLEW
"Use the bundled version of GLEW - only available when KICAD_USE_EGL is set"
ON "KICAD_USE_EGL"
OFF )
option( KICAD_USE_BUNDLED_GLEW
"Use the bundled version of GLEW"
${KICAD_USE_EGL} )
cmake_dependent_option( KICAD_WAYLAND
"Support Wayland features"
@ -760,50 +759,6 @@ if( KICAD_BUILD_I18N )
find_package( Gettext REQUIRED )
endif()
#
# Find OpenGL library, required
#
if( KICAD_USE_EGL )
find_package( OpenGL REQUIRED COMPONENTS OpenGL EGL )
else()
set( OpenGL_GL_PREFERENCE "LEGACY" ) # CMake 3.11+ setting; see 'cmake --help-policy CMP0072'
find_package( OpenGL REQUIRED )
endif()
#
# Find GLEW library, required
#
# The EGL canvas on GTK requires the use of a GLEW version compiled with an EGL flag.
# The one built in the thirdparty directory has the flag for EGL set, so we use it unless told
# otherwise. Then we search for the system GLEW version and use that instead.
#
if( KICAD_USE_EGL AND KICAD_USE_BUNDLED_GLEW AND UNIX AND NOT APPLE )
if( OpenGL_EGL_FOUND )
message( STATUS "Found OpenGL EGL library: ${OPENGL_egl_LIBRARY}" )
else()
message( FATAL_ERROR "OpenGL EGL library not found" )
endif()
# Add the custom GLEW target
add_subdirectory( thirdparty/glew )
# Set the standard package variables to point to our custom target to mimic the system version.
set( GLEW_LIBRARIES glew )
set( GLEW_FOUND TRUE )
include_directories( SYSTEM $<TARGET_PROPERTY:glew,INCLUDE_DIRECTORIES> )
else()
find_package( GLEW REQUIRED )
check_find_package_result( GLEW_FOUND "GLEW" )
include_directories( SYSTEM ${GLEW_INCLUDE_DIR} )
endif()
#
# Find GLM library, required
#
find_package( GLM 0.9.8 REQUIRED )
add_compile_definitions( GLM_FORCE_CTOR_INIT )
include_directories( SYSTEM ${GLM_INCLUDE_DIR} )
#
# Find zlib library, required
#
@ -1098,6 +1053,52 @@ if( MINGW )
endif()
endif()
#
# Find OpenGL library, required
#
if( KICAD_USE_EGL )
find_package( OpenGL REQUIRED COMPONENTS OpenGL EGL )
else()
set( OpenGL_GL_PREFERENCE "LEGACY" ) # CMake 3.11+ setting; see 'cmake --help-policy CMP0072'
find_package( OpenGL REQUIRED )
endif()
#
# Find GLEW library, required
#
# The EGL canvas on GTK requires the use of a GLEW version compiled with an EGL flag.
# The one built in the thirdparty directory has the flag for EGL set, so we use it unless told
# otherwise. Then we search for the system GLEW version and use that instead.
#
if( KICAD_USE_EGL )
if( OpenGL_EGL_FOUND )
message( STATUS "Found OpenGL EGL library: ${OPENGL_egl_LIBRARY}" )
else()
message( FATAL_ERROR "OpenGL EGL library not found" )
endif()
endif()
if( KICAD_USE_BUNDLED_GLEW AND UNIX AND NOT APPLE )
# Add the custom GLEW target
add_subdirectory( thirdparty/glew )
# Set the standard package variables to point to our custom target to mimic the system version.
set( GLEW_LIBRARIES glew )
set( GLEW_FOUND TRUE )
include_directories( SYSTEM $<TARGET_PROPERTY:glew,INCLUDE_DIRECTORIES> )
else()
find_package( GLEW REQUIRED )
check_find_package_result( GLEW_FOUND "GLEW" )
include_directories( SYSTEM ${GLEW_INCLUDE_DIR} )
endif()
#
# Find GLM library, required
#
find_package( GLM 0.9.8 REQUIRED )
add_compile_definitions( GLM_FORCE_CTOR_INIT )
include_directories( SYSTEM ${GLM_INCLUDE_DIR} )
if( APPLE )
# Remove app bundles in ${KICAD_BIN} before installing anything new.
# Must be defined before all includes so that it is executed first.

View File

@ -200,6 +200,9 @@ void EDA_DRAW_PANEL_GAL::onPaint( wxPaintEvent& WXUNUSED( aEvent ) )
bool EDA_DRAW_PANEL_GAL::DoRePaint()
{
if( m_gal->IsContextLocked() )
return false;
if( !m_refreshMutex.try_lock() )
return false;
@ -389,8 +392,7 @@ void EDA_DRAW_PANEL_GAL::RequestRefresh()
void EDA_DRAW_PANEL_GAL::Refresh( bool aEraseBackground, const wxRect* aRect )
{
if( !DoRePaint() )
RequestRefresh();
wxScrolledCanvas::Refresh( aEraseBackground, aRect );
}
@ -415,7 +417,7 @@ void EDA_DRAW_PANEL_GAL::ForceRefresh()
}
}
DoRePaint();
Refresh();
}

View File

@ -384,7 +384,16 @@ void OPENGL_COMPOSITOR::bindFb( unsigned int aFb )
if( m_curFbo != aFb )
{
glBindFramebufferEXT( GL_FRAMEBUFFER, aFb );
unsigned int actualBuffer = aFb;
#ifdef __WXQT__
// Qt needs to draw on a separate framebuffer first
if( aFb == DIRECT_RENDERING )
actualBuffer = QtOpenGLGetOutputFBO();
#endif
glBindFramebufferEXT( GL_FRAMEBUFFER, actualBuffer );
checkGlError( "switching framebuffer", __FILE__, __LINE__ );
m_curFbo = aFb;
}

View File

@ -499,9 +499,9 @@ wxString OPENGL_GAL::CheckFeatures( GAL_DISPLAY_OPTIONS& aOptions )
void OPENGL_GAL::PostPaint( wxPaintEvent& aEvent )
{
// posts an event to m_paint_listener to ask for redraw the canvas.
// Repaint it immediately via m_paintListener.
if( m_paintListener )
wxPostEvent( m_paintListener, aEvent );
m_paintListener->ProcessEvent( aEvent );
}
@ -2687,7 +2687,8 @@ void OPENGL_GAL::init()
// Check correct initialization from the constructor
if( m_tesselator == nullptr )
throw std::runtime_error( "Could not create the tesselator" );
GLenum err = glewInit();
GLenum err = kiglewInit();
#ifdef KICAD_USE_EGL
// TODO: better way to check when EGL is ready (init fails at "getString(GL_VERSION)")
@ -2697,7 +2698,7 @@ void OPENGL_GAL::init()
break;
std::this_thread::sleep_for( std::chrono::milliseconds( 250 ) );
err = glewInit();
err = kiglewInit();
}
#endif // KICAD_USE_EGL

View File

@ -48,7 +48,7 @@ public:
*/
static int SetSwapInterval( int aVal )
{
#if defined( __linux__ ) && !defined( KICAD_USE_EGL )
#if defined( __linux__ ) && !defined( KICAD_USE_EGL ) && !defined( __WXQT__ )
if( Display* dpy = glXGetCurrentDisplay() )
{
@ -109,7 +109,7 @@ public:
}
}
#elif defined( _WIN32 ) and not defined( __WXQT__ )
#elif defined( _WIN32 ) and !defined( __WXQT__ )
const GLubyte* vendor = glGetString( GL_VENDOR );
//const GLubyte* renderer = glGetString( GL_RENDERER );

View File

@ -31,12 +31,16 @@
// Pull in the configuration options for wxWidgets
#include <wx/platform.h>
#ifdef __WXQT__
#include <kiplatform/opengl_qt.h>
#endif
// Apple, in their infinite wisdom, has decided to mark OpenGL as deprecated.
// Luckily we can silence warnings about its deprecation. This is needed on the GLEW
// includes since they transitively include the OpenGL headers.
#define GL_SILENCE_DEPRECATION 1
#if defined( __unix__ ) and not defined( __APPLE__ )
#if defined( __unix__ ) and not defined( __APPLE__ ) and not defined( __WXQT__ )
#ifdef KICAD_USE_EGL
@ -54,6 +58,11 @@
#else
// wxWidgets wasn't compiled with the EGL canvas, so use the X11 GLEW
#include <GL/glxew.h>
// Resolve X.h conflict with wx 3.3
#ifdef Success
#undef Success
#endif
#endif
#endif // KICAD_USE_EGL
@ -63,12 +72,24 @@
// Non-GTK platforms only need the normal GLEW include
#include <GL/glew.h>
#endif // defined( __unix__ ) and not defined( __APPLE__ )
#endif // defined( __unix__ ) and not defined( __APPLE__ ) and not defined( __WXQT__ )
#ifdef _WIN32
#if defined( _WIN32 ) and not defined( __WXQT__ )
#include <GL/wglew.h>
#endif // _WIN32
#endif // defined( _WIN32 ) and not defined( __WXQT__ )
inline GLenum kiglewInit()
{
#ifdef __WXQT__
GLenum err = glewInit( &QtOpenGLGetProcAddress );
#else
GLenum err = glewInit();
#endif
return err;
}
#endif // KIGLEW_H_

View File

@ -42,6 +42,7 @@ elseif( KICAD_WX_PORT STREQUAL gtk )
elseif( KICAD_WX_PORT STREQUAL qt )
set( PLATFORM_SRCS
port/wxqt/ui.cpp
port/wxqt/opengl_qt.cpp
)
set( QT_COMPONENTS Core Widgets Gui )

View File

@ -0,0 +1,38 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 Alex Shvartzkop <dudesuchamazing@gmail.com>
* Copyright (C) 2024 Kicad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef __OPENGL_QT_KICAD
#define __OPENGL_QT_KICAD
#include <cstdint>
// A proxy function for Qt getProcAddress of current context
void* QtOpenGLGetProcAddress( const char* aName );
// A proxy function for Qt defaultFramebufferObject of current context
unsigned int QtOpenGLGetOutputFBO();
#endif // __OPENGL_QT_KICAD

View File

@ -0,0 +1,48 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 Alex Shvartzkop <dudesuchamazing@gmail.com>
* Copyright (C) 2024 Kicad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <kiplatform/opengl_qt.h>
#include <QOpenGLContext>
void* QtOpenGLGetProcAddress( const char* aName )
{
QOpenGLContext* ctx = QOpenGLContext::currentContext();
if( !ctx )
return nullptr;
return (void*) ctx->getProcAddress( aName );
}
unsigned int QtOpenGLGetOutputFBO()
{
QOpenGLContext* ctx = QOpenGLContext::currentContext();
if( !ctx )
return 0;
return ctx->defaultFramebufferObject();
}

View File

@ -8,9 +8,18 @@ target_include_directories( glew PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include" )
# Definitions for compiling GLEW staticly for EGL (extracted from the main GLEW CMakeLists.txt file)
add_compile_definitions( GLEW_STATIC )
add_compile_definitions( GLEW_EGL )
add_compile_definitions( GLEW_NO_GLU )
if( KICAD_USE_EGL )
add_compile_definitions( GLEW_EGL )
target_compile_definitions( glew INTERFACE GLEW_EGL )
endif()
if( KICAD_WX_PORT STREQUAL "qt" )
add_compile_definitions( GLEW_RAW_PTR )
target_compile_definitions( glew INTERFACE GLEW_RAW_PTR )
endif()
target_sources( glew PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src/glew.c
)

View File

@ -26512,7 +26512,12 @@ VERSION_MICRO 0
*/
/* API */
#ifdef GLEW_RAW_PTR
GLEWAPI GLenum GLEWAPIENTRY glewInit (void *(* getProcAddressFn)(const char *));
#else
GLEWAPI GLenum GLEWAPIENTRY glewInit (void);
#endif
GLEWAPI GLboolean GLEWAPIENTRY glewIsSupported (const char *name);
#define glewIsExtensionSupported(x) glewIsSupported(x)

View File

@ -36,6 +36,7 @@
# include GLEW_INCLUDE
#endif
#ifndef GLEW_RAW_PTR
#if defined(GLEW_OSMESA)
# define GLAPI extern
# include <GL/osmesa.h>
@ -54,10 +55,13 @@
#elif !defined(__ANDROID__) && !defined(__native_client__) && !defined(__HAIKU__) && (!defined(__APPLE__) || defined(GLEW_APPLE_GLX))
# include <GL/glxew.h>
#endif
#endif
#include <stddef.h> /* For size_t */
#if defined(GLEW_EGL)
#if defined(GLEW_RAW_PTR)
static void *(*glew_GetProcAddressPtr)(const unsigned char *procName);
#elif defined(GLEW_EGL)
#elif defined(GLEW_REGAL)
/* In GLEW_REGAL mode we call direcly into the linked
@ -158,7 +162,9 @@ void* NSGLGetProcAddress (const GLubyte *name)
/*
* Define glewGetProcAddress.
*/
#if defined(GLEW_REGAL)
#if defined(GLEW_RAW_PTR)
# define glewGetProcAddress(name) (*glew_GetProcAddressPtr)(name)
#elif defined(GLEW_REGAL)
# define glewGetProcAddress(name) regalGetProcAddress((const GLchar *)name)
#elif defined(GLEW_OSMESA)
# define glewGetProcAddress(name) OSMesaGetProcAddress((const char *)name)
@ -22137,7 +22143,7 @@ GLenum GLEWAPIENTRY wglewInit ()
return GLEW_OK;
}
#elif !defined(__ANDROID__) && !defined(__native_client__) && !defined(__HAIKU__) && (!defined(__APPLE__) || defined(GLEW_APPLE_GLX))
#elif !defined(GLEW_RAW_PTR) && !defined(__ANDROID__) && !defined(__native_client__) && !defined(__HAIKU__) && (!defined(__APPLE__) || defined(GLEW_APPLE_GLX))
PFNGLXGETCURRENTDISPLAYPROC __glewXGetCurrentDisplay = NULL;
@ -23226,7 +23232,7 @@ GLenum glxewInit ()
return GLEW_OK;
}
#endif /* !defined(__ANDROID__) && !defined(__native_client__) && !defined(__HAIKU__) && (!defined(__APPLE__) || defined(GLEW_APPLE_GLX)) */
#endif /* !defined(GLEW_RAW_PTR) && !defined(__ANDROID__) && !defined(__native_client__) && !defined(__HAIKU__) && (!defined(__APPLE__) || defined(GLEW_APPLE_GLX)) */
/* ------------------------------------------------------------------------ */
@ -23262,8 +23268,14 @@ const GLubyte * GLEWAPIENTRY glewGetString (GLenum name)
GLboolean glewExperimental = GL_FALSE;
#ifdef GLEW_RAW_PTR
GLenum GLEWAPIENTRY glewInit (void *(* getProcAddressFn)(const char *))
{
glew_GetProcAddressPtr = (void* (*) (const unsigned char*) ) getProcAddressFn;
#else
GLenum GLEWAPIENTRY glewInit (void)
{
#endif
GLenum r;
#if defined(GLEW_EGL)
PFNEGLGETCURRENTDISPLAYPROC getCurrentDisplay = NULL;
@ -23273,7 +23285,7 @@ GLenum GLEWAPIENTRY glewInit (void)
#if defined(GLEW_EGL)
getCurrentDisplay = (PFNEGLGETCURRENTDISPLAYPROC) glewGetProcAddress("eglGetCurrentDisplay");
return eglewInit(getCurrentDisplay());
#elif defined(GLEW_OSMESA) || defined(__ANDROID__) || defined(__native_client__) || defined(__HAIKU__)
#elif defined(GLEW_RAW_PTR) || defined(GLEW_OSMESA) || defined(__ANDROID__) || defined(__native_client__) || defined(__HAIKU__)
return r;
#elif defined(_WIN32)
return wglewInit();
@ -30432,7 +30444,7 @@ GLboolean GLEWAPIENTRY wglewIsSupported (const char* name)
return ret;
}
#elif !defined(GLEW_OSMESA) && !defined(GLEW_EGL) && !defined(__ANDROID__) && !defined(__native_client__) && !defined(__HAIKU__) && !defined(__APPLE__) || defined(GLEW_APPLE_GLX)
#elif !defined(GLEW_RAW_PTR) && !defined(GLEW_OSMESA) && !defined(GLEW_EGL) && !defined(__ANDROID__) && !defined(__native_client__) && !defined(__HAIKU__) && !defined(__APPLE__) || defined(GLEW_APPLE_GLX)
GLboolean glxewIsSupported (const char* name)
{