diff --git a/include/openspace/engine/configurationmanager.h b/include/openspace/engine/configurationmanager.h index 8ec3aa167d..e3a4279164 100644 --- a/include/openspace/engine/configurationmanager.h +++ b/include/openspace/engine/configurationmanager.h @@ -1,4 +1,4 @@ -/***************************************************************************************** +/***************************************************************************************** * * * OpenSpace * * * @@ -144,6 +144,11 @@ public: static const std::string PartFilterIdentifierIdentifier; /// The part of the key storing a list of severities that should be filtered out static const std::string PartFilterSeverity; + /// The part of the key storing whether the OpenGL state should be checked each call + static const std::string KeyCheckOpenGLState; + /// The part of the key storing whether each OpenGL call should be logged + static const std::string KeyLogEachOpenGLCall; + /** * Iteratively walks the directory structure starting with \p filename to find the diff --git a/openspace.cfg b/openspace.cfg index aea8c89557..f470afca71 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -74,6 +74,9 @@ return { Documentation = "${DOCUMENTATION}/Documentation.html", FactoryDocumentation = "${DOCUMENTATION}/FactoryDocumentation.html", + -- CheckOpenGLState = true, + -- LogEachOpenGLCall = true, + ShutdownCountdown = 3, -- OnScreenTextScaling = "framebuffer", -- PerSceneCache = true, diff --git a/src/engine/configurationmanager.cpp b/src/engine/configurationmanager.cpp index 17bb3e8afd..3fbf2d2c49 100644 --- a/src/engine/configurationmanager.cpp +++ b/src/engine/configurationmanager.cpp @@ -1,4 +1,4 @@ -/***************************************************************************************** +/***************************************************************************************** * * * OpenSpace * * * @@ -97,6 +97,8 @@ const string ConfigurationManager::PartFilterIdentifierSource = "Source"; const string ConfigurationManager::PartFilterIdentifierType = "Type"; const string ConfigurationManager::PartFilterIdentifierIdentifier = "Identifier"; const string ConfigurationManager::PartFilterSeverity = "PartFilterSeverity"; +const string ConfigurationManager::KeyCheckOpenGLState = "CheckOpenGLState"; +const string ConfigurationManager::KeyLogEachOpenGLCall = "LogEachOpenGLCall"; string ConfigurationManager::findConfiguration(const string& filename) { using ghoul::filesystem::Directory; diff --git a/src/engine/configurationmanager_doc.inl b/src/engine/configurationmanager_doc.inl index e955c50c75..fe1d4f35c3 100644 --- a/src/engine/configurationmanager_doc.inl +++ b/src/engine/configurationmanager_doc.inl @@ -1,4 +1,4 @@ -/***************************************************************************************** +/***************************************************************************************** * * * OpenSpace * * * @@ -383,6 +383,23 @@ documentation::Documentation ConfigurationManager::Documentation() { }), "Determines the settings for the creation of an OpenGL debug context.", Optional::Yes + }, + { + ConfigurationManager::KeyCheckOpenGLState, + new BoolVerifier, + "Determines whether the OpenGL state is checked after each OpenGL function " + "call. This will dramatically slow down the rendering, but will make finding " + "OpenGL errors easier. This defaults to 'false'.", + Optional::Yes + }, + { + ConfigurationManager::KeyLogEachOpenGLCall, + new BoolVerifier, + "Determines whether each OpenGL call that happens should be logged using the " + "'TRACE' loglevel. This will bring the rendering to a crawl but provides " + "useful debugging features for the order in which OpenGL calls occur. This " + "defaults to 'false'.", + Optional::Yes } } }; diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 0d226fb673..51149a9df4 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -1,4 +1,4 @@ -/***************************************************************************************** +/***************************************************************************************** * * * OpenSpace * * * @@ -59,6 +59,7 @@ #include #include +#include #include #include #include @@ -70,6 +71,7 @@ #include #include +#include #if defined(_MSC_VER) && defined(OPENSPACE_ENABLE_VLD) #include @@ -79,6 +81,8 @@ #include #endif +#include + #include "openspaceengine_lua.inl" using namespace openspace::scripting; @@ -978,6 +982,90 @@ void OpenSpaceEngine::initializeGL() { LTRACE("OpenSpaceEngine::initializeGL::DebugContext(end)"); } + // The ordering of the KeyCheckOpenGLState and KeyLogEachOpenGLCall are important as + // the callback mask in glbinding is stateful for each context, and since + // KeyLogEachOpenGLCall is more specific, we want it to be able to overwrite the + // state from KeyCheckOpenGLState + if (_configurationManager->hasKey(ConfigurationManager::KeyCheckOpenGLState)) { + const bool val = _configurationManager->value( + ConfigurationManager::KeyCheckOpenGLState + ); + + if (val) { + using namespace glbinding; + setCallbackMaskExcept(CallbackMask::After, { "glGetError" }); + setAfterCallback([](const FunctionCall& f) { + const GLenum error = glGetError(); + switch (error) { + case GL_NO_ERROR: + break; + case GL_INVALID_ENUM: + LERRORC( + "OpenGL Invalid State", + "Function " << f.toString() << ": GL_INVALID_ENUM" + ); + break; + case GL_INVALID_VALUE: + LERRORC( + "OpenGL Invalid State", + "Function " << f.toString() << ": GL_INVALID_VALUE" + ); + break; + case GL_INVALID_OPERATION: + LERRORC( + "OpenGL Invalid State", + "Function " << f.toString() << ": GL_INVALID_OPERATION" + ); + break; + case GL_INVALID_FRAMEBUFFER_OPERATION: + LERRORC( + "OpenGL Invalid State", + "Function " << f.toString() << + ": GL_INVALID_FRAMEBUFFER_OPERATION" + ); + break; + case GL_OUT_OF_MEMORY: + LERRORC( + "OpenGL Invalid State", + "Function " << f.toString() << ": GL_OUT_OF_MEMORY" + ); + break; + default: + LERRORC( + "OpenGL Invalid State", + "Unknown error code: " << std::hex << error + ); + } + }); + } + } + + if (_configurationManager->hasKey(ConfigurationManager::KeyLogEachOpenGLCall)) { + const bool val = _configurationManager->value( + ConfigurationManager::KeyLogEachOpenGLCall + ); + + if (val) { + using namespace glbinding; + setCallbackMask(CallbackMask::After | CallbackMask::ParametersAndReturnValue); + glbinding::setAfterCallback([](const glbinding::FunctionCall& call) { + std::string arguments = std::accumulate( + call.parameters.begin(), + call.parameters.end(), + std::string("("), + [](std::string a, AbstractValue* v) { + return a + ", " + v->asString(); + } + ); + + std::string returnValue = call.returnValue ? + " -> " + call.returnValue->asString() : + ""; + + LTRACEC("OpenGL", call.function->name() << arguments << returnValue); + }); + } + } LINFO("Initializing Rendering Engine"); _renderEngine->initializeGL();