Creating the Direct3D Device

The CreateDevice function creates an instance of the Direct3D device we chose earlier, using the specified width and height.

This function handles all aspects of the device creation, including choosing the surface-memory type, creating the device surface, creating the z-buffer (if necessary), and attaching the palette (if required). If you create a z-buffer, you must do so before creating an IDirect3DDevice interface.

static HRESULT 
CreateDevice(DWORD dwWidth, DWORD dwHeight) 
{ 
    LPD3DDEVICEDESC lpd3dDeviceDesc; 
    DWORD           dwDeviceMemType; 
    DWORD           dwZBufferMemType; 
    DDSURFACEDESC   ddsd; 
    HRESULT         hRes; 
    DWORD           dwZBufferBitDepth; 
 
    ASSERT(NULL != lpdd); 
    ASSERT(NULL != lpd3d); 
    ASSERT(NULL != lpddPrimary); 
    ASSERT(NULL == lpddDevice); 
    ASSERT(NULL == lpd3dDevice); 
 
    // Determine the kind of memory (system or video) from which the 
    // device surface should be allocated. 
 
    if (0 != d3dHWDeviceDesc.dcmColorModel) 
    { 
        lpd3dDeviceDesc = &d3dHWDeviceDesc; 
 
        // Device has a hardware rasterizer. Currently this means that 
        // the device surface must be in video memory. 
 
        dwDeviceMemType  = DDSCAPS_VIDEOMEMORY; 
        dwZBufferMemType = DDSCAPS_VIDEOMEMORY; 
    } 
    else 
    { 
        lpd3dDeviceDesc = &d3dSWDeviceDesc; 
 
        // Device has a software rasterizer. We will let DirectDraw 
        // decide where the device surface resides unless we are 
        // running in debug mode, in which case we will force it into 
        // system memory. For a software rasterizer the z-buffer should 
        // always go into system memory. A z-buffer in video memory will 
        // seriously degrade the application's performance. 
 
        dwDeviceMemType  = (fDebug ? DDSCAPS_SYSTEMMEMORY : 0); 
        dwZBufferMemType = DDSCAPS_SYSTEMMEMORY; 
    } 
 
    // Create the device surface. The pixel format will be identical 
    // to that of the primary surface, so we don't have to explicitly 
    // specify it. We do need to explicitly specify the size, memory 
    // type and capabilities  of the surface. 
 
    ZeroMemory(&ddsd, sizeof(ddsd)); 
    ddsd.dwSize         = sizeof(ddsd); 
    ddsd.dwFlags        = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; 
    ddsd.dwWidth        = dwWidth; 
    ddsd.dwHeight       = dwHeight; 
    ddsd.ddsCaps.dwCaps = DDSCAPS_3DDEVICE | DDSCAPS_OFFSCREENPLAIN | 
                          dwDeviceMemType; 
    hRes = lpdd->lpVtbl->CreateSurface(lpdd, &ddsd, &lpddDevice, NULL); 
    if (FAILED(hRes)) 
        return hRes; 
 
    // If we have created a palette, we have already determined that 
    // the primary surface (and hence the device surface) is palettized. 
    // Therefore, we should attach the palette to the device surface. 
    // (The palette is already attached to the primary surface.) 
 
    if (NULL != lpddPalette) 
    { 
        hRes = lpddDevice->lpVtbl->SetPalette(lpddDevice, lpddPalette); 
        if (FAILED(hRes)) 
            return hRes; 
    } 
 
    // We now determine whether or not we need a z-buffer and, if 
    // so, its bit depth. 
 
    if (0 != lpd3dDeviceDesc->dwDeviceZBufferBitDepth) 
    { 
        // The device supports z-buffering. Determine the depth. We 
        // select the lowest supported z-buffer depth to save memory. 
        // (Accuracy is not too important for this sample.) 
 
        dwZBufferBitDepth = 
            FlagsToBitDepth(lpd3dDeviceDesc->dwDeviceZBufferBitDepth); 
 
        // Create the z-buffer. 
 
        ZeroMemory(&ddsd, sizeof(ddsd)); 
        ddsd.dwSize            = sizeof(ddsd); 
        ddsd.dwFlags           = DDSD_CAPS   | 
                                 DDSD_WIDTH  | 
                                 DDSD_HEIGHT | 
                                 DDSD_ZBUFFERBITDEPTH; 
        ddsd.ddsCaps.dwCaps    = DDSCAPS_ZBUFFER | dwZBufferMemType; 
        ddsd.dwWidth           = dwWidth; 
        ddsd.dwHeight          = dwHeight; 
        ddsd.dwZBufferBitDepth = dwZBufferBitDepth; 
        hRes = lpdd->lpVtbl->CreateSurface(lpdd, &ddsd, &lpddZBuffer, 
                                           NULL); 
        if (FAILED(hRes)) 
            return hRes; 
 
                // Attach it to the rendering target. 
 
        hRes = lpddDevice->lpVtbl->AddAttachedSurface(lpddDevice, 
                                                      lpddZBuffer); 
        if (FAILED(hRes)) 
            return hRes; 
    } 
 
    // Now all the elements are in place: the device surface is in the 
    // correct memory type; a z-buffer has been attached with the 
    // correct depth and memory type; and a palette has been attached, 
    // if necessary. Now we can query for the Direct3D device we chose 
    // earlier. 
 
    hRes = lpddDevice->lpVtbl->QueryInterface(lpddDevice, 
                                   &guidDevice, &lpd3dDevice); 
    if (FAILED(hRes)) 
        return hRes; 
 
    return DD_OK; 
}