Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
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
Archives
Today
Total
관리 메뉴

codingfarm

Direct3D의 초기화 - 교환 사슬의 설정 및 생성 본문

computer graphics/DirectX11

Direct3D의 초기화 - 교환 사슬의 설정 및 생성

scarecrow1992 2020. 11. 28. 18:10

교환 사슬의 생성

초기화 공정 이후에는 교환 사슬을 생성해야한다. 이를 위해선 우선 DXGI_SWAP_CHAIN_DESC 구조체의 인스턴스를 만들어서 원하는 교화 ㄴ사슬의 특성들을 설정해야 한다.

이 구조체의 정의는 다음과 같다.

typedef struct DXGI_SWAP_CHAIN_DESC {
    DXGI_MODE_DESC   BufferDesc;
    DXGI_SAMPLE_DESC SampleDesc;
    DXGI_USAGE       BufferUsage;
    UINT             BufferCount;
    HWND             OutputWindow;
    BOOL             Windowed;
    DXGI_SWAP_EFFECT SwapEffect;
    UINT             Flags;
} DXGI_SWAP_CHAIN_DESC;

 

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;

 

DXGI_SWAP_CHAIN_DESC 구조체의 각 필드의 의미를 대략적으로 알아보자.

1. BufferDesc

    생성하고자 하는 후면 버퍼의 속성들을 서술하는 개별 구조체이다.

    버퍼의 너비와 높이, 픽셀 형식을 지정하는 멤버를 통해 서술 가능하다.

 

2. SampleDesc

    다중표본화를 위해 추출할 표본 개수와 품질 수준을 서술하는 구조체

 

3. BufferUsage

    버퍼의 용도를 서술하는 구조체, 지금 맥락에서는 후면 버퍼에 렌더링을 할 것이므로 DXGI_USAGE_RENDER_TARGET_OUTPUT 을 지정한다.

 

4. BufferCount

    교환 사슬에서 사용할 후면 버퍼의 갯수이다. 일반적으로 후면버퍼는 하나만 쓰지만 필요에 따라 그 이상의 갯수도 가능하다.

 

5. OutputWindow

    렌더링 결과를 표시할 창의 핸들이다.

 

6. Windowed

    창 모드를 원하면 true를, 전체화면 모드를 원하면 false를 지정한다.

 

7. SwapEffect

    교환 효과를 서술하는 구조체로, DXGI_SWAP_EFFECT_DISCARD를 지정하면 디스플레이 구동기가 가장 효율적인 제시 방법을 선택하게 된다.

 

8. Flags

    추가적인 플래그들이다, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH를 지정하면, 응용 프로그램이 전체화면 모드로 전환할 때 현재의 후면 버퍼 설정에 가장 잘 부합하는 디스플레이 모드가 자동으로 선택된다. 이 플래그를 지정하지 않으면 응용 프로그램이 전체 화면모드로 전환할 때 그냥 현재의 데스크톱 디스플레이 모드가 사용된다. 이후 포스팅에서는 이 플래그를 지정하지 않는다. 예제 프로그램들은 전체 화면모드에서 현재 데스크톱 디스플레이 모드를 사용해도 잘 돌아가기 때문이다.(대부분의 데스크톱 디스플레이는 모니터의 최적 해상도에 맞게 설정되어 있다.)

 

다음은 예제 프레임워크가 DXGI_SWAPCHAIN_DESC 구조체를 채우는데 사용하는 코드이다.

DXGI_SWAP_CHAIN_DESC sd;
sd.BufferDesc.Width = mClientWidth;
sd.BufferDesc.Height = mClientHeight;
sd.BufferDesc.RefreshRate.Numerator = 60;
sd.BufferDesc.RefreshRate.Denominator = 1;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_NSPECIFIED;
sd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;

// 4X MSAA를 사용하는가?
if( mEnable4XMsaa ) {
    sd.SampleDesc.Count = 4;
    
    //m4xMsaaQuality는 CheckMultisampleQualityLevels()로 얻은것이다.
    sd.SampleDesc.Quality = m4xMsaaQuality - 1;
}
//MSAA를 사용하지 않음
else {
    sd.SampleDesc.Count = 1;
    sd.SampleDesc.Quality = 0;
}

sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.BufferCount = 1;
sd.OutputWindow = mhMainWnd;
sd.Windowed = true;
sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
sd.Flags = 0;

 

실행시점에서 다중표본화 설정을 변경하고 싶다면 교환사슬을 삭제하고 다시 생성하는 것이 한 가지 방법이다.

후면 버퍼에 대해 DXGI_FORMAT_R8G8B8A8_UNORM 형식을 사용하는 이유는 일반적으로 모니터의 색상당 비트수가 24비트 이하이므로 정밀도를 그보다 더 높게 잡아봤자 낭비이기 때문이다. 알파성분이 차지하는 여분의 8비트는 모니터가 출력하는것이 아니다. 그러나 후면 버퍼에 여분의 8비트를 두면 몇 가지 특수 효과들에 활용할 수 있다.

$\blacksquare$

 


교환 사슬의 생성

교환 사슬을 서술하는 구조체를 만들었다면, 다음으로는 IDXGIFactory 인스턴스를 통해 IDXGIFactory::CreateSwapChain 메서드를 호출해서 교환 사슬 인터페이스(IDXGISwapChain)를 생성한다.

HRESULT CreateSwapChain(
  IUnknown             *pDevice,
  DXGI_SWAP_CHAIN_DESC *pDesc,
  IDXGISwapChain       **ppSwapChain
);

IDXGIFactory 인스턴스는 CreateDXGIFactory 함수(dxgi.lib를 링크해야함)를 이용해서 얻을 수도 있다. 그러나 그렇게 얻은 IDXGIFactory 인스턴스로 IDXGIFactory::CreateSwapChain을 호출하면 오류가 난다. 오류를 피하기 위해선 장치의 생성에 쓰인 IDXGIFactory 인스턴스를 사용해야 한다. 그리고 그 인스턴스를 얻으려면 다음과 같이 일련의 COM 질의 과정을 거쳐야 한다.

IDXGIDevice* dxgiDevice = 0;
HR(md3dDevice->QueryInterface(__uuidof(IDXGIDevice),
    (void**)&dxgiDevice));
    
IDXGIAdapter* dxgiAdapter = 0;
HR(dxgiDevice->GetParent(__uuidof(IDXGIAdapter),
    (void**)&dxgiAdapter));

//IDXGIFactory 인터페이스를 얻을 수 있다.
IDXGIFactory* dxgiFactory = 0;
HR(dxgiAdapter->GetParent(__uuidof(IDXGIFactory),
    (void**)&dxgiFactory));
    
// 교환 사슬을 생성한다
IDXGISwapChain* mSwapChain;
HR(dxgiFactory->CreateSwapChain(md3dDevice, &sd, &mSwapChain));

//획득한 COM인터페이스들을 해제한다(다 사용했으므로).
ReleaseCOM(dxgiDevice);
ReleaseCOM(dxgiAdapter);
ReleaseCOM(dxgiFactory);

 


DXGI(DirectX Graphics Infrastructure)

DXGI는 Direct3D와는 개별적인 API로, 교환 사슬 설정이나 그래픽 하드웨어 나열, 창모드와 전체화면 모드 전환 등 그래픽에 관련된 작업을 처리한다. 이를 Direct3D와 분리한 이유는, 다른 그래픽 API(이를테면 Direct2D)에도 교환 사슬, 그래픽 하드웨어 열거, 창 모드-전체화면 모드 전환이 필요하기 때문이다. 이러한 분리 덕분에 여러가지 그래픽 API들이 공통의 DXGI API를 사용해서 원하는 ㅈ가업을 처리할 수 있다.

 

 

Comments