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 D3D begin event with an end event.
41 class 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 template <int N, typename T>
FmtHex(std::ostream & os,T value)145 std::ostream &FmtHex(std::ostream &os, T value)
146 {
147 os << "0x";
148
149 std::ios_base::fmtflags oldFlags = os.flags();
150 std::streamsize oldWidth = os.width();
151 std::ostream::char_type oldFill = os.fill();
152
153 os << std::hex << std::uppercase << std::setw(N) << std::setfill('0') << value;
154
155 os.flags(oldFlags);
156 os.width(oldWidth);
157 os.fill(oldFill);
158
159 return os;
160 }
161
162 template <typename T>
FmtHexAutoSized(std::ostream & os,T value)163 std::ostream &FmtHexAutoSized(std::ostream &os, T value)
164 {
165 constexpr int N = sizeof(T) * 2;
166 return priv::FmtHex<N>(os, value);
167 }
168
169 template <typename T>
170 class FmtHexHelper
171 {
172 public:
FmtHexHelper(const char * prefix,T value)173 FmtHexHelper(const char *prefix, T value) : mPrefix(prefix), mValue(value) {}
FmtHexHelper(T value)174 explicit FmtHexHelper(T value) : mPrefix(nullptr), mValue(value) {}
175
176 private:
177 const char *mPrefix;
178 T mValue;
179
180 friend std::ostream &operator<<(std::ostream &os, const FmtHexHelper &fmt)
181 {
182 if (fmt.mPrefix)
183 {
184 os << fmt.mPrefix;
185 }
186 return FmtHexAutoSized(os, fmt.mValue);
187 }
188 };
189
190 } // namespace priv
191
192 template <typename T>
FmtHex(T value)193 priv::FmtHexHelper<T> FmtHex(T value)
194 {
195 return priv::FmtHexHelper<T>(value);
196 }
197
198 #if defined(ANGLE_PLATFORM_WINDOWS)
199 priv::FmtHexHelper<HRESULT> FmtHR(HRESULT value);
200 priv::FmtHexHelper<DWORD> FmtErr(DWORD value);
201 #endif // defined(ANGLE_PLATFORM_WINDOWS)
202
203 template <typename T>
FmtHex(std::ostream & os,T value)204 std::ostream &FmtHex(std::ostream &os, T value)
205 {
206 return priv::FmtHexAutoSized(os, value);
207 }
208
209 // A few definitions of macros that don't generate much code. These are used
210 // by ANGLE_LOG(). Since these are used all over our code, it's
211 // better to have compact code for these operations.
212 #define COMPACT_ANGLE_LOG_EX_EVENT(ClassName, ...) \
213 ::gl::ClassName(__FILE__, __FUNCTION__, __LINE__, ::gl::LOG_EVENT, ##__VA_ARGS__)
214 #define COMPACT_ANGLE_LOG_EX_INFO(ClassName, ...) \
215 ::gl::ClassName(__FILE__, __FUNCTION__, __LINE__, ::gl::LOG_INFO, ##__VA_ARGS__)
216 #define COMPACT_ANGLE_LOG_EX_WARN(ClassName, ...) \
217 ::gl::ClassName(__FILE__, __FUNCTION__, __LINE__, ::gl::LOG_WARN, ##__VA_ARGS__)
218 #define COMPACT_ANGLE_LOG_EX_ERR(ClassName, ...) \
219 ::gl::ClassName(__FILE__, __FUNCTION__, __LINE__, ::gl::LOG_ERR, ##__VA_ARGS__)
220 #define COMPACT_ANGLE_LOG_EX_FATAL(ClassName, ...) \
221 ::gl::ClassName(__FILE__, __FUNCTION__, __LINE__, ::gl::LOG_FATAL, ##__VA_ARGS__)
222
223 #define COMPACT_ANGLE_LOG_EVENT COMPACT_ANGLE_LOG_EX_EVENT(LogMessage)
224 #define COMPACT_ANGLE_LOG_INFO COMPACT_ANGLE_LOG_EX_INFO(LogMessage)
225 #define COMPACT_ANGLE_LOG_WARN COMPACT_ANGLE_LOG_EX_WARN(LogMessage)
226 #define COMPACT_ANGLE_LOG_ERR COMPACT_ANGLE_LOG_EX_ERR(LogMessage)
227 #define COMPACT_ANGLE_LOG_FATAL COMPACT_ANGLE_LOG_EX_FATAL(LogMessage)
228
229 #define ANGLE_LOG_IS_ON(severity) (::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_##severity))
230
231 // Helper macro which avoids evaluating the arguments to a stream if the condition doesn't hold.
232 // Condition is evaluated once and only once.
233 #define ANGLE_LAZY_STREAM(stream, condition) \
234 !(condition) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify() & (stream)
235
236 // We use the preprocessor's merging operator, "##", so that, e.g.,
237 // ANGLE_LOG(EVENT) becomes the token COMPACT_ANGLE_LOG_EVENT. There's some funny
238 // subtle difference between ostream member streaming functions (e.g.,
239 // ostream::operator<<(int) and ostream non-member streaming functions
240 // (e.g., ::operator<<(ostream&, string&): it turns out that it's
241 // impossible to stream something like a string directly to an unnamed
242 // ostream. We employ a neat hack by calling the stream() member
243 // function of LogMessage which seems to avoid the problem.
244 #define ANGLE_LOG_STREAM(severity) COMPACT_ANGLE_LOG_##severity.stream()
245
246 #define ANGLE_LOG(severity) ANGLE_LAZY_STREAM(ANGLE_LOG_STREAM(severity), ANGLE_LOG_IS_ON(severity))
247
248 } // namespace gl
249
250 #if defined(ANGLE_ENABLE_DEBUG_TRACE) || defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
251 # define ANGLE_TRACE_ENABLED
252 #endif
253
254 #if !defined(NDEBUG) || defined(ANGLE_ASSERT_ALWAYS_ON)
255 # define ANGLE_ENABLE_ASSERTS
256 #endif
257
258 #define INFO() ANGLE_LOG(INFO)
259 #define WARN() ANGLE_LOG(WARN)
260 #define ERR() ANGLE_LOG(ERR)
261 #define FATAL() ANGLE_LOG(FATAL)
262
263 // A macro to log a performance event around a scope.
264 #if defined(ANGLE_TRACE_ENABLED)
265 # if defined(_MSC_VER)
266 # define EVENT(context, entryPoint, message, ...) \
267 gl::ScopedPerfEventHelper scopedPerfEventHelper##__LINE__( \
268 context, angle::EntryPoint::entryPoint); \
269 do \
270 { \
271 if (gl::ShouldBeginScopedEvent()) \
272 { \
273 scopedPerfEventHelper##__LINE__.begin( \
274 "%s(" message ")", GetEntryPointName(angle::EntryPoint::entryPoint), \
275 __VA_ARGS__); \
276 } \
277 } while (0)
278 # else
279 # define EVENT(context, entryPoint, message, ...) \
280 gl::ScopedPerfEventHelper scopedPerfEventHelper(context, \
281 angle::EntryPoint::entryPoint); \
282 do \
283 { \
284 if (gl::ShouldBeginScopedEvent()) \
285 { \
286 scopedPerfEventHelper.begin("%s(" message ")", \
287 GetEntryPointName(angle::EntryPoint::entryPoint), \
288 ##__VA_ARGS__); \
289 } \
290 } while (0)
291 # endif // _MSC_VER
292 #else
293 # define EVENT(message, ...) (void(0))
294 #endif
295
296 // The state tracked by ANGLE will be validated with the driver state before each call
297 #if defined(ANGLE_ENABLE_DEBUG_TRACE)
298 # define ANGLE_STATE_VALIDATION_ENABLED
299 #endif
300
301 #if defined(__GNUC__)
302 # define ANGLE_CRASH() __builtin_trap()
303 #else
304 # define ANGLE_CRASH() ((void)(*(volatile char *)0 = 0)), __assume(0)
305 #endif
306
307 #if !defined(NDEBUG)
308 # define ANGLE_ASSERT_IMPL(expression) assert(expression)
309 #else
310 // TODO(jmadill): Detect if debugger is attached and break.
311 # define ANGLE_ASSERT_IMPL(expression) ANGLE_CRASH()
312 #endif // !defined(NDEBUG)
313
314 // Note that gSwallowStream is used instead of an arbitrary LOG() stream to avoid the creation of an
315 // object with a non-trivial destructor (LogMessage). On MSVC x86 (checked on 2015 Update 3), this
316 // causes a few additional pointless instructions to be emitted even at full optimization level,
317 // even though the : arm of the ternary operator is clearly never executed. Using a simpler object
318 // to be &'d with Voidify() avoids these extra instructions. Using a simpler POD object with a
319 // templated operator<< also works to avoid these instructions. However, this causes warnings on
320 // statically defined implementations of operator<<(std::ostream, ...) in some .cpp files, because
321 // they become defined-but-unreferenced functions. A reinterpret_cast of 0 to an ostream* also is
322 // not suitable, because some compilers warn of undefined behavior.
323 #define ANGLE_EAT_STREAM_PARAMETERS \
324 true ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify() & (*::gl::priv::gSwallowStream)
325
326 // A macro asserting a condition and outputting failures to the debug log
327 #if defined(ANGLE_ENABLE_ASSERTS)
328 # define ASSERT(expression) \
329 (expression ? static_cast<void>(0) \
330 : (FATAL() << "\t! Assert failed in " << __FUNCTION__ << " (" << __FILE__ \
331 << ":" << __LINE__ << "): " << #expression))
332 #else
333 # define ASSERT(condition) ANGLE_EAT_STREAM_PARAMETERS << !(condition)
334 #endif // defined(ANGLE_ENABLE_ASSERTS)
335
336 #define UNREACHABLE_IS_NORETURN 0
337
338 #define ANGLE_UNUSED_VARIABLE(variable) (static_cast<void>(variable))
339
340 // A macro to indicate unimplemented functionality
341 #ifndef NOASSERT_UNIMPLEMENTED
342 # define NOASSERT_UNIMPLEMENTED 1
343 #endif
344
345 #if defined(ANGLE_TRACE_ENABLED) || defined(ANGLE_ENABLE_ASSERTS)
346 # define UNIMPLEMENTED() \
347 do \
348 { \
349 WARN() << "\t! Unimplemented: " << __FUNCTION__ << "(" << __FILE__ << ":" << __LINE__ \
350 << ")"; \
351 ASSERT(NOASSERT_UNIMPLEMENTED); \
352 } while (0)
353
354 // A macro for code which is not expected to be reached under valid assumptions
355 # define UNREACHABLE() \
356 do \
357 { \
358 FATAL() << "\t! Unreachable reached: " << __FUNCTION__ << "(" << __FILE__ << ":" \
359 << __LINE__ << ")"; \
360 } while (0)
361 #else
362 # define UNIMPLEMENTED() \
363 do \
364 { \
365 ASSERT(NOASSERT_UNIMPLEMENTED); \
366 } while (0)
367
368 // A macro for code which is not expected to be reached under valid assumptions
369 # define UNREACHABLE() \
370 do \
371 { \
372 ASSERT(false); \
373 } while (0)
374 #endif // defined(ANGLE_TRACE_ENABLED) || defined(ANGLE_ENABLE_ASSERTS)
375
376 #if defined(ANGLE_PLATFORM_WINDOWS)
377 # define ANGLE_FUNCTION __FUNCTION__
378 #else
379 # define ANGLE_FUNCTION __func__
380 #endif
381
382 // Defining ANGLE_ENABLE_STRUCT_PADDING_WARNINGS will enable warnings when members are added to
383 // structs to enforce packing. This is helpful for diagnosing unexpected struct sizes when making
384 // fast cache variables.
385 #if defined(__clang__)
386 # define ANGLE_ENABLE_STRUCT_PADDING_WARNINGS \
387 _Pragma("clang diagnostic push") _Pragma("clang diagnostic error \"-Wpadded\"")
388 # define ANGLE_DISABLE_STRUCT_PADDING_WARNINGS _Pragma("clang diagnostic pop")
389 #elif defined(__GNUC__)
390 # define ANGLE_ENABLE_STRUCT_PADDING_WARNINGS \
391 _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic error \"-Wpadded\"")
392 # define ANGLE_DISABLE_STRUCT_PADDING_WARNINGS _Pragma("GCC diagnostic pop")
393 #elif defined(_MSC_VER)
394 # define ANGLE_ENABLE_STRUCT_PADDING_WARNINGS \
395 __pragma(warning(push)) __pragma(warning(error : 4820))
396 # define ANGLE_DISABLE_STRUCT_PADDING_WARNINGS __pragma(warning(pop))
397 #else
398 # define ANGLE_ENABLE_STRUCT_PADDING_WARNINGS
399 # define ANGLE_DISABLE_STRUCT_PADDING_WARNINGS
400 #endif
401
402 #if defined(__clang__)
403 # define ANGLE_DISABLE_SUGGEST_OVERRIDE_WARNINGS \
404 _Pragma("clang diagnostic push") \
405 _Pragma("clang diagnostic ignored \"-Wsuggest-destructor-override\"") \
406 _Pragma("clang diagnostic ignored \"-Wsuggest-override\"")
407 # define ANGLE_REENABLE_SUGGEST_OVERRIDE_WARNINGS _Pragma("clang diagnostic pop")
408 #else
409 # define ANGLE_DISABLE_SUGGEST_OVERRIDE_WARNINGS
410 # define ANGLE_REENABLE_SUGGEST_OVERRIDE_WARNINGS
411 #endif
412
413 #if defined(__clang__)
414 # define ANGLE_DISABLE_EXTRA_SEMI_WARNING \
415 _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wextra-semi\"")
416 # define ANGLE_REENABLE_EXTRA_SEMI_WARNING _Pragma("clang diagnostic pop")
417 #else
418 # define ANGLE_DISABLE_EXTRA_SEMI_WARNING
419 # define ANGLE_REENABLE_EXTRA_SEMI_WARNING
420 #endif
421
422 #if defined(__clang__)
423 # define ANGLE_DISABLE_EXTRA_SEMI_STMT_WARNING \
424 _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wextra-semi-stmt\"")
425 # define ANGLE_REENABLE_EXTRA_SEMI_STMT_WARNING _Pragma("clang diagnostic pop")
426 #else
427 # define ANGLE_DISABLE_EXTRA_SEMI_STMT_WARNING
428 # define ANGLE_REENABLE_EXTRA_SEMI_STMT_WARNING
429 #endif
430
431 #if defined(__clang__)
432 # define ANGLE_DISABLE_SHADOWING_WARNING \
433 _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wshadow-field\"")
434 # define ANGLE_REENABLE_SHADOWING_WARNING _Pragma("clang diagnostic pop")
435 #else
436 # define ANGLE_DISABLE_SHADOWING_WARNING
437 # define ANGLE_REENABLE_SHADOWING_WARNING
438 #endif
439
440 #if defined(__clang__)
441 # define ANGLE_DISABLE_DESTRUCTOR_OVERRIDE_WARNING \
442 _Pragma("clang diagnostic push") \
443 _Pragma("clang diagnostic ignored \"-Winconsistent-missing-destructor-override\"")
444 # define ANGLE_REENABLE_DESTRUCTOR_OVERRIDE_WARNING _Pragma("clang diagnostic pop")
445 #else
446 # define ANGLE_DISABLE_DESTRUCTOR_OVERRIDE_WARNING
447 # define ANGLE_REENABLE_DESTRUCTOR_OVERRIDE_WARNING
448 #endif
449
450 #if defined(__clang__)
451 # define ANGLE_DISABLE_UNUSED_FUNCTION_WARNING \
452 _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wunused-function\"")
453 # define ANGLE_REENABLE_UNUSED_FUNCTION_WARNING _Pragma("clang diagnostic pop")
454 #else
455 # define ANGLE_DISABLE_UNUSED_FUNCTION_WARNING
456 # define ANGLE_REENABLE_UNUSED_FUNCTION_WARNING
457 #endif
458
459 #endif // COMMON_DEBUG_H_
460