mirror of https://github.com/mosra/magnum.git
Browse Source
Had to rework the API a bit, the original one (everything through DebugMessage) should be still available, but marked as deprecated (and will be removed in some future release). The whole cycle of reading up on a feature, understanding the feature, understanding the bigger concept under the feature and then having understood everything so thoroughly so I can document the functionality is time consuming.pull/89/head
17 changed files with 1580 additions and 829 deletions
@ -1,241 +0,0 @@
|
||||
/*
|
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014, 2015 |
||||
Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a |
||||
copy of this software and associated documentation files (the "Software"), |
||||
to deal in the Software without restriction, including without limitation |
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
and/or sell copies of the Software, and to permit persons to whom the |
||||
Software is furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included |
||||
in all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||
DEALINGS IN THE SOFTWARE. |
||||
*/ |
||||
|
||||
#include "DebugMessage.h" |
||||
|
||||
#include <Corrade/Utility/Assert.h> |
||||
|
||||
#include "Magnum/Context.h" |
||||
#include "Magnum/Extensions.h" |
||||
#include "Magnum/Implementation/State.h" |
||||
#include "Magnum/Implementation/DebugState.h" |
||||
|
||||
namespace Magnum { |
||||
|
||||
namespace { |
||||
|
||||
#if !defined(CORRADE_TARGET_EMSCRIPTEN) && !defined(CORRADE_TARGET_NACL) |
||||
void |
||||
#ifdef CORRADE_TARGET_WINDOWS |
||||
APIENTRY |
||||
#endif |
||||
callbackWrapper(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) { |
||||
Context::current()->state().debug->messageCallback(DebugMessage::Source(source), DebugMessage::Type(type), id, DebugMessage::Severity(severity), std::string(message, length), userParam); |
||||
} |
||||
#endif |
||||
|
||||
void defaultCallback(const DebugMessage::Source source, const DebugMessage::Type type, const UnsignedInt id, const DebugMessage::Severity severity, const std::string& string, const void*) { |
||||
switch(severity) { |
||||
case DebugMessage::Severity::High: |
||||
Error() << source << type << id << severity << "\n " << string; |
||||
break; |
||||
|
||||
case DebugMessage::Severity::Medium: |
||||
case DebugMessage::Severity::Low: |
||||
Warning() << source << type << id << severity << "\n " << string; |
||||
break; |
||||
|
||||
default: Debug() << source << type << id << severity << "\n " << string; |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
Int DebugMessage::maxLoggedMessages() { |
||||
if(!Context::current()->isExtensionSupported<Extensions::GL::KHR::debug>()) |
||||
return 0; |
||||
|
||||
GLint& value = Context::current()->state().debug->maxLoggedMessages; |
||||
|
||||
if(value == 0) { |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
glGetIntegerv(GL_MAX_DEBUG_LOGGED_MESSAGES, &value); |
||||
#else |
||||
glGetIntegerv(GL_MAX_DEBUG_LOGGED_MESSAGES_KHR, &value); |
||||
#endif |
||||
} |
||||
|
||||
return value; |
||||
} |
||||
|
||||
Int DebugMessage::maxMessageLength() { |
||||
if(!Context::current()->isExtensionSupported<Extensions::GL::KHR::debug>()) |
||||
return 0; |
||||
|
||||
GLint& value = Context::current()->state().debug->maxMessageLength; |
||||
|
||||
if(value == 0) { |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
glGetIntegerv(GL_MAX_DEBUG_MESSAGE_LENGTH, &value); |
||||
#else |
||||
glGetIntegerv(GL_MAX_DEBUG_MESSAGE_LENGTH_KHR, &value); |
||||
#endif |
||||
} |
||||
|
||||
return value; |
||||
} |
||||
|
||||
void DebugMessage::setCallback(const Callback callback, const void* userParam) { |
||||
Context::current()->state().debug->messageCallbackImplementation(callback, userParam); |
||||
} |
||||
|
||||
void DebugMessage::setDefaultCallback() { |
||||
setCallback(defaultCallback, nullptr); |
||||
} |
||||
|
||||
void DebugMessage::insertInternal(const Source source, const Type type, const UnsignedInt id, const Severity severity, const Containers::ArrayReference<const char> string) { |
||||
Context::current()->state().debug->messageInsertImplementation(source, type, id, severity, string); |
||||
} |
||||
|
||||
void DebugMessage::insertImplementationNoOp(Source, Type, UnsignedInt, Severity, const Containers::ArrayReference<const char>) {} |
||||
|
||||
void DebugMessage::insertImplementationKhr(const Source source, const Type type, const UnsignedInt id, const Severity severity, const Containers::ArrayReference<const char> string) { |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
glDebugMessageInsert(GLenum(source), GLenum(type), id, GLenum(severity), string.size(), string.data()); |
||||
#elif !defined(CORRADE_TARGET_EMSCRIPTEN) && !defined(CORRADE_TARGET_NACL) |
||||
glDebugMessageInsertKHR(GLenum(source), GLenum(type), id, GLenum(severity), string.size(), string.data()); |
||||
#else |
||||
static_cast<void>(source); |
||||
static_cast<void>(type); |
||||
static_cast<void>(id); |
||||
static_cast<void>(severity); |
||||
static_cast<void>(string); |
||||
CORRADE_ASSERT_UNREACHABLE(); |
||||
#endif |
||||
} |
||||
|
||||
void DebugMessage::insertImplementationExt(Source, Type, UnsignedInt, Severity, const Containers::ArrayReference<const char> string) { |
||||
#if !defined(CORRADE_TARGET_EMSCRIPTEN) && !defined(CORRADE_TARGET_NACL) |
||||
glInsertEventMarkerEXT(string.size(), string.data()); |
||||
#else |
||||
static_cast<void>(string); |
||||
CORRADE_ASSERT_UNREACHABLE(); |
||||
#endif |
||||
} |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES |
||||
void DebugMessage::insertImplementationGremedy(Source, Type, UnsignedInt, Severity, const Containers::ArrayReference<const char> string) { |
||||
glStringMarkerGREMEDY(string.size(), string.data()); |
||||
} |
||||
#endif |
||||
|
||||
void DebugMessage::setEnabledInternal(const GLenum source, const GLenum type, const GLenum severity, const std::initializer_list<UnsignedInt> ids, const bool enabled) { |
||||
Context::current()->state().debug->messageControlImplementation(source, type, severity, ids, enabled); |
||||
} |
||||
|
||||
void DebugMessage::controlImplementationNoOp(GLenum, GLenum, GLenum, std::initializer_list<UnsignedInt>, bool) {} |
||||
|
||||
void DebugMessage::controlImplementationKhr(const GLenum source, const GLenum type, const GLenum severity, const std::initializer_list<UnsignedInt> ids, const bool enabled) { |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
glDebugMessageControl(source, type, severity, ids.size(), ids.begin(), enabled); |
||||
#elif !defined(CORRADE_TARGET_EMSCRIPTEN) && !defined(CORRADE_TARGET_NACL) |
||||
glDebugMessageControlKHR(source, type, severity, ids.size(), ids.begin(), enabled); |
||||
#else |
||||
static_cast<void>(source); |
||||
static_cast<void>(type); |
||||
static_cast<void>(severity); |
||||
static_cast<void>(ids); |
||||
static_cast<void>(enabled); |
||||
CORRADE_ASSERT_UNREACHABLE(); |
||||
#endif |
||||
} |
||||
|
||||
void DebugMessage::callbackImplementationNoOp(Callback, const void*) {} |
||||
|
||||
void DebugMessage::callbackImplementationKhr(const Callback callback, const void* userParam) { |
||||
/* Replace the callback */ |
||||
const Callback original = Context::current()->state().debug->messageCallback; |
||||
Context::current()->state().debug->messageCallback = callback; |
||||
|
||||
/* Adding callback */ |
||||
if(!original && callback) { |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
glDebugMessageCallback(callbackWrapper, userParam); |
||||
#elif !defined(CORRADE_TARGET_EMSCRIPTEN) && !defined(CORRADE_TARGET_NACL) |
||||
glDebugMessageCallbackKHR(callbackWrapper, userParam); |
||||
#else |
||||
static_cast<void>(userParam); |
||||
CORRADE_ASSERT_UNREACHABLE(); |
||||
#endif |
||||
|
||||
/* Deleting callback */ |
||||
} else if(original && !callback) { |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
glDebugMessageCallback(nullptr, nullptr); |
||||
#elif !defined(CORRADE_TARGET_EMSCRIPTEN) && !defined(CORRADE_TARGET_NACL) |
||||
glDebugMessageCallbackKHR(nullptr, nullptr); |
||||
#else |
||||
CORRADE_ASSERT_UNREACHABLE(); |
||||
#endif |
||||
} |
||||
} |
||||
|
||||
#ifndef DOXYGEN_GENERATING_OUTPUT |
||||
Debug operator<<(Debug debug, const DebugMessage::Source value) { |
||||
switch(value) { |
||||
#define _c(value) case DebugMessage::Source::value: return debug << "DebugMessage::Source::" #value; |
||||
_c(Api) |
||||
_c(WindowSystem) |
||||
_c(ShaderCompiler) |
||||
_c(ThirdParty) |
||||
_c(Application) |
||||
_c(Other) |
||||
#undef _c |
||||
} |
||||
|
||||
return debug << "DebugMessage::Source::(invalid)"; |
||||
} |
||||
|
||||
Debug operator<<(Debug debug, const DebugMessage::Type value) { |
||||
switch(value) { |
||||
#define _c(value) case DebugMessage::Type::value: return debug << "DebugMessage::Type::" #value; |
||||
_c(Error) |
||||
_c(DeprecatedBehavior) |
||||
_c(UndefinedBehavior) |
||||
_c(Portability) |
||||
_c(Performance) |
||||
_c(Other) |
||||
_c(Marker) |
||||
#undef _c |
||||
} |
||||
|
||||
return debug << "DebugMessage::Type::(invalid)"; |
||||
} |
||||
|
||||
Debug operator<<(Debug debug, const DebugMessage::Severity value) { |
||||
switch(value) { |
||||
#define _c(value) case DebugMessage::Severity::value: return debug << "DebugMessage::Severity::" #value; |
||||
_c(High) |
||||
_c(Medium) |
||||
_c(Low) |
||||
_c(Notification) |
||||
#undef _c |
||||
} |
||||
|
||||
return debug << "DebugMessage::Severity::(invalid)"; |
||||
} |
||||
#endif |
||||
|
||||
} |
||||
@ -1,393 +0,0 @@
|
||||
#ifndef Magnum_DebugMessage_h |
||||
#define Magnum_DebugMessage_h |
||||
/*
|
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014, 2015 |
||||
Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a |
||||
copy of this software and associated documentation files (the "Software"), |
||||
to deal in the Software without restriction, including without limitation |
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
and/or sell copies of the Software, and to permit persons to whom the |
||||
Software is furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included |
||||
in all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||
DEALINGS IN THE SOFTWARE. |
||||
*/ |
||||
|
||||
/** @file
|
||||
* @brief Class @ref Magnum::DebugMessage |
||||
*/ |
||||
|
||||
#include <string> |
||||
#include <Corrade/Containers/Array.h> |
||||
|
||||
#include "Magnum/Magnum.h" |
||||
#include "Magnum/OpenGL.h" |
||||
#include "Magnum/visibility.h" |
||||
|
||||
namespace Magnum { |
||||
|
||||
namespace Implementation { struct DebugState; } |
||||
|
||||
/**
|
||||
@brief Debug message |
||||
|
||||
Allows retrieving and inserting debug messages from and to OpenGL command |
||||
stream, for example with conjunction with various debuggers, such as Apitrace |
||||
or gDEBugger. |
||||
|
||||
## Basic usage |
||||
|
||||
To retrieve debug messages from either the GL or your application you need to |
||||
have OpenGL 4.3 or @extension{KHR,debug} desktop/ES extension. You need to |
||||
enable @ref Renderer::Feature::DebugOutput and possibly also |
||||
@ref Renderer::Feature::DebugOutputSynchronous. Then set up message callback |
||||
using @ref setCallback() or use the default one provided in |
||||
@ref setDefaultCallback(): |
||||
|
||||
@code |
||||
Renderer::enable(Renderer::Feature::DebugOutput); |
||||
Renderer::enable(Renderer::Feature::DebugOutputSynchronous); |
||||
|
||||
DebugMessage::setDefaultCallback(); |
||||
DebugMessage::insert(DebugMessage::Source::Application, DebugMessage::Type::Marker, |
||||
1337, DebugMessage::Severity::Notification, "Hello from OpenGL command stream!"); |
||||
@endcode |
||||
|
||||
With default callback the messages will be printed on standard output: |
||||
|
||||
DebugMessage::Source::Application DebugMessage::Type::Marker -1 DebugMessage::Severity::Notification |
||||
Hello from OpenGL command stream! |
||||
*/ |
||||
class MAGNUM_EXPORT DebugMessage { |
||||
friend Implementation::DebugState; |
||||
|
||||
public: |
||||
/**
|
||||
* @brief Message source |
||||
* |
||||
* @see @ref insert(), @ref setCallback() |
||||
*/ |
||||
enum class Source: GLenum { |
||||
/** OpenGL */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
Api = GL_DEBUG_SOURCE_API, |
||||
#else |
||||
Api = GL_DEBUG_SOURCE_API_KHR, |
||||
#endif |
||||
|
||||
/** Window system (GLX, WGL) */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
WindowSystem = GL_DEBUG_SOURCE_WINDOW_SYSTEM, |
||||
#else |
||||
WindowSystem = GL_DEBUG_SOURCE_WINDOW_SYSTEM_KHR, |
||||
#endif |
||||
|
||||
/** Shader compiler */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
ShaderCompiler = GL_DEBUG_SOURCE_SHADER_COMPILER, |
||||
#else |
||||
ShaderCompiler = GL_DEBUG_SOURCE_SHADER_COMPILER_KHR, |
||||
#endif |
||||
|
||||
/** External debugger or third-party middleware */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
ThirdParty = GL_DEBUG_SOURCE_THIRD_PARTY, |
||||
#else |
||||
ThirdParty = GL_DEBUG_SOURCE_THIRD_PARTY_KHR, |
||||
#endif |
||||
|
||||
/** The application */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
Application = GL_DEBUG_SOURCE_APPLICATION, |
||||
#else |
||||
Application = GL_DEBUG_SOURCE_APPLICATION_KHR, |
||||
#endif |
||||
|
||||
/** Any other source */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
Other = GL_DEBUG_SOURCE_OTHER |
||||
#else |
||||
Other = GL_DEBUG_SOURCE_OTHER_KHR |
||||
#endif |
||||
}; |
||||
|
||||
/**
|
||||
* @brief Message type |
||||
* |
||||
* @see @ref insert(), @ref setCallback() |
||||
*/ |
||||
enum class Type: GLenum { |
||||
/** OpenGL error */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
Error = GL_DEBUG_TYPE_ERROR, |
||||
#else |
||||
Error = GL_DEBUG_TYPE_ERROR_KHR, |
||||
#endif |
||||
|
||||
/** Behavior that has been marked for deprecation */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
DeprecatedBehavior = GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, |
||||
#else |
||||
DeprecatedBehavior = GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_KHR, |
||||
#endif |
||||
|
||||
/** Behavior that is undefined according to the specification */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
UndefinedBehavior = GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR, |
||||
#else |
||||
UndefinedBehavior = GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_KHR, |
||||
#endif |
||||
|
||||
/** Non-portable usage of extensions or shaders */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
Portability = GL_DEBUG_TYPE_PORTABILITY, |
||||
#else |
||||
Portability = GL_DEBUG_TYPE_PORTABILITY_KHR, |
||||
#endif |
||||
|
||||
/** Implementation-dependent performance warning */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
Performance = GL_DEBUG_TYPE_PERFORMANCE, |
||||
#else |
||||
Performance = GL_DEBUG_TYPE_PERFORMANCE_KHR, |
||||
#endif |
||||
|
||||
/** Any other type */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
Other = GL_DEBUG_TYPE_OTHER, |
||||
#else |
||||
Other = GL_DEBUG_TYPE_OTHER_KHR, |
||||
#endif |
||||
|
||||
/** Annotation of the command stream */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
Marker = GL_DEBUG_TYPE_MARKER |
||||
#else |
||||
Marker = GL_DEBUG_TYPE_MARKER_KHR |
||||
#endif |
||||
}; |
||||
|
||||
/**
|
||||
* @brief Message severity |
||||
* |
||||
* @see @ref insert(), @ref setCallback() |
||||
*/ |
||||
enum class Severity: GLenum { |
||||
/**
|
||||
* Any OpenGL error, dangerous undefined behavior, shader |
||||
* compilation errors. |
||||
*/ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
High = GL_DEBUG_SEVERITY_HIGH, |
||||
#else |
||||
High = GL_DEBUG_SEVERITY_HIGH_KHR, |
||||
#endif |
||||
|
||||
/**
|
||||
* Severe performance warnings, shader compilation warnings, use of |
||||
* deprecated behavior. |
||||
*/ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
Medium = GL_DEBUG_SEVERITY_MEDIUM, |
||||
#else |
||||
Medium = GL_DEBUG_SEVERITY_MEDIUM_KHR, |
||||
#endif |
||||
|
||||
/** Minor performance warnings, trivial undefined behavior. */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
Low = GL_DEBUG_SEVERITY_LOW, |
||||
#else |
||||
Low = GL_DEBUG_SEVERITY_LOW_KHR, |
||||
#endif |
||||
|
||||
/** Any message other than error or performance warning. */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
Notification = GL_DEBUG_SEVERITY_NOTIFICATION |
||||
#else |
||||
Notification = GL_DEBUG_SEVERITY_NOTIFICATION_KHR |
||||
#endif |
||||
}; |
||||
|
||||
/**
|
||||
* @brief Debug callback |
||||
* |
||||
* @see @ref setCallback() |
||||
*/ |
||||
typedef void(*Callback)(Source, Type, UnsignedInt, Severity, const std::string&, const void*); |
||||
|
||||
/**
|
||||
* @brief Max count of debug messages in log |
||||
* |
||||
* The result is cached, repeated queries don't result in repeated |
||||
* OpenGL calls. If OpenGL 4.3 is not supported and @extension{KHR,debug} |
||||
* desktop or ES extension is not available, returns `0`. |
||||
* @see @fn_gl{Get} with @def_gl{MAX_DEBUG_LOGGED_MESSAGES} |
||||
*/ |
||||
static Int maxLoggedMessages(); |
||||
|
||||
/**
|
||||
* @brief Max debug message length |
||||
* |
||||
* The result is cached, repeated queries don't result in repeated |
||||
* OpenGL calls. If OpenGL 4.3 is not supported and @extension{KHR,debug} |
||||
* desktop or ES extension is not available, returns `0`. |
||||
* @see @fn_gl{Get} with @def_gl{MAX_DEBUG_MESSAGE_LENGTH} |
||||
*/ |
||||
static Int maxMessageLength(); |
||||
|
||||
/**
|
||||
* @brief Insert message |
||||
* @param source Message source. Allowed values are |
||||
* @ref Source::ThirdParty or @ref Source::Application. |
||||
* @param type Message type |
||||
* @param id Message-specific ID |
||||
* @param severity Message severity |
||||
* @param string The actual message |
||||
* |
||||
* If OpenGL 4.3 is not supported and none of @extension{KHR,debug}, |
||||
* @extension2{EXT,debug_marker} or @extension{GREMEDY,string_marker} |
||||
* is available, this function does nothing. |
||||
* |
||||
* If @extension{KHR,debug} is not available and only @extension2{EXT,debug_marker} |
||||
* or @extension{GREMEDY,string_marker} are available, only @p string |
||||
* is used and all other parameters are ignored. The call is then |
||||
* equivalent to the following: |
||||
* @code |
||||
* DebugMessage::insert(DebugMessage::Source::Application, |
||||
* DebugMessage::Type::Marker, 0, DebugMessage::Severity::Notification, string); |
||||
* @endcode |
||||
* |
||||
* @see @ref maxMessageLength(), @fn_gl{DebugMessageInsert}, |
||||
* @fn_gl_extension2{InsertEventMarker,EXT,debug_marker} or |
||||
* @fn_gl_extension{StringMarker,GREMEDY,string_marker} |
||||
*/ |
||||
static void insert(Source source, Type type, UnsignedInt id, Severity severity, const std::string& string) { |
||||
insertInternal(source, type, id, severity, {string.data(), string.size()}); |
||||
} |
||||
|
||||
/** @overload */ |
||||
template<std::size_t size> static void insert(Source source, Type type, UnsignedInt id, Severity severity, const char(&string)[size]) { |
||||
insertInternal(source, type, id, severity, {string, size - 1}); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Enable or disable particular message type |
||||
* |
||||
* @see @ref Renderer::Feature::DebugOutput, @fn_gl{DebugMessageControl} |
||||
*/ |
||||
static void setEnabled(Source source, Type type, std::initializer_list<UnsignedInt> ids, bool enabled) { |
||||
setEnabledInternal(GLenum(source), GLenum(type), GL_DONT_CARE, ids, enabled); |
||||
} |
||||
|
||||
/** @overload */ |
||||
static void setEnabled(Source source, Type type, Severity severity, bool enabled) { |
||||
setEnabledInternal(GLenum(source), GLenum(type), GLenum(severity), {}, enabled); |
||||
} |
||||
|
||||
/** @overload */ |
||||
static void setEnabled(Source source, Type type, bool enabled) { |
||||
setEnabledInternal(GLenum(source), GLenum(type), GL_DONT_CARE, {}, enabled); |
||||
} |
||||
|
||||
/** @overload */ |
||||
static void setEnabled(Source source, Severity severity, bool enabled) { |
||||
setEnabledInternal(GLenum(source), GL_DONT_CARE, GLenum(severity), {}, enabled); |
||||
} |
||||
|
||||
/** @overload */ |
||||
static void setEnabled(Source source, bool enabled) { |
||||
setEnabledInternal(GLenum(source), GL_DONT_CARE, GL_DONT_CARE, {}, enabled); |
||||
} |
||||
|
||||
/** @overload */ |
||||
static void setEnabled(Type type, Severity severity, bool enabled) { |
||||
setEnabledInternal(GL_DONT_CARE, GLenum(type), GLenum(severity), {}, enabled); |
||||
} |
||||
|
||||
/** @overload */ |
||||
static void setEnabled(Type type, bool enabled) { |
||||
setEnabledInternal(GL_DONT_CARE, GLenum(type), GL_DONT_CARE, {}, enabled); |
||||
} |
||||
|
||||
/** @overload */ |
||||
static void setEnabled(Severity severity, bool enabled) { |
||||
setEnabledInternal(GL_DONT_CARE, GL_DONT_CARE, GLenum(severity), {}, enabled); |
||||
} |
||||
|
||||
/** @overload */ |
||||
static void setEnabled(bool enabled) { |
||||
setEnabledInternal(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, {}, enabled); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Set debug message callback |
||||
* |
||||
* The messages are sent to the callback only if |
||||
* @ref Renderer::Feature::DebugOutput is enabled. If OpenGL 4.3 is not |
||||
* supported and @extension{KHR,debug} is not available, this function |
||||
* does nothing. |
||||
* @see @ref setDefaultCallback(), |
||||
* @ref Renderer::Feature::DebugOutputSynchronous, |
||||
* @fn_gl{DebugMessageCallback} |
||||
*/ |
||||
static void setCallback(Callback callback, const void* userParam = nullptr); |
||||
|
||||
/**
|
||||
* @brief Set default debug message callback |
||||
* |
||||
* See @ref setCallback() for more information. The message is printed |
||||
* to either @ref Corrade::Utility::Error "Error", @ref Corrade::Utility::Warning "Warning" |
||||
* or @ref Corrade::Utility::Debug "Debug" in the following format: |
||||
* @code |
||||
* DebugMessage::insert(DebugMessage::Source::Application, |
||||
* DebugMessage::Type::Marker, 1337, DebugMessage::Severity::Notification, "Hello from OpenGL command stream!"); |
||||
* @endcode |
||||
* |
||||
* > DebugMessage::Source::Application DebugMessage::Type::Marker -1 DebugMessage::Severity::Notification\n |
||||
* > Hello from OpenGL command stream! |
||||
*/ |
||||
static void setDefaultCallback(); |
||||
|
||||
DebugMessage() = delete; |
||||
|
||||
private: |
||||
static void insertInternal(Source source, Type type, UnsignedInt id, Severity severity, Containers::ArrayReference<const char> string); |
||||
static MAGNUM_LOCAL void insertImplementationNoOp(Source, Type, UnsignedInt, Severity, Containers::ArrayReference<const char>); |
||||
static MAGNUM_LOCAL void insertImplementationKhr(Source source, Type type, UnsignedInt id, Severity severity, Containers::ArrayReference<const char> string); |
||||
static MAGNUM_LOCAL void insertImplementationExt(Source, Type, UnsignedInt, Severity, Containers::ArrayReference<const char> string); |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
static MAGNUM_LOCAL void insertImplementationGremedy(Source, Type, UnsignedInt, Severity, Containers::ArrayReference<const char> string); |
||||
#endif |
||||
|
||||
static void setEnabledInternal(GLenum source, GLenum type, GLenum severity, std::initializer_list<UnsignedInt> ids, bool enabled); |
||||
static MAGNUM_LOCAL void controlImplementationNoOp(GLenum, GLenum, GLenum, std::initializer_list<UnsignedInt>, bool); |
||||
static MAGNUM_LOCAL void controlImplementationKhr(GLenum source, GLenum type, GLenum severity, std::initializer_list<UnsignedInt> ids, bool enabled); |
||||
|
||||
static MAGNUM_LOCAL void callbackImplementationNoOp(Callback, const void*); |
||||
static MAGNUM_LOCAL void callbackImplementationKhr(Callback callback, const void* userParam); |
||||
}; |
||||
|
||||
/** @debugoperatorclassenum{Magnum::DebugMessage,Magnum::DebugMessage::Source} */ |
||||
Debug MAGNUM_EXPORT operator<<(Debug debug, DebugMessage::Source value); |
||||
|
||||
/** @debugoperatorclassenum{Magnum::DebugMessage,Magnum::DebugMessage::Type} */ |
||||
Debug MAGNUM_EXPORT operator<<(Debug debug, DebugMessage::Type value); |
||||
|
||||
/** @debugoperatorclassenum{Magnum::DebugMessage,Magnum::DebugMessage::Severity} */ |
||||
Debug MAGNUM_EXPORT operator<<(Debug debug, DebugMessage::Severity value); |
||||
|
||||
} |
||||
|
||||
#endif |
||||
@ -0,0 +1,380 @@
|
||||
/*
|
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014, 2015 |
||||
Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a |
||||
copy of this software and associated documentation files (the "Software"), |
||||
to deal in the Software without restriction, including without limitation |
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
and/or sell copies of the Software, and to permit persons to whom the |
||||
Software is furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included |
||||
in all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||
DEALINGS IN THE SOFTWARE. |
||||
*/ |
||||
|
||||
#include "DebugOutput.h" |
||||
|
||||
#include <Corrade/Utility/Assert.h> |
||||
|
||||
#include "Magnum/Context.h" |
||||
#include "Magnum/Extensions.h" |
||||
#include "Magnum/Implementation/State.h" |
||||
#include "Magnum/Implementation/DebugState.h" |
||||
|
||||
namespace Magnum { |
||||
|
||||
namespace { |
||||
|
||||
#if !defined(CORRADE_TARGET_EMSCRIPTEN) && !defined(CORRADE_TARGET_NACL) |
||||
void |
||||
#ifdef CORRADE_TARGET_WINDOWS |
||||
APIENTRY |
||||
#endif |
||||
callbackWrapper(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) { |
||||
Context::current()->state().debug->messageCallback(DebugOutput::Source(source), DebugOutput::Type(type), id, DebugOutput::Severity(severity), std::string{message, std::size_t(length)}, userParam); |
||||
} |
||||
#endif |
||||
|
||||
void defaultCallback(const DebugOutput::Source source, const DebugOutput::Type type, const UnsignedInt id, const DebugOutput::Severity severity, const std::string& string, const void*) { |
||||
switch(severity) { |
||||
case DebugOutput::Severity::High: |
||||
Error() << source << type << id << severity << "\n " << string; |
||||
break; |
||||
|
||||
case DebugOutput::Severity::Medium: |
||||
case DebugOutput::Severity::Low: |
||||
Warning() << source << type << id << severity << "\n " << string; |
||||
break; |
||||
|
||||
default: Debug() << source << type << id << severity << "\n " << string; |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
Int DebugOutput::maxLoggedMessages() { |
||||
if(!Context::current()->isExtensionSupported<Extensions::GL::KHR::debug>()) |
||||
return 0; |
||||
|
||||
GLint& value = Context::current()->state().debug->maxLoggedMessages; |
||||
|
||||
if(value == 0) { |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
glGetIntegerv(GL_MAX_DEBUG_LOGGED_MESSAGES, &value); |
||||
#else |
||||
glGetIntegerv(GL_MAX_DEBUG_LOGGED_MESSAGES_KHR, &value); |
||||
#endif |
||||
} |
||||
|
||||
return value; |
||||
} |
||||
|
||||
Int DebugOutput::maxMessageLength() { |
||||
if(!Context::current()->isExtensionSupported<Extensions::GL::KHR::debug>()) |
||||
return 0; |
||||
|
||||
GLint& value = Context::current()->state().debug->maxMessageLength; |
||||
|
||||
if(value == 0) { |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
glGetIntegerv(GL_MAX_DEBUG_MESSAGE_LENGTH, &value); |
||||
#else |
||||
glGetIntegerv(GL_MAX_DEBUG_MESSAGE_LENGTH_KHR, &value); |
||||
#endif |
||||
} |
||||
|
||||
return value; |
||||
} |
||||
|
||||
void DebugOutput::setCallback(const Callback callback, const void* userParam) { |
||||
Context::current()->state().debug->callbackImplementation(callback, userParam); |
||||
} |
||||
|
||||
void DebugOutput::setDefaultCallback() { |
||||
setCallback(defaultCallback, nullptr); |
||||
} |
||||
|
||||
void DebugOutput::setEnabledInternal(const GLenum source, const GLenum type, const GLenum severity, const std::initializer_list<UnsignedInt> ids, const bool enabled) { |
||||
Context::current()->state().debug->controlImplementation(source, type, severity, ids, enabled); |
||||
} |
||||
|
||||
void DebugOutput::controlImplementationNoOp(GLenum, GLenum, GLenum, std::initializer_list<UnsignedInt>, bool) {} |
||||
|
||||
void DebugOutput::controlImplementationKhr(const GLenum source, const GLenum type, const GLenum severity, const std::initializer_list<UnsignedInt> ids, const bool enabled) { |
||||
#if !defined(CORRADE_TARGET_EMSCRIPTEN) && !defined(CORRADE_TARGET_NACL) |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
glDebugMessageControl |
||||
#else |
||||
glDebugMessageControlKHR |
||||
#endif |
||||
(source, type, severity, ids.size(), ids.begin(), enabled); |
||||
#else |
||||
static_cast<void>(source); |
||||
static_cast<void>(type); |
||||
static_cast<void>(severity); |
||||
static_cast<void>(ids); |
||||
static_cast<void>(enabled); |
||||
CORRADE_ASSERT_UNREACHABLE(); |
||||
#endif |
||||
} |
||||
|
||||
void DebugOutput::callbackImplementationNoOp(Callback, const void*) {} |
||||
|
||||
void DebugOutput::callbackImplementationKhr(const Callback callback, const void* userParam) { |
||||
/* Replace the callback */ |
||||
const Callback original = Context::current()->state().debug->messageCallback; |
||||
Context::current()->state().debug->messageCallback = callback; |
||||
|
||||
/* Adding callback */ |
||||
if(!original && callback) { |
||||
#if !defined(CORRADE_TARGET_EMSCRIPTEN) && !defined(CORRADE_TARGET_NACL) |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
glDebugMessageCallback |
||||
#else |
||||
glDebugMessageCallbackKHR |
||||
#endif |
||||
(callbackWrapper, userParam); |
||||
#else |
||||
static_cast<void>(userParam); |
||||
CORRADE_ASSERT_UNREACHABLE(); |
||||
#endif |
||||
|
||||
/* Deleting callback */ |
||||
} else if(original && !callback) { |
||||
#if !defined(CORRADE_TARGET_EMSCRIPTEN) && !defined(CORRADE_TARGET_NACL) |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
glDebugMessageCallback |
||||
#else |
||||
glDebugMessageCallbackKHR |
||||
#endif |
||||
(nullptr, nullptr); |
||||
#else |
||||
CORRADE_ASSERT_UNREACHABLE(); |
||||
#endif |
||||
} |
||||
} |
||||
|
||||
#ifndef DOXYGEN_GENERATING_OUTPUT |
||||
Debug operator<<(Debug debug, const DebugOutput::Source value) { |
||||
switch(value) { |
||||
#define _c(value) case DebugOutput::Source::value: return debug << "DebugOutput::Source::" #value; |
||||
_c(Api) |
||||
_c(WindowSystem) |
||||
_c(ShaderCompiler) |
||||
_c(ThirdParty) |
||||
_c(Application) |
||||
_c(Other) |
||||
#undef _c |
||||
} |
||||
|
||||
return debug << "DebugOutput::Source::(invalid)"; |
||||
} |
||||
|
||||
Debug operator<<(Debug debug, const DebugOutput::Type value) { |
||||
switch(value) { |
||||
#define _c(value) case DebugOutput::Type::value: return debug << "DebugOutput::Type::" #value; |
||||
_c(Error) |
||||
_c(DeprecatedBehavior) |
||||
_c(UndefinedBehavior) |
||||
_c(Portability) |
||||
_c(Performance) |
||||
_c(Marker) |
||||
_c(PushGroup) |
||||
_c(PopGroup) |
||||
_c(Other) |
||||
#undef _c |
||||
} |
||||
|
||||
return debug << "DebugOutput::Type::(invalid)"; |
||||
} |
||||
|
||||
Debug operator<<(Debug debug, const DebugOutput::Severity value) { |
||||
switch(value) { |
||||
#define _c(value) case DebugOutput::Severity::value: return debug << "DebugOutput::Severity::" #value; |
||||
_c(High) |
||||
_c(Medium) |
||||
_c(Low) |
||||
_c(Notification) |
||||
#undef _c |
||||
} |
||||
|
||||
return debug << "DebugOutput::Severity::(invalid)"; |
||||
} |
||||
#endif |
||||
|
||||
void DebugMessage::insertInternal(const Source source, const Type type, const UnsignedInt id, const DebugOutput::Severity severity, const Containers::ArrayReference<const char> string) { |
||||
Context::current()->state().debug->messageInsertImplementation(source, type, id, severity, string); |
||||
} |
||||
|
||||
void DebugMessage::insertImplementationNoOp(Source, Type, UnsignedInt, DebugOutput::Severity, const Containers::ArrayReference<const char>) {} |
||||
|
||||
void DebugMessage::insertImplementationKhr(const Source source, const Type type, const UnsignedInt id, const DebugOutput::Severity severity, const Containers::ArrayReference<const char> string) { |
||||
#if !defined(CORRADE_TARGET_EMSCRIPTEN) && !defined(CORRADE_TARGET_NACL) |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
glDebugMessageInsert |
||||
#else |
||||
glDebugMessageInsertKHR |
||||
#endif |
||||
(GLenum(source), GLenum(type), id, GLenum(severity), string.size(), string.data()); |
||||
#else |
||||
static_cast<void>(source); |
||||
static_cast<void>(type); |
||||
static_cast<void>(id); |
||||
static_cast<void>(severity); |
||||
static_cast<void>(string); |
||||
CORRADE_ASSERT_UNREACHABLE(); |
||||
#endif |
||||
} |
||||
|
||||
void DebugMessage::insertImplementationExt(Source, Type, UnsignedInt, DebugOutput::Severity, const Containers::ArrayReference<const char> string) { |
||||
#if !defined(CORRADE_TARGET_EMSCRIPTEN) && !defined(CORRADE_TARGET_NACL) |
||||
glInsertEventMarkerEXT(string.size(), string.data()); |
||||
#else |
||||
static_cast<void>(string); |
||||
CORRADE_ASSERT_UNREACHABLE(); |
||||
#endif |
||||
} |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES |
||||
void DebugMessage::insertImplementationGremedy(Source, Type, UnsignedInt, DebugOutput::Severity, const Containers::ArrayReference<const char> string) { |
||||
glStringMarkerGREMEDY(string.size(), string.data()); |
||||
} |
||||
#endif |
||||
|
||||
#ifndef DOXYGEN_GENERATING_OUTPUT |
||||
Debug operator<<(Debug debug, const DebugMessage::Source value) { |
||||
switch(value) { |
||||
#define _c(value) case DebugMessage::Source::value: return debug << "DebugMessage::Source::" #value; |
||||
_c(ThirdParty) |
||||
_c(Application) |
||||
#undef _c |
||||
#ifdef MAGNUM_BUILD_DEPRECATED |
||||
case DebugMessage::Source::Api: |
||||
case DebugMessage::Source::WindowSystem: |
||||
case DebugMessage::Source::ShaderCompiler: |
||||
case DebugMessage::Source::Other: |
||||
return debug << DebugOutput::Source(value); |
||||
#endif |
||||
} |
||||
|
||||
return debug << "DebugMessage::Source::(invalid)"; |
||||
} |
||||
|
||||
Debug operator<<(Debug debug, const DebugMessage::Type value) { |
||||
switch(value) { |
||||
#define _c(value) case DebugMessage::Type::value: return debug << "DebugMessage::Type::" #value; |
||||
_c(Error) |
||||
_c(DeprecatedBehavior) |
||||
_c(UndefinedBehavior) |
||||
_c(Portability) |
||||
_c(Performance) |
||||
_c(Other) |
||||
_c(Marker) |
||||
#undef _c |
||||
} |
||||
|
||||
return debug << "DebugMessage::Type::(invalid)"; |
||||
} |
||||
#endif |
||||
|
||||
Int DebugGroup::maxStackDepth() { |
||||
if(!Context::current()->isExtensionSupported<Extensions::GL::KHR::debug>()) |
||||
return 0; |
||||
|
||||
GLint& value = Context::current()->state().debug->maxStackDepth; |
||||
|
||||
if(value == 0) { |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
glGetIntegerv(GL_MAX_DEBUG_GROUP_STACK_DEPTH, &value); |
||||
#else |
||||
glGetIntegerv(GL_MAX_DEBUG_GROUP_STACK_DEPTH_KHR, &value); |
||||
#endif |
||||
} |
||||
|
||||
return value; |
||||
} |
||||
|
||||
void DebugGroup::pushInternal(const Source source, const UnsignedInt id, const Containers::ArrayReference<const char> message) { |
||||
CORRADE_ASSERT(!_active, "DebugGroup::push(): group is already active", ); |
||||
Context::current()->state().debug->pushGroupImplementation(source, id, message); |
||||
_active = true; |
||||
} |
||||
|
||||
void DebugGroup::pop() { |
||||
CORRADE_ASSERT(_active, "DebugGroup::pop(): group is not active", ); |
||||
Context::current()->state().debug->popGroupImplementation(); |
||||
_active = false; |
||||
} |
||||
|
||||
void DebugGroup::pushImplementationNoOp(Source, UnsignedInt, Containers::ArrayReference<const char>) {} |
||||
|
||||
void DebugGroup::pushImplementationKhr(const Source source, const UnsignedInt id, const Containers::ArrayReference<const char> message) { |
||||
#if !defined(CORRADE_TARGET_EMSCRIPTEN) && !defined(CORRADE_TARGET_NACL) |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
glPushDebugGroup |
||||
#else |
||||
glPushDebugGroupKHR |
||||
#endif |
||||
(GLenum(source), id, message.size(), message.data()); |
||||
#else |
||||
static_cast<void>(source); |
||||
static_cast<void>(id); |
||||
static_cast<void>(message); |
||||
CORRADE_ASSERT_UNREACHABLE(); |
||||
#endif |
||||
} |
||||
|
||||
void DebugGroup::pushImplementationExt(Source, UnsignedInt, const Containers::ArrayReference<const char> message) { |
||||
#if !defined(CORRADE_TARGET_EMSCRIPTEN) && !defined(CORRADE_TARGET_NACL) |
||||
glPushGroupMarkerEXT(message.size(), message.data()); |
||||
#else |
||||
static_cast<void>(message); |
||||
CORRADE_ASSERT_UNREACHABLE(); |
||||
#endif |
||||
} |
||||
|
||||
void DebugGroup::popImplementationNoOp() {} |
||||
|
||||
void DebugGroup::popImplementationKhr() { |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
glPopDebugGroup(); |
||||
#elif !defined(CORRADE_TARGET_EMSCRIPTEN) && !defined(CORRADE_TARGET_NACL) |
||||
glPopDebugGroupKHR(); |
||||
#else |
||||
CORRADE_ASSERT_UNREACHABLE(); |
||||
#endif |
||||
} |
||||
|
||||
void DebugGroup::popImplementationExt() { |
||||
#if !defined(CORRADE_TARGET_EMSCRIPTEN) && !defined(CORRADE_TARGET_NACL) |
||||
glPopGroupMarkerEXT(); |
||||
#else |
||||
CORRADE_ASSERT_UNREACHABLE(); |
||||
#endif |
||||
} |
||||
|
||||
#ifndef DOXYGEN_GENERATING_OUTPUT |
||||
Debug operator<<(Debug debug, const DebugGroup::Source value) { |
||||
switch(value) { |
||||
#define _c(value) case DebugGroup::Source::value: return debug << "DebugGroup::Source::" #value; |
||||
_c(ThirdParty) |
||||
_c(Application) |
||||
#undef _c |
||||
} |
||||
|
||||
return debug << "DebugGroup::Source::(invalid)"; |
||||
} |
||||
#endif |
||||
|
||||
} |
||||
@ -0,0 +1,895 @@
|
||||
#ifndef Magnum_DebugOutput_h |
||||
#define Magnum_DebugOutput_h |
||||
/*
|
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014, 2015 |
||||
Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a |
||||
copy of this software and associated documentation files (the "Software"), |
||||
to deal in the Software without restriction, including without limitation |
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
and/or sell copies of the Software, and to permit persons to whom the |
||||
Software is furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included |
||||
in all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||
DEALINGS IN THE SOFTWARE. |
||||
*/ |
||||
|
||||
/** @file
|
||||
* @brief Class @ref Magnum::DebugOutput, @ref Magnum::DebugMessage, @ref Magnum::DebugGroup |
||||
*/ |
||||
|
||||
#include <string> |
||||
#include <Corrade/Containers/Array.h> |
||||
|
||||
#include "Magnum/Magnum.h" |
||||
#include "Magnum/OpenGL.h" |
||||
#include "Magnum/visibility.h" |
||||
|
||||
namespace Magnum { |
||||
|
||||
namespace Implementation { struct DebugState; } |
||||
|
||||
/**
|
||||
@brief Debug output |
||||
|
||||
Manages OpenGL debug output. The debug messages are emitted either from driver |
||||
(such as GL error descriptions and various performance and optimization hints) |
||||
or from third party software and the application itself using @ref DebugMessage |
||||
and @ref DebugGroup, which can be also used to mark various portions of command |
||||
stream in various graphics debuggers, such as Apitrace or gDEBugger. |
||||
|
||||
## Basic usage |
||||
|
||||
Support for debug output is provided by OpenGL 4.3 or @extension{KHR,debug} |
||||
(desktop/ES extension). Subset of the functionality is provided also by |
||||
@extension2{EXT,debug_marker} (desktop/ES extensions) or |
||||
@extension{GREMEDY,string_marker} (desktop only extension). |
||||
|
||||
With OpenGL 4.3 or @extension{KHR,debug} desktop/ES extension, the debug output |
||||
needs to be enabled first. It can be enabled globally using |
||||
@ref Platform::Sdl2Application::Configuration::Flag::Debug "Platform::*Application::Configuration::Flag::Debug" |
||||
when creating context or only for some portions of the code using |
||||
@ref Renderer::Feature::DebugOutput. If enabled globally, some OpenGL drivers |
||||
may provide additional debugging information. In addition to that you can |
||||
control the output at even finer granularity using @ref setEnabled(). |
||||
|
||||
You can gather the messages either through graphics debugger or in the |
||||
application itself by setting up message callback using @ref setCallback() or |
||||
@ref setDefaultCallback(). You might also want to enable |
||||
@ref Renderer::Feature::DebugOutputSynchronous. Example usage, completely with |
||||
@ref DebugGroup and @link DebugMessage @endlink: |
||||
|
||||
@code |
||||
Renderer::enable(Renderer::Feature::DebugOutput); |
||||
Renderer::enable(Renderer::Feature::DebugOutputSynchronous); |
||||
DebugOutput::setDefaultCallback(); |
||||
|
||||
// Disable rather spammy "Buffer detailed info" debug messages on NVidia drivers
|
||||
DebugOutput::setEnabled(DebugOutput::Source::Api, DebugOutput::Type::Other, {131185}, false); |
||||
|
||||
{ |
||||
DebugGroup group{DebugGroup::Source::Application, 42, "Scene rendering"}; |
||||
|
||||
DebugMessage::insert(DebugMessage::Source::Application, DebugMessage::Type::Marker, |
||||
1337, DebugOutput::Severity::Notification, "Rendering transparent mesh"); |
||||
|
||||
Renderer::enable(Renderer::Feature::Blending); |
||||
mesh.draw(shader); |
||||
Renderer::disable(Renderer::Feature::Blending); |
||||
|
||||
// ...
|
||||
} |
||||
@endcode |
||||
|
||||
With default callback the group entering/leaving and the inserted message (and |
||||
possibly also other messages) will be printed on standard output: |
||||
|
||||
> DebugOutput::Source::Application DebugOutput::Type::PushGroup 42 DebugOutput::Severity::Notification\n |
||||
> Scene rendering\n |
||||
> DebugOutput::Source::Application DebugOutput::Type::Marker 1337 DebugOutput::Severity::Notification\n |
||||
> Rendering transparent mesh\n |
||||
> ...\n |
||||
> DebugOutput::Source::Application DebugOutput::Type::PopGroup 42 DebugOutput::Severity::Notification\n |
||||
> Scene rendering |
||||
|
||||
If only @extension2{EXT,debug_marker} or @extension{GREMEDY,string_marker} are |
||||
supported, only user-inserted messages and debug groups are supported and they |
||||
can be seen only through graphics debugger. |
||||
|
||||
If OpenGL 4.3 is not supported and neither @extension{KHR,debug} nor |
||||
@extension2{EXT,debug_marker} nor @extension{GREMEDY,string_marker} are |
||||
available, all the functions are essentially a no-op. |
||||
|
||||
Besides inserting messages into GL command stream you can also annotate OpenGL |
||||
objects with labels. See @ref AbstractQuery::setLabel(), |
||||
@ref AbstractShaderProgram::setLabel(), @ref AbstractTexture::setLabel(), |
||||
@ref Buffer::setLabel(), @ref Framebuffer::setLabel(), @ref Mesh::setLabel(), |
||||
@ref Renderbuffer::setLabel(), @ref Shader::setLabel() and |
||||
@ref TransformFeedback::setLabel() for more information. |
||||
*/ |
||||
class MAGNUM_EXPORT DebugOutput { |
||||
friend Implementation::DebugState; |
||||
|
||||
public: |
||||
/**
|
||||
* @brief Message source |
||||
* |
||||
* @see @ref setEnabled() |
||||
*/ |
||||
enum class Source: GLenum { |
||||
/** OpenGL */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
Api = GL_DEBUG_SOURCE_API, |
||||
#else |
||||
Api = GL_DEBUG_SOURCE_API_KHR, |
||||
#endif |
||||
|
||||
/** Window system (GLX, WGL) */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
WindowSystem = GL_DEBUG_SOURCE_WINDOW_SYSTEM, |
||||
#else |
||||
WindowSystem = GL_DEBUG_SOURCE_WINDOW_SYSTEM_KHR, |
||||
#endif |
||||
|
||||
/** Shader compiler */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
ShaderCompiler = GL_DEBUG_SOURCE_SHADER_COMPILER, |
||||
#else |
||||
ShaderCompiler = GL_DEBUG_SOURCE_SHADER_COMPILER_KHR, |
||||
#endif |
||||
|
||||
/** External debugger or third-party middleware */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
ThirdParty = GL_DEBUG_SOURCE_THIRD_PARTY, |
||||
#else |
||||
ThirdParty = GL_DEBUG_SOURCE_THIRD_PARTY_KHR, |
||||
#endif |
||||
|
||||
/** The application */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
Application = GL_DEBUG_SOURCE_APPLICATION, |
||||
#else |
||||
Application = GL_DEBUG_SOURCE_APPLICATION_KHR, |
||||
#endif |
||||
|
||||
/** Any other source */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
Other = GL_DEBUG_SOURCE_OTHER |
||||
#else |
||||
Other = GL_DEBUG_SOURCE_OTHER_KHR |
||||
#endif |
||||
}; |
||||
|
||||
/**
|
||||
* @brief Message type |
||||
* |
||||
* @see @ref setEnabled() |
||||
*/ |
||||
enum class Type: GLenum { |
||||
/** OpenGL error */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
Error = GL_DEBUG_TYPE_ERROR, |
||||
#else |
||||
Error = GL_DEBUG_TYPE_ERROR_KHR, |
||||
#endif |
||||
|
||||
/** Behavior that has been marked for deprecation */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
DeprecatedBehavior = GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, |
||||
#else |
||||
DeprecatedBehavior = GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_KHR, |
||||
#endif |
||||
|
||||
/** Behavior that is undefined according to the specification */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
UndefinedBehavior = GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR, |
||||
#else |
||||
UndefinedBehavior = GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_KHR, |
||||
#endif |
||||
|
||||
/** Non-portable usage of extensions or shaders */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
Portability = GL_DEBUG_TYPE_PORTABILITY, |
||||
#else |
||||
Portability = GL_DEBUG_TYPE_PORTABILITY_KHR, |
||||
#endif |
||||
|
||||
/** Implementation-dependent performance warning */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
Performance = GL_DEBUG_TYPE_PERFORMANCE, |
||||
#else |
||||
Performance = GL_DEBUG_TYPE_PERFORMANCE_KHR, |
||||
#endif |
||||
|
||||
/** Annotation of the command stream */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
Marker = GL_DEBUG_TYPE_MARKER, |
||||
#else |
||||
Marker = GL_DEBUG_TYPE_MARKER_KHR, |
||||
#endif |
||||
|
||||
/** Entering a debug group */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
PushGroup = GL_DEBUG_TYPE_PUSH_GROUP, |
||||
#else |
||||
PushGroup = GL_DEBUG_TYPE_PUSH_GROUP_KHR, |
||||
#endif |
||||
|
||||
/** Leaving a debug group */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
PopGroup = GL_DEBUG_TYPE_POP_GROUP, |
||||
#else |
||||
PopGroup = GL_DEBUG_TYPE_POP_GROUP_KHR, |
||||
#endif |
||||
|
||||
/** Any other type */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
Other = GL_DEBUG_TYPE_OTHER, |
||||
#else |
||||
Other = GL_DEBUG_TYPE_OTHER_KHR, |
||||
#endif |
||||
}; |
||||
|
||||
/**
|
||||
* @brief Message severity |
||||
* |
||||
* @see @ref setEnabled() |
||||
*/ |
||||
enum class Severity: GLenum { |
||||
/**
|
||||
* Any OpenGL error, dangerous undefined behavior, shader |
||||
* compilation errors. |
||||
*/ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
High = GL_DEBUG_SEVERITY_HIGH, |
||||
#else |
||||
High = GL_DEBUG_SEVERITY_HIGH_KHR, |
||||
#endif |
||||
|
||||
/**
|
||||
* Severe performance warnings, shader compilation warnings, use of |
||||
* deprecated behavior. |
||||
*/ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
Medium = GL_DEBUG_SEVERITY_MEDIUM, |
||||
#else |
||||
Medium = GL_DEBUG_SEVERITY_MEDIUM_KHR, |
||||
#endif |
||||
|
||||
/** Minor performance warnings, trivial undefined behavior. */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
Low = GL_DEBUG_SEVERITY_LOW, |
||||
#else |
||||
Low = GL_DEBUG_SEVERITY_LOW_KHR, |
||||
#endif |
||||
|
||||
/** Any message other than error or performance warning. */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
Notification = GL_DEBUG_SEVERITY_NOTIFICATION |
||||
#else |
||||
Notification = GL_DEBUG_SEVERITY_NOTIFICATION_KHR |
||||
#endif |
||||
}; |
||||
|
||||
/**
|
||||
* @brief Debug callback |
||||
* |
||||
* @see @ref setCallback() |
||||
*/ |
||||
typedef void(*Callback)(Source, Type, UnsignedInt, Severity, const std::string&, const void*); |
||||
|
||||
/**
|
||||
* @brief Max count of debug messages in log |
||||
* |
||||
* The result is cached, repeated queries don't result in repeated |
||||
* OpenGL calls. If OpenGL 4.3 is not supported and @extension{KHR,debug} |
||||
* desktop or ES extension is not available, returns `0`. |
||||
* @see @fn_gl{Get} with @def_gl{MAX_DEBUG_LOGGED_MESSAGES} |
||||
*/ |
||||
static Int maxLoggedMessages(); |
||||
|
||||
/**
|
||||
* @brief Max debug message length |
||||
* |
||||
* The result is cached, repeated queries don't result in repeated |
||||
* OpenGL calls. If OpenGL 4.3 is not supported and @extension{KHR,debug} |
||||
* desktop or ES extension is not available, returns `0`. |
||||
* @see @fn_gl{Get} with @def_gl{MAX_DEBUG_MESSAGE_LENGTH} |
||||
*/ |
||||
static Int maxMessageLength(); |
||||
|
||||
/**
|
||||
* @brief Enable or disable particular output type |
||||
* |
||||
* @attention If any @ref DebugGroup is active when making this call, |
||||
* the setting will be remembered only for the time in which the |
||||
* group is active and leaving it will revert the setting to state |
||||
* set in parent debug group. See @ref DebugGroup documentation |
||||
* for more information. |
||||
* |
||||
* If OpenGL 4.3 is not supported and @extension{KHR,debug} desktop or |
||||
* ES extension is not available, this function does nothing. |
||||
* @see @ref Renderer::Feature::DebugOutput, @fn_gl{DebugMessageControl} |
||||
*/ |
||||
static void setEnabled(Source source, Type type, std::initializer_list<UnsignedInt> ids, bool enabled) { |
||||
setEnabledInternal(GLenum(source), GLenum(type), GL_DONT_CARE, ids, enabled); |
||||
} |
||||
|
||||
/** @overload */ |
||||
static void setEnabled(Source source, Type type, Severity severity, bool enabled) { |
||||
setEnabledInternal(GLenum(source), GLenum(type), GLenum(severity), {}, enabled); |
||||
} |
||||
|
||||
/** @overload */ |
||||
static void setEnabled(Source source, Type type, bool enabled) { |
||||
setEnabledInternal(GLenum(source), GLenum(type), GL_DONT_CARE, {}, enabled); |
||||
} |
||||
|
||||
/** @overload */ |
||||
static void setEnabled(Source source, Severity severity, bool enabled) { |
||||
setEnabledInternal(GLenum(source), GL_DONT_CARE, GLenum(severity), {}, enabled); |
||||
} |
||||
|
||||
/** @overload */ |
||||
static void setEnabled(Source source, bool enabled) { |
||||
setEnabledInternal(GLenum(source), GL_DONT_CARE, GL_DONT_CARE, {}, enabled); |
||||
} |
||||
|
||||
/** @overload */ |
||||
static void setEnabled(Type type, Severity severity, bool enabled) { |
||||
setEnabledInternal(GL_DONT_CARE, GLenum(type), GLenum(severity), {}, enabled); |
||||
} |
||||
|
||||
/** @overload */ |
||||
static void setEnabled(Type type, bool enabled) { |
||||
setEnabledInternal(GL_DONT_CARE, GLenum(type), GL_DONT_CARE, {}, enabled); |
||||
} |
||||
|
||||
/** @overload */ |
||||
static void setEnabled(Severity severity, bool enabled) { |
||||
setEnabledInternal(GL_DONT_CARE, GL_DONT_CARE, GLenum(severity), {}, enabled); |
||||
} |
||||
|
||||
/** @overload */ |
||||
static void setEnabled(bool enabled) { |
||||
setEnabledInternal(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, {}, enabled); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Set debug message callback |
||||
* |
||||
* The messages are sent to the callback only if |
||||
* @ref Renderer::Feature::DebugOutput is enabled. If OpenGL 4.3 is not |
||||
* supported and @extension{KHR,debug} desktop or ES extension is not |
||||
* available, this function does nothing. |
||||
* @see @ref setDefaultCallback(), |
||||
* @ref Renderer::Feature::DebugOutputSynchronous, |
||||
* @fn_gl{DebugMessageCallback} |
||||
*/ |
||||
static void setCallback(Callback callback, const void* userParam = nullptr); |
||||
|
||||
/**
|
||||
* @brief Set default debug message callback |
||||
* |
||||
* See @ref setCallback() for more information. The message is printed |
||||
* to either @ref Corrade::Utility::Error "Error", @ref Corrade::Utility::Warning "Warning" |
||||
* or @ref Corrade::Utility::Debug "Debug" in the following format: |
||||
* @code |
||||
* DebugMessage::insert(DebugMessage::Source::Application, |
||||
* DebugMessage::Type::Marker, 1337, DebugOutput::Severity::Notification, "Hello from OpenGL command stream!"); |
||||
* @endcode |
||||
* |
||||
* > DebugOutput::Source::Application DebugOutput::Type::Marker 1337 DebugOutput::Severity::Notification\n |
||||
* > Hello from OpenGL command stream! |
||||
*/ |
||||
static void setDefaultCallback(); |
||||
|
||||
/** @brief There's no point in having an instance of this class */ |
||||
DebugOutput() = delete; |
||||
|
||||
private: |
||||
static void setEnabledInternal(GLenum source, GLenum type, GLenum severity, std::initializer_list<UnsignedInt> ids, bool enabled); |
||||
static MAGNUM_LOCAL void controlImplementationNoOp(GLenum, GLenum, GLenum, std::initializer_list<UnsignedInt>, bool); |
||||
static MAGNUM_LOCAL void controlImplementationKhr(GLenum source, GLenum type, GLenum severity, std::initializer_list<UnsignedInt> ids, bool enabled); |
||||
|
||||
static MAGNUM_LOCAL void callbackImplementationNoOp(Callback, const void*); |
||||
static MAGNUM_LOCAL void callbackImplementationKhr(Callback callback, const void* userParam); |
||||
}; |
||||
|
||||
/** @debugoperatorclassenum{Magnum::DebugOutput,Magnum::DebugOutput::Source} */ |
||||
Debug MAGNUM_EXPORT operator<<(Debug debug, DebugOutput::Source value); |
||||
|
||||
/** @debugoperatorclassenum{Magnum::DebugOutput,Magnum::DebugOutput::Type} */ |
||||
Debug MAGNUM_EXPORT operator<<(Debug debug, DebugOutput::Type value); |
||||
|
||||
/** @debugoperatorclassenum{Magnum::DebugOutput,Magnum::DebugOutput::Severity} */ |
||||
Debug MAGNUM_EXPORT operator<<(Debug debug, DebugOutput::Severity value); |
||||
|
||||
/**
|
||||
@brief Debug message |
||||
|
||||
Allows inserting messages GL command stream with labels, useful for example |
||||
with conjunction with various graphics debuggers, such as Apitrace or |
||||
gDEBugger. |
||||
|
||||
## Basic usage |
||||
|
||||
See @ref DebugOutput for introduction. |
||||
|
||||
If OpenGL 4.3 is supported or @extension{KHR,debug} desktop or ES extension is |
||||
available and default debug output callback is enabled for given kind of |
||||
messages, the inserted message will be printed on standard output in the |
||||
following form: |
||||
|
||||
@code |
||||
DebugMessage::insert(DebugMessage::Source::Application, DebugMessage::Type::Marker, |
||||
1337, DebugOutput::Severity::Notification, "Hello from OpenGL command stream!"); |
||||
@endcode |
||||
|
||||
> DebugOutput::Source::Application DebugOutput::Type::Marker 1337 DebugOutput::Severity::Notification\n |
||||
> Hello from OpenGL command stream! |
||||
|
||||
If only @extension2{EXT,debug_marker} or @extension{GREMEDY,string_marker} are |
||||
available, the message can be seen only through graphics debugger. |
||||
|
||||
If OpenGL 4.3 is not supported and neither @extension{KHR,debug} nor |
||||
@extension2{EXT,debug_marker} nor @extension{GREMEDY,string_marker} are |
||||
available, the function is essentially a no-op. |
||||
|
||||
## Performance notes |
||||
|
||||
If you ensure that you always use the `const char` overload of @ref insert() |
||||
and the debug output is either not supported or turned off, the calls will not |
||||
result in any allocations and thus won't have any negative performance effects. |
||||
|
||||
@see @ref DebugGroup |
||||
*/ |
||||
class MAGNUM_EXPORT DebugMessage { |
||||
friend Implementation::DebugState; |
||||
|
||||
public: |
||||
/**
|
||||
* @brief Message source |
||||
* |
||||
* @see @ref insert() |
||||
*/ |
||||
enum class Source: GLenum { |
||||
#ifdef MAGNUM_BUILD_DEPRECATED |
||||
/** @copydoc DebugOutput::Source::Api
|
||||
* @deprecated Use @ref DebugOutput::Source::Api instead. |
||||
*/ |
||||
Api = GLenum(DebugOutput::Source::Api), |
||||
|
||||
/** @copydoc DebugOutput::Source::WindowSystem
|
||||
* @deprecated Use @ref DebugOutput::Source::WindowSystem instead. |
||||
*/ |
||||
WindowSystem = GLenum(DebugOutput::Source::WindowSystem), |
||||
|
||||
/** @copydoc DebugOutput::Source::ShaderCompiler
|
||||
* @deprecated Use @ref DebugOutput::Source::ShaderCompiler instead. |
||||
*/ |
||||
ShaderCompiler = GLenum(DebugOutput::Source::ShaderCompiler), |
||||
#endif |
||||
|
||||
/** External debugger or third-party middleware */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
ThirdParty = GL_DEBUG_SOURCE_THIRD_PARTY, |
||||
#else |
||||
ThirdParty = GL_DEBUG_SOURCE_THIRD_PARTY_KHR, |
||||
#endif |
||||
|
||||
/** The application */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
Application = GL_DEBUG_SOURCE_APPLICATION, |
||||
#else |
||||
Application = GL_DEBUG_SOURCE_APPLICATION_KHR, |
||||
#endif |
||||
|
||||
#ifdef MAGNUM_BUILD_DEPRECATED |
||||
/** @copydoc DebugOutput::Source::Other
|
||||
* @deprecated Use @ref DebugOutput::Source::Other instead. |
||||
*/ |
||||
Other = GLenum(DebugOutput::Source::Other) |
||||
#endif |
||||
}; |
||||
|
||||
/**
|
||||
* @brief Message type |
||||
* |
||||
* @see @ref insert() |
||||
*/ |
||||
enum class Type: GLenum { |
||||
/** OpenGL error */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
Error = GL_DEBUG_TYPE_ERROR, |
||||
#else |
||||
Error = GL_DEBUG_TYPE_ERROR_KHR, |
||||
#endif |
||||
|
||||
/** Behavior that has been marked for deprecation */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
DeprecatedBehavior = GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, |
||||
#else |
||||
DeprecatedBehavior = GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_KHR, |
||||
#endif |
||||
|
||||
/** Behavior that is undefined according to the specification */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
UndefinedBehavior = GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR, |
||||
#else |
||||
UndefinedBehavior = GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_KHR, |
||||
#endif |
||||
|
||||
/** Non-portable usage of extensions or shaders */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
Portability = GL_DEBUG_TYPE_PORTABILITY, |
||||
#else |
||||
Portability = GL_DEBUG_TYPE_PORTABILITY_KHR, |
||||
#endif |
||||
|
||||
/** Implementation-dependent performance warning */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
Performance = GL_DEBUG_TYPE_PERFORMANCE, |
||||
#else |
||||
Performance = GL_DEBUG_TYPE_PERFORMANCE_KHR, |
||||
#endif |
||||
|
||||
/** Annotation of the command stream */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
Marker = GL_DEBUG_TYPE_MARKER, |
||||
#else |
||||
Marker = GL_DEBUG_TYPE_MARKER_KHR, |
||||
#endif |
||||
|
||||
/** Any other type */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
Other = GL_DEBUG_TYPE_OTHER |
||||
#else |
||||
Other = GL_DEBUG_TYPE_OTHER_KHR |
||||
#endif |
||||
}; |
||||
|
||||
#ifdef MAGNUM_BUILD_DEPRECATED |
||||
/** @copybrief DebugOutput::Severity
|
||||
* @deprecated Use @ref DebugOutput::Severity instead. |
||||
*/ |
||||
CORRADE_DEPRECATED("use DebugOutput::Severity instead") typedef DebugOutput::Severity Severity; |
||||
|
||||
/** @copybrief DebugOutput::Callback
|
||||
* @deprecated Use @ref DebugOutput::Callback instead. |
||||
*/ |
||||
/* Can't mark this as deprecated because compiler then complains when I use it as a parameter in setCallback() */ |
||||
typedef void(*Callback)(DebugMessage::Source, DebugMessage::Type, UnsignedInt, DebugOutput::Severity, const std::string&, const void*); |
||||
|
||||
/** @copybrief DebugOutput::maxLoggedMessages()
|
||||
* @deprecated Use @ref DebugOutput::maxLoggedMessages() instead. |
||||
*/ |
||||
CORRADE_DEPRECATED("use DebugOutput::maxLoggedMessages() instead") static Int maxLoggedMessages() { |
||||
return DebugOutput::maxLoggedMessages(); |
||||
} |
||||
|
||||
/** @copybrief DebugOutput::maxMessageLength()
|
||||
* @deprecated Use @ref DebugOutput::maxMessageLength() instead. |
||||
*/ |
||||
CORRADE_DEPRECATED("use DebugOutput::maxMessageLength() instead") static Int maxMessageLength() { |
||||
return DebugOutput::maxMessageLength(); |
||||
} |
||||
|
||||
/** @copybrief DebugOutput::setEnabled()
|
||||
* @deprecated Use @ref DebugOutput::setEnabled() instead. |
||||
*/ |
||||
#ifdef DOXYGEN_GENERATING_OUTPUT |
||||
template<class ...T> static void setEnabled(T... args); |
||||
#else |
||||
CORRADE_DEPRECATED("use DebugOutput::setEnabled() instead") static void setEnabled(Source source, Type type, std::initializer_list<UnsignedInt> ids, bool enabled) { |
||||
DebugOutput::setEnabled(DebugOutput::Source(source), DebugOutput::Type(type), ids, enabled); |
||||
} |
||||
CORRADE_DEPRECATED("use DebugOutput::setEnabled() instead") static void setEnabled(Source source, Type type, DebugOutput::Severity severity, bool enabled) { |
||||
DebugOutput::setEnabled(DebugOutput::Source(source), DebugOutput::Type(type), severity, enabled); |
||||
} |
||||
CORRADE_DEPRECATED("use DebugOutput::setEnabled() instead") static void setEnabled(Source source, Type type, bool enabled) { |
||||
DebugOutput::setEnabled(DebugOutput::Source(source), DebugOutput::Type(type), enabled); |
||||
} |
||||
CORRADE_DEPRECATED("use DebugOutput::setEnabled() instead") static void setEnabled(Source source, DebugOutput::Severity severity, bool enabled) { |
||||
DebugOutput::setEnabled(DebugOutput::Source(source), severity, enabled); |
||||
} |
||||
CORRADE_DEPRECATED("use DebugOutput::setEnabled() instead") static void setEnabled(Source source, bool enabled) { |
||||
DebugOutput::setEnabled(DebugOutput::Source(source), enabled); |
||||
} |
||||
CORRADE_DEPRECATED("use DebugOutput::setEnabled() instead") static void setEnabled(Type type, DebugOutput::Severity severity, bool enabled) { |
||||
DebugOutput::setEnabled(DebugOutput::Type(type), severity, enabled); |
||||
} |
||||
CORRADE_DEPRECATED("use DebugOutput::setEnabled() instead") static void setEnabled(Type type, bool enabled) { |
||||
DebugOutput::setEnabled(DebugOutput::Type(type), enabled); |
||||
} |
||||
CORRADE_DEPRECATED("use DebugOutput::setEnabled() instead") static void setEnabled(DebugOutput::Severity severity, bool enabled) { |
||||
DebugOutput::setEnabled(severity, enabled); |
||||
} |
||||
CORRADE_DEPRECATED("use DebugOutput::setEnabled() instead") static void setEnabled(bool enabled) { |
||||
DebugOutput::setEnabled(enabled); |
||||
} |
||||
#endif |
||||
|
||||
/** @copybrief DebugOutput::setCallback()
|
||||
* @deprecated Use @ref DebugOutput::setCallback() instead. |
||||
*/ |
||||
CORRADE_DEPRECATED("use DebugOutput::setCallback() instead") static void setCallback(Callback callback, const void* userParam = nullptr) { |
||||
DebugOutput::setCallback(reinterpret_cast<DebugOutput::Callback>(callback), userParam); |
||||
} |
||||
|
||||
/** @copybrief DebugOutput::setDefaultCallback()
|
||||
* @deprecated Use @ref DebugOutput::setDefaultCallback() instead. |
||||
*/ |
||||
CORRADE_DEPRECATED("use DebugOutput::setDefaultCallback() instead") static void setDefaultCallback() { |
||||
DebugOutput::setDefaultCallback(); |
||||
} |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief Insert message |
||||
* @param source Message source |
||||
* @param type Message type |
||||
* @param id Message-specific ID |
||||
* @param severity Message severity |
||||
* @param string The actual message |
||||
* |
||||
* If OpenGL 4.3 is not supported and neither @extension{KHR,debug} nor |
||||
* @extension2{EXT,debug_marker} (desktop or ES extensions) nor |
||||
* @extension{GREMEDY,string_marker} (desktop only extension) are |
||||
* available, this function does nothing. |
||||
* |
||||
* If @extension{KHR,debug} is not available and only @extension2{EXT,debug_marker} |
||||
* or @extension{GREMEDY,string_marker} are available, only @p string |
||||
* is used and all other parameters are ignored. |
||||
* @see @ref DebugOutput::maxMessageLength(), @fn_gl{DebugMessageInsert}, |
||||
* @fn_gl_extension2{InsertEventMarker,EXT,debug_marker} or |
||||
* @fn_gl_extension{StringMarker,GREMEDY,string_marker} |
||||
*/ |
||||
static void insert(Source source, Type type, UnsignedInt id, DebugOutput::Severity severity, const std::string& string) { |
||||
insertInternal(source, type, id, severity, {string.data(), string.size()}); |
||||
} |
||||
|
||||
/** @overload */ |
||||
template<std::size_t size> static void insert(Source source, Type type, UnsignedInt id, DebugOutput::Severity severity, const char(&string)[size]) { |
||||
insertInternal(source, type, id, severity, {string, size - 1}); |
||||
} |
||||
|
||||
/** @brief There's no point in having an instance of this class */ |
||||
DebugMessage() = delete; |
||||
|
||||
private: |
||||
static void insertInternal(Source source, Type type, UnsignedInt id, DebugOutput::Severity severity, Containers::ArrayReference<const char> string); |
||||
static MAGNUM_LOCAL void insertImplementationNoOp(Source, Type, UnsignedInt, DebugOutput::Severity, Containers::ArrayReference<const char>); |
||||
static MAGNUM_LOCAL void insertImplementationKhr(Source source, Type type, UnsignedInt id, DebugOutput::Severity severity, Containers::ArrayReference<const char> string); |
||||
static MAGNUM_LOCAL void insertImplementationExt(Source, Type, UnsignedInt, DebugOutput::Severity, Containers::ArrayReference<const char> string); |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
static MAGNUM_LOCAL void insertImplementationGremedy(Source, Type, UnsignedInt, DebugOutput::Severity, Containers::ArrayReference<const char> string); |
||||
#endif |
||||
}; |
||||
|
||||
/** @debugoperatorclassenum{Magnum::DebugMessage,Magnum::DebugMessage::Source} */ |
||||
Debug MAGNUM_EXPORT operator<<(Debug debug, DebugMessage::Source value); |
||||
|
||||
/** @debugoperatorclassenum{Magnum::DebugMessage,Magnum::DebugMessage::Type} */ |
||||
Debug MAGNUM_EXPORT operator<<(Debug debug, DebugMessage::Type value); |
||||
|
||||
/**
|
||||
@brief Debug group |
||||
|
||||
Allows marking portions of GL command stream with labels, useful for example |
||||
with conjunction with various graphics debuggers, such as Apitrace or gDEBugger. |
||||
|
||||
## Basic usage |
||||
|
||||
See @ref DebugOutput for introduction. |
||||
|
||||
Easiest way is to push debug group by creating instance and pop it |
||||
automatically at the end of scope: |
||||
@code |
||||
{ |
||||
// Push debug group
|
||||
DebugGroup group{DebugGroup::Source::Application, 42, "Scene rendering"}; |
||||
|
||||
Renderer::enable(Renderer::Feature::Blending); |
||||
mesh.draw(shader); |
||||
Renderer::disable(Renderer::Feature::Blending); |
||||
|
||||
// The debug group is popped automatically at the end of the scope
|
||||
} |
||||
@endcode |
||||
|
||||
If, for some reason, you need to pop in different scope, you can call @ref push() |
||||
and @ref pop() manually: |
||||
@code |
||||
DebugGroup group; |
||||
|
||||
group.push(DebugGroup::Source::Application, 42, "Scene rendering"); |
||||
|
||||
Renderer::enable(Renderer::Feature::Blending); |
||||
mesh.draw(shader); |
||||
Renderer::disable(Renderer::Feature::Blending); |
||||
|
||||
group.pop(); |
||||
@endcode |
||||
|
||||
If OpenGL 4.3 is supported or @extension{KHR,debug} desktop or ES extension is |
||||
available and the default debug output callback is enabled for these kinds of |
||||
messages, the group entering and leaving will be printed on standard output in |
||||
the following form: |
||||
|
||||
> DebugOutput::Source::Application DebugOutput::Type::PushGroup 42 DebugOutput::Severity::Notification\n |
||||
> Scene rendering\n |
||||
> DebugOutput::Source::Application DebugOutput::Type::PopGroup 42 DebugOutput::Severity::Notification\n |
||||
> Scene rendering |
||||
|
||||
If only @extension2{EXT,debug_marker} is available, the group can be seen only |
||||
through graphics debugger. |
||||
|
||||
If OpenGL 4.3 is not supported and neither @extension{KHR,debug} nor |
||||
@extension2{EXT,debug_marker} are available, the functions are essentially a |
||||
no-op. |
||||
|
||||
@attention To avoid accidental debug group stack overflow/underflow, you cannot |
||||
call @ref push() again when the group is already pushed onto the stack, |
||||
similarly for @ref pop(). So if you want to have nested debug groups, you |
||||
need to create one instance for each level. |
||||
|
||||
## Interaction with debug output volume control |
||||
|
||||
Besides putting hierarchical messages in debug output, the group also affects |
||||
settings done by @ref DebugOutput::setEnabled(). Entering debug group inherits |
||||
the settings from previously active debug group, call to |
||||
@ref DebugOutput::setEnabled() will be remembered only for |
||||
the time in which given group is active and leaving it will revert the setting |
||||
to state set in parent debug group. No state is preserved, thus calling |
||||
@ref push() after previous @ref pop() will not restore settings done when the |
||||
group was active previously. |
||||
|
||||
## Performance notes |
||||
|
||||
If you ensure that you always use the `const char` overload of @ref push() |
||||
and the debug output is either not supported or turned off, the calls will not |
||||
result in any allocations and thus won't have any negative performance effects. |
||||
|
||||
@see @ref DebugMessage |
||||
*/ |
||||
class MAGNUM_EXPORT DebugGroup { |
||||
friend Implementation::DebugState; |
||||
|
||||
public: |
||||
/**
|
||||
* @brief Message source |
||||
* |
||||
* @see @ref DebugGroup(), @ref push() |
||||
*/ |
||||
enum class Source: GLenum { |
||||
/** External debugger or third-party middleware */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
ThirdParty = GL_DEBUG_SOURCE_THIRD_PARTY, |
||||
#else |
||||
ThirdParty = GL_DEBUG_SOURCE_THIRD_PARTY_KHR, |
||||
#endif |
||||
|
||||
/** The application */ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
Application = GL_DEBUG_SOURCE_APPLICATION |
||||
#else |
||||
Application = GL_DEBUG_SOURCE_APPLICATION_KHR |
||||
#endif |
||||
}; |
||||
|
||||
/**
|
||||
* @brief Max debug group stack depth |
||||
* |
||||
* The result is cached, repeated queries don't result in repeated |
||||
* OpenGL calls. If OpenGL 4.3 is not supported and @extension{KHR,debug} |
||||
* desktop or ES extension is not available, returns `0`. |
||||
* @see @fn_gl{Get} with @def_gl{MAX_DEBUG_GROUP_STACK_DEPTH} |
||||
*/ |
||||
static Int maxStackDepth(); |
||||
|
||||
/**
|
||||
* @brief Default constructor |
||||
* |
||||
* Doesn't do anything. Call @ref push() to enter debug group. |
||||
*/ |
||||
explicit DebugGroup(): _active{false} {} |
||||
|
||||
/**
|
||||
* @brief Constructor |
||||
* |
||||
* Calls @ref push(). |
||||
* @see @link ~DebugGroup() @endlink, @ref pop() |
||||
*/ |
||||
explicit DebugGroup(Source source, UnsignedInt id, const std::string& message): DebugGroup{} { |
||||
push(source, id, message); |
||||
} |
||||
|
||||
/** @overload */ |
||||
template<std::size_t size> explicit DebugGroup(Source source, UnsignedInt id, const char(&message)[size]): DebugGroup{} { |
||||
push(source, id, message); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Destructor |
||||
* |
||||
* If the group is active, calls @ref pop(). |
||||
*/ |
||||
~DebugGroup() { if(_active) pop(); } |
||||
|
||||
/**
|
||||
* @brief Push debug group onto the stack |
||||
* |
||||
* Expects that the group isn't already pushed on the stack. The group |
||||
* entering message is put into debug output with |
||||
* @ref DebugOutput::Type::PushGroup and |
||||
* @ref DebugOutput::Severity::Notification. |
||||
* |
||||
* If OpenGL 4.3 is not supported and neither @extension{KHR,debug} nor |
||||
* @extension2{EXT,debug_marker} is available, this function does |
||||
* nothing. If @extension{KHR,debug} is not available and only |
||||
* @extension2{EXT,debug_marker} is available, only @p message is used |
||||
* and all other parameters are ignored. |
||||
* @see @ref pop(), @ref maxStackDepth(), @ref DebugOutput::maxMessageLength(), |
||||
* @ref Renderer::Error::StackOverflow, @fn_gl{PushDebugGroup} or |
||||
* @fn_gl_extension2{PushGroupMarker,EXT,debug_marker} |
||||
*/ |
||||
void push(Source source, UnsignedInt id, const std::string& message) { |
||||
pushInternal(source, id, {message.data(), message.size()}); |
||||
} |
||||
|
||||
/** @overload */ |
||||
template<std::size_t size> void push(Source source, UnsignedInt id, const char(&message)[size]) { |
||||
pushInternal(source, id, {message, size - 1}); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Pop debug group from the stack |
||||
* |
||||
* Expects that the group is currently pushed on the stack. Leaving the |
||||
* group will also revert all @ref DebugOutput::setEnabled() settings |
||||
* done when the group was active. See class documentation for more |
||||
* information. The group leaving message is put into debug output with |
||||
* @ref DebugOutput::Type::PopGroup and |
||||
* @ref DebugOutput::Severity::Notification. |
||||
* |
||||
* If OpenGL 4.3 is not supported and neither @extension{KHR,debug} nor |
||||
* @extension2{EXT,debug_marker} is available, this function does |
||||
* nothing. |
||||
* @see @ref push(), @ref Renderer::Error::StackUnderflow, |
||||
* @fn_gl{PopDebugGroup} or |
||||
* @fn_gl_extension2{PopGroupMarker,EXT,debug_marker} |
||||
*/ |
||||
void pop(); |
||||
|
||||
private: |
||||
void pushInternal(Source source, UnsignedInt id, Containers::ArrayReference<const char> message); |
||||
|
||||
static MAGNUM_LOCAL void pushImplementationNoOp(Source source, UnsignedInt id, Containers::ArrayReference<const char> message); |
||||
static MAGNUM_LOCAL void pushImplementationKhr(Source source, UnsignedInt id, Containers::ArrayReference<const char> message); |
||||
static MAGNUM_LOCAL void pushImplementationExt(Source source, UnsignedInt id, Containers::ArrayReference<const char> message); |
||||
|
||||
static MAGNUM_LOCAL void popImplementationNoOp(); |
||||
static MAGNUM_LOCAL void popImplementationKhr(); |
||||
static MAGNUM_LOCAL void popImplementationExt(); |
||||
|
||||
bool _active; |
||||
}; |
||||
|
||||
/** @debugoperatorclassenum{Magnum::DebugGroup,Magnum::DebugGroup::Source} */ |
||||
Debug MAGNUM_EXPORT operator<<(Debug debug, DebugGroup::Source value); |
||||
|
||||
} |
||||
|
||||
#endif |
||||
@ -1,144 +0,0 @@
|
||||
/*
|
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014, 2015 |
||||
Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a |
||||
copy of this software and associated documentation files (the "Software"), |
||||
to deal in the Software without restriction, including without limitation |
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
and/or sell copies of the Software, and to permit persons to whom the |
||||
Software is furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included |
||||
in all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||
DEALINGS IN THE SOFTWARE. |
||||
*/ |
||||
|
||||
#include <sstream> |
||||
|
||||
#include "Magnum/Context.h" |
||||
#include "Magnum/DebugMessage.h" |
||||
#include "Magnum/Extensions.h" |
||||
#include "Magnum/Test/AbstractOpenGLTester.h" |
||||
|
||||
#ifdef MAGNUM_BUILD_DEPRECATED |
||||
#include "Magnum/DebugMarker.h" |
||||
#endif |
||||
|
||||
namespace Magnum { namespace Test { |
||||
|
||||
struct DebugGLTest: AbstractOpenGLTester { |
||||
explicit DebugGLTest(); |
||||
|
||||
void insertMessageNoOp(); |
||||
void insertMessage(); |
||||
void insertMessageFallback(); |
||||
|
||||
void setMessageEnabled(); |
||||
|
||||
void deprecated(); |
||||
}; |
||||
|
||||
DebugGLTest::DebugGLTest() { |
||||
addTests({&DebugGLTest::insertMessageNoOp, |
||||
&DebugGLTest::insertMessage, |
||||
&DebugGLTest::insertMessageFallback, |
||||
|
||||
&DebugGLTest::setMessageEnabled, |
||||
|
||||
#ifdef MAGNUM_BUILD_DEPRECATED |
||||
&DebugGLTest::deprecated |
||||
#endif |
||||
}); |
||||
} |
||||
|
||||
void DebugGLTest::insertMessageNoOp() { |
||||
if(Context::current()->isExtensionSupported<Extensions::GL::KHR::debug>() || |
||||
Context::current()->isExtensionSupported<Extensions::GL::EXT::debug_marker>() |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
|| Context::current()->isExtensionSupported<Extensions::GL::GREMEDY::string_marker>() |
||||
#endif |
||||
) |
||||
CORRADE_SKIP("The extensions are supported, cannot test."); |
||||
|
||||
DebugMessage::insert(DebugMessage::Source::Application, DebugMessage::Type::Marker, |
||||
1337, DebugMessage::Severity::Notification, "Hello from OpenGL command stream!"); |
||||
|
||||
MAGNUM_VERIFY_NO_ERROR(); |
||||
} |
||||
|
||||
void DebugGLTest::insertMessage() { |
||||
if(!Context::current()->isExtensionSupported<Extensions::GL::KHR::debug>()) |
||||
CORRADE_SKIP(Extensions::GL::KHR::debug::string() + std::string(" is not supported")); |
||||
|
||||
Renderer::enable(Renderer::Feature::DebugOutput); |
||||
|
||||
Renderer::enable(Renderer::Feature::DebugOutputSynchronous); |
||||
std::ostringstream out; |
||||
Debug::setOutput(&out); |
||||
DebugMessage::setDefaultCallback(); |
||||
DebugMessage::insert(DebugMessage::Source::Application, DebugMessage::Type::Marker, |
||||
1337, DebugMessage::Severity::Notification, "Hello from OpenGL command stream!"); |
||||
|
||||
Renderer::enable(Renderer::Feature::DebugOutput); |
||||
|
||||
MAGNUM_VERIFY_NO_ERROR(); |
||||
CORRADE_COMPARE(out.str(), |
||||
"DebugMessage::Source::Application DebugMessage::Type::Marker 1337 DebugMessage::Severity::Notification \n" |
||||
" Hello from OpenGL command stream!\n"); |
||||
} |
||||
|
||||
void DebugGLTest::insertMessageFallback() { |
||||
if(Context::current()->isExtensionSupported<Extensions::GL::KHR::debug>() || |
||||
(!Context::current()->isExtensionSupported<Extensions::GL::EXT::debug_marker>() |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
&& !Context::current()->isExtensionSupported<Extensions::GL::GREMEDY::string_marker>() |
||||
#endif |
||||
)) |
||||
CORRADE_SKIP("No proper extension is supported"); |
||||
|
||||
DebugMessage::insert(DebugMessage::Source::Application, DebugMessage::Type::Marker, |
||||
1337, DebugMessage::Severity::Notification, "Hello from OpenGL command stream!"); |
||||
|
||||
MAGNUM_VERIFY_NO_ERROR(); |
||||
} |
||||
|
||||
void DebugGLTest::setMessageEnabled() { |
||||
if(!Context::current()->isExtensionSupported<Extensions::GL::KHR::debug>()) |
||||
CORRADE_SKIP(Extensions::GL::KHR::debug::string() + std::string(" is not supported")); |
||||
|
||||
/* Try at least some combinations */ |
||||
DebugMessage::setEnabled(DebugMessage::Source::Application, true); |
||||
DebugMessage::setEnabled(DebugMessage::Source::Application, DebugMessage::Type::UndefinedBehavior, {3168, 35487, 234487}, false); |
||||
DebugMessage::setEnabled(true); |
||||
|
||||
MAGNUM_VERIFY_NO_ERROR(); |
||||
} |
||||
|
||||
#ifdef MAGNUM_BUILD_DEPRECATED |
||||
void DebugGLTest::deprecated() { |
||||
#ifdef __GNUC__ |
||||
#pragma GCC diagnostic push |
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations" |
||||
#endif |
||||
DebugMarker::mark("hello"); |
||||
#ifdef __GNUC__ |
||||
#pragma GCC diagnostic pop |
||||
#endif |
||||
|
||||
MAGNUM_VERIFY_NO_ERROR(); |
||||
} |
||||
#endif |
||||
|
||||
}} |
||||
|
||||
CORRADE_TEST_MAIN(Magnum::Test::DebugGLTest) |
||||
@ -0,0 +1,211 @@
|
||||
/*
|
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014, 2015 |
||||
Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a |
||||
copy of this software and associated documentation files (the "Software"), |
||||
to deal in the Software without restriction, including without limitation |
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
and/or sell copies of the Software, and to permit persons to whom the |
||||
Software is furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included |
||||
in all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||
DEALINGS IN THE SOFTWARE. |
||||
*/ |
||||
|
||||
#include <sstream> |
||||
|
||||
#include "Magnum/Context.h" |
||||
#include "Magnum/DebugOutput.h" |
||||
#include "Magnum/Extensions.h" |
||||
#include "Magnum/Test/AbstractOpenGLTester.h" |
||||
|
||||
#ifdef MAGNUM_BUILD_DEPRECATED |
||||
#include "Magnum/DebugMarker.h" |
||||
#endif |
||||
|
||||
namespace Magnum { namespace Test { |
||||
|
||||
struct DebugOutputGLTest: AbstractOpenGLTester { |
||||
explicit DebugOutputGLTest(); |
||||
|
||||
void setCallback(); |
||||
void setEnabled(); |
||||
|
||||
void messageNoOp(); |
||||
void message(); |
||||
void messageFallback(); |
||||
|
||||
void groupNoOp(); |
||||
void group(); |
||||
void groupFallback(); |
||||
|
||||
#ifdef MAGNUM_BUILD_DEPRECATED |
||||
void deprecated(); |
||||
#endif |
||||
}; |
||||
|
||||
DebugOutputGLTest::DebugOutputGLTest() { |
||||
addTests({&DebugOutputGLTest::setCallback, |
||||
&DebugOutputGLTest::setEnabled, |
||||
|
||||
&DebugOutputGLTest::messageNoOp, |
||||
&DebugOutputGLTest::message, |
||||
&DebugOutputGLTest::messageFallback, |
||||
|
||||
&DebugOutputGLTest::groupNoOp, |
||||
&DebugOutputGLTest::group, |
||||
&DebugOutputGLTest::groupFallback, |
||||
|
||||
#ifdef MAGNUM_BUILD_DEPRECATED |
||||
&DebugOutputGLTest::deprecated |
||||
#endif |
||||
}); |
||||
} |
||||
|
||||
void DebugOutputGLTest::setCallback() { |
||||
if(!Context::current()->isExtensionSupported<Extensions::GL::KHR::debug>()) |
||||
CORRADE_SKIP(Extensions::GL::KHR::debug::string() + std::string(" is not supported")); |
||||
|
||||
/* Need to be careful, because the test runner is using debug output too */ |
||||
DebugOutput::setDefaultCallback(); |
||||
|
||||
MAGNUM_VERIFY_NO_ERROR(); |
||||
} |
||||
|
||||
void DebugOutputGLTest::setEnabled() { |
||||
if(!Context::current()->isExtensionSupported<Extensions::GL::KHR::debug>()) |
||||
CORRADE_SKIP(Extensions::GL::KHR::debug::string() + std::string(" is not supported")); |
||||
|
||||
/* Try at least some combinations */ |
||||
DebugOutput::setEnabled(DebugOutput::Source::Application, true); |
||||
DebugOutput::setEnabled(DebugOutput::Source::Application, DebugOutput::Type::UndefinedBehavior, {3168, 35487, 234487}, false); |
||||
DebugOutput::setEnabled(true); |
||||
|
||||
MAGNUM_VERIFY_NO_ERROR(); |
||||
} |
||||
|
||||
void DebugOutputGLTest::messageNoOp() { |
||||
if(Context::current()->isExtensionSupported<Extensions::GL::KHR::debug>() || |
||||
Context::current()->isExtensionSupported<Extensions::GL::EXT::debug_marker>() |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
|| Context::current()->isExtensionSupported<Extensions::GL::GREMEDY::string_marker>() |
||||
#endif |
||||
) |
||||
CORRADE_SKIP("The extensions are supported, cannot test."); |
||||
|
||||
DebugMessage::insert(DebugMessage::Source::Application, DebugMessage::Type::Marker, |
||||
1337, DebugOutput::Severity::Notification, "Hello from OpenGL command stream!"); |
||||
|
||||
MAGNUM_VERIFY_NO_ERROR(); |
||||
} |
||||
|
||||
void DebugOutputGLTest::message() { |
||||
if(!Context::current()->isExtensionSupported<Extensions::GL::KHR::debug>()) |
||||
CORRADE_SKIP(Extensions::GL::KHR::debug::string() + std::string(" is not supported")); |
||||
|
||||
/* Need to be careful, because the test runner is using debug output too */ |
||||
std::ostringstream out; |
||||
Debug::setOutput(&out); |
||||
DebugMessage::insert(DebugMessage::Source::Application, DebugMessage::Type::Marker, |
||||
1337, DebugOutput::Severity::Notification, "Hello from OpenGL command stream!"); |
||||
|
||||
MAGNUM_VERIFY_NO_ERROR(); |
||||
CORRADE_COMPARE(out.str(), |
||||
"DebugOutput::Source::Application DebugOutput::Type::Marker 1337 DebugOutput::Severity::Notification \n" |
||||
" Hello from OpenGL command stream!\n"); |
||||
} |
||||
|
||||
void DebugOutputGLTest::messageFallback() { |
||||
if(Context::current()->isExtensionSupported<Extensions::GL::KHR::debug>() || |
||||
(!Context::current()->isExtensionSupported<Extensions::GL::EXT::debug_marker>() |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
&& !Context::current()->isExtensionSupported<Extensions::GL::GREMEDY::string_marker>() |
||||
#endif |
||||
)) |
||||
CORRADE_SKIP("No proper extension is supported"); |
||||
|
||||
DebugMessage::insert(DebugMessage::Source::Application, DebugMessage::Type::Marker, |
||||
1337, DebugOutput::Severity::Notification, "Hello from OpenGL command stream!"); |
||||
|
||||
MAGNUM_VERIFY_NO_ERROR(); |
||||
} |
||||
|
||||
void DebugOutputGLTest::groupNoOp() { |
||||
if(Context::current()->isExtensionSupported<Extensions::GL::KHR::debug>() || |
||||
Context::current()->isExtensionSupported<Extensions::GL::EXT::debug_marker>()) |
||||
CORRADE_SKIP("The extensions are supported, cannot test."); |
||||
|
||||
{ |
||||
DebugGroup g{DebugGroup::Source::Application, 1337, "Debug group"}; |
||||
} |
||||
|
||||
MAGNUM_VERIFY_NO_ERROR(); |
||||
} |
||||
|
||||
void DebugOutputGLTest::group() { |
||||
if(!Context::current()->isExtensionSupported<Extensions::GL::KHR::debug>()) |
||||
CORRADE_SKIP(Extensions::GL::KHR::debug::string() + std::string(" is not supported")); |
||||
|
||||
/* Need to be careful, because the test runner is using debug output too */ |
||||
std::ostringstream out; |
||||
Debug::setOutput(&out); |
||||
{ |
||||
DebugGroup g1{DebugGroup::Source::Application, 42, "Automatic debug group"}; |
||||
DebugGroup g2; |
||||
g2.push(DebugGroup::Source::Application, 1337, "Manual debug group"); |
||||
g2.pop(); |
||||
} |
||||
|
||||
MAGNUM_VERIFY_NO_ERROR(); |
||||
CORRADE_COMPARE(out.str(), |
||||
"DebugOutput::Source::Application DebugOutput::Type::PushGroup 42 DebugOutput::Severity::Notification \n" |
||||
" Automatic debug group\n" |
||||
"DebugOutput::Source::Application DebugOutput::Type::PushGroup 1337 DebugOutput::Severity::Notification \n" |
||||
" Manual debug group\n" |
||||
"DebugOutput::Source::Application DebugOutput::Type::PopGroup 1337 DebugOutput::Severity::Notification \n" |
||||
" Manual debug group\n" |
||||
"DebugOutput::Source::Application DebugOutput::Type::PopGroup 42 DebugOutput::Severity::Notification \n" |
||||
" Automatic debug group\n"); |
||||
} |
||||
|
||||
void DebugOutputGLTest::groupFallback() { |
||||
if(Context::current()->isExtensionSupported<Extensions::GL::KHR::debug>() || |
||||
!Context::current()->isExtensionSupported<Extensions::GL::EXT::debug_marker>()) |
||||
CORRADE_SKIP("No proper extension is supported"); |
||||
|
||||
{ |
||||
DebugGroup g{DebugGroup::Source::Application, 1337, "Debug group"}; |
||||
} |
||||
|
||||
MAGNUM_VERIFY_NO_ERROR(); |
||||
} |
||||
|
||||
#ifdef MAGNUM_BUILD_DEPRECATED |
||||
void DebugOutputGLTest::deprecated() { |
||||
#ifdef __GNUC__ |
||||
#pragma GCC diagnostic push |
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations" |
||||
#endif |
||||
DebugMarker::mark("hello"); |
||||
#ifdef __GNUC__ |
||||
#pragma GCC diagnostic pop |
||||
#endif |
||||
|
||||
MAGNUM_VERIFY_NO_ERROR(); |
||||
} |
||||
#endif |
||||
|
||||
}} |
||||
|
||||
CORRADE_TEST_MAIN(Magnum::Test::DebugOutputGLTest) |
||||
Loading…
Reference in new issue