sample.cpp.txt 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. #include "pch.h"
  2. #include "Direct3DBase.h"
  3. using namespace Microsoft::WRL;
  4. using namespace Windows::UI::Core;
  5. using namespace Windows::Foundation;
  6. // Constructor.
  7. Direct3DBase::Direct3DBase()
  8. {
  9. }
  10. // Initialize the Direct3D resources required to run.
  11. void Direct3DBase::Initialize(CoreWindow^ window)
  12. {
  13. m_window = window;
  14. CreateDeviceResources();
  15. CreateWindowSizeDependentResources();
  16. }
  17. // These are the resources that depend on the device.
  18. void Direct3DBase::CreateDeviceResources()
  19. {
  20. // This flag adds support for surfaces with a different color channel ordering than the API default.
  21. // It is recommended usage, and is required for compatibility with Direct2D.
  22. UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
  23. #if defined(_DEBUG)
  24. // If the project is in a debug build, enable debugging via SDK Layers with this flag.
  25. creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
  26. #endif
  27. // This array defines the set of DirectX hardware feature levels this app will support.
  28. // Note the ordering should be preserved.
  29. // Don't forget to declare your application's minimum required feature level in its
  30. // description. All applications are assumed to support 9.1 unless otherwise stated.
  31. D3D_FEATURE_LEVEL featureLevels[] =
  32. {
  33. D3D_FEATURE_LEVEL_11_1,
  34. D3D_FEATURE_LEVEL_11_0,
  35. D3D_FEATURE_LEVEL_10_1,
  36. D3D_FEATURE_LEVEL_10_0,
  37. D3D_FEATURE_LEVEL_9_3,
  38. D3D_FEATURE_LEVEL_9_2,
  39. D3D_FEATURE_LEVEL_9_1
  40. };
  41. // Create the DX11 API device object, and get a corresponding context.
  42. ComPtr<ID3D11Device> device;
  43. ComPtr<ID3D11DeviceContext> context;
  44. DX::ThrowIfFailed(
  45. D3D11CreateDevice(
  46. nullptr, // specify null to use the default adapter
  47. D3D_DRIVER_TYPE_HARDWARE,
  48. nullptr, // leave as nullptr unless software device
  49. creationFlags, // optionally set debug and Direct2D compatibility flags
  50. featureLevels, // list of feature levels this app can support
  51. ARRAYSIZE(featureLevels), // number of entries in above list
  52. D3D11_SDK_VERSION, // always set this to D3D11_SDK_VERSION
  53. &device, // returns the Direct3D device created
  54. &m_featureLevel, // returns feature level of device created
  55. &context // returns the device immediate context
  56. )
  57. );
  58. // Get the DirectX11.1 device by QI off the DirectX11 one.
  59. DX::ThrowIfFailed(
  60. device.As(&m_d3dDevice)
  61. );
  62. // And get the corresponding device context in the same way.
  63. DX::ThrowIfFailed(
  64. context.As(&m_d3dContext)
  65. );
  66. }
  67. // Allocate all memory resources that change on a window SizeChanged event.
  68. void Direct3DBase::CreateWindowSizeDependentResources()
  69. {
  70. // Store the window bounds so the next time we get a SizeChanged event we can
  71. // avoid rebuilding everything if the size is identical.
  72. m_windowBounds = m_window->Bounds;
  73. // If the swap chain already exists, resize it.
  74. if(m_swapChain != nullptr)
  75. {
  76. DX::ThrowIfFailed(
  77. m_swapChain->ResizeBuffers(2, 0, 0, DXGI_FORMAT_B8G8R8A8_UNORM, 0)
  78. );
  79. }
  80. // Otherwise, create a new one.
  81. else
  82. {
  83. // Create a descriptor for the swap chain.
  84. DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0};
  85. swapChainDesc.Width = 0; // use automatic sizing
  86. swapChainDesc.Height = 0;
  87. swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // this is the most common swapchain format
  88. swapChainDesc.Stereo = false;
  89. swapChainDesc.SampleDesc.Count = 1; // don't use multi-sampling
  90. swapChainDesc.SampleDesc.Quality = 0;
  91. swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
  92. swapChainDesc.BufferCount = 2; // use two buffers to enable flip effect
  93. swapChainDesc.Scaling = DXGI_SCALING_NONE;
  94. swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // we recommend using this swap effect for all applications
  95. swapChainDesc.Flags = 0;
  96. // Once the desired swap chain description is configured, it must be created on the same adapter as our D3D Device
  97. // First, retrieve the underlying DXGI Device from the D3D Device
  98. ComPtr<IDXGIDevice1> dxgiDevice;
  99. DX::ThrowIfFailed(
  100. m_d3dDevice.As(&dxgiDevice)
  101. );
  102. // Identify the physical adapter (GPU or card) this device is running on.
  103. ComPtr<IDXGIAdapter> dxgiAdapter;
  104. DX::ThrowIfFailed(
  105. dxgiDevice->GetAdapter(&dxgiAdapter)
  106. );
  107. // And obtain the factory object that created it.
  108. ComPtr<IDXGIFactory2> dxgiFactory;
  109. DX::ThrowIfFailed(
  110. dxgiAdapter->GetParent(
  111. __uuidof(IDXGIFactory2),
  112. &dxgiFactory
  113. )
  114. );
  115. Windows::UI::Core::CoreWindow^ p = m_window.Get();
  116. // Create a swap chain for this window from the DXGI factory.
  117. DX::ThrowIfFailed(
  118. dxgiFactory->CreateSwapChainForCoreWindow(
  119. m_d3dDevice.Get(),
  120. reinterpret_cast<IUnknown*>(p),
  121. &swapChainDesc,
  122. nullptr, // allow on all displays
  123. &m_swapChain
  124. )
  125. );
  126. // Ensure that DXGI does not queue more than one frame at a time. This both reduces
  127. // latency and ensures that the application will only render after each VSync, minimizing
  128. // power consumption.
  129. DX::ThrowIfFailed(
  130. dxgiDevice->SetMaximumFrameLatency(1)
  131. );
  132. }
  133. // Obtain the backbuffer for this window which will be the final 3D rendertarget.
  134. ComPtr<ID3D11Texture2D> backBuffer;
  135. DX::ThrowIfFailed(
  136. m_swapChain->GetBuffer(
  137. 0,
  138. __uuidof(ID3D11Texture2D),
  139. &backBuffer
  140. )
  141. );
  142. // Create a view interface on the rendertarget to use on bind.
  143. DX::ThrowIfFailed(
  144. m_d3dDevice->CreateRenderTargetView(
  145. backBuffer.Get(),
  146. nullptr,
  147. &m_renderTargetView
  148. )
  149. );
  150. // Cache the rendertarget dimensions in our helper class for convenient use.
  151. D3D11_TEXTURE2D_DESC backBufferDesc;
  152. backBuffer->GetDesc(&backBufferDesc);
  153. m_renderTargetSize.Width = static_cast<float>(backBufferDesc.Width);
  154. m_renderTargetSize.Height = static_cast<float>(backBufferDesc.Height);
  155. // Create a descriptor for the depth/stencil buffer.
  156. CD3D11_TEXTURE2D_DESC depthStencilDesc(
  157. DXGI_FORMAT_D24_UNORM_S8_UINT,
  158. backBufferDesc.Width,
  159. backBufferDesc.Height,
  160. 1,
  161. 1,
  162. D3D11_BIND_DEPTH_STENCIL);
  163. // Allocate a 2-D surface as the depth/stencil buffer.
  164. ComPtr<ID3D11Texture2D> depthStencil;
  165. DX::ThrowIfFailed(
  166. m_d3dDevice->CreateTexture2D(
  167. &depthStencilDesc,
  168. nullptr,
  169. &depthStencil
  170. )
  171. );
  172. // Create a DepthStencil view on this surface to use on bind.
  173. DX::ThrowIfFailed(
  174. m_d3dDevice->CreateDepthStencilView(
  175. depthStencil.Get(),
  176. &CD3D11_DEPTH_STENCIL_VIEW_DESC(D3D11_DSV_DIMENSION_TEXTURE2D),
  177. &m_depthStencilView
  178. )
  179. );
  180. // Create a viewport descriptor of the full window size.
  181. CD3D11_VIEWPORT viewPort(
  182. 0.0f,
  183. 0.0f,
  184. static_cast<float>(backBufferDesc.Width),
  185. static_cast<float>(backBufferDesc.Height)
  186. );
  187. // Set the current viewport using the descriptor.
  188. m_d3dContext->RSSetViewports(1, &viewPort);
  189. }
  190. void Direct3DBase::UpdateForWindowSizeChange()
  191. {
  192. if (m_window->Bounds.Width != m_windowBounds.Width ||
  193. m_window->Bounds.Height != m_windowBounds.Height)
  194. {
  195. m_renderTargetView = nullptr;
  196. m_depthStencilView = nullptr;
  197. CreateWindowSizeDependentResources();
  198. }
  199. }
  200. void Direct3DBase::Present()
  201. {
  202. // The first argument instructs DXGI to block until VSync, putting the application
  203. // to sleep until the next VSync. This ensures we don't waste any cycles rendering
  204. // frames that will never be displayed to the screen.
  205. HRESULT hr = m_swapChain->Present(1, 0);
  206. // If the device was removed either by a disconnect or a driver upgrade, we
  207. // must completely reinitialize the renderer.
  208. if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
  209. {
  210. Initialize(m_window.Get());
  211. }
  212. else
  213. {
  214. DX::ThrowIfFailed(hr);
  215. }
  216. }