DirectX11 – 디바이스 객체
[DirectX11] 환경 구축를 통해서 프로젝트의 생성까지 모두 끝나고 빌드하면 다음과 같은 화면을 볼 수 있다.

하지만 아직 DirectX
를 통해 렌더링되는 화면은 아니다. 이제부터 DirectX11 API
를 이용해 빈 화면을 우선 렌더링 해보도록 하자.
디바이스 객체들을 만들자
DirectX11 API를 이용하기 위해서 우선적으로 생성해야 하는 객체들이 있다. ID3D11Device
, ID3D11DeviceContext
, IDXGISwapChain
인터페이스 객체 3개가 필요하다. 편의상 이들을 통칭해서 디바이스 객체들이라고 하자. 이들은 렌더링에 필요한 리소스를 생성하고 렌더링 파이프라인에 연결하고 백 버퍼를 갱신하기 위한 객체들이라고 보면 된다.
DirectX가 무엇일까?
DirectX11은 Graphics API이다. GPU를 이용하려면 GPU제조사에서 제공하는 하드웨어 드라이버를 이용해야 한다. GPU 하드웨어 제조사가 하나면 상관이 없지만 여러 제조사라면 이 모든 제조사의 드라이버에 대해 학습을 해야 하고, 로우 레벨에서의 프로그래밍이 필요하다.
DirectX는 이런 제조사의 하드웨어 드라이버 레벨에서 프로그래밍을 하지 않고 공통으로 사용되는 API를 이용해서 여러 제조사의 GPU를 사용할 수 있도록 해준다.
디바이스 객체들의 역할
각 디바이스 객체가 제공하는 인터페이스 함수들을 보면 대략적으로 어떤 역할들을 하는지 알 수 있다. 마이크로 소프트 공식 홈페이지에서 자세히 설명이 되어 있다. 일단은 간략하게 각 객체가 어떤 역할들을 하는지 알아보자.
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에서 확인할 수 있다. 주로 버퍼의 갯수, 버퍼의 용도, 버퍼의 포맷등을 결정하게 된다.
다중 버퍼링
스크린에 렌더링하기 위한 버퍼의 개수는 최소 1개는 있어야 하지만 다수를 이용할 수 있다. 버퍼의 내용이 스크린에 표시되는 동안 버퍼의 내용을 수정해서는 안되기 때문에 2개 이상의 버퍼를 만든 후, 하나의 버퍼를 스크린에 표시 ( Present
)하는 동안 다른 하나의 버퍼에 다음 프레임을 렌더링하는 것이다. 이 과정이 끝나면 다시 렌더링이 끝난 버퍼를 스크린에 표시하고 나머지 하나를 갱신한다.
디바이스 객체 생성 코드
디바이스 객체를 생성하는 코드는 다음과 같다.
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 );
C++D3D11CreateDeviceAndSwapChain
함수에 대한 레퍼런스는 D3D11CreateDeviceAndSwapChain에서 자세히 알 수 있다. 이 함수를 통해 3개의 객체를 모두 생성하면 이제 비로소 DirectX11 API
를 이용하기 위한 준비가 끝난 것이다.
CRD11Device
위에서 설명한 코드들을 가지고 클래스로 만들어보자.
//---------------------------------------------------------------------------------------------------------------------
/// CRD11Device
//---------------------------------------------------------------------------------------------------------------------
class CRD11Device
{
private:
ID3D11Device* DevicePtr = nullptr;
ID3D11DeviceContext* DeviceContextPtr = nullptr;
IDXGISwapChain* SwapChainPtr = nullptr;
public:
/// Constructor
CRD11Device() = default;
/// Create Dx11 device ojects.
bool Create( HWND hWnd );
//-----------------------------------------------------------------------------------------------------------------
/// Getter
//-----------------------------------------------------------------------------------------------------------------
/// 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; }
};
C++
Create
에서 윈도우 핸들을 전달받아 객체들을 생성해준다.
//---------------------------------------------------------------------------------------------------------------------
/// Create
//---------------------------------------------------------------------------------------------------------------------
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++
이 함수는 윈도우 핸들이 생성되는 시점에서 호출해주면 끝이다.
//---------------------------------------------------------------------------------------------------------------------
/// wWinMain
//---------------------------------------------------------------------------------------------------------------------
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.Create( hWnd );
// 코드 생략
}
C++
이렇게 일단 1차적인 준비가 끝났다. 다음엔 DirectX11 API
를 이용해서 빈 화면을 렌더링 해보자.
이전글 : [DirectX11] 환경 구축
댓글을 남겨주세요
Want to join the discussion?Feel free to contribute!