Using Devices with the Sample Framework
Microsoft DirectX 9.0 SDK Update (October 2004)

Using Devices with the Sample Framework


Microsoft DirectX device creation is streamlined with the sample framework. You can instead have your application create a device directly and other features of the framework will still be available.

Creating a Device

You would typically create a device with the standard Microsoft Direct3D method, IDirect3D9::CreateDevice:

HRESULT CreateDevice(
    UINT                  Adapter,
    D3DDEVTYPE            DeviceType,
    HWND                  hFocusWindow,
    DWORD                 BehaviorFlags,
    D3DPRESENT_PARAMETERS *pPresentationParameters,
    IDirect3DDevice9      **ppReturnedDeviceInterface
);

This method requires a valid adapter, device type (hardware abstraction layer (HAL) or reference), window handle, behavior flags (software/hardware vertex processing and other driver flags), and presentation parameters. Furthermore, the D3DPRESENT_PARAMETERS structure has numerous members that specify back buffer settings, multisampling settings, swap effects, windowed mode, depth-stencil buffer settings, refresh rate, presentation interval, and presentation flags.

Selecting valid settings for all of these parameters can be challenging. The framework simplifies this selection process with the DXUTCreateDevice function:

HRESULT DXUTCreateDevice(
    UINT AdapterOrdinal  = D3DADAPTER_DEFAULT,
    BOOL bWindowed       = TRUE,
    INT nSuggestedWidth  = 640,
    INT nSuggestedHeight = 480,
    LPDXUTCALLBACKISDEVICEACCEPTABLE pCallbackIsDeviceAcceptable     = NULL,
    LPDXUTCALLBACKMODIFYDEVICESETTINGS pCallbackModifyDeviceSettings = NULL
);

The most basic usage is simply to call the function using the default parameters:

DXUTCreateDevice();

With this simple call, the framework creates a device with default settings that should work for most cases. The default device creation settings are as follows:

DXUTMatchOptions MemberDirect3D Creation FlagDescription         Default Value from DXUTCreateDevice
eAdapterOrdinalAdapter parameter of IDirect3D9::CreateDeviceDisplay adapter ordinal.D3DADAPTER_DEFAULT
eDeviceTypeDeviceType parameter of IDirect3D9::CreateDeviceEnumerated type of the device.D3DDEVTYPE_HAL if available, otherwise D3DDEVTYPE_REF or failure code if neither is available.
eWindowedD3DPRESENT_PARAMETERS. WindowedWindowed or full-screen mode.TRUE, indicating windowed mode.
eAdapterFormatAdapterFormat parameter of IDirect3D9::CheckDeviceFormatAdapter surface format.Desktop display mode, or D3DFMT_X8R8G8B8 if the desktop display mode is less than 32 bits.
eVertexProcessingBehaviorFlags parameter of IDirect3D9::CreateDeviceVertex processing flags.D3DCREATE_HARDWARE_VERTEXPROCESSING if supported, otherwise D3DCREATE_SOFTWARE_VERTEXPROCESSING.
eResolutionD3DPRESENT_PARAMETERS. BackBufferWidth and .BackBufferHeightDisplay mode resolution.640 x 480 pixels for windowed mode, or the desktop resolution for full-screen mode.
eBackBufferFormatD3DPRESENT_PARAMETERS. BackBufferFormatBack buffer format.Desktop display mode, or D3DFMT_X8R8G8B8 if the desktop display mode is less than 32 bits.
eBackBufferCountD3DPRESENT_PARAMETERS. BackBufferCountNumber of back buffers.2, indicating triple buffering.
eMultiSampleD3DPRESENT_PARAMETERS. MultiSampleQualityQuality level.MultiSampleQuality = 0, indicating multisampling is disabled.
eSwapEffectD3DPRESENT_PARAMETERS. SwapEffectSwap effect.D3DSWAPEFFECT_DISCARD
eDepthFormatD3DPRESENT_PARAMETERS. AutoDepthStencilFormatDepth format of the automatic depth-stencil surface that the device will create.D3DFMT_D16 if the backbuffer format is 16 bits or less, or D3DFMT_D32 otherwise.
eStencilFormatD3DPRESENT_PARAMETERS. AutoDepthStencilFormatStencil format of the automatic depth-stencil surface that the device will create.D3DFMT_D16 if the backbuffer format is 16 bits or less, or D3DFMT_D32 otherwise.
ePresentFlagsD3DPRESENT_PARAMETERS. FlagsPresentation parameters flags.D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
eRefreshRateD3DPRESENT_PARAMETERS. FullScreen_RefreshRateInHzRate at which the display adapter refreshes the screen.0, indicating windowed mode.
ePresentIntervalD3DPRESENT_PARAMETERS. PresentationIntervalPresentation interval.D3DPRESENT_INTERVAL_IMMEDIATE for windowed mode, or D3DPRESENT_INTERVAL_DEFAULT for full-screen mode.
-hFocusWindow parameter of IDirect3D9::CreateDeviceHandle to the created window (see Using Application Windows with the Sample Framework).hWndFocus parameter of DXUTSetWindow
-D3DPRESENT_PARAMETERS. hDeviceWindowHandle to the device window.hWndDeviceFullScreen or hWndDeviceWindowed parameters of DXUTSetWindow
-D3DPRESENT_PARAMETERS. EnableAutoDepthStencilDepth-stencil buffer creation flag.TRUE.

Rather than just using a device created with these defaults, the application can apply more control of device creation through the parameters passed to IDirect3D9::CreateDevice. For example, you can change the window size through the nSuggestedWidth and nSuggestedHeight parameters:

DXUTCreateDevice(
    D3DADAPTER_DEFAULT,
    FALSE,
    1024,
    786,
    NULL,
    NULL
);

For even more control, the application can use the two optional callback functions, LPDXUTCALLBACKISDEVICEACCEPTABLE and LPDXUTCALLBACKMODIFYDEVICESETTINGS.

Choosing the Best Device Settings

You can use the IsDeviceAcceptable callback function in your application to help the framework choose the best device settings for the application, as in the following code:

BOOL CALLBACK IsDeviceAcceptable(
D3DCAPS9      *pCaps,
D3DFORMAT     AdapterFormat,
D3DFORMAT     BackBufferFormat,
BOOL          bWindowed )
{
    // TODO: return TRUE for acceptable settings and FALSE otherwise.
    return TRUE;
}

This callback function is modeled on the prototype LPDXUTCALLBACKISDEVICEACCEPTABLE. The framework calls this function once for each unique valid combination of the following five settings:

D3DDEVTYPE DeviceType;
UINT       AdapterOrdinal;
D3DFORMAT  AdapterFormat;
D3DFORMAT  BackBufferFormat;
BOOL       Windowed;

Note that the adapter ordinal and device type are not passed directly into the callback function, but are, respectively, the DeviceType and AdapterOrdinal members of the D3DCAPS9 structure.

Within this callback function the application can reject any combination that it does not support or want. As an example, the application can use the following code to reject 16-bit back buffer formats and all devices that do not support at least pixel shader ps_2_0:

BOOL CALLBACK IsDeviceAcceptable(
D3DCAPS9      *pCaps,
D3DFORMAT     AdapterFormat,
D3DFORMAT     BackBufferFormat,
BOOL          bWindowed )
{
    if( pCaps->PixelShaderVersion < D3DPS_VERSION(2,0) )
	return FALSE;
    if( BackBufferFormat == D3DFMT_X1R5G5B5
	    || BackBufferFormat == D3DFMT_R5G6B5 )
	return FALSE;
    return TRUE;
}

After the callback function is called for every unique combination of settings, the framework ranks the remaining acceptable combinations and chooses the best among them. Higher rankings are given to combinations that include the following:

With the highest-ranked combination of these settings chosen, the behavior flags and presentation parameters are still needed to create the device. For these settings, Direct3D uses the defaults as shown in the table above.

Modifying Available Device Settings

The application can modify the choices available to the framework by using an optional second callback function ModifyDeviceSettings similar to the following:

void CALLBACK ModifyDeviceSettings(
    DXUTDeviceSettings *pDeviceSettings,
    const D3DCAPS9     *pCaps )
{
    // TODO: Include device creation requirements here
}

This callback function is modeled on the prototype LPDXUTCALLBACKMODIFYDEVICESETTINGS. The DXUTDeviceSettings structure is defined by the framework as follows:

struct DXUTDeviceSettings
{
    UINT       AdapterOrdinal;
    D3DDEVTYPE DeviceType;
    D3DFORMAT  AdapterFormat;
    DWORD      BehaviorFlags;
    D3DPRESENT_PARAMETERS pp;
};

This structure contains everything needed to create a device except the window handle, which is assumed to be the handle to the window created earlier. The framework fills this structure with valid values, and then allows the application to change device creation choices through the ModifyDeviceSettings callback function.

In this callback function the application can change the behavior flags as well as the presentation parameters in the DXUTDeviceSettings structure, as well as anything else in the structure. If the application does not change anything in the callback function, the device will be created successfully. However, any device creation setting changed by the application needs to be supported by the device, otherwise device creation will likely fail.

For example, if the application needs a depth-stencil format of D3DFMT_D24S8, it should verify that the device supports it, as in the following code:

void CALLBACK ModifyDeviceSettings(
    DXUTDeviceSettings *pDeviceSettings,
    const D3DCAPS9     *pCaps )
{
    IDirect3D9* pD3D = DXUTGetD3DObject();
    if( SUCCEEDED( pD3D->CheckDeviceFormat(
	pDeviceSettings->AdapterOrdinal,
	pDeviceSettings->DeviceType,
	pDeviceSettings->AdapterFormat,
	D3DUSAGE_DEPTHSTENCIL,
	D3DRTYPE_SURFACE,
	D3DFMT_D24S8 ) ) )
    {
	if( SUCCEEDED( pD3D->CheckDepthStencilMatch(
	pDeviceSettings->AdapterOrdinal,
	pDeviceSettings->DeviceType,
	pDeviceSettings->AdapterFormat,
	pDeviceSettings->pp.BackBufferFormat,
	D3DFMT_D24S8 ) ) )
	{
	    pDeviceSettings->pp.AutoDepthStencilFormat = D3DFMT_D24S8;
	}
    }
}

Alternately, the callback function could use the framework's CD3DEnumeration object to verify whether D3DFMT_D24S8 is supported:

void CALLBACK ModifyDeviceSettings(
    DXUTDeviceSettings *pDeviceSettings,
    const D3DCAPS9     *pCaps )
{
    CD3DEnumeration *pEnum = DXUTGetEnumeration();
    CD3DEnumDeviceSettingsCombo *pCombo;
	
    pCombo = pEnum->GetDeviceSettingsCombo( pDeviceSettings );
	
    if( pCombo->depthStencilFormatList.Contains( D3DFMT_D24S8 ) )
    pDeviceSettings->pp.AutoDepthStencilFormat = D3DFMT_D24S8;
}

After the application modifies the device settings, the framework creates the device with those new settings.

Using Your Own Device

You do not have to rely on the framework to create the Direct3D device. Instead, the application itself can create the device and pass it to the framework to use, similar to the way the application can override the framework's window creation settings. Simply create a device with all desired settings, and then call the DXUTSetDevice function to enable the framework to render on the device.

Note  If the application creates the device independent of the framework, the application must also release the device interface upon cleanup after main loop execution is complete.

Related Topics



© 2004 Microsoft Corporation. All rights reserved.
Feedback? Please provide us with your comments on this topic.
For more help, visit the DirectX Developer Center.