• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2002 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // debug.h: Debugging utilities. A lot of the logging code is adapted from Chromium's
8 // base/logging.h.
9 
10 #ifndef COMMON_DEBUG_H_
11 #define COMMON_DEBUG_H_
12 
13 #include <assert.h>
14 #include <stdio.h>
15 
16 #include <iomanip>
17 #include <ios>
18 #include <mutex>
19 #include <sstream>
20 #include <string>
21 
22 #include "common/angleutils.h"
23 #include "common/entry_points_enum_autogen.h"
24 #include "common/platform.h"
25 
26 #if defined(ANGLE_PLATFORM_WINDOWS)
27 #    include <sal.h>
28 typedef unsigned long DWORD;
29 typedef _Return_type_success_(return >= 0) long HRESULT;
30 #endif
31 
32 #if !defined(TRACE_OUTPUT_FILE)
33 #    define TRACE_OUTPUT_FILE "angle_debug.txt"
34 #endif
35 
36 namespace gl
37 {
38 class Context;
39 
40 // Pairs a begin event with an end event.
41 class ANGLE_NO_DISCARD ScopedPerfEventHelper : angle::NonCopyable
42 {
43   public:
44     ScopedPerfEventHelper(Context *context, angle::EntryPoint entryPoint);
45     ~ScopedPerfEventHelper();
46     ANGLE_FORMAT_PRINTF(2, 3)
47     void begin(const char *format, ...);
48 
49   private:
50     gl::Context *mContext;
51     const angle::EntryPoint mEntryPoint;
52     const char *mFunctionName;
53     bool mCalledBeginEvent;
54 };
55 
56 using LogSeverity = int;
57 // Note: the log severities are used to index into the array of names,
58 // see g_logSeverityNames.
59 constexpr LogSeverity LOG_EVENT          = 0;
60 constexpr LogSeverity LOG_INFO           = 1;
61 constexpr LogSeverity LOG_WARN           = 2;
62 constexpr LogSeverity LOG_ERR            = 3;
63 constexpr LogSeverity LOG_FATAL          = 4;
64 constexpr LogSeverity LOG_NUM_SEVERITIES = 5;
65 
66 void Trace(LogSeverity severity, const char *message);
67 
68 // This class more or less represents a particular log message.  You
69 // create an instance of LogMessage and then stream stuff to it.
70 // When you finish streaming to it, ~LogMessage is called and the
71 // full message gets streamed to the appropriate destination.
72 //
73 // You shouldn't actually use LogMessage's constructor to log things,
74 // though.  You should use the ERR() and WARN() macros.
75 class LogMessage : angle::NonCopyable
76 {
77   public:
78     // Used for ANGLE_LOG(severity).
79     LogMessage(const char *file, const char *function, int line, LogSeverity severity);
80     ~LogMessage();
stream()81     std::ostream &stream() { return mStream; }
82 
83     LogSeverity getSeverity() const;
84     std::string getMessage() const;
85 
86   private:
87     const char *mFile;
88     const char *mFunction;
89     const int mLine;
90     const LogSeverity mSeverity;
91 
92     std::ostringstream mStream;
93 };
94 
95 // Wraps the API/Platform-specific debug annotation functions.
96 // Also handles redirecting logging destination.
97 class DebugAnnotator : angle::NonCopyable
98 {
99   public:
DebugAnnotator()100     DebugAnnotator() {}
~DebugAnnotator()101     virtual ~DebugAnnotator() {}
102     virtual void beginEvent(gl::Context *context,
103                             angle::EntryPoint entryPoint,
104                             const char *eventName,
105                             const char *eventMessage)   = 0;
106     virtual void endEvent(gl::Context *context,
107                           const char *eventName,
108                           angle::EntryPoint entryPoint) = 0;
109     virtual void setMarker(const char *markerName)      = 0;
110     virtual bool getStatus()                            = 0;
111     // Log Message Handler that gets passed every log message,
112     // when debug annotations are initialized,
113     // replacing default handling by LogMessage.
114     virtual void logMessage(const LogMessage &msg) const = 0;
115 };
116 
117 bool ShouldBeginScopedEvent();
118 void InitializeDebugAnnotations(DebugAnnotator *debugAnnotator);
119 void UninitializeDebugAnnotations();
120 bool DebugAnnotationsActive();
121 bool DebugAnnotationsInitialized();
122 
123 void InitializeDebugMutexIfNeeded();
124 
125 std::mutex &GetDebugMutex();
126 
127 namespace priv
128 {
129 // This class is used to explicitly ignore values in the conditional logging macros. This avoids
130 // compiler warnings like "value computed is not used" and "statement has no effect".
131 class LogMessageVoidify
132 {
133   public:
LogMessageVoidify()134     LogMessageVoidify() {}
135     // This has to be an operator with a precedence lower than << but higher than ?:
136     void operator&(std::ostream &) {}
137 };
138 
139 extern std::ostream *gSwallowStream;
140 
141 // Used by ANGLE_LOG_IS_ON to lazy-evaluate stream arguments.
142 bool ShouldCreatePlatformLogMessage(LogSeverity severity);
143 
144 // N is the width of the output to the stream. The output is padded with zeros
145 // if value is less than N characters.
146 // S is the stream type, either ostream for ANSI or wostream for wide character.
147 // T is the type of the value to output to the stream.
148 // C is the type of characters - either char for ANSI or wchar_t for wide char.
149 template <int N, typename S, typename T, typename C>
FmtHex(S & stream,T value,const C * zeroX,C zero)150 S &FmtHex(S &stream, T value, const C *zeroX, C zero)
151 {
152     stream << zeroX;
153 
154     std::ios_base::fmtflags oldFlags = stream.flags();
155     std::streamsize oldWidth         = stream.width();
156     typename S::char_type oldFill    = stream.fill();
157 
158     stream << std::hex << std::uppercase << std::setw(N) << std::setfill(zero) << value;
159 
160     stream.flags(oldFlags);
161     stream.width(oldWidth);
162     stream.fill(oldFill);
163 
164     return stream;
165 }
166 
167 template <typename S, typename T, typename C>
FmtHexAutoSized(S & stream,T value,const C * prefix,const C * zeroX,C zero)168 S &FmtHexAutoSized(S &stream, T value, const C *prefix, const C *zeroX, C zero)
169 {
170     if (prefix)
171     {
172         stream << prefix;
173     }
174 
175     constexpr int N = sizeof(T) * 2;
176     return priv::FmtHex<N>(stream, value, zeroX, zero);
177 }
178 
179 template <typename T, typename C>
180 class FmtHexHelper
181 {
182   public:
FmtHexHelper(const C * prefix,T value)183     FmtHexHelper(const C *prefix, T value) : mPrefix(prefix), mValue(value) {}
FmtHexHelper(T value)184     explicit FmtHexHelper(T value) : mPrefix(nullptr), mValue(value) {}
185 
186   private:
187     const C *mPrefix;
188     T mValue;
189 
190     friend std::ostream &operator<<(std::ostream &os, const FmtHexHelper &fmt)
191     {
192         return FmtHexAutoSized(os, fmt.mValue, fmt.mPrefix, "0x", '0');
193     }
194 
195     friend std::wostream &operator<<(std::wostream &wos, const FmtHexHelper &fmt)
196     {
197         return FmtHexAutoSized(wos, fmt.mValue, fmt.mPrefix, L"0x", L'0');
198     }
199 };
200 
201 }  // namespace priv
202 
203 template <typename T, typename C = char>
FmtHex(T value)204 priv::FmtHexHelper<T, C> FmtHex(T value)
205 {
206     return priv::FmtHexHelper<T, C>(value);
207 }
208 
209 #if defined(ANGLE_PLATFORM_WINDOWS)
210 priv::FmtHexHelper<HRESULT, char> FmtHR(HRESULT value);
211 priv::FmtHexHelper<DWORD, char> FmtErr(DWORD value);
212 #endif  // defined(ANGLE_PLATFORM_WINDOWS)
213 
214 template <typename T>
FmtHex(std::ostream & os,T value)215 std::ostream &FmtHex(std::ostream &os, T value)
216 {
217     return priv::FmtHexAutoSized(os, value, "", "0x", '0');
218 }
219 
220 // A few definitions of macros that don't generate much code. These are used
221 // by ANGLE_LOG(). Since these are used all over our code, it's
222 // better to have compact code for these operations.
223 #define COMPACT_ANGLE_LOG_EX_EVENT(ClassName, ...) \
224     ::gl::ClassName(__FILE__, __FUNCTION__, __LINE__, ::gl::LOG_EVENT, ##__VA_ARGS__)
225 #define COMPACT_ANGLE_LOG_EX_INFO(ClassName, ...) \
226     ::gl::ClassName(__FILE__, __FUNCTION__, __LINE__, ::gl::LOG_INFO, ##__VA_ARGS__)
227 #define COMPACT_ANGLE_LOG_EX_WARN(ClassName, ...) \
228     ::gl::ClassName(__FILE__, __FUNCTION__, __LINE__, ::gl::LOG_WARN, ##__VA_ARGS__)
229 #define COMPACT_ANGLE_LOG_EX_ERR(ClassName, ...) \
230     ::gl::ClassName(__FILE__, __FUNCTION__, __LINE__, ::gl::LOG_ERR, ##__VA_ARGS__)
231 #define COMPACT_ANGLE_LOG_EX_FATAL(ClassName, ...) \
232     ::gl::ClassName(__FILE__, __FUNCTION__, __LINE__, ::gl::LOG_FATAL, ##__VA_ARGS__)
233 
234 #define COMPACT_ANGLE_LOG_EVENT COMPACT_ANGLE_LOG_EX_EVENT(LogMessage)
235 #define COMPACT_ANGLE_LOG_INFO COMPACT_ANGLE_LOG_EX_INFO(LogMessage)
236 #define COMPACT_ANGLE_LOG_WARN COMPACT_ANGLE_LOG_EX_WARN(LogMessage)
237 #define COMPACT_ANGLE_LOG_ERR COMPACT_ANGLE_LOG_EX_ERR(LogMessage)
238 #define COMPACT_ANGLE_LOG_FATAL COMPACT_ANGLE_LOG_EX_FATAL(LogMessage)
239 
240 #define ANGLE_LOG_IS_ON(severity) (::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_##severity))
241 
242 // Helper macro which avoids evaluating the arguments to a stream if the condition doesn't hold.
243 // Condition is evaluated once and only once.
244 #define ANGLE_LAZY_STREAM(stream, condition) \
245     !(condition) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify() & (stream)
246 
247 // We use the preprocessor's merging operator, "##", so that, e.g.,
248 // ANGLE_LOG(EVENT) becomes the token COMPACT_ANGLE_LOG_EVENT.  There's some funny
249 // subtle difference between ostream member streaming functions (e.g.,
250 // ostream::operator<<(int) and ostream non-member streaming functions
251 // (e.g., ::operator<<(ostream&, string&): it turns out that it's
252 // impossible to stream something like a string directly to an unnamed
253 // ostream. We employ a neat hack by calling the stream() member
254 // function of LogMessage which seems to avoid the problem.
255 #define ANGLE_LOG_STREAM(severity) COMPACT_ANGLE_LOG_##severity.stream()
256 
257 #define ANGLE_LOG(severity) ANGLE_LAZY_STREAM(ANGLE_LOG_STREAM(severity), ANGLE_LOG_IS_ON(severity))
258 
259 }  // namespace gl
260 
261 #if defined(ANGLE_ENABLE_DEBUG_TRACE) || defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
262 #    define ANGLE_TRACE_ENABLED
263 #endif
264 
265 #if !defined(NDEBUG) || defined(ANGLE_ASSERT_ALWAYS_ON)
266 #    define ANGLE_ENABLE_ASSERTS
267 #endif
268 
269 #define INFO() ANGLE_LOG(INFO)
270 #define WARN() ANGLE_LOG(WARN)
271 #define ERR() ANGLE_LOG(ERR)
272 #define FATAL() ANGLE_LOG(FATAL)
273 
274 // A macro to log a performance event around a scope.
275 #if defined(ANGLE_TRACE_ENABLED)
276 #    if defined(_MSC_VER)
277 #        define EVENT(context, entryPoint, message, ...)                                     \
278             gl::ScopedPerfEventHelper scopedPerfEventHelper##__LINE__(                       \
279                 context, angle::EntryPoint::entryPoint);                                     \
280             do                                                                               \
281             {                                                                                \
282                 if (gl::ShouldBeginScopedEvent())                                            \
283                 {                                                                            \
284                     scopedPerfEventHelper##__LINE__.begin(                                   \
285                         "%s(" message ")", GetEntryPointName(angle::EntryPoint::entryPoint), \
286                         __VA_ARGS__);                                                        \
287                 }                                                                            \
288             } while (0)
289 #    else
290 #        define EVENT(context, entryPoint, message, ...)                                          \
291             gl::ScopedPerfEventHelper scopedPerfEventHelper(context,                              \
292                                                             angle::EntryPoint::entryPoint);       \
293             do                                                                                    \
294             {                                                                                     \
295                 if (gl::ShouldBeginScopedEvent())                                                 \
296                 {                                                                                 \
297                     scopedPerfEventHelper.begin("%s(" message ")",                                \
298                                                 GetEntryPointName(angle::EntryPoint::entryPoint), \
299                                                 ##__VA_ARGS__);                                   \
300                 }                                                                                 \
301             } while (0)
302 #    endif  // _MSC_VER
303 #else
304 #    define EVENT(message, ...) (void(0))
305 #endif
306 
307 // The state tracked by ANGLE will be validated with the driver state before each call
308 #if defined(ANGLE_ENABLE_DEBUG_TRACE)
309 #    define ANGLE_STATE_VALIDATION_ENABLED
310 #endif
311 
312 #if defined(__GNUC__)
313 #    define ANGLE_CRASH() __builtin_trap()
314 #else
315 #    define ANGLE_CRASH() ((void)(*(volatile char *)0 = 0)), __assume(0)
316 #endif
317 
318 #if !defined(NDEBUG)
319 #    define ANGLE_ASSERT_IMPL(expression) assert(expression)
320 #else
321 // TODO(jmadill): Detect if debugger is attached and break.
322 #    define ANGLE_ASSERT_IMPL(expression) ANGLE_CRASH()
323 #endif  // !defined(NDEBUG)
324 
325 // Note that gSwallowStream is used instead of an arbitrary LOG() stream to avoid the creation of an
326 // object with a non-trivial destructor (LogMessage). On MSVC x86 (checked on 2015 Update 3), this
327 // causes a few additional pointless instructions to be emitted even at full optimization level,
328 // even though the : arm of the ternary operator is clearly never executed. Using a simpler object
329 // to be &'d with Voidify() avoids these extra instructions. Using a simpler POD object with a
330 // templated operator<< also works to avoid these instructions. However, this causes warnings on
331 // statically defined implementations of operator<<(std::ostream, ...) in some .cpp files, because
332 // they become defined-but-unreferenced functions. A reinterpret_cast of 0 to an ostream* also is
333 // not suitable, because some compilers warn of undefined behavior.
334 #define ANGLE_EAT_STREAM_PARAMETERS \
335     true ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify() & (*::gl::priv::gSwallowStream)
336 
337 // A macro asserting a condition and outputting failures to the debug log
338 #if defined(ANGLE_ENABLE_ASSERTS)
339 #    define ASSERT(expression)                                                                \
340         (expression ? static_cast<void>(0)                                                    \
341                     : (FATAL() << "\t! Assert failed in " << __FUNCTION__ << " (" << __FILE__ \
342                                << ":" << __LINE__ << "): " << #expression))
343 #else
344 #    define ASSERT(condition) ANGLE_EAT_STREAM_PARAMETERS << !(condition)
345 #endif  // defined(ANGLE_ENABLE_ASSERTS)
346 
347 #define UNREACHABLE_IS_NORETURN 0
348 
349 #define ANGLE_UNUSED_VARIABLE(variable) (static_cast<void>(variable))
350 
351 // A macro to indicate unimplemented functionality
352 #ifndef NOASSERT_UNIMPLEMENTED
353 #    define NOASSERT_UNIMPLEMENTED 1
354 #endif
355 
356 #if defined(ANGLE_TRACE_ENABLED) || defined(ANGLE_ENABLE_ASSERTS)
357 #    define UNIMPLEMENTED()                                                                       \
358         do                                                                                        \
359         {                                                                                         \
360             WARN() << "\t! Unimplemented: " << __FUNCTION__ << "(" << __FILE__ << ":" << __LINE__ \
361                    << ")";                                                                        \
362             ASSERT(NOASSERT_UNIMPLEMENTED);                                                       \
363         } while (0)
364 
365 // A macro for code which is not expected to be reached under valid assumptions
366 #    define UNREACHABLE()                                                                    \
367         do                                                                                   \
368         {                                                                                    \
369             FATAL() << "\t! Unreachable reached: " << __FUNCTION__ << "(" << __FILE__ << ":" \
370                     << __LINE__ << ")";                                                      \
371         } while (0)
372 #else
373 #    define UNIMPLEMENTED()                 \
374         do                                  \
375         {                                   \
376             ASSERT(NOASSERT_UNIMPLEMENTED); \
377         } while (0)
378 
379 // A macro for code which is not expected to be reached under valid assumptions
380 #    define UNREACHABLE()  \
381         do                 \
382         {                  \
383             ASSERT(false); \
384         } while (0)
385 #endif  // defined(ANGLE_TRACE_ENABLED) || defined(ANGLE_ENABLE_ASSERTS)
386 
387 #if defined(ANGLE_PLATFORM_WINDOWS)
388 #    define ANGLE_FUNCTION __FUNCTION__
389 #else
390 #    define ANGLE_FUNCTION __func__
391 #endif
392 
393 // Defining ANGLE_ENABLE_STRUCT_PADDING_WARNINGS will enable warnings when members are added to
394 // structs to enforce packing. This is helpful for diagnosing unexpected struct sizes when making
395 // fast cache variables.
396 #if defined(__clang__)
397 #    define ANGLE_ENABLE_STRUCT_PADDING_WARNINGS \
398         _Pragma("clang diagnostic push") _Pragma("clang diagnostic error \"-Wpadded\"")
399 #    define ANGLE_DISABLE_STRUCT_PADDING_WARNINGS _Pragma("clang diagnostic pop")
400 #elif defined(__GNUC__)
401 #    define ANGLE_ENABLE_STRUCT_PADDING_WARNINGS \
402         _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic error \"-Wpadded\"")
403 #    define ANGLE_DISABLE_STRUCT_PADDING_WARNINGS _Pragma("GCC diagnostic pop")
404 #elif defined(_MSC_VER)
405 #    define ANGLE_ENABLE_STRUCT_PADDING_WARNINGS \
406         __pragma(warning(push)) __pragma(warning(error : 4820))
407 #    define ANGLE_DISABLE_STRUCT_PADDING_WARNINGS __pragma(warning(pop))
408 #else
409 #    define ANGLE_ENABLE_STRUCT_PADDING_WARNINGS
410 #    define ANGLE_DISABLE_STRUCT_PADDING_WARNINGS
411 #endif
412 
413 #if defined(__clang__)
414 #    define ANGLE_DISABLE_SUGGEST_OVERRIDE_WARNINGS                               \
415         _Pragma("clang diagnostic push")                                          \
416             _Pragma("clang diagnostic ignored \"-Wsuggest-destructor-override\"") \
417                 _Pragma("clang diagnostic ignored \"-Wsuggest-override\"")
418 #    define ANGLE_REENABLE_SUGGEST_OVERRIDE_WARNINGS _Pragma("clang diagnostic pop")
419 #else
420 #    define ANGLE_DISABLE_SUGGEST_OVERRIDE_WARNINGS
421 #    define ANGLE_REENABLE_SUGGEST_OVERRIDE_WARNINGS
422 #endif
423 
424 #if defined(__clang__)
425 #    define ANGLE_DISABLE_EXTRA_SEMI_WARNING \
426         _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wextra-semi\"")
427 #    define ANGLE_REENABLE_EXTRA_SEMI_WARNING _Pragma("clang diagnostic pop")
428 #else
429 #    define ANGLE_DISABLE_EXTRA_SEMI_WARNING
430 #    define ANGLE_REENABLE_EXTRA_SEMI_WARNING
431 #endif
432 
433 #if defined(__clang__)
434 #    define ANGLE_DISABLE_EXTRA_SEMI_STMT_WARNING \
435         _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wextra-semi-stmt\"")
436 #    define ANGLE_REENABLE_EXTRA_SEMI_STMT_WARNING _Pragma("clang diagnostic pop")
437 #else
438 #    define ANGLE_DISABLE_EXTRA_SEMI_STMT_WARNING
439 #    define ANGLE_REENABLE_EXTRA_SEMI_STMT_WARNING
440 #endif
441 
442 #if defined(__clang__)
443 #    define ANGLE_DISABLE_SHADOWING_WARNING \
444         _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wshadow-field\"")
445 #    define ANGLE_REENABLE_SHADOWING_WARNING _Pragma("clang diagnostic pop")
446 #else
447 #    define ANGLE_DISABLE_SHADOWING_WARNING
448 #    define ANGLE_REENABLE_SHADOWING_WARNING
449 #endif
450 
451 #if defined(__clang__)
452 #    define ANGLE_DISABLE_DESTRUCTOR_OVERRIDE_WARNING \
453         _Pragma("clang diagnostic push")              \
454             _Pragma("clang diagnostic ignored \"-Winconsistent-missing-destructor-override\"")
455 #    define ANGLE_REENABLE_DESTRUCTOR_OVERRIDE_WARNING _Pragma("clang diagnostic pop")
456 #else
457 #    define ANGLE_DISABLE_DESTRUCTOR_OVERRIDE_WARNING
458 #    define ANGLE_REENABLE_DESTRUCTOR_OVERRIDE_WARNING
459 #endif
460 
461 #if defined(__clang__)
462 #    define ANGLE_DISABLE_UNUSED_FUNCTION_WARNING \
463         _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wunused-function\"")
464 #    define ANGLE_REENABLE_UNUSED_FUNCTION_WARNING _Pragma("clang diagnostic pop")
465 #else
466 #    define ANGLE_DISABLE_UNUSED_FUNCTION_WARNING
467 #    define ANGLE_REENABLE_UNUSED_FUNCTION_WARNING
468 #endif
469 
470 #endif  // COMMON_DEBUG_H_
471