// // Copyright (c) 2002-2010 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. // // debug.cpp: Debugging utilities. #include "common/debug.h" #include <stdarg.h> #include <cstdio> #include <fstream> #include <iostream> #include <vector> #include "common/angleutils.h" #include "common/platform.h" #include "common/Optional.h" namespace gl { namespace { class FormattedString final : angle::NonCopyable { public: FormattedString(const char *format, va_list vararg) : mFormat(format) { va_copy(mVarArg, vararg); } const char *c_str() { return str().c_str(); } const std::string &str() { if (!mMessage.valid()) { mMessage = FormatString(mFormat, mVarArg); } return mMessage.value(); } size_t length() { c_str(); return mMessage.value().length(); } private: const char *mFormat; va_list mVarArg; Optional<std::string> mMessage; }; enum DebugTraceOutputType { DebugTraceOutputTypeNone, DebugTraceOutputTypeSetMarker, DebugTraceOutputTypeBeginEvent }; DebugAnnotator *g_debugAnnotator = nullptr; void output(bool traceInDebugOnly, MessageType messageType, DebugTraceOutputType outputType, const char *format, va_list vararg) { if (DebugAnnotationsActive()) { static std::vector<char> buffer(512); size_t len = FormatStringIntoVector(format, vararg, buffer); std::wstring formattedWideMessage(buffer.begin(), buffer.begin() + len); ASSERT(g_debugAnnotator != nullptr); switch (outputType) { case DebugTraceOutputTypeNone: break; case DebugTraceOutputTypeBeginEvent: g_debugAnnotator->beginEvent(formattedWideMessage.c_str()); break; case DebugTraceOutputTypeSetMarker: g_debugAnnotator->setMarker(formattedWideMessage.c_str()); break; } } FormattedString formattedMessage(format, vararg); if (messageType == MESSAGE_ERR) { std::cerr << formattedMessage.c_str(); #if !defined(NDEBUG) && defined(_MSC_VER) OutputDebugStringA(formattedMessage.c_str()); #endif // !defined(NDEBUG) && defined(_MSC_VER) } #if defined(ANGLE_ENABLE_DEBUG_TRACE) #if defined(NDEBUG) if (traceInDebugOnly) { return; } #endif // NDEBUG static std::ofstream file(TRACE_OUTPUT_FILE, std::ofstream::app); if (file) { file.write(formattedMessage.c_str(), formattedMessage.length()); file.flush(); } #if defined(ANGLE_ENABLE_DEBUG_TRACE_TO_DEBUGGER) OutputDebugStringA(formattedMessage.c_str()); #endif // ANGLE_ENABLE_DEBUG_TRACE_TO_DEBUGGER #endif // ANGLE_ENABLE_DEBUG_TRACE } } // namespace bool DebugAnnotationsActive() { #if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS) return g_debugAnnotator != nullptr && g_debugAnnotator->getStatus(); #else return false; #endif } void InitializeDebugAnnotations(DebugAnnotator *debugAnnotator) { UninitializeDebugAnnotations(); g_debugAnnotator = debugAnnotator; } void UninitializeDebugAnnotations() { // Pointer is not managed. g_debugAnnotator = nullptr; } void trace(bool traceInDebugOnly, MessageType messageType, const char *format, ...) { va_list vararg; va_start(vararg, format); output(traceInDebugOnly, messageType, DebugTraceOutputTypeSetMarker, format, vararg); va_end(vararg); } ScopedPerfEventHelper::ScopedPerfEventHelper(const char* format, ...) { #if !defined(ANGLE_ENABLE_DEBUG_TRACE) if (!DebugAnnotationsActive()) { return; } #endif // !ANGLE_ENABLE_DEBUG_TRACE va_list vararg; va_start(vararg, format); output(true, MESSAGE_EVENT, DebugTraceOutputTypeBeginEvent, format, vararg); va_end(vararg); } ScopedPerfEventHelper::~ScopedPerfEventHelper() { if (DebugAnnotationsActive()) { g_debugAnnotator->endEvent(); } } }