aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShahbaz Youssefi <syoussefi@chromium.org>2024-04-16 10:25:49 -0400
committerAngle LUCI CQ <angle-scoped@luci-project-accounts.iam.gserviceaccount.com>2024-04-16 15:57:30 +0000
commit97cb3eb8a79dcf752a99d0895719fde9f6bb3392 (patch)
treeb1c2f95d4a16c543cad83babf44370ba490590a6
parentd9d583bfdc05d3ccbcb4c048fe6693652d89d4ba (diff)
downloadangle-97cb3eb8a79dcf752a99d0895719fde9f6bb3392.tar.gz
Split ASSERT and logs into separate header
This is because SimpleMutex.h wants to ASSERT, which was defined in debug.h. That file has a function that returns a reference to a mutex that would eventually be changed to SimpleMutex. The circular dependency cannot be resolved with a forward declaration with SimpleMutex being defined with `using`. Bug: angleproject:8667 Change-Id: I9a3acb6d07c6702048b47a72d8411b0fc2166922 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5458631 Reviewed-by: Roman Lavrov <romanl@google.com> Commit-Queue: Roman Lavrov <romanl@google.com> Auto-Submit: Shahbaz Youssefi <syoussefi@chromium.org>
-rw-r--r--src/common/SimpleMutex.h2
-rw-r--r--src/common/debug.h284
-rw-r--r--src/common/log_utils.h315
-rw-r--r--src/libGLESv2.gni1
4 files changed, 318 insertions, 284 deletions
diff --git a/src/common/SimpleMutex.h b/src/common/SimpleMutex.h
index a6fd8c2b0a..5d3c30cb93 100644
--- a/src/common/SimpleMutex.h
+++ b/src/common/SimpleMutex.h
@@ -20,7 +20,7 @@
#ifndef COMMON_SIMPLEMUTEX_H_
#define COMMON_SIMPLEMUTEX_H_
-#include "common/debug.h"
+#include "common/log_utils.h"
#include "common/platform.h"
#include <atomic>
diff --git a/src/common/debug.h b/src/common/debug.h
index 21a55151f7..5c37c8ca57 100644
--- a/src/common/debug.h
+++ b/src/common/debug.h
@@ -21,6 +21,7 @@
#include "common/angleutils.h"
#include "common/entry_points_enum_autogen.h"
+#include "common/log_utils.h"
#include "common/platform.h"
#if defined(ANGLE_PLATFORM_WINDOWS)
@@ -53,45 +54,6 @@ class [[nodiscard]] ScopedPerfEventHelper : angle::NonCopyable
bool mCalledBeginEvent;
};
-using LogSeverity = int;
-// Note: the log severities are used to index into the array of names,
-// see g_logSeverityNames.
-constexpr LogSeverity LOG_EVENT = 0;
-constexpr LogSeverity LOG_INFO = 1;
-constexpr LogSeverity LOG_WARN = 2;
-constexpr LogSeverity LOG_ERR = 3;
-constexpr LogSeverity LOG_FATAL = 4;
-constexpr LogSeverity LOG_NUM_SEVERITIES = 5;
-
-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
-{
- public:
- // Used for ANGLE_LOG(severity).
- LogMessage(const char *file, const char *function, int line, LogSeverity severity);
- ~LogMessage();
- std::ostream &stream() { return mStream; }
-
- LogSeverity getSeverity() const;
- std::string getMessage() const;
-
- private:
- const char *mFile;
- const char *mFunction;
- const int mLine;
- const LogSeverity mSeverity;
-
- std::ostringstream mStream;
-};
-
// Wraps the API/Platform-specific debug annotation functions.
// Also handles redirecting logging destination.
class DebugAnnotator : angle::NonCopyable
@@ -114,7 +76,6 @@ class DebugAnnotator : angle::NonCopyable
virtual void logMessage(const LogMessage &msg) const = 0;
};
-bool ShouldBeginScopedEvent(const gl::Context *context);
void InitializeDebugAnnotations(DebugAnnotator *debugAnnotator);
void UninitializeDebugAnnotations();
bool DebugAnnotationsActive(const gl::Context *context);
@@ -123,187 +84,8 @@ bool DebugAnnotationsInitialized();
void InitializeDebugMutexIfNeeded();
std::mutex &GetDebugMutex();
-
-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
-{
- public:
- LogMessageVoidify() {}
- // This has to be an operator with a precedence lower than << but higher than ?:
- void operator&(std::ostream &) {}
-};
-
-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)
-{
- stream << zeroX;
-
- std::ios_base::fmtflags oldFlags = stream.flags();
- std::streamsize oldWidth = stream.width();
- typename S::char_type oldFill = stream.fill();
-
- stream << std::hex << std::uppercase << std::setw(N) << std::setfill(zero) << value;
-
- stream.flags(oldFlags);
- stream.width(oldWidth);
- stream.fill(oldFill);
-
- return stream;
-}
-
-template <typename S, typename T, typename C>
-S &FmtHexAutoSized(S &stream, T value, const C *prefix, const C *zeroX, C zero)
-{
- if (prefix)
- {
- stream << prefix;
- }
-
- constexpr int N = sizeof(T) * 2;
- return priv::FmtHex<N>(stream, value, zeroX, zero);
-}
-
-template <typename T, typename C>
-class FmtHexHelper
-{
- public:
- FmtHexHelper(const C *prefix, T value) : mPrefix(prefix), mValue(value) {}
- explicit FmtHexHelper(T value) : mPrefix(nullptr), mValue(value) {}
-
- private:
- const C *mPrefix;
- T mValue;
-
- friend std::ostream &operator<<(std::ostream &os, const FmtHexHelper &fmt)
- {
- return FmtHexAutoSized(os, fmt.mValue, fmt.mPrefix, "0x", '0');
- }
-
- friend std::wostream &operator<<(std::wostream &wos, const FmtHexHelper &fmt)
- {
- return FmtHexAutoSized(wos, fmt.mValue, fmt.mPrefix, L"0x", L'0');
- }
-};
-
-} // namespace priv
-
-template <typename T, typename C = char>
-priv::FmtHexHelper<T, C> FmtHex(T value)
-{
- return priv::FmtHexHelper<T, C>(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)
-{
- return priv::FmtHexAutoSized(os, value, "", "0x", '0');
-}
-
-// 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, ...) \
- ::gl::ClassName(__FILE__, __FUNCTION__, __LINE__, ::gl::LOG_EVENT, ##__VA_ARGS__)
-#define COMPACT_ANGLE_LOG_EX_INFO(ClassName, ...) \
- ::gl::ClassName(__FILE__, __FUNCTION__, __LINE__, ::gl::LOG_INFO, ##__VA_ARGS__)
-#define COMPACT_ANGLE_LOG_EX_WARN(ClassName, ...) \
- ::gl::ClassName(__FILE__, __FUNCTION__, __LINE__, ::gl::LOG_WARN, ##__VA_ARGS__)
-#define COMPACT_ANGLE_LOG_EX_ERR(ClassName, ...) \
- ::gl::ClassName(__FILE__, __FUNCTION__, __LINE__, ::gl::LOG_ERR, ##__VA_ARGS__)
-#define COMPACT_ANGLE_LOG_EX_FATAL(ClassName, ...) \
- ::gl::ClassName(__FILE__, __FUNCTION__, __LINE__, ::gl::LOG_FATAL, ##__VA_ARGS__)
-
-#define COMPACT_ANGLE_LOG_EVENT COMPACT_ANGLE_LOG_EX_EVENT(LogMessage)
-#define COMPACT_ANGLE_LOG_INFO COMPACT_ANGLE_LOG_EX_INFO(LogMessage)
-#define COMPACT_ANGLE_LOG_WARN COMPACT_ANGLE_LOG_EX_WARN(LogMessage)
-#define COMPACT_ANGLE_LOG_ERR COMPACT_ANGLE_LOG_EX_ERR(LogMessage)
-#define COMPACT_ANGLE_LOG_FATAL COMPACT_ANGLE_LOG_EX_FATAL(LogMessage)
-
-#define ANGLE_LOG_IS_ON(severity) (::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_##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) \
- !(condition) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify() & (stream)
-
-// 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) COMPACT_ANGLE_LOG_##severity.stream()
-
-#define ANGLE_LOG(severity) ANGLE_LAZY_STREAM(ANGLE_LOG_STREAM(severity), ANGLE_LOG_IS_ON(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() ANGLE_LOG(INFO)
-#define WARN() ANGLE_LOG(WARN)
-#define ERR() ANGLE_LOG(ERR)
-#define FATAL() ANGLE_LOG(FATAL)
-
-// A macro to log a performance event around a scope.
-#if defined(ANGLE_TRACE_ENABLED)
-# if defined(_MSC_VER)
-# define EVENT(context, entryPoint, message, ...) \
- gl::ScopedPerfEventHelper scopedPerfEventHelper##__LINE__( \
- context, angle::EntryPoint::entryPoint); \
- do \
- { \
- if (gl::ShouldBeginScopedEvent(context)) \
- { \
- scopedPerfEventHelper##__LINE__.begin( \
- "%s(" message ")", GetEntryPointName(angle::EntryPoint::entryPoint), \
- __VA_ARGS__); \
- } \
- } while (0)
-# else
-# define EVENT(context, entryPoint, message, ...) \
- gl::ScopedPerfEventHelper scopedPerfEventHelper(context, \
- angle::EntryPoint::entryPoint); \
- do \
- { \
- if (gl::ShouldBeginScopedEvent(context)) \
- { \
- scopedPerfEventHelper.begin("%s(" message ")", \
- GetEntryPointName(angle::EntryPoint::entryPoint), \
- ##__VA_ARGS__); \
- } \
- } while (0)
-# endif // _MSC_VER
-#else
-# define EVENT(message, ...) (void(0))
-#endif
-
// The state tracked by ANGLE will be validated with the driver state before each call
#if defined(ANGLE_ENABLE_DEBUG_TRACE)
# define ANGLE_STATE_VALIDATION_ENABLED
@@ -315,72 +97,8 @@ std::ostream &FmtHex(std::ostream &os, T value)
# define ANGLE_CRASH() ((void)(*(volatile char *)0 = 0)), __assume(0)
#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 \
- true ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify() & (*::gl::priv::gSwallowStream)
-
-// A macro asserting a condition and outputting failures to the debug log
-#if defined(ANGLE_ENABLE_ASSERTS)
-# define ASSERT(expression) \
- (expression ? static_cast<void>(0) \
- : (FATAL() << "\t! Assert failed in " << __FUNCTION__ << " (" << __FILE__ \
- << ":" << __LINE__ << "): " << #expression))
-#else
-# define ASSERT(condition) ANGLE_EAT_STREAM_PARAMETERS << !(condition)
-#endif // defined(ANGLE_ENABLE_ASSERTS)
-
#define ANGLE_UNUSED_VARIABLE(variable) (static_cast<void>(variable))
-// A macro to indicate unimplemented functionality
-#ifndef NOASSERT_UNIMPLEMENTED
-# define NOASSERT_UNIMPLEMENTED 1
-#endif
-
-#if defined(ANGLE_TRACE_ENABLED) || defined(ANGLE_ENABLE_ASSERTS)
-# define UNIMPLEMENTED() \
- do \
- { \
- WARN() << "\t! Unimplemented: " << __FUNCTION__ << "(" << __FILE__ << ":" << __LINE__ \
- << ")"; \
- ASSERT(NOASSERT_UNIMPLEMENTED); \
- } while (0)
-
-// A macro for code which is not expected to be reached under valid assumptions
-# define UNREACHABLE() \
- do \
- { \
- FATAL() << "\t! Unreachable reached: " << __FUNCTION__ << "(" << __FILE__ << ":" \
- << __LINE__ << ")"; \
- } while (0)
-#else
-# define UNIMPLEMENTED() \
- do \
- { \
- ASSERT(NOASSERT_UNIMPLEMENTED); \
- } while (0)
-
-// A macro for code which is not expected to be reached under valid assumptions
-# define UNREACHABLE() \
- do \
- { \
- ASSERT(false); \
- } while (0)
-#endif // defined(ANGLE_TRACE_ENABLED) || defined(ANGLE_ENABLE_ASSERTS)
-
-#if defined(ANGLE_PLATFORM_WINDOWS)
-# define ANGLE_FUNCTION __FUNCTION__
-#else
-# define ANGLE_FUNCTION __func__
-#endif
-
// Defining ANGLE_ENABLE_STRUCT_PADDING_WARNINGS will enable warnings when members are added to
// structs to enforce packing. This is helpful for diagnosing unexpected struct sizes when making
// fast cache variables.
diff --git a/src/common/log_utils.h b/src/common/log_utils.h
new file mode 100644
index 0000000000..fc1aa2cccb
--- /dev/null
+++ b/src/common/log_utils.h
@@ -0,0 +1,315 @@
+//
+// 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;
+
+using LogSeverity = int;
+// Note: the log severities are used to index into the array of names,
+// see g_logSeverityNames.
+constexpr LogSeverity LOG_EVENT = 0;
+constexpr LogSeverity LOG_INFO = 1;
+constexpr LogSeverity LOG_WARN = 2;
+constexpr LogSeverity LOG_ERR = 3;
+constexpr LogSeverity LOG_FATAL = 4;
+constexpr LogSeverity LOG_NUM_SEVERITIES = 5;
+
+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
+{
+ public:
+ // Used for ANGLE_LOG(severity).
+ LogMessage(const char *file, const char *function, int line, LogSeverity severity);
+ ~LogMessage();
+ std::ostream &stream() { return mStream; }
+
+ LogSeverity getSeverity() const;
+ std::string getMessage() const;
+
+ private:
+ const char *mFile;
+ const char *mFunction;
+ const int mLine;
+ const LogSeverity mSeverity;
+
+ std::ostringstream mStream;
+};
+
+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
+{
+ public:
+ LogMessageVoidify() {}
+ // This has to be an operator with a precedence lower than << but higher than ?:
+ void operator&(std::ostream &) {}
+};
+
+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)
+{
+ stream << zeroX;
+
+ std::ios_base::fmtflags oldFlags = stream.flags();
+ std::streamsize oldWidth = stream.width();
+ typename S::char_type oldFill = stream.fill();
+
+ stream << std::hex << std::uppercase << std::setw(N) << std::setfill(zero) << value;
+
+ stream.flags(oldFlags);
+ stream.width(oldWidth);
+ stream.fill(oldFill);
+
+ return stream;
+}
+
+template <typename S, typename T, typename C>
+S &FmtHexAutoSized(S &stream, T value, const C *prefix, const C *zeroX, C zero)
+{
+ if (prefix)
+ {
+ stream << prefix;
+ }
+
+ constexpr int N = sizeof(T) * 2;
+ return priv::FmtHex<N>(stream, value, zeroX, zero);
+}
+
+template <typename T, typename C>
+class FmtHexHelper
+{
+ public:
+ FmtHexHelper(const C *prefix, T value) : mPrefix(prefix), mValue(value) {}
+ explicit FmtHexHelper(T value) : mPrefix(nullptr), mValue(value) {}
+
+ private:
+ const C *mPrefix;
+ T mValue;
+
+ friend std::ostream &operator<<(std::ostream &os, const FmtHexHelper &fmt)
+ {
+ return FmtHexAutoSized(os, fmt.mValue, fmt.mPrefix, "0x", '0');
+ }
+
+ friend std::wostream &operator<<(std::wostream &wos, const FmtHexHelper &fmt)
+ {
+ return FmtHexAutoSized(wos, fmt.mValue, fmt.mPrefix, L"0x", L'0');
+ }
+};
+
+} // namespace priv
+
+template <typename T, typename C = char>
+priv::FmtHexHelper<T, C> FmtHex(T value)
+{
+ return priv::FmtHexHelper<T, C>(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)
+{
+ return priv::FmtHexAutoSized(os, value, "", "0x", '0');
+}
+
+// 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, ...) \
+ ::gl::ClassName(__FILE__, __FUNCTION__, __LINE__, ::gl::LOG_EVENT, ##__VA_ARGS__)
+#define COMPACT_ANGLE_LOG_EX_INFO(ClassName, ...) \
+ ::gl::ClassName(__FILE__, __FUNCTION__, __LINE__, ::gl::LOG_INFO, ##__VA_ARGS__)
+#define COMPACT_ANGLE_LOG_EX_WARN(ClassName, ...) \
+ ::gl::ClassName(__FILE__, __FUNCTION__, __LINE__, ::gl::LOG_WARN, ##__VA_ARGS__)
+#define COMPACT_ANGLE_LOG_EX_ERR(ClassName, ...) \
+ ::gl::ClassName(__FILE__, __FUNCTION__, __LINE__, ::gl::LOG_ERR, ##__VA_ARGS__)
+#define COMPACT_ANGLE_LOG_EX_FATAL(ClassName, ...) \
+ ::gl::ClassName(__FILE__, __FUNCTION__, __LINE__, ::gl::LOG_FATAL, ##__VA_ARGS__)
+
+#define COMPACT_ANGLE_LOG_EVENT COMPACT_ANGLE_LOG_EX_EVENT(LogMessage)
+#define COMPACT_ANGLE_LOG_INFO COMPACT_ANGLE_LOG_EX_INFO(LogMessage)
+#define COMPACT_ANGLE_LOG_WARN COMPACT_ANGLE_LOG_EX_WARN(LogMessage)
+#define COMPACT_ANGLE_LOG_ERR COMPACT_ANGLE_LOG_EX_ERR(LogMessage)
+#define COMPACT_ANGLE_LOG_FATAL COMPACT_ANGLE_LOG_EX_FATAL(LogMessage)
+
+#define ANGLE_LOG_IS_ON(severity) (::gl::priv::ShouldCreatePlatformLogMessage(::gl::LOG_##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) \
+ !(condition) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify() & (stream)
+
+// 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) COMPACT_ANGLE_LOG_##severity.stream()
+
+#define ANGLE_LOG(severity) ANGLE_LAZY_STREAM(ANGLE_LOG_STREAM(severity), ANGLE_LOG_IS_ON(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() ANGLE_LOG(INFO)
+#define WARN() ANGLE_LOG(WARN)
+#define ERR() ANGLE_LOG(ERR)
+#define FATAL() ANGLE_LOG(FATAL)
+
+// A macro to log a performance event around a scope.
+#if defined(ANGLE_TRACE_ENABLED)
+# if defined(_MSC_VER)
+# define EVENT(context, entryPoint, message, ...) \
+ gl::ScopedPerfEventHelper scopedPerfEventHelper##__LINE__( \
+ context, angle::EntryPoint::entryPoint); \
+ do \
+ { \
+ if (gl::ShouldBeginScopedEvent(context)) \
+ { \
+ scopedPerfEventHelper##__LINE__.begin( \
+ "%s(" message ")", GetEntryPointName(angle::EntryPoint::entryPoint), \
+ __VA_ARGS__); \
+ } \
+ } while (0)
+# else
+# define EVENT(context, entryPoint, message, ...) \
+ gl::ScopedPerfEventHelper scopedPerfEventHelper(context, \
+ angle::EntryPoint::entryPoint); \
+ do \
+ { \
+ if (gl::ShouldBeginScopedEvent(context)) \
+ { \
+ scopedPerfEventHelper.begin("%s(" message ")", \
+ GetEntryPointName(angle::EntryPoint::entryPoint), \
+ ##__VA_ARGS__); \
+ } \
+ } while (0)
+# endif // _MSC_VER
+#else
+# define EVENT(message, ...) (void(0))
+#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 \
+ true ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify() & (*::gl::priv::gSwallowStream)
+
+// A macro asserting a condition and outputting failures to the debug log
+#if defined(ANGLE_ENABLE_ASSERTS)
+# define ASSERT(expression) \
+ (expression ? static_cast<void>(0) \
+ : (FATAL() << "\t! Assert failed in " << __FUNCTION__ << " (" << __FILE__ \
+ << ":" << __LINE__ << "): " << #expression))
+#else
+# define ASSERT(condition) ANGLE_EAT_STREAM_PARAMETERS << !(condition)
+#endif // defined(ANGLE_ENABLE_ASSERTS)
+
+// A macro to indicate unimplemented functionality
+#ifndef NOASSERT_UNIMPLEMENTED
+# define NOASSERT_UNIMPLEMENTED 1
+#endif
+
+#if defined(ANGLE_TRACE_ENABLED) || defined(ANGLE_ENABLE_ASSERTS)
+# define UNIMPLEMENTED() \
+ do \
+ { \
+ WARN() << "\t! Unimplemented: " << __FUNCTION__ << "(" << __FILE__ << ":" << __LINE__ \
+ << ")"; \
+ ASSERT(NOASSERT_UNIMPLEMENTED); \
+ } while (0)
+
+// A macro for code which is not expected to be reached under valid assumptions
+# define UNREACHABLE() \
+ do \
+ { \
+ FATAL() << "\t! Unreachable reached: " << __FUNCTION__ << "(" << __FILE__ << ":" \
+ << __LINE__ << ")"; \
+ } while (0)
+#else
+# define UNIMPLEMENTED() \
+ do \
+ { \
+ ASSERT(NOASSERT_UNIMPLEMENTED); \
+ } while (0)
+
+// A macro for code which is not expected to be reached under valid assumptions
+# define UNREACHABLE() \
+ do \
+ { \
+ ASSERT(false); \
+ } while (0)
+#endif // defined(ANGLE_TRACE_ENABLED) || defined(ANGLE_ENABLE_ASSERTS)
+
+#if defined(ANGLE_PLATFORM_WINDOWS)
+# define ANGLE_FUNCTION __FUNCTION__
+#else
+# define ANGLE_FUNCTION __func__
+#endif
+
+#endif // COMMON_LOG_UTILS_H_
diff --git a/src/libGLESv2.gni b/src/libGLESv2.gni
index 3f67ef3a27..d50911160e 100644
--- a/src/libGLESv2.gni
+++ b/src/libGLESv2.gni
@@ -53,6 +53,7 @@ libangle_common_headers = [
"src/common/entry_points_enum_autogen.h",
"src/common/event_tracer.h",
"src/common/hash_utils.h",
+ "src/common/log_utils.h",
"src/common/mathutil.h",
"src/common/matrix_utils.h",
"src/common/platform.h",