Direct3DBase.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. /*
  2. * Copyright (c) 2014, Oculus VR, Inc.
  3. * All rights reserved.
  4. *
  5. * This source code is licensed under the BSD-style license found in the
  6. * LICENSE file in the root directory of this source tree. An additional grant
  7. * of patent rights can be found in the PATENTS file in the same directory.
  8. *
  9. */
  10. #include "pch.h"
  11. #include "Direct3DBase.h"
  12. using namespace DirectX;
  13. using namespace Microsoft::WRL;
  14. using namespace Windows::UI::Core;
  15. using namespace Windows::Foundation;
  16. using namespace Windows::Graphics::Display;
  17. // Constructor.
  18. Direct3DBase::Direct3DBase()
  19. {
  20. }
  21. // Initialize the Direct3D resources required to run.
  22. void Direct3DBase::Initialize(CoreWindow^ window)
  23. {
  24. m_window = window;
  25. CreateDeviceResources();
  26. CreateWindowSizeDependentResources();
  27. }
  28. // Recreate all device resources and set them back to the current state.
  29. void Direct3DBase::HandleDeviceLost()
  30. {
  31. // Reset these member variables to ensure that UpdateForWindowSizeChange recreates all resources.
  32. m_windowBounds.Width = 0;
  33. m_windowBounds.Height = 0;
  34. m_swapChain = nullptr;
  35. CreateDeviceResources();
  36. UpdateForWindowSizeChange();
  37. }
  38. // These are the resources that depend on the device.
  39. void Direct3DBase::CreateDeviceResources()
  40. {
  41. // This flag adds support for surfaces with a different color channel ordering
  42. // than the API default. It is required for compatibility with Direct2D.
  43. UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
  44. #if defined(_DEBUG)
  45. // If the project is in a debug build, enable debugging via SDK Layers with this flag.
  46. creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
  47. #endif
  48. // This array defines the set of DirectX hardware feature levels this app will support.
  49. // Note the ordering should be preserved.
  50. // Don't forget to declare your application's minimum required feature level in its
  51. // description. All applications are assumed to support 9.1 unless otherwise stated.
  52. D3D_FEATURE_LEVEL featureLevels[] =
  53. {
  54. D3D_FEATURE_LEVEL_11_1,
  55. D3D_FEATURE_LEVEL_11_0,
  56. D3D_FEATURE_LEVEL_10_1,
  57. D3D_FEATURE_LEVEL_10_0,
  58. D3D_FEATURE_LEVEL_9_3
  59. };
  60. // Create the Direct3D 11 API device object and a corresponding context.
  61. ComPtr<ID3D11Device> device;
  62. ComPtr<ID3D11DeviceContext> context;
  63. DX::ThrowIfFailed(
  64. D3D11CreateDevice(
  65. nullptr, // Specify nullptr to use the default adapter.
  66. D3D_DRIVER_TYPE_HARDWARE,
  67. nullptr,
  68. creationFlags, // Set set debug and Direct2D compatibility flags.
  69. featureLevels, // List of feature levels this app can support.
  70. ARRAYSIZE(featureLevels),
  71. D3D11_SDK_VERSION, // Always set this to D3D11_SDK_VERSION.
  72. &device, // Returns the Direct3D device created.
  73. &m_featureLevel, // Returns feature level of device created.
  74. &context // Returns the device immediate context.
  75. )
  76. );
  77. // Get the Direct3D 11.1 API device and context interfaces.
  78. DX::ThrowIfFailed(
  79. device.As(&m_d3dDevice)
  80. );
  81. DX::ThrowIfFailed(
  82. context.As(&m_d3dContext)
  83. );
  84. }
  85. // Allocate all memory resources that depend on the window size.
  86. void Direct3DBase::CreateWindowSizeDependentResources()
  87. {
  88. m_windowBounds = m_window->Bounds;
  89. // Calculate the necessary swap chain and render target size in pixels.
  90. m_renderTargetSize.Width = ConvertDipsToPixels(m_windowBounds.Width);
  91. m_renderTargetSize.Height = ConvertDipsToPixels(m_windowBounds.Height);
  92. DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0};
  93. swapChainDesc.Width = static_cast<UINT>(m_renderTargetSize.Width); // Match the size of the window.
  94. swapChainDesc.Height = static_cast<UINT>(m_renderTargetSize.Height);
  95. swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // This is the most common swap chain format.
  96. swapChainDesc.Stereo = false;
  97. swapChainDesc.SampleDesc.Count = 1; // Don't use multi-sampling.
  98. swapChainDesc.SampleDesc.Quality = 0;
  99. swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
  100. swapChainDesc.BufferCount = 1; // On phone, only single buffering is supported.
  101. swapChainDesc.Scaling = DXGI_SCALING_STRETCH; // On phone, only stretch and aspect-ratio stretch scaling are allowed.
  102. swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; // On phone, no swap effects are supported.
  103. swapChainDesc.Flags = 0;
  104. ComPtr<IDXGIDevice1> dxgiDevice;
  105. DX::ThrowIfFailed(
  106. m_d3dDevice.As(&dxgiDevice)
  107. );
  108. ComPtr<IDXGIAdapter> dxgiAdapter;
  109. DX::ThrowIfFailed(
  110. dxgiDevice->GetAdapter(&dxgiAdapter)
  111. );
  112. ComPtr<IDXGIFactory2> dxgiFactory;
  113. DX::ThrowIfFailed(
  114. dxgiAdapter->GetParent(
  115. __uuidof(IDXGIFactory2),
  116. &dxgiFactory
  117. )
  118. );
  119. Windows::UI::Core::CoreWindow^ window = m_window.Get();
  120. DX::ThrowIfFailed(
  121. dxgiFactory->CreateSwapChainForCoreWindow(
  122. m_d3dDevice.Get(),
  123. reinterpret_cast<IUnknown*>(window),
  124. &swapChainDesc,
  125. nullptr, // Allow on all displays.
  126. &m_swapChain
  127. )
  128. );
  129. // Ensure that DXGI does not queue more than one frame at a time. This both reduces latency and
  130. // ensures that the application will only render after each VSync, minimizing power consumption.
  131. DX::ThrowIfFailed(
  132. dxgiDevice->SetMaximumFrameLatency(1)
  133. );
  134. // Create a render target view of the swap chain back buffer.
  135. ComPtr<ID3D11Texture2D> backBuffer;
  136. DX::ThrowIfFailed(
  137. m_swapChain->GetBuffer(
  138. 0,
  139. __uuidof(ID3D11Texture2D),
  140. &backBuffer
  141. )
  142. );
  143. DX::ThrowIfFailed(
  144. m_d3dDevice->CreateRenderTargetView(
  145. backBuffer.Get(),
  146. nullptr,
  147. &m_renderTargetView
  148. )
  149. );
  150. // Create a depth stencil view.
  151. CD3D11_TEXTURE2D_DESC depthStencilDesc(
  152. DXGI_FORMAT_D24_UNORM_S8_UINT,
  153. static_cast<UINT>(m_renderTargetSize.Width),
  154. static_cast<UINT>(m_renderTargetSize.Height),
  155. 1,
  156. 1,
  157. D3D11_BIND_DEPTH_STENCIL
  158. );
  159. ComPtr<ID3D11Texture2D> depthStencil;
  160. DX::ThrowIfFailed(
  161. m_d3dDevice->CreateTexture2D(
  162. &depthStencilDesc,
  163. nullptr,
  164. &depthStencil
  165. )
  166. );
  167. CD3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc(D3D11_DSV_DIMENSION_TEXTURE2D);
  168. DX::ThrowIfFailed(
  169. m_d3dDevice->CreateDepthStencilView(
  170. depthStencil.Get(),
  171. &depthStencilViewDesc,
  172. &m_depthStencilView
  173. )
  174. );
  175. // Set the rendering viewport to target the entire window.
  176. CD3D11_VIEWPORT viewport(
  177. 0.0f,
  178. 0.0f,
  179. m_renderTargetSize.Width,
  180. m_renderTargetSize.Height
  181. );
  182. m_d3dContext->RSSetViewports(1, &viewport);
  183. }
  184. // This method is called in the event handler for the SizeChanged event.
  185. void Direct3DBase::UpdateForWindowSizeChange()
  186. {
  187. if (m_window->Bounds.Width != m_windowBounds.Width ||
  188. m_window->Bounds.Height != m_windowBounds.Height)
  189. {
  190. ID3D11RenderTargetView* nullViews[] = {nullptr};
  191. m_d3dContext->OMSetRenderTargets(ARRAYSIZE(nullViews), nullViews, nullptr);
  192. m_renderTargetView = nullptr;
  193. m_depthStencilView = nullptr;
  194. m_d3dContext->Flush();
  195. CreateWindowSizeDependentResources();
  196. }
  197. }
  198. void Direct3DBase::ReleaseResourcesForSuspending()
  199. {
  200. // Phone applications operate in a memory-constrained environment, so when entering
  201. // the background it is a good idea to free memory-intensive objects that will be
  202. // easy to restore upon reactivation. The swapchain and backbuffer are good candidates
  203. // here, as they consume a large amount of memory and can be reinitialized quickly.
  204. m_swapChain = nullptr;
  205. m_renderTargetView = nullptr;
  206. m_depthStencilView = nullptr;
  207. }
  208. // Method to deliver the final image to the display.
  209. void Direct3DBase::Present()
  210. {
  211. // The first argument instructs DXGI to block until VSync, putting the application
  212. // to sleep until the next VSync. This ensures we don't waste any cycles rendering
  213. // frames that will never be displayed to the screen.
  214. HRESULT hr = m_swapChain->Present(1, 0);
  215. // Discard the contents of the render target.
  216. // This is a valid operation only when the existing contents will be entirely
  217. // overwritten. If dirty or scroll rects are used, this call should be removed.
  218. m_d3dContext->DiscardView(m_renderTargetView.Get());
  219. // Discard the contents of the depth stencil.
  220. m_d3dContext->DiscardView(m_depthStencilView.Get());
  221. // If the device was removed either by a disconnect or a driver upgrade, we
  222. // must recreate all device resources.
  223. if (hr == DXGI_ERROR_DEVICE_REMOVED)
  224. {
  225. HandleDeviceLost();
  226. }
  227. else
  228. {
  229. DX::ThrowIfFailed(hr);
  230. }
  231. }
  232. // Method to convert a length in device-independent pixels (DIPs) to a length in physical pixels.
  233. float Direct3DBase::ConvertDipsToPixels(float dips)
  234. {
  235. static const float dipsPerInch = 96.0f;
  236. return floor(dips * DisplayProperties::LogicalDpi / dipsPerInch + 0.5f); // Round to nearest integer.
  237. }
粤ICP备19079148号