// // Copyright 2024 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // log_utils.h: Logging and assert utilities. A lot of the logging code is adapted from Chromium's // base/logging.h. #ifndef COMMON_LOG_UTILS_H_ #define COMMON_LOG_UTILS_H_ #include <assert.h> #include <stdio.h> #include <iomanip> #include <ios> #include <mutex> #include <sstream> #include <string> #include "common/angleutils.h" #include "common/entry_points_enum_autogen.h" #include "common/platform.h" namespace gl { class Context; LogSeverity; // Note: the log severities are used to index into the array of names, // see g_logSeverityNames. constexpr LogSeverity LOG_EVENT = …; constexpr LogSeverity LOG_INFO = …; constexpr LogSeverity LOG_WARN = …; constexpr LogSeverity LOG_ERR = …; constexpr LogSeverity LOG_FATAL = …; constexpr LogSeverity LOG_NUM_SEVERITIES = …; void Trace(LogSeverity severity, const char *message); // This class more or less represents a particular log message. You // create an instance of LogMessage and then stream stuff to it. // When you finish streaming to it, ~LogMessage is called and the // full message gets streamed to the appropriate destination. // // You shouldn't actually use LogMessage's constructor to log things, // though. You should use the ERR() and WARN() macros. class LogMessage : angle::NonCopyable { … }; bool ShouldBeginScopedEvent(const gl::Context *context); namespace priv { // This class is used to explicitly ignore values in the conditional logging macros. This avoids // compiler warnings like "value computed is not used" and "statement has no effect". class LogMessageVoidify { … }; extern std::ostream *gSwallowStream; // Used by ANGLE_LOG_IS_ON to lazy-evaluate stream arguments. bool ShouldCreatePlatformLogMessage(LogSeverity severity); // N is the width of the output to the stream. The output is padded with zeros // if value is less than N characters. // S is the stream type, either ostream for ANSI or wostream for wide character. // T is the type of the value to output to the stream. // C is the type of characters - either char for ANSI or wchar_t for wide char. template <int N, typename S, typename T, typename C> S &FmtHex(S &stream, T value, const C *zeroX, C zero) { … } template <typename S, typename T, typename C> S &FmtHexAutoSized(S &stream, T value, const C *prefix, const C *zeroX, C zero) { … } template <typename T, typename C> class FmtHexHelper { … }; } // namespace priv template <typename T, typename C = char> priv::FmtHexHelper<T, C> FmtHex(T value) { … } #if defined(ANGLE_PLATFORM_WINDOWS) priv::FmtHexHelper<HRESULT, char> FmtHR(HRESULT value); priv::FmtHexHelper<DWORD, char> FmtErr(DWORD value); #endif // defined(ANGLE_PLATFORM_WINDOWS) template <typename T> std::ostream &FmtHex(std::ostream &os, T value) { … } // A few definitions of macros that don't generate much code. These are used // by ANGLE_LOG(). Since these are used all over our code, it's // better to have compact code for these operations. #define COMPACT_ANGLE_LOG_EX_EVENT(ClassName, ...) … #define COMPACT_ANGLE_LOG_EX_INFO(ClassName, ...) … #define COMPACT_ANGLE_LOG_EX_WARN(ClassName, ...) … #define COMPACT_ANGLE_LOG_EX_ERR(ClassName, ...) … #define COMPACT_ANGLE_LOG_EX_FATAL(ClassName, ...) … #define COMPACT_ANGLE_LOG_EVENT … #define COMPACT_ANGLE_LOG_INFO … #define COMPACT_ANGLE_LOG_WARN … #define COMPACT_ANGLE_LOG_ERR … #define COMPACT_ANGLE_LOG_FATAL … #define ANGLE_LOG_IS_ON(severity) … // Helper macro which avoids evaluating the arguments to a stream if the condition doesn't hold. // Condition is evaluated once and only once. #define ANGLE_LAZY_STREAM(stream, condition) … // We use the preprocessor's merging operator, "##", so that, e.g., // ANGLE_LOG(EVENT) becomes the token COMPACT_ANGLE_LOG_EVENT. There's some funny // subtle difference between ostream member streaming functions (e.g., // ostream::operator<<(int) and ostream non-member streaming functions // (e.g., ::operator<<(ostream&, string&): it turns out that it's // impossible to stream something like a string directly to an unnamed // ostream. We employ a neat hack by calling the stream() member // function of LogMessage which seems to avoid the problem. #define ANGLE_LOG_STREAM(severity) … #define ANGLE_LOG(severity) … } // namespace gl #if defined(ANGLE_ENABLE_DEBUG_TRACE) || defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS) #define ANGLE_TRACE_ENABLED #endif #if !defined(NDEBUG) || defined(ANGLE_ASSERT_ALWAYS_ON) #define ANGLE_ENABLE_ASSERTS #endif #define INFO() … #define WARN() … #define ERR() … #define FATAL() … // A macro to log a performance event around a scope. #if defined(ANGLE_TRACE_ENABLED) # if defined(_MSC_VER) #define EVENT … # else #define EVENT … # endif // _MSC_VER #else #define EVENT(message, ...) … #endif // Note that gSwallowStream is used instead of an arbitrary LOG() stream to avoid the creation of an // object with a non-trivial destructor (LogMessage). On MSVC x86 (checked on 2015 Update 3), this // causes a few additional pointless instructions to be emitted even at full optimization level, // even though the : arm of the ternary operator is clearly never executed. Using a simpler object // to be &'d with Voidify() avoids these extra instructions. Using a simpler POD object with a // templated operator<< also works to avoid these instructions. However, this causes warnings on // statically defined implementations of operator<<(std::ostream, ...) in some .cpp files, because // they become defined-but-unreferenced functions. A reinterpret_cast of 0 to an ostream* also is // not suitable, because some compilers warn of undefined behavior. #define ANGLE_EAT_STREAM_PARAMETERS … // A macro asserting a condition and outputting failures to the debug log #if defined(ANGLE_ENABLE_ASSERTS) #define ASSERT(expression) … #else #define ASSERT … #endif // defined(ANGLE_ENABLE_ASSERTS) // A macro to indicate unimplemented functionality #ifndef NOASSERT_UNIMPLEMENTED #define NOASSERT_UNIMPLEMENTED … #endif #if defined(ANGLE_TRACE_ENABLED) || defined(ANGLE_ENABLE_ASSERTS) #define UNIMPLEMENTED() … // A macro for code which is not expected to be reached under valid assumptions #define UNREACHABLE() … #else #define UNIMPLEMENTED … // A macro for code which is not expected to be reached under valid assumptions #define UNREACHABLE … #endif // defined(ANGLE_TRACE_ENABLED) || defined(ANGLE_ENABLE_ASSERTS) #if defined(ANGLE_PLATFORM_WINDOWS) #define ANGLE_FUNCTION … #else #define ANGLE_FUNCTION … #endif #endif // COMMON_LOG_UTILS_H_