DXGI overview

Microsoft DirectX Graphics Infrastructure (DXGI) recognizes that some parts of graphics evolve more slowly than others. The primary goal of DXGI is to manage low-level tasks that can be independent of the DirectX graphics runtime. DXGI provides a common framework for future graphics components; the first component that takes advantage of DXGI is Microsoft Direct3D 10.

In previous versions of Direct3D, low-level tasks like enumeration of hardware devices, presenting rendered frames to an output, controlling gamma, and managing a full-screen transition were included in the Direct3D runtime. These tasks are now implemented in DXGI.

DXGI's purpose is to communicate with the kernel mode driver and the system hardware, as shown in the following diagram.

diagram of the communication between applications, dxgi, and drivers and hardware

An application can access DXGI directly, or call the Direct3D APIs in D3D11_1.h, D3D11.h, D3D10_1.h, or D3D10.h, which handles the communications with DXGI for you. You may want to work with DXGI directly if your application needs to enumerate devices or control how data is presented to an output.

This topic contains the following sections.

To see which formats are supported by Direct3D 11 hardware:

Enumerating adapters

An adapter is an abstraction of the hardware and the software capability of your computer. There are generally many adapters on your machine. Some devices are implemented in hardware (like your video card) and some are implemented in software (like the Direct3D reference rasterizer). Adapters implement functionality used by a graphic application. The following diagram shows a system with a single computer, two adapters (video cards), and three output monitors.

diagram of a computer with two video cards and three monitors

When enumerating these pieces of hardware, DXGI creates an IDXGIOutput1 interface for each output (or monitor) and an IDXGIAdapter2 interface for each video card (even if it is a video card built into a motherboard). Enumeration is done by using an IDXGIFactory interface call, IDXGIFactory::EnumAdapters, to return a set of IDXGIAdapter interfaces that represent the video hardware.

DXGI 1.1 added the IDXGIFactory1 interface. IDXGIFactory1::EnumAdapters1 returns a set of IDXGIAdapter1 interfaces that represents the video hardware.

If you want to select specific video hardware capabilities when you use Direct3D APIs, we recommend that you iteratively call the D3D11CreateDevice or D3D11CreateDeviceAndSwapChain function with each adapter handle and possible hardware feature level. This function succeeds if the feature level is supported by the specified adapter.

New info about enumerating adapters for Windows 8

Starting with Windows 8, an adapter called the "Microsoft Basic Render Driver" is always present. This adapter has a VendorId of 0x1414 and a DeviceID of 0x8c. This adapter also has the DXGI_ADAPTER_FLAG_SOFTWARE value set in the Flags member of its DXGI_ADAPTER_DESC2 structure. This adapter is a render-only device that has no display outputs. DXGI never returns DXGI_ERROR_DEVICE_REMOVED for this adapter.

If a computer's display driver is not functioning or is disabled, the computer's primary (NULL) adapter might also be called "Microsoft Basic Render Driver." But this adapter has outputs and doesn't have the DXGI_ADAPTER_FLAG_SOFTWARE value set. The operating system and apps use this adapter by default. If a display driver is installed or enabled, apps can receive DXGI_ERROR_DEVICE_REMOVED for this adapter and then must re-enumerate adapters again.

When a computer's primary display adapter is the "Microsoft Basic Display Adapter" (WARP adapter), that computer also has a second adapter. This second adapter is the render-only device that has no display outputs and for which DXGI never returns DXGI_ERROR_DEVICE_REMOVED.

If you want to use WARP for rendering, compute, or other long running tasks, we recommend to use the render-only device. You can obtain a pointer to the render-only device by calling the IDXGIFactory1::EnumAdapters1 method. You also create the render-only device when you specify D3D_DRIVER_TYPE_WARP in the DriverType parameter of D3D11CreateDevice because the WARP device also uses the render-only WARP adapter.

Presentation

Your application's job is to render frames and ask DXGI to present those frames to the output. If the application has two buffers available, it can render one buffer while presenting another one. The application might require more than two buffers depending on the time it takes to render a frame or the desired frame rate for presentation. The set of buffers created is called a swap chain, as shown here.

illustration of a swap chain

A swap chain has one front buffer and one or more back buffers. Each application creates its own swap chain. To maximize the speed of the presentation of the data to an output, a swap chain is almost always created in the memory of a display sub-system, which is shown in the following illustration.

illustration of a display sub-system

The display sub-system (which is often a video card but could be implemented on a motherboard) contains a GPU, a digital to analog converter (DAC), and memory. The swap chain is allocated within this memory to make presentation very fast. The display sub-system presents the data in the front buffer to the output.

A swap chain is set up to draw in full-screen or windowed mode, this eliminates the need to know whether an output is windowed or full screen. A full-screen mode swap chain can optimize performance by switching the display resolution.

Create a swap chain

Differences between Direct3D 9 and Direct3D 10: Direct3D 10 is the first graphics component to use DXGI. DXGI has some different swap chain behaviors.
  • In DXGI, a swap chain is tied to a window when the swap chain is created. This change improves performance and saves memory. Previous versions of Direct3D allowed the swap chain to change the window that the swap chain is tied to.
  • In DXGI, a swap chain is tied to a rendering device on creation. The device object that the Direct3D create device functions return implements the IUnknown interface. You can call QueryInterface to query for the device's corresponding IDXGIDevice2 interface. A change to the rendering device requires the swap chain to be recreated.
  • In DXGI, the swap effects available are DXGI_SWAP_EFFECT_DISCARD and DXGI_SWAP_EFFECT_SEQUENTIAL. Starting with Windows 8 the DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL swap effect is also available. The following table shows a mapping of Direct3D 9 to DXGI swap effect defines.

    D3D9 Swap Effect DXGI Swap Effect
    D3DSWAPEFFECT_DISCARD DXGI_SWAP_EFFECT_DISCARD
    D3DSWAPEFFECT_COPY DXGI_SWAP_EFFECT_SEQUENTIAL with 1 buffer
    D3DSWAPEFFECT_FLIP DXGI_SWAP_EFFECT_SEQUENTIAL with 2 or more buffers
    D3DSWAPEFFECT_FLIPEX DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL with 2 or more buffers

A swap chain's buffers are created at a particular size and in a particular format. The application specifies these values (or you can inherit the size from the target window) at startup, and can then optionally modify them as the window size changes in response to user input or program events.

After you create the swap chain, you will typically want to render images into it. Here's a code fragment that sets up a Direct3D context to render into a swap chain. This code extracts a buffer from the swap chain, creates a render-target-view from that buffer, then sets it on the device:

ID3D11Resource * pBB;
ThrowFailure( pSwapChain->GetBuffer(0, __uuidof(pBB),    
  reinterpret_cast<void**>(&pBB)), "Couldn't get back buffer");
ID3D11RenderTargetView * pView;
ThrowFailure( pD3D11Device->CreateRenderTargetView(pBB, NULL, &pView), 
  "Couldn't create view" );
pD3D11DeviceContext->OMSetRenderTargets(1, &pView, 0);
        

After your application renders a frame into a swap-chain buffer, call IDXGISwapChain1::Present1. The application can then go render the next image.

Care and feeding of the swap chain

After you render your image, call IDXGISwapChain1::Present1 and go render the next image. That is the extent of your responsibility.

If you previously called IDXGIFactory::MakeWindowAssociation, the user can press the Alt-Enter key combination and DXGI will transition your application between windowed and full-screen mode. IDXGIFactory::MakeWindowAssociation is recommended, because a standard control mechanism for the user is strongly desired.

While you don't have to write any more code than has been described, a few simple steps can make your application more responsive. The most important consideration is the resizing of the swap chain's buffers in response to the resizing of the output window. Naturally, the application's best route is to respond to WM_SIZE, and call IDXGISwapChain::ResizeBuffers, passing the size contained in the message's parameters. This behavior obviously makes your application respond well to the user when he or she drags the window's borders, but it is also exactly what enables a smooth full-screen transition. Your window will receive a WM_SIZE message whenever such a transition happens, and calling IDXGISwapChain::ResizeBuffers is the swap chain's chance to re-allocate the buffers' storage for optimal presentation. This is why the application is required to release any references it has on the existing buffers before it calls IDXGISwapChain::ResizeBuffers.

Failure to call IDXGISwapChain::ResizeBuffers in response to switching to full-screen mode (most naturally, in response to WM_SIZE), can preclude the optimization of flipping, wherein DXGI can simply swap which buffer is being displayed, rather than copying a full screen's worth of data around.

IDXGISwapChain1::Present1 will inform you if your output window is entirely occluded via DXGI_STATUS_OCCLUDED. When this occurs, we recommended that your application go into standby mode (by calling IDXGISwapChain1::Present1 with DXGI_PRESENT_TEST) since resources used to render the frame are wasted. Using DXGI_PRESENT_TEST will prevent any data from being presented while still performing the occlusion check. Once IDXGISwapChain1::Present1 returns S_OK, you should exit standby mode; do not use the return code to switch to standby mode as doing so can leave the swap chain unable to relinquish full-screen mode.

The Direct3D 11.1 runtime, which is available starting with Windows 8, provides a flip-model swap chain (that is, a swap chain that has the DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL value set in the SwapEffect member of DXGI_SWAP_CHAIN_DESC or DXGI_SWAP_CHAIN_DESC1). When you present frames to an output with a flip-model swap chain, DXGI unbinds the back buffer from all pipeline state locations, like an output-merger render target, that write to back buffer 0. Therefore, we recommend that you call ID3D11DeviceContext::OMSetRenderTargets immediately before you render to the back buffer. For example, don't call OMSetRenderTargets and then perform compute shader work that doesn't end up rendering to the resource. For more info about flip-model swap chains and their benefits, see DXGI Flip Model.

Note

In Direct3D 10 and Direct3D 11, you don't have to call IDXGISwapChain::GetBuffer to retrieve back buffer 0 after you call IDXGISwapChain1::Present1 because for convenience the identities of back buffers change. This doesn't happen in Direct3D 12, and your application must instead manually track back buffer indices.

Handling window resizing

You can use the IDXGISwapChain::ResizeBuffers method to handle window resizing. Before you call ResizeBuffers, you must release all outstanding references to the swap chain's buffers. The object that typically holds a reference to a swap chain's buffer is a render-target-view.

The following example code shows how to call ResizeBuffers from within the WindowProc handler for WM_SIZE messages:

    case WM_SIZE:
        if (g_pSwapChain)
        {
            g_pd3dDeviceContext->OMSetRenderTargets(0, 0, 0);

            // Release all outstanding references to the swap chain's buffers.
            g_pRenderTargetView->Release();

            HRESULT hr;
            // Preserve the existing buffer count and format.
            // Automatically choose the width and height to match the client rect for HWNDs.
            hr = g_pSwapChain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
                                            
            // Perform error handling here!

            // Get buffer and create a render-target-view.
            ID3D11Texture2D* pBuffer;
            hr = g_pSwapChain->GetBuffer(0, __uuidof( ID3D11Texture2D),
                                         (void**) &pBuffer );
            // Perform error handling here!

            hr = g_pd3dDevice->CreateRenderTargetView(pBuffer, NULL,
                                                     &g_pRenderTargetView);
            // Perform error handling here!
            pBuffer->Release();

            g_pd3dDeviceContext->OMSetRenderTargets(1, &g_pRenderTargetView, NULL );

            // Set up the viewport.
            D3D11_VIEWPORT vp;
            vp.Width = width;
            vp.Height = height;
            vp.MinDepth = 0.0f;
            vp.MaxDepth = 1.0f;
            vp.TopLeftX = 0;
            vp.TopLeftY = 0;
            g_pd3dDeviceContext->RSSetViewports( 1, &vp );
        }
        return 1;

Choosing the DXGI output and size

By default, DXGI chooses the output that contains most of the client area of the window. This is the only option available to DXGI when it goes full-screen itself in response to alt-enter. If the application chooses to go to full-screen mode by itself, then it can call IDXGISwapChain::SetFullscreenState and pass an explicit IDXGIOutput1 (or NULL, if the application is happy to let DXGI decide).

To resize the output while either full screen or windowed, we recommend to call IDXGISwapChain::ResizeTarget, since this method resizes the target window also. Since the target window is resized, the operating system sends WM_SIZE, and your code will naturally call IDXGISwapChain::ResizeBuffers in response. It's thus a waste of effort to resize your buffers, and then subsequently resize the target.

Debugging in full-screen mode

A DXGI swap chain relinquishes full-screen mode only when absolutely necessary. This means that you can debug a full-screen application using multiple monitors, as long as the debug window doesn't overlap the swap chain's target window. Alternatively, you can prevent mode switching altogether by not setting the DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH flag.

If mode switching is allowed, a swap chain will relinquish full-screen mode whenever its output window is occluded by another window. The occlusion check is performed during IDXGISwapChain1::Present1, or by a separate thread whose purpose is to watch to see if the application has becomes unresponsive (and no longer calls IDXGISwapChain1::Present1). To disable the ability of the separate thread to cause a switch, set the following registry key to any non-zero value.

HKCU\Software\Microsoft\DXGI\DisableFullscreenWatchdog

Destroying a swap chain

You may not release a swap chain in full-screen mode because doing so may create thread contention (which will cause DXGI to raise a non-continuable exception). Before releasing a swap chain, first switch to windowed mode (using IDXGISwapChain::SetFullscreenState( FALSE, NULL )) and then call IUnknown::Release.

Using a rotated monitor

An application does not need to worry about monitor orientation, DXGI will rotate a swap-chain buffer during presentation, if necessary. Of course, this additional rotation can impact performance. For best performance, take care of the rotation in your application by doing the following:

  • Use the DXGI_SWAP_CHAIN_FLAG_NONPREROTATED. This notifies DXGI that the application will produce a rotated image (for example, by altering its projection matrix). One thing to note, this flag is only valid while in full-screen mode.
  • Allocate each swap-chain buffer in its rotated size. Use IDXGIOutput::GetDesc to get these values, if necessary.

By performing the rotation in your application, DXGI will simply do a copy instead of a copy and a rotate.

The Direct3D 11.1 runtime, which is available starting with Windows 8, provides a flip-model swap chain (that is, a swap chain that has the DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL value set in the SwapEffect member of DXGI_SWAP_CHAIN_DESC1). To maximize the presentation optimizations available with a flip-model swap chain, we recommend that you make your applications orient content to match the particular output on which the content resides when that content fully occupies the output. For more info about flip-model swap chains and their benefits, see DXGI Flip Model.

Switching modes

The DXGI swap chain might change the display mode of an output when making a full-screen transition. To enable the automatic display mode change, you must specify DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH in the swap-chain description. If the display mode automatically changes, DXGI will choose the most modest mode (size and resolution will not change, but the color depth may). Resizing swap chain buffers will not cause a mode switch. The swap chain makes an implicit promise that if you choose a back buffer that exactly matches a display mode supported by the target output, then it will switch to that display mode when entering full-screen mode on that output. Consequently, you choose a display mode by choosing your back buffer size and format.

Full-screen performance tip

When you call IDXGISwapChain1::Present1 on a full-screen application, the swap chain flips (as opposed to blits) the contents of the back buffer to the front buffer. This requires that the swap chain was created by using an enumerated display mode (specified in DXGI_SWAP_CHAIN_DESC1). If you fail to enumerate display modes, or incorrectly specify the display mode in the description, the swap chain may perform a bit-block transfer (bitblt) instead. The bitblt causes an extra stretching copy as well as some increased video memory usage, and is difficult to detect. To avoid this problem, enumerate display modes, and initialize the swap chain description correctly before you create the swap chain. This will ensure maximum performance when flipping in full-screen mode and avoid the extra memory overhead.

Multithread considerations

When you use DXGI in an application with multiple threads, you need to be careful to avoid creating a deadlock, where two different threads are waiting on each other to complete. There are two situations where this can occur.

  • The rendering thread is not the message-pump thread.
  • The thread executing a DXGI API is not the same thread that created the window.

Be careful that you never have the message-pump thread wait on the render thread when you use full-screen swap chains. For instance, calling IDXGISwapChain1::Present1 (from the render thread) may cause the render thread to wait on the message-pump thread. When a mode change occurs, this scenario is possible if Present1 calls ::SetWindowPos() or ::SetWindowStyle() and either of these methods call ::SendMessage(). In this scenario, if the message-pump thread has a critical section guarding it or if the render thread is blocked, then the two threads will deadlock.

For more info about using DXGI with multiple threads, see Multithreading and DXGI.

DXGI responses from DLLMain

Because a DllMain function can't guarantee the order in which it loads and unloads DLLs, we recommend that your app's DllMain function not call Direct3D or DXGI functions or methods, including functions or methods that create or release objects. If your app's DllMain function calls into a particular component, that component might call another DLL that isn't present on the operating system, which causes the operating system to crash. Direct3D and DXGI might load a set of DLLs, typically a set of drivers, that differs from computer to computer. Therefore, even if your app doesn t crash on your development and test computers when its DllMain function calls Direct3D or DXGI functions or methods, it might crash when it runs on another computer.

To prevent you from creating an app that might cause the operating system to crash, DXGI provides the following responses in the specified situations:

  • If your app's DllMain function releases its last reference to a DXGI factory, DXGI raises an exception.
  • If your app's DllMain function creates a DXGI factory, DXGI returns an error code.

DXGI 1.1 changes

We added the following functionality in DXGI 1.1.

DXGI 1.2 changes

We added the following functionality in DXGI 1.2.

  • Stereo swap chain
  • Flip-model swap chain
  • Optimized presentation (scrolling, dirty rectangles, and rotation)
  • Improved shared resources and synchronization
  • Desktop Duplication
  • Optimized use of video memory
  • Support for 16 bits per pixel (bpp) formats (DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_B5G5R5A1_UNORM, DXGI_FORMAT_B4G4R4A4_UNORM)
  • Debugging APIs

For more info about DXGI 1.2, see DXGI 1.2 Improvements.

Programming Guide for DXGI