본문 바로가기

Library/Computer Graphics

A Rough D3D10 Initialization Sketch

D3D10을 사용하여 화면에 무엇을 나타내고자 한다면, 다음과 같은 최소의 과정을 거쳐야 한다. D3D10 이후로는, 각 스테이지에 바인딩되는 뷰를 통해 해당 스테이지에 접근할 수 있다. 또, D3D9은 버텍스 버퍼, 인덱스 버퍼를 각각의 함수를 통해 생성할 수 있었는데, D3D10은 각각의 버퍼들을 단일한 버퍼 생성 함수와 버퍼의 특성을 기술하는 디스크립터를 통해 생성하도록 바뀌었다.

또, 고정 기능 파이프라인의 하드웨어 T&L 기능이 완전히 제거되었기 때문에, 이들 기능을 사용하고자 한다면 직접 쉐이더 코드를 작성해주어야 한다. 또, 과거 FVF 포맷으로 이들을 버텍스 속성을 지정했던 것과 달리, D3D10에서는 IA 스테이지(Input Assembly) 단계에서 버텍스를 인식할 수 있도록 입력 형식을 IA 스테이지에 등록하는 절차가 필요하다. 이 과정을 정리하면, 다음과 같은 형태로 D3D10 초기화 코드가 흘러가게 된다.

1. 버텍스 버퍼를 생성한다. D3D10_BUFFER_DESC 구조체를 생성하고, 생성하려는 버텍스 버퍼의 특성에 맞춰 적절하게 이들 구조체 멤버들을 초기화해야 한다. 버텍스 버퍼를 생성하는데 버퍼의 특성을 기술하는 버퍼 디스크립터 외에도, 서브 리소스 데이터를 기술해야 한다. D3D10_SUBRESOURCE_DATA 구조체를 적절하게 초기화하고, ID3D10Device::CreateBuffer() 함수를 사용하여 버텍스 버퍼를 생성한다.

2. 필요하다면 인덱스 버퍼를 생성한다. 인덱스 버퍼도 위와 마찬가지로 버퍼의 특성을 기술하는 버퍼 디스크립터와 서브 리소스 데이터가 필요하다.

3. 이펙트 프레임워크를 컴파일하면서 렌더링 패스에 대한 정보를 얻고, 버텍스 입력 레이아웃에 대한 정보를 얻는다. 이 정보를 통해 입력 레이아웃을 생성하고, 렌더링 코드에서 IA 스테이지에 버텍스 레이아웃을 바인딩하여 버텍스 버퍼로부터 버텍스 정보를 읽어들이게 된다. D3D10 이후로는 고정 기능 파이프라인에서 지원되는 기능들이 삭제되었기 때문에 거의 필수적으로 쉐이더 코드를 작성해주어야 한다.

4. 렌더 타겟 뷰를 생성한다. 이것은 실제로 렌더링되는 화면을 위해 프런트 버퍼와 백 버퍼를 생성하는 단계이다. 백 버퍼는 메모리 상에 존재하는 텍스처라 할 수 있으므로, 렌더 타겟 뷰를 생성하는데 이를 위한 텍스처 리소스가 필요하다. DXGI의 스왑체인으로부터 CreateBuffer() 함수를 사용하여 새로운 텍스처 리소스를 생성하고, ID3D10Device::CreateRenderTargetView() 함수를 호출할 때 이 값을 같이 넘겨주어서 렌더 타겟 뷰를 생성한다.

5. 깊이 / 스텐실 뷰를 생성한다. 깊이 / 스텐실 뷰 역시 함께 바인딩되는 버퍼가 필요하며, 버퍼를 생성할 때 생성하는 버퍼의 특성을 여기에 맞춰 적절하게 기술해야 한다. 깊이 / 스텐실 뷰와 버퍼가 생성되면, OMSetRenderTargets() 함수를 사용하여 OM 스테이지와 바인딩한다. 렌더링 코드를 실제로 시작하기 전에, 렌더 타겟 뷰와 깊이 / 스텐실 뷰를 깨끗하게 지울 필요가 있기 때문에, 렌더 타겟 뷰와 같은 것들은 미리 OM(output Merger) 스테이지에 바인딩할 필요가 있다.

6. 마지막으로, 화면에 보여질 뷰포트를 설정한다. D3D10_VIEWPORTS 구조체를 생성하고 여기에 적절한 값을 넣고, RSSetViewports() 함수를 통해 래스터라이저 스테이지에서 사용할 설정된 뷰포트 정보를 알려준다.

7. 렌더링 코드에서 원하는 장면을 렌더링한다. 렌더링 코드에서 버텍스 쉐이더나 픽셀 쉐이더, 지오메트리 쉐이더 따위를 활성화하거나 앞서 생성해 두었던 입력 레이아웃 정보를 IA 스테이지에 바인딩하거나 하는 실제 렌더링 작업을 수행하면 된다.


여기서, 텍스처나 버퍼와 같은 리소스를 생성하는데 있어 이들의 특성을 기술한 디스크립터를 확실하게 지정하여 생성해야 한다. 이것은 최적화 때문인데, 이런 정보를 미리 정의하여 D3D에게 알려주는 것은 런타임 시점에서 성능을 향상시킬 수 있다. 성능상의 문제 때문에, 타입 정보가 없는 리소스는 반드시 필요한 경우에만 생성해야 한다.