123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334 |
- #include "pch.h"
- #include "Direct3DBase.h"
- using namespace DirectX;
- using namespace Microsoft::WRL;
- using namespace Windows::UI::Core;
- using namespace Windows::Foundation;
- using namespace Windows::Graphics::Display;
- // Constructor.
- Direct3DBase::Direct3DBase()
- {
- }
- // Initialize the Direct3D resources required to run.
- void Direct3DBase::Initialize(CoreWindow ^ window)
- {
- m_window = window;
- CreateDeviceResources();
- CreateWindowSizeDependentResources();
- }
- // Recreate all device resources and set them back to the current state.
- void Direct3DBase::HandleDeviceLost()
- {
- // Reset these member variables to ensure that UpdateForWindowSizeChange
- // recreates all resources.
- m_windowBounds.Width = 0;
- m_windowBounds.Height = 0;
- m_swapChain = nullptr;
- CreateDeviceResources();
- UpdateForWindowSizeChange();
- }
- // These are the resources that depend on the device.
- void Direct3DBase::CreateDeviceResources()
- {
- // This flag adds support for surfaces with a different color channel
- // ordering
- // than the API default. It is required for compatibility with Direct2D.
- UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
- #if defined(_DEBUG)
- // If the project is in a debug build, enable debugging via SDK Layers with
- // this flag.
- creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
- #endif
- // This array defines the set of DirectX hardware feature levels this app
- // will support.
- // Note the ordering should be preserved.
- // Don't forget to declare your application's minimum required feature level
- // in its
- // description. All applications are assumed to support 9.1 unless otherwise
- // stated.
- D3D_FEATURE_LEVEL featureLevels[] = {
- D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1,
- D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_9_3, D3D_FEATURE_LEVEL_9_2,
- D3D_FEATURE_LEVEL_9_1
- };
- // Create the Direct3D 11 API device object and a corresponding context.
- ComPtr<ID3D11Device> device;
- ComPtr<ID3D11DeviceContext> context;
- DX::ThrowIfFailed(D3D11CreateDevice(
- nullptr, // Specify nullptr to use the default adapter.
- D3D_DRIVER_TYPE_HARDWARE, nullptr,
- creationFlags, // Set set debug and Direct2D compatibility flags.
- featureLevels, // List of feature levels this app can support.
- ARRAYSIZE(featureLevels),
- D3D11_SDK_VERSION, // Always set this to D3D11_SDK_VERSION for Windows
- // Store apps.
- &device, // Returns the Direct3D device created.
- &m_featureLevel, // Returns feature level of device created.
- &context // Returns the device immediate context.
- ));
- // Get the Direct3D 11.1 API device and context interfaces.
- DX::ThrowIfFailed(device.As(&m_d3dDevice));
- DX::ThrowIfFailed(context.As(&m_d3dContext));
- }
- // Allocate all memory resources that change on a window SizeChanged event.
- void Direct3DBase::CreateWindowSizeDependentResources()
- {
- // Store the window bounds so the next time we get a SizeChanged event we can
- // avoid rebuilding everything if the size is identical.
- m_windowBounds = m_window->Bounds;
- // Calculate the necessary swap chain and render target size in pixels.
- float windowWidth = ConvertDipsToPixels(m_windowBounds.Width);
- float windowHeight = ConvertDipsToPixels(m_windowBounds.Height);
- // The width and height of the swap chain must be based on the window's
- // landscape-oriented width and height. If the window is in a portrait
- // orientation, the dimensions must be reversed.
- #if WINVER > 0x0602
- m_orientation = DisplayInformation::GetForCurrentView()->CurrentOrientation;
- #else
- #if PHONE
- // WP8 doesn't support rotations so always make it landscape
- m_orientation = DisplayOrientations::Landscape;
- #else
- m_orientation = DisplayProperties::CurrentOrientation;
- #endif
- #endif
- bool swapDimensions = m_orientation == DisplayOrientations::Portrait ||
- m_orientation == DisplayOrientations::PortraitFlipped;
- m_renderTargetSize.Width = swapDimensions ? windowHeight : windowWidth;
- m_renderTargetSize.Height = swapDimensions ? windowWidth : windowHeight;
- if (m_swapChain != nullptr) {
- // If the swap chain already exists, resize it.
- DX::ThrowIfFailed(
- m_swapChain->ResizeBuffers(2, // Double-buffered swap chain.
- static_cast<UINT>(m_renderTargetSize.Width),
- static_cast<UINT>(m_renderTargetSize.Height),
- DXGI_FORMAT_B8G8R8A8_UNORM, 0));
- } else {
- // Otherwise, create a new one using the same adapter as the existing
- // Direct3D device.
- DXGI_SWAP_CHAIN_DESC1 swapChainDesc = { 0 };
- swapChainDesc.Width = static_cast<UINT>(
- m_renderTargetSize.Width); // Match the size of the window.
- swapChainDesc.Height = static_cast<UINT>(m_renderTargetSize.Height);
- swapChainDesc.Format =
- DXGI_FORMAT_B8G8R8A8_UNORM; // This is the most common swap chain format.
- swapChainDesc.Stereo = false;
- swapChainDesc.SampleDesc.Count = 1; // Don't use multi-sampling.
- swapChainDesc.SampleDesc.Quality = 0;
- swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
- #if PHONE && WINVER <= 0x0602
- swapChainDesc.BufferCount = 1; // Use double-buffering to minimize latency.
- swapChainDesc.Scaling = DXGI_SCALING_STRETCH; // On phone, only stretch and
- // aspect-ratio stretch
- // scaling are allowed.
- swapChainDesc.SwapEffect =
- DXGI_SWAP_EFFECT_DISCARD; // On phone, no swap effects are supported.
- #else
- swapChainDesc.BufferCount = 2; // Use double-buffering to minimize latency.
- swapChainDesc.Scaling = DXGI_SCALING_NONE;
- swapChainDesc.SwapEffect =
- DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // All Windows Store apps must use this
- // SwapEffect.
- #endif
- swapChainDesc.Flags = 0;
- ComPtr<IDXGIDevice1> dxgiDevice;
- DX::ThrowIfFailed(m_d3dDevice.As(&dxgiDevice));
- ComPtr<IDXGIAdapter> dxgiAdapter;
- DX::ThrowIfFailed(dxgiDevice->GetAdapter(&dxgiAdapter));
- ComPtr<IDXGIFactory2> dxgiFactory;
- DX::ThrowIfFailed(
- dxgiAdapter->GetParent(__uuidof(IDXGIFactory2), &dxgiFactory));
- Windows::UI::Core::CoreWindow ^ window = m_window.Get();
- DX::ThrowIfFailed(dxgiFactory->CreateSwapChainForCoreWindow(
- m_d3dDevice.Get(), reinterpret_cast<IUnknown*>(window), &swapChainDesc,
- nullptr, // Allow on all displays.
- &m_swapChain));
- // Ensure that DXGI does not queue more than one frame at a time. This both
- // reduces latency and
- // ensures that the application will only render after each VSync,
- // minimizing power consumption.
- DX::ThrowIfFailed(dxgiDevice->SetMaximumFrameLatency(1));
- }
- // Set the proper orientation for the swap chain, and generate the
- // 3D matrix transformation for rendering to the rotated swap chain.
- DXGI_MODE_ROTATION rotation = DXGI_MODE_ROTATION_UNSPECIFIED;
- switch (m_orientation) {
- case DisplayOrientations::Landscape:
- rotation = DXGI_MODE_ROTATION_IDENTITY;
- m_orientationTransform3D = XMFLOAT4X4( // 0-degree Z-rotation
- 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
- 0.0f, 0.0f, 0.0f, 1.0f);
- break;
- case DisplayOrientations::Portrait:
- rotation = DXGI_MODE_ROTATION_ROTATE270;
- m_orientationTransform3D = XMFLOAT4X4( // 90-degree Z-rotation
- 0.0f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
- 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
- break;
- case DisplayOrientations::LandscapeFlipped:
- rotation = DXGI_MODE_ROTATION_ROTATE180;
- m_orientationTransform3D = XMFLOAT4X4( // 180-degree Z-rotation
- -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
- 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
- break;
- case DisplayOrientations::PortraitFlipped:
- rotation = DXGI_MODE_ROTATION_ROTATE90;
- m_orientationTransform3D = XMFLOAT4X4( // 270-degree Z-rotation
- 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
- 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
- break;
- default:
- throw ref new Platform::FailureException();
- }
- #if !PHONE || WINVER > 0x0602
- DX::ThrowIfFailed(m_swapChain->SetRotation(rotation));
- #endif // !PHONE
- // Create a render target view of the swap chain back buffer.
- ComPtr<ID3D11Texture2D> backBuffer;
- DX::ThrowIfFailed(
- m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), &backBuffer));
- DX::ThrowIfFailed(m_d3dDevice->CreateRenderTargetView(
- backBuffer.Get(), nullptr, &m_renderTargetView));
- // Create a depth stencil view.
- CD3D11_TEXTURE2D_DESC depthStencilDesc(
- DXGI_FORMAT_D24_UNORM_S8_UINT, static_cast<UINT>(m_renderTargetSize.Width),
- static_cast<UINT>(m_renderTargetSize.Height), 1, 1,
- D3D11_BIND_DEPTH_STENCIL);
- ComPtr<ID3D11Texture2D> depthStencil;
- DX::ThrowIfFailed(
- m_d3dDevice->CreateTexture2D(&depthStencilDesc, nullptr, &depthStencil));
- CD3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc(
- D3D11_DSV_DIMENSION_TEXTURE2D);
- DX::ThrowIfFailed(m_d3dDevice->CreateDepthStencilView(
- depthStencil.Get(), &depthStencilViewDesc, &m_depthStencilView));
- // Set the rendering viewport to target the entire window.
- CD3D11_VIEWPORT viewport(0.0f, 0.0f, m_renderTargetSize.Width,
- m_renderTargetSize.Height);
- m_d3dContext->RSSetViewports(1, &viewport);
- }
- // This method is called in the event handler for the SizeChanged event.
- void Direct3DBase::UpdateForWindowSizeChange()
- {
- if (m_window->Bounds.Width != m_windowBounds.Width ||
- m_window->Bounds.Height != m_windowBounds.Height ||
- #if WINVER > 0x0602
- m_orientation !=
- DisplayInformation::GetForCurrentView()->CurrentOrientation)
- #else
- m_orientation != DisplayProperties::CurrentOrientation)
- #endif
- {
- ID3D11RenderTargetView* nullViews[] = { nullptr };
- m_d3dContext->OMSetRenderTargets(ARRAYSIZE(nullViews), nullViews, nullptr);
- m_renderTargetView = nullptr;
- m_depthStencilView = nullptr;
- m_d3dContext->Flush();
- CreateWindowSizeDependentResources();
- }
- }
- void Direct3DBase::ReleaseResourcesForSuspending()
- {
- // Phone applications operate in a memory-constrained environment, so when
- // entering
- // the background it is a good idea to free memory-intensive objects that
- // will be
- // easy to restore upon reactivation. The swapchain and backbuffer are good
- // candidates
- // here, as they consume a large amount of memory and can be reinitialized
- // quickly.
- m_swapChain = nullptr;
- m_renderTargetView = nullptr;
- m_depthStencilView = nullptr;
- }
- // Method to deliver the final image to the display.
- void Direct3DBase::Present()
- {
- // The first argument instructs DXGI to block until VSync, putting the
- // application
- // to sleep until the next VSync. This ensures we don't waste any cycles
- // rendering
- // frames that will never be displayed to the screen.
- #if PHONE && WINVER <= 0x0602
- HRESULT hr = m_swapChain->Present(1, 0);
- #else
- // The application may optionally specify "dirty" or "scroll"
- // rects to improve efficiency in certain scenarios.
- DXGI_PRESENT_PARAMETERS parameters = { 0 };
- parameters.DirtyRectsCount = 0;
- parameters.pDirtyRects = nullptr;
- parameters.pScrollRect = nullptr;
- parameters.pScrollOffset = nullptr;
- HRESULT hr = m_swapChain->Present1(1, 0, ¶meters);
- #endif
- // Discard the contents of the render target.
- // This is a valid operation only when the existing contents will be entirely
- // overwritten. If dirty or scroll rects are used, this call should be
- // removed.
- m_d3dContext->DiscardView(m_renderTargetView.Get());
- // Discard the contents of the depth stencil.
- m_d3dContext->DiscardView(m_depthStencilView.Get());
- // If the device was removed either by a disconnect or a driver upgrade, we
- // must recreate all device resources.
- if (hr == DXGI_ERROR_DEVICE_REMOVED) {
- HandleDeviceLost();
- } else {
- DX::ThrowIfFailed(hr);
- }
- }
- // Method to convert a length in device-independent pixels (DIPs) to a length
- // in physical pixels.
- float Direct3DBase::ConvertDipsToPixels(float dips)
- {
- static const float dipsPerInch = 96.0f;
- #if WINVER > 0x0602
- return floor(dips * DisplayInformation::GetForCurrentView()->LogicalDpi /
- dipsPerInch +
- 0.5f); // Round to nearest integer.
- #else
- return floor(dips * DisplayProperties::LogicalDpi / dipsPerInch +
- 0.5f); // Round to nearest integer.
- #endif
- }
|