blob: 5f55ff1e394ef1b265155486287c8f3a736dc160 [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 Kinross570e83c2014-10-20 14:13:58 -070020#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
Austin Kinross922a9fb2014-10-21 14:26:33 -070021// Wraps the D3D9/D3D11 debug annotation functions.
22class DebugAnnotationWrapper
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000023{
Austin Kinross922a9fb2014-10-21 14:26:33 -070024 public:
25 DebugAnnotationWrapper() { };
26 virtual ~DebugAnnotationWrapper() { };
27 virtual void beginEvent(const std::wstring &eventName) = 0;
28 virtual void endEvent() = 0;
29 virtual void setMarker(const std::wstring &markerName) = 0;
30 virtual bool getStatus() = 0;
31};
32
33#if defined(ANGLE_ENABLE_D3D9)
34class D3D9DebugAnnotationWrapper : public DebugAnnotationWrapper
35{
36 public:
37 void beginEvent(const std::wstring &eventName)
38 {
39 D3DPERF_BeginEvent(0, eventName.c_str());
40 }
41
42 void endEvent()
43 {
44 D3DPERF_EndEvent();
45 }
46
47 void setMarker(const std::wstring &markerName)
48 {
49 D3DPERF_SetMarker(0, markerName.c_str());
50 }
51
52 bool getStatus()
53 {
54 return !!D3DPERF_GetStatus();
55 }
56};
57#endif // ANGLE_ENABLE_D3D9
58
59#if defined(ANGLE_ENABLE_D3D11)
60class D3D11DebugAnnotationWrapper : public DebugAnnotationWrapper
61{
62 public:
63
64 D3D11DebugAnnotationWrapper()
65 : mInitialized(false),
66 mD3d11Module(NULL),
67 mUserDefinedAnnotation(NULL)
68 {
69 // D3D11 devices can't be created during DllMain.
70 // We defer device creation until the object is actually used.
71 }
72
73 ~D3D11DebugAnnotationWrapper()
74 {
75 if (mInitialized)
76 {
77 SafeRelease(mUserDefinedAnnotation);
78 FreeLibrary(mD3d11Module);
79 }
80 }
81
82 virtual void beginEvent(const std::wstring &eventName)
83 {
84 initializeDevice();
85
86 mUserDefinedAnnotation->BeginEvent(eventName.c_str());
87 }
88
89 virtual void endEvent()
90 {
91 initializeDevice();
92
93 mUserDefinedAnnotation->EndEvent();
94 }
95
96 virtual void setMarker(const std::wstring &markerName)
97 {
98 initializeDevice();
99
100 mUserDefinedAnnotation->SetMarker(markerName.c_str());
101 }
102
103 virtual bool getStatus()
104 {
105 // ID3DUserDefinedAnnotation::GetStatus doesn't work with the Graphics Diagnostics tools in Visual Studio 2013.
106
107#if defined(_DEBUG) && defined(ANGLE_ENABLE_WINDOWS_STORE)
108 // In the Windows Store, we can use IDXGraphicsAnalysis. The call to GetDebugInterface1 only succeeds if the app is under capture.
109 // This should only be called in DEBUG mode.
110 // If an app links against DXGIGetDebugInterface1 in release mode then it will fail Windows Store ingestion checks.
111 IDXGraphicsAnalysis* graphicsAnalysis;
112 DXGIGetDebugInterface1(0, IID_PPV_ARGS(&graphicsAnalysis));
113 bool underCapture = (graphicsAnalysis != NULL);
114 SafeRelease(graphicsAnalysis);
115 return underCapture;
Geoff Langfeee44b2014-03-05 11:34:31 -0500116#endif
117
Austin Kinross922a9fb2014-10-21 14:26:33 -0700118 // Otherwise, we have to return true here.
119 return true;
120 }
121
122 protected:
123
124 void initializeDevice()
125 {
126 if (!mInitialized)
127 {
128#if !defined(ANGLE_ENABLE_WINDOWS_STORE)
129 mD3d11Module = LoadLibrary(TEXT("d3d11.dll"));
130 ASSERT(mD3d11Module);
131
132 PFN_D3D11_CREATE_DEVICE D3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(mD3d11Module, "D3D11CreateDevice");
133 ASSERT(D3D11CreateDevice != NULL);
134#endif // !ANGLE_ENABLE_WINDOWS_STORE
135
136 ID3D11Device* device = NULL;
137 ID3D11DeviceContext* context = NULL;
138
139 HRESULT hr = E_FAIL;
140
141 // Create a D3D_DRIVER_TYPE_NULL device, which is much cheaper than other types of device.
142 hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_NULL, NULL, 0, NULL, 0, D3D11_SDK_VERSION, &device, NULL, &context);
143 ASSERT(SUCCEEDED(hr));
144
145 hr = context->QueryInterface(__uuidof(mUserDefinedAnnotation), reinterpret_cast<void**>(&mUserDefinedAnnotation));
146 ASSERT(SUCCEEDED(hr) && mUserDefinedAnnotation != NULL);
147
148 SafeRelease(device);
149 SafeRelease(context);
150
151 mInitialized = true;
152 }
153 }
154
155 bool mInitialized;
156 HMODULE mD3d11Module;
157 ID3DUserDefinedAnnotation* mUserDefinedAnnotation;
158};
159#endif // ANGLE_ENABLE_D3D11
160
161static DebugAnnotationWrapper* g_DebugAnnotationWrapper = NULL;
162
163void InitializeDebugAnnotations()
164{
165#if defined(ANGLE_ENABLE_D3D9)
166 g_DebugAnnotationWrapper = new D3D9DebugAnnotationWrapper();
167#elif defined(ANGLE_ENABLE_D3D11)
168 // If the project uses D3D9 then we can use the D3D9 debug annotations, even with the D3D11 renderer.
169 // However, if D3D9 is unavailable (e.g. in Windows Store), then we use D3D11 debug annotations.
170 // The D3D11 debug annotations are methods on ID3DUserDefinedAnnotation, which is implemented by the DeviceContext.
171 // This doesn't have to be the same DeviceContext that the renderer uses, though.
172 g_DebugAnnotationWrapper = new D3D11DebugAnnotationWrapper();
173#endif
174}
175
176void UninitializeDebugAnnotations()
177{
178 if (g_DebugAnnotationWrapper != NULL)
179 {
180 SafeDelete(g_DebugAnnotationWrapper);
181 }
182}
183
184#endif // ANGLE_ENABLE_DEBUG_ANNOTATIONS
185
186enum DebugTraceOutputType
187{
188 DebugTraceOutputTypeNone,
189 DebugTraceOutputTypeSetMarker,
190 DebugTraceOutputTypeBeginEvent
191};
192
193static void output(bool traceInDebugOnly, DebugTraceOutputType outputType, const char *format, va_list vararg)
194{
Austin Kinross570e83c2014-10-20 14:13:58 -0700195#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
Austin Kinross922a9fb2014-10-21 14:26:33 -0700196 static std::vector<char> buffer(512);
197
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000198 if (perfActive())
199 {
Austin Kinross922a9fb2014-10-21 14:26:33 -0700200 size_t len = FormatStringIntoVector(format, vararg, buffer);
201 std::wstring formattedWideMessage(buffer.begin(), buffer.begin() + len);
202
203 switch (outputType)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000204 {
Austin Kinross922a9fb2014-10-21 14:26:33 -0700205 case DebugTraceOutputTypeNone:
206 break;
207 case DebugTraceOutputTypeBeginEvent:
208 g_DebugAnnotationWrapper->beginEvent(formattedWideMessage);
209 break;
210 case DebugTraceOutputTypeSetMarker:
211 g_DebugAnnotationWrapper->setMarker(formattedWideMessage);
212 break;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000213 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000214 }
Austin Kinross570e83c2014-10-20 14:13:58 -0700215#endif // ANGLE_ENABLE_DEBUG_ANNOTATIONS
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000216
Austin Kinrossf0360c62014-10-20 14:26:13 -0700217#if defined(ANGLE_ENABLE_DEBUG_TRACE)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000218#if defined(NDEBUG)
Austin Kinrossfe14d452014-10-20 14:36:18 -0700219 if (traceInDebugOnly)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000220 {
221 return;
222 }
Geoff Langf5713122013-10-07 17:06:30 -0400223#endif // NDEBUG
Austin Kinross922a9fb2014-10-21 14:26:33 -0700224 std::string formattedMessage = FormatString(format, vararg);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000225
Geoff Langfeee44b2014-03-05 11:34:31 -0500226 static std::ofstream file(TRACE_OUTPUT_FILE, std::ofstream::app);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000227 if (file)
228 {
Geoff Langda5777c2014-07-11 09:52:58 -0400229 file.write(formattedMessage.c_str(), formattedMessage.length());
Geoff Langfeee44b2014-03-05 11:34:31 -0500230 file.flush();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000231 }
Geoff Langfeee44b2014-03-05 11:34:31 -0500232
Austin Kinrossfe14d452014-10-20 14:36:18 -0700233#if defined(ANGLE_ENABLE_DEBUG_TRACE_TO_DEBUGGER)
234 OutputDebugStringA(formattedMessage.c_str());
235#endif // ANGLE_ENABLE_DEBUG_TRACE_TO_DEBUGGER
236
Austin Kinrossf0360c62014-10-20 14:26:13 -0700237#endif // ANGLE_ENABLE_DEBUG_TRACE
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000238}
239
Austin Kinrossfe14d452014-10-20 14:36:18 -0700240void trace(bool traceInDebugOnly, const char *format, ...)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000241{
242 va_list vararg;
243 va_start(vararg, format);
Austin Kinross570e83c2014-10-20 14:13:58 -0700244#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
Austin Kinross922a9fb2014-10-21 14:26:33 -0700245 output(traceInDebugOnly, DebugTraceOutputTypeSetMarker, format, vararg);
Geoff Langf5713122013-10-07 17:06:30 -0400246#else
Austin Kinross922a9fb2014-10-21 14:26:33 -0700247 output(traceInDebugOnly, DebugTraceOutputTypeNone, format, vararg);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000248#endif
249 va_end(vararg);
250}
251
252bool perfActive()
253{
Austin Kinross570e83c2014-10-20 14:13:58 -0700254#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
Austin Kinross922a9fb2014-10-21 14:26:33 -0700255 static bool active = g_DebugAnnotationWrapper->getStatus();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000256 return active;
Geoff Langf5713122013-10-07 17:06:30 -0400257#else
258 return false;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000259#endif
260}
261
262ScopedPerfEventHelper::ScopedPerfEventHelper(const char* format, ...)
263{
Austin Kinrossf0360c62014-10-20 14:26:13 -0700264#if !defined(ANGLE_ENABLE_DEBUG_TRACE)
daniel@transgaming.com5dc3b8b2012-11-28 19:43:49 +0000265 if (!perfActive())
266 {
267 return;
268 }
Austin Kinrossf0360c62014-10-20 14:26:13 -0700269#endif // !ANGLE_ENABLE_DEBUG_TRACE
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000270 va_list vararg;
271 va_start(vararg, format);
Austin Kinross570e83c2014-10-20 14:13:58 -0700272#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
Austin Kinross922a9fb2014-10-21 14:26:33 -0700273 output(true, DebugTraceOutputTypeBeginEvent, format, vararg);
Jamie Madillb60fe312014-09-26 14:56:41 -0400274#else
Austin Kinross922a9fb2014-10-21 14:26:33 -0700275 output(true, DebugTraceOutputTypeNone, format, vararg);
Austin Kinross570e83c2014-10-20 14:13:58 -0700276#endif // ANGLE_ENABLE_DEBUG_ANNOTATIONS
Jamie Madillb60fe312014-09-26 14:56:41 -0400277 va_end(vararg);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000278}
279
280ScopedPerfEventHelper::~ScopedPerfEventHelper()
281{
Austin Kinross570e83c2014-10-20 14:13:58 -0700282#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000283 if (perfActive())
284 {
Austin Kinross922a9fb2014-10-21 14:26:33 -0700285 g_DebugAnnotationWrapper->endEvent();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000286 }
287#endif
288}
289}