#ifndef COMMON_DEBUG_H_
#define COMMON_DEBUG_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"
#if !defined(TRACE_OUTPUT_FILE)
# define TRACE_OUTPUT_FILE "angle_debug.txt"
#endif
namespace gl
{
class Context;
class ScopedPerfEventHelper : angle::NonCopyable
{
public:
ScopedPerfEventHelper(Context *context, angle::EntryPoint entryPoint);
~ScopedPerfEventHelper();
ANGLE_FORMAT_PRINTF(2, 3)
void begin(const char *format, ...);
private:
gl::Context *mContext;
const angle::EntryPoint mEntryPoint;
const char *mFunctionName;
bool mCalledBeginEvent;
};
using LogSeverity = int;
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);
class LogMessage : angle::NonCopyable
{
public:
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;
};
class DebugAnnotator : angle::NonCopyable
{
public:
DebugAnnotator() {}
virtual ~DebugAnnotator() {}
virtual void beginEvent(gl::Context *context,
angle::EntryPoint entryPoint,
const char *eventName,
const char *eventMessage) = 0;
virtual void endEvent(gl::Context *context,
const char *eventName,
angle::EntryPoint entryPoint) = 0;
virtual void setMarker(const char *markerName) = 0;
virtual bool getStatus() = 0;
virtual void logMessage(const LogMessage &msg) const = 0;
};
bool ShouldBeginScopedEvent();
void InitializeDebugAnnotations(DebugAnnotator *debugAnnotator);
void UninitializeDebugAnnotations();
bool DebugAnnotationsActive();
bool DebugAnnotationsInitialized();
void InitializeDebugMutexIfNeeded();
std::mutex &GetDebugMutex();
namespace priv
{
class LogMessageVoidify
{
public:
LogMessageVoidify() {}
void operator&(std::ostream &) {}
};
extern std::ostream *gSwallowStream;
bool ShouldCreatePlatformLogMessage(LogSeverity severity);
template <int N, typename T>
std::ostream &FmtHex(std::ostream &os, T value)
{
os << "0x";
std::ios_base::fmtflags oldFlags = os.flags();
std::streamsize oldWidth = os.width();
std::ostream::char_type oldFill = os.fill();
os << std::hex << std::uppercase << std::setw(N) << std::setfill('0') << value;
os.flags(oldFlags);
os.width(oldWidth);
os.fill(oldFill);
return os;
}
template <typename T>
std::ostream &FmtHexAutoSized(std::ostream &os, T value)
{
constexpr int N = sizeof(T) * 2;
return priv::FmtHex<N>(os, value);
}
template <typename T>
class FmtHexHelper
{
public:
FmtHexHelper(const char *prefix, T value) : mPrefix(prefix), mValue(value) {}
explicit FmtHexHelper(T value) : mPrefix(nullptr), mValue(value) {}
private:
const char *mPrefix;
T mValue;
friend std::ostream &operator<<(std::ostream &os, const FmtHexHelper &fmt)
{
if (fmt.mPrefix)
{
os << fmt.mPrefix;
}
return FmtHexAutoSized(os, fmt.mValue);
}
};
}
template <typename T>
priv::FmtHexHelper<T> FmtHex(T value)
{
return priv::FmtHexHelper<T>(value);
}
#if defined(ANGLE_PLATFORM_WINDOWS)
priv::FmtHexHelper<HRESULT> FmtHR(HRESULT value);
priv::FmtHexHelper<DWORD> FmtErr(DWORD value);
#endif
template <typename T>
std::ostream &FmtHex(std::ostream &os, T value)
{
return priv::FmtHexAutoSized(os, value);
}
#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))
#define ANGLE_LAZY_STREAM(stream, condition) \
!(condition) ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify() & (stream)
#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))
}
#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)
#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()) \
{ \
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()) \
{ \
scopedPerfEventHelper.begin("%s(" message ")", \
GetEntryPointName(angle::EntryPoint::entryPoint), \
##__VA_ARGS__); \
} \
} while (0)
# endif
#else
# define EVENT(message, ...) (void(0))
#endif
#if defined(ANGLE_ENABLE_DEBUG_TRACE)
# define ANGLE_STATE_VALIDATION_ENABLED
#endif
#if defined(__GNUC__)
# define ANGLE_CRASH() __builtin_trap()
#else
# define ANGLE_CRASH() ((void)(*(volatile char *)0 = 0)), __assume(0)
#endif
#if !defined(NDEBUG)
# define ANGLE_ASSERT_IMPL(expression) assert(expression)
#else
# define ANGLE_ASSERT_IMPL(expression) ANGLE_CRASH()
#endif
#define ANGLE_EAT_STREAM_PARAMETERS \
true ? static_cast<void>(0) : ::gl::priv::LogMessageVoidify() & (*::gl::priv::gSwallowStream)
#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
#define UNREACHABLE_IS_NORETURN 0
#define ANGLE_UNUSED_VARIABLE(variable) (static_cast<void>(variable))
#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)
# define UNREACHABLE() \
do \
{ \
FATAL() << "\t! Unreachable reached: " << __FUNCTION__ << "(" << __FILE__ << ":" \
<< __LINE__ << ")"; \
} while (0)
#else
# define UNIMPLEMENTED() \
do \
{ \
ASSERT(NOASSERT_UNIMPLEMENTED); \
} while (0)
# define UNREACHABLE() \
do \
{ \
ASSERT(false); \
} while (0)
#endif
#if defined(ANGLE_PLATFORM_WINDOWS)
# define ANGLE_FUNCTION __FUNCTION__
#else
# define ANGLE_FUNCTION __func__
#endif
#if defined(__clang__)
# define ANGLE_ENABLE_STRUCT_PADDING_WARNINGS \
_Pragma("clang diagnostic push") _Pragma("clang diagnostic error \"-Wpadded\"")
# define ANGLE_DISABLE_STRUCT_PADDING_WARNINGS _Pragma("clang diagnostic pop")
#elif defined(__GNUC__)
# define ANGLE_ENABLE_STRUCT_PADDING_WARNINGS \
_Pragma("GCC diagnostic push") _Pragma("GCC diagnostic error \"-Wpadded\"")
# define ANGLE_DISABLE_STRUCT_PADDING_WARNINGS _Pragma("GCC diagnostic pop")
#elif defined(_MSC_VER)
# define ANGLE_ENABLE_STRUCT_PADDING_WARNINGS \
__pragma(warning(push)) __pragma(warning(error : 4820))
# define ANGLE_DISABLE_STRUCT_PADDING_WARNINGS __pragma(warning(pop))
#else
# define ANGLE_ENABLE_STRUCT_PADDING_WARNINGS
# define ANGLE_DISABLE_STRUCT_PADDING_WARNINGS
#endif
#if defined(__clang__)
# define ANGLE_DISABLE_SUGGEST_OVERRIDE_WARNINGS \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wsuggest-destructor-override\"") \
_Pragma("clang diagnostic ignored \"-Wsuggest-override\"")
# define ANGLE_REENABLE_SUGGEST_OVERRIDE_WARNINGS _Pragma("clang diagnostic pop")
#else
# define ANGLE_DISABLE_SUGGEST_OVERRIDE_WARNINGS
# define ANGLE_REENABLE_SUGGEST_OVERRIDE_WARNINGS
#endif
#if defined(__clang__)
# define ANGLE_DISABLE_EXTRA_SEMI_WARNING \
_Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wextra-semi\"")
# define ANGLE_REENABLE_EXTRA_SEMI_WARNING _Pragma("clang diagnostic pop")
#else
# define ANGLE_DISABLE_EXTRA_SEMI_WARNING
# define ANGLE_REENABLE_EXTRA_SEMI_WARNING
#endif
#if defined(__clang__)
# define ANGLE_DISABLE_EXTRA_SEMI_STMT_WARNING \
_Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wextra-semi-stmt\"")
# define ANGLE_REENABLE_EXTRA_SEMI_STMT_WARNING _Pragma("clang diagnostic pop")
#else
# define ANGLE_DISABLE_EXTRA_SEMI_STMT_WARNING
# define ANGLE_REENABLE_EXTRA_SEMI_STMT_WARNING
#endif
#if defined(__clang__)
# define ANGLE_DISABLE_SHADOWING_WARNING \
_Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wshadow-field\"")
# define ANGLE_REENABLE_SHADOWING_WARNING _Pragma("clang diagnostic pop")
#else
# define ANGLE_DISABLE_SHADOWING_WARNING
# define ANGLE_REENABLE_SHADOWING_WARNING
#endif
#if defined(__clang__)
# define ANGLE_DISABLE_DESTRUCTOR_OVERRIDE_WARNING \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Winconsistent-missing-destructor-override\"")
# define ANGLE_REENABLE_DESTRUCTOR_OVERRIDE_WARNING _Pragma("clang diagnostic pop")
#else
# define ANGLE_DISABLE_DESTRUCTOR_OVERRIDE_WARNING
# define ANGLE_REENABLE_DESTRUCTOR_OVERRIDE_WARNING
#endif
#if defined(__clang__)
# define ANGLE_DISABLE_WEAK_TEMPLATE_VTABLES_WARNING \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wweak-template-vtables\"")
# define ANGLE_REENABLE_WEAK_TEMPLATE_VTABLES_WARNING _Pragma("clang diagnostic pop")
#else
# define ANGLE_DISABLE_WEAK_TEMPLATE_VTABLES_WARNING
# define ANGLE_REENABLE_WEAK_TEMPLATE_VTABLES_WARNING
#endif
#if defined(__clang__)
# define ANGLE_DISABLE_UNUSED_FUNCTION_WARNING \
_Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wunused-function\"")
# define ANGLE_REENABLE_UNUSED_FUNCTION_WARNING _Pragma("clang diagnostic pop")
#else
# define ANGLE_DISABLE_UNUSED_FUNCTION_WARNING
# define ANGLE_REENABLE_UNUSED_FUNCTION_WARNING
#endif
#endif