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