【Direct3D の初期化について】

ここでは、"GameMain.cpp "内のInitialize3DEnvironment 関数について、解説を行う。
HRESULT Initialize3DEnvironment(HWND hWnd)
{
    HRESULT hr;

    D3DAdapterInfo* pAdapterInfo = &g_Adapters[g_dwAdapter];
    D3DDeviceInfo*  pDeviceInfo  = &pAdapterInfo->devices[pAdapterInfo->dwCurrentDevice];
    D3DModeInfo*    pModeInfo    = &pDeviceInfo->modes[pDeviceInfo->dwCurrentMode];

    // Prepare window for possible windowed/fullscreen change

    // Set up the presentation parameters
    ZeroMemory( &g_d3dprm, sizeof(g_d3dprm) );
    g_d3dprm.Windowed               = pDeviceInfo->bWindowed;
    g_d3dprm.BackBufferCount        = 1;
    g_d3dprm.MultiSampleType        = pDeviceInfo->MultiSampleType;
    g_d3dprm.SwapEffect             = D3DSWAPEFFECT_DISCARD;
    g_d3dprm.EnableAutoDepthStencil = g_bUseDepthBuffer;
    g_d3dprm.AutoDepthStencilFormat = pModeInfo->DepthStencilFormat;
    g_d3dprm.hDeviceWindow          = hWnd;
    if( g_d3dprm.Windowed )
    {
        g_d3dprm.BackBufferWidth  = g_rcWindowClient.right - g_rcWindowClient.left;
        g_d3dprm.BackBufferHeight = g_rcWindowClient.bottom - g_rcWindowClient.top;
        g_d3dprm.BackBufferFormat = pAdapterInfo->d3ddmDesktop.Format;
		g_bWindowed = true;
	}
    else
    {
        g_d3dprm.BackBufferWidth  = pModeInfo->Width;
        g_d3dprm.BackBufferHeight = pModeInfo->Height;
        g_d3dprm.BackBufferFormat = pModeInfo->Format;
		g_bWindowed = false;
    }

    // Create the device
    hr = g_lpD3D->CreateDevice( g_dwAdapter, pDeviceInfo->DeviceType,
                               hWnd, pModeInfo->dwBehavior, &g_d3dprm,
                               &g_lpD3DDEV );
    if( SUCCEEDED(hr) ){
        if( g_bWindowed )
        {
            SetWindowPos( hWnd, HWND_NOTOPMOST,
                          g_rcWindowBounds.left, g_rcWindowBounds.top,
                          ( g_rcWindowBounds.right - g_rcWindowBounds.left ),
                          ( g_rcWindowBounds.bottom - g_rcWindowBounds.top ),
                          SWP_SHOWWINDOW );
        }
        hr = InitDeviceObjects();
        if( SUCCEEDED(hr) ){
            hr = RestoreDeviceObjects();
            if( SUCCEEDED(hr) ){
                g_bReady = TRUE;
                return S_OK;
            }
        }

        // Cleanup before we try again
        InvalidateDeviceObjects();
        DeleteDeviceObjects();
        SAFE_RELEASE( g_lpD3DDEV );
		return	hr;
	}

    // If that failed, fall back to the reference rasterizer
    if( pDeviceInfo->DeviceType == D3DDEVTYPE_HAL )
    {
        g_dwAdapter = 0L;
        pAdapterInfo = &g_Adapters[g_dwAdapter];

        // Look for a software device
        for( UINT i=0L; idwNumDevices; i++ )
        {
            if( pAdapterInfo->devices[i].DeviceType == D3DDEVTYPE_REF )
            {
                pAdapterInfo->dwCurrentDevice = i;
                pDeviceInfo = &pAdapterInfo->devices[i];
                        g_bWindowed = pDeviceInfo->bWindowed;
                break;
            }
        }

        // Try again, this time with the reference rasterizer
        if( pAdapterInfo->devices[pAdapterInfo->dwCurrentDevice].DeviceType ==
            D3DDEVTYPE_REF )
        {
            hr = Initialize3DEnvironment(hWnd);
        }
    }
    return hr;
}


冒頭部分つまり、下のリストの部分は、クラス CDeviceInformation の所で解説している
典型的な初期化とほぼ同様の処理である。

    D3DAdapterInfo* pAdapterInfo = &g_Adapters[g_dwAdapter];
    D3DDeviceInfo*  pDeviceInfo  = &pAdapterInfo->devices[pAdapterInfo->dwCurrentDevice];
    D3DModeInfo*    pModeInfo    = &pDeviceInfo->modes[pDeviceInfo->dwCurrentMode];

    // Prepare window for possible windowed/fullscreen change

    // Set up the presentation parameters
    ZeroMemory( &g_d3dprm, sizeof(g_d3dprm) );
    g_d3dprm.Windowed               = pDeviceInfo->bWindowed;
    g_d3dprm.BackBufferCount        = 1;
    g_d3dprm.MultiSampleType        = pDeviceInfo->MultiSampleType;
    g_d3dprm.SwapEffect             = D3DSWAPEFFECT_DISCARD;
    g_d3dprm.EnableAutoDepthStencil = g_bUseDepthBuffer;
    g_d3dprm.AutoDepthStencilFormat = pModeInfo->DepthStencilFormat;
    g_d3dprm.hDeviceWindow          = hWnd;
    if( g_d3dprm.Windowed )
    {
        g_d3dprm.BackBufferWidth  = g_rcWindowClient.right - g_rcWindowClient.left;
        g_d3dprm.BackBufferHeight = g_rcWindowClient.bottom - g_rcWindowClient.top;
        g_d3dprm.BackBufferFormat = pAdapterInfo->d3ddmDesktop.Format;
		g_bWindowed = true;
	}
    else
    {
        g_d3dprm.BackBufferWidth  = pModeInfo->Width;
        g_d3dprm.BackBufferHeight = pModeInfo->Height;
        g_d3dprm.BackBufferFormat = pModeInfo->Format;
		g_bWindowed = false;
    }

    // Create the device
    hr = g_lpD3D->CreateDevice( g_dwAdapter, pDeviceInfo->DeviceType,
                               hWnd, pModeInfo->dwBehavior, &g_d3dprm,
                               &g_lpD3DDEV );




次の部分は、デバイス構築(CreateDevice)に成功したあとの処理である。

    if( SUCCEEDED(hr) ){
        if( g_bWindowed )
        {
            SetWindowPos( hWnd, HWND_NOTOPMOST,
                          g_rcWindowBounds.left, g_rcWindowBounds.top,
                          ( g_rcWindowBounds.right - g_rcWindowBounds.left ),
                          ( g_rcWindowBounds.bottom - g_rcWindowBounds.top ),
                          SWP_SHOWWINDOW );
        }

ここで行っているのは、まず、Window 位置の調整。

続いて、
        hr = InitDeviceObjects();
        if( SUCCEEDED(hr) ){
            hr = RestoreDeviceObjects();
            if( SUCCEEDED(hr) ){
                g_bReady = TRUE;
                return S_OK;
            }
        }

この処理は若干説明が必要と思われる。

Windows はマルチタスクOSである。
ゲームでも複数のゲームを同時に起動する事ができてしまう。

ところが、デバイス(ビデオカード)は通常一枚だけしかない。
複数のゲームのぶんのテクスチャーやその他のデータを置いておく余裕は無い 事が多い。

さてどうするのか?

というと、バックグラウンドにいるアプリケーションからは、 デバイスの使用権を剥ぎ取り、ユーザーに見えているアプリケーションだけに使わせる・・・

ということをしている。

具体的には、デバイスの使用権に依存したオブジェクト(主にテクスチャー)
を、本筋の初期化とは別に行い、以下の処理を用意します。


これが判ると、以下の話がわかるはずだ。

それぞれの関数は、以下の処理を行っている。
InitDeviceObject();デバイス使用権依存オブジェクトの構築
RestoreDeviceObject();デバイス使用権依存オブジェクトの再構築

具体的には以下の処理が行われている。

InitDeviceObject();RestoreDeviceObject() を行うのに必要なメインメモリ上のデータを構築する。
RestoreDeviceObject();実際のビデオメモリ上のデータを構築する。



【InitDeviceObjects 関数】

HRESULT	InitDeviceObjects()
{
	return	S_OK;
}

現在の所空っぽである。



【RestoreDeviceObjects 関数】

HRESULT	RestoreDeviceObjects()
{
    LPDIRECT3DSURFACE8 pBackBuffer;
    g_lpD3DDEV->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer );
    pBackBuffer->GetDesc( &g_d3dsdBackBuffer );
    pBackBuffer->Release();

	return	S_OK;
}

このバージョンでは、オフスクリーンサーフェイスのフォーマットを取得しているだけである。