Creating a Direct3D device and swap chain for Windows Phone 8

[ This article is for Windows Phone 8 developers. If you’re developing for Windows 10, see the latest documentation. ]

This topic shows you the correct way to create a Direct3D graphics device and a swap chain for Windows Phone. The Direct3D app project templates included Windows Phone SDK 8.0 include the code that performs these tasks for you. This topic is intended to call out a few requirements when creating a swap chain for the phone and suggests a small change to the code for creating a graphics device that will help you to test your app more accurately when using the Windows Phone 8 Emulator.

Creating a Direct3D device

ID3D11Device is the fundamental interface of Direct3D development. It is used to create most of the other graphics resources you will use, such as textures, vertex buffers, and shaders. The code that creates the device can be found in the Direct3D app project template in the CreateDeviceResources method of the Direct3Dbase class.

    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
    };

    // 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.
            &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)
        );

Note that the featureLevels array contains a list of constants which represent different device feature levels that may be supported on any particular device. The call to CreateD3D11Device will create a device for the first feature level in the array that is supported on the current device. Windows Phone only supports feature level 9_3 and so this is the only device that will ever be returned when running on a physical device. The Windows Phone 8 Emulator, however, may allow the creation of a higher feature level device. To ensure that you are testing your app with the correct feature level, regardless of whether you are running it on a device or on the emulator, it is recommended that you update the code to only request feature level 9_3. Do this by changing the featureLevels array to the following.

    D3D_FEATURE_LEVEL featureLevels[] = 
    {
        D3D_FEATURE_LEVEL_9_3
    };

For more information on 9_3 feature level support, see Direct3D feature level 9_3 for Windows Phone 8.

Creating a swap chain

Direct3D apps use a swap chain to copy the contents of a back buffer onto the screen. A swap chain is created using the IDXGIFactory2 interface. Only a subset of the methods exposed by this interface are supported on the phone. For a complete list of supported APIs, see Supported Direct3D APIs for Windows Phone 8.

In addition to the fact that some DXGI methods are completely unavailable on the phone, DXGI on Windows Phone 8 also exhibits several key differences for the APIs that are supported, primarily involving the creation of the swap chain and its associated back buffer with IDXGIFactory2::CreateSwapChainForCoreWindow. The following list calls out these key differences:

  1. DXGI_SWAP_CHAIN_DESC1.Format - On Windows Phone 8, the only supported display format support is DXGI_FORMAT_B8G8R8A8_UNORM.

  2. DXGI_SWAP_CHAIN_DESC1.BufferCount - On Windows Phone 8, the buffer count for the swap chain must be 1. If a value higher than 1 is specified, DXGI will default to 1.

  3. DXGI_SWAP_CHAIN_DESC1.SwapEffect - On Windows Phone 8 the only supported swap effect is DXGI_SWAP_EFFECT_DISCARD. This means that DXGI will not preserve the contents of the back buffer after presentation.

  4. DXGI_SWAP_CHAIN_DESC1.Scaling - On Windows Phone 8, the only supported scaling modes are DXGI_SCALING_STRETCH and DXGI_SCALING_ASPECT_RATIO_STRETCH. When the size of the back buffer isn’t equal to the target output, DXGI_SCALING_STRETCH will scale the back buffer contents to fit the target output regardless of the aspect ratio, whereas DXGI_SCALING_ASPECT_RATIO_STRETCH will perform aspect-ratio preserving scaling and letterbox the contents as needed.

The following code shows the creation of the swap chain in the Direct3D app project template.

    m_windowBounds = m_window->Bounds;

    // Calculate the necessary swap chain and render target size in pixels.
    m_renderTargetSize.Width = ConvertDipsToPixels(m_windowBounds.Width);
    m_renderTargetSize.Height = ConvertDipsToPixels(m_windowBounds.Height);

    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;
    swapChainDesc.BufferCount = 1; // On phone, only single buffering is supported.
    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.
    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
            )
        );