1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 // names, trademarks, service marks, or product names of the Licensor
11 // and its affiliates, except as required to comply with Section 4(c) of
12 // the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 // http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 // Diagnostic.cpp
25 //
26
27 #include "pxr/imaging/garch/glApi.h"
28
29 #include "pxr/imaging/glf/diagnostic.h"
30 #include "pxr/imaging/glf/debugCodes.h"
31 #include "pxr/imaging/glf/glContext.h"
32
33 #include "pxr/base/tf/diagnostic.h"
34 #include "pxr/base/tf/envSetting.h"
35 #include "pxr/base/tf/stackTrace.h"
36 #include "pxr/base/tf/stringUtils.h"
37
38 #include <sstream>
39
40 PXR_NAMESPACE_OPEN_SCOPE
41
42
43 TF_DEFINE_ENV_SETTING(GLF_ENABLE_DIAGNOSTIC_TRACE, 0,
44 "Enable glDebug* diagnostic tracing in Glf.");
45
46 static bool
GlfTraceEnabled()47 GlfTraceEnabled()
48 {
49 #if defined(GL_KHR_debug)
50 static bool _v = TfGetEnvSetting(GLF_ENABLE_DIAGNOSTIC_TRACE) == 1;
51 return _v;
52 #else
53 return false;
54 #endif
55 }
56
57 void
GlfPostPendingGLErrors(std::string const & where)58 GlfPostPendingGLErrors(std::string const & where)
59 {
60 bool foundError = false;
61 GLenum error;
62 // Protect from doing infinite looping when glGetError
63 // is called from an invalid context.
64 int watchDogCount = 0;
65 while ((watchDogCount++ < 256) &&
66 ((error = glGetError()) != GL_NO_ERROR)) {
67 foundError = true;
68 const GLubyte *errorString = gluErrorString(error);
69
70 std::ostringstream errorMessage;
71 if (!errorString) {
72 errorMessage << "GL error code: 0x" << std::hex << error
73 << std::dec;
74 } else {
75 errorMessage << "GL error: " << errorString;
76 }
77
78 if (!where.empty()) {
79 errorMessage << ", reported from " << where;
80 }
81
82 TF_DEBUG(GLF_DEBUG_ERROR_STACKTRACE).Msg(errorMessage.str() + "\n");
83
84 TF_RUNTIME_ERROR(errorMessage.str());
85 }
86 if (foundError) {
87 TF_DEBUG(GLF_DEBUG_ERROR_STACKTRACE).Msg(
88 TfStringPrintf("==== GL Error Stack ====\n%s\n",
89 TfGetStackTrace().c_str()));
90 }
91 }
92
93 void
GlfRegisterDefaultDebugOutputMessageCallback()94 GlfRegisterDefaultDebugOutputMessageCallback()
95 {
96 #if defined(GL_KHR_debug)
97 if (glDebugMessageCallbackARB) {
98 glDebugMessageCallbackARB(
99 (GLDEBUGPROCARB)GlfDefaultDebugOutputMessageCallback, 0);
100 // Disable push/pop group messages; we don't want to print these.
101 glDebugMessageControlARB(GL_DONT_CARE, GL_DEBUG_TYPE_PUSH_GROUP,
102 GL_DONT_CARE, 0, nullptr, GL_FALSE);
103 glDebugMessageControlARB(GL_DONT_CARE, GL_DEBUG_TYPE_POP_GROUP,
104 GL_DONT_CARE, 0, nullptr, GL_FALSE);
105 glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
106 }
107 #endif
108 }
109
110 void
GlfDefaultDebugOutputMessageCallback(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,GLchar const * message,GLvoid const * userParam)111 GlfDefaultDebugOutputMessageCallback(
112 GLenum source, GLenum type, GLuint id, GLenum severity,
113 GLsizei length, GLchar const * message, GLvoid const * userParam)
114 {
115 #if defined(GL_ARB_debug_output) || defined(GL_VERSION_4_3)
116 if (type == GL_DEBUG_TYPE_ERROR_ARB) {
117 TF_RUNTIME_ERROR("GL debug output: "
118 "source: %s type: %s id: %d severity: %s message: %s",
119 GlfDebugEnumToString(source),
120 GlfDebugEnumToString(type),
121 id,
122 GlfDebugEnumToString(severity),
123 message);
124
125 TF_DEBUG(GLF_DEBUG_ERROR_STACKTRACE).Msg(
126 TfStringPrintf("==== GL Error Stack ====\n%s\n",
127 TfGetStackTrace().c_str()));
128 } else {
129 TF_WARN("GL debug output: %s", message);
130 }
131 #endif
132 }
133
134 char const *
GlfDebugEnumToString(GLenum debugEnum)135 GlfDebugEnumToString(GLenum debugEnum)
136 {
137 #if defined(GL_ARB_debug_output) || defined(GL_VERSION_4_3)
138 switch (debugEnum) {
139 case GL_DEBUG_SOURCE_API_ARB:
140 return "GL_DEBUG_SOURCE_API";
141 case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB:
142 return "GL_DEBUG_SOURCE_WINDOW_SYSTEM";
143 case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB:
144 return "GL_DEBUG_SOURCE_SHADER_COMPILER";
145 case GL_DEBUG_SOURCE_THIRD_PARTY_ARB:
146 return "GL_DEBUG_SOURCE_THIRD_PARTY";
147 case GL_DEBUG_SOURCE_APPLICATION_ARB:
148 return "GL_DEBUG_SOURCE_APPLICATION";
149 case GL_DEBUG_SOURCE_OTHER_ARB:
150 return "GL_DEBUG_SOURCE_OTHER";
151
152 case GL_DEBUG_TYPE_ERROR_ARB:
153 return "GL_DEBUG_TYPE_ERROR";
154 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB:
155 return "GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR";
156 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB:
157 return "GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR";
158 case GL_DEBUG_TYPE_PORTABILITY_ARB:
159 return "GL_DEBUG_TYPE_PORTABILITY";
160 case GL_DEBUG_TYPE_PERFORMANCE_ARB:
161 return "GL_DEBUG_TYPE_PERFORMANCE";
162 case GL_DEBUG_TYPE_OTHER_ARB:
163 return "GL_DEBUG_TYPE_OTHER";
164 #if defined(GL_VERSION_4_3)
165 case GL_DEBUG_TYPE_MARKER:
166 return "GL_DEBUG_TYPE_MARKER";
167 case GL_DEBUG_TYPE_PUSH_GROUP:
168 return "GL_DEBUG_TYPE_PUSH_GROUP";
169 case GL_DEBUG_TYPE_POP_GROUP:
170 return "GL_DEBUG_TYPE_POP_GROUP";
171 #endif
172
173 #if defined(GL_VERSION_4_3)
174 case GL_DEBUG_SEVERITY_NOTIFICATION:
175 return "GL_DEBUG_SEVERITY_NOTIFICATION";
176 #endif
177 case GL_DEBUG_SEVERITY_HIGH_ARB:
178 return "GL_DEBUG_SEVERITY_HIGH";
179 case GL_DEBUG_SEVERITY_MEDIUM_ARB:
180 return "GL_DEBUG_SEVERITY_MEDIUM";
181 case GL_DEBUG_SEVERITY_LOW_ARB:
182 return "GL_DEBUG_SEVERITY_LOW";
183 }
184 #endif
185 TF_CODING_ERROR("unknown debug enum");
186 return "unknown";
187 }
188
189 static void
_GlfPushDebugGroup(char const * message)190 _GlfPushDebugGroup(char const * message)
191 {
192 #if defined(GL_KHR_debug)
193 if (GARCH_GLAPI_HAS(KHR_debug)) {
194 glPushDebugGroup(GL_DEBUG_SOURCE_THIRD_PARTY, 0, -1, message);
195 }
196 #endif
197 }
198
199 static void
_GlfPopDebugGroup()200 _GlfPopDebugGroup()
201 {
202 #if defined(GL_KHR_debug)
203 if (GARCH_GLAPI_HAS(KHR_debug)) {
204 glPopDebugGroup();
205 }
206 #endif
207 }
208
GlfDebugGroup(char const * message)209 GlfDebugGroup::GlfDebugGroup(char const *message)
210 {
211 if (GlfTraceEnabled()) {
212 _GlfPushDebugGroup(message);
213 }
214 }
215
~GlfDebugGroup()216 GlfDebugGroup::~GlfDebugGroup()
217 {
218 if (GlfTraceEnabled()) {
219 _GlfPopDebugGroup();
220 }
221 }
222
223 void
GlfDebugLabelBuffer(GLuint id,char const * label)224 GlfDebugLabelBuffer(GLuint id, char const *label)
225 {
226 #if defined(GL_KHR_debug)
227 if (GlfTraceEnabled()) {
228 if (GARCH_GLAPI_HAS(KHR_debug)) {
229 glObjectLabel(GL_BUFFER, id, -1, label);
230 }
231 }
232 #endif
233 }
234
235 void
GlfDebugLabelShader(GLuint id,char const * label)236 GlfDebugLabelShader(GLuint id, char const *label)
237 {
238 #if defined(GL_KHR_debug)
239 if (GlfTraceEnabled()) {
240 if (GARCH_GLAPI_HAS(KHR_debug)) {
241 glObjectLabel(GL_SHADER, id, -1, label);
242 }
243 }
244 #endif
245 }
246
247 void
GlfDebugLabelProgram(GLuint id,char const * label)248 GlfDebugLabelProgram(GLuint id, char const *label)
249 {
250 #if defined(GL_KHR_debug)
251 if (GlfTraceEnabled()) {
252 if (GARCH_GLAPI_HAS(KHR_debug)) {
253 glObjectLabel(GL_PROGRAM, id, -1, label);
254 }
255 }
256 #endif
257 }
258
GlfGLQueryObject()259 GlfGLQueryObject::GlfGLQueryObject()
260 : _id(0), _target(0)
261 {
262 GarchGLApiLoad();
263 if (glGenQueries) {
264 glGenQueries(1, &_id);
265 }
266 }
267
~GlfGLQueryObject()268 GlfGLQueryObject::~GlfGLQueryObject()
269 {
270 GlfSharedGLContextScopeHolder sharedGLContextScopeHolder;
271 if (glDeleteQueries && _id) {
272 glDeleteQueries(1, &_id);
273 }
274 }
275
276 void
BeginSamplesPassed()277 GlfGLQueryObject::BeginSamplesPassed()
278 {
279 Begin(GL_SAMPLES_PASSED);
280 }
281
282 void
BeginPrimitivesGenerated()283 GlfGLQueryObject::BeginPrimitivesGenerated()
284 {
285 Begin(GL_PRIMITIVES_GENERATED);
286 }
287 void
BeginTimeElapsed()288 GlfGLQueryObject::BeginTimeElapsed()
289 {
290 Begin(GL_TIME_ELAPSED);
291 }
292
293 void
Begin(GLenum target)294 GlfGLQueryObject::Begin(GLenum target)
295 {
296 _target = target;
297 if (glBeginQuery && _id) {
298 glBeginQuery(_target, _id);
299 }
300 }
301
302 void
End()303 GlfGLQueryObject::End()
304 {
305 if (glEndQuery && _target) {
306 glEndQuery(_target);
307 }
308 _target = 0;
309 }
310
311 GLint64
GetResult()312 GlfGLQueryObject::GetResult()
313 {
314 GLint64 value = 0;
315 if (glGetQueryObjecti64v && _id) {
316 glGetQueryObjecti64v(_id, GL_QUERY_RESULT, &value);
317 }
318 return value;
319 }
320
321 GLint64
GetResultNoWait()322 GlfGLQueryObject::GetResultNoWait()
323 {
324 GLint64 value = 0;
325 if (glGetQueryObjecti64v && _id) {
326 glGetQueryObjecti64v(_id, GL_QUERY_RESULT_AVAILABLE, &value);
327 if (value == GL_TRUE) {
328 glGetQueryObjecti64v(_id, GL_QUERY_RESULT, &value);
329 }
330 }
331 return value;
332 }
333
334 PXR_NAMESPACE_CLOSE_SCOPE
335
336