daniel@transgaming.com | 95a758f | 2012-07-12 15:17:06 +0000 | [diff] [blame] | 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" |
Geoff Lang | 44fa759 | 2014-05-30 11:50:07 -0400 | [diff] [blame] | 10 | #include "common/platform.h" |
Geoff Lang | da5777c | 2014-07-11 09:52:58 -0400 | [diff] [blame] | 11 | #include "common/angleutils.h" |
Geoff Lang | 44fa759 | 2014-05-30 11:50:07 -0400 | [diff] [blame] | 12 | |
Geoff Lang | 8321779 | 2014-01-16 09:52:38 -0500 | [diff] [blame] | 13 | #include <stdarg.h> |
Geoff Lang | feee44b | 2014-03-05 11:34:31 -0500 | [diff] [blame] | 14 | #include <vector> |
| 15 | #include <fstream> |
| 16 | #include <cstdio> |
Geoff Lang | 6850947 | 2013-10-07 17:06:30 -0400 | [diff] [blame] | 17 | |
daniel@transgaming.com | 95a758f | 2012-07-12 15:17:06 +0000 | [diff] [blame] | 18 | namespace gl |
| 19 | { |
Austin Kinross | 922a9fb | 2014-10-21 14:26:33 -0700 | [diff] [blame] | 20 | // Wraps the D3D9/D3D11 debug annotation functions. |
| 21 | class DebugAnnotationWrapper |
daniel@transgaming.com | 95a758f | 2012-07-12 15:17:06 +0000 | [diff] [blame] | 22 | { |
Austin Kinross | 922a9fb | 2014-10-21 14:26:33 -0700 | [diff] [blame] | 23 | public: |
| 24 | DebugAnnotationWrapper() { }; |
| 25 | virtual ~DebugAnnotationWrapper() { }; |
| 26 | virtual void beginEvent(const std::wstring &eventName) = 0; |
| 27 | virtual void endEvent() = 0; |
| 28 | virtual void setMarker(const std::wstring &markerName) = 0; |
| 29 | virtual bool getStatus() = 0; |
| 30 | }; |
| 31 | |
| 32 | #if defined(ANGLE_ENABLE_D3D9) |
| 33 | class D3D9DebugAnnotationWrapper : public DebugAnnotationWrapper |
| 34 | { |
| 35 | public: |
| 36 | void beginEvent(const std::wstring &eventName) |
| 37 | { |
| 38 | D3DPERF_BeginEvent(0, eventName.c_str()); |
| 39 | } |
| 40 | |
| 41 | void endEvent() |
| 42 | { |
| 43 | D3DPERF_EndEvent(); |
| 44 | } |
| 45 | |
| 46 | void setMarker(const std::wstring &markerName) |
| 47 | { |
| 48 | D3DPERF_SetMarker(0, markerName.c_str()); |
| 49 | } |
| 50 | |
| 51 | bool getStatus() |
| 52 | { |
| 53 | return !!D3DPERF_GetStatus(); |
| 54 | } |
| 55 | }; |
| 56 | #endif // ANGLE_ENABLE_D3D9 |
| 57 | |
| 58 | #if defined(ANGLE_ENABLE_D3D11) |
| 59 | class D3D11DebugAnnotationWrapper : public DebugAnnotationWrapper |
| 60 | { |
| 61 | public: |
| 62 | |
| 63 | D3D11DebugAnnotationWrapper() |
| 64 | : mInitialized(false), |
| 65 | mD3d11Module(NULL), |
| 66 | mUserDefinedAnnotation(NULL) |
| 67 | { |
| 68 | // D3D11 devices can't be created during DllMain. |
| 69 | // We defer device creation until the object is actually used. |
| 70 | } |
| 71 | |
| 72 | ~D3D11DebugAnnotationWrapper() |
| 73 | { |
| 74 | if (mInitialized) |
| 75 | { |
| 76 | SafeRelease(mUserDefinedAnnotation); |
| 77 | FreeLibrary(mD3d11Module); |
| 78 | } |
| 79 | } |
| 80 | |
| 81 | virtual void beginEvent(const std::wstring &eventName) |
| 82 | { |
| 83 | initializeDevice(); |
| 84 | |
| 85 | mUserDefinedAnnotation->BeginEvent(eventName.c_str()); |
| 86 | } |
| 87 | |
| 88 | virtual void endEvent() |
| 89 | { |
| 90 | initializeDevice(); |
| 91 | |
| 92 | mUserDefinedAnnotation->EndEvent(); |
| 93 | } |
| 94 | |
| 95 | virtual void setMarker(const std::wstring &markerName) |
| 96 | { |
| 97 | initializeDevice(); |
| 98 | |
| 99 | mUserDefinedAnnotation->SetMarker(markerName.c_str()); |
| 100 | } |
| 101 | |
| 102 | virtual bool getStatus() |
| 103 | { |
| 104 | // ID3DUserDefinedAnnotation::GetStatus doesn't work with the Graphics Diagnostics tools in Visual Studio 2013. |
| 105 | |
| 106 | #if defined(_DEBUG) && defined(ANGLE_ENABLE_WINDOWS_STORE) |
| 107 | // In the Windows Store, we can use IDXGraphicsAnalysis. The call to GetDebugInterface1 only succeeds if the app is under capture. |
| 108 | // This should only be called in DEBUG mode. |
| 109 | // If an app links against DXGIGetDebugInterface1 in release mode then it will fail Windows Store ingestion checks. |
| 110 | IDXGraphicsAnalysis* graphicsAnalysis; |
| 111 | DXGIGetDebugInterface1(0, IID_PPV_ARGS(&graphicsAnalysis)); |
| 112 | bool underCapture = (graphicsAnalysis != NULL); |
| 113 | SafeRelease(graphicsAnalysis); |
| 114 | return underCapture; |
Geoff Lang | feee44b | 2014-03-05 11:34:31 -0500 | [diff] [blame] | 115 | #endif |
| 116 | |
Austin Kinross | 922a9fb | 2014-10-21 14:26:33 -0700 | [diff] [blame] | 117 | // Otherwise, we have to return true here. |
| 118 | return true; |
| 119 | } |
| 120 | |
| 121 | protected: |
| 122 | |
| 123 | void initializeDevice() |
| 124 | { |
| 125 | if (!mInitialized) |
| 126 | { |
| 127 | #if !defined(ANGLE_ENABLE_WINDOWS_STORE) |
| 128 | mD3d11Module = LoadLibrary(TEXT("d3d11.dll")); |
| 129 | ASSERT(mD3d11Module); |
| 130 | |
| 131 | PFN_D3D11_CREATE_DEVICE D3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(mD3d11Module, "D3D11CreateDevice"); |
| 132 | ASSERT(D3D11CreateDevice != NULL); |
| 133 | #endif // !ANGLE_ENABLE_WINDOWS_STORE |
| 134 | |
| 135 | ID3D11Device* device = NULL; |
| 136 | ID3D11DeviceContext* context = NULL; |
| 137 | |
| 138 | HRESULT hr = E_FAIL; |
| 139 | |
| 140 | // Create a D3D_DRIVER_TYPE_NULL device, which is much cheaper than other types of device. |
| 141 | hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_NULL, NULL, 0, NULL, 0, D3D11_SDK_VERSION, &device, NULL, &context); |
| 142 | ASSERT(SUCCEEDED(hr)); |
| 143 | |
| 144 | hr = context->QueryInterface(__uuidof(mUserDefinedAnnotation), reinterpret_cast<void**>(&mUserDefinedAnnotation)); |
| 145 | ASSERT(SUCCEEDED(hr) && mUserDefinedAnnotation != NULL); |
| 146 | |
| 147 | SafeRelease(device); |
| 148 | SafeRelease(context); |
| 149 | |
| 150 | mInitialized = true; |
| 151 | } |
| 152 | } |
| 153 | |
| 154 | bool mInitialized; |
| 155 | HMODULE mD3d11Module; |
| 156 | ID3DUserDefinedAnnotation* mUserDefinedAnnotation; |
| 157 | }; |
| 158 | #endif // ANGLE_ENABLE_D3D11 |
| 159 | |
Geoff Lang | 8bc361e | 2014-11-20 16:23:31 -0500 | [diff] [blame^] | 160 | static DebugAnnotationWrapper *GetDebugAnnotationWrapper() |
Austin Kinross | 922a9fb | 2014-10-21 14:26:33 -0700 | [diff] [blame] | 161 | { |
Geoff Lang | 8bc361e | 2014-11-20 16:23:31 -0500 | [diff] [blame^] | 162 | #if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS) |
| 163 | # if defined(ANGLE_ENABLE_D3D9) |
| 164 | static D3D9DebugAnnotationWrapper wrapper; |
| 165 | # elif defined(ANGLE_ENABLE_D3D11) |
Austin Kinross | 922a9fb | 2014-10-21 14:26:33 -0700 | [diff] [blame] | 166 | // If the project uses D3D9 then we can use the D3D9 debug annotations, even with the D3D11 renderer. |
| 167 | // However, if D3D9 is unavailable (e.g. in Windows Store), then we use D3D11 debug annotations. |
| 168 | // The D3D11 debug annotations are methods on ID3DUserDefinedAnnotation, which is implemented by the DeviceContext. |
| 169 | // This doesn't have to be the same DeviceContext that the renderer uses, though. |
Geoff Lang | 8bc361e | 2014-11-20 16:23:31 -0500 | [diff] [blame^] | 170 | static D3D11DebugAnnotationWrapper wrapper; |
| 171 | # endif |
| 172 | return &wrapper; |
| 173 | #else |
| 174 | return nullptr; |
Austin Kinross | 922a9fb | 2014-10-21 14:26:33 -0700 | [diff] [blame] | 175 | #endif |
| 176 | } |
| 177 | |
Austin Kinross | 922a9fb | 2014-10-21 14:26:33 -0700 | [diff] [blame] | 178 | enum DebugTraceOutputType |
| 179 | { |
| 180 | DebugTraceOutputTypeNone, |
| 181 | DebugTraceOutputTypeSetMarker, |
| 182 | DebugTraceOutputTypeBeginEvent |
| 183 | }; |
| 184 | |
| 185 | static void output(bool traceInDebugOnly, DebugTraceOutputType outputType, const char *format, va_list vararg) |
| 186 | { |
daniel@transgaming.com | 95a758f | 2012-07-12 15:17:06 +0000 | [diff] [blame] | 187 | if (perfActive()) |
| 188 | { |
Geoff Lang | 8bc361e | 2014-11-20 16:23:31 -0500 | [diff] [blame^] | 189 | static std::vector<char> buffer(512); |
Austin Kinross | 922a9fb | 2014-10-21 14:26:33 -0700 | [diff] [blame] | 190 | size_t len = FormatStringIntoVector(format, vararg, buffer); |
| 191 | std::wstring formattedWideMessage(buffer.begin(), buffer.begin() + len); |
| 192 | |
Geoff Lang | 8bc361e | 2014-11-20 16:23:31 -0500 | [diff] [blame^] | 193 | DebugAnnotationWrapper *annotationWrapper = GetDebugAnnotationWrapper(); |
Austin Kinross | 922a9fb | 2014-10-21 14:26:33 -0700 | [diff] [blame] | 194 | switch (outputType) |
daniel@transgaming.com | 95a758f | 2012-07-12 15:17:06 +0000 | [diff] [blame] | 195 | { |
Geoff Lang | 8bc361e | 2014-11-20 16:23:31 -0500 | [diff] [blame^] | 196 | case DebugTraceOutputTypeNone: |
| 197 | break; |
| 198 | case DebugTraceOutputTypeBeginEvent: |
| 199 | annotationWrapper->beginEvent(formattedWideMessage); |
| 200 | break; |
| 201 | case DebugTraceOutputTypeSetMarker: |
| 202 | annotationWrapper->setMarker(formattedWideMessage); |
| 203 | break; |
daniel@transgaming.com | 95a758f | 2012-07-12 15:17:06 +0000 | [diff] [blame] | 204 | } |
daniel@transgaming.com | 95a758f | 2012-07-12 15:17:06 +0000 | [diff] [blame] | 205 | } |
daniel@transgaming.com | 95a758f | 2012-07-12 15:17:06 +0000 | [diff] [blame] | 206 | |
Austin Kinross | f0360c6 | 2014-10-20 14:26:13 -0700 | [diff] [blame] | 207 | #if defined(ANGLE_ENABLE_DEBUG_TRACE) |
daniel@transgaming.com | 95a758f | 2012-07-12 15:17:06 +0000 | [diff] [blame] | 208 | #if defined(NDEBUG) |
Austin Kinross | fe14d45 | 2014-10-20 14:36:18 -0700 | [diff] [blame] | 209 | if (traceInDebugOnly) |
daniel@transgaming.com | 95a758f | 2012-07-12 15:17:06 +0000 | [diff] [blame] | 210 | { |
| 211 | return; |
| 212 | } |
Geoff Lang | f571312 | 2013-10-07 17:06:30 -0400 | [diff] [blame] | 213 | #endif // NDEBUG |
Austin Kinross | 922a9fb | 2014-10-21 14:26:33 -0700 | [diff] [blame] | 214 | std::string formattedMessage = FormatString(format, vararg); |
daniel@transgaming.com | 95a758f | 2012-07-12 15:17:06 +0000 | [diff] [blame] | 215 | |
Geoff Lang | feee44b | 2014-03-05 11:34:31 -0500 | [diff] [blame] | 216 | static std::ofstream file(TRACE_OUTPUT_FILE, std::ofstream::app); |
daniel@transgaming.com | 95a758f | 2012-07-12 15:17:06 +0000 | [diff] [blame] | 217 | if (file) |
| 218 | { |
Geoff Lang | da5777c | 2014-07-11 09:52:58 -0400 | [diff] [blame] | 219 | file.write(formattedMessage.c_str(), formattedMessage.length()); |
Geoff Lang | feee44b | 2014-03-05 11:34:31 -0500 | [diff] [blame] | 220 | file.flush(); |
daniel@transgaming.com | 95a758f | 2012-07-12 15:17:06 +0000 | [diff] [blame] | 221 | } |
Geoff Lang | feee44b | 2014-03-05 11:34:31 -0500 | [diff] [blame] | 222 | |
Austin Kinross | fe14d45 | 2014-10-20 14:36:18 -0700 | [diff] [blame] | 223 | #if defined(ANGLE_ENABLE_DEBUG_TRACE_TO_DEBUGGER) |
| 224 | OutputDebugStringA(formattedMessage.c_str()); |
| 225 | #endif // ANGLE_ENABLE_DEBUG_TRACE_TO_DEBUGGER |
| 226 | |
Austin Kinross | f0360c6 | 2014-10-20 14:26:13 -0700 | [diff] [blame] | 227 | #endif // ANGLE_ENABLE_DEBUG_TRACE |
daniel@transgaming.com | 95a758f | 2012-07-12 15:17:06 +0000 | [diff] [blame] | 228 | } |
| 229 | |
Austin Kinross | fe14d45 | 2014-10-20 14:36:18 -0700 | [diff] [blame] | 230 | void trace(bool traceInDebugOnly, const char *format, ...) |
daniel@transgaming.com | 95a758f | 2012-07-12 15:17:06 +0000 | [diff] [blame] | 231 | { |
| 232 | va_list vararg; |
| 233 | va_start(vararg, format); |
Austin Kinross | 570e83c | 2014-10-20 14:13:58 -0700 | [diff] [blame] | 234 | #if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS) |
Austin Kinross | 922a9fb | 2014-10-21 14:26:33 -0700 | [diff] [blame] | 235 | output(traceInDebugOnly, DebugTraceOutputTypeSetMarker, format, vararg); |
Geoff Lang | f571312 | 2013-10-07 17:06:30 -0400 | [diff] [blame] | 236 | #else |
Austin Kinross | 922a9fb | 2014-10-21 14:26:33 -0700 | [diff] [blame] | 237 | output(traceInDebugOnly, DebugTraceOutputTypeNone, format, vararg); |
daniel@transgaming.com | 95a758f | 2012-07-12 15:17:06 +0000 | [diff] [blame] | 238 | #endif |
| 239 | va_end(vararg); |
| 240 | } |
| 241 | |
| 242 | bool perfActive() |
| 243 | { |
Austin Kinross | 570e83c | 2014-10-20 14:13:58 -0700 | [diff] [blame] | 244 | #if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS) |
Geoff Lang | 8bc361e | 2014-11-20 16:23:31 -0500 | [diff] [blame^] | 245 | static bool active = GetDebugAnnotationWrapper()->getStatus(); |
daniel@transgaming.com | 95a758f | 2012-07-12 15:17:06 +0000 | [diff] [blame] | 246 | return active; |
Geoff Lang | f571312 | 2013-10-07 17:06:30 -0400 | [diff] [blame] | 247 | #else |
| 248 | return false; |
daniel@transgaming.com | 95a758f | 2012-07-12 15:17:06 +0000 | [diff] [blame] | 249 | #endif |
| 250 | } |
| 251 | |
| 252 | ScopedPerfEventHelper::ScopedPerfEventHelper(const char* format, ...) |
| 253 | { |
Austin Kinross | f0360c6 | 2014-10-20 14:26:13 -0700 | [diff] [blame] | 254 | #if !defined(ANGLE_ENABLE_DEBUG_TRACE) |
daniel@transgaming.com | 5dc3b8b | 2012-11-28 19:43:49 +0000 | [diff] [blame] | 255 | if (!perfActive()) |
| 256 | { |
| 257 | return; |
| 258 | } |
Austin Kinross | f0360c6 | 2014-10-20 14:26:13 -0700 | [diff] [blame] | 259 | #endif // !ANGLE_ENABLE_DEBUG_TRACE |
daniel@transgaming.com | 95a758f | 2012-07-12 15:17:06 +0000 | [diff] [blame] | 260 | va_list vararg; |
| 261 | va_start(vararg, format); |
Austin Kinross | 570e83c | 2014-10-20 14:13:58 -0700 | [diff] [blame] | 262 | #if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS) |
Austin Kinross | 922a9fb | 2014-10-21 14:26:33 -0700 | [diff] [blame] | 263 | output(true, DebugTraceOutputTypeBeginEvent, format, vararg); |
Jamie Madill | b60fe31 | 2014-09-26 14:56:41 -0400 | [diff] [blame] | 264 | #else |
Austin Kinross | 922a9fb | 2014-10-21 14:26:33 -0700 | [diff] [blame] | 265 | output(true, DebugTraceOutputTypeNone, format, vararg); |
Austin Kinross | 570e83c | 2014-10-20 14:13:58 -0700 | [diff] [blame] | 266 | #endif // ANGLE_ENABLE_DEBUG_ANNOTATIONS |
Jamie Madill | b60fe31 | 2014-09-26 14:56:41 -0400 | [diff] [blame] | 267 | va_end(vararg); |
daniel@transgaming.com | 95a758f | 2012-07-12 15:17:06 +0000 | [diff] [blame] | 268 | } |
| 269 | |
| 270 | ScopedPerfEventHelper::~ScopedPerfEventHelper() |
| 271 | { |
Austin Kinross | 570e83c | 2014-10-20 14:13:58 -0700 | [diff] [blame] | 272 | #if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS) |
daniel@transgaming.com | 95a758f | 2012-07-12 15:17:06 +0000 | [diff] [blame] | 273 | if (perfActive()) |
| 274 | { |
Geoff Lang | 8bc361e | 2014-11-20 16:23:31 -0500 | [diff] [blame^] | 275 | GetDebugAnnotationWrapper()->endEvent(); |
daniel@transgaming.com | 95a758f | 2012-07-12 15:17:06 +0000 | [diff] [blame] | 276 | } |
| 277 | #endif |
| 278 | } |
| 279 | } |