Grahpics

[Graphics] DirectX12 장치 초기화 (2) - Device

송만덕 2022. 1. 9. 15:56

 

Device

 

DirectX에서 Device Class에서는 각종 디스플레이 관련 객체를 생성한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Device
{
public:
    void Init();
 
    ComPtr<IDXGIFactory> GetDXGI() { return _dxgi; }
    ComPtr<ID3D12Device> GetDevice() { return _device; }
 
private:
/*
     direct x 는 gpu를 제어하고 프로그래밍할 때 쓰이는 저수준 그래픽 API
     -> 우리는 direct x에 집중하고 마쏘와 제조사가 알아서 만든다.
 
     COM(Component Object Model)
     - DX의 프로그래밍 언어 독립성과 하위 호환성을 가능하게 하는 기술
     - COM 객체(COM 인터페이스)를 사용. 세부사항은 우리한테 숨겨짐
     - ComPtr 일종의 스마트 포인터
     - GPU접근 시 ComPtr을 사용함
*/
    ComPtr<ID3D12Debug>        _debugController;
    ComPtr<IDXGIFactory>    _dxgi; // 화면 관련 기능들 (출력..)
    ComPtr<ID3D12Device>    _device; // 각종 객체 생성
};
 
 
void Device::Init()
{
#ifdef _DEBUG
    ::D3D12GetDebugInterface(IID_PPV_ARGS(&_debugController));
    _debugController->EnableDebugLayer();
#endif
 
 
    ::CreateDXGIFactory(IID_PPV_ARGS(&_dxgi));
 
    ::D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&_device));
 
}
cs

 


 

DXGI(DirectX Graphics Infrastructure)

 

ComPtr<IDXGIFactory> _dxgi;
  • Device를 생성하기 위해서는 IDXGIFactory라는 COM 객체가 필요하다.
  • DXGI란 Direct3D와 함께 쓰이는 API로 전체화면 모드전환과 지원되는 디스플레이 열거, 스완체입 생성 등 저수준 작업들을 관리한다.
::CreateDXGIFactory(IID_PPV_ARGS(&_dxgi));
  • IDXGIFactory란 어댑터(비디오 카드), 출력장치(모니터), 디바이스(그래픽 카드)를 포함하는 COM 객체이다.
  • IDXGIFactory를 생성하여 위 기능을 수행할 수 있도록 한다.
  • 첫번째 인자로는 riid(디바이스의 COM ID), 두번쨰 인자로 ppDevice(주소)가 들어가며 IID_PPV_ARGS를 통해 확장하여 사용 하능하다.

 

Device

 

ComPtr<ID3D12Device> _device;

::D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&_device));
  • Device = 디스플레이 어댑터(그래픽 카드)를 나타내는 객체.
  • CreateDevice() = Device를 생성하는 함수.
  • pAdapter = nullptr을 지정하면 시스템 기본 디스플레이 어댑터.
  • MinimumFeatureLevel = 응용 프로그램이 요구하는 최소 기능 수준 (위 코드는 D3D_FEATURE_LEVEL_11_0로 지정되어 있으며, 이 수준을 지원하는 그래픽카드부터 가능하다는 의미.)
  • riid = 디바이스의 COM ID
  • ppDevice = 생성된 장치. CreateDXGIFactory와 같이 IID_PPV_ARGS를 통해 확장 가능.

 

COM

 

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

 

COM 객체는 COM 인터페이스라고도 불린다.

사용자는 COM의 대부분의 세부사항을 볼 수 없다

그저 사용자가 알아야 할 것은 필요한 COM 객체를 가리키는 포인터를 특별한 함수를 이용해서,

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

 

C++처럼 사용하는 방법과 유사하게 COM 객체를 사용할 수 있지만, C++과 다르게 COM 객체는 new나 delete를 이용하여 생성, 삭제를 할 수 없다.

반드시 생성을 위한 별도의 API 함수를 써야하며 그 인터페이스의 Release 메서드를 호출해주어야 한다.

(모든 COM 인터페이스는 IUnknown이라는 COM인터페이스의 기능을 상속하는데, 여기에 Release라는 메서드를 제공한다.)

사용자는 COM 인터페이스 포인터를 AddRef 메서드를 사용하여 다른 변수에 복사할 수 있다. 이때 참조 횟수가 1증가한다.

또한 Release()를 호출하면 참조 횟수가 1감소하며 COM 객체는 참조 횟수가 0이 되면 메모리에서 해제된다.

 

COM 인터페이스들은 이름이 대문자 'I'로 시작한다. 예를 들어 명령 목록(command list)을 나타내는 COM 인터페이스의 이름은 ID3D12GraphicsCommandList이다.

 

출처 : https://lipcoder.tistory.com/9

 

 

COM 객체의 생성과 소멸

출처 : https://lipcoder.tistory.com/9

Device COM 객체를 D3D12CreateDevice API함수를 이용하여 생성하고 그것을 pd3dDeviceCopied 변수에 복사하였다.

이때 AddRef() 메서드를 호출해줘야 하며, 역시 더이상 변수를 사용하지 않을때에도 Release() 메서드를 호출해주어야 한다.

출처 : https://lipcoder.tistory.com/9

COM 객체가 아닌 경우의 API 함수들은 객체 포인터의 주소가 아닌 그냥 주소를 넘겨준다는 점에서 확연한 차이를 보여준다.

 


 

GUID

 

GUID(Globally Unique IDentifier)는 인터페이스 클래스 식별자(ID)를 나타내는 128비트(16바이트) 정수 문자열이다. Microsoft의 COM에서는 인터페이스들을 구별하기 위해 GUID가 사용된다.

서로 호환되지 않을 수 있는 두개의 COM이 동일한 인터페이스 이름을 사용하더라도, 고유한 GUID 덕분에 구별이 가능하다.

 

__uuidof 연산자와 IID_PPV_ARGS 매크로 중 하나를 사용하여 비교적 쉽게 인터페이스 자료형, 클래스 이름, 인터페이스 포인터에 알맞는 GUID를  얻을 수 있다.

 

위의 코드에서는 IID_PPV_ARGS를 사용하여 작성된 것이다.

 

또한 COM 객체의 수명 관리를 돕기 위해 ComPtr 클래스를 제공한다.

이 클래스는 COM 객체를 위한 스마트 포인터라고 할 수 있다.

범위를 벗어난 ComPtr 인스턴스는 COM 객체에 대해 자동으로 Release를 호출한다.

따라서 사용자는 직접 Release를 호출할 필요가 없다.

 

COM과 GUID부분의 내용의 출처 : https://lipcoder.tistory.com/9

 

[DirectX 12] 기본지식 - COM(Component Object Model)

COM(Component Object Model)은 DirectX의 프로그래밍 언어 독립성과 하위 호환성을 가능하게 하는 기술이다. C++ 클래스로 간주하고 사용해도 무방하기 때문에 주로 COM 객체라고 흔히 부른다.  COM 객체는

lipcoder.tistory.com