[DirectX11] 2. 초기화 – 디바이스 객체들을 만들어 보자.

환경 구축를 통해서 프로젝트의 생성까지 모두 끝나고 빌드하면 다음과 같은 화면을 볼 수 있다.

빈 화면을 표시하는 윈도우

하지만 아직 DirectX를 통해 렌더링되는 화면은 아니다. 이제부터 DirectX11 API를 이용해 빈 화면을 우선 렌더링 해보도록 하자.


DirectX11 API를 이용하기 위해서 우선적으로 생성해야 하는 객체들이 있다. ID3D11Device, ID3D11DeviceContext, IDXGISwapChain 인터페이스 객체 3개가 필요하다. 편의상 이들을 통칭해서 디바이스 객체들이라고 하자. 이들은 렌더링에 필요한 리소스를 생성하고 렌더링 파이프라인에 연결하고 스크린 버퍼를 갱신하기 위한 객체들이라고 보면 된다.

각 디바이스 객체가 제공하는 인터페이스 함수들을 보면 대략적으로 어떤 역할들을 하는지 알 수 있다. 마이크로 소프트 공식 홈페이지에서 자세히 설명이 되어 있다. 일단은 간략하게 각 객체가 어떤 역할들을 하는지 알아보자.

ID3D11Device

ID3D11Device는 대체적으로 리소스나 쉐이더 객체등을 생성할 수 있는 함수들을 제공한다.

  • CreateBuffer, CreateTexture2D, CreateRenderTargetView, CreateVertexShader, CreateComputeShader

ID3D11DeviceContext

ID3D11DeviceContext는 렌더링 파이프라인에 리소스나 쉐이더를 연결하는 함수들을 제공한다. 함수들의 네이밍에 앞 2글자 ( IA, VS, HS등 )는 렌더링 파이프라인 스테이지의 약어이다.

  • IASetIndexBuffer, IASetInputLayout, VSSetConstantBuffers, HSSetSamplers, DSSetShader

IDXGISwapChain

IDXGISwapChain은 스크린 버퍼와 관련된 함수들을 제공한다.

  • Present, ResizeBuffers, SetFullscreenState

이 스왑 체인을 만들기 위해선 Description Structure를 통해서 어떤 스왑 체인을 만들지 결정을 해야 한다. 이는 DXGI_SWAP_CHAIN_DESC를 통해서 전달한다. 레퍼런스는 DXGI_SWAP_CHAIN_DESC에서 확인할 수 있다. 주로 버퍼의 갯수, 버퍼의 용도, 버퍼의 포맷등을 결정하게 된다.

디바이스 객체를 생성하는 코드는 다음과 같다.

C++
DXGI_SWAP_CHAIN_DESC scd;
ZeroMemory( &scd, sizeof( DXGI_SWAP_CHAIN_DESC ) );

scd.BufferCount = 1;
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
scd.OutputWindow = hWnd;
scd.SampleDesc.Count = 4;
scd.Windowed = True;

D3D11CreateDeviceAndSwapChain( nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, nullptr, nullptr, nullptr, D3D11_SDK_VERSION, &scd, &Swapchain, &Device, nullptr, &DeviceContext );

D3D11CreateDeviceAndSwapChain함수에 대한 레퍼런스는 D3D11CreateDeviceAndSwapChain에서 자세히 알 수 있다. 이 함수를 통해 3개의 객체를 모두 생성하면 이제 비로소 DirectX11 API를 이용하기 위한 준비가 끝난 것이다.


위에서 설명한 코드들을 가지고 클래스로 만들어보자.

C++
class CRD11Device  
{  
private:  
    ID3D11Device*        DevicePtr        = nullptr;  
    ID3D11DeviceContext* DeviceContextPtr = nullptr;  
    IDXGISwapChain*      SwapChainPtr     = nullptr;  

public:  
    /// Constructor  
    CRD11Device() = default;  

    /// Create Dx11 device ojects.  
    bool Create( HWND hWnd );  

    /// Get Dx11 device object.
    ID3D11Device* GetDevice() const { return DevicePtr; }  

    /// Get Dx11 device context object.  
    ID3D11DeviceContext* GetDeviceContext() const { return DeviceContextPtr; }  

    /// Get Dx11 swap chain object.  
    IDXGISwapChain* GetSwapChain() const { return SwapChainPtr; }  
};

Create에서 윈도우 핸들을 전달받아 객체들을 생성해준다.

C++
bool CRD11Device::Create( HWND hWnd )  
{  
    DXGI_SWAP_CHAIN_DESC scd;  
    ZeroMemory( &scd, sizeof( DXGI_SWAP_CHAIN_DESC ) );  

    scd.BufferCount       = 1;  
    scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;  
    scd.BufferUsage       = DXGI_USAGE_RENDER_TARGET_OUTPUT;  
    scd.OutputWindow      = hWnd;  
    scd.SampleDesc.Count  = 1;  
    scd.Windowed          = true;  

    HRESULT hr = D3D11CreateDeviceAndSwapChain  
    (  
       nullptr,  
       D3D_DRIVER_TYPE_HARDWARE,  
       nullptr,  
       0,  
       nullptr,  
       0,  
       D3D11_SDK_VERSION,  
       &scd,  
       &SwapChainPtr,  
       &DevicePtr,  
       nullptr,  
       &DeviceContextPtr  
    );  

    if ( FAILED( hr ) ) return false;  

    return true;  
}

이 함수는 윈도우 핸들이 생성되는 시점에서 호출해주면 끝이다.

C++
int APIENTRY wWinMain( _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow )  
{  
    // 코드 생략

    HWND hWnd = CreateWindowW( szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr );  
    if ( !hWnd ) return false;  

    // GD11은 CRD11Device의 전역 인스턴스이다.
    GD11.Create( hWnd );

    // 코드 생략
}

이렇게 DirectX11 디바이스 객체들의 사용 준비가 끝났다. 다음엔 DirectX11 API를 이용해서 빈 화면을 렌더링 해보자.

이전글 : [DirectX11] 1. 환경 구축을 해보자
다음글 : [DirectX11] 3. 초기화 – DirectX11 API를 이용한 빈 화면 렌더링 하기

Leave a Comment