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