[DirectX12] #Part 2 - Direct 3D 기초
"DirectX12를 이용한 3D 게임 프로그래밍 입문" 서적의 Part 2, "Direct3D의 기초"에 해당하는 내용입니다.
현재, 게임 개발에 입문하여 기초지식을 습득하여 기록하기 위함이며, 개념 이해와 예제코드 작성을 진행.
DXGI?
DirectX Graphics Infrastructure는 여러 그래픽 API들에 공통인 그래픽 관련 작업들이 존재하는 API입니다. 예를 들면, 화면 모드 전환, 디스플레이 어댑터나 모니터, 지원되는 디스플레이 모드 같은 그래픽 시스템 정보의 열거 등의 기능은 DXGI가 제공합니다. DXGI의 핵심 인터페이스 중 하나로 IDXGIFactory 인터페이스가 있습니다. 이 인터페이스는 IDXGISwapChain 인터페이스 생성과 디스플레이 어댑터 열거에 쓰이죠. 여기서 디스플레이 어댑터란 그래픽 기능성을 구현합니다. 일반적으로 우리가 잘 아는 그래픽 카드가 있죠. 물론 하드웨어 그래픽 기능성을 흉내내는 소프트웨어 디스플레이 어댑터도 존재합니다. 이러한 디스플레이 어댑터들의 목록을 보여주는 IDXGIAdaptor를 살펴보겠습니다.
IDXGIAdaptor
void D3DApp::LogAdapter(){
UINT i= 0;
IDXGIAdapter* adpater = nullptr; // IDXGIAdapter 포인터
std::vector<IDXGIAdapter*> adapterList; // Adpator들을 담는 vector
while(mdxgiFacotry->EnumAdapterList(i, &adapter) != DXGI_ERROR_NOT_FOUND){
DXGI_ADAPTER_DESC desc;
adapter->GetDesc(&desc);
std::wstring text = L"***Adpater: ";
text+= desc.Description;
text+= L"\n";
OutputDebugString(text.C_str());
adapterList.push_back(adapter);
++i;
}
for(size_t i =0; i< adapterList.size(); ++i){
LogAdapterOutputs(adapterList[i]);
ReleaseCom(adapterList[i]);
}
}
IDXGIOutput
void D3DApp::LogAdapterOutputs(IDXGIAdapter* adapter)
{
UINT i= 0;
IDXGIOutput* output = nullptr; // 출력을 가리키는 포인터
while(adapter->EnumOutputs(i, &output) != DXGI_ERROR_NOT_FOUND)
{
DXGI_OUTPUT_DESC desc; // Descending Order로 정렬
output->GetDesc(&desc);
std::wstring text = L"***Adpater: ";
text+= desc.Description;
text+= L"\n";
OutputDebugString(text.C_str());
LogOutputDisplayModes(output, DXGI_FORMAT_B8G8R8A8_UNORM);
Release(output);
++i;
}
}
모니터는 디스플레이 출력의 한 예이다. 디스플레이 출력은 "IDXGIOutput" 인터페이스가 대표합니다. 각 어댑터는 출력들의 목록이 연관되어 있죠. 예를들면, 어떤 시스템에 그래픽 카드가 2개, 모니터가 3개 연결되어 있으며, 한 그래픽 카드가 모니터 2개를 담당하고, 다른 나머지 하나가 다른 한 개의 모니터를 담당하고 있습니다. 각각의 어댑터마다 연관되어 있는 출력 목록이 다르겠죠. 위 코드는 주어진 하나의 어댑터에 연관된 모든 출력들을 열거합니다.
DXGI_MODE_DESC
typedef struct DXGI_MODE_DESC
{
UINT Width; // 가로 해상도
UINT Height; // 세로 해상도
DXGI_RATIONAL RefreshRate;
DXGI_FORMAT Format; // 디스플레이 형식
DXGI_MODE_SCANLINE_ORDER ScanlineOrdering; //스캔 방식
DXGI_MODE_SCALING Scaling; // 스케일링 방식
}
하나의 출력은 여러 디스플레이 모드를 지원합니다. 이때, 하나의 디스플레이 모드를 서술하는 여러 멤버들이 DXGI_MODE_DESC 구조체에 있습니다.
출력과 디스플레이 형식을 지원하는 모든 디스플레이 모드
void D3DApp::LogOutputDisplayModes(IDXGIOutput* output, DXGI_FORMAT format)
{
UINT Count = 0;
UINT flags = 0;
// nullptr을 인수로 하면, 디스플레이 모드의 개수를 얻어온다.
output->GetDisplayModeList(format, flags, &count, &modeList[0]);
// for-each 문
for(auto& x: modeList){
UINT n = x.RefreshRate.Numerator;
UINT d = x.RefreshRate.Denominator;
std::wstring text =
L"Width =" "+ std::to_wstring(x.Width) + L" " +
L"Height =" "+ std::to_wstring(x.Height) + L" " +
L"Refresh =" "+ std::to_wstring(n) + L"/" + std::to_wstring(d) +
L"\n";
::OutputDebugString(text.c_str());
}
}
// 출력 화면
***Output: \\.\DISPLAY2
...
Width = 1920 Height = 1080 Refresh = 59950/1000
Width = 1920 Height = 1200 Refresh = 59950/1000
디스플레이 모드 열거는 전체 화면 모드로 갈 때 특히 중요합니다. 전체 화면 성능을 극대화하려면, 지정된 디스플레이 모드가 반드시 모니터가 지원하는 한 디스플레이 모드와 정확히 일치해야 하기 때문입니다. 따라서, 위처럼 모니터가 지원하는 디스플레이 모드들을 열거한 뒤, 그 중 하나를 지정하면 되겠죠.
DXGI 통해 Direct3D 초기화 과정에 쓰이는 인터페이스들을 얻을 수 있습니다
'게임개발 > DirectX12' 카테고리의 다른 글
[DirectX12]#Part2 - Direct3D의 기초_상주성(Residency) (0) | 2021.12.28 |
---|---|
[DirectX12]#Part2 - Direct3D의 기초_기능 지원 점검 (0) | 2021.12.28 |
[DirectX12]#Part2 - Direct3D의 기초_엘리어싱과 다중표본화 (0) | 2021.12.27 |
[DirectX12]#Part2 - Direct3D의 기초_자원과 서술자 (0) | 2021.12.27 |
[DirectX12]#Part2 - Direct3D의 기초_교환 사슬 & 깊이 버퍼링 (0) | 2021.12.24 |