DirectX3D와 같은 그래픽 라이브러리는 하드웨어(GPU)와 응용 프로그램 사이에 위치하여 프로그래머가 하드웨어와 드라이버에 대한 지식 없이 그래픽 라이브러리에서 제공해주는 인터페이스를 사용하여 간접적으로 렌더링 작업을 할 수 있도록 도와준다. 그래픽 라이브러리에서는 프로그래머가 보다 편하게 작업할 수 있도록 다양한 기능을 제공해주는데, COM도 그 중 하나라고 할 수 있다. DX에서 COM 객체를 사용하기 위한 간단한 정보들을 정리했다.
1. COM 객체 할당 및 해제
DX에서 제공하는 인터페이스 중에서 접두사 I
로 시작하는 것들이 있다.(ex. ID3D11Device
, ID3D11Buffer
...) 이런 유형의 인터페이스들을 COM 객체라고 보면 된다. 마이크로소프트에서 설명하는 COM 구성 요소의 개요를 보면 다음과 같은 내용이 있다.
https://learn.microsoft.com/en-us/windows/win32/prog-dx-with-com
A COM object is not created in the same way as a C++ object. There are several ways to create a COM object, but all involve COM-specific techniques. The DirectX API includes a variety of helper functions and methods that simplify creating most of the DirectX COM objects.
요약하면 COM 객체는 일반적인 C++의 객체처럼 new
나 delete
키워드를 사용해서 사용하지 말고, COM 객체의 생성을 위한 별도의 테크닉(= 별도의 생성 함수)를 사용하라는 것이다. 일례로 ID3D11Device
객체는 다음과 같은 별도의 생성 함수를 통해 만들 수 있다.
HRESULT D3D11CreateDevice(
[in, optional] IDXGIAdapter *pAdapter,
D3D_DRIVER_TYPE DriverType,
HMODULE Software,
UINT Flags,
[in, optional] const D3D_FEATURE_LEVEL *pFeatureLevels,
UINT FeatureLevels,
UINT SDKVersion,
[out, optional] ID3D11Device **ppDevice,
[out, optional] D3D_FEATURE_LEVEL *pFeatureLevel,
[out, optional] ID3D11DeviceContext **ppImmediateContext
);
D3D11CreateDevice
호출에 필요한 여러 인자들 중에서 ppDevice
라는 이중 포인터가 있는데, 이 인자가 바로 함수를 통해 생성되는 ID3D11Device
객체다. HRESULT
는 이 함수의 동작이 정상적으로 수행되었는지 확인할 때 사용한다.
이렇게 생성된 COM 객체의 할당을 해제하는 방법 역시 delete
를 사용하는 것이 아니라 Release
라는 함수를 따로 호출해주어야 한다. 모든 COM 객체는 IUnknown
인터페이스를 조상으로 두고 있고, IUnknown
의 Release
함수에서는 COM 객체의 참조 카운트를 계산하여 포인터의 메모리 할당을 해제하는 로직이 담겨 있기 때문이다. 따라서 모든 COM 객체는 기본적으로 참조 카운팅 방식을 통해 메모리 관리가 되고 있음을 알 수 있다.
2. ComPtr
COM 객체를 생성하고 해제하는 방식은 일반적인 C++의 객체와는 다르지만, 생성하고 나서 사용하는 방법은 일반적인 C++의 객체와 크게 다르지 않다. 따라서 COM 객체를 보다 편하게 사용하기 위해 ComPtr
을 사용할 수 있다. ComPtr
은 마이크로소프트에서 제공하는 wrl.h
헤더에 포함되어 있으며 COM 객체에 대한 스마트 포인터라고 생각하면 된다, 다음과 같이 사용할 수 있다.
#include<d3d11.h> // COM 사용을 위한 D3D11 헤더 추가
#include <wrl.h> // ComPtr 사용을 위한 wrl 헤더 추가
Microsoft::WRL::ComPtr<ID3D11Device> device;
3. GetAddressOf()
https://github.com/Microsoft/DirectXTK/wiki/ComPtr#initialization
ComPtr
을 사용하게 되면 COM 객체 생성 함수에서 리턴 값을 받기 위한 이중 포인터 인자를 전달할 때, GetAddressOf()
함수를 사용하면 이중 포인터의 시작 주소를 전달할 수 있어 자주 사용한다. 물론 operator&
를 사용해서 직접 주소를 전달해주어도 된다. 하지만 여기서 알아두면 좋을 부분이 있다.
ComPtr
은 내부적으로 operator&
를 오버로딩하고 있으며, 이 오버로딩된 연산자는 ReleaseAndGetAddressOf()
함수와 동일한 역할을 한다. 이는 ComPtr
이 클래스이 멤버로 사용되었을 때, 새롭게 COM 객체를 생성하려고 하면 기존에 할당된 객체를 해제하고 새로 할당 받기 위한 설계이다.
따라서 ComPtr
을 사용하고 있는 상황에서 COM 객체를 생성하거나 참조하기 위해 주소값이 필요한 경우에는 operator&
를 사용하는 것보다 GetAddressOf()
, Get()
과 같은 함수를 호출하여 명시적인 사용 용도를 표시하는게 좋다.
'그래픽스 > DirectX11' 카테고리의 다른 글
RenderTargetView의 의미 (0) | 2024.04.19 |
---|---|
DXGI_SWAP_CHAIN_DESC에 관하여 (1) | 2024.04.19 |
ID3D11Device 초기화, 생성 팁 (0) | 2024.04.16 |
DirectX 11 도형 출력(버텍스 버퍼, 버텍스 쉐이더, 픽셀 쉐이더 설정) (0) | 2024.04.12 |
DirectX 11 초기 설정(Device, DeviceContext, SwapChain) (0) | 2024.04.12 |