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(TRACE_OUTPUT_FILE)
27 # define TRACE_OUTPUT_FILE "angle_debug.txt"
28 #endif
29
30 namespace gl
31 {
32 class Context;
33
34 // Pairs a D3D begin event with an end event.
35 class ScopedPerfEventHelper : angle::NonCopyable
36 {
37 public:
38 ScopedPerfEventHelper(Context *context, angle::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 angle::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 angle::EntryPoint entryPoint,
97 const char *eventName,
98 const char *eventMessage) = 0;
99 virtual void endEvent(gl::Context *context,
100 const char *eventName,
101 angle::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_ASSERT_ALWAYS_ON)
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, message, ...) \
260 gl::ScopedPerfEventHelper scopedPerfEventHelper##__LINE__( \
261 context, angle::EntryPoint::entryPoint); \
262 do \
263 { \
264 if (gl::ShouldBeginScopedEvent()) \
265 { \
266 scopedPerfEventHelper##__LINE__.begin( \
267 "%s(" message ")", GetEntryPointName(angle::EntryPoint::entryPoint), \
268 __VA_ARGS__); \
269 } \
270 } while (0)
271 # else
272 # define EVENT(context, entryPoint, message, ...) \
273 gl::ScopedPerfEventHelper scopedPerfEventHelper(context, \
274 angle::EntryPoint::entryPoint); \
275 do \
276 { \
277 if (gl::ShouldBeginScopedEvent()) \
278 { \
279 scopedPerfEventHelper.begin("%s(" message ")", \
280 GetEntryPointName(angle::EntryPoint::entryPoint), \
281 ##__VA_ARGS__); \
282 } \
283 } while (0)
284 # endif // _MSC_VER
285 #else
286 # define EVENT(message, ...) (void(0))
287 #endif
288
289 // The state tracked by ANGLE will be validated with the driver state before each call
290 #if defined(ANGLE_ENABLE_DEBUG_TRACE)
291 # define ANGLE_STATE_VALIDATION_ENABLED
292 #endif
293
294 #if defined(__GNUC__)
295 # define ANGLE_CRASH() __builtin_trap()
296 #else
297 # define ANGLE_CRASH() ((void)(*(volatile char *)0 = 0)), __assume(0)
298 #endif
299
300 #if !defined(NDEBUG)
301 # define ANGLE_ASSERT_IMPL(expression) assert(expression)
302 #else
303 // TODO(jmadill): Detect if debugger is attached and break.
304 # define ANGLE_ASSERT_IMPL(expression) ANGLE_CRASH()
305 #endif // !defined(NDEBUG)
306
307 // Note that gSwallowStream is used instead of an arbitrary LOG() stream to avoid the creation of an
308 // object with a non-trivial destructor (LogMessage). On MSVC x86 (checked on 2015 Update 3), this
309 // causes a few additional pointless instructions to be emitted even at full optimization level,
310 // even though the : arm of the ternary operator is clearly never executed. Using a simpler object
311 // to be &'d with Voidify() avoids these extra instructions. Using a simpler POD object with a
312 // templated operator<< also works to avoid these instructions. However, this causes warnings on
313 // statically defined implementations of operator<<(std::ostream, ...) in some .cpp files, because
314 // they become defined-but-unreferenced functions. A reinterpret_cast of 0 to an ostream* also is
315 // not suitable, because some compilers warn of undefined behavior.
316 #define ANGLE_EAT_STREAM_PARAMETERS \
317 true ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify() & (*::gl::priv::gSwallowStream)
318
319 // A macro asserting a condition and outputting failures to the debug log
320 #if defined(ANGLE_ENABLE_ASSERTS)
321 # define ASSERT(expression) \
322 (expression ? static_cast<void>(0) \
323 : (FATAL() << "\t! Assert failed in " << __FUNCTION__ << " (" << __FILE__ \
324 << ":" << __LINE__ << "): " << #expression))
325 #else
326 # define ASSERT(condition) ANGLE_EAT_STREAM_PARAMETERS << !(condition)
327 #endif // defined(ANGLE_ENABLE_ASSERTS)
328
329 #define UNREACHABLE_IS_NORETURN 0
330
331 #define ANGLE_UNUSED_VARIABLE(variable) (static_cast<void>(variable))
332
333 // A macro to indicate unimplemented functionality
334 #ifndef NOASSERT_UNIMPLEMENTED
335 # define NOASSERT_UNIMPLEMENTED 1
336 #endif
337
338 #if defined(ANGLE_TRACE_ENABLED) || defined(ANGLE_ENABLE_ASSERTS)
339 # define UNIMPLEMENTED() \
340 do \
341 { \
342 WARN() << "\t! Unimplemented: " << __FUNCTION__ << "(" << __FILE__ << ":" << __LINE__ \
343 << ")"; \
344 ASSERT(NOASSERT_UNIMPLEMENTED); \
345 } while (0)
346
347 // A macro for code which is not expected to be reached under valid assumptions
348 # define UNREACHABLE() \
349 do \
350 { \
351 FATAL() << "\t! Unreachable reached: " << __FUNCTION__ << "(" << __FILE__ << ":" \
352 << __LINE__ << ")"; \
353 } while (0)
354 #else
355 # define UNIMPLEMENTED() \
356 do \
357 { \
358 ASSERT(NOASSERT_UNIMPLEMENTED); \
359 } while (0)
360
361 // A macro for code which is not expected to be reached under valid assumptions
362 # define UNREACHABLE() \
363 do \
364 { \
365 ASSERT(false); \
366 } while (0)
367 #endif // defined(ANGLE_TRACE_ENABLED) || defined(ANGLE_ENABLE_ASSERTS)
368
369 #if defined(ANGLE_PLATFORM_WINDOWS)
370 # define ANGLE_FUNCTION __FUNCTION__
371 #else
372 # define ANGLE_FUNCTION __func__
373 #endif
374
375 // Defining ANGLE_ENABLE_STRUCT_PADDING_WARNINGS will enable warnings when members are added to
376 // structs to enforce packing. This is helpful for diagnosing unexpected struct sizes when making
377 // fast cache variables.
378 #if defined(__clang__)
379 # define ANGLE_ENABLE_STRUCT_PADDING_WARNINGS \
380 _Pragma("clang diagnostic push") _Pragma("clang diagnostic error \"-Wpadded\"")
381 # define ANGLE_DISABLE_STRUCT_PADDING_WARNINGS _Pragma("clang diagnostic pop")
382 #elif defined(__GNUC__)
383 # define ANGLE_ENABLE_STRUCT_PADDING_WARNINGS \
384 _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic error \"-Wpadded\"")
385 # define ANGLE_DISABLE_STRUCT_PADDING_WARNINGS _Pragma("GCC diagnostic pop")
386 #elif defined(_MSC_VER)
387 # define ANGLE_ENABLE_STRUCT_PADDING_WARNINGS \
388 __pragma(warning(push)) __pragma(warning(error : 4820))
389 # define ANGLE_DISABLE_STRUCT_PADDING_WARNINGS __pragma(warning(pop))
390 #else
391 # define ANGLE_ENABLE_STRUCT_PADDING_WARNINGS
392 # define ANGLE_DISABLE_STRUCT_PADDING_WARNINGS
393 #endif
394
395 #if defined(__clang__)
396 # define ANGLE_DISABLE_SUGGEST_OVERRIDE_WARNINGS \
397 _Pragma("clang diagnostic push") \
398 _Pragma("clang diagnostic ignored \"-Wsuggest-destructor-override\"") \
399 _Pragma("clang diagnostic ignored \"-Wsuggest-override\"")
400 # define ANGLE_REENABLE_SUGGEST_OVERRIDE_WARNINGS _Pragma("clang diagnostic pop")
401 #else
402 # define ANGLE_DISABLE_SUGGEST_OVERRIDE_WARNINGS
403 # define ANGLE_REENABLE_SUGGEST_OVERRIDE_WARNINGS
404 #endif
405
406 #if defined(__clang__)
407 # define ANGLE_DISABLE_EXTRA_SEMI_WARNING \
408 _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wextra-semi\"")
409 # define ANGLE_REENABLE_EXTRA_SEMI_WARNING _Pragma("clang diagnostic pop")
410 #else
411 # define ANGLE_DISABLE_EXTRA_SEMI_WARNING
412 # define ANGLE_REENABLE_EXTRA_SEMI_WARNING
413 #endif
414
415 #if defined(__clang__)
416 # define ANGLE_DISABLE_EXTRA_SEMI_STMT_WARNING \
417 _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wextra-semi-stmt\"")
418 # define ANGLE_REENABLE_EXTRA_SEMI_STMT_WARNING _Pragma("clang diagnostic pop")
419 #else
420 # define ANGLE_DISABLE_EXTRA_SEMI_STMT_WARNING
421 # define ANGLE_REENABLE_EXTRA_SEMI_STMT_WARNING
422 #endif
423
424 #if defined(__clang__)
425 # define ANGLE_DISABLE_SHADOWING_WARNING \
426 _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wshadow-field\"")
427 # define ANGLE_REENABLE_SHADOWING_WARNING _Pragma("clang diagnostic pop")
428 #else
429 # define ANGLE_DISABLE_SHADOWING_WARNING
430 # define ANGLE_REENABLE_SHADOWING_WARNING
431 #endif
432
433 #if defined(__clang__)
434 # define ANGLE_DISABLE_DESTRUCTOR_OVERRIDE_WARNING \
435 _Pragma("clang diagnostic push") \
436 _Pragma("clang diagnostic ignored \"-Winconsistent-missing-destructor-override\"")
437 # define ANGLE_REENABLE_DESTRUCTOR_OVERRIDE_WARNING _Pragma("clang diagnostic pop")
438 #else
439 # define ANGLE_DISABLE_DESTRUCTOR_OVERRIDE_WARNING
440 # define ANGLE_REENABLE_DESTRUCTOR_OVERRIDE_WARNING
441 #endif
442
443 #if defined(__clang__)
444 # define ANGLE_DISABLE_WEAK_TEMPLATE_VTABLES_WARNING \
445 _Pragma("clang diagnostic push") \
446 _Pragma("clang diagnostic ignored \"-Wweak-template-vtables\"")
447 # define ANGLE_REENABLE_WEAK_TEMPLATE_VTABLES_WARNING _Pragma("clang diagnostic pop")
448 #else
449 # define ANGLE_DISABLE_WEAK_TEMPLATE_VTABLES_WARNING
450 # define ANGLE_REENABLE_WEAK_TEMPLATE_VTABLES_WARNING
451 #endif
452
453 #if defined(__clang__)
454 # define ANGLE_DISABLE_UNUSED_FUNCTION_WARNING \
455 _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wunused-function\"")
456 # define ANGLE_REENABLE_UNUSED_FUNCTION_WARNING _Pragma("clang diagnostic pop")
457 #else
458 # define ANGLE_DISABLE_UNUSED_FUNCTION_WARNING
459 # define ANGLE_REENABLE_UNUSED_FUNCTION_WARNING
460 #endif
461
462 #endif // COMMON_DEBUG_H_
463