Use D3D11 Debug Annotations when D3D9 is unavailable
Change-Id: I37ac5fe7f0b2fe5e71bd7f0afca55e9894f3463c
Reviewed-on: https://chromium-review.googlesource.com/224512
Tested-by: Austin Kinross <aukinros@microsoft.com>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/common/angleutils.cpp b/src/common/angleutils.cpp
index 2ced98d..c1367c4 100644
--- a/src/common/angleutils.cpp
+++ b/src/common/angleutils.cpp
@@ -5,26 +5,32 @@
//
#include "common/angleutils.h"
-
+#include "debug.h"
#include <stdio.h>
#include <vector>
+size_t FormatStringIntoVector(const char *fmt, va_list vararg, std::vector<char>& outBuffer)
+{
+ // Attempt to just print to the current buffer
+ int len = vsnprintf(&(outBuffer.front()), outBuffer.size(), fmt, vararg);
+ if (len < 0 || static_cast<size_t>(len) >= outBuffer.size())
+ {
+ // Buffer was not large enough, calculate the required size and resize the buffer
+ len = vsnprintf(NULL, 0, fmt, vararg);
+ outBuffer.resize(len + 1);
+
+ // Print again
+ len = vsnprintf(&(outBuffer.front()), outBuffer.size(), fmt, vararg);
+ }
+ ASSERT(len >= 0);
+ return static_cast<size_t>(len);
+}
+
std::string FormatString(const char *fmt, va_list vararg)
{
static std::vector<char> buffer(512);
- // Attempt to just print to the current buffer
- int len = vsnprintf(&buffer[0], buffer.size(), fmt, vararg);
- if (len < 0 || static_cast<size_t>(len) >= buffer.size())
- {
- // Buffer was not large enough, calculate the required size and resize the buffer
- len = vsnprintf(NULL, 0, fmt, vararg);
- buffer.resize(len + 1);
-
- // Print again
- vsnprintf(&buffer[0], buffer.size(), fmt, vararg);
- }
-
+ size_t len = FormatStringIntoVector(fmt, vararg, buffer);
return std::string(&buffer[0], len);
}
diff --git a/src/common/angleutils.h b/src/common/angleutils.h
index 22c33bf..e77fcc7 100644
--- a/src/common/angleutils.h
+++ b/src/common/angleutils.h
@@ -17,6 +17,7 @@
#include <set>
#include <sstream>
#include <cstdarg>
+#include <vector>
// A macro to disallow the copy constructor and operator= functions
// This must be used in the private: declarations for a class
@@ -139,6 +140,8 @@
return strstr.str();
}
+size_t FormatStringIntoVector(const char *fmt, va_list vararg, std::vector<char>& buffer);
+
std::string FormatString(const char *fmt, va_list vararg);
std::string FormatString(const char *fmt, ...);
diff --git a/src/common/debug.cpp b/src/common/debug.cpp
index e09d560..5f55ff1 100644
--- a/src/common/debug.cpp
+++ b/src/common/debug.cpp
@@ -18,30 +18,199 @@
namespace gl
{
#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
-typedef void (WINAPI *PerfOutputFunction)(D3DCOLOR, LPCWSTR);
-#else
-typedef void (*PerfOutputFunction)(unsigned int, const wchar_t*);
-#endif
-
-static void output(bool traceInDebugOnly, PerfOutputFunction perfFunc, const char *format, va_list vararg)
+// Wraps the D3D9/D3D11 debug annotation functions.
+class DebugAnnotationWrapper
{
-#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS) || defined(ANGLE_ENABLE_DEBUG_TRACE)
- std::string formattedMessage = FormatString(format, vararg);
+ public:
+ DebugAnnotationWrapper() { };
+ virtual ~DebugAnnotationWrapper() { };
+ virtual void beginEvent(const std::wstring &eventName) = 0;
+ virtual void endEvent() = 0;
+ virtual void setMarker(const std::wstring &markerName) = 0;
+ virtual bool getStatus() = 0;
+};
+
+#if defined(ANGLE_ENABLE_D3D9)
+class D3D9DebugAnnotationWrapper : public DebugAnnotationWrapper
+{
+ public:
+ void beginEvent(const std::wstring &eventName)
+ {
+ D3DPERF_BeginEvent(0, eventName.c_str());
+ }
+
+ void endEvent()
+ {
+ D3DPERF_EndEvent();
+ }
+
+ void setMarker(const std::wstring &markerName)
+ {
+ D3DPERF_SetMarker(0, markerName.c_str());
+ }
+
+ bool getStatus()
+ {
+ return !!D3DPERF_GetStatus();
+ }
+};
+#endif // ANGLE_ENABLE_D3D9
+
+#if defined(ANGLE_ENABLE_D3D11)
+class D3D11DebugAnnotationWrapper : public DebugAnnotationWrapper
+{
+ public:
+
+ D3D11DebugAnnotationWrapper()
+ : mInitialized(false),
+ mD3d11Module(NULL),
+ mUserDefinedAnnotation(NULL)
+ {
+ // D3D11 devices can't be created during DllMain.
+ // We defer device creation until the object is actually used.
+ }
+
+ ~D3D11DebugAnnotationWrapper()
+ {
+ if (mInitialized)
+ {
+ SafeRelease(mUserDefinedAnnotation);
+ FreeLibrary(mD3d11Module);
+ }
+ }
+
+ virtual void beginEvent(const std::wstring &eventName)
+ {
+ initializeDevice();
+
+ mUserDefinedAnnotation->BeginEvent(eventName.c_str());
+ }
+
+ virtual void endEvent()
+ {
+ initializeDevice();
+
+ mUserDefinedAnnotation->EndEvent();
+ }
+
+ virtual void setMarker(const std::wstring &markerName)
+ {
+ initializeDevice();
+
+ mUserDefinedAnnotation->SetMarker(markerName.c_str());
+ }
+
+ virtual bool getStatus()
+ {
+ // ID3DUserDefinedAnnotation::GetStatus doesn't work with the Graphics Diagnostics tools in Visual Studio 2013.
+
+#if defined(_DEBUG) && defined(ANGLE_ENABLE_WINDOWS_STORE)
+ // In the Windows Store, we can use IDXGraphicsAnalysis. The call to GetDebugInterface1 only succeeds if the app is under capture.
+ // This should only be called in DEBUG mode.
+ // If an app links against DXGIGetDebugInterface1 in release mode then it will fail Windows Store ingestion checks.
+ IDXGraphicsAnalysis* graphicsAnalysis;
+ DXGIGetDebugInterface1(0, IID_PPV_ARGS(&graphicsAnalysis));
+ bool underCapture = (graphicsAnalysis != NULL);
+ SafeRelease(graphicsAnalysis);
+ return underCapture;
#endif
+ // Otherwise, we have to return true here.
+ return true;
+ }
+
+ protected:
+
+ void initializeDevice()
+ {
+ if (!mInitialized)
+ {
+#if !defined(ANGLE_ENABLE_WINDOWS_STORE)
+ mD3d11Module = LoadLibrary(TEXT("d3d11.dll"));
+ ASSERT(mD3d11Module);
+
+ PFN_D3D11_CREATE_DEVICE D3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(mD3d11Module, "D3D11CreateDevice");
+ ASSERT(D3D11CreateDevice != NULL);
+#endif // !ANGLE_ENABLE_WINDOWS_STORE
+
+ ID3D11Device* device = NULL;
+ ID3D11DeviceContext* context = NULL;
+
+ HRESULT hr = E_FAIL;
+
+ // Create a D3D_DRIVER_TYPE_NULL device, which is much cheaper than other types of device.
+ hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_NULL, NULL, 0, NULL, 0, D3D11_SDK_VERSION, &device, NULL, &context);
+ ASSERT(SUCCEEDED(hr));
+
+ hr = context->QueryInterface(__uuidof(mUserDefinedAnnotation), reinterpret_cast<void**>(&mUserDefinedAnnotation));
+ ASSERT(SUCCEEDED(hr) && mUserDefinedAnnotation != NULL);
+
+ SafeRelease(device);
+ SafeRelease(context);
+
+ mInitialized = true;
+ }
+ }
+
+ bool mInitialized;
+ HMODULE mD3d11Module;
+ ID3DUserDefinedAnnotation* mUserDefinedAnnotation;
+};
+#endif // ANGLE_ENABLE_D3D11
+
+static DebugAnnotationWrapper* g_DebugAnnotationWrapper = NULL;
+
+void InitializeDebugAnnotations()
+{
+#if defined(ANGLE_ENABLE_D3D9)
+ g_DebugAnnotationWrapper = new D3D9DebugAnnotationWrapper();
+#elif defined(ANGLE_ENABLE_D3D11)
+ // If the project uses D3D9 then we can use the D3D9 debug annotations, even with the D3D11 renderer.
+ // However, if D3D9 is unavailable (e.g. in Windows Store), then we use D3D11 debug annotations.
+ // The D3D11 debug annotations are methods on ID3DUserDefinedAnnotation, which is implemented by the DeviceContext.
+ // This doesn't have to be the same DeviceContext that the renderer uses, though.
+ g_DebugAnnotationWrapper = new D3D11DebugAnnotationWrapper();
+#endif
+}
+
+void UninitializeDebugAnnotations()
+{
+ if (g_DebugAnnotationWrapper != NULL)
+ {
+ SafeDelete(g_DebugAnnotationWrapper);
+ }
+}
+
+#endif // ANGLE_ENABLE_DEBUG_ANNOTATIONS
+
+enum DebugTraceOutputType
+{
+ DebugTraceOutputTypeNone,
+ DebugTraceOutputTypeSetMarker,
+ DebugTraceOutputTypeBeginEvent
+};
+
+static void output(bool traceInDebugOnly, DebugTraceOutputType outputType, const char *format, va_list vararg)
+{
#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
+ static std::vector<char> buffer(512);
+
if (perfActive())
{
- // The perf function only accepts wide strings, widen the ascii message
- static std::wstring wideMessage;
- if (wideMessage.capacity() < formattedMessage.length())
+ size_t len = FormatStringIntoVector(format, vararg, buffer);
+ std::wstring formattedWideMessage(buffer.begin(), buffer.begin() + len);
+
+ switch (outputType)
{
- wideMessage.reserve(formattedMessage.size());
+ case DebugTraceOutputTypeNone:
+ break;
+ case DebugTraceOutputTypeBeginEvent:
+ g_DebugAnnotationWrapper->beginEvent(formattedWideMessage);
+ break;
+ case DebugTraceOutputTypeSetMarker:
+ g_DebugAnnotationWrapper->setMarker(formattedWideMessage);
+ break;
}
-
- wideMessage.assign(formattedMessage.begin(), formattedMessage.end());
-
- perfFunc(0, wideMessage.c_str());
}
#endif // ANGLE_ENABLE_DEBUG_ANNOTATIONS
@@ -52,6 +221,7 @@
return;
}
#endif // NDEBUG
+ std::string formattedMessage = FormatString(format, vararg);
static std::ofstream file(TRACE_OUTPUT_FILE, std::ofstream::app);
if (file)
@@ -72,9 +242,9 @@
va_list vararg;
va_start(vararg, format);
#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
- output(traceInDebugOnly, D3DPERF_SetMarker, format, vararg);
+ output(traceInDebugOnly, DebugTraceOutputTypeSetMarker, format, vararg);
#else
- output(traceInDebugOnly, NULL, format, vararg);
+ output(traceInDebugOnly, DebugTraceOutputTypeNone, format, vararg);
#endif
va_end(vararg);
}
@@ -82,7 +252,7 @@
bool perfActive()
{
#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
- static bool active = D3DPERF_GetStatus() != 0;
+ static bool active = g_DebugAnnotationWrapper->getStatus();
return active;
#else
return false;
@@ -100,9 +270,9 @@
va_list vararg;
va_start(vararg, format);
#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
- output(true, reinterpret_cast<PerfOutputFunction>(D3DPERF_BeginEvent), format, vararg);
+ output(true, DebugTraceOutputTypeBeginEvent, format, vararg);
#else
- output(true, NULL, format, vararg);
+ output(true, DebugTraceOutputTypeNone, format, vararg);
#endif // ANGLE_ENABLE_DEBUG_ANNOTATIONS
va_end(vararg);
}
@@ -112,7 +282,7 @@
#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
if (perfActive())
{
- D3DPERF_EndEvent();
+ g_DebugAnnotationWrapper->endEvent();
}
#endif
}
diff --git a/src/common/debug.h b/src/common/debug.h
index 8883ce5..c177f51 100644
--- a/src/common/debug.h
+++ b/src/common/debug.h
@@ -36,6 +36,9 @@
private:
DISALLOW_COPY_AND_ASSIGN(ScopedPerfEventHelper);
};
+
+ void InitializeDebugAnnotations();
+ void UninitializeDebugAnnotations();
}
// A macro to output a trace of a function call and its arguments to the debugging log
diff --git a/src/common/platform.h b/src/common/platform.h
index 07890aa..cd12dba 100644
--- a/src/common/platform.h
+++ b/src/common/platform.h
@@ -50,7 +50,7 @@
# include <windows.h>
# include <intrin.h>
-# if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS)
+# if defined(ANGLE_ENABLE_D3D9)
# include <d3d9.h>
# include <d3dcompiler.h>
# endif
@@ -58,14 +58,18 @@
# if defined(ANGLE_ENABLE_D3D11)
# include <d3d10_1.h>
# include <d3d11.h>
+# include <d3d11_1.h>
# include <dxgi.h>
# include <dxgi1_2.h>
# include <d3dcompiler.h>
# endif
# if defined(ANGLE_ENABLE_WINDOWS_STORE)
-# undef ANGLE_ENABLE_DEBUG_ANNOTATIONS
# include <dxgi1_3.h>
+# if defined(_DEBUG)
+# include <DXProgrammableCapture.h>
+# include <dxgidebug.h>
+# endif
# endif
# undef near
diff --git a/src/common/utilities.cpp b/src/common/utilities.cpp
index d646585..9d797a6 100644
--- a/src/common/utilities.cpp
+++ b/src/common/utilities.cpp
@@ -446,82 +446,26 @@
}
+#if !defined(ANGLE_ENABLE_WINDOWS_STORE)
std::string getTempPath()
{
#ifdef ANGLE_PLATFORM_WINDOWS
- #if defined(ANGLE_ENABLE_WINDOWS_STORE)
-
- using namespace Microsoft::WRL;
- using namespace Microsoft::WRL::Wrappers;
- using namespace ABI::Windows::ApplicationModel::Core;
- using namespace ABI::Windows::Foundation;
- using namespace ABI::Windows::Foundation::Collections;
-
- ComPtr<IActivationFactory> pActivationFactory;
- ComPtr<ABI::Windows::ApplicationModel::IPackageStatics> packageStatics;
- ComPtr<ABI::Windows::ApplicationModel::IPackage> package;
- ComPtr<ABI::Windows::Storage::IStorageFolder> storageFolder;
- ComPtr<ABI::Windows::Storage::IStorageItem> storageItem;
- HString hstrPath;
-
- HRESULT result = GetActivationFactory(HStringReference(RuntimeClass_Windows_ApplicationModel_Package).Get(), &pActivationFactory);
- ASSERT(SUCCEEDED(result));
- if (SUCCEEDED(result))
- {
- result = pActivationFactory.As(&packageStatics);
- ASSERT(SUCCEEDED(result));
- }
-
- if (SUCCEEDED(result))
- {
- result = packageStatics->get_Current(&package);
- ASSERT(SUCCEEDED(result));
- }
-
- if (SUCCEEDED(result))
- {
- result = package->get_InstalledLocation(&storageFolder);
- ASSERT(SUCCEEDED(result));
- }
-
- if (SUCCEEDED(result))
- {
- result = storageFolder.As(&storageItem);
- ASSERT(SUCCEEDED(result));
- }
-
- if (SUCCEEDED(result))
- {
- result = storageItem->get_Path(hstrPath.GetAddressOf());
- ASSERT(SUCCEEDED(result));
- }
-
- if (SUCCEEDED(result))
- {
- std::wstring t = std::wstring(hstrPath.GetRawBuffer(nullptr));
- return std::string(t.begin(), t.end());
- }
-
+ char path[MAX_PATH];
+ DWORD pathLen = GetTempPathA(sizeof(path) / sizeof(path[0]), path);
+ if (pathLen == 0)
+ {
UNREACHABLE();
return std::string();
- #else
- char path[MAX_PATH];
- DWORD pathLen = GetTempPathA(sizeof(path) / sizeof(path[0]), path);
- if (pathLen == 0)
- {
- UNREACHABLE();
- return std::string();
- }
+ }
- UINT unique = GetTempFileNameA(path, "sh", 0, path);
- if (unique == 0)
- {
- UNREACHABLE();
- return std::string();
- }
+ UINT unique = GetTempFileNameA(path, "sh", 0, path);
+ if (unique == 0)
+ {
+ UNREACHABLE();
+ return std::string();
+ }
- return path;
- #endif
+ return path;
#else
UNIMPLEMENTED();
return "";
@@ -540,6 +484,7 @@
fwrite(content, sizeof(char), size, file);
fclose(file);
}
+#endif // !ANGLE_ENABLE_WINDOWS_STORE
#if defined(ANGLE_ENABLE_WINDOWS_STORE)
@@ -568,4 +513,4 @@
WaitForSingleObjectEx(sleepEvent, dwMilliseconds, false);
}
-#endif
+#endif // ANGLE_ENABLE_WINDOWS_STORE
diff --git a/src/common/utilities.h b/src/common/utilities.h
index f7cc998..2cf6bed 100644
--- a/src/common/utilities.h
+++ b/src/common/utilities.h
@@ -46,8 +46,10 @@
}
+#if !defined(ANGLE_ENABLE_WINDOWS_STORE)
std::string getTempPath();
void writeFile(const char* path, const void* data, size_t size);
+#endif
#if defined(ANGLE_ENABLE_WINDOWS_STORE)
void Sleep(_In_ unsigned long dwMilliseconds);
diff --git a/src/libEGL.gypi b/src/libEGL.gypi
index 0c56193..041ef87 100644
--- a/src/libEGL.gypi
+++ b/src/libEGL.gypi
@@ -155,6 +155,13 @@
'd3d9.lib',
],
}],
+ ['angle_build_winrt==1',
+ {
+ 'AdditionalDependencies':
+ [
+ 'd3d11.lib',
+ ],
+ }],
],
},
},
diff --git a/src/libEGL/main.cpp b/src/libEGL/main.cpp
index aa4333e..35857df 100644
--- a/src/libEGL/main.cpp
+++ b/src/libEGL/main.cpp
@@ -75,6 +75,10 @@
{
return FALSE;
}
+
+#ifdef ANGLE_ENABLE_DEBUG_ANNOTATIONS
+ gl::InitializeDebugAnnotations();
+#endif
}
// Fall through to initialize index
case DLL_THREAD_ATTACH:
@@ -91,6 +95,10 @@
{
egl::DeallocateCurrent();
DestroyTLSIndex(currentTLS);
+
+#ifdef ANGLE_ENABLE_DEBUG_ANNOTATIONS
+ gl::UninitializeDebugAnnotations();
+#endif
}
break;
default:
diff --git a/src/libGLESv2.gypi b/src/libGLESv2.gypi
index 0b80d75..361e645 100644
--- a/src/libGLESv2.gypi
+++ b/src/libGLESv2.gypi
@@ -520,6 +520,16 @@
'msvs_enable_winphone' : '1',
}],
],
+ 'configurations':
+ {
+ 'Debug_Base':
+ {
+ 'defines':
+ [
+ 'ANGLE_ENABLE_DEBUG_ANNOTATIONS',
+ ],
+ },
+ },
},
{
'target_name': 'libGLESv2_static',
diff --git a/src/libGLESv2/main.cpp b/src/libGLESv2/main.cpp
index 2135d8b..7557348 100644
--- a/src/libGLESv2/main.cpp
+++ b/src/libGLESv2/main.cpp
@@ -85,6 +85,10 @@
{
return FALSE;
}
+
+#ifdef ANGLE_ENABLE_DEBUG_ANNOTATIONS
+ gl::InitializeDebugAnnotations();
+#endif
}
// Fall through to initialize index
case DLL_THREAD_ATTACH:
@@ -101,6 +105,10 @@
{
gl::DeallocateCurrent();
gl::DestroyThreadLocalIndex();
+
+#ifdef ANGLE_ENABLE_DEBUG_ANNOTATIONS
+ gl::UninitializeDebugAnnotations();
+#endif
}
break;
default:
diff --git a/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp b/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp
index a67d274..59a6a2f 100644
--- a/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp
+++ b/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp
@@ -183,12 +183,14 @@
#endif
ASSERT(mD3DCompileFunc);
+#if !defined(ANGLE_ENABLE_WINDOWS_STORE)
if (gl::perfActive())
{
std::string sourcePath = getTempPath();
std::string sourceText = FormatString("#line 2 \"%s\"\n\n%s", sourcePath.c_str(), hlsl.c_str());
writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size());
}
+#endif
const D3D_SHADER_MACRO *macros = overrideMacros ? overrideMacros : NULL;
diff --git a/src/libGLESv2/renderer/d3d/ShaderD3D.cpp b/src/libGLESv2/renderer/d3d/ShaderD3D.cpp
index cdb927b..de35624 100644
--- a/src/libGLESv2/renderer/d3d/ShaderD3D.cpp
+++ b/src/libGLESv2/renderer/d3d/ShaderD3D.cpp
@@ -220,12 +220,15 @@
int compileOptions = (SH_OBJECT_CODE | SH_VARIABLES);
std::string sourcePath;
+
+#if !defined (ANGLE_ENABLE_WINDOWS_STORE)
if (gl::perfActive())
{
sourcePath = getTempPath();
writeFile(sourcePath.c_str(), source.c_str(), source.length());
compileOptions |= SH_LINE_DIRECTIVES;
}
+#endif
int result;
if (sourcePath.empty())