Debug Output: Difference between revisions
m KHR/core clarification. |
|||
Line 31: | Line 31: | ||
Implementations may create messages at their discretion. In general, you can expect to see messages for OpenGL Errors and GLSL compiling and linking failures. From there, it becomes a quality-of-implementation question. | Implementations may create messages at their discretion. In general, you can expect to see messages for OpenGL Errors and GLSL compiling and linking failures. From there, it becomes a quality-of-implementation question. | ||
{| | |||
|- valign="top" | |||
| | |||
{| class="wikitable" | |||
|+ Message Sources | |||
! Source enum | |||
! Generated by | |||
|- | |||
| {{enum|DEBUG_SOURCE_API}} | |||
| Calls to the OpenGL API | |||
|- | |||
| {{enum|DEBUG_SOURCE_WINDOW_SYSTEM}} | |||
| Calls to a window-system API | |||
|- | |||
| {{enum|DEBUG_SOURCE_SHADER_COMPILER}} | |||
| A compiler for a [[OpenGL Shading Language|shading language]] | |||
|- | |||
| {{enum|DEBUG_SOURCE_THIRD_PARTY}} | |||
| An application associated with OpenGL | |||
|- | |||
| {{enum|DEBUG_SOURCE_APPLICATION}} | |||
| Generated by the [[#User messages|user of this application]] | |||
|- | |||
| {{enum|DEBUG_SOURCE_OTHER}} | |||
| Some source that isn't one of these | |||
|} | |||
| | |||
{| class="wikitable" | |||
|+ Message Types | |||
! Type enum | |||
! Meaning | |||
|- | |||
| {{enum|DEBUG_TYPE_ERROR}} | |||
| An error, typically from the API | |||
|- | |||
| {{enum|DEBUG_TYPE_DEPRECATED_BEHAVIOR}} | |||
| Some behavior marked deprecated has been used | |||
|- | |||
| {{enum|DEBUG_TYPE_UNDEFINED_BEHAVIOR}} | |||
| Something has invoked undefined behavior | |||
|- | |||
| {{enum|DEBUG_TYPE_PORTABILITY}} | |||
| Some functionality the user relies upon is not portable | |||
|- | |||
| {{enum|DEBUG_TYPE_PERFORMANCE}} | |||
| Code has triggered possible performance issues | |||
|- | |||
| {{enum|DEBUG_TYPE_MARKER}} | |||
| Command stream annotation | |||
|- | |||
| {{enum|DEBUG_TYPE_PUSH_GROUP}} | |||
| [[#Scoping messages|Group pushing]] | |||
|- | |||
| {{enum|DEBUG_TYPE_POP_GROUP}} | |||
| [[#Scoping messages|foo]] | |||
|- | |||
| {{enum|DEBUG_TYPE_OTHER}} | |||
| Some type that isn't one of these | |||
|} | |||
|} | |||
{| class="wikitable" width="70%" | |||
|+ Message Severity | |||
! Severity enum | |||
! Meaning | |||
|- | |||
| {{enum|DEBUG_SEVERITY_HIGH}} | |||
| All [[OpenGL Error]]s, shader compilation/linking errors, or highly-dangerous undefined behavior | |||
|- | |||
| {{enum|DEBUG_SEVERITY_MEDIUM}} | |||
| Major performance warnings, shader compilation/linking warnings, or the use of deprecated functionality | |||
|- | |||
| {{enum|DEBUG_SEVERITY_LOW}} | |||
| Redundant state change performance warning, or unimportant undefined behavior | |||
|- | |||
| {{enum|DEBUG_SEVERITY_NOTIFICATION}} | |||
| Anything that isn't an error or performance issue. | |||
|} | |||
=== User messages === | |||
=== Getting messages === | === Getting messages === |
Revision as of 11:21, 24 February 2013
Core in version | 4.6 | |
---|---|---|
Core since version | 4.3 | |
Core ARB extension | KHR_debug | |
ARB extension | ARB_debug_output | |
Vendor extension | AMD_debug_output |
Debug Output is an OpenGL feature that makes Error Checking from functions easier.
Note that this feature, which is core in 4.3, has functionality that is generally exposed by two different extensions. The KHR extension is the core feature, which is always advertised when available. The other two are generally only advertised when the OpenGL Context was created with the WGL/GLX_DEBUG_CONTEXT_BIT.
This page describes the KHR/core functionality. The ARB/AMD version contains only the message log part, without the object names or the scoped messages. They also have some slight differences in the callback function parameters and the types of messages they work with.
This article is a stub. You can help the OpenGL Wiki by expanding it. |
Message
The heart of debug output is a message. Messages are generated when certain things happen in the OpenGL implementation; the user can even generate message of their own.
In order to have messages generated at all, debug output must first be enabled. If the context is a debug context (ie: GL_CONTEXT_FLAG_DEBUG_BIT is part of the GL_CONTEXT_FLAGS state), then debug output is already enabled. Otherwise it starts disabled and must be enabled with an explicit glEnable(GL_DEBUG_OUTPUT).
If the context isn't a debug context, then the implementation is free to provide no messages at all, even user-generated ones.
Messages can come from a variety of sources, but they each contain the following data:
- The source that produced the message.
- The type of message.
- The message severity (how important it is).
- An ID, as a GLuint.
- A null-terminated string describing the message.
Implementations may create messages at their discretion. In general, you can expect to see messages for OpenGL Errors and GLSL compiling and linking failures. From there, it becomes a quality-of-implementation question.
|
|
Severity enum | Meaning |
---|---|
DEBUG_SEVERITY_HIGH | All OpenGL Errors, shader compilation/linking errors, or highly-dangerous undefined behavior |
DEBUG_SEVERITY_MEDIUM | Major performance warnings, shader compilation/linking warnings, or the use of deprecated functionality |
DEBUG_SEVERITY_LOW | Redundant state change performance warning, or unimportant undefined behavior |
DEBUG_SEVERITY_NOTIFICATION | Anything that isn't an error or performance issue. |
User messages
Getting messages
Messages, once generated, can either be stored in a log or passed directly to the application via a callback function. If a callback is registered, then the messages are not stored in a log.
Messages can be routed to a callback via this function:
The type of callback is a function of the form:
typedef void APIENTRY funcname(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, void* userParam);
source, type, and severity are the messages source, type, and severity enumerators. id is the message's identifier integer. length is the length of the message string, excluding the null-terminator.
The userParam that is registered with glDebugMessageCallback will be passed to the given callback function with each message.
The callback can be called synchronously or asynchronously. This is controlled by the glEnable flag GL_DEBUG_OUTPUT_SYNCHRONOUS. If this flag is enabled, then OpenGL guarantees that your callback will be called:
- In the same thread as the context.
- In the scope of the OpenGL function call that fired the message.
If the flag is disabled, then none of these are guaranteed. So if you want asynchronous debug output (for performance reasons), you must take into account the following possibilities:
- The thread the callback is called on is not the context's thread.
- Multiple instances of the same callback function may be called at the same time.
- Messages may be issued out of the order of their occurrence.
Logging
If no callback is registered, then messages are stored in a log. This log has a fixed, implementation defined length of GL_MAX_DEBUG_LOGGED_MESSAGES message entries. If the log is full and more messages are generated, then the new messages will be discarded.
Messages from the log can be fetched with this function:
GLuint glGetDebugMessageLog(GLuint count, GLsizei bufSize, GLenum *sources, Glenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
count is the number of messages that you want to try to fetch. The return value is the number of messages actually fetched. Any messages successfully fetched will be removed from the message log.
sources, types, ids, severities, lengths are arrays that must be at least count in size. For each successfully extracted message, an entry in these arrays will be filled in with the appropriate message data. The lengths are the lengths of the string for that index's corresponding messages.
The behavior of the character data is more difficult to deal with. messageLog is a single array of characters, of at least bufSize in size. The function will copy into this string the message strings for each message extracted, separated by null characters (and terminated by one). However, if it is unable to copy a string due to lack of space remaining in bufSize, then this message, and all subsequent messages, will remain in the log.
Therefore, if you do not provide enough space in messageLog, you cannot get any messages from the log. You can query the length of the string in the first message of the log with GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH. This includes the null-terminator, so you can use that directly to get at least the first message. If you want to be able to query any number of messages, you can use the implementation-defined GL_MAX_DEBUG_MESSAGE_LENGTH value, which is the maximum length (including null-terminator) of message strings.
Here is an example of code that can get the first N messages:
void GetFirstNMessages(GLuint numMsgs)
{
GLint maxMsgLen = 0;
glGetIntegerv(GL_MAX_DEBUG_MESSAGE_LENGTH, &maxMsgLen);
std::vector<GLchar> msgData(numMsgs * maxMsgLen);
std::vector<GLenum> sources(numMsgs);
std::vector<GLenum> types(numMsgs);
std::vector<GLenum> severities(numMsgs);
std::vector<GLuint> ids(numMsgs);
std::vector<GLsizei> lengths(numMsgs);
GLuint numFound = glGetDebugMessageLog(numMsgs, msgs.size(), &sources[0], &types[0], &ids[0], &severities[0], &lengths[0], &msgData[0]);
sources.resize(numFound);
types.resize(numFound);
severities.resize(numFound);
ids.resize(numFound);
lengths.resize(numFound);
std::vector<std::string> messages;
messages.reserve(numFound);
std::vector<GLchar>::iterator currPos = msgData.begin();
for(size_t msg = 0; msg < lengths.size(); ++msg)
{
messages.push_back(std::string(currPos, currPos + lengths[msg] - 1));
currPos = currPos + lengths[msg];
}
}
Message filtering
Implementations can emit a lot of messages. As such, it is often useful to be able to filter out certain messages.