blob: ae38f0d22b6b86ce22577c86a0e5bdf597476557 [file] [log] [blame]
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001//
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 Lang44fa7592014-05-30 11:50:07 -040010#include "common/platform.h"
Geoff Langda5777c2014-07-11 09:52:58 -040011#include "common/angleutils.h"
Geoff Lang44fa7592014-05-30 11:50:07 -040012
Geoff Lang83217792014-01-16 09:52:38 -050013#include <stdarg.h>
Geoff Langfeee44b2014-03-05 11:34:31 -050014#include <vector>
15#include <fstream>
16#include <cstdio>
Geoff Lang68509472013-10-07 17:06:30 -040017
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000018namespace gl
19{
Austin Kinross922a9fb2014-10-21 14:26:33 -070020// Wraps the D3D9/D3D11 debug annotation functions.
21class DebugAnnotationWrapper
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000022{
Austin Kinross922a9fb2014-10-21 14:26:33 -070023 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)
33class 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)
59class 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 Langfeee44b2014-03-05 11:34:31 -0500115#endif
116
Austin Kinross922a9fb2014-10-21 14:26:33 -0700117 // 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 Lang8bc361e2014-11-20 16:23:31 -0500160static DebugAnnotationWrapper *GetDebugAnnotationWrapper()
Austin Kinross922a9fb2014-10-21 14:26:33 -0700161{
Geoff Lang8bc361e2014-11-20 16:23:31 -0500162#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
163# if defined(ANGLE_ENABLE_D3D9)
164 static D3D9DebugAnnotationWrapper wrapper;
165# elif defined(ANGLE_ENABLE_D3D11)
Austin Kinross922a9fb2014-10-21 14:26:33 -0700166 // 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 Lang8bc361e2014-11-20 16:23:31 -0500170 static D3D11DebugAnnotationWrapper wrapper;
171# endif
172 return &wrapper;
173#else
174 return nullptr;
Austin Kinross922a9fb2014-10-21 14:26:33 -0700175#endif
176}
177
Austin Kinross922a9fb2014-10-21 14:26:33 -0700178enum DebugTraceOutputType
179{
180 DebugTraceOutputTypeNone,
181 DebugTraceOutputTypeSetMarker,
182 DebugTraceOutputTypeBeginEvent
183};
184
Jamie Madill14aa40f2015-01-07 15:12:47 -0500185static void output(bool traceInDebugOnly, MessageType messageType, DebugTraceOutputType outputType,
186 const char *format, va_list vararg)
Austin Kinross922a9fb2014-10-21 14:26:33 -0700187{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000188 if (perfActive())
189 {
Geoff Lang8bc361e2014-11-20 16:23:31 -0500190 static std::vector<char> buffer(512);
Austin Kinross922a9fb2014-10-21 14:26:33 -0700191 size_t len = FormatStringIntoVector(format, vararg, buffer);
192 std::wstring formattedWideMessage(buffer.begin(), buffer.begin() + len);
193
Geoff Lang8bc361e2014-11-20 16:23:31 -0500194 DebugAnnotationWrapper *annotationWrapper = GetDebugAnnotationWrapper();
Austin Kinross922a9fb2014-10-21 14:26:33 -0700195 switch (outputType)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000196 {
Geoff Lang8bc361e2014-11-20 16:23:31 -0500197 case DebugTraceOutputTypeNone:
198 break;
199 case DebugTraceOutputTypeBeginEvent:
200 annotationWrapper->beginEvent(formattedWideMessage);
201 break;
202 case DebugTraceOutputTypeSetMarker:
203 annotationWrapper->setMarker(formattedWideMessage);
204 break;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000205 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000206 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000207
Jamie Madill14aa40f2015-01-07 15:12:47 -0500208 std::string formattedMessage;
209 UNUSED_TRACE_VARIABLE(formattedMessage);
210
211#if !defined(NDEBUG) && defined(_MSC_VER)
212 if (messageType == MESSAGE_ERR)
213 {
214 if (formattedMessage.empty())
215 {
216 formattedMessage = FormatString(format, vararg);
217 }
218 OutputDebugString(formattedMessage.c_str());
219 }
220#endif
221
Austin Kinrossf0360c62014-10-20 14:26:13 -0700222#if defined(ANGLE_ENABLE_DEBUG_TRACE)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000223#if defined(NDEBUG)
Austin Kinrossfe14d452014-10-20 14:36:18 -0700224 if (traceInDebugOnly)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000225 {
226 return;
227 }
Geoff Langf5713122013-10-07 17:06:30 -0400228#endif // NDEBUG
Jamie Madill14aa40f2015-01-07 15:12:47 -0500229 if (formattedMessage.empty())
230 {
231 formattedMessage = FormatString(format, vararg);
232 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000233
Geoff Langfeee44b2014-03-05 11:34:31 -0500234 static std::ofstream file(TRACE_OUTPUT_FILE, std::ofstream::app);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000235 if (file)
236 {
Geoff Langda5777c2014-07-11 09:52:58 -0400237 file.write(formattedMessage.c_str(), formattedMessage.length());
Geoff Langfeee44b2014-03-05 11:34:31 -0500238 file.flush();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000239 }
Geoff Langfeee44b2014-03-05 11:34:31 -0500240
Austin Kinrossfe14d452014-10-20 14:36:18 -0700241#if defined(ANGLE_ENABLE_DEBUG_TRACE_TO_DEBUGGER)
242 OutputDebugStringA(formattedMessage.c_str());
243#endif // ANGLE_ENABLE_DEBUG_TRACE_TO_DEBUGGER
244
Austin Kinrossf0360c62014-10-20 14:26:13 -0700245#endif // ANGLE_ENABLE_DEBUG_TRACE
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000246}
247
Jamie Madill14aa40f2015-01-07 15:12:47 -0500248void trace(bool traceInDebugOnly, MessageType messageType, const char *format, ...)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000249{
250 va_list vararg;
251 va_start(vararg, format);
Austin Kinross570e83c2014-10-20 14:13:58 -0700252#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
Jamie Madill14aa40f2015-01-07 15:12:47 -0500253 output(traceInDebugOnly, messageType, DebugTraceOutputTypeSetMarker, format, vararg);
Geoff Langf5713122013-10-07 17:06:30 -0400254#else
Jamie Madill14aa40f2015-01-07 15:12:47 -0500255 output(traceInDebugOnly, messageType, DebugTraceOutputTypeNone, format, vararg);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000256#endif
257 va_end(vararg);
258}
259
260bool perfActive()
261{
Austin Kinross570e83c2014-10-20 14:13:58 -0700262#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
Geoff Lang8bc361e2014-11-20 16:23:31 -0500263 static bool active = GetDebugAnnotationWrapper()->getStatus();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000264 return active;
Geoff Langf5713122013-10-07 17:06:30 -0400265#else
266 return false;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000267#endif
268}
269
270ScopedPerfEventHelper::ScopedPerfEventHelper(const char* format, ...)
271{
Austin Kinrossf0360c62014-10-20 14:26:13 -0700272#if !defined(ANGLE_ENABLE_DEBUG_TRACE)
daniel@transgaming.com5dc3b8b2012-11-28 19:43:49 +0000273 if (!perfActive())
274 {
275 return;
276 }
Austin Kinrossf0360c62014-10-20 14:26:13 -0700277#endif // !ANGLE_ENABLE_DEBUG_TRACE
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000278 va_list vararg;
279 va_start(vararg, format);
Austin Kinross570e83c2014-10-20 14:13:58 -0700280#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
Jamie Madill14aa40f2015-01-07 15:12:47 -0500281 output(true, MESSAGE_EVENT, DebugTraceOutputTypeBeginEvent, format, vararg);
Jamie Madillb60fe312014-09-26 14:56:41 -0400282#else
Jamie Madill14aa40f2015-01-07 15:12:47 -0500283 output(true, MESSAGE_EVENT, DebugTraceOutputTypeNone, format, vararg);
Austin Kinross570e83c2014-10-20 14:13:58 -0700284#endif // ANGLE_ENABLE_DEBUG_ANNOTATIONS
Jamie Madillb60fe312014-09-26 14:56:41 -0400285 va_end(vararg);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000286}
287
288ScopedPerfEventHelper::~ScopedPerfEventHelper()
289{
Austin Kinross570e83c2014-10-20 14:13:58 -0700290#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000291 if (perfActive())
292 {
Geoff Lang8bc361e2014-11-20 16:23:31 -0500293 GetDebugAnnotationWrapper()->endEvent();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000294 }
295#endif
296}
297}