blob: 49ed05df6a70fd0d7792fec9f03d81274df7a584 [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
185static void output(bool traceInDebugOnly, DebugTraceOutputType outputType, const char *format, va_list vararg)
186{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000187 if (perfActive())
188 {
Geoff Lang8bc361e2014-11-20 16:23:31 -0500189 static std::vector<char> buffer(512);
Austin Kinross922a9fb2014-10-21 14:26:33 -0700190 size_t len = FormatStringIntoVector(format, vararg, buffer);
191 std::wstring formattedWideMessage(buffer.begin(), buffer.begin() + len);
192
Geoff Lang8bc361e2014-11-20 16:23:31 -0500193 DebugAnnotationWrapper *annotationWrapper = GetDebugAnnotationWrapper();
Austin Kinross922a9fb2014-10-21 14:26:33 -0700194 switch (outputType)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000195 {
Geoff Lang8bc361e2014-11-20 16:23:31 -0500196 case DebugTraceOutputTypeNone:
197 break;
198 case DebugTraceOutputTypeBeginEvent:
199 annotationWrapper->beginEvent(formattedWideMessage);
200 break;
201 case DebugTraceOutputTypeSetMarker:
202 annotationWrapper->setMarker(formattedWideMessage);
203 break;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000204 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000205 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000206
Austin Kinrossf0360c62014-10-20 14:26:13 -0700207#if defined(ANGLE_ENABLE_DEBUG_TRACE)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000208#if defined(NDEBUG)
Austin Kinrossfe14d452014-10-20 14:36:18 -0700209 if (traceInDebugOnly)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000210 {
211 return;
212 }
Geoff Langf5713122013-10-07 17:06:30 -0400213#endif // NDEBUG
Austin Kinross922a9fb2014-10-21 14:26:33 -0700214 std::string formattedMessage = FormatString(format, vararg);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000215
Geoff Langfeee44b2014-03-05 11:34:31 -0500216 static std::ofstream file(TRACE_OUTPUT_FILE, std::ofstream::app);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000217 if (file)
218 {
Geoff Langda5777c2014-07-11 09:52:58 -0400219 file.write(formattedMessage.c_str(), formattedMessage.length());
Geoff Langfeee44b2014-03-05 11:34:31 -0500220 file.flush();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000221 }
Geoff Langfeee44b2014-03-05 11:34:31 -0500222
Austin Kinrossfe14d452014-10-20 14:36:18 -0700223#if defined(ANGLE_ENABLE_DEBUG_TRACE_TO_DEBUGGER)
224 OutputDebugStringA(formattedMessage.c_str());
225#endif // ANGLE_ENABLE_DEBUG_TRACE_TO_DEBUGGER
226
Austin Kinrossf0360c62014-10-20 14:26:13 -0700227#endif // ANGLE_ENABLE_DEBUG_TRACE
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000228}
229
Austin Kinrossfe14d452014-10-20 14:36:18 -0700230void trace(bool traceInDebugOnly, const char *format, ...)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000231{
232 va_list vararg;
233 va_start(vararg, format);
Austin Kinross570e83c2014-10-20 14:13:58 -0700234#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
Austin Kinross922a9fb2014-10-21 14:26:33 -0700235 output(traceInDebugOnly, DebugTraceOutputTypeSetMarker, format, vararg);
Geoff Langf5713122013-10-07 17:06:30 -0400236#else
Austin Kinross922a9fb2014-10-21 14:26:33 -0700237 output(traceInDebugOnly, DebugTraceOutputTypeNone, format, vararg);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000238#endif
239 va_end(vararg);
240}
241
242bool perfActive()
243{
Austin Kinross570e83c2014-10-20 14:13:58 -0700244#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
Geoff Lang8bc361e2014-11-20 16:23:31 -0500245 static bool active = GetDebugAnnotationWrapper()->getStatus();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000246 return active;
Geoff Langf5713122013-10-07 17:06:30 -0400247#else
248 return false;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000249#endif
250}
251
252ScopedPerfEventHelper::ScopedPerfEventHelper(const char* format, ...)
253{
Austin Kinrossf0360c62014-10-20 14:26:13 -0700254#if !defined(ANGLE_ENABLE_DEBUG_TRACE)
daniel@transgaming.com5dc3b8b2012-11-28 19:43:49 +0000255 if (!perfActive())
256 {
257 return;
258 }
Austin Kinrossf0360c62014-10-20 14:26:13 -0700259#endif // !ANGLE_ENABLE_DEBUG_TRACE
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000260 va_list vararg;
261 va_start(vararg, format);
Austin Kinross570e83c2014-10-20 14:13:58 -0700262#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
Austin Kinross922a9fb2014-10-21 14:26:33 -0700263 output(true, DebugTraceOutputTypeBeginEvent, format, vararg);
Jamie Madillb60fe312014-09-26 14:56:41 -0400264#else
Austin Kinross922a9fb2014-10-21 14:26:33 -0700265 output(true, DebugTraceOutputTypeNone, format, vararg);
Austin Kinross570e83c2014-10-20 14:13:58 -0700266#endif // ANGLE_ENABLE_DEBUG_ANNOTATIONS
Jamie Madillb60fe312014-09-26 14:56:41 -0400267 va_end(vararg);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000268}
269
270ScopedPerfEventHelper::~ScopedPerfEventHelper()
271{
Austin Kinross570e83c2014-10-20 14:13:58 -0700272#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000273 if (perfActive())
274 {
Geoff Lang8bc361e2014-11-20 16:23:31 -0500275 GetDebugAnnotationWrapper()->endEvent();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000276 }
277#endif
278}
279}