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.cpp: Debugging utilities.
8
9#include "common/debug.h"
10
11#include <stdarg.h>
12
13#include <array>
14#include <cstdio>
15#include <fstream>
16#include <mutex>
17#include <ostream>
18#include <vector>
19
20#if defined(ANGLE_PLATFORM_ANDROID)
21# include <android/log.h>
22#endif
23
24#include "common/Optional.h"
25#include "common/angleutils.h"
26
27namespace gl
28{
29
30namespace
31{
32
33DebugAnnotator *g_debugAnnotator = nullptr;
34
35std::mutex *g_debugMutex = nullptr;
36
37constexpr std::array<const char *, LOG_NUM_SEVERITIES> g_logSeverityNames = {
38 {"EVENT", "WARN", "ERR", "FATAL"}};
39
40constexpr const char *LogSeverityName(int severity)
41{
42 return (severity >= 0 && severity < LOG_NUM_SEVERITIES) ? g_logSeverityNames[severity]
43 : "UNKNOWN";
44}
45
46bool ShouldCreateLogMessage(LogSeverity severity)
47{
48#if defined(ANGLE_TRACE_ENABLED)
49 return true;
50#elif defined(ANGLE_ENABLE_ASSERTS)
51 return severity != LOG_EVENT;
52#else
53 return false;
54#endif
55}
56
57} // namespace
58
59namespace priv
60{
61
62bool ShouldCreatePlatformLogMessage(LogSeverity severity)
63{
64#if defined(ANGLE_TRACE_ENABLED)
65 return true;
66#else
67 return severity != LOG_EVENT;
68#endif
69}
70
71// This is never instantiated, it's just used for EAT_STREAM_PARAMETERS to an object of the correct
72// type on the LHS of the unused part of the ternary operator.
73std::ostream *gSwallowStream;
74} // namespace priv
75
76bool DebugAnnotationsActive()
77{
78#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
79 return g_debugAnnotator != nullptr && g_debugAnnotator->getStatus();
80#else
81 return false;
82#endif
83}
84
85bool DebugAnnotationsInitialized()
86{
87 return g_debugAnnotator != nullptr;
88}
89
90void InitializeDebugAnnotations(DebugAnnotator *debugAnnotator)
91{
92 UninitializeDebugAnnotations();
93 g_debugAnnotator = debugAnnotator;
94}
95
96void UninitializeDebugAnnotations()
97{
98 // Pointer is not managed.
99 g_debugAnnotator = nullptr;
100}
101
102void InitializeDebugMutexIfNeeded()
103{
104 if (g_debugMutex == nullptr)
105 {
106 g_debugMutex = new std::mutex();
107 }
108}
109
110ScopedPerfEventHelper::ScopedPerfEventHelper(const char *format, ...) : mFunctionName(nullptr)
111{
112 bool dbgTrace = DebugAnnotationsActive();
113#if !defined(ANGLE_ENABLE_DEBUG_TRACE)
114 if (!dbgTrace)
115 {
116 return;
117 }
118#endif // !ANGLE_ENABLE_DEBUG_TRACE
119
120 va_list vararg;
121 va_start(vararg, format);
122 std::vector<char> buffer(512);
123 size_t len = FormatStringIntoVector(format, vararg, buffer);
124 ANGLE_LOG(EVENT) << std::string(&buffer[0], len);
125 // Pull function name from variable args
126 mFunctionName = va_arg(vararg, const char *);
127 va_end(vararg);
128 if (dbgTrace)
129 {
130 g_debugAnnotator->beginEvent(mFunctionName, buffer.data());
131 }
132}
133
134ScopedPerfEventHelper::~ScopedPerfEventHelper()
135{
136 if (DebugAnnotationsActive())
137 {
138 g_debugAnnotator->endEvent(mFunctionName);
139 }
140}
141
142LogMessage::LogMessage(const char *function, int line, LogSeverity severity)
143 : mFunction(function), mLine(line), mSeverity(severity)
144{
145 // EVENT() does not require additional function(line) info.
146 if (mSeverity != LOG_EVENT)
147 {
148 mStream << mFunction << "(" << mLine << "): ";
149 }
150}
151
152LogMessage::~LogMessage()
153{
154 std::unique_lock<std::mutex> lock;
155 if (g_debugMutex != nullptr)
156 {
157 lock = std::unique_lock<std::mutex>(*g_debugMutex);
158 }
159
160 if (DebugAnnotationsInitialized() && (mSeverity >= LOG_WARN))
161 {
162 g_debugAnnotator->logMessage(*this);
163 }
164 else
165 {
166 Trace(getSeverity(), getMessage().c_str());
167 }
168
169 if (mSeverity == LOG_FATAL)
170 {
171 ANGLE_CRASH();
172 }
173}
174
175void Trace(LogSeverity severity, const char *message)
176{
177 if (!ShouldCreateLogMessage(severity))
178 {
179 return;
180 }
181
182 std::string str(message);
183
184 if (DebugAnnotationsActive())
185 {
186
187 switch (severity)
188 {
189 case LOG_EVENT:
190 // Debugging logging done in ScopedPerfEventHelper
191 break;
192 default:
193 g_debugAnnotator->setMarker(message);
194 break;
195 }
196 }
197
198 if (severity == LOG_FATAL || severity == LOG_ERR || severity == LOG_WARN)
199 {
200#if defined(ANGLE_PLATFORM_ANDROID)
201 android_LogPriority android_priority = ANDROID_LOG_ERROR;
202 switch (severity)
203 {
204 case LOG_WARN:
205 android_priority = ANDROID_LOG_WARN;
206 break;
207 case LOG_ERR:
208 android_priority = ANDROID_LOG_ERROR;
209 break;
210 case LOG_FATAL:
211 android_priority = ANDROID_LOG_FATAL;
212 break;
213 default:
214 UNREACHABLE();
215 }
216 __android_log_print(android_priority, "ANGLE", "%s: %s\n", LogSeverityName(severity),
217 str.c_str());
218#else
219 // Note: we use fprintf because <iostream> includes static initializers.
220 fprintf((severity >= LOG_ERR) ? stderr : stdout, "%s: %s\n", LogSeverityName(severity),
221 str.c_str());
222#endif
223 }
224
225#if defined(ANGLE_PLATFORM_WINDOWS) && \
226 (defined(ANGLE_ENABLE_DEBUG_TRACE_TO_DEBUGGER) || !defined(NDEBUG))
227# if !defined(ANGLE_ENABLE_DEBUG_TRACE_TO_DEBUGGER)
228 if (severity >= LOG_ERR)
229# endif // !defined(ANGLE_ENABLE_DEBUG_TRACE_TO_DEBUGGER)
230 {
231 OutputDebugStringA(str.c_str());
232 }
233#endif
234
235#if defined(ANGLE_ENABLE_DEBUG_TRACE)
236# if defined(NDEBUG)
237 if (severity == LOG_EVENT || severity == LOG_WARN)
238 {
239 return;
240 }
241# endif // defined(NDEBUG)
242 static std::ofstream file(TRACE_OUTPUT_FILE, std::ofstream::app);
243 if (file)
244 {
245 file << LogSeverityName(severity) << ": " << str << std::endl;
246 file.flush();
247 }
248#endif // defined(ANGLE_ENABLE_DEBUG_TRACE)
249}
250
251LogSeverity LogMessage::getSeverity() const
252{
253 return mSeverity;
254}
255
256std::string LogMessage::getMessage() const
257{
258 return mStream.str();
259}
260
261#if defined(ANGLE_PLATFORM_WINDOWS)
262priv::FmtHexHelper<HRESULT> FmtHR(HRESULT value)
263{
264 return priv::FmtHexHelper<HRESULT>("HRESULT: ", value);
265}
266
267priv::FmtHexHelper<DWORD> FmtErr(DWORD value)
268{
269 return priv::FmtHexHelper<DWORD>("error: ", value);
270}
271#endif // defined(ANGLE_PLATFORM_WINDOWS)
272
273} // namespace gl
274