From 5d99a37d6919c70dfcfcf1f4e950c17cd38c43e7 Mon Sep 17 00:00:00 2001
From: Philip Rebohle <philip.rebohle@tu-dortmund.de>
Date: Wed, 11 Oct 2017 15:31:36 +0200
Subject: [PATCH] [dxgi] Implemented DxgiDevice

---
 src/dxgi/dxgi_adapter.cpp  |   6 +++
 src/dxgi/dxgi_adapter.h    |   9 ++--
 src/dxgi/dxgi_device.cpp   | 106 +++++++++++++++++++++++++++++++++++++
 src/dxgi/dxgi_device.h     |  71 +++++++++++++++++++++++++
 src/dxgi/dxgi_factory.cpp  |  10 ++--
 src/dxgi/dxgi_factory.h    |   2 +-
 src/dxgi/dxgi_include.h    |   3 ++
 src/dxgi/dxgi_interfaces.h |  45 ++++++++++++++++
 src/dxgi/dxgi_object.h     |   4 +-
 src/dxgi/dxgi_output.h     |   4 +-
 src/dxgi/meson.build       |   5 +-
 src/util/com/com_guid.cpp  |   5 ++
 src/util/com/com_object.h  |  12 +++--
 13 files changed, 262 insertions(+), 20 deletions(-)
 create mode 100644 src/dxgi/dxgi_device.cpp
 create mode 100644 src/dxgi/dxgi_device.h
 create mode 100644 src/dxgi/dxgi_interfaces.h

diff --git a/src/dxgi/dxgi_adapter.cpp b/src/dxgi/dxgi_adapter.cpp
index e067ad050..bdff44d49 100644
--- a/src/dxgi/dxgi_adapter.cpp
+++ b/src/dxgi/dxgi_adapter.cpp
@@ -24,6 +24,7 @@ namespace dxvk {
   HRESULT DxgiAdapter::QueryInterface(
           REFIID riid,
           void **ppvObject) {
+    COM_QUERY_IFACE(riid, ppvObject, IDXVKAdapter);
     COM_QUERY_IFACE(riid, ppvObject, IDXGIAdapter);
     
     Logger::warn("DxgiAdapter::QueryInterface: Unknown interface query");
@@ -102,4 +103,9 @@ namespace dxvk {
     return S_OK;
   }
   
+  
+  Rc<DxvkAdapter> DxgiAdapter::GetDXVKAdapter() {
+    return m_adapter;
+  }
+  
 }
diff --git a/src/dxgi/dxgi_adapter.h b/src/dxgi/dxgi_adapter.h
index 972ecd6f3..cd33ccde3 100644
--- a/src/dxgi/dxgi_adapter.h
+++ b/src/dxgi/dxgi_adapter.h
@@ -5,6 +5,7 @@
 
 #include <dxvk_adapter.h>
 
+#include "dxgi_interfaces.h"
 #include "dxgi_object.h"
 
 namespace dxvk {
@@ -12,7 +13,7 @@ namespace dxvk {
   class DxgiFactory;
   class DxgiOutput;
   
-  class DxgiAdapter : public DxgiObject<IDXGIAdapter> {
+  class DxgiAdapter : public DxgiObject<IDXVKAdapter> {
     
   public:
     
@@ -40,10 +41,12 @@ namespace dxvk {
     HRESULT GetDesc(
             DXGI_ADAPTER_DESC *pDesc) final;
     
+    Rc<DxvkAdapter> GetDXVKAdapter() final;
+    
   private:
     
-    DxgiFactory*    m_factory;
-    Rc<DxvkAdapter> m_adapter;
+    Com<DxgiFactory>  m_factory;
+    Rc<DxvkAdapter>   m_adapter;
     
   };
 
diff --git a/src/dxgi/dxgi_device.cpp b/src/dxgi/dxgi_device.cpp
new file mode 100644
index 000000000..d6bd5c8a2
--- /dev/null
+++ b/src/dxgi/dxgi_device.cpp
@@ -0,0 +1,106 @@
+#include "dxgi_device.h"
+#include "dxgi_factory.h"
+
+namespace dxvk {
+  
+  DxgiDevice::DxgiDevice(IDXVKAdapter* adapter)
+  : m_adapter(adapter) {
+    TRACE(this, adapter);
+    m_device = m_adapter->GetDXVKAdapter()->createDevice();
+  }
+  
+  
+  DxgiDevice::~DxgiDevice() {
+    TRACE(this);
+  }
+  
+  
+  HRESULT DxgiDevice::QueryInterface(REFIID riid, void** ppvObject) {
+    COM_QUERY_IFACE(riid, ppvObject, IDXVKDevice);
+    COM_QUERY_IFACE(riid, ppvObject, IDXGIDevice);
+    
+    if (m_layer != nullptr)
+      return m_layer->QueryInterface(riid, ppvObject);
+    
+    Logger::warn("DxgiDevice::QueryInterface: Unknown interface query");
+    return E_NOINTERFACE;
+  }
+  
+  
+  HRESULT DxgiDevice::GetParent(REFIID riid, void** ppParent) {
+    return m_adapter->QueryInterface(riid, ppParent);
+  }
+  
+  
+  HRESULT DxgiDevice::CreateSurface(
+    const DXGI_SURFACE_DESC*    pDesc,
+          UINT                  NumSurfaces,
+          DXGI_USAGE            Usage,
+    const DXGI_SHARED_RESOURCE* pSharedResource,
+          IDXGISurface**        ppSurface) {
+    Logger::err("DxgiDevice::CreateSurface: Not implemented");
+    return E_NOTIMPL;
+  }
+  
+  
+  HRESULT DxgiDevice::GetAdapter(
+          IDXGIAdapter**        pAdapter) {
+    *pAdapter = static_cast<IDXGIAdapter*>(m_adapter.ref());
+    return S_OK;
+  }
+  
+  
+  HRESULT DxgiDevice::GetGPUThreadPriority(
+          INT*                  pPriority) {
+    *pPriority = 0;
+    return S_OK;
+  }
+  
+  
+  HRESULT DxgiDevice::QueryResourceResidency(
+          IUnknown* const*      ppResources,
+          DXGI_RESIDENCY*       pResidencyStatus,
+          UINT                  NumResources) {
+    Logger::err("DxgiDevice::QueryResourceResidency: Not implemented");
+    return E_NOTIMPL;
+  }
+  
+  
+  HRESULT DxgiDevice::SetGPUThreadPriority(
+          INT                   Priority) {
+    if (Priority < -7 || Priority > 7)
+      return E_INVALIDARG;
+    
+    Logger::err("DxgiDevice::SetGPUThreadPriority: Ignoring");
+    return S_OK;
+  }
+  
+  
+  void DxgiDevice::SetDeviceLayer(IUnknown* layer) {
+    TRACE(this, layer);
+    m_layer = layer;
+  }
+  
+  
+  Rc<DxvkDevice> DxgiDevice::GetDXVKDevice() {
+    return m_device;
+  }
+  
+}
+
+
+extern "C" {
+  
+  DLLEXPORT HRESULT __stdcall DXGICreateDXVKDevice(
+          IDXVKAdapter*   pAdapter,
+          IDXVKDevice**   ppDevice) {
+    try {
+      *ppDevice = dxvk::ref(new dxvk::DxgiDevice(pAdapter));
+      return S_OK;
+    } catch (const dxvk::DxvkError& e) {
+      dxvk::Logger::err(e.message());
+      return DXGI_ERROR_UNSUPPORTED;
+    }
+  }
+  
+}
\ No newline at end of file
diff --git a/src/dxgi/dxgi_device.h b/src/dxgi/dxgi_device.h
new file mode 100644
index 000000000..b4d5203f1
--- /dev/null
+++ b/src/dxgi/dxgi_device.h
@@ -0,0 +1,71 @@
+#pragma once
+
+#include <dxvk_device.h>
+
+#include "dxgi_adapter.h"
+#include "dxgi_interfaces.h"
+
+namespace dxvk {
+  
+  class DxgiFactory;
+  
+  class DxgiDevice : public DxgiObject<IDXVKDevice> {
+    
+  public:
+    
+    DxgiDevice(IDXVKAdapter* adapter);
+    ~DxgiDevice();
+    
+    HRESULT QueryInterface(
+            REFIID riid,
+            void **ppvObject) final;
+    
+    HRESULT GetParent(
+            REFIID riid,
+            void   **ppParent) final;
+    
+    HRESULT CreateSurface(
+      const DXGI_SURFACE_DESC*    pDesc,
+            UINT                  NumSurfaces,
+            DXGI_USAGE            Usage,
+      const DXGI_SHARED_RESOURCE* pSharedResource,
+            IDXGISurface**        ppSurface) final;
+    
+    HRESULT GetAdapter(
+            IDXGIAdapter**        pAdapter) final;
+    
+    HRESULT GetGPUThreadPriority(
+            INT*                  pPriority) final;
+    
+    HRESULT QueryResourceResidency(
+            IUnknown* const*      ppResources,
+            DXGI_RESIDENCY*       pResidencyStatus,
+            UINT                  NumResources) final;
+    
+    HRESULT SetGPUThreadPriority(
+            INT                   Priority) final;
+    
+    void SetDeviceLayer(
+            IUnknown*             layer) final;
+    
+    Rc<DxvkDevice> GetDXVKDevice() final;
+    
+  private:
+    
+    Com<IDXVKAdapter> m_adapter;
+    Rc<DxvkDevice>    m_device;
+    
+    IUnknown*         m_layer = nullptr;
+    
+  };
+
+}
+
+
+extern "C" {
+  
+  DLLEXPORT HRESULT __stdcall DXGICreateDXVKDevice(
+          IDXVKAdapter*   pAdapter,
+          IDXVKDevice**   ppDevice);
+  
+}
\ No newline at end of file
diff --git a/src/dxgi/dxgi_factory.cpp b/src/dxgi/dxgi_factory.cpp
index 82d92de57..0beb1a310 100644
--- a/src/dxgi/dxgi_factory.cpp
+++ b/src/dxgi/dxgi_factory.cpp
@@ -4,12 +4,9 @@
 namespace dxvk {
   
   DxgiFactory::DxgiFactory()
-  : m_instance(new DxvkInstance()) {
+  : m_instance(new DxvkInstance()),
+    m_adapters(m_instance->enumAdapters()) {
     TRACE(this);
-    
-    auto adapters = m_instance->enumAdapters();
-    for (auto a : adapters)
-      m_adapters.push_back(new DxgiAdapter(this, a));
   }
   
   
@@ -64,7 +61,8 @@ namespace dxvk {
     if (Adapter >= m_adapters.size())
       return DXGI_ERROR_NOT_FOUND;
     
-    *ppAdapter = m_adapters.at(Adapter).ref();
+    *ppAdapter = ref(new DxgiAdapter(
+      this, m_adapters.at(Adapter)));
     return S_OK;
   }
   
diff --git a/src/dxgi/dxgi_factory.h b/src/dxgi/dxgi_factory.h
index 6903dc45b..7744469eb 100644
--- a/src/dxgi/dxgi_factory.h
+++ b/src/dxgi/dxgi_factory.h
@@ -46,7 +46,7 @@ namespace dxvk {
   private:
     
     Rc<DxvkInstance>              m_instance;
-    std::vector<Com<DxgiAdapter>> m_adapters;
+    std::vector<Rc<DxvkAdapter>>  m_adapters;
     
     HWND m_associatedWindow = nullptr;
     
diff --git a/src/dxgi/dxgi_include.h b/src/dxgi/dxgi_include.h
index 5fab09b35..ebdeba6a5 100644
--- a/src/dxgi/dxgi_include.h
+++ b/src/dxgi/dxgi_include.h
@@ -9,6 +9,9 @@
 #include "../util/log/log.h"
 #include "../util/log/log_debug.h"
 
+#include "../util/rc/util_rc.h"
+#include "../util/rc/util_rc_ptr.h"
+
 #include "../util/util_enum.h"
 #include "../util/util_error.h"
 #include "../util/util_string.h"
diff --git a/src/dxgi/dxgi_interfaces.h b/src/dxgi/dxgi_interfaces.h
new file mode 100644
index 000000000..3e8d9291f
--- /dev/null
+++ b/src/dxgi/dxgi_interfaces.h
@@ -0,0 +1,45 @@
+#pragma once
+
+#include "dxgi_include.h"
+
+namespace dxvk {
+  class DxgiAdapter;
+  class DxvkAdapter;
+  class DxvkDevice;
+}
+  
+/**
+ * \brief DXVK adapter
+ * 
+ * The implementation of \c IDXGIAdapter holds a
+ * \ref DxvkAdapter which can be retrieved using
+ * this interface.
+ */
+MIDL_INTERFACE("907bf281-ea3c-43b4-a8e4-9f231107b4ff")
+IDXVKAdapter : public IDXGIAdapter {
+  static const GUID guid;
+  
+  virtual dxvk::Rc<dxvk::DxvkAdapter> GetDXVKAdapter() = 0;
+};
+
+
+/**
+ * \brief DXVK device
+ * 
+ * The implementation of \c IDXGIDevice stores a
+ * \ref DxvkDevice which can be retrieved using
+ * this interface.
+ */
+MIDL_INTERFACE("7a622cf6-627a-46b2-b52f-360ef3da831c")
+IDXVKDevice : public IDXGIDevice {
+  static const GUID guid;
+  
+  virtual void SetDeviceLayer(
+          IUnknown* layer) = 0;
+  
+  virtual dxvk::Rc<dxvk::DxvkDevice> GetDXVKDevice() = 0;
+};
+
+
+template<> inline GUID const& __mingw_uuidof<IDXVKAdapter>() { return IDXVKAdapter::guid; }
+template<> inline GUID const& __mingw_uuidof<IDXVKDevice> () { return IDXVKDevice ::guid; }
diff --git a/src/dxgi/dxgi_object.h b/src/dxgi/dxgi_object.h
index e14a32e60..c51b58ade 100644
--- a/src/dxgi/dxgi_object.h
+++ b/src/dxgi/dxgi_object.h
@@ -6,8 +6,8 @@
 
 namespace dxvk {
   
-  template<typename Base>
-  class DxgiObject : public ComObject<Base> {
+  template<typename... Base>
+  class DxgiObject : public ComObject<Base...> {
     
   public:
     
diff --git a/src/dxgi/dxgi_output.h b/src/dxgi/dxgi_output.h
index 0abf323a4..e92a96f5f 100644
--- a/src/dxgi/dxgi_output.h
+++ b/src/dxgi/dxgi_output.h
@@ -66,8 +66,8 @@ namespace dxvk {
     
   private:
     
-    DxgiAdapter*  m_adapter;
-    UINT          m_display;
+    Com<DxgiAdapter>  m_adapter;
+    UINT              m_display;
     
   };
 
diff --git a/src/dxgi/meson.build b/src/dxgi/meson.build
index 0bee8ffed..fb8590cd9 100644
--- a/src/dxgi/meson.build
+++ b/src/dxgi/meson.build
@@ -1,5 +1,6 @@
 dxgi_src = [
   'dxgi_adapter.cpp',
+  'dxgi_device.cpp',
   'dxgi_factory.cpp',
   'dxgi_main.cpp',
   'dxgi_output.cpp',
@@ -7,9 +8,11 @@ dxgi_src = [
 ]
 
 dxgi_dll = shared_library('dxgi', dxgi_src,
+  name_prefix         : '',
   link_with           : [ util_lib ],
   dependencies        : [ dxvk_dep ],
-  include_directories : dxvk_include_path)
+  include_directories : dxvk_include_path,
+  install             : true)
 
 dxgi_dep = declare_dependency(
   link_with           : [ dxgi_dll ],
diff --git a/src/util/com/com_guid.cpp b/src/util/com/com_guid.cpp
index 2b81f7568..e308a8e8f 100644
--- a/src/util/com/com_guid.cpp
+++ b/src/util/com/com_guid.cpp
@@ -1,5 +1,10 @@
 #include "com_guid.h"
 
+#include "../../dxgi/dxgi_interfaces.h"
+
+const GUID IDXVKAdapter::guid     = {0x907bf281,0xea3c,0x43b4,{0xa8,0xe4,0x9f,0x23,0x11,0x07,0xb4,0xff}};
+const GUID IDXVKDevice::guid      = {0x7a622cf6,0x627a,0x46b2,{0xb5,0x2f,0x36,0x0e,0xf3,0xda,0x83,0x1c}};
+
 std::ostream& operator << (std::ostream& os, REFIID guid) {
   os.width(8);
   os << std::hex << guid.Data1 << '-';
diff --git a/src/util/com/com_object.h b/src/util/com/com_object.h
index 4b6b7d1d3..9a6e7958a 100644
--- a/src/util/com/com_object.h
+++ b/src/util/com/com_object.h
@@ -5,11 +5,13 @@
 #include "com_include.h"
 
 #define COM_QUERY_IFACE(riid, ppvObject, Iface) \
-  if (riid == __uuidof(Iface)) {                \
-    this->AddRef();                             \
-    *ppvObject = static_cast<Iface*>(this);     \
-    return S_OK;                                \
-  }
+  do {                                          \
+    if (riid == __uuidof(Iface)) {              \
+      this->AddRef();                           \
+      *ppvObject = static_cast<Iface*>(this);   \
+      return S_OK;                              \
+    }                                           \
+  } while (0)
 
 namespace dxvk {