Browse Source

#12000: Fixes incorrect detection of supported OpenGL version (SPE-2092)

1) Force OpenGL 3.2 as minimum required. If the graphic card does not support it, automatically switch to software renderer.

2) command line option: --opengl-version=X.Y -> allows to select core profile of version X.Y.

3) command line option: --opengl-compatibility -> allows to select compatibility profile of the highest OpenGL version supported by the graphic card.

4) command line option: --opengl-debug -> enable OpenGL debug output on card supporting OpenGL 4.3 or higher (output on console).
enricoturri1966 1 year ago
parent
commit
1832c833a1

+ 17 - 13
src/PrusaSlicer.cpp

@@ -170,10 +170,9 @@ int CLI::run(int argc, char **argv)
 
 #ifdef SLIC3R_GUI
 #if ENABLE_GL_CORE_PROFILE
-    std::pair<int, int>              opengl_version = { 0, 0 };
-#if ENABLE_OPENGL_DEBUG_OPTION
-    bool                             opengl_debug = false;
-#endif // ENABLE_OPENGL_DEBUG_OPTION
+    std::pair<int, int> opengl_version = { 0, 0 };
+    bool                opengl_debug = false;
+    bool                opengl_compatibility_profile = false;
 
     // search for special keys into command line parameters
     auto it = std::find(m_actions.begin(), m_actions.end(), "gcodeviewer");
@@ -187,10 +186,8 @@ int CLI::run(int argc, char **argv)
     if (it != m_actions.end()) {
         std::string opengl_version_str = m_config.opt_string("opengl-version");
         if (std::find(Slic3r::GUI::OpenGLVersions::core_str.begin(), Slic3r::GUI::OpenGLVersions::core_str.end(), opengl_version_str) == Slic3r::GUI::OpenGLVersions::core_str.end()) {
-            if (std::find(Slic3r::GUI::OpenGLVersions::precore_str.begin(), Slic3r::GUI::OpenGLVersions::precore_str.end(), opengl_version_str) == Slic3r::GUI::OpenGLVersions::precore_str.end()) {
-                boost::nowide::cerr << "Found invalid OpenGL version: " << opengl_version_str << std::endl;
-                opengl_version_str.clear();
-            }
+            boost::nowide::cerr << "Required OpenGL version " << opengl_version_str << " is invalid. Must be greater than or equal to 3.2" << std::endl;
+            opengl_version_str.clear();
         }
 
         if (!opengl_version_str.empty()) {
@@ -203,12 +200,20 @@ int CLI::run(int argc, char **argv)
         m_actions.erase(it);
     }
 
+    it = std::find(m_actions.begin(), m_actions.end(), "opengl-compatibility");
+    if (it != m_actions.end()) {
+        start_gui = true;
+        opengl_compatibility_profile = true;
+        // reset version as compatibility profile always take the highest version
+        // supported by the graphic card
+        opengl_version = std::make_pair(0, 0);
+        m_actions.erase(it);
+    }
+
     it = std::find(m_actions.begin(), m_actions.end(), "opengl-debug");
     if (it != m_actions.end()) {
         start_gui = true;
-#if ENABLE_OPENGL_DEBUG_OPTION
         opengl_debug = true;
-#endif // ENABLE_OPENGL_DEBUG_OPTION
         m_actions.erase(it);
     }
 #else
@@ -224,7 +229,7 @@ int CLI::run(int argc, char **argv)
 #endif // ENABLE_GL_CORE_PROFILE
 #else // SLIC3R_GUI
     // If there is no GUI, we shall ignore the parameters. Remove them from the list.
-    for (const std::string& s : { "opengl-version", "opengl-debug", "gcodeviewer" }) {
+    for (const std::string& s : { "opengl-version", "opengl-compatibility", "opengl-debug", "gcodeviewer" }) {
         auto it = std::find(m_actions.cbegin(), m_actions.cend(), s);
         if (it != m_actions.end()) {
             boost::nowide::cerr << "Parameter '" << s << "' is ignored, this PrusaSlicer build is CLI only." << std::endl;
@@ -714,10 +719,9 @@ int CLI::run(int argc, char **argv)
         params.download_url = download_url;
         params.delete_after_load = delete_after_load;
 #if ENABLE_GL_CORE_PROFILE
-#if ENABLE_OPENGL_DEBUG_OPTION
         params.opengl_version = opengl_version;
         params.opengl_debug = opengl_debug;
-#endif // ENABLE_OPENGL_DEBUG_OPTION
+        params.opengl_compatibiity_profile = opengl_compatibility_profile;
 #endif // ENABLE_GL_CORE_PROFILE
         return Slic3r::GUI::GUI_Run(params);
 #else // SLIC3R_GUI

+ 1 - 1
src/PrusaSlicer_app_msvc.cpp

@@ -266,7 +266,7 @@ int wmain(int argc, wchar_t **argv)
         // In that case, use Mesa.
         (::GetSystemMetrics(SM_REMOTESESSION) && !force_hw) ||
         // Try to load the default OpenGL driver and test its context version.
-        ! opengl_version_check.load_opengl_dll() || ! opengl_version_check.is_version_greater_or_equal_to(2, 0);
+        ! opengl_version_check.load_opengl_dll() || ! opengl_version_check.is_version_greater_or_equal_to(3, 2);
 #endif /* SLIC3R_GUI */
 
     wchar_t path_to_exe[MAX_PATH + 1] = { 0 };

+ 7 - 1
src/libslic3r/PrintConfig.cpp

@@ -4889,9 +4889,15 @@ CLIActionsConfigDef::CLIActionsConfigDef()
     def->cli = "opengl-version";
     def->set_default_value(new ConfigOptionString());
 
+    def = this->add("opengl-compatibility", coBool);
+    def->label = L("OpenGL compatibility profile");
+    def->tooltip = L("Enable OpenGL compatibility profile");
+    def->cli = "opengl-compatibility";
+    def->set_default_value(new ConfigOptionBool(false));
+
     def = this->add("opengl-debug", coBool);
     def->label = L("OpenGL debug output");
-    def->tooltip = L("Activate OpenGL debug output on graphic cards which support it");
+    def->tooltip = L("Activate OpenGL debug output on graphic cards which support it (OpenGL 4.3 or higher)");
     def->cli = "opengl-debug";
     def->set_default_value(new ConfigOptionBool(false));
 #endif // ENABLE_GL_CORE_PROFILE

+ 0 - 2
src/libslic3r/Technologies.hpp

@@ -55,8 +55,6 @@
 #define ENABLE_OPENGL_ES 0
 // Enable OpenGL core profile context (tested against Mesa 20.1.8 on Windows)
 #define ENABLE_GL_CORE_PROFILE (1 && !ENABLE_OPENGL_ES)
-// Enable OpenGL debug messages using debug context
-#define ENABLE_OPENGL_DEBUG_OPTION (1 && ENABLE_GL_CORE_PROFILE)
 
 // Enable imgui dialog which allows to set the parameters used to export binarized gcode
 #define ENABLE_BINARIZED_GCODE_DEBUG_WINDOW 0

+ 1 - 5
src/slic3r/GUI/GUI_App.cpp

@@ -889,12 +889,8 @@ std::string GUI_App::get_gl_info(bool for_github)
 wxGLContext* GUI_App::init_glcontext(wxGLCanvas& canvas)
 {
 #if ENABLE_GL_CORE_PROFILE
-#if ENABLE_OPENGL_DEBUG_OPTION
     return m_opengl_mgr.init_glcontext(canvas, init_params != nullptr ? init_params->opengl_version : std::make_pair(0, 0),
-        init_params != nullptr ? init_params->opengl_debug : false);
-#else
-    return m_opengl_mgr.init_glcontext(canvas, init_params != nullptr ? init_params->opengl_version : std::make_pair(0, 0));
-#endif // ENABLE_OPENGL_DEBUG_OPTION
+        init_params != nullptr ? init_params->opengl_compatibiity_profile : false, init_params != nullptr ? init_params->opengl_debug : false);
 #else
     return m_opengl_mgr.init_glcontext(canvas);
 #endif // ENABLE_GL_CORE_PROFILE

+ 6 - 7
src/slic3r/GUI/GUI_Init.hpp

@@ -33,15 +33,14 @@ struct GUI_InitParams
     DynamicPrintConfig          extra_config;
     std::vector<std::string>    input_files;
 
-	bool	                    start_as_gcodeviewer;
-	bool						start_downloader;
-	bool					    delete_after_load;
+    bool                        start_as_gcodeviewer;
+    bool                        start_downloader;
+    bool                        delete_after_load;
     std::string                 download_url;
 #if ENABLE_GL_CORE_PROFILE
-	std::pair<int, int>         opengl_version;
-#if ENABLE_OPENGL_DEBUG_OPTION
-	bool                        opengl_debug;
-#endif // ENABLE_OPENGL_DEBUG_OPTION
+		std::pair<int, int>         opengl_version;
+		bool                        opengl_debug;
+		bool                        opengl_compatibiity_profile;
 #endif // ENABLE_GL_CORE_PROFILE
 };
 

+ 40 - 50
src/slic3r/GUI/OpenGLManager.cpp

@@ -127,6 +127,10 @@ void OpenGLManager::GLInfo::detect() const
         float* max_anisotropy = const_cast<float*>(&m_max_anisotropy);
         glsafe(::glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy));
     }
+
+    if (!GLEW_ARB_compatibility)
+        *const_cast<bool*>(&m_core_profile) = true;
+
     *const_cast<bool*>(&m_detected) = true;
 }
 
@@ -197,7 +201,7 @@ std::string OpenGLManager::GLInfo::to_string(bool for_github) const
     std::string line_end = format_as_html ? "<br>" : "\n";
 
     out << h2_start << "OpenGL installation" << h2_end << line_end;
-    out << b_start << "GL version:   " << b_end << m_version << line_end;
+    out << b_start << "GL version:   " << b_end << m_version << " (" << m_version_string << ")" << line_end;
 #if ENABLE_GL_CORE_PROFILE
     out << b_start << "Profile:      " << b_end << (is_core_profile() ? "Core" : "Compatibility") << line_end;
 #endif // ENABLE_GL_CORE_PROFILE
@@ -287,14 +291,14 @@ OpenGLManager::~OpenGLManager()
 #endif //__APPLE__
 }
 
-#if ENABLE_OPENGL_DEBUG_OPTION
+#if ENABLE_GL_CORE_PROFILE
 #ifdef _WIN32
 static void APIENTRY CustomGLDebugOutput(GLenum source, GLenum type, unsigned int id, GLenum severity, GLsizei length, const char* message, const void* userParam)
 #else
 static void CustomGLDebugOutput(GLenum source, GLenum type, unsigned int id, GLenum severity, GLsizei length, const char* message, const void* userParam)
 #endif // _WIN32
 {
-    if (severity == GL_DEBUG_SEVERITY_NOTIFICATION)
+    if (severity != GL_DEBUG_SEVERITY_HIGH)
         return;
 
     std::string out = "OpenGL DEBUG message [";
@@ -331,7 +335,7 @@ static void CustomGLDebugOutput(GLenum source, GLenum type, unsigned int id, GLe
     out += "]:\n";
     std::cout << out << "(" << id << "): " << message << "\n\n";
 }
-#endif // ENABLE_OPENGL_DEBUG_OPTION
+#endif // ENABLE_GL_CORE_PROFILE
 
 bool OpenGLManager::init_gl()
 {
@@ -369,7 +373,7 @@ bool OpenGLManager::init_gl()
 #if ENABLE_OPENGL_ES
         bool valid_version = s_gl_info.is_version_greater_or_equal_to(2, 0);
 #elif ENABLE_GL_CORE_PROFILE
-        bool valid_version = s_gl_info.is_core_profile() ? s_gl_info.is_version_greater_or_equal_to(3, 2) : s_gl_info.is_version_greater_or_equal_to(2, 0);
+        const bool valid_version = s_gl_info.is_version_greater_or_equal_to(3, 2);
 #else
         bool valid_version = s_gl_info.is_version_greater_or_equal_to(2, 0);
 #endif // ENABLE_OPENGL_ES
@@ -379,16 +383,16 @@ bool OpenGLManager::init_gl()
             wxString message = format_wxstr(
 #if ENABLE_OPENGL_ES
                 _L("PrusaSlicer requires OpenGL ES 2.0 capable graphics driver to run correctly, \n"
-                    "while OpenGL version %s, render %s, vendor %s was detected."), s_gl_info.get_version_string(), s_gl_info.get_renderer(), s_gl_info.get_vendor());
+                   "while OpenGL version %s, render %s, vendor %s was detected."), s_gl_info.get_version_string(), s_gl_info.get_renderer(), s_gl_info.get_vendor());
 #elif ENABLE_GL_CORE_PROFILE
-                _L("PrusaSlicer requires OpenGL %s capable graphics driver to run correctly, \n"
-                    "while OpenGL version %s, render %s, vendor %s was detected."), (s_gl_info.is_core_profile() ? "3.3" : "2.0"), s_gl_info.get_version_string(), s_gl_info.get_renderer(), s_gl_info.get_vendor());
+                _L("PrusaSlicer requires OpenGL 3.2 capable graphics driver to run correctly,\n"
+                   "while OpenGL version %s, render %s, vendor %s was detected."), s_gl_info.get_version_string(), s_gl_info.get_renderer(), s_gl_info.get_vendor());
 #else
                 _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_string(), s_gl_info.get_renderer(), s_gl_info.get_vendor());
+                   "while OpenGL version %s, render %s, vendor %s was detected."), s_gl_info.get_version_string(), s_gl_info.get_renderer(), s_gl_info.get_vendor());
 #endif // ENABLE_OPENGL_ES
             message += "\n";
-        	message += _L("You may need to update your graphics card driver.");
+          	message += _L("You may need to update your graphics card driver.");
 #ifdef _WIN32
             message += "\n";
             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.");
@@ -403,14 +407,15 @@ bool OpenGLManager::init_gl()
                 wxString message = format_wxstr(_L("Unable to load the following shaders:\n%s"), error);
                 wxMessageBox(message, wxString("PrusaSlicer - ") + _L("Error loading shaders"), wxOK | wxICON_ERROR);
             }
-#if ENABLE_OPENGL_DEBUG_OPTION
-            if (m_debug_enabled && GLEW_KHR_debug) {
+#if ENABLE_GL_CORE_PROFILE
+            if (m_debug_enabled && s_gl_info.is_version_greater_or_equal_to(4, 3) && GLEW_KHR_debug) {
                 ::glEnable(GL_DEBUG_OUTPUT);
                 ::glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
                 ::glDebugMessageCallback(CustomGLDebugOutput, nullptr);
                 ::glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE);
+                std::cout << "Enabled OpenGL debug output\n";
             }
-#endif // ENABLE_OPENGL_DEBUG_OPTION
+#endif // ENABLE_GL_CORE_PROFILE
         }
 
 #ifdef _WIN32
@@ -437,11 +442,8 @@ bool OpenGLManager::init_gl()
 }
 
 #if ENABLE_GL_CORE_PROFILE
-#if ENABLE_OPENGL_DEBUG_OPTION
-wxGLContext* OpenGLManager::init_glcontext(wxGLCanvas& canvas, const std::pair<int, int>& required_opengl_version, bool enable_debug)
-#else
-wxGLContext* OpenGLManager::init_glcontext(wxGLCanvas& canvas, const std::pair<int, int>& required_opengl_version)
-#endif // ENABLE_OPENGL_DEBUG_OPTION
+wxGLContext* OpenGLManager::init_glcontext(wxGLCanvas& canvas, const std::pair<int, int>& required_opengl_version, bool enable_compatibility_profile,
+    bool enable_debug)
 #else
 wxGLContext* OpenGLManager::init_glcontext(wxGLCanvas& canvas)
 #endif // ENABLE_GL_CORE_PROFILE
@@ -452,33 +454,25 @@ wxGLContext* OpenGLManager::init_glcontext(wxGLCanvas& canvas)
         attrs.PlatformDefaults().ES2().MajorVersion(2).EndList();
         m_context = new wxGLContext(&canvas, nullptr, &attrs);
 #elif ENABLE_GL_CORE_PROFILE
-#if ENABLE_OPENGL_DEBUG_OPTION
         m_debug_enabled = enable_debug;
-#endif // ENABLE_OPENGL_DEBUG_OPTION
 
         const int gl_major = required_opengl_version.first;
         const int gl_minor = required_opengl_version.second;
         const bool supports_core_profile = (gl_major < 3) ? false : (gl_major > 3) ? true : gl_minor >= 2;
 
-        if (gl_major == 0) {
+        if (gl_major == 0 && !enable_compatibility_profile) {
             // search for highest supported core profile version
             // disable wxWidgets logging to avoid showing the log dialog in case the following code fails generating a valid gl context
             wxLogNull logNo;
             for (auto v = OpenGLVersions::core.rbegin(); v != OpenGLVersions::core.rend(); ++v) {
                 wxGLContextAttrs attrs;
-#if ENABLE_OPENGL_DEBUG_OPTION
                 attrs.PlatformDefaults().MajorVersion(v->first).MinorVersion(v->second).CoreProfile().ForwardCompatible();
                 if (m_debug_enabled)
                     attrs.DebugCtx();
                 attrs.EndList();
-#else
-                attrs.PlatformDefaults().MajorVersion(gl_major).MinorVersion(gl_minor).CoreProfile().ForwardCompatible().EndList();
-#endif // ENABLE_OPENGL_DEBUG_OPTION
                 m_context = new wxGLContext(&canvas, nullptr, &attrs);
-                if (m_context->IsOK()) {
-                    s_gl_info.set_core_profile(true);
+                if (m_context->IsOK())
                     break;
-                }
                 else {
                     delete m_context;
                     m_context = nullptr;
@@ -487,45 +481,41 @@ wxGLContext* OpenGLManager::init_glcontext(wxGLCanvas& canvas)
         }
 
         if (m_context == nullptr) {
+            // search for requested compatibility profile version 
+            if (enable_compatibility_profile) {
+                // disable wxWidgets logging to avoid showing the log dialog in case the following code fails generating a valid gl context
+                wxLogNull logNo;
+                wxGLContextAttrs attrs;
+                attrs.PlatformDefaults().CompatibilityProfile();
+                if (m_debug_enabled)
+                    attrs.DebugCtx();
+                attrs.EndList();
+                m_context = new wxGLContext(&canvas, nullptr, &attrs);
+                if (!m_context->IsOK()) {
+                    delete m_context;
+                    m_context = nullptr;
+                }
+            }
             // search for requested core profile version 
-            if (supports_core_profile) {
+            else if (supports_core_profile) {
                 // disable wxWidgets logging to avoid showing the log dialog in case the following code fails generating a valid gl context
                 wxLogNull logNo;
                 wxGLContextAttrs attrs;
-#if ENABLE_OPENGL_DEBUG_OPTION
                 attrs.PlatformDefaults().MajorVersion(gl_major).MinorVersion(gl_minor).CoreProfile().ForwardCompatible();
                 if (m_debug_enabled)
                     attrs.DebugCtx();
                 attrs.EndList();
-#else
-                attrs.PlatformDefaults().MajorVersion(gl_major).MinorVersion(gl_minor).CoreProfile().ForwardCompatible().EndList();
-#endif // ENABLE_OPENGL_DEBUG_OPTION
                 m_context = new wxGLContext(&canvas, nullptr, &attrs);
                 if (!m_context->IsOK()) {
-                    BOOST_LOG_TRIVIAL(error) << "Unable to create context for required OpenGL " << gl_major << "." << gl_minor;
                     delete m_context;
                     m_context = nullptr;
                 }
-                else
-                    s_gl_info.set_core_profile(true);
             }
         }
 
-#if ENABLE_OPENGL_DEBUG_OPTION
-        if (m_context == nullptr) {
-            wxGLContextAttrs attrs;
-            attrs.PlatformDefaults();
-            if (m_debug_enabled)
-                attrs.DebugCtx();
-            attrs.EndList();
-            // if no valid context was created use the default one
-            m_context = new wxGLContext(&canvas, nullptr, &attrs);
-        }
-#else
         if (m_context == nullptr)
-            // if no valid context was created use the default one
-            m_context = new wxGLContext(&canvas);
-#endif // ENABLE_OPENGL_DEBUG_OPTION
+            // no valid context was created
+            throw Slic3r::RuntimeError("Unable to create context for OpenGL.");
 #else
         m_context = new wxGLContext(&canvas);
 #endif // ENABLE_OPENGL_ES

+ 3 - 11
src/slic3r/GUI/OpenGLManager.hpp

@@ -54,15 +54,13 @@ public:
         const std::string& get_renderer() const;
 
         bool is_core_profile() const { return m_core_profile; }
-        void set_core_profile(bool value) { m_core_profile = value; }
 
         bool is_mesa() const;
         bool is_es() const {
-            return
 #if ENABLE_OPENGL_ES
-                true;
+            return true;
 #else
-                false;
+            return false;
 #endif // ENABLE_OPENGL_ES
         }
 
@@ -104,9 +102,7 @@ private:
 
     bool m_gl_initialized{ false };
     wxGLContext* m_context{ nullptr };
-#if ENABLE_OPENGL_DEBUG_OPTION
     bool m_debug_enabled{ false };
-#endif // ENABLE_OPENGL_DEBUG_OPTION
     GLShadersManager m_shaders_manager;
     static GLInfo s_gl_info;
 #ifdef __APPLE__ 
@@ -125,11 +121,7 @@ public:
 
     bool init_gl();
 #if ENABLE_GL_CORE_PROFILE
-#if ENABLE_OPENGL_DEBUG_OPTION
-    wxGLContext* init_glcontext(wxGLCanvas& canvas, const std::pair<int, int>& required_opengl_version, bool enable_debug);
-#else
-    wxGLContext* init_glcontext(wxGLCanvas& canvas, const std::pair<int, int>& required_opengl_version);
-#endif // ENABLE_OPENGL_DEBUG_OPTION
+    wxGLContext* init_glcontext(wxGLCanvas& canvas, const std::pair<int, int>& required_opengl_version, bool enable_compatibility_profile, bool enable_debug);
 #else
     wxGLContext* init_glcontext(wxGLCanvas& canvas);
 #endif // ENABLE_GL_CORE_PROFILE