2020-03-02 09:58:46 +00:00
# include "libslic3r/libslic3r.h"
2020-05-06 12:38:53 +00:00
# include "OpenGLManager.hpp"
# include "GUI.hpp"
# include "I18N.hpp"
# include "3DScene.hpp"
2018-05-09 08:47:04 +00:00
# include <GL/glew.h>
# include <boost/algorithm/string/split.hpp>
# include <boost/algorithm/string/classification.hpp>
2020-03-02 10:40:35 +00:00
# include <boost/log/trivial.hpp>
2018-05-09 08:47:04 +00:00
2020-05-06 12:38:53 +00:00
# include <wx/glcanvas.h>
2020-05-06 12:48:40 +00:00
# include <wx/msgdlg.h>
2018-05-09 08:47:04 +00:00
2020-03-02 13:37:01 +00:00
# if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
# ifdef __APPLE__
// Part of hack to remove crash when closing the application on OSX 10.9.5 when building against newer wxWidgets
# include <wx/platinfo.h>
# endif // __APPLE__
# endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
2020-02-27 13:55:27 +00:00
2019-05-23 11:49:57 +00:00
# ifdef __APPLE__
# include "../Utils/MacDarkMode.hpp"
# endif // __APPLE__
2018-05-09 08:47:04 +00:00
namespace Slic3r {
namespace GUI {
2020-05-06 12:38:53 +00:00
const std : : string & OpenGLManager : : GLInfo : : get_version ( ) const
2019-05-23 11:49:57 +00:00
{
if ( ! m_detected )
detect ( ) ;
return m_version ;
}
2020-05-06 12:38:53 +00:00
const std : : string & OpenGLManager : : GLInfo : : get_glsl_version ( ) const
2019-05-23 11:49:57 +00:00
{
if ( ! m_detected )
detect ( ) ;
return m_glsl_version ;
}
2020-05-06 12:38:53 +00:00
const std : : string & OpenGLManager : : GLInfo : : get_vendor ( ) const
2019-05-23 11:49:57 +00:00
{
if ( ! m_detected )
detect ( ) ;
return m_vendor ;
}
2020-05-06 12:38:53 +00:00
const std : : string & OpenGLManager : : GLInfo : : get_renderer ( ) const
2019-05-23 11:49:57 +00:00
{
if ( ! m_detected )
detect ( ) ;
return m_renderer ;
}
2020-05-06 12:38:53 +00:00
int OpenGLManager : : GLInfo : : get_max_tex_size ( ) const
2018-05-09 08:47:04 +00:00
{
2019-05-23 11:49:57 +00:00
if ( ! m_detected )
detect ( ) ;
// clamp to avoid the texture generation become too slow and use too much GPU memory
# ifdef __APPLE__
// and use smaller texture for non retina systems
return ( Slic3r : : GUI : : mac_max_scaling_factor ( ) > 1.0 ) ? std : : min ( m_max_tex_size , 8192 ) : std : : min ( m_max_tex_size / 2 , 4096 ) ;
# else
// and use smaller texture for older OpenGL versions
return is_version_greater_or_equal_to ( 3 , 0 ) ? std : : min ( m_max_tex_size , 8192 ) : std : : min ( m_max_tex_size / 2 , 4096 ) ;
# endif // __APPLE__
2018-05-09 08:47:04 +00:00
}
2020-05-06 12:38:53 +00:00
float OpenGLManager : : GLInfo : : get_max_anisotropy ( ) const
2019-05-23 11:49:57 +00:00
{
if ( ! m_detected )
detect ( ) ;
return m_max_anisotropy ;
}
2020-05-06 12:38:53 +00:00
void OpenGLManager : : GLInfo : : detect ( ) const
2019-05-23 11:49:57 +00:00
{
const char * data = ( const char * ) : : glGetString ( GL_VERSION ) ;
if ( data ! = nullptr )
m_version = data ;
data = ( const char * ) : : glGetString ( GL_SHADING_LANGUAGE_VERSION ) ;
if ( data ! = nullptr )
m_glsl_version = data ;
data = ( const char * ) : : glGetString ( GL_VENDOR ) ;
if ( data ! = nullptr )
m_vendor = data ;
data = ( const char * ) : : glGetString ( GL_RENDERER ) ;
if ( data ! = nullptr )
m_renderer = data ;
glsafe ( : : glGetIntegerv ( GL_MAX_TEXTURE_SIZE , & m_max_tex_size ) ) ;
2019-10-10 07:35:21 +00:00
m_max_tex_size / = 2 ;
2020-02-27 14:38:35 +00:00
if ( Slic3r : : total_physical_memory ( ) / ( 1024 * 1024 * 1024 ) < 6 )
m_max_tex_size / = 2 ;
2019-05-23 11:49:57 +00:00
if ( GLEW_EXT_texture_filter_anisotropic )
glsafe ( : : glGetFloatv ( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT , & m_max_anisotropy ) ) ;
m_detected = true ;
}
2018-06-04 08:14:09 +00:00
2020-05-06 12:38:53 +00:00
bool OpenGLManager : : GLInfo : : is_version_greater_or_equal_to ( unsigned int major , unsigned int minor ) const
2019-05-23 11:49:57 +00:00
{
if ( ! m_detected )
detect ( ) ;
std : : vector < std : : string > tokens ;
boost : : split ( tokens , m_version , boost : : is_any_of ( " " ) , boost : : token_compress_on ) ;
if ( tokens . empty ( ) )
return false ;
std : : vector < std : : string > numbers ;
boost : : split ( numbers , tokens [ 0 ] , boost : : is_any_of ( " . " ) , boost : : token_compress_on ) ;
unsigned int gl_major = 0 ;
unsigned int gl_minor = 0 ;
if ( numbers . size ( ) > 0 )
gl_major = : : atoi ( numbers [ 0 ] . c_str ( ) ) ;
if ( numbers . size ( ) > 1 )
gl_minor = : : atoi ( numbers [ 1 ] . c_str ( ) ) ;
if ( gl_major < major )
return false ;
else if ( gl_major > major )
return true ;
else
return gl_minor > = minor ;
}
2018-06-04 08:14:09 +00:00
2020-05-06 12:38:53 +00:00
std : : string OpenGLManager : : GLInfo : : to_string ( bool format_as_html , bool extensions ) const
2018-06-04 08:14:09 +00:00
{
2019-05-23 11:49:57 +00:00
if ( ! m_detected )
detect ( ) ;
2018-06-04 08:14:09 +00:00
std : : stringstream out ;
std : : string h2_start = format_as_html ? " <b> " : " " ;
2018-07-12 11:34:39 +00:00
std : : string h2_end = format_as_html ? " </b> " : " " ;
std : : string b_start = format_as_html ? " <b> " : " " ;
std : : string b_end = format_as_html ? " </b> " : " " ;
2018-06-04 08:14:09 +00:00
std : : string line_end = format_as_html ? " <br> " : " \n " ;
out < < h2_start < < " OpenGL installation " < < h2_end < < line_end ;
2019-05-23 11:49:57 +00:00
out < < b_start < < " GL version: " < < b_end < < ( m_version . empty ( ) ? " N/A " : m_version ) < < line_end ;
out < < b_start < < " Vendor: " < < b_end < < ( m_vendor . empty ( ) ? " N/A " : m_vendor ) < < line_end ;
out < < b_start < < " Renderer: " < < b_end < < ( m_renderer . empty ( ) ? " N/A " : m_renderer ) < < line_end ;
out < < b_start < < " GLSL version: " < < b_end < < ( m_glsl_version . empty ( ) ? " N/A " : m_glsl_version ) < < line_end ;
2018-07-12 10:15:30 +00:00
2018-06-04 08:14:09 +00:00
if ( extensions )
{
std : : vector < std : : string > extensions_list ;
2018-07-12 11:10:18 +00:00
std : : string extensions_str = ( const char * ) : : glGetString ( GL_EXTENSIONS ) ;
boost : : split ( extensions_list , extensions_str , boost : : is_any_of ( " " ) , boost : : token_compress_off ) ;
2018-07-12 10:15:30 +00:00
if ( ! extensions_list . empty ( ) )
2018-06-04 08:14:09 +00:00
{
2018-07-12 10:15:30 +00:00
out < < h2_start < < " Installed extensions: " < < h2_end < < line_end ;
std : : sort ( extensions_list . begin ( ) , extensions_list . end ( ) ) ;
for ( const std : : string & ext : extensions_list )
{
out < < ext < < line_end ;
}
2018-06-04 08:14:09 +00:00
}
}
return out . str ( ) ;
2018-05-09 08:47:04 +00:00
}
2020-05-06 12:38:53 +00:00
OpenGLManager : : GLInfo OpenGLManager : : s_gl_info ;
bool OpenGLManager : : s_compressed_textures_supported = false ;
OpenGLManager : : EMultisampleState OpenGLManager : : s_multisample = OpenGLManager : : EMultisampleState : : Unknown ;
OpenGLManager : : EFramebufferType OpenGLManager : : s_framebuffers_type = OpenGLManager : : EFramebufferType : : Unknown ;
2018-10-02 12:01:22 +00:00
2020-03-02 13:37:01 +00:00
# if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
# ifdef __APPLE__
// Part of hack to remove crash when closing the application on OSX 10.9.5 when building against newer wxWidgets
2020-05-06 12:38:53 +00:00
OpenGLManager : : OSInfo OpenGLManager : : s_os_info ;
2020-03-02 13:37:01 +00:00
# endif // __APPLE__
# endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
2018-10-02 12:01:22 +00:00
2020-05-06 12:38:53 +00:00
OpenGLManager : : ~ OpenGLManager ( )
2018-10-04 08:41:11 +00:00
{
2020-03-02 13:37:01 +00:00
# if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
# ifdef __APPLE__
// This is an ugly hack needed to solve the crash happening when closing the application on OSX 10.9.5 with newer wxWidgets
// The crash is triggered inside wxGLContext destructor
if ( s_os_info . major ! = 10 | | s_os_info . minor ! = 9 | | s_os_info . micro ! = 5 )
{
# endif //__APPLE__
# endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
2020-03-02 14:22:41 +00:00
if ( m_context ! = nullptr )
delete m_context ;
2020-03-02 13:37:01 +00:00
# if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
# ifdef __APPLE__
}
# endif //__APPLE__
# endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
2018-10-04 08:41:11 +00:00
}
2020-05-06 12:38:53 +00:00
bool OpenGLManager : : init_gl ( )
2018-05-09 08:47:04 +00:00
{
if ( ! m_gl_initialized )
{
2020-03-02 09:58:46 +00:00
if ( glewInit ( ) ! = GLEW_OK )
{
BOOST_LOG_TRIVIAL ( error ) < < " Unable to init glew library " ;
return false ;
}
2018-06-20 12:34:20 +00:00
m_gl_initialized = true ;
2019-05-21 12:19:03 +00:00
if ( GLEW_EXT_texture_compression_s3tc )
s_compressed_textures_supported = true ;
else
s_compressed_textures_supported = false ;
2019-08-30 07:19:45 +00:00
2020-03-02 09:58:46 +00:00
if ( GLEW_ARB_framebuffer_object )
s_framebuffers_type = EFramebufferType : : Arb ;
else if ( GLEW_EXT_framebuffer_object )
s_framebuffers_type = EFramebufferType : : Ext ;
else
2020-03-02 12:09:12 +00:00
s_framebuffers_type = EFramebufferType : : Unknown ;
2019-10-29 09:27:51 +00:00
2019-08-30 07:19:45 +00:00
if ( ! s_gl_info . is_version_greater_or_equal_to ( 2 , 0 ) ) {
// Complain about the OpenGL version.
2020-03-02 10:48:31 +00:00
wxString message = from_u8 ( ( boost : : format (
_utf8 ( L ( " PrusaSlicer requires OpenGL 2.0 capable graphics driver to run correctly, \n "
" while OpenGL version %s, render %s, vendor %s was detected. " ) ) ) % s_gl_info . get_version ( ) % s_gl_info . get_renderer ( ) % s_gl_info . get_vendor ( ) ) . str ( ) ) ;
2019-08-30 07:19:45 +00:00
message + = " \n " ;
2020-05-06 12:38:53 +00:00
message + = _L ( " You may need to update your graphics card driver. " ) ;
2019-08-30 07:19:45 +00:00
# ifdef _WIN32
message + = " \n " ;
2020-05-06 12:38:53 +00:00
message + = _L ( " As a workaround, you may run PrusaSlicer with a software rendered 3D graphics by running prusa-slicer.exe with the --sw_renderer parameter. " ) ;
2019-08-30 07:19:45 +00:00
# endif
2020-05-06 12:38:53 +00:00
wxMessageBox ( message , wxString ( " PrusaSlicer - " ) + _L ( " Unsupported OpenGL version " ) , wxOK | wxICON_ERROR ) ;
2019-08-30 07:19:45 +00:00
}
2018-05-09 08:47:04 +00:00
}
2020-03-02 09:58:46 +00:00
return true ;
2018-05-09 08:47:04 +00:00
}
2020-05-06 12:38:53 +00:00
wxGLContext * OpenGLManager : : init_glcontext ( wxGLCanvas & canvas )
2020-03-02 09:58:46 +00:00
{
if ( m_context = = nullptr )
2020-03-02 14:55:36 +00:00
{
2020-03-02 09:58:46 +00:00
m_context = new wxGLContext ( & canvas ) ;
2020-03-02 14:55:36 +00:00
# if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
# ifdef __APPLE__
// Part of hack to remove crash when closing the application on OSX 10.9.5 when building against newer wxWidgets
s_os_info . major = wxPlatformInfo : : Get ( ) . GetOSMajorVersion ( ) ;
s_os_info . minor = wxPlatformInfo : : Get ( ) . GetOSMinorVersion ( ) ;
s_os_info . micro = wxPlatformInfo : : Get ( ) . GetOSMicroVersion ( ) ;
# endif //__APPLE__
# endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
}
2020-03-02 09:58:46 +00:00
return m_context ;
}
2019-08-22 18:02:25 +00:00
2020-05-06 12:38:53 +00:00
wxGLCanvas * OpenGLManager : : create_wxglcanvas ( wxWindow & parent )
2018-10-01 14:48:08 +00:00
{
2019-08-07 12:55:34 +00:00
int attribList [ ] = {
WX_GL_RGBA ,
WX_GL_DOUBLEBUFFER ,
// RGB channels each should be allocated with 8 bit depth. One should almost certainly get these bit depths by default.
WX_GL_MIN_RED , 8 ,
WX_GL_MIN_GREEN , 8 ,
WX_GL_MIN_BLUE , 8 ,
// Requesting an 8 bit alpha channel. Interestingly, the NVIDIA drivers would most likely work with some alpha plane, but glReadPixels would not return
// the alpha channel on NVIDIA if not requested when the GL context is created.
2019-08-07 13:03:43 +00:00
WX_GL_MIN_ALPHA , 8 ,
2019-08-07 12:55:34 +00:00
WX_GL_DEPTH_SIZE , 24 ,
WX_GL_SAMPLE_BUFFERS , GL_TRUE ,
WX_GL_SAMPLES , 4 ,
0
} ;
2018-10-01 14:48:08 +00:00
2020-03-02 09:58:46 +00:00
if ( s_multisample = = EMultisampleState : : Unknown )
2018-10-02 12:01:22 +00:00
{
2019-05-21 12:19:03 +00:00
detect_multisample ( attribList ) ;
// // debug output
// std::cout << "Multisample " << (can_multisample() ? "enabled" : "disabled") << std::endl;
2018-10-02 12:01:22 +00:00
}
2019-05-21 12:19:03 +00:00
if ( ! can_multisample ( ) )
2019-08-07 13:03:43 +00:00
attribList [ 12 ] = 0 ;
2018-10-01 14:48:08 +00:00
2020-03-02 09:58:46 +00:00
return new wxGLCanvas ( & parent , wxID_ANY , attribList , wxDefaultPosition , wxDefaultSize , wxWANTS_CHARS ) ;
2018-05-09 08:47:04 +00:00
}
2020-05-06 12:38:53 +00:00
void OpenGLManager : : detect_multisample ( int * attribList )
2018-10-02 12:01:22 +00:00
{
int wxVersion = wxMAJOR_VERSION * 10000 + wxMINOR_VERSION * 100 + wxRELEASE_NUMBER ;
2019-06-25 07:20:58 +00:00
bool enable_multisample = wxVersion > = 30003 ;
2020-03-02 09:58:46 +00:00
s_multisample = ( enable_multisample & & wxGLCanvas : : IsDisplaySupported ( attribList ) ) ? EMultisampleState : : Enabled : EMultisampleState : : Disabled ;
2018-10-02 12:01:22 +00:00
// Alternative method: it was working on previous version of wxWidgets but not with the latest, at least on Windows
// s_multisample = enable_multisample && wxGLCanvas::IsExtensionSupported("WGL_ARB_multisample");
}
2018-05-09 08:47:04 +00:00
} // namespace GUI
} // namespace Slic3r