Complete code for a DirectX Windows Store app framework
[ This article is for Windows 8.x and Windows Phone 8.x developers writing Windows Runtime apps. If you’re developing for Windows 10, see the latest documentation ]
This topic provides the complete code sample used in the tutorial How to set up your DirectX Windows Store app to display a view.
This code assumes that you are using Microsoft Visual Studio 2013, and that you have created a Direct3D project.
This topic contains these sections:
- Technologies
- Requirements
- View the code (C++)
Download location
This sample is not available for download.
Technologies
Programming languages | C++ |
Programming models | Windows Runtime |
Requirements
Minimum supported client | Windows 8.1 |
Minimum supported server | Windows Server 2012 R2 |
Minimum required SDK | Visual Studio 2013 |
View the code (C++)
App.h
#pragma once
#include "pch.h"
#include "DeviceResources.h"
#include "MyDirectXAppMain.h"
namespace MyDirectXApp
{
// Main entry point for our app. Connects the app with the Windows shell and handles application lifecycle events.
ref class App sealed : public Windows::ApplicationModel::Core::IFrameworkView
{
public:
App();
// IFrameworkView Methods.
virtual void Initialize(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView);
virtual void SetWindow(Windows::UI::Core::CoreWindow^ window);
virtual void Load(Platform::String^ entryPoint);
virtual void Run();
virtual void Uninitialize();
protected:
// Application lifecycle event handlers.
void OnActivated(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView, Windows::ApplicationModel::Activation::IActivatedEventArgs^ args);
void OnSuspending(Platform::Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ args);
void OnResuming(Platform::Object^ sender, Platform::Object^ args);
// Window event handlers.
void OnWindowSizeChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::WindowSizeChangedEventArgs^ args);
void OnVisibilityChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ args);
void OnWindowClosed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::CoreWindowEventArgs^ args);
// Display properties event handlers.
void OnDpiChanged(Windows::Graphics::Display::DisplayInformation^ sender, Platform::Object^ args);
void OnOrientationChanged(Windows::Graphics::Display::DisplayInformation^ sender, Platform::Object^ args);
void OnDisplayContentsInvalidated(Windows::Graphics::Display::DisplayInformation^ sender, Platform::Object^ args);
private:
std::shared_ptr<DeviceResources> m_deviceResources;
std::unique_ptr<MyDirectXAppMain> m_main;
bool m_windowClosed;
bool m_windowVisible;
};
}
ref class Direct3DApplicationSource sealed : Windows::ApplicationModel::Core::IFrameworkViewSource
{
public:
virtual Windows::ApplicationModel::Core::IFrameworkView^ CreateView();
};
App.cpp
#include "pch.h"
#include "App.h"
#include <ppltasks.h> // For create_task
using namespace MyDirectXApp;
using namespace concurrency;
using namespace Windows::ApplicationModel;
using namespace Windows::ApplicationModel::Core;
using namespace Windows::ApplicationModel::Activation;
using namespace Windows::UI::Core;
using namespace Windows::UI::Input;
using namespace Windows::System;
using namespace Windows::Foundation;
using namespace Windows::Graphics::Display;
// The main function is only used to initialize our IFrameworkView class.
[Platform::MTAThread]
int main(Platform::Array<Platform::String^>^)
{
auto direct3DApplicationSource = ref new Direct3DApplicationSource();
CoreApplication::Run(direct3DApplicationSource);
return 0;
}
IFrameworkView^ Direct3DApplicationSource::CreateView()
{
return ref new App();
}
App::App() :
m_windowClosed(false),
m_windowVisible(true)
{}
// The first method called when the IFrameworkView is being created.
void App::Initialize(CoreApplicationView^ applicationView)
{
// Register event handlers for app lifecycle. This example includes Activated, so that we
// can make the CoreWindow active and start rendering on the window.
applicationView->Activated +=
ref new TypedEventHandler<CoreApplicationView^, IActivatedEventArgs^>(this, &App::OnActivated);
CoreApplication::Suspending +=
ref new EventHandler<SuspendingEventArgs^>(this, &App::OnSuspending);
CoreApplication::Resuming +=
ref new EventHandler<Platform::Object^>(this, &App::OnResuming);
// At this point we have access to the device.
// We can create the device-dependent resources.
m_deviceResources = std::make_shared<DeviceResources>();
}
// Called when the CoreWindow object is created (or re-created).
void App::SetWindow(CoreWindow^ window)
{
window->SizeChanged +=
ref new TypedEventHandler<CoreWindow^, WindowSizeChangedEventArgs^>(this, &App::OnWindowSizeChanged);
window->VisibilityChanged +=
ref new TypedEventHandler<CoreWindow^, VisibilityChangedEventArgs^>(this, &App::OnVisibilityChanged);
window->Closed +=
ref new TypedEventHandler<CoreWindow^, CoreWindowEventArgs^>(this, &App::OnWindowClosed);
DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView();
currentDisplayInformation->DpiChanged +=
ref new TypedEventHandler<DisplayInformation^, Object^>(this, &App::OnDpiChanged);
currentDisplayInformation->OrientationChanged +=
ref new TypedEventHandler<DisplayInformation^, Object^>(this, &App::OnOrientationChanged);
DisplayInformation::DisplayContentsInvalidated +=
ref new TypedEventHandler<DisplayInformation^, Object^>(this, &App::OnDisplayContentsInvalidated);
// Disable all pointer visual feedback for better performance when touching.
auto pointerVisualizationSettings = PointerVisualizationSettings::GetForCurrentView();
pointerVisualizationSettings->IsContactFeedbackEnabled = false;
pointerVisualizationSettings->IsBarrelButtonFeedbackEnabled = false;
m_deviceResources->SetWindow(window);
}
// Initializes scene resources, or loads a previously saved app state.
void App::Load(Platform::String^ entryPoint)
{
m_main = std::unique_ptr<MyDirectXAppMain>(new MyDirectXAppMain(m_deviceResources));
}
// This method is called after the window becomes active.
void App::Run()
{
while (!m_windowClosed)
{
if (m_windowVisible)
{
CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
m_main->Update();
if (m_main->Render())
{
m_deviceResources->Present();
}
}
else
{
CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
}
}
}
// Required for IFrameworkView.
// Terminate events do not cause Uninitialize to be called. It will be called if your IFrameworkView
// class is torn down while the app is in the foreground.
void App::Uninitialize()
{
}
// Application lifecycle event handlers.
void App::OnActivated(CoreApplicationView^ applicationView, IActivatedEventArgs^ args)
{
// Run() won't start until the CoreWindow is activated.
CoreWindow::GetForCurrentThread()->Activate();
}
void App::OnSuspending(Platform::Object^ sender, SuspendingEventArgs^ args)
{
// Save app state asynchronously after requesting a deferral. Holding a deferral
// indicates that the application is busy performing suspending operations. Be
// aware that a deferral may not be held indefinitely. After about five seconds,
// the app will be forced to exit.
SuspendingDeferral^ deferral = args->SuspendingOperation->GetDeferral();
create_task([this, deferral]()
{
m_deviceResources->Trim();
// Insert your code here.
deferral->Complete();
});
}
void App::OnResuming(Platform::Object^ sender, Platform::Object^ args)
{
// Restore any data or state that was unloaded on suspend. By default, data
// and state are persisted when resuming from suspend. Note that this event
// does not occur if the app was previously terminated.
// Insert your code here.
}
// Window event handlers.
void App::OnWindowSizeChanged(CoreWindow^ sender, WindowSizeChangedEventArgs^ args)
{
m_deviceResources->UpdateForWindowSizeChange();
m_main->CreateWindowSizeDependentResources();
}
void App::OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEventArgs^ args)
{
m_windowVisible = args->Visible;
}
void App::OnWindowClosed(CoreWindow^ sender, CoreWindowEventArgs^ args)
{
m_windowClosed = true;
}
// Display properties event handlers.
void App::OnDpiChanged(DisplayInformation^ sender, Object^ args)
{
m_deviceResources->SetDpi(sender->LogicalDpi);
}
void App::OnOrientationChanged(DisplayInformation^ sender, Object^ args)
{
m_deviceResources->UpdateForWindowSizeChange();
m_main->CreateWindowSizeDependentResources();
}
void App::OnDisplayContentsInvalidated(DisplayInformation^ sender, Object^ args)
{
m_deviceResources->ValidateDevice();
}
DeviceResources.h
#pragma once
namespace MyDirectXApp
{
// Provides an interface for an application that owns DeviceResources to be notified of the Device being lost or created
interface IDeviceNotify
{
virtual void OnDeviceLost() = 0;
virtual void OnDeviceRecreated() = 0;
};
// Controls all the DirectX device resources.
class DeviceResources
{
public:
DeviceResources();
void CreateDeviceIndependentResources();
void CreateDeviceResources();
void CreateWindowSizeDependentResources();
void SetWindow(Windows::UI::Core::CoreWindow^ window);
void SetWindow(Windows::UI::Core::CoreWindow^ window, Windows::UI::Xaml::Controls::SwapChainPanel^ panel);
void SetDpi(float dpi);
void UpdateForWindowSizeChange();
void ValidateDevice();
void HandleDeviceLost();
void RegisterDeviceNotify(IDeviceNotify* deviceNotify);
void Trim();
void Present();
// Device Accessors.
Windows::Foundation::Size GetOutputBounds() const { return m_outputSize; }
// D3D Accessors.
ID3D11Device2* GetD3DDevice() const { return m_d3dDevice.Get(); }
ID3D11DeviceContext2* GetD3DDeviceContext() const { return m_d3dContext.Get(); }
IDXGISwapChain1* GetSwapChain() const { return m_swapChain.Get(); }
D3D_FEATURE_LEVEL GetDeviceFeatureLevel() const { return m_d3dFeatureLevel; }
ID3D11RenderTargetView* GetBackBufferRenderTargetView() const { return m_d3dRenderTargetView.Get(); }
ID3D11DepthStencilView* GetDepthStencilView() const { return m_d3dDepthStencilView.Get(); }
D3D11_VIEWPORT GetScreenViewport() const { return m_screenViewport; }
DirectX::XMFLOAT4X4 GetOrientationTransform3D() const { return m_orientationTransform3D; }
// D2D Accessors.
ID2D1Factory2* GetD2DFactory() const { return m_d2dFactory.Get(); }
ID2D1Device1* GetD2DDevice() const { return m_d2dDevice.Get(); }
ID2D1DeviceContext1* GetD2DDeviceContext() const { return m_d2dContext.Get(); }
ID2D1Bitmap1* GetD2DTargetBitmap() const { return m_d2dTargetBitmap.Get(); }
IDWriteFactory2* GetDWriteFactory() const { return m_dwriteFactory.Get(); }
IWICImagingFactory2* GetWicImagingFactory() const { return m_wicFactory.Get(); }
D2D1::Matrix3x2F GetOrientationTransform2D() const { return m_orientationTransform2D; }
private:
DXGI_MODE_ROTATION ComputeDisplayRotation();
// Direct3D objects.
Microsoft::WRL::ComPtr<ID3D11Device2> m_d3dDevice;
Microsoft::WRL::ComPtr<ID3D11DeviceContext2> m_d3dContext;
Microsoft::WRL::ComPtr<IDXGISwapChain1> m_swapChain;
// Direct3D rendering objects. Required for 3D.
Microsoft::WRL::ComPtr<ID3D11RenderTargetView> m_d3dRenderTargetView;
Microsoft::WRL::ComPtr<ID3D11DepthStencilView> m_d3dDepthStencilView;
D3D11_VIEWPORT m_screenViewport;
// Direct2D drawing components.
Microsoft::WRL::ComPtr<ID2D1Factory2> m_d2dFactory;
Microsoft::WRL::ComPtr<ID2D1Device1> m_d2dDevice;
Microsoft::WRL::ComPtr<ID2D1DeviceContext1> m_d2dContext;
Microsoft::WRL::ComPtr<ID2D1Bitmap1> m_d2dTargetBitmap;
// DirectWrite drawing components.
Microsoft::WRL::ComPtr<IDWriteFactory2> m_dwriteFactory;
Microsoft::WRL::ComPtr<IWICImagingFactory2> m_wicFactory;
// Cached reference to the Window.
Platform::Agile<Windows::UI::Core::CoreWindow> m_window;
// Cached reference to the XAML panel (optional).
Windows::UI::Xaml::Controls::SwapChainPanel^ m_swapChainPanel;
// Cached device properties.
D3D_FEATURE_LEVEL m_d3dFeatureLevel;
Windows::Foundation::Size m_d3dRenderTargetSize;
Windows::Foundation::Size m_outputSize;
Windows::Graphics::Display::DisplayOrientations m_orientation;
float m_dpi;
// Transforms used for display orientation.
D2D1::Matrix3x2F m_orientationTransform2D;
DirectX::XMFLOAT4X4 m_orientationTransform3D;
// The IDeviceNotify can be held directly as it owns the DeviceResources
IDeviceNotify* m_deviceNotify;
};
}
DeviceResources.cpp
#include "pch.h"
#include "DeviceResources.h"
#include "Common\DirectXHelper.h" // For ThrowIfFailed
#include <windows.ui.xaml.media.dxinterop.h> // For SwapChainBackgroundPanel native methods
using namespace MyDirectXApp;
using namespace D2D1;
using namespace DirectX;
using namespace Microsoft::WRL;
using namespace Windows::Graphics::Display;
using namespace Windows::UI::Core;
using namespace Windows::UI::Xaml::Controls;
// Constants used to calculate screen rotations
namespace ScreenRotation
{
// 0-degree Z-rotation
static const XMFLOAT4X4 Rotation0(
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
);
// 90-degree Z-rotation
static const XMFLOAT4X4 Rotation90(
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
);
// 180-degree Z-rotation
static const XMFLOAT4X4 Rotation180(
-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
);
// 270-degree Z-rotation
static const XMFLOAT4X4 Rotation270(
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
);
};
// Constructor for DeviceResources.
DeviceResources::DeviceResources() :
m_screenViewport(),
m_d3dFeatureLevel(D3D_FEATURE_LEVEL_9_1),
m_d3dRenderTargetSize(),
m_outputSize(),
m_orientation(DisplayOrientations::None),
m_dpi(-1.0f),
m_deviceNotify(nullptr)
{
CreateDeviceIndependentResources();
CreateDeviceResources();
}
// Configures resources that don't depend on the Direct3D device.
void DeviceResources::CreateDeviceIndependentResources()
{
// Initialize Direct2D resources
D2D1_FACTORY_OPTIONS options;
ZeroMemory(&options, sizeof(D2D1_FACTORY_OPTIONS));
#if defined(_DEBUG)
// If the project is in a debug build, enable Direct2D debugging via SDK Layers.
options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION;
#endif
// Initialize the Direct2D Factory
DX::ThrowIfFailed(
D2D1CreateFactory(
D2D1_FACTORY_TYPE_SINGLE_THREADED,
__uuidof(ID2D1Factory2),
&options,
&m_d2dFactory
)
);
// Initialize the DirectWrite Factory
DX::ThrowIfFailed(
DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(IDWriteFactory2),
&m_dwriteFactory
)
);
// Initialize the Windows Imaging Component (WIC) Factory
DX::ThrowIfFailed(
CoCreateInstance(
CLSID_WICImagingFactory2,
nullptr,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&m_wicFactory)
)
);
}
// Configures the Direct3D device, and stores handles to it and the device context.
void DeviceResources::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 (DX::SdkLayersAvailable())
{
// 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;
HRESULT hr = D3D11CreateDevice(
nullptr, // Specify nullptr to use the default adapter.
D3D_DRIVER_TYPE_HARDWARE, // Create a device using the hardware graphics driver.
0, // Should be 0 unless the driver is D3D_DRIVER_TYPE_SOFTWARE.
creationFlags, // Set debug and Direct2D compatibility flags.
featureLevels, // List of feature levels this app can support.
ARRAYSIZE(featureLevels), // Size of the list above.
D3D11_SDK_VERSION, // Always set this to D3D11_SDK_VERSION for Windows Store apps.
&device, // Returns the Direct3D device created.
&m_d3dFeatureLevel, // Returns feature level of device created.
&context // Returns the device immediate context.
);
if (FAILED(hr))
{
// If the initialization fails, fall back to the WARP device.
// For more information on WARP, see:
// https://go.microsoft.com/fwlink/p/?LinkID=286690
DX::ThrowIfFailed(
D3D11CreateDevice(
nullptr,
D3D_DRIVER_TYPE_WARP, // Create a WARP device instead of a hardware device.
0,
creationFlags,
featureLevels,
ARRAYSIZE(featureLevels),
D3D11_SDK_VERSION,
&device,
&m_d3dFeatureLevel,
&context
)
);
}
// Store pointers to the Direct3D 11.1 API device and immediate context.
DX::ThrowIfFailed(
device.As(&m_d3dDevice)
);
DX::ThrowIfFailed(
context.As(&m_d3dContext)
);
// Create the Direct2D device object and a corresponding context.
ComPtr<IDXGIDevice3> dxgiDevice;
DX::ThrowIfFailed(
m_d3dDevice.As(&dxgiDevice)
);
DX::ThrowIfFailed(
m_d2dFactory->CreateDevice(dxgiDevice.Get(), &m_d2dDevice)
);
DX::ThrowIfFailed(
m_d2dDevice->CreateDeviceContext(
D2D1_DEVICE_CONTEXT_OPTIONS_NONE,
&m_d2dContext
)
);
}
// These resources need to be recreated every time the window size is changed.
void DeviceResources::CreateWindowSizeDependentResources()
{
// Clear our previous window size specific context
ID3D11RenderTargetView* nullViews[] = {nullptr};
m_d3dContext->OMSetRenderTargets(ARRAYSIZE(nullViews), nullViews, nullptr);
m_d3dRenderTargetView = nullptr;
m_d2dContext->SetTarget(nullptr);
m_d2dTargetBitmap = nullptr;
m_d3dDepthStencilView = nullptr;
m_d3dContext->Flush();
// Store the output bounds so the next time we get a SizeChanged event we can
// avoid rebuilding everything if the size is identical.
DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView();
m_outputSize.Width = m_swapChainPanel == nullptr ? m_window->Bounds.Width : static_cast<float>(m_swapChainPanel->ActualWidth);
m_outputSize.Height = m_swapChainPanel == nullptr ? m_window->Bounds.Height : static_cast<float>(m_swapChainPanel->ActualHeight);
// Prevent zero size DirectX content from being created
m_outputSize.Width = m_outputSize.Width > 0 ? m_outputSize.Width : 1;
m_outputSize.Height = m_outputSize.Height > 0 ? m_outputSize.Height : 1;
// Calculate the necessary swap chain and render target size in pixels.
float outputWidthInPixels;
float outputHeightInPixels;
if (m_swapChainPanel != nullptr)
{
outputWidthInPixels = m_outputSize.Width * m_swapChainPanel->CompositionScaleX;
outputHeightInPixels = m_outputSize.Height * m_swapChainPanel->CompositionScaleY;
}
else
{
outputWidthInPixels = DX::ConvertDipsToPixels(m_outputSize.Width, currentDisplayInformation->LogicalDpi);
outputHeightInPixels = DX::ConvertDipsToPixels(m_outputSize.Height, currentDisplayInformation->LogicalDpi);
}
// The width and height of the swap chain must be based on the window's
// natively-oriented width and height. If the window is not in the native
// orientation, the dimensions must be reversed.
m_orientation = currentDisplayInformation->CurrentOrientation;
DXGI_MODE_ROTATION displayRotation = ComputeDisplayRotation();
bool swapDimensions = displayRotation == DXGI_MODE_ROTATION_ROTATE90 || displayRotation == DXGI_MODE_ROTATION_ROTATE270;
m_d3dRenderTargetSize.Width = swapDimensions ? outputHeightInPixels : outputWidthInPixels;
m_d3dRenderTargetSize.Height = swapDimensions ? outputWidthInPixels : outputHeightInPixels;
if (m_swapChain)
{
// If the swap chain already exists, resize it.
HRESULT hr = m_swapChain->ResizeBuffers(
2, // Double-buffered swap chain.
static_cast<UINT>(m_d3dRenderTargetSize.Width),
static_cast<UINT>(m_d3dRenderTargetSize.Height),
DXGI_FORMAT_B8G8R8A8_UNORM,
0
);
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
{
// If the device was removed for any reason, a new device and swap chain will need to be created.
HandleDeviceLost();
// Everything is set up now. Do not continue execution of this method.
return;
}
else
{
DX::ThrowIfFailed(hr);
}
}
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_d3dRenderTargetSize.Width); // Match the size of the window.
swapChainDesc.Height = static_cast<UINT>(m_d3dRenderTargetSize.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;
swapChainDesc.BufferCount = 2; // Use double-buffering to minimize latency.
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // All Windows Store apps must use this SwapEffect.
swapChainDesc.Flags = 0;
// When using XAML interop, change the Scaling to DXGI_SCALING_STRETCH
if (m_swapChainPanel == nullptr)
{
swapChainDesc.Scaling = DXGI_SCALING_NONE;
}
else
{
swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
}
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
// This sequence obtains the DXGI factory that was used to create the Direct3D device above.
ComPtr<IDXGIDevice3> 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
)
);
// When using XAML interop, the SwapChain must be created for composition
if (m_swapChainPanel == nullptr)
{
DX::ThrowIfFailed(
dxgiFactory->CreateSwapChainForCoreWindow(
m_d3dDevice.Get(),
reinterpret_cast<IUnknown*>(m_window.Get()),
&swapChainDesc,
nullptr,
&m_swapChain
)
);
}
else
{
DX::ThrowIfFailed(
dxgiFactory->CreateSwapChainForComposition(
m_d3dDevice.Get(),
&swapChainDesc,
nullptr,
&m_swapChain
)
);
// Get backing native interface for SwapChainPanel
ComPtr<ISwapChainPanelNative> panelNative;
DX::ThrowIfFailed(
reinterpret_cast<IUnknown*>(m_swapChainPanel)->QueryInterface(IID_PPV_ARGS(&panelNative))
);
// Associate swap chain with SwapChainPanel
DX::ThrowIfFailed(
panelNative->SetSwapChain(m_swapChain.Get())
);
}
// 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 2D and
// 3D matrix transformations for rendering to the rotated swap chain.
// Note the rotation angle for the 2D and 3D transforms are different.
// This is due to the difference in coordinate spaces. Additionally,
// the 3D matrix is specified explicitly to avoid rounding errors.
switch (displayRotation)
{
case DXGI_MODE_ROTATION_IDENTITY:
m_orientationTransform2D = Matrix3x2F::Identity();
m_orientationTransform3D = ScreenRotation::Rotation0;
break;
case DXGI_MODE_ROTATION_ROTATE90:
m_orientationTransform2D =
Matrix3x2F::Rotation(90.0f) *
Matrix3x2F::Translation(m_outputSize.Height, 0.0f);
m_orientationTransform3D = ScreenRotation::Rotation270;
break;
case DXGI_MODE_ROTATION_ROTATE180:
m_orientationTransform2D =
Matrix3x2F::Rotation(180.0f) *
Matrix3x2F::Translation(m_outputSize.Width, m_outputSize.Height);
m_orientationTransform3D = ScreenRotation::Rotation180;
break;
case DXGI_MODE_ROTATION_ROTATE270:
m_orientationTransform2D =
Matrix3x2F::Rotation(270.0f) *
Matrix3x2F::Translation(0.0f, m_outputSize.Width);
m_orientationTransform3D = ScreenRotation::Rotation90;
break;
default:
throw ref new Platform::FailureException();
}
DX::ThrowIfFailed(
m_swapChain->SetRotation(displayRotation)
);
// Setup inverse scale on the swapchain
if (m_swapChainPanel != nullptr)
{
DXGI_MATRIX_3X2_F inverseScale = { 0 };
inverseScale._11 = 1.0f / m_swapChainPanel->CompositionScaleX;
inverseScale._22 = 1.0f / m_swapChainPanel->CompositionScaleY;
ComPtr<IDXGISwapChain2> spSwapChain2;
m_swapChain.As<IDXGISwapChain2>(&spSwapChain2);
spSwapChain2->SetMatrixTransform(&inverseScale);
}
// Create a render target view of the swap chain back buffer.
ComPtr<ID3D11Texture2D> backBuffer;
DX::ThrowIfFailed(
m_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer))
);
DX::ThrowIfFailed(
m_d3dDevice->CreateRenderTargetView(
backBuffer.Get(),
nullptr,
&m_d3dRenderTargetView
)
);
// Create a depth stencil view for use with 3D rendering if needed.
CD3D11_TEXTURE2D_DESC depthStencilDesc(
DXGI_FORMAT_D24_UNORM_S8_UINT,
static_cast<UINT>(m_d3dRenderTargetSize.Width),
static_cast<UINT>(m_d3dRenderTargetSize.Height),
1, // This depth stencil view has only one texture.
1, // Use a single mipmap level.
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_d3dDepthStencilView
)
);
// Set the 3D rendering viewport to target the entire window.
m_screenViewport = CD3D11_VIEWPORT(
0.0f,
0.0f,
m_d3dRenderTargetSize.Width,
m_d3dRenderTargetSize.Height
);
m_d3dContext->RSSetViewports(1, &m_screenViewport);
// Create a Direct2D target bitmap associated with the
// swap chain back buffer and set it as the current target.
D2D1_BITMAP_PROPERTIES1 bitmapProperties =
D2D1::BitmapProperties1(
D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED),
m_dpi,
m_dpi
);
ComPtr<IDXGISurface2> dxgiBackBuffer;
DX::ThrowIfFailed(
m_swapChain->GetBuffer(0, IID_PPV_ARGS(&dxgiBackBuffer))
);
DX::ThrowIfFailed(
m_d2dContext->CreateBitmapFromDxgiSurface(
dxgiBackBuffer.Get(),
&bitmapProperties,
&m_d2dTargetBitmap
)
);
m_d2dContext->SetTarget(m_d2dTargetBitmap.Get());
// Grayscale text anti-aliasing is recommended for all Windows Store apps.
m_d2dContext->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE);
}
// This method is called when the CoreWindow is created (or re-created)
void DeviceResources::SetWindow(CoreWindow^ window)
{
m_window = window;
// SetDpi() will call CreateWindowSizeDependentResources()
// if those resources have not been created yet.
SetDpi(DisplayInformation::GetForCurrentView()->LogicalDpi);
UpdateForWindowSizeChange();
}
// This method is called when the XAML control is created (or re-created)
void DeviceResources::SetWindow(CoreWindow^ window, SwapChainPanel^ panel)
{
m_swapChainPanel = panel;
SetWindow(window);
}
// This method is called in the event handler for the LogicalDpiChanged event.
void DeviceResources::SetDpi(float dpi)
{
if (dpi != m_dpi)
{
// Save the updated DPI value.
m_dpi = dpi;
// Update Direct2D's stored DPI.
m_d2dContext->SetDpi(m_dpi, m_dpi);
// Often a DPI change implies a window size change. In some cases Windows will issue
// both a size changed event and a DPI changed event. In this case, the resulting bounds
// will not change, and the window resize code will only be executed once.
UpdateForWindowSizeChange();
}
}
// This method is called in the event handler for the SizeChanged event.
void DeviceResources::UpdateForWindowSizeChange()
{
DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView();
if (m_swapChainPanel == nullptr && (
m_window->Bounds.Width != m_outputSize.Width ||
m_window->Bounds.Height != m_outputSize.Height
) || m_swapChainPanel != nullptr && (
m_swapChainPanel->ActualWidth != m_outputSize.Width ||
m_swapChainPanel->ActualHeight != m_outputSize.Height
) || m_orientation != currentDisplayInformation->CurrentOrientation)
{
CreateWindowSizeDependentResources();
}
}
// This method is called in the event handler for the DisplayContentsInvalidated event.
void DeviceResources::ValidateDevice()
{
// The D3D Device is no longer valid if the default adapter changes or if
// the device has been removed.
// First, get the information for the adapter related to the current device.
ComPtr<IDXGIDevice3> dxgiDevice;
DX::ThrowIfFailed(m_d3dDevice.As(&dxgiDevice));
ComPtr<IDXGIAdapter> deviceAdapter;
DX::ThrowIfFailed(dxgiDevice->GetAdapter(&deviceAdapter));
DXGI_ADAPTER_DESC adapterDesc;
DX::ThrowIfFailed(deviceAdapter->GetDesc(&adapterDesc));
// Next, get the information for the default adapter.
ComPtr<IDXGIFactory2> dxgiFactory;
DX::ThrowIfFailed(CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory)));
ComPtr<IDXGIAdapter1> currentAdapter;
DX::ThrowIfFailed(dxgiFactory->EnumAdapters1(0, ¤tAdapter));
DXGI_ADAPTER_DESC currentDesc;
DX::ThrowIfFailed(currentAdapter->GetDesc(¤tDesc));
// If the adapter LUIDs don't match, or if the device reports that it has been removed,
// a new D3D device must be created.
if (adapterDesc.AdapterLuid.LowPart != currentDesc.AdapterLuid.LowPart ||
adapterDesc.AdapterLuid.HighPart != currentDesc.AdapterLuid.HighPart ||
FAILED(m_d3dDevice->GetDeviceRemovedReason()))
{
// Release references to resources related to the old device.
dxgiDevice = nullptr;
deviceAdapter = nullptr;
// Create a new device and swap chain.
HandleDeviceLost();
}
}
// Recreate all device resources and set them back to the current state.
void DeviceResources::HandleDeviceLost()
{
// Reset these member variables to ensure that SetDpi recreates all resources.
float dpi = m_dpi;
m_dpi = -1.0f;
m_outputSize.Width = 0;
m_outputSize.Height = 0;
m_swapChain = nullptr;
if (m_deviceNotify != nullptr)
{
m_deviceNotify->OnDeviceLost();
}
CreateDeviceResources();
SetDpi(dpi);
if (m_deviceNotify != nullptr)
{
m_deviceNotify->OnDeviceRecreated();
}
}
// Register our DeviceNotify to be informed on device lost and creation
void DeviceResources::RegisterDeviceNotify(IDeviceNotify* deviceNotify)
{
m_deviceNotify = deviceNotify;
}
// Call this method when the app suspends to hint to the driver that the app is entering an idle state
// and that temporary buffers can be reclaimed for use by other apps.
void DeviceResources::Trim()
{
ComPtr<IDXGIDevice3> dxgiDevice;
m_d3dDevice.As(&dxgiDevice);
dxgiDevice->Trim();
}
// Present the contents of the swap chain to the screen.
void DeviceResources::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.
HRESULT hr = m_swapChain->Present(1, 0);
// 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_d3dRenderTargetView.Get());
// Discard the contents of the depth stencil.
m_d3dContext->DiscardView(m_d3dDepthStencilView.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 || hr == DXGI_ERROR_DEVICE_RESET)
{
HandleDeviceLost();
}
else
{
DX::ThrowIfFailed(hr);
}
}
// This method determines the rotation between the display device's native Orientation and the
// current display orientation.
DXGI_MODE_ROTATION DeviceResources::ComputeDisplayRotation()
{
DXGI_MODE_ROTATION rotation = DXGI_MODE_ROTATION_UNSPECIFIED;
// Note: NativeOrientation can only be Landscape or Portrait even though
// the DisplayOrientations enum has other values.
auto displayInformation = DisplayInformation::GetForCurrentView();
switch (displayInformation->NativeOrientation)
{
case DisplayOrientations::Landscape:
switch (displayInformation->CurrentOrientation)
{
case DisplayOrientations::Landscape:
rotation = DXGI_MODE_ROTATION_IDENTITY;
break;
case DisplayOrientations::Portrait:
rotation = DXGI_MODE_ROTATION_ROTATE90;
break;
case DisplayOrientations::LandscapeFlipped:
rotation = DXGI_MODE_ROTATION_ROTATE180;
break;
case DisplayOrientations::PortraitFlipped:
rotation = DXGI_MODE_ROTATION_ROTATE270;
break;
}
break;
case DisplayOrientations::Portrait:
switch (displayInformation->CurrentOrientation)
{
case DisplayOrientations::Landscape:
rotation = DXGI_MODE_ROTATION_ROTATE270;
break;
case DisplayOrientations::Portrait:
rotation = DXGI_MODE_ROTATION_IDENTITY;
break;
case DisplayOrientations::LandscapeFlipped:
rotation = DXGI_MODE_ROTATION_ROTATE90;
break;
case DisplayOrientations::PortraitFlipped:
rotation = DXGI_MODE_ROTATION_ROTATE180;
break;
}
break;
}
return rotation;
}