Selecting An Enumerated Device

The D3DEnumDevicesCallback function is invoked for each Direct3D device installed on the system. When it is called, its first parameter is a globally unique ID (GUID) for the device that is being enumerated. The value of the GUID will be IID_IDirect3DHALDevice, IID_IDirect3DMMXDevice, IID_IDirect3DRGBDevice, or IID_IDirect3DRampDevice. The D3DEnumDevicesCallback function selects the device that is most appropriate for your application based on this information.

The second and third parameters to the D3DEnumDevicesCallback function are text strings containing the name and user-friendly description of the device.

The fourth parameter is a pointer to a D3DDEVICEDESC structure containing information about the hardware capabilities of the device. Even if the device being enumerated is a HAL device, the particular hardware may not support all of the capabilities that the Direct3D API allows.

The fifth parameter to the D3DEnumDevicesCallback function contains a pointer to a D3DDEVICEDESC structure that describes the software-emulated capabilities of the computer on which your application is running. This information is relevant when you are using a software-emulated device (MMX, RGB, or RAMP device).

The last parameter is a programmer-defined value. Your application passes this value to the IDirect3D3::EnumDevices method. It in turn passes this value to the D3DEnumDevicesCallback function.

The following code fragment illustrates how to create a D3DEnumDevicesCallback function. In this example, the application-supplied callback function is named EnumDeviceCallback. The EnumDeviceCallback function uses the following algorithm to choose an appropriate Direct3D device:

  1. Discard any devices which don't match the current display depth.
  2. Discard any devices which can't do Gouraud-shaded triangles.
  3. If a hardware device is found which matches points 1 and 2, use it. However, if the application is running in debug mode, it will not use the hardware device.
  4. Otherwise favor Mono/Ramp mode software renderers over RGB ones; until MMX is widespread, Mono will be faster.

The code for the EnumDeviceCallback function is shown in the following example:

// This function is written with the assumption that the following
// global variables are declared in the program.
// DWORD                   dwDeviceBitDepth          = 0; 
// GUID                    guidDevice; 
// char                    szDeviceName[MAX_DEVICE_NAME]; 
// char                    szDeviceDesc[MAX_DEVICE_DESC]; 
// D3DDEVICEDESC           d3dHWDeviceDesc; 
// D3DDEVICEDESC           d3dSWDeviceDesc; 
 
static HRESULT WINAPI 
EnumDeviceCallback(LPGUID          lpGUID, 
                   LPSTR           lpszDeviceDesc, 
                   LPSTR           lpszDeviceName, 
                   LPD3DDEVICEDESC lpd3dHWDeviceDesc, 
                   LPD3DDEVICEDESC lpd3dSWDeviceDesc, 
                   LPVOID          lpUserArg) 
{ 
    BOOL            fIsHardware; 
    LPD3DDEVICEDESC lpd3dDeviceDesc; 
 
    // If there is no hardware support the color model is zero. 
 
    fIsHardware     = (lpd3dHWDeviceDesc->dcmColorModel != 0); 
    lpd3dDeviceDesc = (fIsHardware ? lpd3dHWDeviceDesc : 
                                     lpd3dSWDeviceDesc); 
 
    // Does the device render at the depth we want? 
     if ((lpd3dDeviceDesc->dwDeviceRenderBitDepth & dwDeviceBitDepth) 
        == 0) 
    { 
        // If not, skip this device. 
 
        return D3DENUMRET_OK; 
    } 
 
    // The device must support Gouraud-shaded triangles. 
 
    if (D3DCOLOR_MONO == lpd3dDeviceDesc->dcmColorModel) 
    { 
        if (!(lpd3dDeviceDesc->dpcTriCaps.dwShadeCaps & 
              D3DPSHADECAPS_COLORGOURAUDMONO)) 
        { 
            // No Gouraud shading. Skip this device. 
 
            return D3DENUMRET_OK; 
        } 
    } 
    else 
    { 
        if (!(lpd3dDeviceDesc->dpcTriCaps.dwShadeCaps & 
              D3DPSHADECAPS_COLORGOURAUDRGB)) 
        { 
            // No Gouraud shading. Skip this device. 
 
            return D3DENUMRET_OK; 
        } 
    } 
 
    // If a software device was found on a previous invocation
    // of this callback function.
    if (!fIsHardware && *lpUserArg && 
           (D3DCOLOR_RGB == lpd3dDeviceDesc->dcmColorModel)) 
    { 
        // If this is software RGB and we already have found 
        // a software monochromatic renderer, we are not 
        // interested. Skip this device. 
 
        return D3DENUMRET_OK; 
    } 
 
    //
    // This is a device we are interested in. Save the details. 
    //
    *lpUserArg = TRUE; 
    CopyMemory(&guidDevice, lpGUID, sizeof(GUID)); 
    strcpy(szDeviceDesc, lpszDeviceDesc); 
    strcpy(szDeviceName, lpszDeviceName); 
    CopyMemory(&d3dHWDeviceDesc, lpd3dHWDeviceDesc, 
               sizeof(D3DDEVICEDESC)); 
    CopyMemory(&d3dSWDeviceDesc, lpd3dSWDeviceDesc, 
               sizeof(D3DDEVICEDESC)); 
 
    // If this is a hardware device, we have found 
    // what we are looking for. 
     if (fIsHardware) 
        return D3DENUMRET_CANCEL; 
 
    // Otherwise, keep looking. 
 
    return D3DENUMRET_OK; 
}