Direct3D11 の初期化と終了

(VS2012)プロジェクトをダウンロード



ウィンドウを生成してWindowsアプリケーションを初期化したら、
Direct3Dを初期化します。具体的には5つのオブジェクトを生成します。
これらのオブジェクトが生成できたら、とりあえずDirect3Dが使用可能になります。

【DX11_Init.cpp】

//----------------------------------------------------------
//
//  Application
//    DX11_Init
//
//  First Edition : October 21 2016
//  Author Mr.K
//
#include "stdafx.h"
#include <stdio.h>
#include <crtdbg.h>
#include <D3D11.h>
#include <directxmath.h>
#include <D3Dcompiler.h>

using namespace DirectX;

//  import libraries
#pragma comment(lib,"d3d11.lib")
#pragma comment(lib,"d3dcompiler.lib")

#define MAX_LOADSTRING 100

#define SAFE_DELETE(o)       if (o){  delete (o);  o = NULL;    }
#define SAFE_DELETE_ARRAY(o) if (o){  delete [] (o);  o = NULL; }
#define SAFE_RELEASE(o)      if (o){  (o)->Release(); o = NULL; }

//  Globals
TCHAR *g_pDriverType = NULL;
TCHAR *g_pFeatureLevel = NULL;
UINT  g_uiCount=0;

//
//  prototypes
//
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
HRESULT GetBackBufferSize(IDXGISwapChain *pSwapChain, DWORD *pWidth, DWORD *pHeight);
HRESULT CreateDepthStencilView(
    ID3D11Device *pDevice,
    INT          width,
    INT          height,
    DXGI_FORMAT  fmtDepthStencil,
    ID3D11DepthStencilView    **ppDepthStencilView,
    ID3D11Texture2D           **ppDepthStencilTexture,
    ID3D11ShaderResourceView  **ppDepthStencilShaderResourceView
);
HRESULT CreateRenderTargetView(
    ID3D11Device             *pDevice,
    IDXGISwapChain           *pSwapChain,
    ID3D11RenderTargetView   **ppRenderTargetView,
    ID3D11ShaderResourceView **ppRenderTargetShaderResourceView
);
HRESULT CreateDeviceContextAndSwapChain(
    HWND                  hWnd,
    ID3D11Device          **ppDevice,        
    ID3D11DeviceContext   **ppContext,    
    IDXGISwapChain        **ppSwapChain,
    D3D_DRIVER_TYPE       *pDriverType,
    D3D_FEATURE_LEVEL     *pFeatureLevel
);

TCHAR *GetDriverTypeText(D3D_DRIVER_TYPE dt);
TCHAR *GetFeatureLevelText(D3D_FEATURE_LEVEL fl);

//
//  WinMain
//  the entry point of windows application
//
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPTSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );

    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    MSG msg;

    //  変数宣言
    WNDCLASSEX wcex;  //  ウィンドウクラス構造体
    HWND hWnd;        //  ウィンドウハンドル
    RECT    bounds,client;  //  RECT 構造体

    //  (1)-a ウィンドウクラスの登録
    wcex.cbSize = sizeof(WNDCLASSEX); 
    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = (WNDPROC)WndProc;  //  ウィンドウプロシージャの登録
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;  //  アプリケーションインスタンス
    wcex.hIcon          = LoadIcon(NULL, MAKEINTRESOURCE(IDI_APPLICATION));
    wcex.hCursor        = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = NULL;
    wcex.lpszClassName  = _T("D3D11_Sprite");  //  ウィンドウクラス名
    wcex.hIconSm        = LoadIcon(NULL, IDI_APPLICATION);
    RegisterClassEx(&wcex);
 
    //  (1)-b ウィンドウの生成
    hWnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,wcex.lpszClassName,_T("D3D11_Sprite"),
                WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX,
                CW_USEDEFAULT,0,640,480,NULL,NULL,hInstance,NULL);
    if( !hWnd )
        return FALSE;

    //  ウィンドウサイズの調整
    //  ここは無くても動く
    GetWindowRect(hWnd,&bounds);
    GetClientRect(hWnd,&client);
    MoveWindow(hWnd,bounds.left,bounds.top,
        640 * 2 - client.right,
        480 * 2 - client.bottom,
        false );

    //  ウィンドウの再表示
    ShowWindow( hWnd, nCmdShow );
    UpdateWindow( hWnd );

    //==========Direct3D11 の初期化処理===================

    CoInitializeEx(NULL,COINIT_APARTMENTTHREADED);          //  COM を初期化

    D3D_DRIVER_TYPE DriverType = D3D_DRIVER_TYPE_NULL;

    ID3D11DeviceContext      *pContext = NULL;              //  描画環境
    ID3D11Device             *pDevice = NULL;               //  仮想アダプタ(ハードウエア)
    IDXGISwapChain           *pSwapChain = NULL;            //  スワップチェイン
    ID3D11RenderTargetView   *pRenderTargetView = NULL;     //  レンダーターゲット
    ID3D11DepthStencilView   *pDepthStencilView = NULL;     //  深度ステンシルバッファ

    ID3D11Texture2D          *pDepthStencilTexture = NULL;            //  深度ステンシルサーフェイス
    ID3D11ShaderResourceView *pRenderTargetShaderResourceView = NULL; //  RenderTargetを TextureSampler からアクセス可能にしておく
    ID3D11ShaderResourceView *pDepthStencilShaderResourceView = NULL; //  DepthStencilを TextureSampler からアクセス可能にしておく

    D3D_FEATURE_LEVEL    FeatureLevel;

    DWORD        width, height;     //  Screen width, Screen height
    HRESULT      hr;

    //  デバイス、デバイスコンテキストそしてスワップチェインを生成
    hr = CreateDeviceContextAndSwapChain(hWnd,&pDevice,&pContext,&pSwapChain,&DriverType,&FeatureLevel);
    if ( FAILED( hr ) )
        goto ERROR_EXIT;

    //  RenderTaget を生成
    hr = CreateRenderTargetView(pDevice,pSwapChain,&pRenderTargetView,&pRenderTargetShaderResourceView);
    if ( FAILED( hr ) )
        goto ERROR_EXIT;

    //  深度ステンシルバッファ生成のため Backbuffer のサイズを取得
    hr = GetBackBufferSize(pSwapChain,&width, &height);
    if ( FAILED( hr ) )
        goto ERROR_EXIT;

    //  サイズとフォーマットを指定して、深度ステンシルバッファを生成
    hr = CreateDepthStencilView(pDevice,width,height,DXGI_FORMAT_D16_UNORM,&pDepthStencilView,&pDepthStencilTexture,&pDepthStencilShaderResourceView);
    if ( FAILED( hr ) )
        goto ERROR_EXIT;

    //  デバイスコンテキストにレンダーターゲットと深度ステンシルを設定
    pContext->OMSetRenderTargets( 1, &pRenderTargetView,pDepthStencilView);

    // ビューポートの設定.
    D3D11_VIEWPORT vp;
    vp.Width    = (FLOAT)width;
    vp.Height   = (FLOAT)height;
    vp.MinDepth = 0.0f;
    vp.MaxDepth = 1.0f;
    vp.TopLeftX = 0;
    vp.TopLeftY = 0;

    // デバイスコンテキストにビューポートを設定.
    pContext->RSSetViewports( 1, &vp );

    //==========各種オブジェクト生成===================


    //=================================================

    // メイン メッセージ ループ:
    //  (2)メッセージループ
    FLOAT    fAngle = 0;
    while(true){
        if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)){
            if(msg.message == WM_QUIT)
                break;
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }else{
            // 指定色で画面クリア
            float ClearColor[4] = { 0.0f, 0.125f, 0.3f, 1.0f }; //red,green,blue,alpha
            pContext->ClearRenderTargetView( pRenderTargetView, ClearColor );
            pContext->ClearDepthStencilView( pDepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0 );

            g_uiCount++;
            //結果をウインドウに反映
            if (FAILED(hr = pSwapChain->Present( 1, 0 ))){
                //  デバイスロストへの対処は可能だが、ここでは単に終了する事にする
                if (hr == DXGI_ERROR_DEVICE_RESET || hr == DXGI_ERROR_DEVICE_REMOVED){
                    MessageBox(NULL,_T("Device が失われましたので終了します"),_T("Assert"),MB_OK);
                    break;
                }
            }
        }
    }

ERROR_EXIT:
    if (pContext){
        pContext->ClearState();
        pContext->Flush();
    }

    SAFE_RELEASE(pRenderTargetShaderResourceView);
    SAFE_RELEASE(pDepthStencilTexture);
    SAFE_RELEASE(pDepthStencilShaderResourceView);
    SAFE_RELEASE(pRenderTargetView);
    SAFE_RELEASE(pDepthStencilView);
    SAFE_RELEASE(pSwapChain);
    SAFE_RELEASE(pContext);
    SAFE_RELEASE(pDevice);

    CoUninitialize();    //  COM の終了

    return (int) msg.wParam;
}




//
//  関数:WndProc
//  説明:ウインドウに渡されたイベントのハンドラ
//
LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{

    switch (message){
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return    0;
}



【CreateDeviceContextAndSwapChain・・・デバイスとスワップチェインの生成】

Direct3D11 では、Device, DeviceContext, SwapChain の3つを同時に生成します。 以下のプログラムでは、ウィンドウのクライアント領域一杯に表示するよう、 Device, DeviceContext, SwapChain を生成します。それぞれ以下のような 役割を果たします
Device
ビデオカードなどのハードウェア固有の処理を抽象化したもの
DeviceContext
描画環境
SwapChain
表示用バッファ(テクスチャ)と描画用バッファの組み合わせ
//=============================================================================
//
//    Create DeviceContext and SwapChain
//    param :
//        hWnd : (in)window's handle
//        ppDevice : (out)created device
//        ppContext : (out)created device context
//        ppSwapChain : (out)swap chain
//        pDriverType : (out)device's driver type
//        pFeatureLevel : (out)device's feature level
//
HRESULT CreateDeviceContextAndSwapChain(
    HWND                hWnd,
    ID3D11Device        **ppDevice,        
    ID3D11DeviceContext    **ppContext,    
    IDXGISwapChain        **ppSwapChain,
    D3D_DRIVER_TYPE        *pDriverType,
    D3D_FEATURE_LEVEL    *pFeatureLevel
){
    HRESULT hr = E_FAIL;

    // デバイス生成フラグ.
    UINT createDeviceFlags = 0;

    // ドライバータイプ候補
    D3D_DRIVER_TYPE driverTypes[] = {
        D3D_DRIVER_TYPE_HARDWARE,
        D3D_DRIVER_TYPE_WARP,
        D3D_DRIVER_TYPE_REFERENCE,
    };
    UINT numDriverTytpes = sizeof( driverTypes ) / sizeof( driverTypes[0] );

    // 機能レベル候補
    static const D3D_FEATURE_LEVEL featureLevels[] = {
        D3D_FEATURE_LEVEL_11_0,
        D3D_FEATURE_LEVEL_10_1,
        D3D_FEATURE_LEVEL_10_0,
    };
    UINT numFeatureLevels = sizeof( featureLevels ) / sizeof( featureLevels[0] );
    RECT rc;
    GetClientRect( hWnd, &rc );
    UINT width = rc.right - rc.left;
    UINT height = rc.bottom - rc.top;

    // スワップチェインの構成設定.
    DXGI_SWAP_CHAIN_DESC sd;
    ZeroMemory( &sd, sizeof(DXGI_SWAP_CHAIN_DESC) );
    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 | DXGI_USAGE_SHADER_INPUT;
    sd.OutputWindow                         = hWnd;
    sd.SampleDesc.Count                     = 1;
    sd.SampleDesc.Quality                   = 0;
    sd.Windowed                             = TRUE;

    for( UINT idx = 0; idx < numDriverTytpes; ++idx ){
        // ドライバータイプ設定.
        D3D_DRIVER_TYPE DriverType = driverTypes[ idx ];
  
        // デバイスとスワップチェインの生成.
        hr = D3D11CreateDeviceAndSwapChain(
            NULL, 
            DriverType,
            NULL,
            createDeviceFlags,
            featureLevels,
            numFeatureLevels,
            D3D11_SDK_VERSION,
            &sd,
            ppSwapChain,
            ppDevice,
            pFeatureLevel,
            ppContext 
        );
        *pDriverType = DriverType;

        // 成功したらループを脱出.
        if ( SUCCEEDED( hr ) )
            break; 
    }
    return hr;
}



【CreateRenderTargetView・・・レンダーターゲットの生成】

SwapChain より RenderTargetView を作成し、描画用バッファに描画できるように 準備します。
当面使用しませんが、将来を見越して、描画用バッファのShaderResourceView も 用意しておきます。
//=============================================================================
//
//    Create Render Target
//    param :
//        pDevice    : (in)Direct3D device object
//        pSwapChain : (in)device's swap chain
//        ppRenderTargetView : (out)Created render target view
//        ppRenderTargetShaderResourceView : (out)render target's shader resource view
//
HRESULT CreateRenderTargetView(
    ID3D11Device        *pDevice,
    IDXGISwapChain        *pSwapChain,
    ID3D11RenderTargetView    **ppRenderTargetView,
    ID3D11ShaderResourceView    **ppRenderTargetShaderResourceView
){
    ID3D11Texture2D    *pBackBuffer = NULL;
    HRESULT hr = E_FAIL;

    //  スワップチェインよりバックバッファを取得.
    hr = pSwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), (LPVOID*)&pBackBuffer );
    if ( FAILED( hr ) )
        goto ERROR_EXIT;

    //    バックバッファより、レンダーターゲットを生成.
    hr = pDevice->CreateRenderTargetView( pBackBuffer, NULL, ppRenderTargetView );
    if ( FAILED( hr ) )
        goto ERROR_EXIT;

    // レンダーターゲットのシェーダリソースビューを生成.
    hr = pDevice->CreateShaderResourceView( pBackBuffer, NULL, ppRenderTargetShaderResourceView );
    if ( FAILED( hr ) )
        goto ERROR_EXIT;

ERROR_EXIT:
    SAFE_RELEASE(pBackBuffer);    //    バックバッファを開放

    return hr;
}



【CreateDepthStencilView・・・深度ステンシルバッファの生成】

指定されたサイズとフォーマットを使用して、深度ステンシルバッファを生成します。
将来を見越して、深度ステンシルバッファのShaderResoureceView も用意しておきます。
//=============================================================================
//
//    create depth-stencil view
//    param :
//        pDevice : (in)Direct3D device
//        width   : (in)screen width
//        height  : (in)screen height
//        fmtDepthStencil    : (in)depth stencil format.
//        ppDepthStencilView : (out)depth stencil buffer
//        ppDepthStencilTexture : (out)depth stencil surface texture
//        ppDepthStencilShaderResourceView : (out)depth-stencil's shader resource view
//        
HRESULT    CreateDepthStencilView(
    ID3D11Device        *pDevice,
    INT    width,
    INT height,
    DXGI_FORMAT fmtDepthStencil,
    ID3D11DepthStencilView        **ppDepthStencilView,
    ID3D11Texture2D                **ppDepthStencilTexture,
    ID3D11ShaderResourceView    **ppDepthStencilShaderResourceView
){
    DXGI_FORMAT textureFormat   = DXGI_FORMAT_R16_TYPELESS;
    DXGI_FORMAT resourceFormat  = DXGI_FORMAT_R16_UNORM;
    HRESULT hr = E_FAIL;

    //  深度ステンシルテクスチャとシェーダリソースビューのフォーマットを
    //  適切なものに変更.
    switch( fmtDepthStencil )
    {
    case DXGI_FORMAT_D16_UNORM:
        textureFormat  = DXGI_FORMAT_R16_TYPELESS;
        resourceFormat = DXGI_FORMAT_R16_UNORM;
        break;
  
    case DXGI_FORMAT_D24_UNORM_S8_UINT:
        textureFormat  = DXGI_FORMAT_R24G8_TYPELESS;
        resourceFormat = DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
        break;
  
    case DXGI_FORMAT_D32_FLOAT:
        textureFormat  = DXGI_FORMAT_R32_TYPELESS;
        resourceFormat = DXGI_FORMAT_R32_FLOAT;
        break;
  
    case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
        textureFormat  = DXGI_FORMAT_R32G8X24_TYPELESS;
        resourceFormat = DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
        break;
    default:
        hr = E_FAIL;
        goto ERROR_EXIT;
    }
  
    //    深度ステンシルテクスチャの生成.
    D3D11_TEXTURE2D_DESC td;
    ZeroMemory( &td, sizeof( D3D11_TEXTURE2D_DESC ) );
    td.Width                = width;
    td.Height               = height;
    td.MipLevels            = 1;
    td.ArraySize            = 1;
    td.Format               = textureFormat;
    td.SampleDesc.Count     = 1;    //    MULTI SAMPLE COUNT
    td.SampleDesc.Quality   = 0;    //    MULtI SAMPLE QUALITY
    td.Usage                = D3D11_USAGE_DEFAULT;
    td.BindFlags            = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE;
    td.CPUAccessFlags       = 0;
    td.MiscFlags            = 0;
  
    // 深度ステンシルテクスチャの生成.
    hr = pDevice->CreateTexture2D( &td, NULL, ppDepthStencilTexture );
    if ( FAILED( hr ) )
        goto ERROR_EXIT;
  
    // 深度ステンシルビューの設定.
    D3D11_DEPTH_STENCIL_VIEW_DESC dsvd;
    ZeroMemory( &dsvd, sizeof( D3D11_DEPTH_STENCIL_VIEW_DESC ) );
    dsvd.Format         = fmtDepthStencil;
    if ( td.SampleDesc.Count == 0 )
    {
        dsvd.ViewDimension      = D3D11_DSV_DIMENSION_TEXTURE2D;
        dsvd.Texture2D.MipSlice = 0;
    }
    else
    {
        dsvd.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS;
    }
  
    // 深度ステンシルビューの生成.
    hr = pDevice->CreateDepthStencilView( *ppDepthStencilTexture, &dsvd, ppDepthStencilView );
    if ( FAILED( hr ) )
    {
      goto ERROR_EXIT;
    }

    // シェーダリソースビューの設定.
    D3D11_SHADER_RESOURCE_VIEW_DESC srvd;
    ZeroMemory( &srvd, sizeof( D3D11_SHADER_RESOURCE_VIEW_DESC ) );
    srvd.Format                     = resourceFormat;
  
    if ( td.SampleDesc.Count == 0 )
    {
        srvd.ViewDimension              = D3D11_SRV_DIMENSION_TEXTURE2D;
        srvd.Texture2D.MostDetailedMip  = 0;
        srvd.Texture2D.MipLevels        = 1;
    }
    else
    {
        srvd.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMS;
    }
  
    // シェーダリソースビューを生成.
    hr = pDevice->CreateShaderResourceView( *ppDepthStencilTexture, &srvd, ppDepthStencilShaderResourceView );
    if ( FAILED( hr ) )
    { 
      goto ERROR_EXIT;
    }
ERROR_EXIT:
    return hr;
}



【GetBackBufferSize・・・バックバッファサイズの取得】

SwapChain より、バックバッファの幅と高さを取得します。
//=============================================================================
//
//    Get back-buffer size from swap chain
//    param :
//        pSwapChain : (in)swap chain
//        pWidth     : (out)back-buffer width
//        pHeight    : (out)back-buffer height]
//
HRESULT GetBackBufferSize(IDXGISwapChain *pSwapChain, DWORD *pWidth, DWORD *pHeight){
    ID3D11Texture2D    *pBackBuffer = NULL;
    HRESULT hr = E_FAIL;
    D3D11_TEXTURE2D_DESC desc;
    //  スワップチェインよりバックバッファを取得.
    hr = pSwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), 
                         (LPVOID*)&pBackBuffer );
    if ( FAILED( hr ) )
        goto ERROR_EXIT;
    pBackBuffer->GetDesc(&desc);

    *pWidth  = (DWORD)desc.Width;
    *pHeight = (DWORD)desc.Height;
    hr = S_OK;

ERROR_EXIT:
    SAFE_RELEASE(pBackBuffer);
    return hr;
}



【デバッグ用関数】

//=============================================================================
//
//  Debug utility
//  Get the name of driver type
//
TCHAR *GetDriverTypeText(D3D_DRIVER_TYPE dt){
    switch(dt){
    case    D3D_DRIVER_TYPE_UNKNOWN:
        return _T("D3D_DRIVER_TYPE_UNKNOWN");
    case    D3D_DRIVER_TYPE_HARDWARE:    
        return _T("D3D_DRIVER_TYPE_HARDWARE");
    case    D3D_DRIVER_TYPE_REFERENCE:
        return _T("D3D_DRIVER_TYPE_REFERENCE");
    case    D3D_DRIVER_TYPE_NULL:
        return _T("D3D_DRIVER_TYPE_NULL");
    case    D3D_DRIVER_TYPE_SOFTWARE:    
        return _T("D3D_DRIVER_TYPE_SOFTWARE");
    case    D3D_DRIVER_TYPE_WARP:        
        return _T("D3D_DRIVER_TYPE_WARP");
    }
    return NULL;
}

//=============================================================================
//
//  Debug utility
//  Get the name of feature level
//
TCHAR *GetFeatureLevelText(D3D_FEATURE_LEVEL fl){
    switch(fl){
    case    D3D_FEATURE_LEVEL_9_1:    
        return _T("D3D_FEATURE_LEVEL_9_1");
    case    D3D_FEATURE_LEVEL_9_2:    
        return _T("D3D_FEATURE_LEVEL_9_2");
    case    D3D_FEATURE_LEVEL_9_3:
        return _T("D3D_FEATURE_LEVEL_9_3");
    case    D3D_FEATURE_LEVEL_10_0:
        return _T("D3D_FEATURE_LEVEL_10_0");
    case    D3D_FEATURE_LEVEL_10_1:
        return _T("D3D_FEATURE_LEVEL_10_1");
    case    D3D_FEATURE_LEVEL_11_0:
        return _T("D3D_FEATURE_LEVEL_11_0");
    }
    return NULL;
}