DirectX programming

Windows 8.1 introduces DirectX 11.2, which brings a host of new features to improve performance in your games and graphics apps.

New or updated in Windows 8.1

HLSL shader linking

[Get the HLSL shader compiler sample now.]

Windows 8.1 adds separate compilation and linking of HLSL shaders, which allows graphics programmers to create precompiled HLSL functions, package them into libraries, and link them into full shaders at run-time. This is essentially an equivalent of C/C++ separate compilation, libraries, and linking, and it allows programmers to compose precompiled HLSL code when more information becomes available to finalize the computation.

Programmers complete several steps to create a final shader using dynamic linkage at run-time:

  • Create a ID3D11Linker linker object, which represents a linking context. A single context cannot be used to produce multiple shaders; a linking context is used to produce a single shader and then the linking context is thrown away.

  • Use D3DLoadModule to load and set libraries from their library blobs.

  • Use D3DLoadModule to load and set an entry shader blob, or create an FLG shader (see next section).

  • Use ID3D11Module::CreateInstance to create ID3D11ModuleInstance objects, then call functions on these objects to rebind resources to their final slots.

  • Add the libraries to the linker, then Call ID3D11Linker::Link to produce final shader byte code that can then be loaded and used in the current D3D runtime(s) just like a fully precompiled and linked shader.

Function linking graph (FLG)

Windows 8.1 also adds the Function Linking Graph (FLG). The FLG enables programmers to construct shaders that consist of a sequence of precompiled function invocations that pass values to each other. When using the FLG, there is no need to write HLSL and invoke the HLSL compiler. Instead, the shader structure is specified programmatically using C++ API calls. FLG nodes represent input and output signatures and invocations of precompiled library functions. The order of registering the function-call nodes defines the sequence of invocations. The input signature node must be specified first, while the output signature node must be specified last. FLG edges define how values are passed from one node to another. The data types of passed values must be the same; there is no implicit type conversion. Shape and swizzling rules follow the HLSL behavior and values can only be passed forward in this sequence. For info on the FLG API see ID3D11FunctionLinkingGraph.

Inbox HLSL compiler

[Get the HLSL shader compiler sample now.]

The HLSL compiler is now inbox on Windows 8.1 and later. Now, most APIs for shader programming can be used in Windows Store apps that are built for Windows 8.1 and later. Many APIs for shader programming couldn't be used in Windows Store apps that were built for Windows 8; the reference pages for these APIs were marked with a note. But some shader APIs (for example, D3DCompileFromFile) can still only be used to develop Windows Store apps, and not in apps that you submit to the Windows Store; the reference pages for these APIs are still marked with a note.

GPU overlay support

[Get the DirectX Foreground Swap Chains now.]

GPU multi-plane overlay support keeps your gorgeous 2D art and interfaces looking their best in native resolution, while you draw your 3D scenes to a smaller, scaled frame buffer. Use the new IDXGIOutput2::SupportsOverlays method to determine if the platform supports multiple draw planes. Create a new overlay swap chain by specifying the DXGI_SWAP_CHAIN_FLAG_FOREGROUND_LAYER flag (see DXGI_SWAP_CHAIN_FLAG).

This feature allows the scaling and composition of two swap chains to happen automatically on the fixed-function overlays hardware, without using any GPU resources at all. This leaves more GPU resources for the app rendering code. Apps can already use code to render at multiple resolutions, but this just involves extra copies and composition passes that aren't ideal on low-power platforms.

You use the IDXGISwapChain2::SetSourceSize API to resize the bottom '3D' swap chain to less-than-native resolution, while you create a new 'foreground' swap chain at native resolution that contains the '2D' content. In this way, you control the sizing for both swap chains.

DirectX tiled resources

[Get the Direct3D Tiled Resources sample now.]

Windows 8.1 includes a new Direct3D feature called tiled resources, which exposes a limited virtual graphics memory model to apps and thereby permits loose mapping between logical resource data and physical memory. This allows the creation of large logical resources that utilize small amounts of physical memory. This is useful (for example) with terrain in games, and app UI.

Tiled resources are created by specifying the D3D11_RESOURCE_MISC_TILED flag. See the following API functions for working with tiled resources: UpdateTiles, UpdateTileMappings, and GetResourceTiling.

DirectX tiled resources feature support

Before using the tiled resources feature, you need to find out if the device supports tiled resources. Check feature support for tiled resources as follows:


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 (SUCCEEDED(hr))
{
    D3D11_FEATURE_DATA_D3D11_OPTIONS1 featureData;
    DX::ThrowIfFailed(
        device->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS1, &featureData, sizeof(featureData))
        );

    m_tiledResourcesTier = featureData.TiledResourcesTier;
}

Direct3D low-latency presentation API

[Get the DirectXLatency sample now.]

Windows 8.1 includes a new set of APIs for DirectX apps to present frames with lower latency, allowing for faster UI response. By using the new APIs, apps can wait for the DXGI swap chain to present, as opposed to having the swap chain wait on the app. Like existing block-on-present behavior, the desired frame latency is adjustable using API calls.

Using the low-latency presentation API

Programmers can use the low-latency presentation API as follows.

  • Create the swap chain with the DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT flag.

    
    DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0};
    swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; // Enable GetFrameLatencyWaitableObject().
    
    
  • Swap chains created with the DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT flag use their own per-swap-chain latency setting instead of the one associated with the DXGI device. The default per-swap-chain latency is 1, which ensures that DXGI does not queue more than one frame at a time. This both reduces latency and ensures that the app will render only after each VSync, minimizing power consumption.

    There is a trade-off between the latency setting and how much CPU/GPU work is parallelizable. If an app's serialized CPU and GPU work will exceed 17 milliseconds (ms), it should change the frame latency to 2 which allows enough time for the CPU/GPU work to be parallelized. If your app will do more than 17 ms of work per frame, set the latency to 2 by calling SetMaximumFrameLatency.

    
    DX::ThrowIfFailed(
        m_swapChain->SetMaximumFrameLatency(2)
        );
    
    

    Then, call GetFrameLatencyWaitableObject to get the swap chain's frame latency waitable object.

    
    m_frameLatencyWaitableObject = m_swapChain->GetFrameLatencyWaitableObject();
    
    

    In the rendering loop, make sure to call WaitForSingleObjectEx at the start of each loop. This ensures the app will wait for the swap chain to be available for new rendering work before the app starts rendering each new frame.

    
    DWORD result = WaitForSingleObjectEx(
        m_frameLatencyWaitableObject,
        1000, // 1-second timeout (shouldn't ever occur)
        true
        );
    
    

Frame buffer scaling

New GPU scaling lets you dynamically resize your frame buffer to keep your 3D graphics smooth. The new IDXGISwapChain2 interface defines a set of new methods to get and set the source swap chain size, and define the scaling matrix for your frame buffer.

DXGI Trim API and map default buffer

[Get the DXGI swap chain rotation sample now.]

Windows 8.1 adds the new DXGI IDXGIDevice3::Trim method, which allows DirectX apps to release device memory allocated by the graphics driver thereby reducing the app's memory profile while it is suspended.

Additionally, Windows 8.1 includes a new map default buffer operation for Direct3D apps that lets your app access a GPU’s default buffers directly (if supported by the device), without the need for a more expensive intermediate copy operation to a temporary buffer.

Multithreading with SurfaceImageSource

[Get the XAML SurfaceImageSource DirectX interop sample now.]

In Windows 8.1, apps can also access and update SurfaceImageSource (SIS) XAML elements from a background thread.

Apps can now call ISurfaceImageSourceNativeWithD2D::BeginDraw from any thread. Likewise, the new ISurfaceImageSourceNativeWithD2D:SuspendDraw and ISurfaceImageSourceNativeWithD2D:ResumeDraw methods allow apps to suspend drawing on one thread and resume on another.

To take advantage of multithreading, your app must meet these conditions :

  • These objects (if used) must be multithreaded:
  • The app calls BeginDraw, SuspendDraw, and ResumeDraw on any thread, but calls EndDraw only on the XAML UI thread. Note that apps are not required to call ResumeDraw before calling EndDraw, and that all EndDraw updates that are submitted within the same XAML UI thread tick will be submitted in the same frame.

Here's a code example that shows how to use multithreading with a SurfaceImageSource.

// Create a SIS element and associate a multithreaded DirectX device
ComPtr<ISurfaceImageSourceNativeWithD2D> m_sisNative;

// ...

m_sisNative->SetDevice1(m_d3dDevice.Get());

POINT offset;
ComPtr<IDXGISurface> surface;

// Begin drawing.
HRESULT beginDrawHR = m_sisNative->BeginDraw1(
updateRect, IID_IDXGISurface, &surface, &offset);

// QI for target texture from DXGI surface.
ComPtr<ID3D11Texture2D> d3DTexture;
surface.As(&d3DTexture);

// Create render target view.
m_d3dDevice->CreateRenderTargetView(d3DTexture.Get(), nullptr,   
  &m_renderTargetView); 

// Render complex content.
// ...

// Suspend drawing before signaling the UI thread.
m_sisNative->SuspendDraw();

// Signal the UI thread that drawing is complete, so EndDraw() can be called.
// ...

// Call EndDraw() on the UI thread to commit changes for the current frame.
m_sisNative->EndDraw();

Key points about the new ISurfaceImageSourceNative1::SetDevice1 and ISurfaceImageSourceNative1::BeginDraw1 methods:

  • Unlike SetDevice(), SetDevice1() will alternatively accept an ID2D1Device instead of an IDXGIDevice. This is required to support Direct2D batching across surfaces.

  • The new BeginDraw1() overload returns a device context rather than directly returning a scratch surface if a Direct2D device was passed to SetDevice.

Interactive DirectX composition of XAML visual elements

[Get the XAML SwapChainPanel DirectX interop sample now.]

You can use the SwapChainPanel class in Windows 8.1 to render DirectX graphics content in an app that uses XAML, with better performance and lower latency than when you use the SurfaceImageSource class in Windows 8, and with fewer layout restrictions than when you use the SwapChainBackgroundPanel class.

SwapChainPanel is similar to SwapChainBackgroundPanel in Windows 8, but with fewer restrictions on XAML tree placement and usage. (SwapChainBackgroundPanel was restricted to full-screen display and placement behind all XAML content in the element display tree).

SwapChainPanel supports the following display options:

  • Arbitrary sizes, transformations, and opacity levels

  • Interleaving with other visual elements in the XAML tree

  • Scrolling with the ScrollViewer control

Your app can also have multiple swap chains, with each providing the presentation for an individual SwapChainPanel. But beware that performance may decline if many swap chains are updated simultaneously. We recommend that your app use no more than four swap chains.

SwapChainPanel objects are declared like any other XAML element, at any place in the element tree and in any size.

Here's how you declare a SwapChainPanel in your XAML page.


<Page>
  <Grid>
    <SwapChainPanel x:Name=”mySwapChainPanel” Height=”300” Width=”400” />
    <!-- Additional XAML code ..>
</Grid>
</Page>


As with SwapChainBackgroundPanel, apps create a backing swap chain by calling the IDXGIFactory2::CreateSwapChainForComposition method and associating it with an instance of SwapChainPanel. You make this association by using a smart pointer to the ISwapChainPanelNative interface.

These conditions apply to the swap chain you create:

  • The swap chain can be of any size considered valid by the Microsoft DirectX Graphics Infrastructure (DXGI).

  • The swap chain is not stretched when it's resized by the user; instead, the resizing behavior is similar to setting Stretch=None on an Image element.

  • Apps can associate a swap chain (via the ISwapChainPanelNative::SetSwapChain method) only on the main UI thread (CoreWindow).

  • A single swap chain can be associated with multiple SwapChainPanels. Apps can render to and present the swap chain at any interval from either the UI thread or a background thread, assuming that DirectX multithreading conditions are met.

Here's a code example that shows how to associate a swap chain with a SwapChainPanel instance.


ComPtr<ISwapChainPanelNative> panelNative;
 
reinterpret_cast<IUnknown*>(mySwapChainPanel)->QueryInterface(IID_PPV_ARGS(&panelNative));
panelNative->SetSwapChain(m_swapChain.Get());



Direct2D batching with SurfaceImageSource

[Get the XAML SurfaceImageSource DirectX interop sample now.]

With Windows 8.1, apps can update multiple SurfaceImageSource (SIS) and VirtualSurfaceImageSource (VSIS) XAML elements without requiring a separate Direct2D batch operation for each update.

Apps can opt in to this new batching behavior by calling the QueryInterface method and acquiring a pointer to the new ISurfaceImageSourceNativeWithD2D interface.

As with other DirectX-to-XAML interop APIs, these are "native" COM interfaces rather than Windows Runtime APIs, because they interoperate with the DirectX APIs directly. After accessing the new interfaces, apps can call the SetDevice1 method on either interface and pass an ID2D1Device or an IDXGIDevice object.

If the app supplies a Direct2D device, this indicates that the SIS should support batching Direct2D calls. In the case where BeginDraw is called on the ISurfaceImageSourceNativeWithD2D interface, the app receives an ID2D1DeviceContext object rather than an IDXGISurface object. Supply this device to the XAML framework, which then creates a corresponding surface. All drawing commands issued for the ID2D1DeviceContext are then batched (when possible) with Direct2D drawing commands for any other SIS elements that:

This new behavior is best for when an app will simultaneously update two SIS elements containing Direct2D content. The app uses the new batching functionality to share a Direct2D device and context and so avoids flushing Direct2D batches between each SIS update. Reducing CPU work improves performance.

Here's some code that shows how to do all this.

// Create SIS elements and associate a multithreaded DirectX device.
ComPtr<ISurfaceImageSourceNativeWithD2D> m_sisNative1;
ComPtr<ISurfaceImageSourceNativeWithD2D> m_sisNative2;

// ...

m_sisNative1->SetDevice1(m_d3dDevice.Get());
m_sisNative2->SetDevice1(m_d3dDevice.Get());

// Set device for both SIS elements.
m_sisNative1->SetDevice(m_d2dDevice.Get());
m_sisNative2->SetDevice(m_d2dDevice.Get());

POINT offset;
ComPtr<ID2D1DeviceContext> d2dContext;

// Begin drawing SIS #1. 
HRESULT beginDrawHR = m_sisNative1->BeginDraw(
updateRect, IID_ID2D1DeviceContext, &d2dContext, &offset);
 
if (beginDrawHR == DXGI_ERROR_DEVICE_REMOVED || 
    beginDrawHR == DXGI_ERROR_DEVICE_RESET)
{ // Error checking }

// App does not call BeginDraw/EndDraw on Direct2D context;
// this is managed by the framework.

// Issue Direct2D drawing commands for SIS #1.
d2dContext->FillRectangle(D2D1::RectF(0,0,10,10), m_brush1.Get());

// Begin drawing SIS #2. 
beginDrawHR = m_sisNative2->BeginDraw(
updateRect, IID_ID2D1DeviceContext, &d2dContext, &offset);
 
if (beginDrawHR == DXGI_ERROR_DEVICE_REMOVED || 
    beginDrawHR == DXGI_ERROR_DEVICE_RESET)
{ // Error checking. }

// Issue Direct2D drawing commands for SIS #2.
d2dContext ->FillRectangle(D2D1::RectF(20,20,30,30), m_brush2.Get());

Note  Here are a few additional tips:

 

 

Show:
© 2014 Microsoft. All rights reserved.