그래픽스/DX12

D3D12 게임 프로그래밍 입문 - 기본 지식 (1)

게임 개발 2023. 12. 20. 16:51

 

 

 

 

 

Direct3D 12의 개요

 

 응용 프로그램과 그래픽 하드웨어 사이에

Direct3D라는 간접층과 하드웨어 드라이버가 Direct3D 명령들을 시스템의 GPU가 직접 이해하는

고유한 기계어 명령들로 번역해 주므로, 해당 GPU가 Direct3D 12를 지원하는 한,

응용 프로그램 개발자는 GPU의 세부사항을 걱정할 필요가 없다.

 단, 이를 위해서는 GPU 제조사들이 Direct3D 명세를 준수하는 드라이버를 제공해야 한다.

 

 이전 버전들에 비한 주된 개선점은 CPU 부담을 크게 줄이고

다중 스레드 지원을 개선하기 위해서 설계를 다시 했다는 점이다.

D3D11보다 D3D12가 보다 헐씬 낮은 (즉, GPU 쪽에 더 가까운) 수준의 API가 되었다.

D3D12는 이전보다 추상화가 줄었고, 개발자가 손수 관리해야 할 영역이 늘었어났으며,

현세대 GPU 구조(아키텍처)들을 좀 더 밀접하게 반영한다.

API를 사용하기에는 좀 더 어려워졌지만, 대신 성능이 개선되었다.

 

 

 

COM

COM(Component Object Model)은 DX의 프로그래밍 언어 독립성과 하위 호환성을 가능하게 하는 기술이다.

프로그래머가 알아야 할 것은 COM 인터페이스를 가리키는 포인터를 특별한 함수들을 이용해서,

또는 다른 COM 인터페이스의 메서드를 이용해서 얻는 방법뿐이다.

COM 인터페이스는 new로 직접 생성할 일은 없으며, 다 사용하고 난 뒤에는 delete로 삭제하는 것이 아니라, 

Release메서드를 호출해 주어야 한다는 것이다.

Windows 런타임 라이브러리는 Microsoft::WRL::ComPtr이라는 클래스를 제공한다.

이 클래스는 COM 객체를 위한 SmartPTR이라 할 수 있다.

이는 프로그래머가 Release를 직접 호출할 필요가 없다.

 

  1. Get : 바탕 COM 인터페이스를 가리키는 포인터를 돌려준다.
    해당 COM 인터페이스 포인터 형식의 인수를 받는 함수를 호출할 때 흔히 쓰인다.


  2. GetAddressOf : 바탕 COM 인터페이스를 가리키는 포인터의 주소를 돌려준다.
    함수 매개변수를 통해서
    COM 인터페이스 포인터*(= 인터페이스의 포인터의 포인터)를 돌려받을 때 흔히 쓰인다.


  3. Reset : ComPtr 인스턴스를 nullptr로 설정하고 바탕 COM 인터페이스의 참조 횟수를 1 감소한다.
    이 메서드를 사용하는 대신 ComPtr 인스턴스에 직접 nullptr를 배정해도 된다.
    (역시 참조 횟수가 감소한다)  

 

 

 

텍스처 형식

 

2차원 텍스처는 자료 원소들의 행렬(2차원 배열)이다.

2차원 텍스처의 용도 하나는 2차원 이미지 자료를 저장하는 것인데,

이때 텍스처의 각 원소는 픽셀 하나의 색상을 담는다.

그러나 이 것이 텍스처의 유일한 용도는 아니다.

예를 들어 법선 매핑이라고 하는 고급 기법에서는 

텍스처의 각 원소가 색상이 아니라 3차원 벡터를 담는다.

법선 매핑이란, 3차원 그래픽스에서 튀어나온 곳과 움푹 들어간 곳의 빛을 왜곡시키는 기법으로, 법선 매핑의 구현체이다. <출저 -위키백과>

 

텍스처라고 하면 흔히 이미지 자료의 저장을 떠올리지만,

법선 매핑의 예에서 보듯이 훨씬 범용적으로 사용이 가능하다.

 

마찬가지로, 1차원 텍스처는 자료 원소들의 1차원 배열에 해당하고,

3차원 텍스처는 자료 원소들의 3차원 배열에 해당한다.

사실 텍스처가 단순한 자료 배열인 것만은 아니다.

텍스처에 밉맵 수준들이 존재할 수 있으며, GPU 필터링, 다중표본화 등의

특별한 연산을 텍스처에 적용할 수 있다.

더 나아가서, 텍스처에 아무 자료나 담을 수 있는 것은 아니라는 점도 중요하다.

텍스처에는 특정 형식 (format)의 자료 원소들만 담을 수 있는데,

구체적인 형식은 DXGI_FORMAT이라는 열거형으로 지정한다.

다음은 텍스처에 담을 수 있는 자료 원소 형식들의 예이다.

 

  1. DXGI_FORMAT_R32G32B32_FLOAT :
    각 원소는 32비트 부동소수점 성분 세 개로 이루어진다.

  2. DXGI_FORMAT_R16G16B16A16_UNORM :
    각 원소는 [0, 1] 구간으로 사상되는 16비트 성분 네 개로 이루어진다.

  3. DXGI_FORMAT_R32G32_UINT : 각 원소는 부호 없는 32비트 정수 성분 두 개로 이루어진다.

  4. DXGI_FORMAT_R8G8B8A8_UNORM :
    각 원소는 [0,1] 구간으로 사상되는 부호 없는 8비트 성분 네 개로 이루어진다.

  5. DXGI_FORMAT_R8G8B8A8_SNORM :
    각 원소는 [-1, 1] 구간으로 사상되는 부호 있는 8비트 성분 네 개로 이루어진다.
  6. DXGI_FORMAT_R8G8B8A8_SINT :
    각 원소는 [-128, 127] 구간으로 사상되는 부호 있는 8비트 정수 성분 네 개로 이루어진다.
  7. DXGI_FORMAT_R8G8B8A8_UINT :
    각 원소는 [0, 255] 구간으로 사상되는 부호 없는 8비트 정수 성분 네 개로 이루어진다.

 

무형식 텍스처들이 있는데,

이런 텍스처는 일단 메모리만 확보해 두고

자료의 구체적인 해석 방식은
나중에 텍스처를 파이브라인에 묶을 때 지정하는 (C++의 reinterpret_cast와 비슷하게) 용도로 쓰인다.

예를 들어 다음의 무형식 텍스처 형식은

원소마다 16비트 성분 네 개를 할당하되,

각 16비트 성분의 구체적인 자료 형식 (즉 정수, 부동소수점, 부호 없는 정수 등)은 지정하지 않는다.

 

DXGI_FORMAT 열거형은 정점 자료 형식과 색인 자료 형식을 서술할 때에도 쓰인다.