DxgiAPI.cpp
  1  #include "pch.h"
  2  
  3  #include "DxgiAPI.h"
  4  
  5  #include <common/Display/dpi_aware.h>
  6  
  7  //#define DEBUG_DEVICES
  8  #define SEPARATE_D3D_FOR_CAPTURE
  9  
 10  namespace
 11  {
 12      DxgiAPI::D3D CreateD3D()
 13      {
 14          DxgiAPI::D3D d3d;
 15          UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
 16  #if defined(DEBUG_DEVICES)
 17          flags |= D3D11_CREATE_DEVICE_DEBUG;
 18  #endif
 19          HRESULT hr =
 20              D3D11CreateDevice(nullptr,
 21                                D3D_DRIVER_TYPE_HARDWARE,
 22                                nullptr,
 23                                flags,
 24                                nullptr,
 25                                0,
 26                                D3D11_SDK_VERSION,
 27                                d3d.d3dDevice.put(),
 28                                nullptr,
 29                                nullptr);
 30          if (hr == DXGI_ERROR_UNSUPPORTED)
 31          {
 32              hr = D3D11CreateDevice(nullptr,
 33                                     D3D_DRIVER_TYPE_WARP,
 34                                     nullptr,
 35                                     flags,
 36                                     nullptr,
 37                                     0,
 38                                     D3D11_SDK_VERSION,
 39                                     d3d.d3dDevice.put(),
 40                                     nullptr,
 41                                     nullptr);
 42          }
 43          winrt::check_hresult(hr);
 44  
 45          d3d.dxgiDevice = d3d.d3dDevice.as<IDXGIDevice>();
 46          winrt::check_hresult(CreateDirect3D11DeviceFromDXGIDevice(d3d.dxgiDevice.get(), d3d.d3dDeviceInspectable.put()));
 47  
 48          winrt::com_ptr<IDXGIAdapter> adapter;
 49          winrt::check_hresult(d3d.dxgiDevice->GetParent(winrt::guid_of<IDXGIAdapter>(), adapter.put_void()));
 50          winrt::check_hresult(adapter->GetParent(winrt::guid_of<IDXGIFactory2>(), d3d.dxgiFactory2.put_void()));
 51  
 52          d3d.d3dDevice->GetImmediateContext(d3d.d3dContext.put());
 53          winrt::check_bool(d3d.d3dContext);
 54          auto contextMultithread = d3d.d3dContext.as<ID3D11Multithread>();
 55          contextMultithread->SetMultithreadProtected(true);
 56  
 57          return d3d;
 58      }
 59  }
 60  
 61  DxgiAPI::DxgiAPI()
 62  {
 63      const D2D1_FACTORY_OPTIONS d2dFactoryOptions = {
 64  #if defined(DEBUG_DEVICES)
 65          D2D1_DEBUG_LEVEL_INFORMATION
 66  #else
 67          D2D1_DEBUG_LEVEL_NONE
 68  #endif
 69      };
 70  
 71      winrt::check_hresult(D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, d2dFactoryOptions, d2dFactory2.put()));
 72  
 73      winrt::check_hresult(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED,
 74                                               winrt::guid_of<IDWriteFactory>(),
 75                                               reinterpret_cast<IUnknown**>(writeFactory.put())));
 76  
 77      auto d3d = CreateD3D();
 78      d3dDevice = d3d.d3dDevice;
 79      dxgiDevice = d3d.dxgiDevice;
 80      d3dDeviceInspectable = d3d.d3dDeviceInspectable;
 81      dxgiFactory2 = d3d.dxgiFactory2;
 82      d3dContext = d3d.d3dContext;
 83  #if defined(SEPARATE_D3D_FOR_CAPTURE)
 84      auto d3dFC = CreateD3D();
 85      d3dForCapture = d3dFC;
 86  #else
 87      d3dForCapture = d3d;
 88  #endif
 89      winrt::check_hresult(d2dFactory2->CreateDevice(dxgiDevice.get(), d2dDevice1.put()));
 90      winrt::check_hresult(DCompositionCreateDevice(
 91          dxgiDevice.get(),
 92          winrt::guid_of<IDCompositionDevice>(),
 93          compositionDevice.put_void()));
 94  }
 95  
 96  DxgiWindowState DxgiAPI::CreateD2D1RenderTarget(HWND window) const
 97  {
 98      RECT rect = {};
 99      winrt::check_bool(GetClientRect(window, &rect));
100  
101      const DXGI_SWAP_CHAIN_DESC1 desc = {
102          .Width = static_cast<UINT>(rect.right - rect.left),
103          .Height = static_cast<UINT>(rect.bottom - rect.top),
104          .Format = static_cast<DXGI_FORMAT>(winrt::DirectXPixelFormat::B8G8R8A8UIntNormalized),
105          .SampleDesc = { .Count = 1, .Quality = 0 },
106          .BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT,
107          .BufferCount = 2,
108          .Scaling = DXGI_SCALING_STRETCH,
109          .SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD,
110          .AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED,
111      };
112  
113      DxgiWindowState state;
114      winrt::com_ptr<ID2D1DeviceContext> rt;
115      d2dDevice1->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE, rt.put());
116      state.rt = rt;
117  
118      winrt::check_hresult(dxgiFactory2->CreateSwapChainForComposition(d3dDevice.get(),
119                                                                       &desc,
120                                                                       nullptr,
121                                                                       state.swapChain.put()));
122      winrt::com_ptr<IDXGISurface> surface;
123      winrt::check_hresult(state.swapChain->GetBuffer(0, winrt::guid_of<IDXGISurface>(), surface.put_void()));
124  
125      const D2D1_BITMAP_PROPERTIES1 properties = {
126          .pixelFormat = { .format = DXGI_FORMAT_B8G8R8A8_UNORM, .alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED },
127          .bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW
128      };
129      winrt::com_ptr<ID2D1Bitmap1> bitmap;
130      winrt::check_hresult(rt->CreateBitmapFromDxgiSurface(surface.get(),
131                                                           properties,
132                                                           bitmap.put()));
133      rt->SetTarget(bitmap.get());
134      winrt::check_hresult(compositionDevice->CreateTargetForHwnd(window,
135                                                                  true,
136                                                                  state.compositionTarget.put()));
137  
138      winrt::com_ptr<IDCompositionVisual> visual;
139      winrt::check_hresult(compositionDevice->CreateVisual(visual.put()));
140      winrt::check_hresult(visual->SetContent(state.swapChain.get()));
141      winrt::check_hresult(state.compositionTarget->SetRoot(visual.get()));
142      winrt::check_hresult(compositionDevice->Commit());
143  
144      return state;
145  }