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.
8 
9 #ifndef COMMON_DEBUG_H_
10 #define COMMON_DEBUG_H_
11 
12 #include <assert.h>
13 #include <stdio.h>
14 
15 #include <ios>
16 #include <iomanip>
17 #include <sstream>
18 #include <string>
19 
20 #include "common/angleutils.h"
21 
22 #if !defined(TRACE_OUTPUT_FILE)
23 #define TRACE_OUTPUT_FILE "angle_debug.txt"
24 #endif
25 
26 namespace gl
27 {
28 
29 // Pairs a D3D begin event with an end event.
30 class ScopedPerfEventHelper : angle::NonCopyable
31 {
32   public:
33     ScopedPerfEventHelper(const char* format, ...);
34     ~ScopedPerfEventHelper();
35 };
36 
37 using LogSeverity = int;
38 // Note: the log severities are used to index into the array of names,
39 // see g_logSeverityNames.
40 constexpr LogSeverity LOG_EVENT          = 0;
41 constexpr LogSeverity LOG_WARN           = 1;
42 constexpr LogSeverity LOG_ERR            = 2;
43 constexpr LogSeverity LOG_NUM_SEVERITIES = 3;
44 
45 void Trace(LogSeverity severity, const char *message);
46 
47 // This class more or less represents a particular log message.  You
48 // create an instance of LogMessage and then stream stuff to it.
49 // When you finish streaming to it, ~LogMessage is called and the
50 // full message gets streamed to the appropriate destination.
51 //
52 // You shouldn't actually use LogMessage's constructor to log things,
53 // though.  You should use the ERR() and WARN() macros.
54 class LogMessage : angle::NonCopyable
55 {
56   public:
57     // Used for ANGLE_LOG(severity).
58     LogMessage(const char *function, int line, LogSeverity severity);
59     ~LogMessage();
stream()60     std::ostream &stream() { return mStream; }
61 
62     LogSeverity getSeverity() const;
63     std::string getMessage() const;
64 
65   private:
66     const char *mFunction;
67     const int mLine;
68     const LogSeverity mSeverity;
69 
70     std::ostringstream mStream;
71 };
72 
73 // Wraps the D3D9/D3D11 debug annotation functions.
74 // Also handles redirecting logging destination.
75 class DebugAnnotator : angle::NonCopyable
76 {
77   public:
DebugAnnotator()78     DebugAnnotator(){};
~DebugAnnotator()79     virtual ~DebugAnnotator() { };
80     virtual void beginEvent(const wchar_t *eventName) = 0;
81     virtual void endEvent() = 0;
82     virtual void setMarker(const wchar_t *markerName) = 0;
83     virtual bool getStatus() = 0;
84     // Log Message Handler that gets passed every log message,
85     // when debug annotations are initialized,
86     // replacing default handling by LogMessage.
87     virtual void logMessage(const LogMessage &msg) const = 0;
88 };
89 
90 void InitializeDebugAnnotations(DebugAnnotator *debugAnnotator);
91 void UninitializeDebugAnnotations();
92 bool DebugAnnotationsActive();
93 bool DebugAnnotationsInitialized();
94 
95 namespace priv
96 {
97 // This class is used to explicitly ignore values in the conditional logging macros. This avoids
98 // compiler warnings like "value computed is not used" and "statement has no effect".
99 class LogMessageVoidify
100 {
101   public:
LogMessageVoidify()102     LogMessageVoidify() {}
103     // This has to be an operator with a precedence lower than << but higher than ?:
104     void operator&(std::ostream &) {}
105 };
106 
107 // Used by ANGLE_LOG_IS_ON to lazy-evaluate stream arguments.
108 bool ShouldCreatePlatformLogMessage(LogSeverity severity);
109 
110 template <int N, typename T>
FmtHex(std::ostream & os,T value)111 std::ostream &FmtHex(std::ostream &os, T value)
112 {
113     os << "0x";
114 
115     std::ios_base::fmtflags oldFlags = os.flags();
116     std::streamsize oldWidth         = os.width();
117     std::ostream::char_type oldFill  = os.fill();
118 
119     os << std::hex << std::uppercase << std::setw(N) << std::setfill('0') << value;
120 
121     os.flags(oldFlags);
122     os.width(oldWidth);
123     os.fill(oldFill);
124 
125     return os;
126 }
127 }  // namespace priv
128 
129 #if defined(ANGLE_PLATFORM_WINDOWS)
130 class FmtHR
131 {
132   public:
FmtHR(HRESULT hresult)133     explicit FmtHR(HRESULT hresult) : mHR(hresult) {}
134   private:
135     HRESULT mHR;
136     friend std::ostream &operator<<(std::ostream &os, const FmtHR &fmt);
137 };
138 
139 class FmtErr
140 {
141   public:
FmtErr(DWORD err)142     explicit FmtErr(DWORD err) : mErr(err) {}
143 
144   private:
145     DWORD mErr;
146     friend std::ostream &operator<<(std::ostream &os, const FmtErr &fmt);
147 };
148 #endif  // defined(ANGLE_PLATFORM_WINDOWS)
149 
150 template <typename T>
FmtHexShort(std::ostream & os,T value)151 std::ostream &FmtHexShort(std::ostream &os, T value)
152 {
153     return priv::FmtHex<4>(os, value);
154 }
155 
156 template <typename T>
FmtHexInt(std::ostream & os,T value)157 std::ostream &FmtHexInt(std::ostream &os, T value)
158 {
159     return priv::FmtHex<8>(os, value);
160 }
161 
162 // A few definitions of macros that don't generate much code. These are used
163 // by ANGLE_LOG(). Since these are used all over our code, it's
164 // better to have compact code for these operations.
165 #define COMPACT_ANGLE_LOG_EX_EVENT(ClassName, ...) \
166     ::gl::ClassName(__FUNCTION__, __LINE__, ::gl::LOG_EVENT, ##__VA_ARGS__)
167 #define COMPACT_ANGLE_LOG_EX_WARN(ClassName, ...) \
168     ::gl::ClassName(__FUNCTION__, __LINE__, ::gl::LOG_WARN, ##__VA_ARGS__)
169 #define COMPACT_ANGLE_LOG_EX_ERR(ClassName, ...) \
170     ::gl::ClassName(__FUNCTION__, __LINE__, ::gl::LOG_ERR, ##__VA_ARGS__)
171 
172 #define COMPACT_ANGLE_LOG_EVENT COMPACT_ANGLE_LOG_EX_EVENT(LogMessage)
173 #define COMPACT_ANGLE_LOG_WARN COMPACT_ANGLE_LOG_EX_WARN(LogMessage)
174 #define COMPACT_ANGLE_LOG_ERR COMPACT_ANGLE_LOG_EX_ERR(LogMessage)
175 
176 #define ANGLE_LOG_IS_ON(severity) (::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_##severity))
177 
178 // Helper macro which avoids evaluating the arguments to a stream if the condition doesn't hold.
179 // Condition is evaluated once and only once.
180 #define ANGLE_LAZY_STREAM(stream, condition) \
181     !(condition) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify() & (stream)
182 
183 // We use the preprocessor's merging operator, "##", so that, e.g.,
184 // ANGLE_LOG(EVENT) becomes the token COMPACT_ANGLE_LOG_EVENT.  There's some funny
185 // subtle difference between ostream member streaming functions (e.g.,
186 // ostream::operator<<(int) and ostream non-member streaming functions
187 // (e.g., ::operator<<(ostream&, string&): it turns out that it's
188 // impossible to stream something like a string directly to an unnamed
189 // ostream. We employ a neat hack by calling the stream() member
190 // function of LogMessage which seems to avoid the problem.
191 #define ANGLE_LOG_STREAM(severity) COMPACT_ANGLE_LOG_##severity.stream()
192 
193 #define ANGLE_LOG(severity) ANGLE_LAZY_STREAM(ANGLE_LOG_STREAM(severity), ANGLE_LOG_IS_ON(severity))
194 
195 }  // namespace gl
196 
197 #if defined(ANGLE_ENABLE_DEBUG_TRACE) || defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
198 #define ANGLE_TRACE_ENABLED
199 #endif
200 
201 #define ANGLE_EMPTY_STATEMENT for (;;) break
202 #if !defined(NDEBUG) || defined(ANGLE_ENABLE_RELEASE_ASSERTS)
203 #define ANGLE_ENABLE_ASSERTS
204 #endif
205 
206 #define WARN() ANGLE_LOG(WARN)
207 #define ERR() ANGLE_LOG(ERR)
208 
209 // A macro to log a performance event around a scope.
210 #if defined(ANGLE_TRACE_ENABLED)
211 #if defined(_MSC_VER)
212 #define EVENT(message, ...) gl::ScopedPerfEventHelper scopedPerfEventHelper ## __LINE__("%s" message "\n", __FUNCTION__, __VA_ARGS__);
213 #else
214 #define EVENT(message, ...) gl::ScopedPerfEventHelper scopedPerfEventHelper("%s" message "\n", __FUNCTION__, ##__VA_ARGS__);
215 #endif // _MSC_VER
216 #else
217 #define EVENT(message, ...) (void(0))
218 #endif
219 
220 #if defined(COMPILER_GCC) || defined(__clang__)
221 #define ANGLE_CRASH() __builtin_trap()
222 #else
223 #define ANGLE_CRASH() ((void)(*(volatile char *)0 = 0))
224 #endif
225 
226 #if !defined(NDEBUG)
227 #define ANGLE_ASSERT_IMPL(expression) assert(expression)
228 #else
229 // TODO(jmadill): Detect if debugger is attached and break.
230 #define ANGLE_ASSERT_IMPL(expression) ANGLE_CRASH()
231 #endif  // !defined(NDEBUG)
232 
233 // A macro asserting a condition and outputting failures to the debug log
234 #if defined(ANGLE_ENABLE_ASSERTS)
235 #define ASSERT(expression)                                                                         \
236     (expression ? static_cast<void>(0) : ((ERR() << "\t! Assert failed in " << __FUNCTION__ << "(" \
237                                                  << __LINE__ << "): " << #expression),             \
238                                           ANGLE_ASSERT_IMPL(expression)))
239 #else
240 // These are just dummy values.
241 #define COMPACT_ANGLE_LOG_EX_ASSERT(ClassName, ...) \
242     COMPACT_ANGLE_LOG_EX_EVENT(ClassName, ##__VA_ARGS__)
243 #define COMPACT_ANGLE_LOG_ASSERT COMPACT_ANGLE_LOG_EVENT
244 namespace gl
245 {
246 constexpr LogSeverity LOG_ASSERT = LOG_EVENT;
247 }  // namespace gl
248 
249 #define ASSERT(condition)                                                     \
250     ANGLE_LAZY_STREAM(ANGLE_LOG_STREAM(ASSERT), false ? !(condition) : false) \
251         << "Check failed: " #condition ". "
252 #endif  // defined(ANGLE_ENABLE_ASSERTS)
253 
254 #define UNUSED_VARIABLE(variable) ((void)variable)
255 
256 // A macro to indicate unimplemented functionality
257 #ifndef NOASSERT_UNIMPLEMENTED
258 #define NOASSERT_UNIMPLEMENTED 1
259 #endif
260 
261 #if defined(ANGLE_TRACE_ENABLED) || defined(ANGLE_ENABLE_ASSERTS)
262 #define UNIMPLEMENTED()                                                                      \
263     {                                                                                        \
264         ERR() << "\t! Unimplemented: " << __FUNCTION__ << "(" << __FILE__ << ":" << __LINE__ \
265               << ")";                                                                        \
266         ASSERT(NOASSERT_UNIMPLEMENTED);                                                      \
267     }                                                                                        \
268     ANGLE_EMPTY_STATEMENT
269 
270 // A macro for code which is not expected to be reached under valid assumptions
271 #define UNREACHABLE()                                                                            \
272     ((ERR() << "\t! Unreachable reached: " << __FUNCTION__ << "(" << __FILE__ << ":" << __LINE__ \
273             << ")"),                                                                             \
274      ASSERT(false))
275 #else
276 #define UNIMPLEMENTED()                 \
277     {                                   \
278         ASSERT(NOASSERT_UNIMPLEMENTED); \
279     }                                   \
280     ANGLE_EMPTY_STATEMENT
281 
282 // A macro for code which is not expected to be reached under valid assumptions
283 #define UNREACHABLE() ASSERT(false)
284 #endif  // defined(ANGLE_TRACE_ENABLED) || defined(ANGLE_ENABLE_ASSERTS)
285 
286 #endif   // COMMON_DEBUG_H_
287