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