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