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())