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 | |
28 | namespace gl |
29 | { |
30 | |
31 | // Pairs a D3D begin event with an end event. |
32 | class 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 | |
43 | using LogSeverity = int; |
44 | // Note: the log severities are used to index into the array of names, |
45 | // see g_logSeverityNames. |
46 | constexpr LogSeverity LOG_EVENT = 0; |
47 | constexpr LogSeverity LOG_WARN = 1; |
48 | constexpr LogSeverity LOG_ERR = 2; |
49 | constexpr LogSeverity LOG_FATAL = 3; |
50 | constexpr LogSeverity LOG_NUM_SEVERITIES = 4; |
51 | |
52 | void 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. |
61 | class 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. |
82 | class 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 | |
97 | void InitializeDebugAnnotations(DebugAnnotator *debugAnnotator); |
98 | void UninitializeDebugAnnotations(); |
99 | bool DebugAnnotationsActive(); |
100 | bool DebugAnnotationsInitialized(); |
101 | |
102 | void InitializeDebugMutexIfNeeded(); |
103 | |
104 | namespace 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". |
108 | class 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 | |
116 | extern std::ostream *gSwallowStream; |
117 | |
118 | // Used by ANGLE_LOG_IS_ON to lazy-evaluate stream arguments. |
119 | bool ShouldCreatePlatformLogMessage(LogSeverity severity); |
120 | |
121 | template <int N, typename T> |
122 | std::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 | |
139 | template <typename T> |
140 | std::ostream &FmtHexAutoSized(std::ostream &os, T value) |
141 | { |
142 | constexpr int N = sizeof(T) * 2; |
143 | return priv::FmtHex<N>(os, value); |
144 | } |
145 | |
146 | template <typename T> |
147 | class 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 | |
169 | template <typename T> |
170 | priv::FmtHexHelper<T> FmtHex(T value) |
171 | { |
172 | return priv::FmtHexHelper<T>(value); |
173 | } |
174 | |
175 | #if defined(ANGLE_PLATFORM_WINDOWS) |
176 | priv::FmtHexHelper<HRESULT> FmtHR(HRESULT value); |
177 | priv::FmtHexHelper<DWORD> FmtErr(DWORD value); |
178 | #endif // defined(ANGLE_PLATFORM_WINDOWS) |
179 | |
180 | template <typename T> |
181 | std::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 \ |
354 | _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wextra-semi\"") |
355 | # define _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 | |