기록공간

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

DirectX/기초

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

입코딩 2020. 2. 2. 23:00
반응형

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

 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이다.


코드로 COM 객체의 생성과 소멸을 간략하게 살펴보자.

ID3D12Device *pd3dDevice = NULL;

D3D12CreateDevice(NULL, ..., &pd3dDevice, ...);

ID3D12Device *pd3dDeviceCopied = pd3dDevice;
pd3dDeviceCopied->AddRef();

pd3dDeviceCopied->Release();

pd3dDevice->Release();

 

위의 코드를 그림으로 표현하였을때의 모습이다.

 Device COM 객체를 D3D12CreateDevice API함수를 이용하여 생성하고 그것을 pd3dDeviceCopied 변수에 복사하였다. 이때 AddRef() 메서드를 호출해줘야 하며, 역시 더이상 변수를 사용하지 않을때에도 Release() 메서드를 호출해주어야 한다.

 

초기화시 NULL이였던 객체 포인터 변수 pd3dDevice가 API 함수를 거치며 COM 객체를 생성하고 pd3dDevice의 주소를 참조하게 되었다.

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


GUID

GUID(Globally Unique IDentifier)는 인터페이스 클래스 식별자(ID)를 나타내는 128비트(16바이트) 정수 문자열이다. Microsoft의 COM에서는 인터페이스들을 구별하기 위해 GUID가 사용된다. 서로 호환되지 않을 수 있는 두개의 COM이 동일한 인터페이스 이름을 사용하더라도, 고유한 GUID 덕분에 구별이 가능하다. 

 

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

ID3D12Device* pd3dDevice;

// __uuidof 사용시
D3D12CreateDevice(..., __uuidof(ID3D12Device), &pd3dDevice);

// IID_PPV_ARGS 매크로 사용시
D3D12CreateDevice(..., IID_PPV_ARGS(&pd3dDevice));

//...

 

또한 COM 객체의 수명 관리를 돕기 위해 ComPtr 클래스를 제공한다. 이 클래스는 COM 객체를 위한 스마트 포인터라고 할 수 있다. 범위를 벗어난 ComPtr 인스턴스는 COM 객체에 대해 자동으로 Release를 호출한다. 따라서 사용자는 직접 Release를 호출할 필요가 없다. ComPtr 클래스에서 제공하는 메서드들을 살펴보면 다음과 같다.

template<typename T> class ComPtr;
T* ComPtr::Get() const; // 인터페이스 포인터를 반환
T** ComPtr::GetAddressOf(); // 인터페이스 포인터의 주소를 반환
unsigned long ComPtr::Reset(); // 인터페이스 포인터에 대한 모든 참조를 Release()
ComPtr::operator-> Operator // 인터페이스 포인터를 반환(Get과 동일)
ComPtr::operator& Operator // 인터페이스 포인터의 주소를 반환(GetAddressOf와 동일)

 

반응형
Comments