D3DBook:DXGI

From GDWiki
Jump to: navigation, search

Contents

DXGI

Beside of Direct3D 10 Windows Vista introduce a second API that is tightly coupled with graphics operations. The DirectX Graphics Infrastructure (DXGI) is responsible for the hardware enumeration and the presentation of images rendered with Direct3D. While the enumeration works with every kind of graphics adapter the presentation part is limited to devices that support at last Direct3D 10.

Factories, Adapters and Displays

The main DXGI object is the factory. Created with CreateDXGIFactory it provides a snap shot of the current system state. Because of this you need to recreate the factory after every hardware change to reflect these changes. To get access to the adapter objects you need to call EnumAdapters with increasing index numbers until it returns DXGI_ERROR_NOTFOUND.

IDXGIFactory* pDXGIFactory;
 
HRESULT hr = CreateDXGIFactory (__uuidof(IDXGIFactory), (void<nowiki>**)&pDXGIFactory);</nowiki>
 
if (hr != S_OK)
    return -1;
 
int AdapterIndex = 0;
IDXGIAdapter* pAdapter;
 
// Loop as long as DXGI returns valid adapters.
while (pDXGIFactory->EnumAdapters (AdapterIndex, &pAdapter) == S_OK)
{
    // Do something with the adapter object
 
    pAdapter->Release (); // Don't forget to release when you are done
 
    AdapterIndex++;
}
 
pDXGIFactory->Release ();

Beside of the physical adapters in the system the factory could create a software adapter, too. To do this you have to provide the module handle for the dynamic link library that contains the software adapter implementation to the CreateSoftwareAdapter method. Currently the reference rasterizer is the only available software device and it could not be redistribute without the whole SDK.

The adapter object provides only information methods. Beside of the GetDesc method for the general Information CheckInterfaceSupport let you ask the driver if it supports a Direct3D version. To be ready for future versions it takes the GUID of the device interface for the version of interest.

LARGE_INTEGER version;
 
if (pAdapter->CheckInterfaceSupport (__uuidof (ID3D10Device), &version) != S_OK)
    // No D3D10
else
    // Yes we can use D3D10

But even if CheckInterfaceSupport reports an Direct3D 10 compatible driver on the system the creation of the device can still fail.

The final purpose of the adapter object is to enumerate the attached output devices. Like the adapters the enumeration requires to call EnumOutputs until DXGI_ERROR_NOT_FOUND is returned.

int OutputIndex = 0;
 
IDXGIOutput* pOutput;
 
while (pAdapter->EnumOutputs (OutputIndex, &pOutput) == S_OK)
{
    // Do something with the output object
    pOutput->Release ();
 
    OutputIndex++;
}

The output objects that represent a display are more powerful than the adapter object. Additional to the information methods there are methods to set the gamma behavior for the display, wait for the vertical retrace or access the surface for the display.

Devices

Like Direct3D 10 the DXGI API includes a interface for device objects, too. The limited function set provides access to the GPU thread priority and let you check the current memory location of your resources. To make use of this functionality the interface need to be requested from the Direct3D device.

Swap chains

One of the main DXGI objects are the swap chains. As Direct3D 10 doesn't provide any method to manage the presentation process they are the only way to display your render results. Swap chains are created from the DXGI factory for an already created device. As these objects contains and control the back buffers it would always be necessary to attach the buffer from a swap chain to the device as render target before you can start render.

// First the device
hr = D3D10CreateDevice( NULL, D3D10_DRIVER_TYPE_HARDWARE, NULL, 0, D3D10_SDK_VERSION, &g_pd3dDevice );
 
if( FAILED(hr) )
    return hr;
 
IDXGIFactory *pFactory;
 
CreateDXGIFactory (__uuidof(IDXGIFactory), (void<nowiki>**)&pFactory);</nowiki>
 
DXGI_SWAP_CHAIN_DESC sd;
ZeroMemory( &sd, sizeof(sd) );
sd.BufferCount = 1;
sd.BufferDesc.Width = width;
sd.BufferDesc.Height = height;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.BufferDesc.RefreshRate.Numerator = 60;
sd.BufferDesc.RefreshRate.Denominator = 1;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.OutputWindow = hWnd;
sd.SampleDesc.Count = 1;
sd.SampleDesc.Quality = 0;
sd.Windowed = TRUE;
 
// and then the swap chain
pFactory->CreateSwapChain (pd3dDevice, &sd, &pSwapChain);
 
// Get the back buffer of the swap chain …
ID3D10Texture2D *pBackBuffer;
hr = pSwapChain->GetBuffer( 0, __uuidof( ID3D10Texture2D ), (LPVOID*)&pBackBuffer );
 
if( FAILED(hr) )
    return hr;
 
// Create a render target view
 
hr = pd3dDevice->CreateRenderTargetView( pBackBuffer, NULL, &pRenderTargetView );
 
pBackBuffer->Release();
 
if( FAILED(hr) )
    return hr;
 
pd3dDevice->OMSetRenderTargets( 1, &pRenderTargetView, NULL );
 
// finaly set the viewport as it is empty on a new device
D3D10_VIEWPORT vp;
vp.Width = width;
vp.Height = height;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
pd3dDevice->RSSetViewports( 1, &vp );

As a shortcut you can create the device and swap chain together with one call. But Even then you have to attach the back buffer as render target by your own.

DXGI_SWAP_CHAIN_DESC sd;
ZeroMemory( &sd, sizeof(sd) );
sd.BufferCount = 1;
sd.BufferDesc.Width = width;
sd.BufferDesc.Height = height;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.BufferDesc.RefreshRate.Numerator = 60;
sd.BufferDesc.RefreshRate.Denominator = 1;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.OutputWindow = hWnd;
sd.SampleDesc.Count = 1;
sd.SampleDesc.Quality = 0;
sd.Windowed = TRUE;
 
// device and swap chain created together
 
hr = D3D10CreateDeviceAndSwapChain( NULL, D3D10_DRIVER_TYPE_HARDWARE, NULL, 0, D3D10_SDK_VERSION, &sd, &pSwapChain, &pd3dDevice );

Resources

Like every Direct3D 10 device implements the DXGI device interface there is a DXGI resource interface. Its main purpose is to manage the eviction priority for low memory situations and give access to the shared handle if any.

Personal tools