1 //// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
2 //// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
3 //// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
4 //// PARTICULAR PURPOSE.
6 //// Copyright (c) Microsoft Corporation. All rights reserved
9 #include "DirectXBase.h"
11 using namespace Windows::UI::Core;
12 using namespace Windows::Foundation;
13 using namespace Microsoft::WRL;
17 DirectXBase::DirectXBase() :
22 // Initialize the Direct3D resources required to run.
23 void DirectXBase::Initialize(CoreWindow^ window, float dpi)
27 CreateDeviceIndependentResources();
28 CreateDeviceResources();
32 // These are the resources required independent of hardware.
33 void DirectXBase::CreateDeviceIndependentResources()
35 D2D1_FACTORY_OPTIONS options;
36 ZeroMemory(&options, sizeof(D2D1_FACTORY_OPTIONS));
39 // If the project is in a debug build, enable Direct2D debugging via SDK Layers
40 options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION;
45 D2D1_FACTORY_TYPE_SINGLE_THREADED,
46 __uuidof(ID2D1Factory1),
54 DWRITE_FACTORY_TYPE_SHARED,
55 __uuidof(IDWriteFactory),
62 CLSID_WICImagingFactory,
65 IID_PPV_ARGS(&m_wicFactory)
70 // These are the resources that depend on the device.
71 void DirectXBase::CreateDeviceResources()
73 // This flag adds support for surfaces with a different color channel ordering than the API default.
74 // It is recommended usage, and is required for compatibility with Direct2D.
75 UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
76 ComPtr<IDXGIDevice> dxgiDevice;
79 // If the project is in a debug build, enable debugging via SDK Layers with this flag.
80 creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
83 // This array defines the set of DirectX hardware feature levels this app will support.
84 // Note the ordering should be preserved.
85 // Don't forget to declare your application's minimum required feature level in its
86 // description. All applications are assumed to support 9.1 unless otherwise stated.
87 D3D_FEATURE_LEVEL featureLevels[] =
89 D3D_FEATURE_LEVEL_11_1,
90 D3D_FEATURE_LEVEL_11_0,
91 D3D_FEATURE_LEVEL_10_1,
92 D3D_FEATURE_LEVEL_10_0,
93 D3D_FEATURE_LEVEL_9_3,
94 D3D_FEATURE_LEVEL_9_2,
98 // Create the DX11 API device object, and get a corresponding context.
99 ComPtr<ID3D11Device> device;
100 ComPtr<ID3D11DeviceContext> context;
103 nullptr, // specify null to use the default adapter
104 D3D_DRIVER_TYPE_HARDWARE,
105 0, // leave as 0 unless software device
106 creationFlags, // optionally set debug and Direct2D compatibility flags
107 featureLevels, // list of feature levels this app can support
108 ARRAYSIZE(featureLevels), // number of entries in above list
109 D3D11_SDK_VERSION, // always set this to D3D11_SDK_VERSION for Metro style apps
110 &device, // returns the Direct3D device created
111 &m_featureLevel, // returns feature level of device created
112 &context // returns the device immediate context
116 // Get the DirectX11.1 device by QI off the DirectX11 one.
118 device.As(&m_d3dDevice)
121 // And get the corresponding device context in the same way.
123 context.As(&m_d3dContext)
126 // Obtain the underlying DXGI device of the Direct3D11.1 device.
128 m_d3dDevice.As(&dxgiDevice)
131 // Obtain the Direct2D device for 2-D rendering.
133 m_d2dFactory->CreateDevice(dxgiDevice.Get(), &m_d2dDevice)
136 // And get its corresponding device context object.
138 m_d2dDevice->CreateDeviceContext(
139 D2D1_DEVICE_CONTEXT_OPTIONS_NONE,
144 // Release the swap chain (if it exists) as it will be incompatible with
146 m_swapChain = nullptr;
149 // Helps track the DPI in the helper class.
150 // This is called in the dpiChanged event handler in the view class.
151 void DirectXBase::SetDpi(float dpi)
155 // Save the DPI of this display in our class.
158 // Update Direct2D's stored DPI.
159 m_d2dContext->SetDpi(m_dpi, m_dpi);
161 // Often a DPI change implies a window size change. In some cases Windows will issues
162 // both a size changed event and a DPI changed event. In this case, the resulting bounds
163 // will not change, and the window resize code will only be executed once.
164 UpdateForWindowSizeChange();
168 // This routine is called in the event handler for the view SizeChanged event.
169 void DirectXBase::UpdateForWindowSizeChange()
171 if (m_window->Bounds.Width != m_windowBounds.Width ||
172 m_window->Bounds.Height != m_windowBounds.Height)
174 m_d2dContext->SetTarget(nullptr);
175 m_d2dTargetBitmap = nullptr;
176 m_renderTargetView = nullptr;
177 m_depthStencilView = nullptr;
178 CreateWindowSizeDependentResources();
182 // Allocate all memory resources that change on a window SizeChanged event.
183 void DirectXBase::CreateWindowSizeDependentResources()
185 // Store the window bounds so the next time we get a SizeChanged event we can
186 // avoid rebuilding everything if the size is identical.
187 m_windowBounds = m_window->Bounds;
189 // If the swap chain already exists, resize it.
190 if(m_swapChain != nullptr)
193 m_swapChain->ResizeBuffers(2, 0, 0, DXGI_FORMAT_B8G8R8A8_UNORM, 0)
196 // Otherwise, create a new one.
199 // Allocate a descriptor.
200 DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0};
201 swapChainDesc.Width = 0; // use automatic sizing
202 swapChainDesc.Height = 0;
203 swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // this is the most common swapchain format
204 swapChainDesc.Stereo = false;
205 swapChainDesc.SampleDesc.Count = 1; // don't use multi-sampling
206 swapChainDesc.SampleDesc.Quality = 0;
207 swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
208 swapChainDesc.BufferCount = 2; // use double buffering to enable flip
209 swapChainDesc.Scaling = DXGI_SCALING_NONE;
210 swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // all Metro style apps must use this SwapEffect
211 swapChainDesc.Flags = 0;
213 // Once the desired swap chain description is configured, it must be created on the same adapter as our D3D Device
215 // First, retrieve the underlying DXGI Device from the D3D Device.
216 ComPtr<IDXGIDevice1> dxgiDevice;
218 m_d3dDevice.As(&dxgiDevice)
221 // Identify the physical adapter (GPU or card) this device is running on.
222 ComPtr<IDXGIAdapter> dxgiAdapter;
224 dxgiDevice->GetAdapter(&dxgiAdapter)
227 // And obtain the factory object that created it.
228 ComPtr<IDXGIFactory2> dxgiFactory;
230 dxgiAdapter->GetParent(IID_PPV_ARGS(&dxgiFactory))
233 // Obtain the final swap chain for this window from the DXGI factory.
235 dxgiFactory->CreateSwapChainForCoreWindow(
237 reinterpret_cast<IUnknown*>(m_window),
239 nullptr, // allow on all displays
244 // Ensure that DXGI does not queue more than one frame at a time. This both reduces
245 // latency and ensures that the application will only render after each VSync, minimizing
246 // power consumption.
248 dxgiDevice->SetMaximumFrameLatency(1)
253 // Obtain the backbuffer for this window which will be the final 3D rendertarget.
254 ComPtr<ID3D11Texture2D> backBuffer;
256 m_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer))
259 // Create a view interface on the rendertarget to use on bind.
261 m_d3dDevice->CreateRenderTargetView(
268 // Cache the rendertarget dimensions in our helper class for convenient use.
269 D3D11_TEXTURE2D_DESC backBufferDesc = {0};
270 backBuffer->GetDesc(&backBufferDesc);
271 m_renderTargetSize.Width = static_cast<float>(backBufferDesc.Width);
272 m_renderTargetSize.Height = static_cast<float>(backBufferDesc.Height);
274 // Create a descriptor for the depth/stencil buffer.
275 CD3D11_TEXTURE2D_DESC depthStencilDesc(
276 DXGI_FORMAT_D24_UNORM_S8_UINT,
277 backBufferDesc.Width,
278 backBufferDesc.Height,
281 D3D11_BIND_DEPTH_STENCIL
284 // Allocate a 2-D surface as the depth/stencil buffer.
285 ComPtr<ID3D11Texture2D> depthStencil;
287 m_d3dDevice->CreateTexture2D(
294 // Create a DepthStencil view on this surface to use on bind.
296 m_d3dDevice->CreateDepthStencilView(
298 &CD3D11_DEPTH_STENCIL_VIEW_DESC(D3D11_DSV_DIMENSION_TEXTURE2D),
303 // Create a viewport descriptor of the full window size.
304 CD3D11_VIEWPORT viewport(
307 static_cast<float>(backBufferDesc.Width),
308 static_cast<float>(backBufferDesc.Height)
311 // Set the current viewport using the descriptor.
312 m_d3dContext->RSSetViewports(1, &viewport);
314 // Now we set up the Direct2D render target bitmap linked to the swapchain.
315 // Whenever we render to this bitmap, it will be directly rendered to the
316 // swapchain associated with the window.
317 D2D1_BITMAP_PROPERTIES1 bitmapProperties =
319 D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
320 PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED),
325 // Direct2D needs the dxgi version of the backbuffer surface pointer.
326 ComPtr<IDXGISurface> dxgiBackBuffer;
328 m_swapChain->GetBuffer(0, IID_PPV_ARGS(&dxgiBackBuffer))
331 // Get a D2D surface from the DXGI back buffer to use as the D2D render target.
333 m_d2dContext->CreateBitmapFromDxgiSurface(
334 dxgiBackBuffer.Get(),
340 // So now we can set the Direct2D render target.
341 m_d2dContext->SetTarget(m_d2dTargetBitmap.Get());
343 // Set D2D text anti-alias mode to Grayscale to ensure proper rendering of text on intermediate surfaces.
344 m_d2dContext->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE);
347 // Method to deliver the final image to the display.
348 void DirectXBase::Present()
350 // The application may optionally specify "dirty" or "scroll" rects to improve efficiency
351 // in certain scenarios. In this sample, however, we do not utilize those features.
352 DXGI_PRESENT_PARAMETERS parameters = {0};
353 parameters.DirtyRectsCount = 0;
354 parameters.pDirtyRects = nullptr;
355 parameters.pScrollRect = nullptr;
356 parameters.pScrollOffset = nullptr;
358 // The first argument instructs DXGI to block until VSync, putting the application
359 // to sleep until the next VSync. This ensures we don't waste any cycles rendering
360 // frames that will never be displayed to the screen.
361 HRESULT hr = m_swapChain->Present1(1, 0, ¶meters);
363 // If the device was removed either by a disconnect or a driver upgrade, we
364 // must completely reinitialize the renderer.
365 if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
367 Initialize(m_window, m_dpi);
371 DX::ThrowIfFailed(hr);